Skip to content

Overview: grappa 1.0.x vs parboiled java

Francis Galiegue edited this page May 19, 2014 · 9 revisions

Introduction

This page is an (hopefully not biased!) overview of the differences (and compatibilities) between parboiled-java and grappa 1.0.x. It is a high-level view of the (very technical and sometimes arid) release notes.

Notable changes

Build system

Grappa uses gradle as a build system, where parboiled uses SBT.

Grappa also makes use of the gradle wrapper; this means that you don't need anything other than a working Internet connection, git and a JDK (6 or more) to get started.

No scala support anymore

Grappa is meant to be Java and only Java; as such, Scala support has been removed entirely.

Partial Java 8 compatibility

Partial in the sense that Grappa will run on a 1.8 JRE, unlike parboiled; however, parsers are still generated using 1.6 bytecode, so you cannot (yet) write grammars making use of new features available in Java 7 (try-with-resources for instance) or Java 8 (lambdas, etc).

Dependencies

Grappa depends on Guava (version 17.0); this allows to make full use of this library's very powerful features.

The ASM dependency has been updated from 4.x to 5.x; what is more, the dependency is on asm-debug-all instead of "non debug" versions of ASM: this allows for much easier debugging.

CharSequence support for input buffers

This means you can use Grappa to parse CharBuffers, but also very large text files using largetext.

Event-driven parsing

Grappa provides another mechanism for managing parser rule outputs in addition to the value stack, actions and Vars: you can now trigger events on the inputs you choose.

All this requires is that you write an event class and listener class; see here for more details.

Grammars

Full parboiled compatibility

Grappa 1.0.x is fully backwards-compatible with parboiled. All your grammars written for parboiled should work out of the box with Grappa, with no modifications. Any custom actions you may have written etc should also work.

If this isn't the case, this is a bug, and yours truly asks that you open an issue.

Note however that all basic rules which were defined in parboiled are deprecated in order to be compliant with Java naming conventions; that is, FirstOf is now firstOf etc. Other than that, the new rules work exactly the same.

Again, if this isn't the case, this is a bug, and yours truly asks that you open an issue.

New rules

Grappa has new rules not present in parboiled:

  • Unicode matchers: you can match a single code point (unicodeChar()) or a range of code points (unicodeRange());
  • all rules (lowercased) defined by RFC 5234, Appendix B, section 1 are present, except for LWSP. This means you have digit(), alpha(), etc;
  • trie(): this new rule uses a trie to match one string among many; for instance trie("Alice", "Bob", "Fred"); note that it will always find the longest match: trie("do", "double") will find double in doubles, not do;
  • join(): this is a general joining rule allowing all combinations of repetitions; note that the joining rule should not match an empty string: if it does, you will get an exception at runtime.

Example usage of join(): let us say you parse a JSON Array; you have a clear separator which is the comma (,), with JSON values inbetween. Provided you have the appropriate rules, here is how you would match a JSON array:

Rule jsonArray()
{
    return sequence('[', join(jsonValue()).using(',').min(0), ']');
}

This will even match empty arrays. Whitespaces etc not accounted for but they can be inserted with little effort.

The code in general

Java 6 updates

Parboiled was written with Java 5 in mind; grappa is (for version 1.0.x! 2.0.x will go Java 7) written with Java 6 in mind. As such, a lot of code has been modified to account for Java 6 features (for instance, the appearance of Deque, String's .isEmpty(), others).

JSR 305 annotations

The code is nearly fully annotated with JSR 305 annotations; this allows IDEs or tools supporting them (IDEA, FindBugs, others) to report problems related to these annotations.

Note that unfortunately, the annotation which is by far the most prominent in the current code is @Nullable. If you use an IDE which warns on nullable value problems, you will probably get a lot of those if your existing grammars use the stack or Vars a lot, since all of these accept or can produce nulls. This will not change for version 1.0 but it will change for version 1.1.

Much more robust testing

A lot of tests (not all of them yet) have been converted from using String-based comparisons (!!!) to using assertions (using AssertJ). Another added dependency is Mockito.

Grappa also has the ability to run mutation testing using pitest via the existing gradle plugin.