diff --git a/src/samples/ParserExample/Program.cs b/src/samples/ParserExample/Program.cs index a213c7a7..96b233b8 100644 --- a/src/samples/ParserExample/Program.cs +++ b/src/samples/ParserExample/Program.cs @@ -133,7 +133,41 @@ public static object Rec(List args) return "_"; } + private static void testIssue516() + { + ParserBuilder builder = new ParserBuilder(); + var xmlparser = new MinimalXmlParser(); + var r = builder.BuildParser(xmlparser, ParserType.EBNF_LL_RECURSIVE_DESCENT, "document"); + Check.That(r.IsError).IsFalse(); + var parser = r.Result; + var parsed = parser.Parse(@" + + + + + + + + inner inner content +"); + if (parsed.IsError) + { + parsed.Errors.ForEach(Console.WriteLine); + } + return; + var jBuilder = new ParserBuilder(); + var jsonParser = new EbnfJsonGenericParser(); + var jr = jBuilder.BuildParser(jsonParser, ParserType.EBNF_LL_RECURSIVE_DESCENT, "root"); + Check.That(jr).IsOk(); + var jparsed = jr.Result.Parse("{ \"toto\":1"); + if (jparsed.IsError) + { + jparsed.Errors.ForEach(Console.WriteLine); + } + + } + private static void TestIssue507() { var tests = new EBNFTests(); @@ -1360,7 +1394,8 @@ print a } private static void Main(string[] args) { - TestIssue507(); + testIssue516(); + //TestIssue507(); //TestFStrings(); //TestIssue495(); //testGenericLexerJson(); diff --git a/src/sly/parser/parser/UnexpectedTokenSyntaxError.cs b/src/sly/parser/parser/UnexpectedTokenSyntaxError.cs index d585b8af..a2e1700d 100644 --- a/src/sly/parser/parser/UnexpectedTokenSyntaxError.cs +++ b/src/sly/parser/parser/UnexpectedTokenSyntaxError.cs @@ -13,7 +13,7 @@ public class UnexpectedTokenSyntaxError : ParseError, IComparable where T : s { private readonly string _i18N; - private readonly Dictionary> _labels; + private readonly Dictionary> _labels = new Dictionary>(); public UnexpectedTokenSyntaxError(Token unexpectedToken, Dictionary> labels, string i18n=null, params LeadingToken[] expectedTokens ) { _labels = labels; diff --git a/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.cs b/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.cs index df2f60a6..4a3829a7 100644 --- a/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.cs +++ b/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.cs @@ -36,7 +36,6 @@ public SyntaxParseResult SafeParse(IList> tokens, SyntaxParsingCon var errors = new List>(); var nt = NonTerminals[start]; - var rs = new List>(); var matchingRuleCount = 0; diff --git a/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.EBNFRecursiveDescentSyntaxParser.Choice.cs b/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.EBNFRecursiveDescentSyntaxParser.Choice.cs index 540b5655..cc5f7fb8 100644 --- a/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.EBNFRecursiveDescentSyntaxParser.Choice.cs +++ b/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.EBNFRecursiveDescentSyntaxParser.Choice.cs @@ -29,21 +29,25 @@ public SyntaxParseResult ParseChoice(IList> tokens, ChoiceClause> alternateResults = new List>(); foreach (var alternate in clause.Choices) { switch (alternate) { case TerminalClause terminalAlternate: - result = ParseTerminal(tokens, terminalAlternate, currentPosition, parsingContext); + var rterm = ParseTerminal(tokens, terminalAlternate, currentPosition, parsingContext); + alternateResults.Add(rterm); break; case NonTerminalClause nonTerminalAlternate: - result = ParseNonTerminal(tokens, nonTerminalAlternate, currentPosition, parsingContext); + var rnonterm = ParseNonTerminal(tokens, nonTerminalAlternate, currentPosition, parsingContext); + alternateResults.Add(rnonterm); break; default: throw new InvalidOperationException("unable to apply repeater inside " + clause.GetType().Name); } + result = alternateResults.Last(); if (result.IsOk) { if (clause.IsTerminalChoice && clause.IsDiscarded && result.Root is SyntaxLeaf leaf) @@ -57,13 +61,21 @@ public SyntaxParseResult ParseChoice(IList> tokens, ChoiceClause>(); var expected = terminalAlternates.Select(x => x.ExpectedToken).ToList(); result.AddError(new UnexpectedTokenSyntaxError(tokens[currentPosition], LexemeLabels, I18n, expected.ToArray())); } + else + { + var greaterPosition = alternateResults.Select(x => x.EndingPosition).Max(); + var errors= alternateResults.Where(x => x.EndingPosition == greaterPosition).SelectMany(x => x.GetErrors()).ToList(); + result.AddErrors(errors); + result.IsError = true; + } parsingContext.Memoize(clause, position, result); return result; diff --git a/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.cs b/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.cs index e6f48d83..57b0ef26 100644 --- a/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.cs +++ b/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.cs @@ -57,10 +57,10 @@ public override SyntaxParseResult Parse(IList> tokens, Rule ru isError = isError || termRes.IsError; break; } - case NonTerminalClause terminalClause: + case NonTerminalClause nonTerminalClause: { var nonTerminalResult = - ParseNonTerminal(tokens, terminalClause, currentPosition, parsingContext); + ParseNonTerminal(tokens, nonTerminalClause, currentPosition, parsingContext); if (!nonTerminalResult.IsError) { errors.AddRange(nonTerminalResult.GetErrors()); @@ -154,7 +154,7 @@ public override SyntaxParseResult Parse(IList> tokens, Rule ru node.ExpressionAffix = rule.ExpressionAffix; node = ManageExpressionRules(rule, node); result.Root = node; - result.IsEnded = tokens[result.EndingPosition].IsEOS + result.IsEnded = tokens[result.EndingPosition].IsEOS || node.IsEpsilon && tokens[result.EndingPosition+1].IsEOS; } } diff --git a/src/sly/sly.csproj b/src/sly/sly.csproj index d2902c67..497c140e 100644 --- a/src/sly/sly.csproj +++ b/src/sly/sly.csproj @@ -37,7 +37,7 @@ all - + diff --git a/tests/ParserTests/samples/XmlTests.cs b/tests/ParserTests/samples/XmlTests.cs new file mode 100644 index 00000000..2ea1ac80 --- /dev/null +++ b/tests/ParserTests/samples/XmlTests.cs @@ -0,0 +1,34 @@ +using NFluent; +using sly.parser; +using sly.parser.generator; +using XML; +using Xunit; + +namespace ParserTests.samples; + +public class XmlTests +{ + + [Fact] + public void TestXmlParserWithLexerModes() + { + ParserBuilder builder = new ParserBuilder(); + var xmlparser = new MinimalXmlParser(); + var r = builder.BuildParser(xmlparser, ParserType.EBNF_LL_RECURSIVE_DESCENT, "document"); + Check.That(r.IsError).IsFalse(); + var parser = r.Result; + var parsed = parser.Parse(@" + + + + + + + + inner inner content +"); + Check.That(parsed).Not.IsOkParsing(); + var error = parsed.Errors[0]; + Check.That(error.ErrorType).IsEqualTo(ErrorType.UnexpectedEOS); + } +} \ No newline at end of file