It is a common task to track positions of recognized AST nodes. parboiled2
has no built-in facilities to do that. The reason is that different applications have different needs with regard to position tracking. Still, there are ways to capture positions.
One way is to compose capturing rules with existing DSL rules (originally proposed at parboiled user group):
var nodes = Map.empty[AstNode, Position]
def someAstNode = rule {
startAstNode ~ ... /* match AST node syntax */ ... ~> MyAstNode ~ endAstNode ~ restOfRule
}
def startAstNode = rule { push(cursor) }
def endAstNode[A <: AstNode]: Rule[Int :: A :: HNil, A :: HNil] = rule {
run { (start: Int, node: A) =>
val pos = Position(start, cursor)
nodes = nodes.updated(node, pos)
node
}
}
The problem with approach is that nodes
structure together with both rules do not have properties of value stack
. For example, if restOfRule
fails then something (not clear how to implement) should track all stored AST nodes in nodes
to clean it up later.
It would be useful if parboiled2
has facilities to add custom rules to DSL. Alas, parboiled2
has no easy way to do it. I know only one way to make it effectively: to patch source code. Hopefully, there are few steps to do it that are as follows:
- add DSL entity to
RuleDSLActions.scala
- add quasiquote AST match to
OpTreeContext.scala
- implement code rendering at the same
OpTreeContext.scala
Summary of changes to capture positions is publicly available.