diff --git a/sly/parser/generator/ExpressionRulesGenerator.cs b/sly/parser/generator/ExpressionRulesGenerator.cs index 39acc4b3..70158eb1 100644 --- a/sly/parser/generator/ExpressionRulesGenerator.cs +++ b/sly/parser/generator/ExpressionRulesGenerator.cs @@ -54,18 +54,16 @@ public class ExpressionRulesGenerator return attr != null; }).ToList(); - var operationsByPrecedence = new Dictionary>>(); - methods.ForEach(m => { var attributes = - (OperationAttribute[]) m.GetCustomAttributes(typeof(OperationAttribute), true); + (OperationAttribute[])m.GetCustomAttributes(typeof(OperationAttribute), true); foreach (var attr in attributes) { - IN oper = default(IN); + IN oper = default; if (attr.IsIntToken) { oper = EnumConverter.ConvertIntToEnum(attr.IntToken); @@ -74,7 +72,7 @@ public class ExpressionRulesGenerator { oper = EnumConverter.ConvertStringToEnum(attr.StringToken); } - var operation = new OperationMetaData(attr.Precedence, attr.Assoc, m, attr.Affix,oper); + var operation = new OperationMetaData(attr.Precedence, attr.Assoc, m, attr.Affix, oper); var operations = new List>(); if (operationsByPrecedence.ContainsKey(operation.Precedence)) operations = operationsByPrecedence[operation.Precedence]; @@ -127,7 +125,6 @@ public class ExpressionRulesGenerator { var precedences = operationsByPrecedence.Keys.ToList(); precedences.Sort(); - var max = precedences.Max(); for (var i = 0; i < precedences.Count; i++) { @@ -135,11 +132,9 @@ public class ExpressionRulesGenerator var nextPrecedence = i < precedences.Count - 1 ? precedences[i + 1] : -1; var operations = operationsByPrecedence[precedence]; var name = GetNonTerminalNameForPrecedence(precedence, operationsByPrecedence, operandNonTerminal); - var nextName = - GetNonTerminalNameForPrecedence(nextPrecedence, operationsByPrecedence, operandNonTerminal); + var nextName = GetNonTerminalNameForPrecedence(nextPrecedence, operationsByPrecedence, operandNonTerminal); - var nonTerminal = BuildNonTerminal(i == precedences.Count - 1, name, nextName, operations, - operationsByPrecedence); + var nonTerminal = BuildNonTerminal(name, nextName, operations); configuration.NonTerminals[nonTerminal.Name] = nonTerminal; } @@ -157,44 +152,65 @@ public class ExpressionRulesGenerator entrypoint.Rules.Add(rule); } - - private static NonTerminal BuildNonTerminal(bool last, string name, string nextName, - List> operations, Dictionary>> operationsByPrecedence) - where IN : struct + private static NonTerminal BuildNonTerminal(string name, string nextName, List> operations) where IN : struct { var nonTerminal = new NonTerminal(name, new List>()); - foreach (var operation in operations) - if (operation.Affix == Affix.InFix) + + var InFixOps = operations.Where(x => x.Affix == Affix.InFix).ToList(); + if (InFixOps.Count > 0) + { + var InFixClauses = InFixOps.Select(x => new TerminalClause(x.OperatorToken)).ToList>(); + + var rule = new Rule() { - var rule = new Rule(); - rule.Clauses.Add(new NonTerminalClause(nextName)); - rule.Clauses.Add(new TerminalClause(operation.OperatorToken)); - rule.Clauses.Add(new NonTerminalClause(name)); - rule.IsExpressionRule = true; - rule.ExpressionAffix = operation.Affix; - rule.SetVisitor(operation); - nonTerminal.Rules.Add(rule); - } - else if (operation.Affix == Affix.PreFix) + ExpressionAffix = Affix.InFix, + IsExpressionRule = true + }; + + rule.Clauses.Add(new NonTerminalClause(nextName)); + rule.Clauses.Add(InFixClauses.Count == 1 ? InFixClauses[0] : new ChoiceClause(InFixClauses)); + rule.Clauses.Add(new NonTerminalClause(name)); + + InFixOps.ForEach(x => rule.SetVisitor(x)); + nonTerminal.Rules.Add(rule); + } + + + var PreFixOps = operations.Where(x => x.Affix == Affix.PreFix).ToList(); + if (PreFixOps.Count > 0) + { + var PreFixClauses = PreFixOps.Select(x => new TerminalClause(x.OperatorToken)).ToList>(); + + var rule = new Rule() { - var rule = new Rule(); - rule.Clauses.Add(new TerminalClause(operation.OperatorToken)); - rule.Clauses.Add(new NonTerminalClause(nextName)); - rule.IsExpressionRule = true; - rule.ExpressionAffix = operation.Affix; - rule.SetVisitor(operation); - nonTerminal.Rules.Add(rule); - } - else if (operation.Affix == Affix.PostFix) + ExpressionAffix = Affix.PreFix, + IsExpressionRule = true + }; + + rule.Clauses.Add(PreFixClauses.Count == 1 ? PreFixClauses[0] : new ChoiceClause(PreFixClauses)); + rule.Clauses.Add(new NonTerminalClause(nextName)); + + PreFixOps.ForEach(x => rule.SetVisitor(x)); + nonTerminal.Rules.Add(rule); + } + + var PostFixOps = operations.Where(x => x.Affix == Affix.PostFix).ToList(); + if (PostFixOps.Count > 0) + { + var PostFixClauses = PostFixOps.Select(x => new TerminalClause(x.OperatorToken)).ToList>(); + + var rule = new Rule() { - var rule = new Rule(); - rule.Clauses.Add(new NonTerminalClause(nextName)); - rule.Clauses.Add(new TerminalClause(operation.OperatorToken)); - rule.IsExpressionRule = true; - rule.ExpressionAffix = operation.Affix; - rule.SetVisitor(operation); - nonTerminal.Rules.Add(rule); - } + ExpressionAffix = Affix.PostFix, + IsExpressionRule = true + }; + + rule.Clauses.Add(new NonTerminalClause(nextName)); + rule.Clauses.Add(PostFixClauses.Count == 1 ? PostFixClauses[0] : new ChoiceClause(PostFixClauses)); + + PostFixOps.ForEach(x => rule.SetVisitor(x)); + nonTerminal.Rules.Add(rule); + } var rule0 = new Rule(); rule0.Clauses.Add(new NonTerminalClause(nextName)); @@ -224,13 +240,8 @@ public class ExpressionRulesGenerator .Select(oper => oper.ToString()) .ToList() .Aggregate((s1, s2) => $"{s1}_{s2}"); - var name = $"expr_{precedence}_{operatorsPart}"; - - - return name; + + return $"expr_{precedence}_{operatorsPart}"; } - - - } } \ No newline at end of file diff --git a/sly/parser/syntax/grammar/Rule.cs b/sly/parser/syntax/grammar/Rule.cs index f72d20f4..d4a7a110 100644 --- a/sly/parser/syntax/grammar/Rule.cs +++ b/sly/parser/syntax/grammar/Rule.cs @@ -33,11 +33,12 @@ public string Key { get { - var k = Clauses - .Select(c => c.ToString()) - .Aggregate((c1, c2) => c1.ToString() + "_" + c2.ToString()); - if (Clauses.Count == 1) k += "_"; - return k; + var key = string.Join("_", Clauses.Select(c => c.ToString())); + + if (Clauses.Count == 1) + key += "_"; + + return IsExpressionRule ? key.Replace(" | ", "_") : key; } }