sebastienros / parlot

Fast and lightweight parser creation tools

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Implement look-ahead parser

sebastienros opened this issue · comments

A parser that comes back to the start position when it succeeds.

Example:

{% assign a = b | plus 1 %}

To detect that : is missing after plus we need to check that the next token after plus is either , or %}, without consuming the next tokens.

commented

Here's a simple lookahead parser:

    public sealed class Lookahead<T, T2> : Parser<T>
    {
        private readonly Parser<T> _parser;
        private readonly Parser<T2> _lookaheadParser;

        public Lookahead(Parser<T> parser, Parser<T2> lookaheadParser)
        {
            _parser          = parser          ?? throw new ArgumentNullException(nameof(parser));
            _lookaheadParser = lookaheadParser ?? throw new ArgumentNullException(nameof(lookaheadParser));
        }

        public override bool Parse(ParseContext context, ref ParseResult<T> result)
        {
            context.EnterParser(this);

            var start = context.Scanner.Cursor.Position;
            if (_parser.Parse(context, ref result))
            {
                var parseResult2 = new ParseResult<T2>();
                var start2 = context.Scanner.Cursor.Position;

                var valid = _lookaheadParser.Parse(context, ref parseResult2);

                context.Scanner.Cursor.ResetPosition(start2);

                return valid;
            }

            context.Scanner.Cursor.ResetPosition(start);

            return false;
        }
    }

FollowedBy ?

commented

FollowedBy ?

It's kind of ambiguous whether parser backtracks it's position. Peek or AndPeek maybe?

I am not sure Peek makes it obvious that it enhances the previous parser. Maybe same issue with FollowedBy, so maybe something like WhenFollowedBy, WhenBefore. Could be IfFollowedBy but we already have a When so to keep it consistent.

Also we need the opposite to it, aka WhenNotFollowedBy, such that a parser succeeds if the next token is not something.

commented

Ideally, it would communicate that it enhances the previous parser (FollowedBy, When) and that it backtracks the position (Lookahead, Peek). Maybe WhenPeek? WhenFollowedBy kind of implies (?) that it might backtrack, but is long. WhenNext seems similar to WhenFollowedBy. Naming things is hard :)

Another issue is: are there any use cases where peeked result should be returned? My implementation discards the result, as I don't need it in my case. Maybe there could be two versions of lookahead, a When... that discards the result and an And... that keeps it. I'm not sure there is any need for the latter.

For the opposite version. I checked my uses of look-ahed parser and I always negate it (eg. .Lookahead(NotDigit)). So a WhenNot... version would definitely make it easier.

are there any use cases where peeked result should be returned?

Reminder that there is a SkipAnd and AndSkip. It will parse, advance (consume) but ignore the result (noise).