Sign in

    similarity

    AST similarity caliculator by APTED / Tree Edit Distance

    Download zip
    Author
    Version
    0.2.2
    License
    Apache-2.0
    Last updated
    17 days ago
    Downloads
    56K

    #similarity.mbt

    Code similarity detection for MoonBit using AST-based comparison (TSED - Tree Structure Edit Distance).

    #Features

    • AST-based comparison - Uses moonbitlang/parser to parse MoonBit code
    • TSED Algorithm - Tree Structure Edit Distance for accurate structural similarity
    • Function extraction - Extracts functions, methods, and tests from MoonBit source
    • Cross-file detection - Compare functions across multiple files

    #Installation

    #CLI Tool

    git clone https://github.com/mizchi/similarity.mbt cd similarity.mbt make install # Installs to ~/.local/bin/similarity-mbt

    Make sure ~/.local/bin is in your PATH.

    #As a Library

    Add to your moon.mod.json:

    { "deps": { "mizchi/similarity": "0.1.0" } }

    #Usage

    #CLI

    # Scan all .mbt files in current directory similarity-mbt # Scan specific files similarity-mbt src/*.mbt # Adjust threshold (default: 0.88) similarity-mbt -t 0.95 *.mbt # Exclude test files similarity-mbt --no-tests # Show help similarity-mbt -h

    #Basic similarity detection (Library)

    let source =
    #|fn add(a : Int, b : Int) -> Int { a + b }
    #|fn sum(x : Int, y : Int) -> Int { x + y }

    let options = @similarity.DetectorOptions::default()
    let results = @similarity.detect_similarities(source, options)

    for result in results {
    println(result) // add <-> sum (similarity: 95%, score: 2.8)
    }

    #Custom options

    ///|
    let options : @similarity.DetectorOptions = {
    threshold: 0.80, // Minimum similarity (0.0-1.0)
    min_lines: 3, // Minimum lines per function
    size_penalty: true, // Penalize size differences
    }

    #Cross-file comparison

    let files = [
    ("file1.mbt", source1),
    ("file2.mbt", source2),
    ]
    let results = @similarity.detect_cross_file_similarities(files, options)

    for result in results {
    let (file1, file2, sim) = result
    println("\{file1}:\{sim.func1.name} <-> \{file2}:\{sim.func2.name}")
    }

    #Direct tree comparison

    ///|
    let functions = @similarity.extract_functions(source)

    ///|
    let tsed_options = @similarity.TSEDOptions::default()

    ///|
    let similarity = @similarity.calculate_tsed(
    functions[0].tree,
    functions[1].tree,
    tsed_options,
    )

    #API

    #Types

    • DetectorOptions - Configuration for similarity detection
    • FunctionInfo - Extracted function with name, line info, and AST tree
    • SimilarityResult - Comparison result with similarity score
    • TreeNode - AST tree node for TSED comparison

    #Functions

    • detect_similarities(source, options) - Detect similar functions in source
    • detect_cross_file_similarities(sources, options) - Cross-file comparison
    • extract_functions(source) - Extract functions from source code
    • calculate_tsed(tree1, tree2, options) - Calculate tree edit distance

    #Algorithm

    Based on APTED (All Path Tree Edit Distance) with TSED normalization:

    1. Parse - Convert MoonBit source to AST using moonbitlang/parser
    2. Extract - Extract function bodies as tree structures
    3. Compare - Calculate edit distance between trees
    4. Normalize - Apply size penalties and normalization

    #License

    Apache-2.0

    APTEDOptions

    pub(all) struct APTEDOptions {
    rename_cost : Double
    delete_cost : Double
    insert_cost : Double
    compare_values : Bool
    }

    APTEDOptions::default

    fn APTEDOptions::default() -> APTEDOptions

    DetectorOptions

    pub(all) struct DetectorOptions {
    threshold : Double
    min_lines : Int
    size_penalty : Bool
    }

    DetectorOptions::default

    FunctionInfo

    pub(all) struct FunctionInfo {
    name : String
    start_line : Int
    end_line : Int
    tree : TreeNode
    }

    FunctionInfo::output

    fn FunctionInfo::output(self : FunctionInfo, logger : &Logger) -> Unit

    FunctionInfo::to_string

    fn FunctionInfo::to_string(self : FunctionInfo) -> String

    SimilarityResult

    pub(all) struct SimilarityResult {
    func1 : FunctionInfo
    func2 : FunctionInfo
    similarity : Double
    score : Double
    }

    SimilarityResult::output

    fn SimilarityResult::output(self : SimilarityResult, logger : &Logger) -> Unit

    SimilarityResult::to_string

    fn SimilarityResult::to_string(self : SimilarityResult) -> String

    TSEDOptions

    pub(all) struct TSEDOptions {
    apted_options : APTEDOptions
    min_lines : Int
    min_tokens : Int?
    size_penalty : Bool
    }

    TSEDOptions::default

    fn TSEDOptions::default() -> TSEDOptions

    TreeNode

    pub(all) struct TreeNode {
    label : String
    value : String
    children : Array[TreeNode]
    id : Int
    cached_size : Int
    }

    impl Show for TreeNode

    TreeNode::add_child

    fn TreeNode::add_child(self : TreeNode, child : TreeNode) -> Unit

    TreeNode::finalize_labels

    fn TreeNode::finalize_labels(self : TreeNode) -> Unit

    Add children count to labels for better structural comparison e.g., "For" -> "For_3" if the node has 3 children

    TreeNode::get_subtree_size

    fn TreeNode::get_subtree_size(self : TreeNode) -> Int

    TreeNode::new

    fn TreeNode::new(label : String, value : String, id : Int) -> TreeNode

    TreeNode::output

    fn TreeNode::output(self : TreeNode, logger : &Logger) -> Unit

    TreeNode::to_string

    fn TreeNode::to_string(self : TreeNode) -> String

    calculate_tsed

    fn calculate_tsed(tree1 : TreeNode, tree2 : TreeNode, options : TSEDOptions) -> Double

    compute_edit_distance

    fn compute_edit_distance(tree1 : TreeNode, tree2 : TreeNode, options : APTEDOptions) -> Double

    detect_cross_file_similarities

    fn detect_cross_file_similarities(sources : Array[(String, String)], options : DetectorOptions) -> Array[(String, String, SimilarityResult)]

    detect_similarities

    fn detect_similarities(source : String, options : DetectorOptions) -> Array[SimilarityResult]

    extract_functions

    fn extract_functions(source : String) -> Array[FunctionInfo]

    Powered by MoonBit

    Site sourceReport issuePackagesBuild queueSkillsStatistics

    © 2026 mooncakes.io