benjamin-hodgson / Pidgin

A lightweight and fast parsing library for C#.
https://www.benjamin.pizza/Pidgin/
MIT License
914 stars 70 forks source link

Confusing API: unexpected EOF error #150

Closed CyborTronik closed 5 months ago

CyborTronik commented 10 months ago

By having next definition:

    public Parser<char, Term> DefineTerm()
    {
     ...
        var underscore = Char('_');
        var atom = Letter.Or(underscore)
            .Then(LetterOrDigit.Or(underscore).ManyString(), (first, rest) => first + rest)
            .Select(x => (Term)new Atom(x))
            .Labelled("atom");
        return atom.Before(SkipWhitespaces);
    }

    public Parser<char, Sentence> DefineSentence()
    {
        var term = DefineTerm();
        var compound = Char('(')
            .Then(term.Separated(SkipWhitespaces), (open, content) => content)
            .Before(Try(Char(')')).Before(SkipWhitespaces))
            .Select(x => RelationFactory.Create(x.ToArray()))
            .Labelled("relation");

        var dot = Char('.').Before(SkipWhitespaces);
        var defineSentence = term.Or(compound)I can 
            .Separated(SkipWhitespaces)
            .Before(dot)
            .Select(x => RelationFactory.CreateSentence(x.ToArray()))
            .Labelled("sentence");
        return SkipWhitespaces.Then(defineSentence);
    }

When I run:


    [Fact]
    public void SimpleSentence()
    {
        var grammar = new Grammar();
        var sentences = grammar.DefineSentence();
        var result = sentences.ParseOrThrow("label.");
        result.Verb.ToString()
            .Should().Be("label");
    }

I get the following error, and is not clear why and what to do next:

Pidgin.ParseException
Parse error.
    unexpected EOF
    expected sentence
    at line 1, col 7

Wonder if I can have some suggestions on how this can be understood/debug in order to make it work?

benjamin-hodgson commented 8 months ago

Without running your code I suspect the problem is with Separated(SkipWhitespaces). After reading label, the SkipWhitespaces parser succeeds (without consuming any input since there’s no whitespace). This tells the Separated parser to continue its loop; it tries to parse a term and fails because there isn’t one.

I recommend consuming the whitespace at the token level, but you might be able to kludge it with SeparatedAndTerminated