petitparser / dart-petitparser

Dynamic parser combinators in Dart.
https://pub.dartlang.org/packages/petitparser
MIT License
453 stars 47 forks source link

Relevance of `refX`? #126

Closed NobbZ closed 2 years ago

NobbZ commented 2 years ago

Hello!

I'm currently checking out dart and petitparser as an alternative to a rust based parser I currently have.

So far I really love it, and the declared parsers reads much cleaner.

Though I am wondering how refX is relevant?

It seems that both date and dateRef in the following definition just work…

ExampleGrammarDefinition extends GrammarDefinition {
  Parser start() => date();

  Parser date() => _dateHelp().flatten().map(DateTime.parse);
  Parser _dateHelp() => _year() & char('-') & _month() & char('-') & _day();

  Parser dateRef() => ref0(_dateHelpRef).flatten().map(DateTime.parse);
  Parser _dateHelp() => ref0(_year) & char('-') & ref0(_month) & char('-') & ref0(_day);

  Parser _year() => digit().times(4);
  Parser _month() => digit().times(2);
  Parser _day() => digit().times(2);
}

Omitting the refX makes the code much cleaner, though I fear to miss something. In case I am missing something important, I think it would be nice to add about the relevancy to the documentation.

renggli commented 2 years ago

You are right, in the example above you do not need ref0, because there are no cycles in your grammar.

Consider the following example that parses balanced parenthesis:

class ParensGrammar extends GrammarDefinition {
  Parser start() => char('(') & ref0(start) & char(')') 
                  | epsilon();
}

If you replaced ref0(start) with start() you would end up with an infinite recursion when building the grammar. The ref0 functionality breaks such cycles apart and makes sure that repeatedly referenced parsers are only instantiated once (see documentation).