Hi Malte,
As you are finding, it’s quite fiddly to propagate extra information through traversals and keep it all straight. Also, Kiama’s query traversals are not as expressive as the rewriting ones.
I think if it was me I would be looking at using attributes to do this kind of job instead of traversals. If you think of things like “under which conditions can an atom be reached” as a property of the atom node, then it’s clearer to encode as an attribute of that node, I think.
Suppose we have this grammar
R ::= T
T ::= A | T && T | T ==> T
where A is an atom and R is the root of the tree. We can define an inherited attribute “conds” for the conditions a term depends on with equations something like this (numbering non-terminals to distinguish occurrences)
R ::= T
T.conds = []
T1 ::= T2 && T3
T2.conds = T1.conds
T3.conds = T1.conds
T1 ::= T2 ==> T3
T2.conds = T1.conds
T3.conds = T1.conds ++ [T2]
Encoding this kind of thing using Kiama is fairly easy once you get your head around how we deal with inherited attributes. You could have something like:
val conds : Term => Seq[Term] =
attr {
case tree.parent(t : And) =>
conds(t)
case tree.parent.pair(n, t @ Implies(l, _)) if n eq l =>
conds(t)
case tree.parent.pair(n, t @ Implies(l, r)) if n eq r =>
conds(t) ++ List(l)
case _ =>
List.empty()
}
The tree.parent pattern matching stuff is how Kiama encodes inherited attribute equations where the equation to choose depends on what is higher up in the tree. The pattern tree.parent(p) succeeds if the node being matched has a parent and it binds p to the parent node. Similarly, tree.parent.pair(n, p) succeeds if n matches the current node and p matches the parent. Each of n and p can be nested patterns, so you can craft checks to match further against what is above. The two cases for Implies distinguish between whether the current node is the left or the right child of the Implies. The default case is used when there is no parent, i.e., you’re at the top of the tree, so there is no need for the R ::= T production.
There are plenty of examples in the Kiama repo of using attributes for similar kinds of things, including how to set up the tree stuff. Look for modules like semantic analysis for the sample languages. Of course, I’m happy to help if you get stuck. Also, the following paper might be of interest:
cheers,