I Hate Anonyous Classes!
As you might have guessed, the whole idea of jparsec is pretty much based on a functional mind set. After starting using jparsec, it won't take long for you to find yourself implementing Map, Map2, Map3 etc a lot. And implementing them using anonymous classes can be verbose. For example, we have a Parser<A>, Parser<B> and a Parser<C> and they will be sequentially executed and the 3 result objects will be used to construct a D, as in:
Not too bad, huh? Now imagine in real life A becomes UnbelievableGadget<Ipod>, B is IncredibleCartoon<Panda<KungFu>> and C is ViciouslyBeautiful<KingKong>, how does the following look like?
I hope you enjoyed the ride.
So what would we do if in case we are in a dynamic language like Ruby that's not so crazy about the pointy brackets? Hang on:
And what do the functional nerds do in Haskell? You mean like this?
Awwwwww! And you said you're a Java programmer?
Wait, before you numb yourself with drugs, there is still hope! Every code monkey is created equal (though Haskell programmers are more equal).
The Mapper class is designed to help. So to do it the Ruby way:
"Hey, that's not truly comparable, what are those '<' and '>' joggling there for?"
Hang on, don't push your luck, JAVA programmers!
And here's an interesting one, it's called "curry":
The curry() method takes extra parameters for "currying" purpose. i.e. you can pass in extra parameters to the constructor of D if they are known before the parsers run. For example, if the D constructor takes an extra boolean parameter and you know that you want to pass a "true", here is how it's done:
A real example is to parse the Java ternary "?:" operator. let's first assume that the conditional expression is modeled as:
After careful observation of the precedence and associativity, the "? consequenceExpression :" part is indeed a right-associative binary operator. Any expression can be the consequenceExpression, but the "?:" binds more tightly to the alternativeExpression than the condExpression.
In order to declare the "?:" operator as a binary right associative operator, we'll need to create a parser that parses the consequence expression between a "?" and a ":". This parser should return a Map2 that transforms the left operand (condition) and the right operand (alternative) to the conditional expression. Like this:
I'll pause for 5 minutes for you to read through the above code snippet and understand the wits buried in the annonymous class nested in the outer anonymous class, and of course, to understand this sentence.
Okay, time's up.
The returned Parser<Binary<Expression>> can then be used in an OperatorTable, as:
And if you now see what I'm really up to, and unsurprisingly not impressed by the extra noises in the anonymous classes, here's how we can do it differently with Mapper:
This code does exactly the same thing as our super duper anonymous classes above.
And using the _ method to explicitly ignore the return values of the "?" and ":" operators, we can make it look even more intuitive:
For something as cunning as Mapper, I hope you aren't surprised by its extra requirement of cglib to stay sane performance wise.