ParboiledをGroovyから使おうとしてできなかった話。


Javaに[PegDown](https://github.com/sirthias/pegdown)というmarkdown変換用ライブラリがあって、[Parboiled](https://github.com/sirthias/parboiled)はそれで使っているパーサジェネレータ。
同じ人が開発している。

parboiled
https://github.com/sirthias/parboiled/wiki

ドキュメントがしっかりあり、構文も短くて良いと思ったので、[Simple Java Example](https://github.com/sirthias/parboiled/wiki/Simple-Java-Example) のページを見ながらgroovyで書いて試そうとした。
Groovy Version: 2.0.6 JVM: 1.6.0_37 Vendor: Apple Inc. OS: Mac OS X

```groovy:
import org.parboiled.BaseParser
import org.parboiled.Rule
import org.parboiled.annotations.BuildParseTree
import org.parboiled.Parboiled
import org.parboiled.support.ParsingResult
import org.parboiled.parserunners.ReportingParseRunner
import org.parboiled.support.ParseTreeUtils
@Grab('org.parboiled:parboiled-java:latest.release')

@BuildParseTree 
class CalculatorParser extends BaseParser {
    Rule Expression() {
        Sequence( Term(), ZeroOrMore(AnyOf("+-"), Term()) )
    }
    Rule Term() {
        Sequence( Factor(), ZeroOrMore(AnyOf("*/"), Factor() ) )
    }
    Rule Factor() {
        FirstOf( Number(), Sequence('(', Expression(), ')' ) )
    }
    Rule Number() {
        OneOrMore(CharRange('0', '9'))
    }
}

String input = "1+2"
CalculatorParser parser = Parboiled.createParser(CalculatorParser.class)
ParsingResult result = ReportingParseRunner.run(parser.Expression(), input)
String parseTreePrintOut = ParseTreeUtils.printNodeTree(result)
println parseTreePrintOut
```
が、なんかエラーが出て動かない。

```
Caught: java.lang.RuntimeException: Error creating extended parser class: Class not found
java.lang.RuntimeException: Error creating extended parser class: Class not found
	at org.parboiled.Parboiled.createParser(Parboiled.java:58)
	at test.run(test.groovy:27)
Caused by: java.io.IOException: Class not found
	at org.objectweb.asm.ClassReader.a(Unknown Source)
	at org.objectweb.asm.ClassReader.<init>(Unknown Source)
	at org.parboiled.transform.AsmUtils.createClassReader(AsmUtils.java:56)
	at org.parboiled.transform.ClassNodeInitializer.process(ClassNodeInitializer.java:62)
	at org.parboiled.transform.ParserTransformer.extendParserClass(ParserTransformer.java:44)
	at org.parboiled.transform.ParserTransformer.transformParser(ParserTransformer.java:38)
	at org.parboiled.Parboiled.createParser(Parboiled.java:54)
	... 1 more
```

納得いかなかったので、Parboiledのソースを落として調べた。
[org.parboiled.transform.AsmUtils](https://github.com/sirthias/parboiled/blob/master/parboiled-java/src/main/java/org/parboiled/transform/AsmUtils.java) の、line 51

```java:
...
    public static ClassReader createClassReader(Class<?> clazz) throws IOException {
        checkArgNotNull(clazz, "clazz");
        String classFilename = clazz.getName().replace('.', '/') + ".class"; //<- line51 ここ！
        InputStream inputStream = clazz.getClassLoader().getResourceAsStream(classFilename);
        if (inputStream == null) {
            inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(classFilename);
        }
        return new ClassReader(inputStream);
    }
...
```

ここで、クラス名から.classファイルを探し出し、[ASM](http://asm.ow2.org/)でバイトコードを読み出してるみたい。
.groovyファイルひとつで試してるから、当然 .classファイルはできていない。
だから使えなかったのか。そうかー。

groovyで気軽に使えるパーサライブラリが欲しいなぁ。