diff --git a/Sources/Props/Benchmark.Build.props b/Sources/Props/Benchmark.Build.props index a18f50c5..41efffba 100644 --- a/Sources/Props/Benchmark.Build.props +++ b/Sources/Props/Benchmark.Build.props @@ -1,15 +1,20 @@ + + false + - net6.0 + net8.0 + enable + enable Exe false false - + diff --git a/Sources/SynKit/Benchmarks/.gitignore b/Sources/SynKit/Benchmarks/.gitignore index e69de29b..91a99327 100644 --- a/Sources/SynKit/Benchmarks/.gitignore +++ b/Sources/SynKit/Benchmarks/.gitignore @@ -0,0 +1 @@ +BenchmarkDotNet.Artifacts/ diff --git a/Sources/SynKit/Benchmarks/Directory.Build.props b/Sources/SynKit/Benchmarks/Directory.Build.props new file mode 100644 index 00000000..91415dd9 --- /dev/null +++ b/Sources/SynKit/Benchmarks/Directory.Build.props @@ -0,0 +1,8 @@ + + + + + + Yoakke.SynKit.$(MSBuildProjectName) + + diff --git a/Sources/SynKit/Benchmarks/Parser.Benchmarks/ExpressionBenchmarks.cs b/Sources/SynKit/Benchmarks/Parser.Benchmarks/ExpressionBenchmarks.cs new file mode 100644 index 00000000..3930f600 --- /dev/null +++ b/Sources/SynKit/Benchmarks/Parser.Benchmarks/ExpressionBenchmarks.cs @@ -0,0 +1,94 @@ +// Copyright (c) 2021-2022 Yoakke. +// Licensed under the Apache License, Version 2.0. +// Source repository: https://github.com/LanguageDev/Yoakke + +using BenchmarkDotNet.Attributes; +using Yoakke.SynKit.Lexer; +using Yoakke.SynKit.Parser; +using Yoakke.SynKit.Lexer.Attributes; +using Yoakke.SynKit.Parser.Attributes; + +namespace Yoakke.SynKit.Parser.Benchmarks; + +public partial class ExpressionBenchmarks +{ + private static string source = "(((((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))) + ((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))))+(((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))) + ((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))))))))+((((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))) + ((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))))+(((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))) + ((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))))))))) + (((((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))) + ((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))))+(((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))) + ((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))))))))+((((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))) + ((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))))+(((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))) + ((((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))+(((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))) + ((((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1))) + (((2 + 2) + (1 + 1)) + ((2 + 2) + (1 + 1)))))))))"; + + [Benchmark] + public ParseResult Parse() + { + return new Parser(new Lexer(source)).ParseProgram(); + } + + [Benchmark] + public List> Lex() + { + return new Lexer(source).LexAll(); + } + +} + +public enum TokenType +{ + [Error] Error, + [End] End, + [Ignore][Regex(Regexes.Whitespace)] Whitespace, + + [Token("(")] OpenParen, + [Token(")")] CloseParen, + + [Token("+")] Add, + [Token("-")] Sub, + [Token("*")] Mul, + [Token("/")] Div, + [Token("%")] Mod, + [Token("^")] Exp, + + [Token(";")] Semicol, + + [Regex(Regexes.IntLiteral)] IntLit, +} + +[Lexer(typeof(TokenType))] +public partial class Lexer +{ + public List> LexAll() + { + var list = new List>(); + while (true) + { + var token = Next(); + list.Add(token); + if (token.Kind == TokenType.End) break; + } + return list; + } +} + +[Parser(typeof(TokenType))] +public partial class Parser +{ + [Rule("program: expression ';'")] + public static int Program(int n, IToken _) => n; + + [Right("^")] + [Left("*", "/", "%")] + [Left("+", "-")] + [Rule("expression")] + public static int BinOp(int a, IToken op, int b) => op.Text switch + { + "^" => (int)Math.Pow(a, b), + "*" => a * b, + "/" => a / b, + "%" => a % b, + "+" => a + b, + "-" => a - b, + _ => throw new NotImplementedException(), + }; + + [Rule("expression : '(' expression ')'")] + public static int Grouping(IToken _1, int n, IToken _2) => n; + + [Rule("expression : IntLit")] + public static int IntLit(IToken token) => int.Parse(token.Text); +} diff --git a/Sources/SynKit/Benchmarks/Parser.Benchmarks/Parser.Benchmarks.csproj b/Sources/SynKit/Benchmarks/Parser.Benchmarks/Parser.Benchmarks.csproj new file mode 100644 index 00000000..43369c59 --- /dev/null +++ b/Sources/SynKit/Benchmarks/Parser.Benchmarks/Parser.Benchmarks.csproj @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Sources/SynKit/Benchmarks/Parser.Benchmarks/Program.cs b/Sources/SynKit/Benchmarks/Parser.Benchmarks/Program.cs new file mode 100644 index 00000000..b9a3713a --- /dev/null +++ b/Sources/SynKit/Benchmarks/Parser.Benchmarks/Program.cs @@ -0,0 +1,8 @@ +// Copyright (c) 2021-2022 Yoakke. +// Licensed under the Apache License, Version 2.0. +// Source repository: https://github.com/LanguageDev/Yoakke + +using BenchmarkDotNet.Running; + +BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); + diff --git a/Sources/SynKit/Libraries/Lexer.Generator/LexerSourceGenerator.cs b/Sources/SynKit/Libraries/Lexer.Generator/LexerSourceGenerator.cs index 7f2e6333..a1bab260 100644 --- a/Sources/SynKit/Libraries/Lexer.Generator/LexerSourceGenerator.cs +++ b/Sources/SynKit/Libraries/Lexer.Generator/LexerSourceGenerator.cs @@ -358,7 +358,7 @@ int MakeState() Name = lexerModel.LexerType.Name, GenericArgs = lexerModel.LexerType.TypeArguments.Select(t => t.Name).ToList(), }, - TokenType = lexerModel.TokenType.ToDisplayString(), + TokenType = lexerModel.TokenType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), ImplicitConstructor = lexerModel.LexerType.HasNoUserDefinedCtors() && lexerModel.SourceField is null, SourceName = lexerModel.SourceField?.Name ?? "CharStream", EndTokenName = lexerModel.EndVariant.Name, diff --git a/Sources/Yoakke.sln b/Sources/Yoakke.sln index 6c54b85d..e10b49c5 100644 --- a/Sources/Yoakke.sln +++ b/Sources/Yoakke.sln @@ -86,6 +86,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{55 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Parser.Generator.Tests", "SynKit\Tests\Parser.Generator.Tests\Parser.Generator.Tests.csproj", "{CCD7B565-36BB-F60A-17DC-BD62000BD0C5}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Parser.Benchmarks", "SynKit\Benchmarks\Parser.Benchmarks\Parser.Benchmarks.csproj", "{6A52197D-7F3F-46F5-B549-A4DFEDD48C48}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Benchmarks", "Benchmarks", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -200,6 +204,10 @@ Global {CCD7B565-36BB-F60A-17DC-BD62000BD0C5}.Debug|Any CPU.Build.0 = Debug|Any CPU {CCD7B565-36BB-F60A-17DC-BD62000BD0C5}.Release|Any CPU.ActiveCfg = Release|Any CPU {CCD7B565-36BB-F60A-17DC-BD62000BD0C5}.Release|Any CPU.Build.0 = Release|Any CPU + {6A52197D-7F3F-46F5-B549-A4DFEDD48C48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6A52197D-7F3F-46F5-B549-A4DFEDD48C48}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6A52197D-7F3F-46F5-B549-A4DFEDD48C48}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6A52197D-7F3F-46F5-B549-A4DFEDD48C48}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -235,6 +243,8 @@ Global {F51DEFFD-626F-4040-9227-A59BF67F4F53} = {807C54A7-C3E0-4F31-95A8-C9FD3F4D5660} {55692E6E-198F-4699-B6D3-CBA49D22A2D3} = {807C54A7-C3E0-4F31-95A8-C9FD3F4D5660} {CCD7B565-36BB-F60A-17DC-BD62000BD0C5} = {F51DEFFD-626F-4040-9227-A59BF67F4F53} + {6A52197D-7F3F-46F5-B549-A4DFEDD48C48} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {807C54A7-C3E0-4F31-95A8-C9FD3F4D5660} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {1EDE8F07-AE3A-4556-AEF0-3AC518F18F92}