diff --git a/sly.sln b/sly.sln index de101a0e..c1a0e16b 100644 --- a/sly.sln +++ b/sly.sln @@ -45,6 +45,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CslyGenerator.Tests", "test EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GeneratedXML", "src\samples\GeneratedXML\GeneratedXML.csproj", "{7FEF0D32-FFC7-4886-A4B7-71314C25627E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExplicitTokens", "src\samples\ExplicitTokens\ExplicitTokens.csproj", "{94B9B654-82CB-4969-8DCA-250916E53724}" +EndProject Global GlobalSection(Performance) = preSolution HasPerformanceSessions = true @@ -138,6 +140,10 @@ Global {7FEF0D32-FFC7-4886-A4B7-71314C25627E}.Debug|Any CPU.Build.0 = Debug|Any CPU {7FEF0D32-FFC7-4886-A4B7-71314C25627E}.Release|Any CPU.ActiveCfg = Release|Any CPU {7FEF0D32-FFC7-4886-A4B7-71314C25627E}.Release|Any CPU.Build.0 = Release|Any CPU + {94B9B654-82CB-4969-8DCA-250916E53724}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {94B9B654-82CB-4969-8DCA-250916E53724}.Debug|Any CPU.Build.0 = Debug|Any CPU + {94B9B654-82CB-4969-8DCA-250916E53724}.Release|Any CPU.ActiveCfg = Release|Any CPU + {94B9B654-82CB-4969-8DCA-250916E53724}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -155,6 +161,7 @@ Global {81E72CFA-A6D6-4DB4-B3B5-E167064E7858} = {36ED7F1A-2E81-4A71-81FE-A357E5840A33} {BC5020CA-6BFC-4895-9A1E-99B4A0AEDB11} = {36ED7F1A-2E81-4A71-81FE-A357E5840A33} {7FEF0D32-FFC7-4886-A4B7-71314C25627E} = {36ED7F1A-2E81-4A71-81FE-A357E5840A33} + {94B9B654-82CB-4969-8DCA-250916E53724} = {36ED7F1A-2E81-4A71-81FE-A357E5840A33} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {43254130-CF3E-480E-952F-E50CA5D2E417} diff --git a/src/samples/ExplicitTokens/ExplicitTokens.csproj b/src/samples/ExplicitTokens/ExplicitTokens.csproj new file mode 100644 index 00000000..2d531923 --- /dev/null +++ b/src/samples/ExplicitTokens/ExplicitTokens.csproj @@ -0,0 +1,11 @@ + + + + net7.0 + enable + enable + + + + + diff --git a/src/samples/ExplicitTokens/ExplicitTokensExpressionParser.cs b/src/samples/ExplicitTokens/ExplicitTokensExpressionParser.cs new file mode 100644 index 00000000..611ead82 --- /dev/null +++ b/src/samples/ExplicitTokens/ExplicitTokensExpressionParser.cs @@ -0,0 +1,89 @@ +using sly.lexer; +using sly.parser.generator; + +namespace ExplicitTokens; + +[ParserRoot("ExplicitTokensExpressionParser_expressions")] +public class ExplicitTokensExpressionParser +{ + [Production("primary: DOUBLE")] + [Operand] + public double Primary(Token doubleToken) + { + return doubleToken.DoubleValue; + } + + [Operand] + [Production("primary : 'bozzo'[d]")] + public double Bozzo() + { + return 42.0; + } + + [Operand] + [Production("primary : TEST[d]")] + public double Test() + { + return 0.0; + } + + + [Infix("'+'",Associativity.Left, 10)] + [Infix("'-'", Associativity.Left, 10)] + public double BinaryTermExpression(double left, Token operation, double right) + { + switch (operation.Value) + { + case "+" : return left + right; + case "-" : return left - right; + default : throw new InvalidOperationException($"that is not possible ! {operation.Value} is not a valid operation"); + } + } + + [Operation((int) ExplicitTokensTokens.TIMES, Affix.InFix, Associativity.Left, 50)] + [Operation("DIVIDE", Affix.InFix, Associativity.Left, 50)] + public double BinaryFactorExpression(double left, Token operation, double right) + { + double result = 0; + switch (operation.TokenID) + { + case ExplicitTokensTokens.TIMES: + { + result = left * right; + break; + } + case ExplicitTokensTokens.DIVIDE: + { + result = left / right; + break; + } + } + + return result; + } + + + [Prefix("'-'", Associativity.Right, 100)] + public double PreFixExpression(Token operation, double value) + { + return -value; + } + + [Postfix("'!'", Associativity.Left, 110)] + public double PostFixExpression(double value, Token operation) + { + double factorial = 1; + for (int i = 0; i < value; i++) + { + factorial *= i; + } + + return factorial; + } + + + + + + +} \ No newline at end of file diff --git a/src/samples/ExplicitTokens/ExplicitTokensExpressionParserGenerator.cs b/src/samples/ExplicitTokens/ExplicitTokensExpressionParserGenerator.cs new file mode 100644 index 00000000..a3a7245e --- /dev/null +++ b/src/samples/ExplicitTokens/ExplicitTokensExpressionParserGenerator.cs @@ -0,0 +1,10 @@ +using sly.sourceGenerator; + +namespace ExplicitTokens; + + +[ParserGenerator(typeof(ExplicitTokensTokens), typeof(ExplicitTokensExpressionParser),typeof(double))] +public partial class ExplicitTokensExpressionParserGenerator : AbstractParserGenerator +{ + +} \ No newline at end of file diff --git a/src/samples/ExplicitTokens/ExplicitTokensParser.cs b/src/samples/ExplicitTokens/ExplicitTokensParser.cs new file mode 100644 index 00000000..82e4e6fe --- /dev/null +++ b/src/samples/ExplicitTokens/ExplicitTokensParser.cs @@ -0,0 +1,63 @@ +using sly.lexer; +using sly.parser.generator; + +namespace ExplicitTokens; + +[ParserRoot("expression")] +public class ExplicitTokensParser +{ + [Production("primary: DOUBLE")] + public double Primary(Token doubleToken) + { + return doubleToken.DoubleValue; + } + + [Production("primary : 'bozzo'[d]")] + public double Bozzo() + { + return 42.0; + } + + [Production("primary : TEST[d]")] + public double Test() + { + return 0.0; + } + + + [Production("expression : primary ['+' | '-'] expression")] + + + public double Expression(double left, Token operatorToken, double right) + { + double result = 0.0; + + + switch (operatorToken.StringWithoutQuotes) + { + case "+": + { + result = left + right; + break; + } + case "-": + { + result = left - right; + break; + } + } + + return result; + } + + + [Production("expression : primary ")] + public double Simple(double value) + { + return value; + } + + + + +} \ No newline at end of file diff --git a/src/samples/ExplicitTokens/ExplicitTokensParserGenerator.cs b/src/samples/ExplicitTokens/ExplicitTokensParserGenerator.cs new file mode 100644 index 00000000..9b0ac2b7 --- /dev/null +++ b/src/samples/ExplicitTokens/ExplicitTokensParserGenerator.cs @@ -0,0 +1,9 @@ +using sly.sourceGenerator; + +namespace ExplicitTokens; + +[ParserGenerator(typeof(ExplicitTokensTokens), typeof(ExplicitTokensParser), typeof(double))] +public partial class ExplicitTokensParserGenerator : AbstractParserGenerator +{ + +} \ No newline at end of file diff --git a/src/samples/ExplicitTokens/ExplicitTokensTokens.cs b/src/samples/ExplicitTokens/ExplicitTokensTokens.cs new file mode 100644 index 00000000..bd9bc792 --- /dev/null +++ b/src/samples/ExplicitTokens/ExplicitTokensTokens.cs @@ -0,0 +1,27 @@ +using sly.lexer; + +namespace ExplicitTokens; + +[Lexer(IgnoreWS = true, IgnoreEOL = true)] +public enum ExplicitTokensTokens +{ + [MultiLineComment("/*","*/")] + MULTILINECOMMENT = 1, + + [SingleLineComment("//")] + SINGLELINECOMMENT = 2, + + [Lexeme(GenericToken.Identifier, IdentifierType.AlphaNumeric)] + ID = 3, + + [Lexeme(GenericToken.Double, channel:101)] + DOUBLE = 4, + + [Keyword("Test")] + TEST = 5, + [Sugar("*")] + TIMES = 6, + + [Sugar("/")] + DIVIDE = 7 +} \ No newline at end of file diff --git a/tests/CslyGenerator.Tests/CslyGenerator.Tests.csproj b/tests/CslyGenerator.Tests/CslyGenerator.Tests.csproj index 602743d6..ede69ce6 100644 --- a/tests/CslyGenerator.Tests/CslyGenerator.Tests.csproj +++ b/tests/CslyGenerator.Tests/CslyGenerator.Tests.csproj @@ -26,6 +26,7 @@ + diff --git a/tests/CslyGenerator.Tests/SourceGeneratorTests.cs b/tests/CslyGenerator.Tests/SourceGeneratorTests.cs index ede64612..3d4feca9 100644 --- a/tests/CslyGenerator.Tests/SourceGeneratorTests.cs +++ b/tests/CslyGenerator.Tests/SourceGeneratorTests.cs @@ -63,6 +63,7 @@ private ImmutableArray generateSource(string source, string classNam [InlineData("/data/callbacks.txt", "ParserCallbacksGenerator")] [InlineData("/data/labels.txt", "DuplicateLabelLexerGenerator")] [InlineData("/data/expression.txt", "ExpressionParserGenerator")] + [InlineData("/data/explicits.txt", "ExplicitTokensExpressionParserGenerator")] public void TestGenerator(string source, string className) { var code = _embeddedResourceFileSystem.ReadAllText(source); diff --git a/tests/ParserTests/ExplicitTokensExpressionParser.cs b/tests/CslyGenerator.Tests/data/explicits.txt similarity index 75% rename from tests/ParserTests/ExplicitTokensExpressionParser.cs rename to tests/CslyGenerator.Tests/data/explicits.txt index 24f811ef..238256b8 100644 --- a/tests/ParserTests/ExplicitTokensExpressionParser.cs +++ b/tests/CslyGenerator.Tests/data/explicits.txt @@ -1,11 +1,35 @@ -using System; -using expressionparser; -using sly.lexer; -using sly.parser.generator; +[ParserGenerator(typeof(ExplicitTokensTokens), typeof(ExplicitTokensExpressionParser),typeof(double))] +public class ExplicitTokensExpressionParserGenerator : AbstractParserGenerator +{ + +} -namespace ParserTests +[Lexer(IgnoreWS = true, IgnoreEOL = true)] +public enum ExplicitTokensTokens { - public class ExplicitTokensExpressionParser + [MultiLineComment("/*","*/")] + MULTILINECOMMENT = 1, + + [SingleLineComment("//")] + SINGLELINECOMMENT = 2, + + [Lexeme(GenericToken.Identifier, IdentifierType.AlphaNumeric)] + ID = 3, + + [Lexeme(GenericToken.Double, channel:101)] + DOUBLE = 4, + + [Keyword("Test")] + TEST = 5, + [Sugar("*")] + TIMES = 6, + + [Sugar("/")] + DIVIDE = 7 +} + + +public class ExplicitTokensExpressionParser { [Production("primary: DOUBLE")] [Operand] @@ -87,5 +111,4 @@ public double PostFixExpression(double value, Token operat - } -} \ No newline at end of file +} \ No newline at end of file diff --git a/tests/ParserTests/ExplicitTokensGeneratorTests.cs b/tests/ParserTests/ExplicitTokensGeneratorTests.cs new file mode 100644 index 00000000..5715eae6 --- /dev/null +++ b/tests/ParserTests/ExplicitTokensGeneratorTests.cs @@ -0,0 +1,120 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using csly.whileLang.model; +using ExplicitTokens; +using NFluent; +using sly.buildresult; +using sly.lexer; +using sly.parser; +using sly.parser.generator; +using sly.parser.generator.visitor; +using Xunit; + +namespace ParserTests +{ + + + + public class ExplicitTokensGeneratorTests + { + private BuildResult> BuildParser() + { + var generator = new ExplicitTokensParserGenerator(); + var result = generator.GetParser(); + return result; + } + + private BuildResult> BuildExpressionParser() + { + var generator = new ExplicitTokensExpressionParserGenerator(); + var result = generator.GetParser(); + return result; + } + + [Fact] + public void BuildParserTest() + { + var parser = BuildParser(); + Check.That(parser.IsOk).IsTrue(); + Check.That(parser.Result).IsNotNull(); + var r = parser.Result.Parse("2.0 - 2.0 + bozzo + Test"); + + + + Check.That(r).IsOkParsing(); + // grammar is left associative so expression really is + // (2.0 - (2.0 + (bozzo + Test))) = 2 - ( 2 + (42 + 0)) = 2 - (2 + 42) = 2 - 44 = -42 + Check.That(r.Result).IsEqualTo(-42.0d); + } + + [Fact] + public void BuildExpressionParserTest() + { + var parser = BuildExpressionParser(); + Check.That(parser.IsOk).IsTrue(); + Check.That(parser.Result).IsNotNull(); + var r = parser.Result.Parse("2.0 - 2.0 + bozzo + Test"); + Check.That(r).IsOkParsing(); + var tree = r.SyntaxTree; + var graphviz = new GraphVizEBNFSyntaxTreeVisitor(); + var dump = tree.Dump("\t"); + var json = $@"{{ +{tree.ToJson()} +}}"; + + var root = graphviz.VisitTree(tree); + string graph = graphviz.Graph.Compile(); + Check.That(graph).Contains(@"label=""\""bozzo\""""") + .And.Contains(@"label=""\""+\"""""); + + Check.That(r.Result).IsEqualTo(2 - 2 + 42 + 0); + } + + [Fact] + public void TestErrorWhenUsingImplicitTokensAndRegexLexer() + { + var parserInstance = new RegexLexAndExplicitTokensParser(); + var builder = new ParserBuilder(); + var result = builder.BuildParser(parserInstance, ParserType.EBNF_LL_RECURSIVE_DESCENT, nameof(RegexLexAndExplicitTokensParser)+"_expressions"); + Check.That(result.IsError).IsTrue(); + Check.That(result.Errors).CountIs(1); + Check.That(result.Errors.First().Code).IsEqualTo(ErrorCodes.LEXER_CANNOT_USE_IMPLICIT_TOKENS_WITH_REGEX_LEXER); + } + + [Fact] + public void TestNoIdentifierPatternSuppliedWithImplicitTokens() + { + var parserInstance = new NoIdentifierParser(); + var builder = new ParserBuilder(); + var result = builder.BuildParser(parserInstance, ParserType.EBNF_LL_RECURSIVE_DESCENT, "main"); + Check.That(result.IsError).IsFalse(); + Check.That(result.Result).IsNotNull(); + var r = result.Result.Parse("test 1 test 2 test 3"); + Check.That(r.IsError).IsFalse(); + Check.That(r.Result).IsEqualTo("test:1,test:2,test:3"); + } + + [Fact] + public void Test() + { + var parserInstance = new Parse(); + var builder = new ParserBuilder(); + var result = builder.BuildParser(parserInstance, ParserType.EBNF_LL_RECURSIVE_DESCENT, "program"); + Check.That(result).IsOk(); + var r = result.Result.Parse(@" +if a == 1.0 then + b = 1.0 + 2.0 * 3.0 +else + b = 2.0 + a +c = 3.0 +"); + Check.That(r).IsOkParsing(); + //"(condition:(a == 1.0,(b = ( 1.0 + ( 2.0 * 3.0 ) )),(b = ( 2.0 + a ))))(c = 3.0)" + Check.That(r.Result).IsEqualTo("((condition:(a == 1.0,(b = ( 1.0 + ( 2.0 * 3.0 ) )),(b = ( 2.0 + a )))),(c = 3.0))"); + } + + } + +} diff --git a/tests/ParserTests/ExplicitTokensParser.cs b/tests/ParserTests/ExplicitTokensParser.cs deleted file mode 100644 index 3578ef13..00000000 --- a/tests/ParserTests/ExplicitTokensParser.cs +++ /dev/null @@ -1,63 +0,0 @@ -using sly.lexer; -using sly.parser.generator; - -namespace ParserTests -{ - public class ExplicitTokensParser - { - [Production("primary: DOUBLE")] - public double Primary(Token doubleToken) - { - return doubleToken.DoubleValue; - } - - [Production("primary : 'bozzo'[d]")] - public double Bozzo() - { - return 42.0; - } - - [Production("primary : TEST[d]")] - public double Test() - { - return 0.0; - } - - - [Production("expression : primary ['+' | '-'] expression")] - - - public double Expression(double left, Token operatorToken, double right) - { - double result = 0.0; - - - switch (operatorToken.StringWithoutQuotes) - { - case "+": - { - result = left + right; - break; - } - case "-": - { - result = left - right; - break; - } - } - - return result; - } - - - [Production("expression : primary ")] - public double Simple(double value) - { - return value; - } - - - - - } -} \ No newline at end of file diff --git a/tests/ParserTests/ExplicitTokensTests.cs b/tests/ParserTests/ExplicitTokensTests.cs index fbc8caec..724186f2 100644 --- a/tests/ParserTests/ExplicitTokensTests.cs +++ b/tests/ParserTests/ExplicitTokensTests.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Text; using csly.whileLang.model; +using ExplicitTokens; using NFluent; using sly.buildresult; using sly.lexer; diff --git a/tests/ParserTests/ExplicitTokensTokens.cs b/tests/ParserTests/ExplicitTokensTokens.cs deleted file mode 100644 index b484f6c8..00000000 --- a/tests/ParserTests/ExplicitTokensTokens.cs +++ /dev/null @@ -1,28 +0,0 @@ -using sly.lexer; - -namespace ParserTests -{ - [Lexer(IgnoreWS = true, IgnoreEOL = true)] - public enum ExplicitTokensTokens - { - [MultiLineComment("/*","*/")] - MULTILINECOMMENT = 1, - - [SingleLineComment("//")] - SINGLELINECOMMENT = 2, - - [Lexeme(GenericToken.Identifier, IdentifierType.AlphaNumeric)] - ID = 3, - - [Lexeme(GenericToken.Double, channel:101)] - DOUBLE = 4, - - [Keyword("Test")] - TEST = 5, - [Sugar("*")] - TIMES = 6, - - [Sugar("/")] - DIVIDE = 7 - } -} \ No newline at end of file diff --git a/tests/ParserTests/ParserTests.csproj b/tests/ParserTests/ParserTests.csproj index 789aa3e9..9cc4a390 100644 --- a/tests/ParserTests/ParserTests.csproj +++ b/tests/ParserTests/ParserTests.csproj @@ -22,6 +22,7 @@ + @@ -33,7 +34,7 @@ - +