Search code examples
rascal

Count the number of methods in a Java file


I am trying to parse a Java file and count the method declarations in it. Right now I am using the following code:

import ParseTree;
import lang::java::\syntax::Java15;
import IO;

public int countMethods(loc file) {
    int n = 0;
    try {
        comp = parse(#CompilationUnit, file);
        for (/MethodDec md <- comp) {
            n = n + 1;
        }
    } catch ParseError(loc l): {
        println("Error at line <l.begin.line>, col <l.begin.column>.");
    }
    return n;
}

I am stuck with the error message that the CompilationUnit type is not enumerable. Now i wonder how I can get/iterate through all the methods?


Solution

  • int x <- l means iterate over l and apply the pattern match int x on it, if that succeedes, bind x to the value. This means that for <- the right side has to be enumarable (lists, sets, maps,..). When you want to match all cases using a descendant match, you often want to use the := match operator. Even when the right hand side is enumerable. See example below:

    import IO;
    list[list[int]] ll = [[1,2],[1,3,4],[3],[1,1,1,3,4]];
    println("Pattern match on the children of ll");
    for (/list[value] v <- ll) {
        println(v);
    }
    println("Pattern match on the children of ll and ll itself");
    for (/list[value] v := ll) {
        println(v);
    }
    

    this outputs:

    Pattern match on the children of ll
    [1,2]
    [1,3,4]
    [3]
    [1,1,1,3,4]
    Pattern match on the children of ll and ll itself
    [1,2]
    [1,3,4]
    [3]
    [1,1,1,3,4]
    [[1,2],[1,3,4],[3],[1,1,1,3,4]]
    

    The difference is the candidates the pattern matcher tries.

    For your specific example, you could also write it using reducers:

    public int countMethods(loc file) {
        try {
            return (0 | it + 1 | /MethodDec md := parse(#CompilationUnit, file));
        } catch ParseError(loc l): {
            println("Error at line <l.begin.line>, col <l.begin.column>.");
            return 0;   
        }
    }