opeongo Replying to my own question, after building the example project with congocc I see that the #Values token on line 74 both declared the class and assigned a new instance to thisProduction.values. Very concise and clever.
Yes, it is, but the credit for that should go to John Bradley (whose login on this forum is adMartem). He added that feature just over a month ago, so it is very very new, and it's not actually documented anywhere. You'd have to read the code to know that you can do that!
Though, actually, a lot of things aren't documented anywhere, I have to admit. A feature that has been in the code for a good, long time, but I've never really documented it is that you can (quite similar to this) put a left-hand-side on a lookahead (in CongoCC, that's SCAN
, not LOOKAHEAD
). So you can write:
result = SCAN Foo Bar => Foobar
So, I mean, you can store the result of the lookahead in a variable. result
in this case, which would have to be defined somewhere or other, of course. And, actually, if all you wanted was to know whether the upcoming input matches Foo
followed by Bar
and store it in a variable, you could do:
[ result = SCAN Foo Bar => {} ]
In that case, you don't consume any input whether the lookahead succeeds or not. The only purpose of the above would be to set the result
variable, which you'd presumably use later somehow or other. Of course, now that I think about it, the above is the exact same as:
{result = false;}
[ SCAN Foo Bar => {result = true;} ]
And inserting the Value elements in to the array was left as an exercise for the reader.
Yes, well, regardless of the left-hand-side (which is a very new feature) if you annotate an expansion as building a node, then any new nodes created when building that node become child nodes of the node you just built. The way the Array
production was originally written was:
Array :
<OPEN_BRACKET>
[
Value (<COMMA> Value)*!
]
<CLOSE_BRACKET>
;
But, do note that the tree-building strategy is very bloody-minded, so the generated parse tree contains all the open/close bracket and commas inside, and very typically you don't want that. One solution might be:
INJECT Array:
{
public java.util.List<Node> getUsefulChildren() {
return childrenOfType(Node.class, n->n.getType() != OPEN_BRACKET && n.getType() != CLOSE_BRACKET && n.getType() != COMMA);
}
}
I think there is a bit of a conceptual shift when going from legacy JavaCC to Congo. For one thing, the parse tree is generated by default, so that is assumed to be the most typical usage pattern. And then typical solution to whatever it is is very typically something like the above, you just inject the method you need into the appropriate object in the parse tree. In typical usage, you would have no more reason to look at the generated Array.java
than there is to eyeball a .class file. That's the idea anyway.
Well, I just thought to make a few points. Glad to see you here, Tom.