简体   繁体   中英

How can I improve Sprache parser error messaging with missing closing brace?

I am building a simple command-style grammar using Sprache. I am trying to find out if there's a way to get better error reporting when missing a closing character (eg ], ), }).

If a closing character is missing my grammar correctly reports an error. However, the messaging leads to difficulty in appreciating the real problem. Given the following string to be parsed:

sum 10 [multiply 5 4

Sprache reports the following error:

Sprache.ParseException : Parsing failure: unexpected '['; expected newline or end of input (Line 1, Column 8); recently consumed: sum 10

What appears to be happening is that the parser tries to match on my CommandSubstitution and fails to find a closing ']' . This causes the parser to fallback and try an alternate. As it can't match any more Things for the command, it tries to match on the CommandTerminator . As that can't match a '[' it reports the error complaining about the expected newline or end of input instead of saying, "Hey, buddy, you didn't match your brace!"

Are there any workarounds or recommendations of how the grammar could be improved to make the reporting better using a parsing library like Sprache?

public static readonly Parser<Word> Word = Parse.Char(IsWordChar, "word character").AtLeastOnce().Text()
                                                .Select(str => new Word(str));

public static readonly Parser<CommandSubstitution> CommandSubstitution = from open in Parse.Char('[').Once()
                                                                            from body in Parse.Ref(() => Things)
                                                                            from close in Parse.Char(']').Once()
                                                                            select new CommandSubstitution(body.ToList());


public static readonly Parser<Thing> Thing = CommandSubstitution.Or<Thing>(Word);

public static readonly Parser<IEnumerable<Thing>> Things = (from ignoreBefore in WordSeparator.Optional()
                                                            from thing in Thing
                                                            from ignoreAfter in WordSeparator.Optional()
                                                            select thing).Many();

public static readonly Parser<IEnumerable<Thing>> Command = from things in Things
                                                            from terminator in CommandTerminator
                                                            select things;

It sounds like the overall problem is that Sprache is failing, trying alternatives, and failing again, when it ought to just give up after the first failure instead.

You're defining the Things parser using the Parse.Many extension method. The thing about the Parse.Many parser is that it always succeeds regardless of whether its inner parser succeeds or fails. If the inner parser fails, Parse.Many simply assumes that there is no more input that it needs to consume.

This is what seems to be happening here. First, Parse.Many consumes the fragment "sum 10 " . Then it tries to parse more input, but fails. Since it has failed to parse any more input, it assumes that there is no more input it needs to consume. But then an error results, because the fragment [multiply 5 4 has not been consumed.

To fix this, use Parse.XMany instead of Parse.Many . If the inner parser for Parse.XMany fails after consuming at least one character , then Parse.XMany will give up immediately and report the failure.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM