Rewrite Tree Node Stream Design
Working on design for tree grammar rewriting. I want to be able to tweak a tree w/o having to rebuild whole tree. Imagine
a : ^(A B c D) ; c : C -> E F ;
which means replace the C with E F using a rewrite rule. Suppose we only want to alter the 2nd child of A and not the whole tree. I want to avoid a bunch of extra generated code in favor of making the tree node stream track current child number and start/stop index for rule invocation. Those could be made available to actions if you want, though I don't want to make TreeNodeStream interface too large. Anyway, I suggest added enterRule(), exitRule() methds to TreeNodeStream so it can keep track of the variables I need to do a rewrite
void a() { match(A); match(DOWN); r=c(); // replace tree associated with last rule invocation input.rewrite(r.tree); // NEW match(D); match(UP); } c_return c() { input.enterRule(); // NEW match(C); return ^(nil E F); input.exit(); // NEW }
The rewrite(r.tree) amounts to:
input.rewrite(startIndex, stopIndex, startChild, stopChild, r.tree);
but those variables are tracked within the stream. If done immediately after rule invocation, stream only needs to track one set of variables. Further, this doesn't really require much in code gen.
The rewrite method should not alter the stream if the tree is the same. How do I indicate difference between no return tree and blank (delete) rewrite? Oh, the rewrite only happens in the actual rewrite. Duh:
void a() { match(A); match(DOWN); r=c(); match(D); match(UP); } c_return c() { input.enterRule(); // NEW match(C); // replace tree associated with last rule invocation input.rewrite(^(nil E F)); // NEW return ^(nil E F); input.exit(); // NEW }
That way, we only have to track start index and start child.
The key here is that the stream is rewritten as is the tree. Next use of the stream will see the modified tree. I would just keep the serialized streams for rewrite sections and use those instead of the old stream, just like TokenRewriteStream does. Very efficient.