Hi folks,
Really enjoying Parboiled2 so far, but have a question about how to unit test a rule which relies on the presence of an item in the value stack.
I'm trying to parse some XML-like messages with nested tags. Take something like this for instance
<foo><bar>this is a bar</bar><baz>bazzz</baz></foo>
Foo is actually an Avro specific record and when I encounter a <bar> or <baz> tag (they can appear in any order) I want to be able to set the relevant properties on the Foo object. Here's a slightly simplified example to illustrate how my parser is written:
def foo= rule {
tagBegin("foo") ~ push(Foo.newBuilder()) ~ ws ~ zeroOrMore(bar | baz) ~ tagEnd("foo") ~>((f: Foo.Builder) => f.build())
}
def bar = rule { leafTag("bar") ~>((f: Foo.Builder, s: String) => f.setBar(s)) }
def baz = rule { leafTag("baz") ~>((f: Foo.Builder, s: String) => f.setBaz(s)) }
I can easily unit test my "foo" rule with:
it should "parse a Foo" in {
val p = new FooParser("<foo><bar>this is a bar</bar><baz>bazzz</baz></foo>")
p.foo.run() match {
case Success(x) => println(x)
case Failure(e: ParseError) => println(p.formatError(e))
case Failure(e) => throw e
}
}
But how do I unit test my "bar" or "baz" rules? They rely on the presence of an existing value on the value-stack... This fails to compile:
it should "parse a Foo" in {
val p = new FooParser("<bar>this is a bar</bar>")
p.bar.run() match {
case Success(x) => println(x)
case Failure(e: ParseError) => println(p.formatError(e))
case Failure(e) => throw e
}
}
I get
Error:(43, 11) value run is not a member of org.parboiled2.Rule[shapeless.::[com.example.Foo.Builder,shapeless.HNil],shapeless.::[com.example.Foo.Builder,shapeless.HNil]]
p.bar.run() match {
^
How can I prepare the value-stack and then run the parser to get the output? Is there a different pattern I should be following for setting properties of an object conditional on what was parsed?
Advice appreciated, thanks!