From bba2730f6880059af5b66b3ff6feca9870ed8d66 Mon Sep 17 00:00:00 2001 From: b3b00 Date: Tue, 30 Jul 2024 15:50:18 +0200 Subject: [PATCH 1/3] split BNF and EBNF parsers into partial for better readability --- .../EBNFRecursiveDescentSyntaxParser.cs | 443 ------------------ .../llparser/RecursiveDescentSyntaxParser.cs | 201 -------- ...ecursiveDescentSyntaxParser.Expressions.cs | 59 +++ ...ecursiveDescentSyntaxParser.NonTerminal.cs | 141 ++++++ .../RecursiveDescentSyntaxParser.Terminal.cs | 40 ++ ...EBNFRecursiveDescentSyntaxParser.Choice.cs | 72 +++ ...ecursiveDescentSyntaxParser.Expressions.cs | 147 ++++++ .../EBNFRecursiveDescentSyntaxParser.Many.cs | 188 ++++++++ ...EBNFRecursiveDescentSyntaxParser.Option.cs | 100 ++++ 9 files changed, 747 insertions(+), 644 deletions(-) create mode 100644 src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.Expressions.cs create mode 100644 src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.NonTerminal.cs create mode 100644 src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.Terminal.cs create mode 100644 src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.EBNFRecursiveDescentSyntaxParser.Choice.cs create mode 100644 src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.Expressions.cs create mode 100644 src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.Many.cs create mode 100644 src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.Option.cs diff --git a/src/sly/parser/parser/llparser/EBNFRecursiveDescentSyntaxParser.cs b/src/sly/parser/parser/llparser/EBNFRecursiveDescentSyntaxParser.cs index 0547b972..5f88d977 100644 --- a/src/sly/parser/parser/llparser/EBNFRecursiveDescentSyntaxParser.cs +++ b/src/sly/parser/parser/llparser/EBNFRecursiveDescentSyntaxParser.cs @@ -161,449 +161,6 @@ public override SyntaxParseResult Parse(IList> tokens, Rule ru return result; } - - public virtual SyntaxParseResult ParseInfixExpressionRule(IList> tokens, Rule rule, - int position, - string nonTerminalName, SyntaxParsingContext parsingContext) - { - var currentPosition = position; - var errors = new List>(); - var isError = false; - var children = new List>(); - if (!tokens[position].IsEOS && rule.Match(tokens,position,Configuration)) - if (rule.Clauses != null && rule.Clauses.Count > 0) - { - if (MatchExpressionRuleScheme(rule)) - { - var first = rule.Clauses[0]; - SyntaxParseResult firstResult = null; - if (first is NonTerminalClause firstNonTerminal) - { - firstResult = ParseNonTerminal(tokens, firstNonTerminal, currentPosition, parsingContext); - - if (firstResult.IsError) - { - return firstResult; - } - } - - currentPosition = firstResult.EndingPosition; - var second = rule.Clauses[1]; - SyntaxParseResult secondResult = null; - switch (second) - { - case ChoiceClause secondChoice: - { - secondResult = ParseChoice(tokens, secondChoice, currentPosition, parsingContext); - - if (secondResult.IsError) - { - if (firstResult.Root is SyntaxNode) - { - firstResult.Errors.AddRange(secondResult.Errors); - firstResult.AddExpectings(secondResult.Expecting); - return firstResult; - } - } - else - { - currentPosition = secondResult.EndingPosition; - } - - break; - } - case TerminalClause secondTerminal: - { - secondResult = ParseTerminal(tokens, secondTerminal, currentPosition, parsingContext); - - if (secondResult.IsError) - { - if (firstResult.Root is SyntaxNode) - { - firstResult.Errors.AddRange(secondResult.Errors); - firstResult.AddExpectings(secondResult.Expecting); - return firstResult; - } - } - - break; - } - } - - - currentPosition = secondResult.EndingPosition; - var third = rule.Clauses[2]; - SyntaxParseResult thirdResult; - if (third is NonTerminalClause thirdNonTerminal) - { - thirdResult = ParseNonTerminal(tokens, thirdNonTerminal, currentPosition, parsingContext); - if (thirdResult.IsError) - { - return thirdResult; - } - else - { - children = new List>(); - children.Add(firstResult.Root); - children.Add(secondResult.Root); - children.Add(thirdResult.Root); - currentPosition = thirdResult.EndingPosition; - var finalNode = new SyntaxNode( nonTerminalName, children); - finalNode.ExpressionAffix = rule.ExpressionAffix; - finalNode = ManageExpressionRules(rule, finalNode); - var finalResult = new SyntaxParseResult(); - finalResult.Root = finalNode; - finalResult.IsEnded = currentPosition >= tokens.Count - 1 - || currentPosition == tokens.Count - 2 && - tokens[tokens.Count - 1].IsEOS; - finalResult.EndingPosition = currentPosition; - return finalResult; - } - } - } - } - - var result = new SyntaxParseResult(); - result.IsError = isError; - result.Errors = errors; - result.EndingPosition = currentPosition; - if (!isError) - { - SyntaxNode node = null; - if (rule.IsSubRule) - node = new GroupSyntaxNode(nonTerminalName, children); - else - node = new SyntaxNode( nonTerminalName, children); - node = ManageExpressionRules(rule, node); - if (node.IsByPassNode) // inutile de créer un niveau supplémentaire - result.Root = children[0]; - result.Root = node; - result.IsEnded = result.EndingPosition >= tokens.Count - 1 - || result.EndingPosition == tokens.Count - 2 && - tokens[tokens.Count - 1].IsEOS; - - } - - - return result; - } - - private static bool MatchExpressionRuleScheme(Rule rule) - { - return rule.Clauses.Count == 3 - && rule.Clauses[0] is NonTerminalClause - && (rule.Clauses[1] is ChoiceClause || - rule.Clauses[1] is TerminalClause) - && rule.Clauses[2] is NonTerminalClause; - } - - public SyntaxParseResult ParseZeroOrMore(IList> tokens, ZeroOrMoreClause clause, int position, - SyntaxParsingContext parsingContext) - { - if (parsingContext.TryGetParseResult(clause, position, out var parseResult)) - { - return parseResult; - } - var result = new SyntaxParseResult(); - var manyNode = new ManySyntaxNode($"{clause.Clause.ToString()}*"); - var currentPosition = position; - var innerClause = clause.Clause; - var stillOk = true; - - - SyntaxParseResult lastInnerResult = null; - - var innerErrors = new List>(); - - bool hasByPasNodes = false; - while (stillOk) - { - SyntaxParseResult innerResult = null; - switch (innerClause) - { - case TerminalClause term: - manyNode.IsManyTokens = true; - innerResult = ParseTerminal(tokens, term, currentPosition,parsingContext); - hasByPasNodes = hasByPasNodes || innerResult.HasByPassNodes; - break; - case NonTerminalClause nonTerm: - { - innerResult = ParseNonTerminal(tokens, nonTerm, currentPosition, parsingContext); - hasByPasNodes = hasByPasNodes || innerResult.HasByPassNodes; - if (nonTerm.IsGroup) - manyNode.IsManyGroups = true; - else - manyNode.IsManyValues = true; - break; - } - case GroupClause _: - manyNode.IsManyGroups = true; - innerResult = ParseNonTerminal(tokens, innerClause as NonTerminalClause, currentPosition, parsingContext); - hasByPasNodes = hasByPasNodes || innerResult.HasByPassNodes; - break; - case ChoiceClause choice: - manyNode.IsManyTokens = choice.IsTerminalChoice; - manyNode.IsManyValues = choice.IsNonTerminalChoice; - innerResult = ParseChoice(tokens, choice, currentPosition, parsingContext); - hasByPasNodes = hasByPasNodes || innerResult.HasByPassNodes; - break; - default: - throw new InvalidOperationException("unable to apply repeater to " + innerClause.GetType().Name); - } - - if (innerResult != null && !innerResult.IsError) - { - manyNode.Add(innerResult.Root); - currentPosition = innerResult.EndingPosition; - lastInnerResult = innerResult; - hasByPasNodes = hasByPasNodes || innerResult.HasByPassNodes; - innerErrors.AddRange(lastInnerResult.Errors); - } - else - { - if (innerResult != null) - { - innerErrors.AddRange(innerResult.Errors); - } - } - stillOk = innerResult != null && !innerResult.IsError && currentPosition < tokens.Count; - } - - - result.EndingPosition = currentPosition; - result.IsError = false; - result.Errors = innerErrors; - result.Root = manyNode; - result.IsEnded = lastInnerResult != null && lastInnerResult.IsEnded; - result.HasByPassNodes = hasByPasNodes; - parsingContext.Memoize(clause,position,result); - return result; - } - - public SyntaxParseResult ParseOneOrMore(IList> tokens, OneOrMoreClause clause, int position, - SyntaxParsingContext parsingContext) - { - if (parsingContext.TryGetParseResult(clause, position, out var parseResult)) - { - return parseResult; - } - - var result = new SyntaxParseResult(); - var manyNode = new ManySyntaxNode($"{clause.Clause.ToString()}+"); - var currentPosition = position; - var innerClause = clause.Clause; - bool isError; - - SyntaxParseResult lastInnerResult = null; - - bool hasByPasNodes = false; - SyntaxParseResult firstInnerResult = null; - var innerErrors = new List>(); - - switch (innerClause) - { - case TerminalClause terminalClause: - manyNode.IsManyTokens = true; - firstInnerResult = ParseTerminal(tokens, terminalClause, currentPosition, parsingContext); - hasByPasNodes = hasByPasNodes || firstInnerResult.HasByPassNodes; - break; - case NonTerminalClause nonTerm: - { - firstInnerResult = ParseNonTerminal(tokens, nonTerm, currentPosition, parsingContext); - hasByPasNodes = hasByPasNodes || firstInnerResult.HasByPassNodes; - if (nonTerm.IsGroup) - manyNode.IsManyGroups = true; - else - manyNode.IsManyValues = true; - break; - } - case ChoiceClause choice: - manyNode.IsManyTokens = choice.IsTerminalChoice; - manyNode.IsManyValues = choice.IsNonTerminalChoice; - firstInnerResult = ParseChoice(tokens, choice, currentPosition, parsingContext); - hasByPasNodes = hasByPasNodes || firstInnerResult.HasByPassNodes; - break; - default: - throw new InvalidOperationException("unable to apply repeater to " + innerClause.GetType().Name); - } - - if (firstInnerResult != null && !firstInnerResult.IsError) - { - manyNode.Add(firstInnerResult.Root); - lastInnerResult = firstInnerResult; - currentPosition = firstInnerResult.EndingPosition; - var more = new ZeroOrMoreClause(innerClause); - var nextResult = ParseZeroOrMore(tokens, more, currentPosition, parsingContext); - if (nextResult != null && !nextResult.IsError) - { - currentPosition = nextResult.EndingPosition; - var moreChildren = (ManySyntaxNode) nextResult.Root; - manyNode.Children.AddRange(moreChildren.Children); - } - if (nextResult != null) - { - innerErrors.AddRange(nextResult.Errors); - } - - isError = false; - } - else - { - if (firstInnerResult != null) - { - innerErrors.AddRange(firstInnerResult.Errors); - } - isError = true; - } - - result.EndingPosition = currentPosition; - result.IsError = isError; - result.Errors = innerErrors; - result.Root = manyNode; - result.IsEnded = lastInnerResult != null && lastInnerResult.IsEnded; - result.HasByPassNodes = hasByPasNodes; - parsingContext.Memoize(clause,position,result); - return result; - } - - public SyntaxParseResult ParseOption(IList> tokens, OptionClause clause, Rule rule, - int position, SyntaxParsingContext parsingContext) - { - if (parsingContext.TryGetParseResult(clause, position, out var parseResult)) - { - return parseResult; - } - var result = new SyntaxParseResult(); - var currentPosition = position; - var innerClause = clause.Clause; - - SyntaxParseResult innerResult = null; - - switch (innerClause) - { - case TerminalClause term: - innerResult = ParseTerminal(tokens, term, currentPosition, parsingContext); - break; - case NonTerminalClause nonTerm: - innerResult = ParseNonTerminal(tokens, nonTerm, currentPosition, parsingContext); - break; - case ChoiceClause choice: - innerResult = ParseChoice(tokens, choice, currentPosition, parsingContext); - break; - default: - throw new InvalidOperationException("unable to apply repeater to " + innerClause.GetType().Name); - } - - - if (innerResult.IsError) - { - switch (innerClause) - { - case TerminalClause _: - result = new SyntaxParseResult(); - result.IsError = true; - result.Root = new SyntaxLeaf(Token.Empty(),false); - result.EndingPosition = position; - break; - case ChoiceClause choiceClause: - { - if (choiceClause.IsTerminalChoice) - { - result = new SyntaxParseResult(); - result.IsError = false; - result.Root = new SyntaxLeaf(Token.Empty(),false); - result.EndingPosition = position; - } - else if (choiceClause.IsNonTerminalChoice) - { - result = new SyntaxParseResult(); - result.IsError = false; - result.Root = new SyntaxEpsilon(); - result.EndingPosition = position; - } - - break; - } - default: - { - result = new SyntaxParseResult(); - result.IsError = true; - var children = new List> {innerResult.Root}; - if (innerResult.IsError) children.Clear(); - result.Root = new OptionSyntaxNode( rule.NonTerminalName, children, - rule.GetVisitor()); - (result.Root as OptionSyntaxNode).IsGroupOption = clause.IsGroupOption; - result.EndingPosition = position; - break; - } - } - } - else - { - var children = new List> {innerResult.Root}; - result.Root = - new OptionSyntaxNode( rule.NonTerminalName,children, rule.GetVisitor()); - result.EndingPosition = innerResult.EndingPosition; - result.HasByPassNodes = innerResult.HasByPassNodes; - } - - parsingContext.Memoize(clause, position, result); - return result; - } - - public SyntaxParseResult ParseChoice(IList> tokens, ChoiceClause clause, - int position, SyntaxParsingContext parsingContext) - { - if (parsingContext.TryGetParseResult(clause, position, out var parseResult)) - { - return parseResult; - } - var currentPosition = position; - - SyntaxParseResult result = new SyntaxParseResult - { - IsError = true, - IsEnded = false, - EndingPosition = currentPosition - }; - - - foreach (var alternate in clause.Choices) - { - switch (alternate) - { - case TerminalClause terminalAlternate: - result = ParseTerminal(tokens, terminalAlternate, currentPosition, parsingContext); - break; - case NonTerminalClause nonTerminalAlternate: - result = ParseNonTerminal(tokens, nonTerminalAlternate, currentPosition, parsingContext); - break; - default: - throw new InvalidOperationException("unable to apply repeater inside " + clause.GetType().Name); - } - - if (result.IsOk) - { - if (clause.IsTerminalChoice && clause.IsDiscarded && result.Root is SyntaxLeaf leaf) - { - var discardedToken = new SyntaxLeaf(leaf.Token, true); - result.Root = discardedToken; - } - parsingContext.Memoize(clause,position,result); - return result; - } - } - - if (result.IsError && clause.IsTerminalChoice) - { - var terminalAlternates = clause.Choices.Cast>(); - var expected = terminalAlternates.Select(x => x.ExpectedToken).ToList(); - result.Errors.Add(new UnexpectedTokenSyntaxError(tokens[currentPosition], LexemeLabels, I18n,expected.ToArray())); - } - parsingContext.Memoize(clause,position,result); - return result; - } - #endregion } } \ No newline at end of file diff --git a/src/sly/parser/parser/llparser/RecursiveDescentSyntaxParser.cs b/src/sly/parser/parser/llparser/RecursiveDescentSyntaxParser.cs index 3f824ff4..9ae3a119 100644 --- a/src/sly/parser/parser/llparser/RecursiveDescentSyntaxParser.cs +++ b/src/sly/parser/parser/llparser/RecursiveDescentSyntaxParser.cs @@ -206,209 +206,8 @@ public virtual SyntaxParseResult Parse(IList> tokens, Rule rul return result; } - protected SyntaxNode ManageExpressionRules(Rule rule, SyntaxNode node) - { - var operatorIndex = -1; - switch (rule.IsExpressionRule) - { - case true when rule.IsByPassRule: - node.IsByPassNode = true; - node.HasByPassNodes = true; - break; - case true when !rule.IsByPassRule: - { - node.ExpressionAffix = rule.ExpressionAffix; - switch (node.Children.Count) - { - case 3: - operatorIndex = 1; - break; - case 2 when node.ExpressionAffix == Affix.PreFix: - operatorIndex = 0; - break; - case 2: - { - if (node.ExpressionAffix == Affix.PostFix) operatorIndex = 1; - break; - } - } - - if (operatorIndex >= 0) - if (node.Children[operatorIndex] is SyntaxLeaf operatorNode) - if (operatorNode != null) - { - var visitor = rule.GetVisitor(operatorNode.Token.TokenID); - if (visitor != null) - { - node.Visitor = visitor; - node.Operation = rule.GetOperation(operatorNode.Token.TokenID); - } - } - - break; - } - case false: - node.Visitor = rule.GetVisitor(); - break; - } - - return node; - } - - public SyntaxParseResult ParseTerminal(IList> tokens, TerminalClause terminal, int position, - SyntaxParsingContext parsingContext) - { - if (parsingContext.TryGetParseResult(terminal, position, out var parseResult)) - { - return parseResult; - } - var result = new SyntaxParseResult(); - result.IsError = !terminal.Check(tokens[position]); - result.EndingPosition = !result.IsError ? position + 1 : position; - var token = tokens[position]; - token.Discarded = terminal.Discarded; - token.IsExplicit = terminal.IsExplicitToken; - result.Root = new SyntaxLeaf(token, terminal.Discarded); - result.HasByPassNodes = false; - if (result.IsError) - { - result.Errors.Add( - new UnexpectedTokenSyntaxError(token, LexemeLabels, I18n, terminal.ExpectedToken)); - result.AddExpecting(terminal.ExpectedToken); - } - parsingContext.Memoize(terminal,position,result); - return result; - } - - - - public SyntaxParseResult ParseNonTerminal(IList> tokens, NonTerminalClause nonTermClause, - int currentPosition, SyntaxParsingContext parsingContext) - { - var result = ParseNonTerminal(tokens, nonTermClause.NonTerminalName, currentPosition, parsingContext); - return result; - } - - - public SyntaxParseResult ParseNonTerminal(IList> tokens, string nonTerminalName, - int currentPosition, SyntaxParsingContext parsingContext) - { - if (parsingContext.TryGetParseResult(new NonTerminalClause(nonTerminalName),currentPosition, out var memoizedResult)) - { - return memoizedResult; - } - var startPosition = currentPosition; - var nt = Configuration.NonTerminals[nonTerminalName]; - var errors = new List>(); - - var i = 0; - var rules = nt.Rules; - - var innerRuleErrors = new List>(); - var greaterIndex = 0; - var rulesResults = new List>(); - while (i < rules.Count) - { - var innerrule = rules[i]; - if (startPosition < tokens.Count && !tokens[startPosition].IsEOS && - innerrule.Match(tokens,startPosition,Configuration)) - { - var innerRuleRes = Parse(tokens, innerrule, startPosition, nonTerminalName, parsingContext); - rulesResults.Add(innerRuleRes); - var other = greaterIndex == 0 && innerRuleRes.EndingPosition == 0; - if (innerRuleRes.EndingPosition > greaterIndex && innerRuleRes.Errors != null && - innerRuleRes.Errors.Count == 0 || other) - { - greaterIndex = innerRuleRes.EndingPosition; - //innerRuleErrors.Clear(); - innerRuleErrors.AddRange(innerRuleRes.Errors); - } - - innerRuleErrors.AddRange(innerRuleRes.Errors); - } - - i++; - } - - if (rulesResults.Count == 0) - { - var allAcceptableTokens = new List>(); - nt.Rules.ForEach(r => - { - if (r != null && r.PossibleLeadingTokens != null) - allAcceptableTokens.AddRange(r.PossibleLeadingTokens); - }); - // allAcceptableTokens = allAcceptableTokens.ToList(); - - var noMatching = NoMatchingRuleError(tokens, currentPosition, allAcceptableTokens); - parsingContext.Memoize(new NonTerminalClause(nonTerminalName),currentPosition,noMatching); - return noMatching; - } - - errors.AddRange(innerRuleErrors); - SyntaxParseResult max = null; - int okEndingPosition = -1; - int koEndingPosition = -1; - bool hasOk = false; - SyntaxParseResult maxOk = null; - SyntaxParseResult maxKo = null; - foreach (var rulesResult in rulesResults) - { - if (rulesResult.IsOk) - { - hasOk = true; - if (rulesResult.EndingPosition > okEndingPosition) - { - okEndingPosition = rulesResult.EndingPosition; - maxOk = rulesResult; - } - } - - if (rulesResult.IsError) - { - if (rulesResult.EndingPosition > koEndingPosition) - { - koEndingPosition = rulesResult.EndingPosition; - maxKo = rulesResult; - } - } - } - - if (hasOk) - { - max = maxOk; - } - else - { - max = maxKo; - } - - - var result = new SyntaxParseResult(); - result.Errors = errors; - result.Root = max.Root; - result.EndingPosition = max.EndingPosition; - result.IsError = max.IsError; - result.IsEnded = max.IsEnded; - result.HasByPassNodes = max.HasByPassNodes; - - if (rulesResults.Count > 0) - { - List> terr = new List>(); - foreach (var ruleResult in rulesResults) - { - terr.AddRange(ruleResult.Errors); - foreach (var err in ruleResult.Errors) - { - result.AddExpectings(err.ExpectedTokens); - } - } - } - parsingContext.Memoize(new NonTerminalClause(nonTerminalName),currentPosition,result); - return result; - } private SyntaxParseResult NoMatchingRuleError(IList> tokens, int currentPosition, List> allAcceptableTokens) diff --git a/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.Expressions.cs b/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.Expressions.cs new file mode 100644 index 00000000..200ac90c --- /dev/null +++ b/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.Expressions.cs @@ -0,0 +1,59 @@ +using sly.parser.generator; +using sly.parser.syntax.grammar; +using sly.parser.syntax.tree; + +namespace sly.parser.llparser; + +public partial class RecursiveDescentSyntaxParser +{ + + protected SyntaxNode ManageExpressionRules(Rule rule, SyntaxNode node) + { + var operatorIndex = -1; + switch (rule.IsExpressionRule) + { + case true when rule.IsByPassRule: + node.IsByPassNode = true; + node.HasByPassNodes = true; + break; + case true when !rule.IsByPassRule: + { + node.ExpressionAffix = rule.ExpressionAffix; + switch (node.Children.Count) + { + case 3: + operatorIndex = 1; + break; + case 2 when node.ExpressionAffix == Affix.PreFix: + operatorIndex = 0; + break; + case 2: + { + if (node.ExpressionAffix == Affix.PostFix) operatorIndex = 1; + break; + } + } + + if (operatorIndex >= 0) + if (node.Children[operatorIndex] is SyntaxLeaf operatorNode) + if (operatorNode != null) + { + var visitor = rule.GetVisitor(operatorNode.Token.TokenID); + if (visitor != null) + { + node.Visitor = visitor; + node.Operation = rule.GetOperation(operatorNode.Token.TokenID); + } + } + + break; + } + case false: + node.Visitor = rule.GetVisitor(); + break; + } + + return node; + } + +} \ No newline at end of file diff --git a/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.NonTerminal.cs b/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.NonTerminal.cs new file mode 100644 index 00000000..2c96e464 --- /dev/null +++ b/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.NonTerminal.cs @@ -0,0 +1,141 @@ +using System.Collections.Generic; +using sly.lexer; +using sly.parser.syntax.grammar; + +namespace sly.parser.llparser; + +public partial class RecursiveDescentSyntaxParser +{ + #region parsing + + public SyntaxParseResult ParseNonTerminal(IList> tokens, NonTerminalClause nonTermClause, + int currentPosition, SyntaxParsingContext parsingContext) + { + var result = ParseNonTerminal(tokens, nonTermClause.NonTerminalName, currentPosition, parsingContext); + return result; + } + + public SyntaxParseResult ParseNonTerminal(IList> tokens, string nonTerminalName, + int currentPosition, SyntaxParsingContext parsingContext) + { + if (parsingContext.TryGetParseResult(new NonTerminalClause(nonTerminalName), currentPosition, + out var memoizedResult)) + { + return memoizedResult; + } + + var startPosition = currentPosition; + var nt = Configuration.NonTerminals[nonTerminalName]; + var errors = new List>(); + + var i = 0; + var rules = nt.Rules; + + var innerRuleErrors = new List>(); + var greaterIndex = 0; + var rulesResults = new List>(); + while (i < rules.Count) + { + var innerrule = rules[i]; + if (startPosition < tokens.Count && !tokens[startPosition].IsEOS && + innerrule.Match(tokens, startPosition, Configuration)) + { + var innerRuleRes = Parse(tokens, innerrule, startPosition, nonTerminalName, parsingContext); + rulesResults.Add(innerRuleRes); + + var other = greaterIndex == 0 && innerRuleRes.EndingPosition == 0; + if (innerRuleRes.EndingPosition > greaterIndex && innerRuleRes.Errors != null && + innerRuleRes.Errors.Count == 0 || other) + { + greaterIndex = innerRuleRes.EndingPosition; + //innerRuleErrors.Clear(); + innerRuleErrors.AddRange(innerRuleRes.Errors); + } + + innerRuleErrors.AddRange(innerRuleRes.Errors); + } + + i++; + } + + if (rulesResults.Count == 0) + { + var allAcceptableTokens = new List>(); + nt.Rules.ForEach(r => + { + if (r != null && r.PossibleLeadingTokens != null) + allAcceptableTokens.AddRange(r.PossibleLeadingTokens); + }); + // allAcceptableTokens = allAcceptableTokens.ToList(); + + var noMatching = NoMatchingRuleError(tokens, currentPosition, allAcceptableTokens); + parsingContext.Memoize(new NonTerminalClause(nonTerminalName), currentPosition, noMatching); + return noMatching; + } + + errors.AddRange(innerRuleErrors); + SyntaxParseResult max = null; + int okEndingPosition = -1; + int koEndingPosition = -1; + bool hasOk = false; + SyntaxParseResult maxOk = null; + SyntaxParseResult maxKo = null; + foreach (var rulesResult in rulesResults) + { + if (rulesResult.IsOk) + { + hasOk = true; + if (rulesResult.EndingPosition > okEndingPosition) + { + okEndingPosition = rulesResult.EndingPosition; + maxOk = rulesResult; + } + } + + if (rulesResult.IsError) + { + if (rulesResult.EndingPosition > koEndingPosition) + { + koEndingPosition = rulesResult.EndingPosition; + maxKo = rulesResult; + } + } + } + + if (hasOk) + { + max = maxOk; + } + else + { + max = maxKo; + } + + + var result = new SyntaxParseResult(); + result.Errors = errors; + result.Root = max.Root; + result.EndingPosition = max.EndingPosition; + result.IsError = max.IsError; + result.IsEnded = max.IsEnded; + result.HasByPassNodes = max.HasByPassNodes; + + if (rulesResults.Count > 0) + { + List> terr = new List>(); + foreach (var ruleResult in rulesResults) + { + terr.AddRange(ruleResult.Errors); + foreach (var err in ruleResult.Errors) + { + result.AddExpectings(err.ExpectedTokens); + } + } + } + + parsingContext.Memoize(new NonTerminalClause(nonTerminalName), currentPosition, result); + return result; + } + + #endregion +} \ No newline at end of file diff --git a/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.Terminal.cs b/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.Terminal.cs new file mode 100644 index 00000000..b92b6b2f --- /dev/null +++ b/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.Terminal.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using sly.lexer; +using sly.parser.syntax.grammar; +using sly.parser.syntax.tree; + +namespace sly.parser.llparser; + +public partial class RecursiveDescentSyntaxParser +{ + #region parsing + + public SyntaxParseResult ParseTerminal(IList> tokens, TerminalClause terminal, int position, + SyntaxParsingContext parsingContext) + { + if (parsingContext.TryGetParseResult(terminal, position, out var parseResult)) + { + return parseResult; + } + + var result = new SyntaxParseResult(); + result.IsError = !terminal.Check(tokens[position]); + result.EndingPosition = !result.IsError ? position + 1 : position; + var token = tokens[position]; + token.Discarded = terminal.Discarded; + token.IsExplicit = terminal.IsExplicitToken; + result.Root = new SyntaxLeaf(token, terminal.Discarded); + result.HasByPassNodes = false; + if (result.IsError) + { + result.Errors.Add( + new UnexpectedTokenSyntaxError(token, LexemeLabels, I18n, terminal.ExpectedToken)); + result.AddExpecting(terminal.ExpectedToken); + } + + parsingContext.Memoize(terminal, position, result); + return result; + } + + #endregion +} \ No newline at end of file diff --git a/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.EBNFRecursiveDescentSyntaxParser.Choice.cs b/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.EBNFRecursiveDescentSyntaxParser.Choice.cs new file mode 100644 index 00000000..b5096264 --- /dev/null +++ b/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.EBNFRecursiveDescentSyntaxParser.Choice.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using sly.lexer; +using sly.parser.syntax.grammar; +using sly.parser.syntax.tree; + +namespace sly.parser.llparser; + +public partial class EBNFRecursiveDescentSyntaxParser +{ + #region parsing + + public SyntaxParseResult ParseChoice(IList> tokens, ChoiceClause clause, + int position, SyntaxParsingContext parsingContext) + { + if (parsingContext.TryGetParseResult(clause, position, out var parseResult)) + { + return parseResult; + } + + var currentPosition = position; + + SyntaxParseResult result = new SyntaxParseResult + { + IsError = true, + IsEnded = false, + EndingPosition = currentPosition + }; + + + foreach (var alternate in clause.Choices) + { + switch (alternate) + { + case TerminalClause terminalAlternate: + result = ParseTerminal(tokens, terminalAlternate, currentPosition, parsingContext); + break; + case NonTerminalClause nonTerminalAlternate: + result = ParseNonTerminal(tokens, nonTerminalAlternate, currentPosition, parsingContext); + break; + default: + throw new InvalidOperationException("unable to apply repeater inside " + clause.GetType().Name); + } + + if (result.IsOk) + { + if (clause.IsTerminalChoice && clause.IsDiscarded && result.Root is SyntaxLeaf leaf) + { + var discardedToken = new SyntaxLeaf(leaf.Token, true); + result.Root = discardedToken; + } + + parsingContext.Memoize(clause, position, result); + return result; + } + } + + if (result.IsError && clause.IsTerminalChoice) + { + var terminalAlternates = clause.Choices.Cast>(); + var expected = terminalAlternates.Select(x => x.ExpectedToken).ToList(); + result.Errors.Add(new UnexpectedTokenSyntaxError(tokens[currentPosition], LexemeLabels, I18n, + expected.ToArray())); + } + + parsingContext.Memoize(clause, position, result); + return result; + } + + #endregion +} \ No newline at end of file diff --git a/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.Expressions.cs b/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.Expressions.cs new file mode 100644 index 00000000..f74256e9 --- /dev/null +++ b/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.Expressions.cs @@ -0,0 +1,147 @@ +using System.Collections.Generic; +using sly.lexer; +using sly.parser.syntax.grammar; +using sly.parser.syntax.tree; + +namespace sly.parser.llparser; + +public partial class EBNFRecursiveDescentSyntaxParser +{ + #region parsing + + public virtual SyntaxParseResult ParseInfixExpressionRule(IList> tokens, Rule rule, + int position, + string nonTerminalName, SyntaxParsingContext parsingContext) + { + var currentPosition = position; + var errors = new List>(); + var isError = false; + var children = new List>(); + if (!tokens[position].IsEOS && rule.Match(tokens, position, Configuration)) + if (rule.Clauses != null && rule.Clauses.Count > 0) + { + if (MatchExpressionRuleScheme(rule)) + { + var first = rule.Clauses[0]; + SyntaxParseResult firstResult = null; + if (first is NonTerminalClause firstNonTerminal) + { + firstResult = ParseNonTerminal(tokens, firstNonTerminal, currentPosition, parsingContext); + + if (firstResult.IsError) + { + return firstResult; + } + } + + currentPosition = firstResult.EndingPosition; + var second = rule.Clauses[1]; + SyntaxParseResult secondResult = null; + switch (second) + { + case ChoiceClause secondChoice: + { + secondResult = ParseChoice(tokens, secondChoice, currentPosition, parsingContext); + + if (secondResult.IsError) + { + if (firstResult.Root is SyntaxNode) + { + firstResult.Errors.AddRange(secondResult.Errors); + firstResult.AddExpectings(secondResult.Expecting); + return firstResult; + } + } + else + { + currentPosition = secondResult.EndingPosition; + } + + break; + } + case TerminalClause secondTerminal: + { + secondResult = ParseTerminal(tokens, secondTerminal, currentPosition, parsingContext); + + if (secondResult.IsError) + { + if (firstResult.Root is SyntaxNode) + { + firstResult.Errors.AddRange(secondResult.Errors); + firstResult.AddExpectings(secondResult.Expecting); + return firstResult; + } + } + + break; + } + } + + + currentPosition = secondResult.EndingPosition; + var third = rule.Clauses[2]; + SyntaxParseResult thirdResult; + if (third is NonTerminalClause thirdNonTerminal) + { + thirdResult = ParseNonTerminal(tokens, thirdNonTerminal, currentPosition, parsingContext); + if (thirdResult.IsError) + { + return thirdResult; + } + else + { + children = new List>(); + children.Add(firstResult.Root); + children.Add(secondResult.Root); + children.Add(thirdResult.Root); + currentPosition = thirdResult.EndingPosition; + var finalNode = new SyntaxNode(nonTerminalName, children); + finalNode.ExpressionAffix = rule.ExpressionAffix; + finalNode = ManageExpressionRules(rule, finalNode); + var finalResult = new SyntaxParseResult(); + finalResult.Root = finalNode; + finalResult.IsEnded = currentPosition >= tokens.Count - 1 + || currentPosition == tokens.Count - 2 && + tokens[tokens.Count - 1].IsEOS; + finalResult.EndingPosition = currentPosition; + return finalResult; + } + } + } + } + + var result = new SyntaxParseResult(); + result.IsError = isError; + result.Errors = errors; + result.EndingPosition = currentPosition; + if (!isError) + { + SyntaxNode node = null; + if (rule.IsSubRule) + node = new GroupSyntaxNode(nonTerminalName, children); + else + node = new SyntaxNode(nonTerminalName, children); + node = ManageExpressionRules(rule, node); + if (node.IsByPassNode) // inutile de créer un niveau supplémentaire + result.Root = children[0]; + result.Root = node; + result.IsEnded = result.EndingPosition >= tokens.Count - 1 + || result.EndingPosition == tokens.Count - 2 && + tokens[tokens.Count - 1].IsEOS; + } + + + return result; + } + + private static bool MatchExpressionRuleScheme(Rule rule) + { + return rule.Clauses.Count == 3 + && rule.Clauses[0] is NonTerminalClause + && (rule.Clauses[1] is ChoiceClause || + rule.Clauses[1] is TerminalClause) + && rule.Clauses[2] is NonTerminalClause; + } + + #endregion +} \ No newline at end of file diff --git a/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.Many.cs b/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.Many.cs new file mode 100644 index 00000000..12aa6aea --- /dev/null +++ b/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.Many.cs @@ -0,0 +1,188 @@ +using System; +using System.Collections.Generic; +using sly.lexer; +using sly.parser.syntax.grammar; +using sly.parser.syntax.tree; + +namespace sly.parser.llparser; + +public partial class EBNFRecursiveDescentSyntaxParser +{ + #region parsing + + public SyntaxParseResult ParseZeroOrMore(IList> tokens, ZeroOrMoreClause clause, int position, + SyntaxParsingContext parsingContext) + { + if (parsingContext.TryGetParseResult(clause, position, out var parseResult)) + { + return parseResult; + } + + var result = new SyntaxParseResult(); + var manyNode = new ManySyntaxNode($"{clause.Clause.ToString()}*"); + var currentPosition = position; + var innerClause = clause.Clause; + var stillOk = true; + + + SyntaxParseResult lastInnerResult = null; + + var innerErrors = new List>(); + + bool hasByPasNodes = false; + while (stillOk) + { + SyntaxParseResult innerResult = null; + switch (innerClause) + { + case TerminalClause term: + manyNode.IsManyTokens = true; + innerResult = ParseTerminal(tokens, term, currentPosition, parsingContext); + hasByPasNodes = hasByPasNodes || innerResult.HasByPassNodes; + break; + case NonTerminalClause nonTerm: + { + innerResult = ParseNonTerminal(tokens, nonTerm, currentPosition, parsingContext); + hasByPasNodes = hasByPasNodes || innerResult.HasByPassNodes; + if (nonTerm.IsGroup) + manyNode.IsManyGroups = true; + else + manyNode.IsManyValues = true; + break; + } + case GroupClause _: + manyNode.IsManyGroups = true; + innerResult = ParseNonTerminal(tokens, innerClause as NonTerminalClause, currentPosition, + parsingContext); + hasByPasNodes = hasByPasNodes || innerResult.HasByPassNodes; + break; + case ChoiceClause choice: + manyNode.IsManyTokens = choice.IsTerminalChoice; + manyNode.IsManyValues = choice.IsNonTerminalChoice; + innerResult = ParseChoice(tokens, choice, currentPosition, parsingContext); + hasByPasNodes = hasByPasNodes || innerResult.HasByPassNodes; + break; + default: + throw new InvalidOperationException("unable to apply repeater to " + innerClause.GetType().Name); + } + + if (innerResult != null && !innerResult.IsError) + { + manyNode.Add(innerResult.Root); + currentPosition = innerResult.EndingPosition; + lastInnerResult = innerResult; + hasByPasNodes = hasByPasNodes || innerResult.HasByPassNodes; + innerErrors.AddRange(lastInnerResult.Errors); + } + else + { + if (innerResult != null) + { + innerErrors.AddRange(innerResult.Errors); + } + } + + stillOk = innerResult != null && !innerResult.IsError && currentPosition < tokens.Count; + } + + + result.EndingPosition = currentPosition; + result.IsError = false; + result.Errors = innerErrors; + result.Root = manyNode; + result.IsEnded = lastInnerResult != null && lastInnerResult.IsEnded; + result.HasByPassNodes = hasByPasNodes; + parsingContext.Memoize(clause, position, result); + return result; + } + + public SyntaxParseResult ParseOneOrMore(IList> tokens, OneOrMoreClause clause, int position, + SyntaxParsingContext parsingContext) + { + if (parsingContext.TryGetParseResult(clause, position, out var parseResult)) + { + return parseResult; + } + + var result = new SyntaxParseResult(); + var manyNode = new ManySyntaxNode($"{clause.Clause.ToString()}+"); + var currentPosition = position; + var innerClause = clause.Clause; + bool isError; + + SyntaxParseResult lastInnerResult = null; + + bool hasByPasNodes = false; + SyntaxParseResult firstInnerResult = null; + var innerErrors = new List>(); + + switch (innerClause) + { + case TerminalClause terminalClause: + manyNode.IsManyTokens = true; + firstInnerResult = ParseTerminal(tokens, terminalClause, currentPosition, parsingContext); + hasByPasNodes = hasByPasNodes || firstInnerResult.HasByPassNodes; + break; + case NonTerminalClause nonTerm: + { + firstInnerResult = ParseNonTerminal(tokens, nonTerm, currentPosition, parsingContext); + hasByPasNodes = hasByPasNodes || firstInnerResult.HasByPassNodes; + if (nonTerm.IsGroup) + manyNode.IsManyGroups = true; + else + manyNode.IsManyValues = true; + break; + } + case ChoiceClause choice: + manyNode.IsManyTokens = choice.IsTerminalChoice; + manyNode.IsManyValues = choice.IsNonTerminalChoice; + firstInnerResult = ParseChoice(tokens, choice, currentPosition, parsingContext); + hasByPasNodes = hasByPasNodes || firstInnerResult.HasByPassNodes; + break; + default: + throw new InvalidOperationException("unable to apply repeater to " + innerClause.GetType().Name); + } + + if (firstInnerResult != null && !firstInnerResult.IsError) + { + manyNode.Add(firstInnerResult.Root); + lastInnerResult = firstInnerResult; + currentPosition = firstInnerResult.EndingPosition; + var more = new ZeroOrMoreClause(innerClause); + var nextResult = ParseZeroOrMore(tokens, more, currentPosition, parsingContext); + if (nextResult != null && !nextResult.IsError) + { + currentPosition = nextResult.EndingPosition; + var moreChildren = (ManySyntaxNode)nextResult.Root; + manyNode.Children.AddRange(moreChildren.Children); + } + + if (nextResult != null) + { + innerErrors.AddRange(nextResult.Errors); + } + + isError = false; + } + else + { + if (firstInnerResult != null) + { + innerErrors.AddRange(firstInnerResult.Errors); + } + + isError = true; + } + + result.EndingPosition = currentPosition; + result.IsError = isError; + result.Errors = innerErrors; + result.Root = manyNode; + result.IsEnded = lastInnerResult != null && lastInnerResult.IsEnded; + result.HasByPassNodes = hasByPasNodes; + parsingContext.Memoize(clause, position, result); + return result; + } + + #endregion +} \ No newline at end of file diff --git a/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.Option.cs b/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.Option.cs new file mode 100644 index 00000000..bff652e4 --- /dev/null +++ b/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.Option.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using sly.lexer; +using sly.parser.syntax.grammar; +using sly.parser.syntax.tree; + +namespace sly.parser.llparser; + +public partial class EBNFRecursiveDescentSyntaxParser +{ + #region parsing + + public SyntaxParseResult ParseOption(IList> tokens, OptionClause clause, Rule rule, + int position, SyntaxParsingContext parsingContext) + { + if (parsingContext.TryGetParseResult(clause, position, out var parseResult)) + { + return parseResult; + } + + var result = new SyntaxParseResult(); + var currentPosition = position; + var innerClause = clause.Clause; + + SyntaxParseResult innerResult = null; + + switch (innerClause) + { + case TerminalClause term: + innerResult = ParseTerminal(tokens, term, currentPosition, parsingContext); + break; + case NonTerminalClause nonTerm: + innerResult = ParseNonTerminal(tokens, nonTerm, currentPosition, parsingContext); + break; + case ChoiceClause choice: + innerResult = ParseChoice(tokens, choice, currentPosition, parsingContext); + break; + default: + throw new InvalidOperationException("unable to apply repeater to " + innerClause.GetType().Name); + } + + + if (innerResult.IsError) + { + switch (innerClause) + { + case TerminalClause _: + result = new SyntaxParseResult(); + result.IsError = true; + result.Root = new SyntaxLeaf(Token.Empty(), false); + result.EndingPosition = position; + break; + case ChoiceClause choiceClause: + { + if (choiceClause.IsTerminalChoice) + { + result = new SyntaxParseResult(); + result.IsError = false; + result.Root = new SyntaxLeaf(Token.Empty(), false); + result.EndingPosition = position; + } + else if (choiceClause.IsNonTerminalChoice) + { + result = new SyntaxParseResult(); + result.IsError = false; + result.Root = new SyntaxEpsilon(); + result.EndingPosition = position; + } + + break; + } + default: + { + result = new SyntaxParseResult(); + result.IsError = true; + var children = new List> { innerResult.Root }; + if (innerResult.IsError) children.Clear(); + result.Root = new OptionSyntaxNode(rule.NonTerminalName, children, + rule.GetVisitor()); + (result.Root as OptionSyntaxNode).IsGroupOption = clause.IsGroupOption; + result.EndingPosition = position; + break; + } + } + } + else + { + var children = new List> { innerResult.Root }; + result.Root = + new OptionSyntaxNode(rule.NonTerminalName, children, rule.GetVisitor()); + result.EndingPosition = innerResult.EndingPosition; + result.HasByPassNodes = innerResult.HasByPassNodes; + } + + parsingContext.Memoize(clause, position, result); + return result; + } + + #endregion +} \ No newline at end of file From edb4d01368d288212ee98ba53d251c6d9a55a5f2 Mon Sep 17 00:00:00 2001 From: b3b00 Date: Tue, 30 Jul 2024 16:06:02 +0200 Subject: [PATCH 2/3] move BNF and EBNF parsers in their own namespace --- src/sly/parser/generator/EBNFParserBuilder.cs | 3 ++- src/sly/parser/generator/ParserBuilder.cs | 2 +- src/sly/parser/parser/Parser.cs | 3 ++- .../llparser/bnf/RecursiveDescentSyntaxParser.Expressions.cs | 4 ++-- .../llparser/bnf/RecursiveDescentSyntaxParser.NonTerminal.cs | 4 ++-- .../llparser/bnf/RecursiveDescentSyntaxParser.Terminal.cs | 4 ++-- .../llparser/{ => bnf}/RecursiveDescentSyntaxParser.cs | 2 +- .../{ => bnf}/RecursiveDescentSyntaxParserStarter.cs | 2 +- ...ntSyntaxParser.EBNFRecursiveDescentSyntaxParser.Choice.cs | 5 +++-- .../ebnf/EBNFRecursiveDescentSyntaxParser.Expressions.cs | 3 ++- .../llparser/ebnf/EBNFRecursiveDescentSyntaxParser.Many.cs | 4 ++-- .../llparser/ebnf/EBNFRecursiveDescentSyntaxParser.Option.cs | 4 ++-- .../llparser/{ => ebnf}/EBNFRecursiveDescentSyntaxParser.cs | 3 ++- .../{ => ebnf}/EBNFRecursiveDescentSyntaxParserStarter.cs | 3 ++- tests/ParserTests/EBNFTests.cs | 2 +- 15 files changed, 27 insertions(+), 21 deletions(-) rename src/sly/parser/parser/llparser/{ => bnf}/RecursiveDescentSyntaxParser.cs (99%) rename src/sly/parser/parser/llparser/{ => bnf}/RecursiveDescentSyntaxParserStarter.cs (99%) rename src/sly/parser/parser/llparser/{ => ebnf}/EBNFRecursiveDescentSyntaxParser.cs (99%) rename src/sly/parser/parser/llparser/{ => ebnf}/EBNFRecursiveDescentSyntaxParserStarter.cs (99%) diff --git a/src/sly/parser/generator/EBNFParserBuilder.cs b/src/sly/parser/generator/EBNFParserBuilder.cs index 5a277a1f..64e0222b 100644 --- a/src/sly/parser/generator/EBNFParserBuilder.cs +++ b/src/sly/parser/generator/EBNFParserBuilder.cs @@ -7,7 +7,8 @@ using sly.lexer; using sly.lexer.fsm; using sly.parser.generator.visitor; -using sly.parser.llparser; +using sly.parser.llparser.bnf; +using sly.parser.llparser.ebnf; using sly.parser.syntax.grammar; namespace sly.parser.generator diff --git a/src/sly/parser/generator/ParserBuilder.cs b/src/sly/parser/generator/ParserBuilder.cs index 2e33e162..87f2e58c 100644 --- a/src/sly/parser/generator/ParserBuilder.cs +++ b/src/sly/parser/generator/ParserBuilder.cs @@ -8,7 +8,7 @@ using sly.lexer; using sly.lexer.fsm; using sly.parser.generator.visitor; -using sly.parser.llparser; +using sly.parser.llparser.bnf; using sly.parser.parser; using sly.parser.syntax.grammar; diff --git a/src/sly/parser/parser/Parser.cs b/src/sly/parser/parser/Parser.cs index 3fb8cb15..cd125167 100644 --- a/src/sly/parser/parser/Parser.cs +++ b/src/sly/parser/parser/Parser.cs @@ -6,7 +6,8 @@ using sly.lexer; using sly.parser.generator; using sly.parser.generator.visitor; -using sly.parser.llparser; +using sly.parser.llparser.bnf; +using sly.parser.llparser.ebnf; using sly.parser.parser; using sly.parser.syntax.grammar; using sly.parser.syntax.tree; diff --git a/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.Expressions.cs b/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.Expressions.cs index 200ac90c..56d4159d 100644 --- a/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.Expressions.cs +++ b/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.Expressions.cs @@ -2,9 +2,9 @@ using sly.parser.syntax.grammar; using sly.parser.syntax.tree; -namespace sly.parser.llparser; +namespace sly.parser.llparser.bnf; -public partial class RecursiveDescentSyntaxParser +public partial class RecursiveDescentSyntaxParser where IN : struct { protected SyntaxNode ManageExpressionRules(Rule rule, SyntaxNode node) diff --git a/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.NonTerminal.cs b/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.NonTerminal.cs index 2c96e464..e05a1dc3 100644 --- a/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.NonTerminal.cs +++ b/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.NonTerminal.cs @@ -2,9 +2,9 @@ using sly.lexer; using sly.parser.syntax.grammar; -namespace sly.parser.llparser; +namespace sly.parser.llparser.bnf; -public partial class RecursiveDescentSyntaxParser +public partial class RecursiveDescentSyntaxParser where IN : struct { #region parsing diff --git a/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.Terminal.cs b/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.Terminal.cs index b92b6b2f..ce174426 100644 --- a/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.Terminal.cs +++ b/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.Terminal.cs @@ -3,9 +3,9 @@ using sly.parser.syntax.grammar; using sly.parser.syntax.tree; -namespace sly.parser.llparser; +namespace sly.parser.llparser.bnf; -public partial class RecursiveDescentSyntaxParser +public partial class RecursiveDescentSyntaxParser where IN : struct { #region parsing diff --git a/src/sly/parser/parser/llparser/RecursiveDescentSyntaxParser.cs b/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.cs similarity index 99% rename from src/sly/parser/parser/llparser/RecursiveDescentSyntaxParser.cs rename to src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.cs index 9ae3a119..e1f719bc 100644 --- a/src/sly/parser/parser/llparser/RecursiveDescentSyntaxParser.cs +++ b/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.cs @@ -5,7 +5,7 @@ using sly.parser.syntax.tree; using System.Linq; -namespace sly.parser.llparser +namespace sly.parser.llparser.bnf { public partial class RecursiveDescentSyntaxParser where IN : struct { diff --git a/src/sly/parser/parser/llparser/RecursiveDescentSyntaxParserStarter.cs b/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParserStarter.cs similarity index 99% rename from src/sly/parser/parser/llparser/RecursiveDescentSyntaxParserStarter.cs rename to src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParserStarter.cs index 55dd8931..7cdb766b 100644 --- a/src/sly/parser/parser/llparser/RecursiveDescentSyntaxParserStarter.cs +++ b/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParserStarter.cs @@ -3,7 +3,7 @@ using sly.parser.generator; using sly.parser.syntax.grammar; -namespace sly.parser.llparser +namespace sly.parser.llparser.bnf { public partial class RecursiveDescentSyntaxParser : ISyntaxParser where IN : struct { 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 b5096264..5c2f949f 100644 --- a/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.EBNFRecursiveDescentSyntaxParser.Choice.cs +++ b/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.EBNFRecursiveDescentSyntaxParser.Choice.cs @@ -2,12 +2,13 @@ using System.Collections.Generic; using System.Linq; using sly.lexer; +using sly.parser; using sly.parser.syntax.grammar; using sly.parser.syntax.tree; -namespace sly.parser.llparser; +namespace sly.parser.llparser.ebnf; -public partial class EBNFRecursiveDescentSyntaxParser +public partial class EBNFRecursiveDescentSyntaxParser where IN : struct { #region parsing diff --git a/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.Expressions.cs b/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.Expressions.cs index f74256e9..7a0d2f99 100644 --- a/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.Expressions.cs +++ b/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.Expressions.cs @@ -1,9 +1,10 @@ using System.Collections.Generic; using sly.lexer; +using sly.parser; using sly.parser.syntax.grammar; using sly.parser.syntax.tree; -namespace sly.parser.llparser; +namespace sly.parser.llparser.ebnf; public partial class EBNFRecursiveDescentSyntaxParser { diff --git a/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.Many.cs b/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.Many.cs index 12aa6aea..05ad9a74 100644 --- a/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.Many.cs +++ b/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.Many.cs @@ -4,9 +4,9 @@ using sly.parser.syntax.grammar; using sly.parser.syntax.tree; -namespace sly.parser.llparser; +namespace sly.parser.llparser.ebnf; -public partial class EBNFRecursiveDescentSyntaxParser +public partial class EBNFRecursiveDescentSyntaxParser where IN : struct { #region parsing diff --git a/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.Option.cs b/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.Option.cs index bff652e4..e2efbe28 100644 --- a/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.Option.cs +++ b/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.Option.cs @@ -4,9 +4,9 @@ using sly.parser.syntax.grammar; using sly.parser.syntax.tree; -namespace sly.parser.llparser; +namespace sly.parser.llparser.ebnf; -public partial class EBNFRecursiveDescentSyntaxParser +public partial class EBNFRecursiveDescentSyntaxParser where IN : struct { #region parsing diff --git a/src/sly/parser/parser/llparser/EBNFRecursiveDescentSyntaxParser.cs b/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.cs similarity index 99% rename from src/sly/parser/parser/llparser/EBNFRecursiveDescentSyntaxParser.cs rename to src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.cs index 5f88d977..e5bc8550 100644 --- a/src/sly/parser/parser/llparser/EBNFRecursiveDescentSyntaxParser.cs +++ b/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.cs @@ -5,8 +5,9 @@ using sly.parser.generator; using sly.parser.syntax.tree; using sly.parser.syntax.grammar; +using sly.parser.llparser.bnf; -namespace sly.parser.llparser +namespace sly.parser.llparser.ebnf { public partial class EBNFRecursiveDescentSyntaxParser : RecursiveDescentSyntaxParser where IN : struct { diff --git a/src/sly/parser/parser/llparser/EBNFRecursiveDescentSyntaxParserStarter.cs b/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParserStarter.cs similarity index 99% rename from src/sly/parser/parser/llparser/EBNFRecursiveDescentSyntaxParserStarter.cs rename to src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParserStarter.cs index 120e9306..8dfcfcd2 100644 --- a/src/sly/parser/parser/llparser/EBNFRecursiveDescentSyntaxParserStarter.cs +++ b/src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParserStarter.cs @@ -2,8 +2,9 @@ using System.Linq; using sly.parser.generator; using sly.parser.syntax.grammar; +using sly.parser.llparser.bnf; -namespace sly.parser.llparser +namespace sly.parser.llparser.ebnf { public partial class EBNFRecursiveDescentSyntaxParser where IN : struct { diff --git a/tests/ParserTests/EBNFTests.cs b/tests/ParserTests/EBNFTests.cs index d23c5684..d8ce7713 100644 --- a/tests/ParserTests/EBNFTests.cs +++ b/tests/ParserTests/EBNFTests.cs @@ -12,7 +12,7 @@ using sly.lexer; using sly.parser; using sly.parser.generator; -using sly.parser.llparser; +using sly.parser.llparser.ebnf; using sly.parser.parser; using sly.parser.syntax.grammar; using Xunit; From da62af126a36729ebd5818f1ae2f6b7fccac1da3 Mon Sep 17 00:00:00 2001 From: b3b00 Date: Tue, 30 Jul 2024 16:37:11 +0200 Subject: [PATCH 3/3] sonar linting --- ...ecursiveDescentSyntaxParser.NonTerminal.cs | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.NonTerminal.cs b/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.NonTerminal.cs index e05a1dc3..ed9a3beb 100644 --- a/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.NonTerminal.cs +++ b/src/sly/parser/parser/llparser/bnf/RecursiveDescentSyntaxParser.NonTerminal.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using sly.lexer; using sly.parser.syntax.grammar; @@ -48,7 +49,6 @@ public SyntaxParseResult ParseNonTerminal(IList> tokens, string no innerRuleRes.Errors.Count == 0 || other) { greaterIndex = innerRuleRes.EndingPosition; - //innerRuleErrors.Clear(); innerRuleErrors.AddRange(innerRuleRes.Errors); } @@ -66,7 +66,6 @@ public SyntaxParseResult ParseNonTerminal(IList> tokens, string no if (r != null && r.PossibleLeadingTokens != null) allAcceptableTokens.AddRange(r.PossibleLeadingTokens); }); - // allAcceptableTokens = allAcceptableTokens.ToList(); var noMatching = NoMatchingRuleError(tokens, currentPosition, allAcceptableTokens); parsingContext.Memoize(new NonTerminalClause(nonTerminalName), currentPosition, noMatching); @@ -92,13 +91,10 @@ public SyntaxParseResult ParseNonTerminal(IList> tokens, string no } } - if (rulesResult.IsError) + if (rulesResult.IsError && rulesResult.EndingPosition > koEndingPosition) { - if (rulesResult.EndingPosition > koEndingPosition) - { - koEndingPosition = rulesResult.EndingPosition; - maxKo = rulesResult; - } + koEndingPosition = rulesResult.EndingPosition; + maxKo = rulesResult; } } @@ -120,17 +116,12 @@ public SyntaxParseResult ParseNonTerminal(IList> tokens, string no result.IsEnded = max.IsEnded; result.HasByPassNodes = max.HasByPassNodes; - if (rulesResults.Count > 0) + + List> terr = new List>(); + foreach (var ruleResult in rulesResults) { - List> terr = new List>(); - foreach (var ruleResult in rulesResults) - { - terr.AddRange(ruleResult.Errors); - foreach (var err in ruleResult.Errors) - { - result.AddExpectings(err.ExpectedTokens); - } - } + terr.AddRange(ruleResult.Errors); + result.AddExpectings(ruleResult.Errors.SelectMany(x => x.ExpectedTokens)); } parsingContext.Memoize(new NonTerminalClause(nonTerminalName), currentPosition, result);