There are use cases when developing custom low-level DSL rules might be very effective. It is possible without changing source code of parboiled2
. And requirements to achive that are as follows:
First, we need a RuleDSLActionsCustom
trait that contains rules declarations:
trait RuleDSLActionsCustom {
@compileTimeOnly("Calls to `debug` must be inside `rule` macro")
def debug(msg: String): Rule0 = `n/a`
}
Second, we need to mix it in a class ParserCustom
:
abstract class ParserCustom extends RuleTypes
with RuleDSLBasics with RuleDSLCombinators
with RuleDSLActions with RuleDSLActionsCustom
Next we need to deliver debug
rule to a OpTreeContextCustom
class: it should extend OpTreeContext.opTreePF
function with proper implementation of code generation for debug
rule:
class OpTreeContextCustom[OpTreeCtx <: reflect.macros.blackbox.Context](val c1: OpTreeCtx) extends OpTreeContext[OpTreeCtx](c1) {
import c.universe._
override def opTreePF: PartialFunction[Tree, OpTree] = {
case q"$a.this.debug($msg)" => Debug(OpTree(arg))
case t => super.opTreePF(t)
}
case class Debug(msg: Tree) extends OpTree {
def renderInner(wrapped: Boolean): Tree = q"println($msg)"
}
And here is the place where code starts to smell. The complication arises from the implementation currently not designed for such extensions. Parser
tighgly depends on ParserMacros
, that in its turn tightly depends on OpTreeContext
. It is still possible to extend those things (like it experimentally done for CapturePos
for custom debug
rule. Overall, it all implies that custom extension should copy-paste almost entire inner implementation of ParserMacros
and OpTreeContext
, and even worse keep it updated with original upstream to properly merge updates.
The approach for custom rule implementation is useless. It is possible though to redesign parboiled2
inner API to make it easier to extend Parser
with custom rules. But, it would make much harder to evolve that API. Practically, it is easier to keep a simple patch to a fork then to maintain classes derived from parboiled2
inner API.