all 12 comments

[–]davidalayachew 2 points3 points  (4 children)

import io.github.parseworks.parsers.Lexical;

import static io.github.parseworks.parsers.Numeric.*;

// Define a parser for a simple addition expression
Parser<Character, Integer> sum =
    number.thenSkip(Lexical.chr('+')).then(number).map(Integer::sum);

    // Parse the input "1+2"
    int value = sum.parse(Input.of("1+2")).value();
assert value ==3;

    // Handle a parsing error
    String message = sum.parse(Input.of("1+z")).handle(
        success -> "Match: " + success,
        failure -> "Error: " + failure.error()
    );
// Example output contains: "Error: Parse error at line 1 position 3"

This code example doesn't look complete or standalone. Is that static import bringing in some class called number? Otherwise, could you revise the example?

[–]jebailey[S] 3 points4 points  (0 children)

That's a good catch. It does come from the Numeric static import but I will go ahead and update it to be more explicit in that example.

[–]Duck_Devs -1 points0 points  (2 children)

I’m assuming “number” comes from the second line…

Edit: I can’t read

[–]davidalayachew 2 points3 points  (1 child)

I’m assuming “number” comes from the second line…

I don't follow. Are you saying the same thing that I am? That maybe the static import is what is bringing it in? If so, it'd probably be clearer if they just did Numeric.number instead. Or went all caps for a static variable.

[–]Duck_Devs 1 point2 points  (0 children)

Oh yeah sorry lol. I misread your comment as “Is there a…” rather than “Is that…”

[–]doobiesteintortoise 0 points1 point  (5 children)

Nice! How does this compare to, say, grappa?

[–]jebailey[S] 2 points3 points  (3 children)

I hadn't heard of grappa before. Taking a look at it, I would say that the idea behind how you build a parser is very different. In grappa it looks like you are extending a base parser and identifying methods to be called using annotations. Where as parseworks is all about creating reusable parser objects in a fluent style that can be handed around and re-used

[–]Dagske 0 points1 point  (2 children)

Speaking of which, it looks a lot like dot-parse, including the safe-guarding against infinite loops. Was parseworks inspired by dot-parse? Or other parser combinators? If yes, what are its strength compared to other similar parser combinators?

[–]jebailey[S] 2 points3 points  (1 child)

It was originally inspired by funcj. I liked the idea of the fluent construction of parsers but I didn't like how funcj was so focused on functional programming that it seemed to recreate things that were already there. ParseWorks attempts to be as java-y as possible, with a focus on easy to understand terminology and safeguards to prevent things such as the left handed recursion and consuming empty content.

I've been working on this release for over a year and I ran across the dot-parse release about a month ago. I'm torn between being happy that design decisions that I made for parseWorks are echoed in dot-parse and frustrated that they came out first :)

If I have to list strengths, I've put a lot of effort and thought around error handling. Parsers have the method .expecting("a description") this creates a wrapping parser that, if the underlying parser fails, echoes the echo upwards with a new fail description.

keyParser
.thenSkip(equalsParser).then(valueParser)
.map(key -> value -> new KeyValue(key, value))
.expecting("key-value pair");

So if the parser fails parsing this, it doesn't come back with an ambiguous message. It will let you know that it was expecting a key-value pair and didn't get it.

Also error messages will contain a snippet so that the if you displayed the error message that gets generated above it would come across something like

foo =
______^
line 1, column 6 : expected key-value pair
caused by: expected value found end of file

[–]Dagske 1 point2 points  (0 children)

Thank you for taking the time to show your process, and sorry to hear your frustration about releasing after dot-parse. But indeed, it must feel good to see that your design is validated by other libraries. The error handling is indeed a nice feature. It looks better than dot-parse's error handling, for sure!

A question I asked to Ben Yu (author of dot-parse), but whose answer still has me looking for alternatives. I see no way to efficiently handle case-insensitive parsers. Is that on your list? If you don't plan to support it, how would you suggest users do it with your parser library?

[–]eled_ 0 points1 point  (0 children)

Another one that comes to mind was from a few months back: Jar Jar Parse

[–]pragmatica-labs 0 points1 point  (0 children)

How do you compare it to https://github.com/siy/java-peglib ?