diff --git a/Sources/SynKit/Libraries/Parser.Generator/BnfDesugar.cs b/Sources/SynKit/Libraries/Parser.Generator/BnfDesugar.cs index 5484ce32..45f075cb 100644 --- a/Sources/SynKit/Libraries/Parser.Generator/BnfDesugar.cs +++ b/Sources/SynKit/Libraries/Parser.Generator/BnfDesugar.cs @@ -71,8 +71,9 @@ void DesugarRuleSet() public static IList GeneratePrecedenceParser(Rule rule, IList precedenceTable) { // The resulting precedence rules should look like - // RULE_N : (RULE_N OP RULE_(N+1)) {TR} | RULE_(N+1) for left-associative - // RULE_N : (RULE_(N+1) OP RULE_N) {TR} | RULE_(N+1) for right-associative + // RULE_N_OP : (OP1 | OP2 | ...) {TR} + // RULE_N : (RULE_N RULE_N_OP RULE_(N+1)) {TR} | RULE_(N+1) for left-associative + // RULE_N : (RULE_(N+1) RULE_N_OP RULE_N) {TR} | RULE_(N+1) for right-associative // And simply the passed-in rule as atomic var result = new List(); var atom = new Rule($"{rule.Name}_atomic", rule.Ast, false); @@ -80,25 +81,19 @@ public static IList GeneratePrecedenceParser(Rule rule, IList new BnfAst.Literal(op))); + var operatorCall = new BnfAst.Call(i == 0 ? $"{rule.Name}_operator" : $"{rule.Name}_level{i}_operator"); var currentCall = new BnfAst.Call(i == 0 ? rule.Name : $"{rule.Name}_level{i}"); var nextCall = new BnfAst.Call(i == precedenceTable.Count - 1 ? atom.Name : $"{rule.Name}_level{i + 1}"); - BnfAst? toAdd = null; - foreach (var op in prec.Operators) - { - var opNode = new BnfAst.Literal(op); - var seq = prec.Left - ? new BnfAst[] { currentCall, opNode, nextCall } - : new BnfAst[] { nextCall, opNode, currentCall }; - var alt = new BnfAst.Transform(new BnfAst.Seq(seq), prec.Method); - if (toAdd == null) toAdd = alt; - else toAdd = new BnfAst.Alt(toAdd, alt); - } - // Default is always stepping a level down - if (toAdd is null) toAdd = nextCall; - else toAdd = new BnfAst.Alt(toAdd, nextCall); + BnfAst[] seq = prec.Left + ? [currentCall, operatorCall, nextCall] + : [nextCall, operatorCall, currentCall]; + BnfAst toAdd = new BnfAst.Transform(new BnfAst.Seq(seq), prec.Method); + toAdd = new BnfAst.Alt(toAdd, nextCall); result.Add(new Rule(currentCall.Name, toAdd, i == 0) { VisualName = rule.VisualName }); + result.Add(new Rule(operatorCall.Name, operatorRule, i == 0) { VisualName = rule.VisualName }); } return result; } diff --git a/Sources/SynKit/Tests/Parser.Generator.Tests/verified/ExpressionParserTests.SimpleMathExpression.verified.txt b/Sources/SynKit/Tests/Parser.Generator.Tests/verified/ExpressionParserTests.SimpleMathExpression.verified.txt index b7994b9e..e5934fe6 100644 --- a/Sources/SynKit/Tests/Parser.Generator.Tests/verified/ExpressionParserTests.SimpleMathExpression.verified.txt +++ b/Sources/SynKit/Tests/Parser.Generator.Tests/verified/ExpressionParserTests.SimpleMathExpression.verified.txt @@ -248,120 +248,58 @@ namespace Foo while (true) { ParseResult a27; - ParseResult a28; - ParseResult<(int, Yoakke.SynKit.Lexer.IToken, int)> a29; - ParseResult a30; - a30 = placeholder; - if (a30.IsOk) - { - ParseResult> a31; - if (this.TokenStream.TryLookAhead(a30.Ok.Offset, out var a32) && a32.Text == "+") - { - a31 = ParseResult.Ok(a32, a30.Ok.Offset + 1); - } - else - { - a31 = ParseResult.Error("+", a32, a32.Range.Start, "expression"); - } - - a31 = a31 | a30.Ok.FurthestError; - if (a31.IsOk) - { - ParseResult a33; - a33 = parseExpressionLevel1(a31.Ok.Offset); - if (a33.IsError && (!this.TokenStream.TryLookAhead(a31.Ok.Offset, out var a34) || ReferenceEquals(a34, a33.Error.Got))) - { - a33 = ParseResult.Error("expression_level1", a33.Error.Got, a33.Error.Position, "expression"); - } - - a33 = a33 | a31.Ok.FurthestError; - if (a33.IsOk) - { - a29 = ParseResult.Ok((a30.Ok.Value, a31.Ok.Value, a33.Ok.Value), a33.Ok.Offset, a33.Ok.FurthestError); - } - else - { - a29 = a33.Error; - } - } - else - { - a29 = a31.Error; - } - } - else - { - a29 = a30.Error; - } - + ParseResult<(int, Yoakke.SynKit.Lexer.IToken, int)> a28; + ParseResult a29; + a29 = placeholder; if (a29.IsOk) { - var(a35, a36, a37) = a29.Ok.Value; - a28 = ParseResult.Ok(Op(a35, a36, a37), a29.Ok.Offset, a29.Ok.FurthestError); - } - else - { - a28 = a29.Error; - } - - a27 = a28; - ParseResult a38; - ParseResult<(int, Yoakke.SynKit.Lexer.IToken, int)> a39; - ParseResult a40; - a40 = placeholder; - if (a40.IsOk) - { - ParseResult> a41; - if (this.TokenStream.TryLookAhead(a40.Ok.Offset, out var a42) && a42.Text == "-") + ParseResult> a30; + a30 = parseExpressionOperator(a29.Ok.Offset); + if (a30.IsError && (!this.TokenStream.TryLookAhead(a29.Ok.Offset, out var a31) || ReferenceEquals(a31, a30.Error.Got))) { - a41 = ParseResult.Ok(a42, a40.Ok.Offset + 1); - } - else - { - a41 = ParseResult.Error("-", a42, a42.Range.Start, "expression"); + a30 = ParseResult.Error("expression_operator", a30.Error.Got, a30.Error.Position, "expression"); } - a41 = a41 | a40.Ok.FurthestError; - if (a41.IsOk) + a30 = a30 | a29.Ok.FurthestError; + if (a30.IsOk) { - ParseResult a43; - a43 = parseExpressionLevel1(a41.Ok.Offset); - if (a43.IsError && (!this.TokenStream.TryLookAhead(a41.Ok.Offset, out var a44) || ReferenceEquals(a44, a43.Error.Got))) + ParseResult a32; + a32 = parseExpressionLevel1(a30.Ok.Offset); + if (a32.IsError && (!this.TokenStream.TryLookAhead(a30.Ok.Offset, out var a33) || ReferenceEquals(a33, a32.Error.Got))) { - a43 = ParseResult.Error("expression_level1", a43.Error.Got, a43.Error.Position, "expression"); + a32 = ParseResult.Error("expression_level1", a32.Error.Got, a32.Error.Position, "expression"); } - a43 = a43 | a41.Ok.FurthestError; - if (a43.IsOk) + a32 = a32 | a30.Ok.FurthestError; + if (a32.IsOk) { - a39 = ParseResult.Ok((a40.Ok.Value, a41.Ok.Value, a43.Ok.Value), a43.Ok.Offset, a43.Ok.FurthestError); + a28 = ParseResult.Ok((a29.Ok.Value, a30.Ok.Value, a32.Ok.Value), a32.Ok.Offset, a32.Ok.FurthestError); } else { - a39 = a43.Error; + a28 = a32.Error; } } else { - a39 = a41.Error; + a28 = a30.Error; } } else { - a39 = a40.Error; + a28 = a29.Error; } - if (a39.IsOk) + if (a28.IsOk) { - var(a45, a46, a47) = a39.Ok.Value; - a38 = ParseResult.Ok(Op(a45, a46, a47), a39.Ok.Offset, a39.Ok.FurthestError); + var(a34, a35, a36) = a28.Ok.Value; + a27 = ParseResult.Ok(Op(a34, a35, a36), a28.Ok.Offset, a28.Ok.FurthestError); } else { - a38 = a39.Error; + a27 = a28.Error; } - a27 = a27 | a38; if (a27.IsOk) { placeholder = a27; @@ -381,141 +319,133 @@ namespace Foo return a24; } - private ParseResult parseExpressionLevel1(int offset) + public bool TryParseExpressionOperator([MaybeNullWhen(false)] out Yoakke.SynKit.Lexer.IToken value) { - ParseResult a48; - ParseResult a49; - a49 = parseExpressionLevel2(offset); - if (a49.IsError && (!this.TokenStream.TryLookAhead(offset, out var a50) || ReferenceEquals(a50, a49.Error.Got))) + var result = parseExpressionOperator(0); + if (result.IsOk) { - a49 = ParseResult.Error("expression_level2", a49.Error.Got, a49.Error.Position, "expression"); + value = result.Ok.Value; + this.TokenStream.Consume(result.Ok.Offset); + return true; } + else + { + value = default; + return false; + } + } - if (a49.IsOk) + public ParseResult> ParseExpressionOperator() + { + var result = parseExpressionOperator(0); + if (result.IsOk) + this.TokenStream.Consume(result.Ok.Offset); + else + this.TokenStream.Consume(1); + return result; + } + + private ParseResult> parseExpressionOperator(int offset) + { + ParseResult> a37; + ParseResult> a38; + if (this.TokenStream.TryLookAhead(offset, out var a39) && a39.Text == "+") { - var placeholder = a49; - a48 = a49.Ok; - while (true) - { - ParseResult a51; - ParseResult a52; - ParseResult<(int, Yoakke.SynKit.Lexer.IToken, int)> a53; - ParseResult a54; - a54 = placeholder; - if (a54.IsOk) - { - ParseResult> a55; - if (this.TokenStream.TryLookAhead(a54.Ok.Offset, out var a56) && a56.Text == "*") - { - a55 = ParseResult.Ok(a56, a54.Ok.Offset + 1); - } - else - { - a55 = ParseResult.Error("*", a56, a56.Range.Start, "expression"); - } + a38 = ParseResult.Ok(a39, offset + 1); + } + else + { + a38 = ParseResult.Error("+", a39, a39.Range.Start, "expression"); + } - a55 = a55 | a54.Ok.FurthestError; - if (a55.IsOk) - { - ParseResult a57; - a57 = parseExpressionLevel2(a55.Ok.Offset); - if (a57.IsError && (!this.TokenStream.TryLookAhead(a55.Ok.Offset, out var a58) || ReferenceEquals(a58, a57.Error.Got))) - { - a57 = ParseResult.Error("expression_level2", a57.Error.Got, a57.Error.Position, "expression"); - } + a37 = a38; + ParseResult> a40; + if (this.TokenStream.TryLookAhead(offset, out var a41) && a41.Text == "-") + { + a40 = ParseResult.Ok(a41, offset + 1); + } + else + { + a40 = ParseResult.Error("-", a41, a41.Range.Start, "expression"); + } - a57 = a57 | a55.Ok.FurthestError; - if (a57.IsOk) - { - a53 = ParseResult.Ok((a54.Ok.Value, a55.Ok.Value, a57.Ok.Value), a57.Ok.Offset, a57.Ok.FurthestError); - } - else - { - a53 = a57.Error; - } - } - else - { - a53 = a55.Error; - } - } - else - { - a53 = a54.Error; - } + a37 = a37 | a40; + return a37; + } - if (a53.IsOk) - { - var(a59, a60, a61) = a53.Ok.Value; - a52 = ParseResult.Ok(Op(a59, a60, a61), a53.Ok.Offset, a53.Ok.FurthestError); - } - else - { - a52 = a53.Error; - } + private ParseResult parseExpressionLevel1(int offset) + { + ParseResult a42; + ParseResult a43; + a43 = parseExpressionLevel2(offset); + if (a43.IsError && (!this.TokenStream.TryLookAhead(offset, out var a44) || ReferenceEquals(a44, a43.Error.Got))) + { + a43 = ParseResult.Error("expression_level2", a43.Error.Got, a43.Error.Position, "expression"); + } - a51 = a52; - ParseResult a62; - ParseResult<(int, Yoakke.SynKit.Lexer.IToken, int)> a63; - ParseResult a64; - a64 = placeholder; - if (a64.IsOk) + if (a43.IsOk) + { + var placeholder = a43; + a42 = a43.Ok; + while (true) + { + ParseResult a45; + ParseResult<(int, Yoakke.SynKit.Lexer.IToken, int)> a46; + ParseResult a47; + a47 = placeholder; + if (a47.IsOk) { - ParseResult> a65; - if (this.TokenStream.TryLookAhead(a64.Ok.Offset, out var a66) && a66.Text == "/") + ParseResult> a48; + a48 = parseExpressionLevel1Operator(a47.Ok.Offset); + if (a48.IsError && (!this.TokenStream.TryLookAhead(a47.Ok.Offset, out var a49) || ReferenceEquals(a49, a48.Error.Got))) { - a65 = ParseResult.Ok(a66, a64.Ok.Offset + 1); - } - else - { - a65 = ParseResult.Error("/", a66, a66.Range.Start, "expression"); + a48 = ParseResult.Error("expression_level1_operator", a48.Error.Got, a48.Error.Position, "expression"); } - a65 = a65 | a64.Ok.FurthestError; - if (a65.IsOk) + a48 = a48 | a47.Ok.FurthestError; + if (a48.IsOk) { - ParseResult a67; - a67 = parseExpressionLevel2(a65.Ok.Offset); - if (a67.IsError && (!this.TokenStream.TryLookAhead(a65.Ok.Offset, out var a68) || ReferenceEquals(a68, a67.Error.Got))) + ParseResult a50; + a50 = parseExpressionLevel2(a48.Ok.Offset); + if (a50.IsError && (!this.TokenStream.TryLookAhead(a48.Ok.Offset, out var a51) || ReferenceEquals(a51, a50.Error.Got))) { - a67 = ParseResult.Error("expression_level2", a67.Error.Got, a67.Error.Position, "expression"); + a50 = ParseResult.Error("expression_level2", a50.Error.Got, a50.Error.Position, "expression"); } - a67 = a67 | a65.Ok.FurthestError; - if (a67.IsOk) + a50 = a50 | a48.Ok.FurthestError; + if (a50.IsOk) { - a63 = ParseResult.Ok((a64.Ok.Value, a65.Ok.Value, a67.Ok.Value), a67.Ok.Offset, a67.Ok.FurthestError); + a46 = ParseResult.Ok((a47.Ok.Value, a48.Ok.Value, a50.Ok.Value), a50.Ok.Offset, a50.Ok.FurthestError); } else { - a63 = a67.Error; + a46 = a50.Error; } } else { - a63 = a65.Error; + a46 = a48.Error; } } else { - a63 = a64.Error; + a46 = a47.Error; } - if (a63.IsOk) + if (a46.IsOk) { - var(a69, a70, a71) = a63.Ok.Value; - a62 = ParseResult.Ok(Op(a69, a70, a71), a63.Ok.Offset, a63.Ok.FurthestError); + var(a52, a53, a54) = a46.Ok.Value; + a45 = ParseResult.Ok(Op(a52, a53, a54), a46.Ok.Offset, a46.Ok.FurthestError); } else { - a62 = a63.Error; + a45 = a46.Error; } - a51 = a51 | a62; - if (a51.IsOk) + if (a45.IsOk) { - placeholder = a51; - a48 = a51.Ok; + placeholder = a45; + a42 = a45.Ok; } else { @@ -525,86 +455,126 @@ namespace Foo } else { - a48 = a49.Error; + a42 = a43.Error; } - return a48; + return a42; + } + + private ParseResult> parseExpressionLevel1Operator(int offset) + { + ParseResult> a55; + ParseResult> a56; + if (this.TokenStream.TryLookAhead(offset, out var a57) && a57.Text == "*") + { + a56 = ParseResult.Ok(a57, offset + 1); + } + else + { + a56 = ParseResult.Error("*", a57, a57.Range.Start, "expression"); + } + + a55 = a56; + ParseResult> a58; + if (this.TokenStream.TryLookAhead(offset, out var a59) && a59.Text == "/") + { + a58 = ParseResult.Ok(a59, offset + 1); + } + else + { + a58 = ParseResult.Error("/", a59, a59.Range.Start, "expression"); + } + + a55 = a55 | a58; + return a55; } private ParseResult parseExpressionLevel2(int offset) { - ParseResult a72; - ParseResult a73; - ParseResult<(int, Yoakke.SynKit.Lexer.IToken, int)> a74; - ParseResult a75; - a75 = parseExpressionAtomic(offset); - if (a75.IsError && (!this.TokenStream.TryLookAhead(offset, out var a76) || ReferenceEquals(a76, a75.Error.Got))) + ParseResult a60; + ParseResult a61; + ParseResult<(int, Yoakke.SynKit.Lexer.IToken, int)> a62; + ParseResult a63; + a63 = parseExpressionAtomic(offset); + if (a63.IsError && (!this.TokenStream.TryLookAhead(offset, out var a64) || ReferenceEquals(a64, a63.Error.Got))) { - a75 = ParseResult.Error("expression_atomic", a75.Error.Got, a75.Error.Position, "expression"); + a63 = ParseResult.Error("expression_atomic", a63.Error.Got, a63.Error.Position, "expression"); } - if (a75.IsOk) + if (a63.IsOk) { - ParseResult> a77; - if (this.TokenStream.TryLookAhead(a75.Ok.Offset, out var a78) && a78.Text == "^") - { - a77 = ParseResult.Ok(a78, a75.Ok.Offset + 1); - } - else + ParseResult> a65; + a65 = parseExpressionLevel2Operator(a63.Ok.Offset); + if (a65.IsError && (!this.TokenStream.TryLookAhead(a63.Ok.Offset, out var a66) || ReferenceEquals(a66, a65.Error.Got))) { - a77 = ParseResult.Error("^", a78, a78.Range.Start, "expression"); + a65 = ParseResult.Error("expression_level2_operator", a65.Error.Got, a65.Error.Position, "expression"); } - a77 = a77 | a75.Ok.FurthestError; - if (a77.IsOk) + a65 = a65 | a63.Ok.FurthestError; + if (a65.IsOk) { - ParseResult a79; - a79 = parseExpressionLevel2(a77.Ok.Offset); - if (a79.IsError && (!this.TokenStream.TryLookAhead(a77.Ok.Offset, out var a80) || ReferenceEquals(a80, a79.Error.Got))) + ParseResult a67; + a67 = parseExpressionLevel2(a65.Ok.Offset); + if (a67.IsError && (!this.TokenStream.TryLookAhead(a65.Ok.Offset, out var a68) || ReferenceEquals(a68, a67.Error.Got))) { - a79 = ParseResult.Error("expression_level2", a79.Error.Got, a79.Error.Position, "expression"); + a67 = ParseResult.Error("expression_level2", a67.Error.Got, a67.Error.Position, "expression"); } - a79 = a79 | a77.Ok.FurthestError; - if (a79.IsOk) + a67 = a67 | a65.Ok.FurthestError; + if (a67.IsOk) { - a74 = ParseResult.Ok((a75.Ok.Value, a77.Ok.Value, a79.Ok.Value), a79.Ok.Offset, a79.Ok.FurthestError); + a62 = ParseResult.Ok((a63.Ok.Value, a65.Ok.Value, a67.Ok.Value), a67.Ok.Offset, a67.Ok.FurthestError); } else { - a74 = a79.Error; + a62 = a67.Error; } } else { - a74 = a77.Error; + a62 = a65.Error; } } else { - a74 = a75.Error; + a62 = a63.Error; } - if (a74.IsOk) + if (a62.IsOk) { - var(a81, a82, a83) = a74.Ok.Value; - a73 = ParseResult.Ok(Op(a81, a82, a83), a74.Ok.Offset, a74.Ok.FurthestError); + var(a69, a70, a71) = a62.Ok.Value; + a61 = ParseResult.Ok(Op(a69, a70, a71), a62.Ok.Offset, a62.Ok.FurthestError); } else { - a73 = a74.Error; + a61 = a62.Error; + } + + a60 = a61; + ParseResult a72; + a72 = parseExpressionAtomic(offset); + if (a72.IsError && (!this.TokenStream.TryLookAhead(offset, out var a73) || ReferenceEquals(a73, a72.Error.Got))) + { + a72 = ParseResult.Error("expression_atomic", a72.Error.Got, a72.Error.Position, "expression"); } - a72 = a73; - ParseResult a84; - a84 = parseExpressionAtomic(offset); - if (a84.IsError && (!this.TokenStream.TryLookAhead(offset, out var a85) || ReferenceEquals(a85, a84.Error.Got))) + a60 = a60 | a72; + return a60; + } + + private ParseResult> parseExpressionLevel2Operator(int offset) + { + ParseResult> a74; + if (this.TokenStream.TryLookAhead(offset, out var a75) && a75.Text == "^") + { + a74 = ParseResult.Ok(a75, offset + 1); + } + else { - a84 = ParseResult.Error("expression_atomic", a84.Error.Got, a84.Error.Position, "expression"); + a74 = ParseResult.Error("^", a75, a75.Range.Start, "expression"); } - a72 = a72 | a84; - return a72; + return a74; } } }