Search code examples
rascal

Get children count of a tree node


The docs for Node only mention following methods:

Equal, GreaterThan, GreaterThanOrEqual, LessThan, LessThanOrEqual, NotEqual, Slice, Subscription

It does mention how to access child by index using Subscription, but how can I find out the count of children node has to iterate over them?

Here is my use case:

Exp parsed = parse(#Exp, "2+(4+3)*48");
println("the number of root children is: " + size(parsed));

But it yields error, as size() seems to only work with a List.


Solution

  • Different answers, different aspects that are better or worse. Here are a few:

    import ParseTree;
    
    int getChildrenCount1(Tree parsed) {
       return (0 | it + 1 | _ <- parsed.args);
    }
    

    getChildrenCount1 iterates over the raw children of a parse tree node. This includes whitespace and comment nodes (layout) and keywords (literals). You might want to filter for those, or compensate by division.

    On the other hand, this seems a bit indirect. We could also just directly ask for the length of the children list:

    import List;
    import ParseTree;
    
    int getChildrenCount2(Tree parsed) {
       return size(parsed.args) / 2 + 1; // here we divide by two assuming every other node is a layout node
    }
    

    There is also the way of meta-data. Every parse tree node has a declarative description of the production directly there which can be queried and explored:

    import ParseTree;
    import List;
    
    // immediately match on the meta-structure of a parse node:
    int getChildrenCount3(appl(Production prod, list[Tree] args)) {
        return size(prod.symbols);
    }
    

    This length of symbols should be the same as the length of args.

    // To filter for "meaningful" children in a declarative way:
    int getChildrenCount4(appl(prod(_, list[Symbol] symbols, _), list[Tree] args)) {
        return (0 | it + 1 | sort(_) <- symbols);
    }
    

    The sort filters for context-free non-terminals as declared with syntax rules. Lexical children would match lex and layout and literals with layouts and lit.

    Without all that pattern matching:

    int getChildrenCount4(Tree tree) {
        return (0 | it + 1 | s <- tree.prod.symbols, isInteresting(s));
    }
    
    bool isInteresting(Symbol s) = s is sort || s is lex;