Alternative to trim parser or how to discard unwanted input? #149
-
First of all, thanks for this awesome package. I've been playing around with this in a hobby project for a day or two and have been wanting to have a more concise way of expressing some parsers, I've been looking through most combinators but might be missing something please point me in the right direction in case that's true. So lets use a simple example (not my case but just to explain) lets say I want to parse a number between parens // Version 1
final Parser<int> parserV1 = char('(') & digit() & char(')').map((values) => int.parse(values[1]));
// Version 2
final Parser<int> parserV2 = digit().trim(char('('), char(')')).map((value) => int.parse(value));
With version1 you have to keep track of the index to know which value to extract from values and to correctly map the parser, so not the best solution. version 2 works perfectly but has a default parser for left and right using whitespace() What I would like to accomplish is something like this: // Desired
final Parser<int> parserV3 = char('(').dicard() & digit().map((value) => int.parse(value)) & char(')').dicard(); Someway of telling the parser consume input throwing it away completely, so that when composed in sequence it won't accumulate in the result list. If that's not possible then would be great to have individual TrimLeft and TrimRight parsers. Is there an extension I'm missing ? |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments
-
Thank you for the kind words and the question with the great examples. This is not something that is provided out of the box from this package. I don't think Probably the easiest solution that comes closest to your version 2 would be to add a helper extension, like so: extension SurroundedParserExtension<T> on Parser<T> {
Parser<T> surroundedBy(Parser<void> left, [Parser<void>? right]) =>
[left, this, right ?? left].toSequenceParser().pick(1).cast<T>();
}
final parserV2 = digit().map(int.parse).surroundedBy(char('('), char(')')); You can copy that extension to your own code. We can also consider adding it to the package, if people think it is generally useful? While it obviously simplifies the creation of some quick parsers, I am afraid that in practice it might not be that useful (often exact positions of characters surrounding some other expression need to be known, i.e. for a syntax highlighter). Something like version 3 could be implemented, but there are various complications that make it tricky: the typing in Dart doesn't work in your example, and you would still need to somehow unwrap the resulting element from a list and cast it to the right type. Also parser transformations (and optimizations) might become more complicated. Still could be worth to investigate. |
Beta Was this translation helpful? Give feedback.
-
Hey @renggli thanks for the quick reply, playing around a bit more I found this alternative which is more declarative. Sadly Dart doesn't seem to support generic params for operators and no way of specifying associativity and precedence for them either if I'm not mistaken. extension SurroundParserExtension<T> on Parser<T> {
Parser<dynamic> operator >>(Parser<dynamic> other) =>
[this, other].toSequenceParser().pick(1);
Parser<T> operator <<(Parser<void> other) =>
[this, other].toSequenceParser().pick(0).cast<T>();
}
final Parser<int> num = digit().map((value) => int.parse(value));
final exampleParser = char('(') >> (num << char(')'));
final typedParser = exampleParser.cast<int>();
|
Beta Was this translation helpful? Give feedback.
-
There is now also the skip-parser, that addresses various of the mentioned concerns: https://pub.dev/documentation/petitparser/latest/parser/SkipParserExtension/skip.html |
Beta Was this translation helpful? Give feedback.
Thank you for the kind words and the question with the great examples.
This is not something that is provided out of the box from this package. I don't think
trim
is a good stand-in here, because it consumes the opening and closing params an arbitrary amount of times. Furthermore, it also passes if the before and after characters are entirely absent.Probably the easiest solution that comes closest to your version 2 would be to add a helper extension, like so: