dartpetitparser

Can a petitparser parser be reused safely?


Using petitparser in Dart, is it ok to reuse a parser?

For example, say we want to parse an IPv4 style address like 192.168.1.21.

Initally, I wrote:

final ipv4Part = digit().repeat(1, 3).flatten();
final ipv4Address = (ipv4Part &
        char('.') &
        ipv4Part &
        char('.') &
        ipv4Part &
        char('.') &
        ipv4Part)
    .flatten();
ipv4Address.parse('192.168.1.21');

I noticed that my sequence parser had 7 children, as expected, but the number parsers were all identical (at least all had the same hashCode) whereas the dot parsers were all different. Nonetheless, the parser seemed to work.

I experimented with:

Parser ipv4Part() => digit().repeat(1, 3).flatten();
final ipv4Address = (ipv4Part() &
        char('.') &
        ipv4Part() &
        char('.') &
        ipv4Part() &
        char('.') &
        ipv4Part())
    .flatten();

which worked equally well in this simple case, at the expense of a few extra ()s and a handful more objects in memory.

Is there any reason to prefer one style over the other? Is there a better way to write this?

Was I just lucky that my first attempt worked? If I change all my finals to functions returning Parser it seems I'm adopting the style of GrammarDefinition. Would I have to / should I then use the ref(parser) syntax throughout?

My overall parser is for a non-recursive grammar, and at the moment I'm not using GrammarDefinition. What are the benefits of reworking what I've done into a grammar definition when, so far, I don't think there's any recursion in my grammar?


Solution

  • Yes, parsers can (and should) be reused. The parser objects can be seen as configurable functions that know how to parse a particular grammar. You can call (parse some input) and reuse parsers like Dart functions.

    Either of the above examples work and do the same, the first one just produces a bit of a smaller parser graph. When using GrammarDefinition you should use ref, it works with recursive grammars and automatically reuses the parser objects. In your case I would go with the initial example, it seems to be the most succinct solution.