4

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?

shad
  • 43
  • 4

2 Answers2

4

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;   
    }
}
Davy Landman
  • 15,109
  • 6
  • 49
  • 73
3

Why not this?

public int countMethods(loc file)
{
    try
    {
        return size([1 | /MethodDec md <- parse(#CompilationUnit, file)]);
    }
    catch ParseError(loc l):
    {
        println("Error at line <l.begin.line>, col <l.begin.column>.");
        return 0;
    }
}
Floris Velleman
  • 4,848
  • 4
  • 29
  • 46
grammarware
  • 120
  • 6
  • There are more roads to Rome ;-). I would not that it uses `<-` instead of `:=` (not solving the question). And a minor point, it builds an unnecessary list. – Davy Landman May 27 '16 at 09:31
  • In my experience building such a list costs virtually nothing in Rascal (as opposed to, say, any variation of `[m | /MethodDec m := ...]`), but yes, the counting primitive is kinda missing in Rascal yet. In RcScript we can have `COUNT [X] IN SomeSet :- X IS MethodDec` with neither explicitly looping nor having this temp list. I might propose it as a Rascal feature... – grammarware May 27 '16 at 21:30
  • @grammarware hey dude, updated the code formatting. Just paste the code and select code sample instead of using ` for blocks. Also, will `[1 | /MethodDec md...` not always return 1 to much? – Floris Velleman Jun 02 '16 at 13:15
  • `int countMethods(loc file) = (0 | it + 1 | /MethodDec md := parse(#start[CompilationUnit], file));` @grammarware this does not generate an intermediate list. – Jurgen Vinju Jun 02 '16 at 13:39