├── .all-contributorsrc ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug-report.md │ ├── feature-request.md │ ├── module-request.md │ ├── question.md │ └── something-else.md ├── pull_request_template.md ├── resources │ ├── DocfxBadge.svg │ ├── UsingYoakke.svg │ ├── YoakkeLogo.png │ ├── YoakkeLogo.svg │ └── YoakkeLogoAnimated.svg └── workflows │ ├── Docfx.yml │ ├── PublishNightly.yml │ ├── PublishPackages.yml │ └── RunTests.yml ├── .gitignore ├── CONTRIBUTING.md ├── Documentation ├── README.md └── docfx_project │ ├── .gitignore │ ├── api │ ├── .gitignore │ └── index.md │ ├── articles │ ├── fixing-vs-issues.md │ ├── intro.md │ ├── lexer.md │ ├── parser.md │ ├── reporting.md │ └── toc.yml │ ├── docfx.json │ ├── images │ └── fixing-vs-issues │ │ ├── vs-options.png │ │ ├── vs-sourcegenerator.png │ │ ├── vs-texteditor.png │ │ └── vs-tools.png │ ├── index.md │ └── toc.yml ├── LICENSE ├── README.md └── Sources ├── .editorconfig ├── .idea └── .idea.Yoakke │ └── .idea │ ├── .gitignore │ ├── .name │ ├── encodings.xml │ ├── indexLayout.xml │ └── vcs.xml ├── Benchmarks └── .gitignore ├── Examples └── .gitignore ├── Props ├── Benchmark.Build.props ├── Example.Build.props ├── Package.Build.props ├── Shared.Build.props ├── SourceGenerator.Build.props └── Test.Build.props ├── Shared ├── Benchmarks │ └── .gitignore ├── Libraries │ ├── Collections │ │ ├── Collections.csproj │ │ ├── Dense │ │ │ ├── Combiner.cs │ │ │ ├── DenseMap.cs │ │ │ ├── DenseSet.cs │ │ │ ├── ICombiner.cs │ │ │ ├── IDenseMap.cs │ │ │ ├── IDenseSet.cs │ │ │ ├── IReadOnlyDenseMap.cs │ │ │ └── IReadOnlyDenseSet.cs │ │ ├── Graphs │ │ │ └── BreadthFirst.cs │ │ ├── IDeque.cs │ │ ├── Internal │ │ │ └── SortedIntervalList.cs │ │ ├── Intervals │ │ │ ├── Bound.cs │ │ │ ├── BoundComparer.cs │ │ │ ├── Interval.Factory.cs │ │ │ ├── Interval.cs │ │ │ ├── IntervalComparer.cs │ │ │ ├── IntervalRelation.cs │ │ │ ├── LowerBound.cs │ │ │ └── UpperBound.cs │ │ ├── RingBuffer.cs │ │ ├── TupleEqualityComparer.cs │ │ ├── Values │ │ │ ├── IReadOnlyValueDictionary.cs │ │ │ ├── IReadOnlyValueList.cs │ │ │ ├── ReadOnlyValueDictionary.cs │ │ │ ├── ReadOnlyValueList.cs │ │ │ └── ValueCollectionExtensions.cs │ │ └── key.snk │ ├── Directory.Build.props │ ├── Polyfill │ │ ├── DictionaryExtensions.cs │ │ ├── EnumerableExtensions.cs │ │ ├── IReadOnlySet.cs │ │ ├── KeyValuePairExtensions.cs │ │ ├── Polyfill.csproj │ │ ├── QueueExtensions.cs │ │ ├── ReferenceEqualityComparer.cs │ │ ├── StackExtensions.cs │ │ ├── StringExtensions.cs │ │ ├── TypeExtensions.cs │ │ └── key.snk │ ├── SourceGenerator.Common │ │ ├── AssemblyExtensions.cs │ │ ├── RoslynExtensions │ │ │ ├── AttributeDataExtensions.cs │ │ │ ├── AttributeDescriptor.cs │ │ │ ├── SymbolExtensions.cs │ │ │ ├── SyntaxExtensions.cs │ │ │ └── TypeEnclosure.cs │ │ ├── ScribanExtensions.cs │ │ ├── SourceGenerator.Common.csproj │ │ ├── SourceGeneratorExtensions.cs │ │ └── key.snk │ └── Streams │ │ ├── BufferedStream.cs │ │ ├── EnumerableStream.cs │ │ ├── FilteredStream.cs │ │ ├── IPeekableStream.cs │ │ ├── IStream.cs │ │ ├── MemoryStream.cs │ │ ├── PeekStream.cs │ │ ├── StreamExtensions.cs │ │ ├── Streams.csproj │ │ └── key.snk └── Tests │ ├── Collections.Tests │ ├── Collections.Tests.csproj │ ├── DenseMapTests.cs │ ├── DenseSetTests.cs │ ├── IntervalTests.cs │ ├── RingBufferTests.cs │ ├── ValueDictionaryTests.cs │ ├── ValueListTests.cs │ └── key.snk │ ├── Directory.Build.props │ └── Streams.Tests │ ├── Streams.Tests.csproj │ ├── StreamsTests.cs │ └── key.snk ├── SynKit ├── Benchmarks │ ├── .gitignore │ ├── Directory.Build.props │ └── Parser.Benchmarks │ │ ├── ExpressionBenchmarks.cs │ │ ├── ExpressionParser.cs │ │ ├── Parser.Benchmarks.csproj │ │ ├── Program.cs │ │ └── Properties │ │ └── launchSettings.json ├── Examples │ ├── Automata.Sample │ │ ├── Automata.Sample.csproj │ │ ├── Program.cs │ │ └── key.snk │ ├── C.Syntax.Sample │ │ ├── C.Syntax.Sample.csproj │ │ ├── Program.cs │ │ └── key.snk │ ├── Directory.Build.props │ ├── Lexer.Sample │ │ ├── Lexer.Sample.csproj │ │ ├── Program.cs │ │ └── key.snk │ ├── Parser.Sample │ │ ├── Parser.Sample.csproj │ │ ├── Program.cs │ │ └── key.snk │ └── Reporting.Sample │ │ ├── Program.cs │ │ ├── Reporting.Sample.csproj │ │ └── key.snk ├── Libraries │ ├── Automata │ │ ├── Automata.csproj │ │ ├── Dense │ │ │ ├── DenseDfa.cs │ │ │ ├── DenseNfa.cs │ │ │ ├── IDenseDfa.cs │ │ │ ├── IDenseFiniteAutomaton.cs │ │ │ ├── IDenseNfa.cs │ │ │ ├── IReadOnlyDenseDfa.cs │ │ │ ├── IReadOnlyDenseFiniteAutomaton.cs │ │ │ └── IReadOnlyDenseNfa.cs │ │ ├── DfaExtensions.cs │ │ ├── EpsilonTransition.cs │ │ ├── IDfa.cs │ │ ├── IFiniteAutomaton.cs │ │ ├── INfa.cs │ │ ├── IReadOnlyDfa.cs │ │ ├── IReadOnlyFiniteAutomaton.cs │ │ ├── IReadOnlyNfa.cs │ │ ├── IStateCombiner.cs │ │ ├── Internal │ │ │ ├── DotWriter.cs │ │ │ ├── EquivalenceTable.cs │ │ │ ├── ObservableCollection.cs │ │ │ └── TrivialImpl.cs │ │ ├── NfaExtensions.cs │ │ ├── RegExAst │ │ │ ├── IRegExNode.cs │ │ │ ├── RegEx.cs │ │ │ ├── RegExAnyNode.cs │ │ │ ├── RegExLitNode.cs │ │ │ ├── RegExNopNode.cs │ │ │ ├── RegExOptNode.cs │ │ │ ├── RegExOrNode.cs │ │ │ ├── RegExRangeNode.cs │ │ │ ├── RegExRep0Node.cs │ │ │ ├── RegExRep1Node.cs │ │ │ ├── RegExRepBetweenNode.cs │ │ │ └── RegExSeqNode.cs │ │ ├── Sparse │ │ │ ├── Dfa.cs │ │ │ ├── IReadOnlySparseDfa.cs │ │ │ ├── IReadOnlySparseFiniteAutomaton.cs │ │ │ ├── IReadOnlySparseNfa.cs │ │ │ ├── ISparseDfa.cs │ │ │ ├── ISparseFiniteAutomaton.cs │ │ │ ├── ISparseNfa.cs │ │ │ └── Nfa.cs │ │ ├── StateCombiner.cs │ │ ├── StateSet.cs │ │ ├── Transition.cs │ │ └── key.snk │ ├── C.Syntax │ │ ├── C.Syntax.csproj │ │ ├── CLexer.cs │ │ ├── CPreProcessor.cs │ │ ├── CToken.cs │ │ ├── CTokenType.cs │ │ ├── IMacro.cs │ │ ├── IPreProcessor.cs │ │ ├── MacroElement.cs │ │ ├── Macros │ │ │ └── CounterMacro.cs │ │ ├── PreProcessorExtensions.cs │ │ ├── UserMacro.cs │ │ └── key.snk │ ├── Directory.Build.props │ ├── Lexer.Generator │ │ ├── Diagnostics.cs │ │ ├── InjectedSources │ │ │ ├── CharSourceAttribute.cs │ │ │ ├── EndAttribute.cs │ │ │ ├── ErrorAttribute.cs │ │ │ ├── IgnoreAttribute.cs │ │ │ ├── LexerAttribute.cs │ │ │ ├── RegexAttribute.cs │ │ │ └── TokenAttribute.cs │ │ ├── Lexer.Generator.csproj │ │ ├── LexerSourceGenerator.cs │ │ ├── Model │ │ │ ├── LexerModel.cs │ │ │ └── TokenModel.cs │ │ ├── RegExParser.cs │ │ ├── Templates │ │ │ └── lexer.sbncs │ │ └── key.snk │ ├── Lexer │ │ ├── CharStreamExtensions.cs │ │ ├── ICharStream.cs │ │ ├── ILexer.cs │ │ ├── IToken.Generic.cs │ │ ├── IToken.cs │ │ ├── Lexer.csproj │ │ ├── LexerExtensions.cs │ │ ├── Regexes.cs │ │ ├── TextReaderCharStream.cs │ │ ├── Token.cs │ │ └── key.snk │ ├── Parser.Generator │ │ ├── Ast │ │ │ ├── BnfAst.Alt.cs │ │ │ ├── BnfAst.Call.cs │ │ │ ├── BnfAst.FoldLeft.cs │ │ │ ├── BnfAst.Group.cs │ │ │ ├── BnfAst.Literal.cs │ │ │ ├── BnfAst.MethodCall.cs │ │ │ ├── BnfAst.Opt.cs │ │ │ ├── BnfAst.Placeholder.cs │ │ │ ├── BnfAst.Rep0.cs │ │ │ ├── BnfAst.Rep1.cs │ │ │ ├── BnfAst.Seq.cs │ │ │ ├── BnfAst.Transform.cs │ │ │ └── BnfAst.cs │ │ ├── BnfDesugar.cs │ │ ├── Diagnostics.cs │ │ ├── InjectedSources │ │ │ ├── CustomParserAttribute.cs │ │ │ ├── LeftAttribute.cs │ │ │ ├── ParserAttribute.cs │ │ │ ├── RightAttribute.cs │ │ │ ├── RuleAttribute.cs │ │ │ └── TokenSourceAttribute.cs │ │ ├── Model │ │ │ ├── ParserModel.cs │ │ │ ├── PrecedenceEntry.cs │ │ │ ├── Rule.cs │ │ │ ├── RuleSet.cs │ │ │ └── TokenKindSet.cs │ │ ├── Parser.Generator.csproj │ │ ├── ParserSourceGenerator.cs │ │ ├── Syntax │ │ │ ├── BnfLexer.cs │ │ │ ├── BnfParser.cs │ │ │ ├── BnfToken.cs │ │ │ └── BnfTokenType.cs │ │ ├── Templates │ │ │ └── parser.sbncs │ │ ├── TypeNames.cs │ │ └── key.snk │ ├── Parser │ │ ├── Combinator.cs │ │ ├── ParseError.cs │ │ ├── ParseErrorElement.cs │ │ ├── ParseErrorElementDictionary.cs │ │ ├── ParseOk.cs │ │ ├── ParseResult.Factory.cs │ │ ├── ParseResult.cs │ │ ├── Parser.csproj │ │ ├── Punctuated.cs │ │ ├── PunctuatedValue.cs │ │ └── key.snk │ ├── Reporting │ │ ├── Diagnostics.cs │ │ ├── FootnoteDiagnosticInfo.cs │ │ ├── IDiagnosticInfo.cs │ │ ├── Present │ │ │ ├── ColoredBuffer.cs │ │ │ ├── ColoredToken.cs │ │ │ ├── DiagnosticsStyle.cs │ │ │ ├── IDiagnosticsPresenter.cs │ │ │ ├── ISyntaxHighlighter.cs │ │ │ ├── NullSyntaxHighlighter.cs │ │ │ ├── SyntaxHighlightStyle.cs │ │ │ ├── TextDiagnosticsPresenter.cs │ │ │ └── TokenKind.cs │ │ ├── Reporting.csproj │ │ ├── Severity.cs │ │ ├── SourceDiagnosticInfo.cs │ │ └── key.snk │ └── Text │ │ ├── ISourceFile.cs │ │ ├── Location.cs │ │ ├── Metrics │ │ ├── IStringMetric.cs │ │ ├── LevenshteinDistance.cs │ │ └── OptimalStringAlignmentDistance.cs │ │ ├── Position.cs │ │ ├── Range.cs │ │ ├── SourceFile.cs │ │ ├── Text.csproj │ │ └── key.snk ├── README.md └── Tests │ ├── Automata.Tests │ ├── Automata.Tests.csproj │ ├── AutomatonTestBase.cs │ ├── DfaTests.cs │ ├── EpsilonNfaTests.cs │ ├── NfaTests.cs │ └── key.snk │ ├── C.Syntax.Tests │ ├── C.Syntax.Tests.csproj │ ├── CLexerTests.cs │ ├── CPreProcessorTests.cs │ └── key.snk │ ├── Directory.Build.props │ ├── Lexer.Tests │ ├── AdvancedLexerGeneratorTests.cs │ ├── CharStreamTests.cs │ ├── Issue140Tests.cs │ ├── Issue17Tests.cs │ ├── Lexer.Tests.csproj │ ├── LexerGeneratorTests.cs │ ├── LexerGeneratorWithoutNamespaceTests.cs │ ├── RegexesTests.cs │ ├── TestBase.cs │ ├── TokenTests.cs │ └── key.snk │ ├── Parser.Generator.Tests │ ├── CodeGenerationTestBase.cs │ ├── ExpressionParserTests.cs │ ├── Parser.Generator.Tests.csproj │ ├── key.snk │ └── verified │ │ └── ExpressionParserTests.SimpleMathExpression.verified.txt │ ├── Parser.Tests │ ├── CombinatorTests.cs │ ├── ExpressionParserTests.cs │ ├── IndirectLeftRecursionTests.cs │ ├── Issue138Tests.cs │ ├── Issue17Tests.cs │ ├── Issue59Tests.cs │ ├── Issue62Tests.cs │ ├── LeftRecursionTests.cs │ ├── ParseErrorTests.cs │ ├── Parser.Tests.csproj │ ├── PunctuatedTests.cs │ └── key.snk │ ├── Reporting.Tests │ ├── AssertUtils.cs │ ├── Reporting.Tests.csproj │ ├── TextPresenterTests.cs │ ├── UnfilledTestPresenterTests.cs │ └── key.snk │ └── Text.Tests │ ├── PositionTests.cs │ ├── RangeTests.cs │ ├── SourceFileTests.cs │ ├── StringMetricsTests.cs │ ├── Text.Tests.csproj │ └── key.snk ├── Tests └── .gitignore ├── Tools ├── .gitignore ├── Directory.Build.props └── NugetMaintainer │ ├── NugetMaintainer.csproj │ ├── Program.cs │ └── key.snk └── Yoakke.sln /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.png binary 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a bug report to help us fix the issue 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **Which libraries does it affect?** 14 | Which Yoakke modules are you using that causes this problem. 15 | 16 | **To Reproduce** 17 | Steps to reproduce the behavior: 18 | 1. Go to '...' 19 | 2. Click on '....' 20 | 3. Scroll down to '....' 21 | 4. See error 22 | 23 | **Expected behavior** 24 | A clear and concise description of what you expected to happen. 25 | 26 | **Environment (please complete the following information):** 27 | - OS: [e.g. Windows 10] 28 | - .NET version: [e.g. .NET 5] 29 | - Version [e.g. 1.1-preview] 30 | 31 | **Additional context** 32 | Add any other context about the problem here. 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest a feature for an existing module 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/module-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Module request 3 | about: Suggest a new module idea 4 | title: "[MODULE REQUEST]" 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **What area would this module cover? Please describe.** 11 | A clear and concise description of what this new model would help in. Ex. I'd like to generate ELF binaries but there's no way to do that yet without involving an external assembler [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. What would you like to see in the module? How will that fit into the existing ecosystem? 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: Ask something that wasn't clarified in the available documents 4 | title: '' 5 | labels: documentation, question 6 | assignees: '' 7 | 8 | --- 9 | 10 | Ask your question here. 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/something-else.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Something else 3 | about: If your issue does not fit into the other categories 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | Please describe your issue thoroughly. 11 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | If this is still work in progress, make sure to mark it as 'Draft'! You can change it back to ready, once you are done. 4 | 5 | 9 | 10 | **Please describe what this PR does, which issue(s) it solves** 11 | If there is no issue created yet, consider opening an issue first. You can link the related issue using a keyword and the issue number, like `Closes #12` or `Fixes #5`. 12 | 13 | 17 | 18 | -------------------------------------------------------------------------------- /.github/resources/YoakkeLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/.github/resources/YoakkeLogo.png -------------------------------------------------------------------------------- /.github/workflows/Docfx.yml: -------------------------------------------------------------------------------- 1 | name: 'Docfx generation' 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - master 8 | paths: 9 | - 'Sources/**' 10 | - 'Documentation/docfx_project/**' 11 | 12 | jobs: 13 | documentation: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Clone the repo 17 | uses: actions/checkout@v2 18 | - name: Setup .NET 19 | uses: actions/setup-dotnet@v1 20 | with: 21 | dotnet-version: '8.0.407' 22 | - name: Run DocFx 23 | uses: nikeee/docfx-action@v1.0.0 24 | with: 25 | args: Documentation/docfx_project/docfx.json 26 | - name: Publish to Github Pages 27 | uses: maxheld83/ghpages@master 28 | env: 29 | BUILD_DIR: Documentation/docfx_project/_site 30 | GH_PAT: ${{ secrets.GH_PAT }} 31 | -------------------------------------------------------------------------------- /.github/workflows/PublishNightly.yml: -------------------------------------------------------------------------------- 1 | name: 'Publish nightly' 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: '0 2 * * *' # run at 2 AM UTC 7 | 8 | jobs: 9 | check: 10 | continue-on-error: true 11 | runs-on: windows-latest 12 | outputs: 13 | status: ${{ join(steps.*.conclusion) }} 14 | steps: 15 | - id: clone-repo 16 | name: Clone the repo 17 | uses: actions/checkout@v2 18 | - id: commits-happened 19 | name: Check if commits happened in the last 72 hours 20 | run: | 21 | if([string]::IsNullOrWhitespace((git log ${GITHUB_REF##*/} --since="72 hours ago") -join '')) { 22 | Echo "No recent commits, skipping nightly build" 23 | Exit 1 24 | } 25 | deployment: 26 | runs-on: windows-latest 27 | needs: check 28 | if: "!contains(needs.check.outputs.status, 'failure')" 29 | steps: 30 | - name: Clone the repo 31 | uses: actions/checkout@v2 32 | - name: Setup .NET 33 | uses: actions/setup-dotnet@v1 34 | with: 35 | dotnet-version: '8.0.407' 36 | - name: Get current time 37 | uses: 1466587594/get-current-time@v2 38 | id: current-time 39 | with: 40 | format: Y.M.D-H.m.s 41 | - name: Build and package 42 | run: dotnet build Sources/Yoakke.sln --configuration Release /p:VersionPrefix=${{ steps.current-time.outputs.formattedTime }} /p:VersionSuffix=nightly /p:PackageReleaseNotes="Nightly build" 43 | - name: Clean up NuGet.org packages 44 | run: dotnet run --project Sources/Tools/NugetMaintainer/NugetMaintainer.csproj -- --local-root Sources --prefix Yoakke --owner LanguageDev --api-key ${{ secrets.NUGET_TOKEN }} --nightly-suffix nightly --timestamp ${{ steps.current-time.outputs.formattedTime }} --timestamp-format yyyy.M.d-H.m.s- --lookbehind-days 3 --delay-between-requests 15 45 | - name: Upload to NuGet.org 46 | run: dotnet nuget push Sources/**/*${{ steps.current-time.outputs.formattedTime }}-nightly.nupkg --api-key ${{ secrets.NUGET_TOKEN }} --source https://api.nuget.org/v3/index.json --no-symbols 47 | -------------------------------------------------------------------------------- /.github/workflows/PublishPackages.yml: -------------------------------------------------------------------------------- 1 | name: 'Publish packages' 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | deployment: 9 | runs-on: windows-latest 10 | steps: 11 | - name: Clone the repo 12 | uses: actions/checkout@v2 13 | - name: Setup .NET 14 | uses: actions/setup-dotnet@v1 15 | with: 16 | dotnet-version: '8.0.407' 17 | - name: Build and package 18 | run: dotnet build Sources/Yoakke.sln --configuration Release /p:Version=${{ github.event.release.tag_name }} /p:PackageReleaseNotes="See https://github.com/LanguageDev/Yoakke/releases/tag/${{ github.event.release.tag_name }}" 19 | - name: Upload to GitHub 20 | uses: actions/upload-artifact@v2 21 | with: 22 | name: Yoakke 23 | path: Sources/**/*${{ github.event.release.tag_name }}.nupkg 24 | - name: Upload to NuGet.org 25 | run: dotnet nuget push Sources/**/*${{ github.event.release.tag_name }}.nupkg --api-key ${{ secrets.NUGET_TOKEN }} --source https://api.nuget.org/v3/index.json --no-symbols true 26 | -------------------------------------------------------------------------------- /.github/workflows/RunTests.yml: -------------------------------------------------------------------------------- 1 | name: 'Run tests' 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - master 8 | paths: 9 | - 'Sources/**' 10 | pull_request: 11 | branches: 12 | - '*' 13 | paths: 14 | - 'Sources/**' 15 | 16 | jobs: 17 | Solution: 18 | runs-on: ${{ matrix.os }} 19 | strategy: 20 | matrix: 21 | os: [windows-latest, ubuntu-latest, macos-latest] 22 | steps: 23 | - name: Clone the repo 24 | uses: actions/checkout@v2 25 | - name: Setup .NET 26 | uses: actions/setup-dotnet@v1 27 | with: 28 | dotnet-version: '8.0.407' 29 | - name: Test 30 | run: | 31 | cd Sources 32 | dotnet test 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | obj 2 | bin 3 | doc 4 | .vs 5 | .vscode 6 | *.filters 7 | *.user 8 | TestResults 9 | CoverageResults 10 | node_modules 11 | *.binlog 12 | -------------------------------------------------------------------------------- /Documentation/README.md: -------------------------------------------------------------------------------- 1 | # Yoakke Documentation 2 | 3 | The documentation for Yoakke is inside a [DocFX](https://dotnet.github.io/docfx/) project. The API docs is automaticall generated from source code, while the articles are written in the project folder in the [Markdown](https://daringfireball.net/projects/markdown/) format. 4 | 5 | The documentation is published to this repositorys [GitHub Pages](https://languagedev.github.io/Yoakke/). 6 | -------------------------------------------------------------------------------- /Documentation/docfx_project/.gitignore: -------------------------------------------------------------------------------- 1 | ############### 2 | # folder # 3 | ############### 4 | /**/DROP/ 5 | /**/TEMP/ 6 | /**/packages/ 7 | /**/bin/ 8 | /**/obj/ 9 | _site 10 | -------------------------------------------------------------------------------- /Documentation/docfx_project/api/.gitignore: -------------------------------------------------------------------------------- 1 | ############### 2 | # temp file # 3 | ############### 4 | *.yml 5 | .manifest 6 | -------------------------------------------------------------------------------- /Documentation/docfx_project/api/index.md: -------------------------------------------------------------------------------- 1 | # Yoakke API docs 2 | This is the API documentation for Yoakke generated from source code. 3 | 4 | Ideally, if you want to improve this, please do so in the code doc comments as that will help during development too! 5 | -------------------------------------------------------------------------------- /Documentation/docfx_project/articles/fixing-vs-issues.md: -------------------------------------------------------------------------------- 1 | # Fixing Visual Studio issues 2 | 3 | When using Visual Studio either as an end-user of Yoakke, or as a library developer, you might encounter an odd issue related to Source Generators: 4 | 5 | There are errors appearing in the Error List but in the Output window the build succeeds, still, Visual Studio refuses to start any application in the project. To fix this, please try the steps below. 6 | 7 | ### 1) First, you should open the `Tools` in the menu bar: 8 | 9 | ![Tools menu](./../images/fixing-vs-issues/vs-tools.png) 10 | 11 | ### 2) Then, you go to `Options`: 12 | 13 | ![Options](./../images/fixing-vs-issues/vs-options.png) 14 | 15 | ### 3) You will find a menu called `Text editor`. You open it, then click on `C#` then `Advanced`: 16 | 17 | ![Text editor / C# / Advanced](./../images/fixing-vs-issues/vs-texteditor.png) 18 | 19 | ### 4) Make sure the tick box in `Editor Help` called `Enable all features in opened files from source generators` is **ENABLED**: 20 | 21 | ![Editor Help / Enable all features in opened files from source generators](./../images/fixing-vs-issues/vs-sourcegenerator.png) -------------------------------------------------------------------------------- /Documentation/docfx_project/articles/intro.md: -------------------------------------------------------------------------------- 1 | # Using the Yoakke libraries 2 | 3 | Here your can find small articles and tutorials about how to use different modules of Yoakke. 4 | -------------------------------------------------------------------------------- /Documentation/docfx_project/articles/toc.yml: -------------------------------------------------------------------------------- 1 | - name: Introduction 2 | href: intro.md 3 | - name: Fixing Visual Studio issues 4 | href: fixing-vs-issues.md 5 | - name: Lexing 6 | href: lexer.md 7 | - name: Parsing 8 | href: parser.md 9 | - name: Error reporting 10 | href: reporting.md 11 | -------------------------------------------------------------------------------- /Documentation/docfx_project/docfx.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": [ 3 | { 4 | "src": [ 5 | { 6 | "src": "../../", 7 | "files": [ 8 | "Sources/**.csproj" 9 | ], 10 | "exclude": [ 11 | "**/Examples/**", 12 | "**/Benchmarks/**", 13 | "**/Tests/**", 14 | "**/*.Tests/**", 15 | "**/*.Tests.*/**", 16 | "**/*.Example/**", 17 | "**/*.Sample/**", 18 | "**/*.Benchmarks/**" 19 | ] 20 | } 21 | ], 22 | "dest": "api", 23 | "disableGitFeatures": false, 24 | "disableDefaultFilter": false 25 | } 26 | ], 27 | "build": { 28 | "globalMetadata": { 29 | "_gitContribute": { 30 | "apiSpecFolder": "Documentation/docfx_project/apidoc" 31 | } 32 | }, 33 | "content": [ 34 | { 35 | "files": [ 36 | "api/**.yml", 37 | "api/index.md" 38 | ] 39 | }, 40 | { 41 | "files": [ 42 | "articles/**.md", 43 | "articles/**/toc.yml", 44 | "toc.yml", 45 | "*.md" 46 | ] 47 | } 48 | ], 49 | "resource": [ 50 | { 51 | "files": [ 52 | "images/**" 53 | ] 54 | } 55 | ], 56 | "overwrite": [ 57 | { 58 | "files": [ 59 | "apidoc/**.md" 60 | ], 61 | "exclude": [ 62 | "obj/**", 63 | "_site/**" 64 | ] 65 | } 66 | ], 67 | "dest": "_site", 68 | "globalMetadataFiles": [], 69 | "fileMetadataFiles": [], 70 | "template": [ 71 | "default" 72 | ], 73 | "postProcessors": [], 74 | "markdownEngineName": "markdig", 75 | "noLangKeyword": false, 76 | "keepFileLink": false, 77 | "cleanupCacheHistory": false, 78 | "disableGitFeatures": false 79 | } 80 | } -------------------------------------------------------------------------------- /Documentation/docfx_project/images/fixing-vs-issues/vs-options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Documentation/docfx_project/images/fixing-vs-issues/vs-options.png -------------------------------------------------------------------------------- /Documentation/docfx_project/images/fixing-vs-issues/vs-sourcegenerator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Documentation/docfx_project/images/fixing-vs-issues/vs-sourcegenerator.png -------------------------------------------------------------------------------- /Documentation/docfx_project/images/fixing-vs-issues/vs-texteditor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Documentation/docfx_project/images/fixing-vs-issues/vs-texteditor.png -------------------------------------------------------------------------------- /Documentation/docfx_project/images/fixing-vs-issues/vs-tools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Documentation/docfx_project/images/fixing-vs-issues/vs-tools.png -------------------------------------------------------------------------------- /Documentation/docfx_project/index.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | # The official Yoakke documentation 6 | 7 | This site contains API documentation as well as articles about how to use the different modules. 8 | 9 | Very much work in progress, contributions are welcome! 10 | -------------------------------------------------------------------------------- /Documentation/docfx_project/toc.yml: -------------------------------------------------------------------------------- 1 | - name: Articles 2 | href: articles/ 3 | homepage: articles/intro.md 4 | - name: Api Documentation 5 | href: api/ 6 | homepage: api/index.md 7 | -------------------------------------------------------------------------------- /Sources/.idea/.idea.Yoakke/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Rider ignored files 5 | /projectSettingsUpdater.xml 6 | /modules.xml 7 | /contentModel.xml 8 | /.idea.Yoakke.iml 9 | # Editor-based HTTP Client requests 10 | /httpRequests/ 11 | # Datasource local storage ignored files 12 | /dataSources/ 13 | /dataSources.local.xml 14 | -------------------------------------------------------------------------------- /Sources/.idea/.idea.Yoakke/.idea/.name: -------------------------------------------------------------------------------- 1 | Yoakke -------------------------------------------------------------------------------- /Sources/.idea/.idea.Yoakke/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Sources/.idea/.idea.Yoakke/.idea/indexLayout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Sources/.idea/.idea.Yoakke/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Sources/Benchmarks/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/Benchmarks/.gitignore -------------------------------------------------------------------------------- /Sources/Examples/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/Examples/.gitignore -------------------------------------------------------------------------------- /Sources/Props/Benchmark.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | 7 | 8 | 9 | net8.0 10 | enable 11 | enable 12 | Exe 13 | false 14 | false 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Sources/Props/Example.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | net8.0 7 | Exe 8 | false 9 | false 10 | 11 | 12 | -------------------------------------------------------------------------------- /Sources/Props/Package.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | netstandard2.0 7 | 8 | 9 | 10 | $(MSBuildProjectDirectory)/bin/doc/Yoakke.$(MSBuildProjectName).xml 11 | Yoakke.$(MSBuildProjectName) 12 | true 13 | Yoakke.$(MSBuildProjectName) 14 | YoakkeLogo.png 15 | LanguageDev team 16 | A collection of .NET libraries to help compiler development. 17 | Apache-2.0 18 | Yoakke, library, framework, infrastructure, lexer, parser, compiler, interpreter 19 | Copyright (c) 2021 LanguageDev team 20 | git 21 | https://github.com/LanguageDev/Yoakke 22 | 23 | 24 | 25 | 26 | True 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Sources/Props/Shared.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | latest 6 | enable 7 | 8 | 9 | latest 10 | 9999 11 | 12 | 13 | Yoakke.$(MSBuildProjectName) 14 | $(MSBuildThisFileDirectory)..\ 15 | $(SolutionDir) 16 | 17 | 18 | true 19 | key.snk 20 | 21 | 22 | -------------------------------------------------------------------------------- /Sources/Props/Test.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | net8.0 7 | false 8 | false 9 | 10 | 11 | 12 | 13 | 14 | 15 | runtime; build; native; contentfiles; analyzers; buildtransitive 16 | all 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Sources/Shared/Benchmarks/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/Shared/Benchmarks/.gitignore -------------------------------------------------------------------------------- /Sources/Shared/Libraries/Collections/Collections.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Sources/Shared/Libraries/Collections/Dense/Combiner.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Yoakke.Collections.Dense; 10 | 11 | /// 12 | /// Utilities for s. 13 | /// 14 | /// The type of values to combine. 15 | public static class Combiner 16 | { 17 | private class OverrideCombiner : ICombiner 18 | { 19 | public T Combine(T existing, T added) => added; 20 | } 21 | 22 | private class LambdaCombiner : ICombiner 23 | { 24 | private readonly Combine combine; 25 | 26 | public LambdaCombiner(Combine combine) 27 | { 28 | this.combine = combine; 29 | } 30 | 31 | public T Combine(T existing, T added) => this.combine(existing, added); 32 | } 33 | 34 | /// 35 | /// Combines an existing value with a new one. 36 | /// 37 | /// The existing value. 38 | /// The new value. 39 | /// The new, combined value of the existing and the new one. 40 | public delegate T Combine(T existing, T added); 41 | 42 | /// 43 | /// A default instance, that simply overrides the existing value with the new one. 44 | /// 45 | public static ICombiner Default { get; } = new OverrideCombiner(); 46 | 47 | /// 48 | /// Creates a combiner from the given delegate. 49 | /// 50 | /// The delegate to use for combination. 51 | /// The combiner created from . 52 | public static ICombiner Create(Combine combine) => new LambdaCombiner(combine); 53 | } 54 | -------------------------------------------------------------------------------- /Sources/Shared/Libraries/Collections/Dense/ICombiner.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Yoakke.Collections.Dense; 10 | 11 | /// 12 | /// An object that can combine multiple values into one. 13 | /// Can be used to combine overlapping values in a mapping for example. 14 | /// 15 | /// The type of values to combine. 16 | public interface ICombiner 17 | { 18 | /// 19 | /// Combines an existing value with a new one. 20 | /// 21 | /// The existing value. 22 | /// The new value. 23 | /// The new, combined value of and . 24 | public T Combine(T existing, T added); 25 | } 26 | -------------------------------------------------------------------------------- /Sources/Shared/Libraries/Collections/Dense/IDenseMap.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | using Yoakke.Collections.Intervals; 9 | 10 | namespace Yoakke.Collections.Dense; 11 | 12 | /// 13 | /// A mapping interface that stores the contained elements as intervals. 14 | /// 15 | /// The key type. 16 | /// The value type. 17 | public interface IDenseMap : IReadOnlyDenseMap, ICollection, TValue>> 18 | { 19 | /// 20 | /// Adds an element with the provided interval of keys and value to the mapping. 21 | /// 22 | /// The object to use as the keys of the element to add. 23 | /// The object to use as the value of the element to add. 24 | public void Add(Interval keys, TValue value); 25 | 26 | /// 27 | /// Removes the element with the specified interval of keys from the mapping. 28 | /// 29 | /// The keys of the element to remove. 30 | /// True if the element is successfully removed, otherwise false. 31 | /// This method also returns false if no keys were found in the mapping. 32 | public bool Remove(Interval keys); 33 | } 34 | -------------------------------------------------------------------------------- /Sources/Shared/Libraries/Collections/Graphs/BreadthFirst.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Collections.Generic.Polyfill; 8 | using System.Text; 9 | 10 | namespace Yoakke.Collections.Graphs; 11 | 12 | /// 13 | /// Generic BFS implementation. 14 | /// 15 | public static class BreadthFirst 16 | { 17 | /// 18 | /// Does a breadth-first search. 19 | /// 20 | /// The vertex type. 21 | /// The initial vertex. 22 | /// The function to retrieve the neighbors. 23 | /// The sequence of the visited vertices. 24 | public static IEnumerable Search(TVertex initial, Func> getNeighbors) => 25 | Search(initial, getNeighbors, EqualityComparer.Default); 26 | 27 | /// 28 | /// Does a breadth-first search. 29 | /// 30 | /// The vertex type. 31 | /// The initial vertex. 32 | /// The function to retrieve the neighbors. 33 | /// The vertex comparer to use. 34 | /// The sequence of the visited vertices. 35 | public static IEnumerable Search( 36 | TVertex initial, 37 | Func> getNeighbors, 38 | IEqualityComparer comparer) 39 | { 40 | var explored = new HashSet(comparer); 41 | var q = new Queue(); 42 | q.Enqueue(initial); 43 | while (q.TryDequeue(out var v)) 44 | { 45 | yield return v; 46 | foreach (var w in getNeighbors(v)) 47 | { 48 | if (explored.Add(w)) q.Enqueue(w); 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Sources/Shared/Libraries/Collections/IDeque.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Yoakke.Collections; 10 | 11 | /// 12 | /// A generic double-ended queue interface. 13 | /// 14 | /// The item type. 15 | public interface IDeque : IReadOnlyList, IList 16 | { 17 | /// 18 | /// Adds an item to the front of the queue. 19 | /// 20 | /// The item to add. 21 | public void AddFront(T item); 22 | 23 | /// 24 | /// Adds an item to the back of the queue. 25 | /// 26 | /// The item to add. 27 | public void AddBack(T item); 28 | 29 | /// 30 | /// Removes an item from the front of the queue. 31 | /// 32 | /// The removed item. 33 | public T RemoveFront(); 34 | 35 | /// 36 | /// Removes an item from the back of the queue. 37 | /// 38 | /// The removed item. 39 | public T RemoveBack(); 40 | } 41 | -------------------------------------------------------------------------------- /Sources/Shared/Libraries/Collections/Intervals/Bound.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Yoakke.Collections.Intervals; 10 | 11 | /// 12 | /// A common base for interval endpoints. 13 | /// 14 | /// The type of the endpoint value. 15 | public abstract record Bound : IComparable> 16 | { 17 | /// 18 | public int CompareTo(Bound other) => BoundComparer.Default.Compare(this, other); 19 | 20 | /// 21 | public override int GetHashCode() => BoundComparer.Default.GetHashCode(this); 22 | } 23 | -------------------------------------------------------------------------------- /Sources/Shared/Libraries/Collections/Intervals/Interval.Factory.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Yoakke.Collections.Intervals; 10 | 11 | /// 12 | /// Factory methods and constants for generic intervals. 13 | /// 14 | internal static class Interval 15 | { 16 | /// 17 | /// The valid infinity strings without sign. 18 | /// 19 | internal static readonly IReadOnlyList InfinityStrings = new[] 20 | { 21 | "∞", "oo", "infinity", "infty", string.Empty, 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /Sources/Shared/Libraries/Collections/TupleEqualityComparer.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Yoakke.Collections; 10 | 11 | /// 12 | /// A tuple equality comparer with custom element comparers. 13 | /// 14 | /// The first element type. 15 | /// The second element type. 16 | public class TupleEqualityComparer : IEqualityComparer<(T1, T2)> 17 | { 18 | /// 19 | /// The comparer of the first element. 20 | /// 21 | public IEqualityComparer FirstComparer { get; } 22 | 23 | /// 24 | /// The comparer of the second element. 25 | /// 26 | public IEqualityComparer SecondComparer { get; } 27 | 28 | /// 29 | /// Initializes a new instance of the class. 30 | /// 31 | /// The first comparer to use. 32 | /// The second comparer to use. 33 | public TupleEqualityComparer(IEqualityComparer firstComparer, IEqualityComparer secondComparer) 34 | { 35 | this.FirstComparer = firstComparer; 36 | this.SecondComparer = secondComparer; 37 | } 38 | 39 | /// 40 | public bool Equals((T1, T2) x, (T1, T2) y) => 41 | this.FirstComparer.Equals(x.Item1, y.Item1) 42 | && this.SecondComparer.Equals(x.Item2, y.Item2); 43 | 44 | /// 45 | public int GetHashCode((T1, T2) obj) 46 | { 47 | var h = default(HashCode); 48 | h.Add(obj.Item1, this.FirstComparer); 49 | h.Add(obj.Item2, this.SecondComparer); 50 | return h.ToHashCode(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Sources/Shared/Libraries/Collections/Values/IReadOnlyValueDictionary.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | 8 | namespace Yoakke.Collections.Values; 9 | 10 | /// 11 | /// Represents a generic associative container of keys and values that implements value-based equality. 12 | /// 13 | /// The key type. 14 | /// The value type. 15 | public interface IReadOnlyValueDictionary 16 | : IReadOnlyDictionary, 17 | IEquatable>, 18 | IEquatable> 19 | { 20 | } 21 | -------------------------------------------------------------------------------- /Sources/Shared/Libraries/Collections/Values/IReadOnlyValueList.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | 8 | namespace Yoakke.Collections.Values; 9 | 10 | /// 11 | /// Represents a generic read-only list of elements that implements value-based equality. 12 | /// 13 | /// The type of the elements. 14 | public interface IReadOnlyValueList 15 | : IReadOnlyList, 16 | IEquatable>, 17 | IEquatable> 18 | { 19 | } 20 | -------------------------------------------------------------------------------- /Sources/Shared/Libraries/Collections/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/Shared/Libraries/Collections/key.snk -------------------------------------------------------------------------------- /Sources/Shared/Libraries/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Sources/Shared/Libraries/Polyfill/DictionaryExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System.Diagnostics.CodeAnalysis; 6 | 7 | namespace System.Collections.Generic.Polyfill; 8 | 9 | /// 10 | /// Extensions for . 11 | /// 12 | public static class DictionaryExtensions 13 | { 14 | /// 15 | /// Removes the value with the specified key from the , and copies 16 | /// the element to the parameter. 17 | /// 18 | /// The type of the keys in the dictionary. 19 | /// The type of the values in the dictionary. 20 | /// The . 21 | /// The key of the element to remove. 22 | /// The removed element. 23 | /// True if the element is successfully found and removed; otherwise, false. 24 | public static bool Remove( 25 | this Dictionary dictionary, 26 | TKey key, 27 | [MaybeNullWhen(false)] out TValue value) 28 | { 29 | if (dictionary.TryGetValue(key, out value)) 30 | { 31 | dictionary.Remove(key); 32 | return true; 33 | } 34 | else 35 | { 36 | return false; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/Shared/Libraries/Polyfill/KeyValuePairExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | namespace System.Collections.Generic.Polyfill; 6 | 7 | /// 8 | /// Extensions for . 9 | /// 10 | public static class KeyValuePairExtensions 11 | { 12 | /// 13 | /// Deconstructs the current . 14 | /// 15 | /// The type of the key. 16 | /// The type of the value. 17 | /// The to deconstruct. 18 | /// The key of the current . 19 | /// The value of the current . 20 | public static void Deconstruct(this KeyValuePair keyValuePair, out TKey key, out TValue value) 21 | { 22 | key = keyValuePair.Key; 23 | value = keyValuePair.Value; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/Shared/Libraries/Polyfill/Polyfill.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Sources/Shared/Libraries/Polyfill/QueueExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Diagnostics.CodeAnalysis; 8 | using System.Text; 9 | 10 | namespace System.Collections.Generic.Polyfill; 11 | 12 | /// 13 | /// Extensions for . 14 | /// 15 | public static class QueueExtensions 16 | { 17 | /// 18 | /// Removes the object at the beginning of the , and copies it to the 19 | /// parameter. 20 | /// 21 | /// Specifies the type of elements in the queue. 22 | /// The queue to dequeue from. 23 | /// The removed object. 24 | /// True if the object is successfully removed, false if the is empty. 25 | public static bool TryDequeue(this Queue queue, [MaybeNullWhen(false)] out T result) 26 | { 27 | if (queue.Count > 0) 28 | { 29 | result = queue.Dequeue(); 30 | return true; 31 | } 32 | else 33 | { 34 | result = default; 35 | return false; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/Shared/Libraries/Polyfill/ReferenceEqualityComparer.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System.Runtime.CompilerServices; 6 | 7 | namespace System.Collections.Generic.Polyfill; 8 | 9 | /// 10 | /// An that uses reference equality () 11 | /// instead of value equality () when comparing two object instances. 12 | /// 13 | public sealed class ReferenceEqualityComparer : IEqualityComparer, IEqualityComparer 14 | { 15 | /// 16 | /// Gets the singleton instance. 17 | /// 18 | public static ReferenceEqualityComparer Instance { get; } = new(); 19 | 20 | /// 21 | /// Determines whether two object references refer to the same object instance. 22 | /// 23 | /// The first object to compare. 24 | /// The second object to compare. 25 | /// True if both and refer to the same object instance or 26 | /// if both are null; otherwise, false. 27 | public new bool Equals(object? x, object? y) => ReferenceEquals(x, y); 28 | 29 | /// 30 | /// Returns a hash code for the specified object. The returned hash code is based on the object identity, 31 | /// not on the contents of the object. 32 | /// 33 | /// The object for which to retrieve the hash code. 34 | /// A hash code for the identity of . 35 | public int GetHashCode(object? obj) => RuntimeHelpers.GetHashCode(obj); 36 | } 37 | -------------------------------------------------------------------------------- /Sources/Shared/Libraries/Polyfill/StringExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | namespace System.Polyfill; 6 | 7 | /// 8 | /// Extensions for . 9 | /// 10 | public static class StringExtensions 11 | { 12 | /// 13 | /// Returns a value indicating whether a specified character occurs within this string. 14 | /// 15 | /// The . 16 | /// The character to seek. 17 | /// True if the parameter occurs within this string; otherwise, false. 18 | public static bool Contains(this string str, char value) 19 | { 20 | for (var i = 0; i < str.Length; ++i) 21 | { 22 | if (str[i] == value) return true; 23 | } 24 | return false; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Shared/Libraries/Polyfill/TypeExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | namespace System.Polyfill; 6 | 7 | /// 8 | /// Extensions for . 9 | /// 10 | public static class TypeExtensions 11 | { 12 | /// 13 | /// Determines whether the current can be assigned to a variable of the 14 | /// specified . 15 | /// 16 | /// The current to check if it's assignable to . 17 | /// The type to compare with the current type. 18 | /// True, if a value of type is assignable to . 19 | public static bool IsAssignableTo(this Type type, Type? targetType) => 20 | targetType?.IsAssignableFrom(type) ?? false; 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Shared/Libraries/Polyfill/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/Shared/Libraries/Polyfill/key.snk -------------------------------------------------------------------------------- /Sources/Shared/Libraries/SourceGenerator.Common/AssemblyExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.IO; 8 | using System.Reflection; 9 | using System.Text; 10 | 11 | namespace Yoakke.SourceGenerator.Common; 12 | 13 | /// 14 | /// Extensions for .NET Assemblies. 15 | /// 16 | public static class AssemblyExtensions 17 | { 18 | /// 19 | /// Reads an embedded resource text from an assembly. 20 | /// 21 | /// The assembly to read from. 22 | /// The name of the embedded resource text. 23 | /// The resource text read from the assembly. 24 | public static string ReadManifestResourceText(this Assembly assembly, string name) 25 | { 26 | using var stream = assembly.GetManifestResourceStream(name); 27 | using var reader = new StreamReader(stream); 28 | return reader.ReadToEnd(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/Shared/Libraries/SourceGenerator.Common/RoslynExtensions/SyntaxExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System.Linq; 6 | using Microsoft.CodeAnalysis; 7 | using Microsoft.CodeAnalysis.CSharp; 8 | using Microsoft.CodeAnalysis.CSharp.Syntax; 9 | 10 | namespace Yoakke.SourceGenerator.Common.RoslynExtensions; 11 | 12 | /// 13 | /// Extension functionalify for syntax elements. 14 | /// 15 | public static class SyntaxExtensions 16 | { 17 | /// 18 | /// Checks, if a node is partial. 19 | /// 20 | /// The to check. 21 | /// True, if is declared partial. 22 | public static bool IsPartial(this TypeDeclarationSyntax syntax) => 23 | syntax.Modifiers.Any(SyntaxKind.PartialKeyword); 24 | } 25 | -------------------------------------------------------------------------------- /Sources/Shared/Libraries/SourceGenerator.Common/RoslynExtensions/TypeEnclosure.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Yoakke.SourceGenerator.Common.RoslynExtensions; 10 | 11 | /// 12 | /// Represents the complete enclosure of a type. 13 | /// 14 | /// The prefix part of the enclosing types. 15 | /// The suffix part of the enclosing types. 16 | public record class TypeEnclosure(string Prefix, string Suffix); 17 | -------------------------------------------------------------------------------- /Sources/Shared/Libraries/SourceGenerator.Common/SourceGenerator.Common.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /Sources/Shared/Libraries/SourceGenerator.Common/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/Shared/Libraries/SourceGenerator.Common/key.snk -------------------------------------------------------------------------------- /Sources/Shared/Libraries/Streams/EnumerableStream.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System.Collections.Generic; 6 | using System.Diagnostics.CodeAnalysis; 7 | 8 | namespace Yoakke.Streams; 9 | 10 | /// 11 | /// An wrapper for an . 12 | /// 13 | /// The item type. 14 | public class EnumerableStream : IStream 15 | { 16 | /// 17 | public bool IsEnd { get; private set; } 18 | 19 | private readonly IEnumerator enumerator; 20 | 21 | /// 22 | /// Initializes a new instance of the class. 23 | /// 24 | /// The enumerable to wrap. 25 | public EnumerableStream(IEnumerable items) 26 | { 27 | this.enumerator = items.GetEnumerator(); 28 | this.IsEnd = !this.enumerator.MoveNext(); 29 | } 30 | 31 | /// 32 | public bool TryConsume([MaybeNullWhen(false)] out T item) 33 | { 34 | if (this.IsEnd) 35 | { 36 | item = default; 37 | return false; 38 | } 39 | else 40 | { 41 | item = this.enumerator.Current; 42 | this.IsEnd = !this.enumerator.MoveNext(); 43 | return true; 44 | } 45 | } 46 | 47 | /// 48 | public int Consume(int amount) => StreamExtensions.Consume(this, amount); 49 | } 50 | -------------------------------------------------------------------------------- /Sources/Shared/Libraries/Streams/IPeekableStream.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System.Diagnostics.CodeAnalysis; 6 | 7 | namespace Yoakke.Streams; 8 | 9 | /// 10 | /// Represents some stream of items that can be peeked ahead and consumed sequentially. 11 | /// 12 | /// The stream element type. 13 | public interface IPeekableStream : IStream 14 | { 15 | /// 16 | /// Retrieves the upcoming item without consuming it. 17 | /// 18 | /// The peeked item gets written here, if there was any. 19 | /// True, if there was an item to peek. 20 | public bool TryPeek([MaybeNullWhen(false)] out T item); 21 | 22 | /// 23 | /// Peeks ahead a given amount of items without consuming them. With set to 0 24 | /// this is equivalent to . 25 | /// 26 | /// The offset to look ahead. 27 | /// The peeked item gets written here, if there was any. 28 | /// True, if there was an item to peek. 29 | public bool TryLookAhead(int offset, [MaybeNullWhen(false)] out T item); 30 | 31 | /// 32 | /// Pushes an item to the front of the stream. 33 | /// This operation might not be supported by all streams. 34 | /// 35 | /// The item to push into the front. 36 | public void Defer(T item); 37 | } 38 | -------------------------------------------------------------------------------- /Sources/Shared/Libraries/Streams/IStream.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System.Diagnostics.CodeAnalysis; 6 | 7 | namespace Yoakke.Streams; 8 | 9 | /// 10 | /// Represents some stream of items that can be consumed sequentially. 11 | /// 12 | /// The stream element type. 13 | public interface IStream 14 | { 15 | /// 16 | /// True, if the stream is out of items. 17 | /// 18 | public bool IsEnd { get; } 19 | 20 | /// 21 | /// Consumes the upcoming element in the stream. 22 | /// 23 | /// The consumed element gets written here, if there was any. 24 | /// True, if there was an item to advance. 25 | public bool TryConsume([MaybeNullWhen(false)] out T item); 26 | 27 | /// 28 | /// Consumes a given amount of items in the stream. 29 | /// 30 | /// The number of items to advance. 31 | /// The number of items actually consumed. 32 | public int Consume(int amount); 33 | } 34 | -------------------------------------------------------------------------------- /Sources/Shared/Libraries/Streams/Streams.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Sources/Shared/Libraries/Streams/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/Shared/Libraries/Streams/key.snk -------------------------------------------------------------------------------- /Sources/Shared/Tests/Collections.Tests/Collections.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Sources/Shared/Tests/Collections.Tests/ValueListTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System.Collections.Generic; 6 | using Xunit; 7 | using Yoakke.Collections.Values; 8 | 9 | namespace Yoakke.Collections.Tests; 10 | 11 | public class ValueListTests 12 | { 13 | [Fact] 14 | public void Equal() 15 | { 16 | var list1 = new List { 1, 2, 3 }.ToValue(); 17 | var list2 = new List { 1, 2, 3 }.ToValue(); 18 | 19 | Assert.Equal(list1, list2); 20 | Assert.False(ReferenceEquals(list1, list2)); 21 | Assert.Equal(list1.GetHashCode(), list2.GetHashCode()); 22 | } 23 | 24 | [Fact] 25 | public void DifferentCount() 26 | { 27 | var list1 = new List { 1, 2, 3 }.ToValue(); 28 | var list2 = new List { 1, 2, 3, 4 }.ToValue(); 29 | 30 | Assert.NotEqual(list1, list2); 31 | Assert.False(ReferenceEquals(list1, list2)); 32 | } 33 | 34 | [Fact] 35 | public void DifferentValue() 36 | { 37 | var list1 = new List { 1, 2, 3 }.ToValue(); 38 | var list2 = new List { 1, 2, 4 }.ToValue(); 39 | 40 | Assert.NotEqual(list1, list2); 41 | Assert.False(ReferenceEquals(list1, list2)); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/Shared/Tests/Collections.Tests/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/Shared/Tests/Collections.Tests/key.snk -------------------------------------------------------------------------------- /Sources/Shared/Tests/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Sources/Shared/Tests/Streams.Tests/Streams.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Sources/Shared/Tests/Streams.Tests/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/Shared/Tests/Streams.Tests/key.snk -------------------------------------------------------------------------------- /Sources/SynKit/Benchmarks/.gitignore: -------------------------------------------------------------------------------- 1 | BenchmarkDotNet.Artifacts/ 2 | -------------------------------------------------------------------------------- /Sources/SynKit/Benchmarks/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Yoakke.SynKit.$(MSBuildProjectName) 7 | 8 | 9 | -------------------------------------------------------------------------------- /Sources/SynKit/Benchmarks/Parser.Benchmarks/Parser.Benchmarks.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Sources/SynKit/Benchmarks/Parser.Benchmarks/Program.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using BenchmarkDotNet.Running; 6 | 7 | if (args.Length == 1 && args[0] == "parser") 8 | { 9 | new Yoakke.SynKit.Parser.Benchmarks.ExpressionBenchmarks().ExpressionParser(); 10 | } 11 | else if (args.Length == 1 && args[0] == "manual_parser") 12 | { 13 | new Yoakke.SynKit.Parser.Benchmarks.ExpressionBenchmarks().ManualExpressionParser(); 14 | } 15 | else if (args.Length == 1 && args[0] == "worst_parser") 16 | { 17 | new Yoakke.SynKit.Parser.Benchmarks.ExpressionBenchmarks().WorstManualExpressionParser(); 18 | } 19 | else if (args.Length == 1 && args[0] == "complex") 20 | { 21 | new Yoakke.SynKit.Parser.Benchmarks.ExpressionBenchmarks().ComplexExpressionParser(); 22 | } 23 | else if (args.Length == 1 && args[0] == "manual_complex") 24 | { 25 | new Yoakke.SynKit.Parser.Benchmarks.ExpressionBenchmarks().ManualComplexExpressionParser(); 26 | } 27 | else 28 | { 29 | BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); 30 | } 31 | -------------------------------------------------------------------------------- /Sources/SynKit/Benchmarks/Parser.Benchmarks/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Parser.Benchmarks": { 4 | "commandName": "Project" 5 | }, 6 | "parser": { 7 | "commandName": "Project", 8 | "commandLineArgs": "parser" 9 | }, 10 | "complex": { 11 | "commandName": "Project", 12 | "commandLineArgs": "complex" 13 | }, 14 | "manual_complex": { 15 | "commandName": "Project", 16 | "commandLineArgs": "manual_complex" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sources/SynKit/Examples/Automata.Sample/Automata.Sample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Sources/SynKit/Examples/Automata.Sample/Program.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using Yoakke.SynKit.Automata.Dense; 9 | using Yoakke.SynKit.Automata.RegExAst; 10 | using Yoakke.SynKit.Automata.Sparse; 11 | using Yoakke.Collections.Dense; 12 | using Yoakke.Collections.Intervals; 13 | 14 | namespace Yoakke.SynKit.Automata.Sample; 15 | 16 | internal class Program 17 | { 18 | internal static void Main(string[] args) 19 | { 20 | var dfa = new DenseDfa(); 21 | dfa.InitialState = 0; 22 | dfa.AcceptingStates.Add(3); 23 | dfa.AcceptingStates.Add(4); 24 | dfa.AddTransition(0, '0', 1); 25 | dfa.AddTransition(1, 'x', 2); 26 | dfa.AddTransition(2, '0', 3); 27 | dfa.AddTransition(3, '0', 4); 28 | dfa.AddTransition(4, '0', 4); 29 | 30 | var minDfa = dfa.Minimize(); 31 | 32 | Console.WriteLine(dfa.ToDot()); 33 | Console.WriteLine(minDfa.ToDot()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/SynKit/Examples/Automata.Sample/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/SynKit/Examples/Automata.Sample/key.snk -------------------------------------------------------------------------------- /Sources/SynKit/Examples/C.Syntax.Sample/C.Syntax.Sample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Sources/SynKit/Examples/C.Syntax.Sample/Program.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | 7 | namespace Yoakke.SynKit.C.Syntax.Sample; 8 | 9 | class Program 10 | { 11 | static void Main(string[] args) 12 | { 13 | var sourceCode = @" 14 | #define FOO(x, y) x ## y 15 | FOO(L, ""asd"") 16 | "; 17 | var lexer = new CLexer(sourceCode); 18 | var pp = new CPreProcessor(lexer); 19 | 20 | while (true) 21 | { 22 | var token = pp.Next(); 23 | if (token.Kind == CTokenType.End) break; 24 | Console.WriteLine(token.LogicalText); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/SynKit/Examples/C.Syntax.Sample/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/SynKit/Examples/C.Syntax.Sample/key.snk -------------------------------------------------------------------------------- /Sources/SynKit/Examples/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Yoakke.SynKit.$(MSBuildProjectName) 7 | 8 | 9 | -------------------------------------------------------------------------------- /Sources/SynKit/Examples/Lexer.Sample/Lexer.Sample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Sources/SynKit/Examples/Lexer.Sample/Program.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using Yoakke.SynKit.Lexer.Attributes; 7 | 8 | namespace Yoakke.SynKit.Lexer.Sample; 9 | 10 | public enum TokenType 11 | { 12 | [Error] Error, 13 | [End] End, 14 | [Ignore] [Regex(Regexes.Whitespace)] Whitespace, 15 | 16 | [Token("if")] KwIf, 17 | [Token("else")] KwElse, 18 | [Token("func")] KwFunc, 19 | [Regex(Regexes.Identifier)] Ident, 20 | 21 | [Token("{")] OpenBrace, 22 | [Token("}")] CloseBrace, 23 | [Token("(")] OpenParen, 24 | [Token(")")] CloseParen, 25 | 26 | [Token("+")] Plus, 27 | [Token("-")] Minus, 28 | 29 | [Regex(Regexes.IntLiteral)] IntLiteral, 30 | } 31 | 32 | [Lexer(typeof(TokenType))] 33 | internal partial class Lexer 34 | { 35 | } 36 | 37 | internal class Program 38 | { 39 | private static void Main(string[] args) 40 | { 41 | var lexer = new Lexer(Console.In); 42 | while (true) 43 | { 44 | var t = lexer.Next(); 45 | Console.WriteLine($"{t.Text} [{t.Kind}] ({t.Range.Start})"); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Sources/SynKit/Examples/Lexer.Sample/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/SynKit/Examples/Lexer.Sample/key.snk -------------------------------------------------------------------------------- /Sources/SynKit/Examples/Parser.Sample/Parser.Sample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Sources/SynKit/Examples/Parser.Sample/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/SynKit/Examples/Parser.Sample/key.snk -------------------------------------------------------------------------------- /Sources/SynKit/Examples/Reporting.Sample/Program.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using Yoakke.SynKit.Reporting.Present; 8 | using Yoakke.SynKit.Text; 9 | 10 | namespace Yoakke.SynKit.Reporting.Sample; 11 | 12 | internal class MyHighlighter : ISyntaxHighlighter 13 | { 14 | /// 15 | public SyntaxHighlightStyle Style { get; set; } = SyntaxHighlightStyle.Default; 16 | 17 | /// 18 | public IReadOnlyList GetHighlightingForLine(ISourceFile sourceFile, int line) 19 | { 20 | if (line == 1) 21 | { 22 | return new ColoredToken[] 23 | { 24 | new ColoredToken(0, 4, TokenKind.Keyword), 25 | new ColoredToken(5, 3, TokenKind.Name), 26 | }; 27 | } 28 | else if (line == 2) 29 | { 30 | return new ColoredToken[] 31 | { 32 | new ColoredToken(4, 6, TokenKind.Keyword), 33 | new ColoredToken(11, 1, TokenKind.Literal), 34 | new ColoredToken(12, 1, TokenKind.Punctuation), 35 | }; 36 | } 37 | return Array.Empty(); 38 | } 39 | } 40 | 41 | internal class Program 42 | { 43 | private static void Main(string[] args) 44 | { 45 | var src = new SourceFile("test.txt", @" 46 | func foo() { 47 | return 0; 48 | } 49 | "); 50 | 51 | var presenter = new TextDiagnosticsPresenter(Console.Error) 52 | { 53 | SyntaxHighlighter = new MyHighlighter(), 54 | }; 55 | 56 | var diag = new Diagnostics() 57 | .WithCode("E001") 58 | .WithSeverity(Severity.Error) 59 | .WithMessage("you made a mistake") 60 | .WithSourceInfo(new Location(src, new Text.Range(new Position(2, 4), 6)), Severity.Error, "mistake made here"); 61 | 62 | presenter.Present(diag); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Sources/SynKit/Examples/Reporting.Sample/Reporting.Sample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Sources/SynKit/Examples/Reporting.Sample/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/SynKit/Examples/Reporting.Sample/key.snk -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/Automata.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/Dense/IDenseDfa.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | using Yoakke.Collections.Intervals; 9 | 10 | namespace Yoakke.SynKit.Automata.Dense; 11 | 12 | /// 13 | /// Represents a dense DFA. 14 | /// 15 | /// The state type. 16 | /// The symbol type. 17 | public interface IDenseDfa 18 | : IDfa, 19 | IReadOnlyDenseDfa, 20 | IDenseFiniteAutomaton 21 | { 22 | /// 23 | /// Completes this DFA over the given alphabet. 24 | /// 25 | /// The alphabet to complete over. 26 | /// A default trap state to transition to. 27 | /// True, if this DFA was not completed and needed completion, false otherwise. 28 | public bool Complete(IEnumerable> alphabet, TState trap); 29 | } 30 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/Dense/IDenseFiniteAutomaton.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | using Yoakke.Collections.Intervals; 9 | 10 | namespace Yoakke.SynKit.Automata.Dense; 11 | 12 | /// 13 | /// Represents a dense finite automaton that stores all transitions as intervals. 14 | /// 15 | /// The state type. 16 | /// The symbol type. 17 | public interface IDenseFiniteAutomaton 18 | : IReadOnlyDenseFiniteAutomaton, 19 | IFiniteAutomaton 20 | { 21 | /// 22 | /// The alphabet of this automaton. 23 | /// 24 | public new ICollection> Alphabet { get; } 25 | 26 | /// 27 | /// The transitions of this automaton. 28 | /// 29 | public new ICollection>> Transitions { get; } 30 | 31 | /// 32 | /// Adds a transition to this automaton. 33 | /// 34 | /// The state to transition from. 35 | /// The interval of symbols that triggers this transition. 36 | /// The state to transition to. 37 | public void AddTransition(TState from, Interval on, TState to); 38 | 39 | /// 40 | /// Removes a transition from this automaton. 41 | /// 42 | /// The state to transition from. 43 | /// The interval of symbols that triggers this transition. 44 | /// The state to transition to. 45 | /// True, if the transition was found and removed, false otherwise. 46 | public bool RemoveTransition(TState from, Interval on, TState to); 47 | } 48 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/Dense/IDenseNfa.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Yoakke.SynKit.Automata.Dense; 10 | 11 | /// 12 | /// Represents a dense NFA. 13 | /// 14 | /// The state type. 15 | /// The symbol type. 16 | public interface IDenseNfa 17 | : INfa, 18 | IReadOnlyDenseNfa, 19 | IDenseFiniteAutomaton 20 | { 21 | } 22 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/Dense/IReadOnlyDenseDfa.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | using Yoakke.Collections.Intervals; 9 | 10 | namespace Yoakke.SynKit.Automata.Dense; 11 | 12 | /// 13 | /// Represents a read-only, dense DFA. 14 | /// 15 | /// The state type. 16 | /// The symbol type. 17 | public interface IReadOnlyDenseDfa 18 | : IReadOnlyDfa, 19 | IReadOnlyDenseFiniteAutomaton 20 | { 21 | /// 22 | /// Checks, if this DFA is complete over a given alphabet. 23 | /// 24 | /// The alphabet to check completeness over. 25 | /// True, if the DFA is complete over . 26 | public bool IsComplete(IEnumerable> alphabet); 27 | 28 | /// 29 | /// Minimizes this DFA into an equivalent one with the least amount of states possible. 30 | /// 31 | /// The state type of the resulting DFA. 32 | /// The state combiner to use. 33 | /// The pairs of states that must not be merged in the minimization process. 34 | /// This can be useful if some states have associated values to them that we want to keep. 35 | /// The minimized DFA. 36 | public new IDenseDfa Minimize( 37 | IStateCombiner combiner, 38 | IEnumerable<(TState, TState)> differentiatePairs); 39 | } 40 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/Dense/IReadOnlyDenseFiniteAutomaton.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | using Yoakke.Collections.Intervals; 9 | 10 | namespace Yoakke.SynKit.Automata.Dense; 11 | 12 | /// 13 | /// Represents a dense finite automaton that stores transitions as intervals. 14 | /// 15 | /// The state type. 16 | /// The symbol type. 17 | public interface IReadOnlyDenseFiniteAutomaton : IReadOnlyFiniteAutomaton 18 | { 19 | /// 20 | /// The alphabet of this automaton. 21 | /// 22 | public IReadOnlyCollection> Alphabet { get; } 23 | 24 | /// 25 | /// The transitions of this automaton. 26 | /// 27 | public IReadOnlyCollection>> Transitions { get; } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/Dense/IReadOnlyDenseNfa.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | using Yoakke.Collections.Intervals; 9 | 10 | namespace Yoakke.SynKit.Automata.Dense; 11 | 12 | /// 13 | /// Represents a read-only, dense NFA. 14 | /// 15 | /// The state type. 16 | /// The symbol type. 17 | public interface IReadOnlyDenseNfa 18 | : IReadOnlyNfa, 19 | IReadOnlyDenseFiniteAutomaton 20 | { 21 | /// 22 | /// The comparer for symbol intervals. 23 | /// 24 | public IntervalComparer SymbolIntervalComparer { get; } 25 | 26 | /// 27 | /// Constructs an equivalent DFA from this NFA. 28 | /// 29 | /// The result state type. 30 | /// The state combiner to use. 31 | /// The constructed DFA. 32 | public new IDenseDfa Determinize(IStateCombiner combiner); 33 | } 34 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/EpsilonTransition.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Yoakke.SynKit.Automata; 10 | 11 | /// 12 | /// Represents a single epsilon-transition. 13 | /// 14 | /// The state type. 15 | /// The source state. 16 | /// The destination state. 17 | public readonly record struct EpsilonTransition(TState Source, TState Destination); 18 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/IDfa.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Yoakke.SynKit.Automata; 10 | 11 | /// 12 | /// Represents a generic deterministic finite automaton. 13 | /// 14 | /// The state type. 15 | /// The symbol type. 16 | public interface IDfa : IReadOnlyDfa, IFiniteAutomaton 17 | { 18 | /// 19 | /// The initial state of the automaton. 20 | /// 21 | public new TState InitialState { get; set; } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/IFiniteAutomaton.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Yoakke.SynKit.Automata; 10 | 11 | /// 12 | /// Represents a generic finite automaton. 13 | /// 14 | /// The state type. 15 | /// The symbol type. 16 | public interface IFiniteAutomaton : IReadOnlyFiniteAutomaton 17 | { 18 | /// 19 | /// All states of the automaton. 20 | /// 21 | public new ICollection States { get; } 22 | 23 | /// 24 | /// The accepting states of the automaton. 25 | /// 26 | public new ICollection AcceptingStates { get; } 27 | 28 | /// 29 | /// Adds a transition to this automaton. 30 | /// 31 | /// The state to transition from. 32 | /// The symbol that triggers this transition. 33 | /// The state to transition to. 34 | public void AddTransition(TState from, TSymbol on, TState to); 35 | 36 | /// 37 | /// Removes a transition from this automaton. 38 | /// 39 | /// The state to transition from. 40 | /// The symbol that triggers this transition. 41 | /// The state to transition to. 42 | /// True, if the transition was found and removed, false otherwise. 43 | public bool RemoveTransition(TState from, TSymbol on, TState to); 44 | 45 | /// 46 | /// Removes states and transitions from the automaton that are not reachable from the initial state. 47 | /// 48 | /// True, if there were unreachable states, false otherwise. 49 | public bool RemoveUnreachable(); 50 | } 51 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/INfa.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | using Yoakke.SynKit.Automata.Sparse; 9 | 10 | namespace Yoakke.SynKit.Automata; 11 | 12 | /// 13 | /// Represents a generic nondeterministic finite automaton. 14 | /// 15 | /// The state type. 16 | /// The symbol type. 17 | public interface INfa : IReadOnlyNfa, IFiniteAutomaton 18 | { 19 | /// 20 | /// The initial states of the automaton. 21 | /// 22 | public new ICollection InitialStates { get; } 23 | 24 | /// 25 | /// The epsilon transitions of this automaton. 26 | /// 27 | public new ICollection> EpsilonTransitions { get; } 28 | 29 | /// 30 | /// Adds an epsilon transition to this automaton. 31 | /// 32 | /// The state to transition from. 33 | /// The state to transition to. 34 | public void AddEpsilonTransition(TState from, TState to); 35 | 36 | /// 37 | /// Removes an epsilon transition from this automaton. 38 | /// 39 | /// The state to transition from. 40 | /// The state to transition to. 41 | /// True, if the transition was found and successfully removed. 42 | public bool RemoveEpsilonTransition(TState from, TState to); 43 | 44 | /// 45 | /// Eliminates the epsilon-transitions from this NFA, keeping it equivalent. 46 | /// 47 | /// True, if there were epsilon transitions to eliminate. 48 | public bool EliminateEpsilonTransitions(); 49 | } 50 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/IReadOnlyFiniteAutomaton.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Yoakke.SynKit.Automata; 10 | 11 | /// 12 | /// Represents a generic, read-only finite automaton. 13 | /// 14 | /// The state type. 15 | /// The symbol type. 16 | public interface IReadOnlyFiniteAutomaton 17 | { 18 | /// 19 | /// All states of the automaton. 20 | /// 21 | public IReadOnlyCollection States { get; } 22 | 23 | /// 24 | /// The accepting states of the automaton. 25 | /// 26 | public IReadOnlyCollection AcceptingStates { get; } 27 | 28 | /// 29 | /// Finds all the reachable states from the initial state. 30 | /// 31 | public IEnumerable ReachableStates { get; } 32 | 33 | /// 34 | /// The state comparer used by the automaton. 35 | /// 36 | public IEqualityComparer StateComparer { get; } 37 | 38 | /// 39 | /// Checks if this automaton results in an accepting state for the given input. 40 | /// 41 | /// The sequence of input to feed in for the automaton. 42 | /// True, if the automaton accepts the input, false otherwise. 43 | public bool Accepts(IEnumerable input); 44 | 45 | /// 46 | /// Creates a Graphviz DOT code representation of this automaton for visualization. 47 | /// 48 | /// The full graphviz code. 49 | public string ToDot(); 50 | } 51 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/IStateCombiner.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Yoakke.SynKit.Automata; 10 | 11 | /// 12 | /// A combiner that can combine states and produce new ones for finite automata algorithms. 13 | /// 14 | /// The original state type to combine. 15 | /// The combined state type. 16 | public interface IStateCombiner 17 | { 18 | /// 19 | /// Retrieves the comparer to be used by the result type. 20 | /// 21 | public IEqualityComparer ResultComparer { get; } 22 | 23 | /// 24 | /// Combines the given into a . 25 | /// 26 | /// The sequence of states to combine. 27 | /// The combined states. 28 | public TResultState Combine(IEnumerable states); 29 | } 30 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/RegExAst/IRegExNode.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | using Yoakke.SynKit.Automata.Dense; 9 | 10 | namespace Yoakke.SynKit.Automata.RegExAst; 11 | 12 | /// 13 | /// Represents a regular expression AST node. 14 | /// 15 | /// The symbol type. 16 | public interface IRegExNode 17 | { 18 | /// 19 | /// Desugars this node into simpler constructs. 20 | /// 21 | /// The equivalent, possibly simpler regex node. 22 | public IRegExNode Desugar(); 23 | 24 | /// 25 | /// Constructs this node inside the given NFA. This can throw a , in case this 26 | /// is preferred to be desugared into simpler elements with . 27 | /// 28 | /// The state type. 29 | /// The NFA to construct into. 30 | /// A function to create a unique state. 31 | /// The starting and ending states of the built construct. 32 | public (TState Start, TState End) ThompsonsConstruct(INfa nfa, Func makeState); 33 | } 34 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/RegExAst/RegExAnyNode.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | using Yoakke.SynKit.Automata.Dense; 9 | using Yoakke.Collections.Intervals; 10 | 11 | namespace Yoakke.SynKit.Automata.RegExAst; 12 | 13 | /// 14 | /// A node matching any character. 15 | /// 16 | /// The symbol type. 17 | public record RegExAnyNode : IRegExNode 18 | { 19 | /// 20 | /// The instance to use. 21 | /// 22 | public static RegExAnyNode Instance { get; } = new(); 23 | 24 | private RegExAnyNode() 25 | { 26 | } 27 | 28 | /// 29 | public IRegExNode Desugar() => this; 30 | 31 | /// 32 | public (TState Start, TState End) ThompsonsConstruct(INfa nfa, Func makeState) 33 | { 34 | if (nfa is not IDenseNfa denseNfa) throw new NotSupportedException("Only dense NFAs support wildcards."); 35 | 36 | var start = makeState(); 37 | var end = makeState(); 38 | 39 | denseNfa.AddTransition(start, Interval.Full, end); 40 | 41 | return (start, end); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/RegExAst/RegExLitNode.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Yoakke.SynKit.Automata.RegExAst; 10 | 11 | /// 12 | /// A literal match regex node. 13 | /// 14 | /// The symbol type. 15 | public record RegExLitNode(TSymbol Symbol) : IRegExNode 16 | { 17 | /// 18 | public IRegExNode Desugar() => this; 19 | 20 | /// 21 | public (TState Start, TState End) ThompsonsConstruct(INfa nfa, Func makeState) 22 | { 23 | var start = makeState(); 24 | var end = makeState(); 25 | 26 | nfa.AddTransition(start, this.Symbol, end); 27 | 28 | return (start, end); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/RegExAst/RegExNopNode.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Yoakke.SynKit.Automata.RegExAst; 10 | 11 | /// 12 | /// A no-operation regex node. Useful for desugaring. 13 | /// 14 | /// The symbol type. 15 | public record RegExNopNode : IRegExNode 16 | { 17 | /// 18 | /// A default instance to use. 19 | /// 20 | public static RegExNopNode Instance { get; } = new(); 21 | 22 | private RegExNopNode() 23 | { 24 | } 25 | 26 | /// 27 | public IRegExNode Desugar() => this; 28 | 29 | /// 30 | public (TState Start, TState End) ThompsonsConstruct(INfa nfa, Func makeState) 31 | { 32 | var start = makeState(); 33 | var end = makeState(); 34 | 35 | nfa.AddEpsilonTransition(start, end); 36 | 37 | return (start, end); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/RegExAst/RegExOptNode.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Yoakke.SynKit.Automata.RegExAst; 10 | 11 | /// 12 | /// Makes a regex construct optional. 13 | /// 14 | /// The symbol type. 15 | public record RegExOptNode(IRegExNode Element) : IRegExNode 16 | { 17 | /// 18 | public IRegExNode Desugar() => new RegExOptNode(this.Element.Desugar()); 19 | 20 | /// 21 | public (TState Start, TState End) ThompsonsConstruct(INfa nfa, Func makeState) 22 | { 23 | var (start, end) = this.Element.ThompsonsConstruct(nfa, makeState); 24 | 25 | nfa.AddEpsilonTransition(start, end); 26 | 27 | return (start, end); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/RegExAst/RegExOrNode.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Yoakke.SynKit.Automata.RegExAst; 10 | 11 | /// 12 | /// Merges two alternative regex nodes so either are accepted. 13 | /// 14 | /// The symbol type. 15 | public record RegExOrNode(IRegExNode First, IRegExNode Second) : IRegExNode 16 | { 17 | /// 18 | public IRegExNode Desugar() => new RegExOrNode(this.First.Desugar(), this.Second.Desugar()); 19 | 20 | /// 21 | public (TState Start, TState End) ThompsonsConstruct(INfa nfa, Func makeState) 22 | { 23 | var start = makeState(); 24 | var end = makeState(); 25 | 26 | var (firstStart, firstEnd) = this.First.ThompsonsConstruct(nfa, makeState); 27 | var (secondStart, secondEnd) = this.Second.ThompsonsConstruct(nfa, makeState); 28 | 29 | nfa.AddEpsilonTransition(start, firstStart); 30 | nfa.AddEpsilonTransition(start, secondStart); 31 | 32 | nfa.AddEpsilonTransition(firstEnd, end); 33 | nfa.AddEpsilonTransition(secondEnd, end); 34 | 35 | return (start, end); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/RegExAst/RegExRangeNode.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | using Yoakke.SynKit.Automata.Dense; 9 | using Yoakke.Collections.Dense; 10 | using Yoakke.Collections.Intervals; 11 | 12 | namespace Yoakke.SynKit.Automata.RegExAst; 13 | 14 | /// 15 | /// A literal range match node. 16 | /// 17 | /// The symbol type. 18 | public record RegExRangeNode(bool Invert, IReadOnlyCollection> Ranges) : IRegExNode 19 | { 20 | /// 21 | public IRegExNode Desugar() => this; 22 | 23 | /// 24 | public (TState Start, TState End) ThompsonsConstruct(INfa nfa, Func makeState) 25 | { 26 | if (nfa is not IDenseNfa denseNfa) throw new NotSupportedException("Only dense NFAs support literal ranges."); 27 | 28 | // Construct the set 29 | var set = new DenseSet(denseNfa.SymbolIntervalComparer); 30 | foreach (var iv in this.Ranges) set.Add(iv); 31 | 32 | // Invert, if needed 33 | if (this.Invert) set.Complement(); 34 | 35 | // Add transitions 36 | var start = makeState(); 37 | var end = makeState(); 38 | 39 | foreach (var iv in set) denseNfa.AddTransition(start, iv, end); 40 | 41 | return (start, end); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/RegExAst/RegExRep0Node.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Yoakke.SynKit.Automata.RegExAst; 10 | 11 | /// 12 | /// Makes a regex construct repeated 0 or more times. 13 | /// 14 | /// The symbol type. 15 | public record RegExRep0Node(IRegExNode Element) : IRegExNode 16 | { 17 | /// 18 | public IRegExNode Desugar() => new RegExRep0Node(this.Element.Desugar()); 19 | 20 | /// 21 | public (TState Start, TState End) ThompsonsConstruct(INfa nfa, Func makeState) 22 | { 23 | var start = makeState(); 24 | var end = makeState(); 25 | 26 | var (elementStart, elementEnd) = this.Element.ThompsonsConstruct(nfa, makeState); 27 | 28 | nfa.AddEpsilonTransition(start, end); 29 | nfa.AddEpsilonTransition(start, elementStart); 30 | nfa.AddEpsilonTransition(elementEnd, end); 31 | nfa.AddEpsilonTransition(elementEnd, elementStart); 32 | 33 | return (start, end); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/RegExAst/RegExRep1Node.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Yoakke.SynKit.Automata.RegExAst; 10 | 11 | /// 12 | /// Makes a regex construct repeated 1 or more times. 13 | /// 14 | /// The symbol type. 15 | public record RegExRep1Node(IRegExNode Element) : IRegExNode 16 | { 17 | /// 18 | public IRegExNode Desugar() 19 | { 20 | var elementDesugared = this.Element.Desugar(); 21 | return new RegExSeqNode(elementDesugared, new RegExRep0Node(elementDesugared)); 22 | } 23 | 24 | /// 25 | public (TState Start, TState End) ThompsonsConstruct(INfa nfa, Func makeState) => 26 | throw new NotSupportedException("Element must be desugared."); 27 | } 28 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/RegExAst/RegExSeqNode.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Yoakke.SynKit.Automata.RegExAst; 10 | 11 | /// 12 | /// Merges two consecutive regex nodes so one is accepted after another. 13 | /// 14 | /// The symbol type. 15 | public record RegExSeqNode(IRegExNode First, IRegExNode Second) : IRegExNode 16 | { 17 | /// 18 | public IRegExNode Desugar() => new RegExSeqNode(this.First.Desugar(), this.Second.Desugar()); 19 | 20 | /// 21 | public (TState Start, TState End) ThompsonsConstruct(INfa nfa, Func makeState) 22 | { 23 | var (firstStart, firstEnd) = this.First.ThompsonsConstruct(nfa, makeState); 24 | var (secondStart, secondEnd) = this.Second.ThompsonsConstruct(nfa, makeState); 25 | 26 | nfa.AddEpsilonTransition(firstEnd, secondStart); 27 | 28 | return (firstStart, secondEnd); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/Sparse/IReadOnlySparseDfa.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Yoakke.SynKit.Automata.Sparse; 10 | 11 | /// 12 | /// Represents a read-only, sparse DFA. 13 | /// 14 | /// The state type. 15 | /// The symbol type. 16 | public interface IReadOnlySparseDfa 17 | : IReadOnlyDfa, 18 | IReadOnlySparseFiniteAutomaton 19 | { 20 | /// 21 | /// True, if the DFA is complete over its alphabet. 22 | /// 23 | public bool IsComplete { get; } 24 | 25 | /// 26 | /// Minimizes this DFA into an equivalent one with the least amount of states possible. 27 | /// 28 | /// The state type of the resulting DFA. 29 | /// The state combiner to use. 30 | /// The pairs of states that must not be merged in the minimization process. 31 | /// This can be useful if some states have associated values to them that we want to keep. 32 | /// The minimized DFA. 33 | public new ISparseDfa Minimize( 34 | IStateCombiner combiner, 35 | IEnumerable<(TState, TState)> differentiatePairs); 36 | } 37 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/Sparse/IReadOnlySparseFiniteAutomaton.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Yoakke.SynKit.Automata.Sparse; 10 | 11 | /// 12 | /// Represents a sparse finite automaton that stores all transitions separately. 13 | /// 14 | /// The state type. 15 | /// The symbol type. 16 | public interface IReadOnlySparseFiniteAutomaton : IReadOnlyFiniteAutomaton 17 | { 18 | /// 19 | /// The alphabet of this automaton. 20 | /// 21 | public IReadOnlyCollection Alphabet { get; } 22 | 23 | /// 24 | /// The transitions of this automaton. 25 | /// 26 | public IReadOnlyCollection> Transitions { get; } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/Sparse/IReadOnlySparseNfa.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Yoakke.SynKit.Automata.Sparse; 10 | 11 | /// 12 | /// Represents a read-only, sparse NFA. 13 | /// 14 | /// The state type. 15 | /// The symbol type. 16 | public interface IReadOnlySparseNfa 17 | : IReadOnlyNfa, 18 | IReadOnlySparseFiniteAutomaton 19 | { 20 | /// 21 | /// Constructs an equivalent DFA from this NFA. 22 | /// 23 | /// The result state type. 24 | /// The state combiner to use. 25 | /// The constructed DFA. 26 | public new ISparseDfa Determinize(IStateCombiner combiner); 27 | } 28 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/Sparse/ISparseDfa.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Yoakke.SynKit.Automata.Sparse; 10 | 11 | /// 12 | /// Represents a sparse DFA. 13 | /// 14 | /// The state type. 15 | /// The symbol type. 16 | public interface ISparseDfa 17 | : IDfa, 18 | IReadOnlySparseDfa, 19 | ISparseFiniteAutomaton 20 | { 21 | /// 22 | /// Completes this DFA over its alphabet. 23 | /// 24 | /// A default trap state to transition to. 25 | /// True, if this DFA was not completed and needed completion, false otherwise. 26 | public bool Complete(TState trap); 27 | } 28 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/Sparse/ISparseFiniteAutomaton.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Yoakke.SynKit.Automata.Sparse; 10 | 11 | /// 12 | /// Represents a sparse finite automaton that stores all transitions separately. 13 | /// 14 | /// The state type. 15 | /// The symbol type. 16 | public interface ISparseFiniteAutomaton 17 | : IReadOnlySparseFiniteAutomaton, 18 | IFiniteAutomaton 19 | { 20 | /// 21 | /// The alphabet of this automaton. 22 | /// 23 | public new ICollection Alphabet { get; } 24 | 25 | /// 26 | /// The transitions of this automaton. 27 | /// 28 | public new ICollection> Transitions { get; } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/Sparse/ISparseNfa.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Yoakke.SynKit.Automata.Sparse; 10 | 11 | /// 12 | /// Represents a sparse NFA. 13 | /// 14 | /// The state type. 15 | /// The symbol type. 16 | public interface ISparseNfa 17 | : INfa, 18 | IReadOnlySparseNfa, 19 | ISparseFiniteAutomaton 20 | { 21 | } 22 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/Transition.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Yoakke.SynKit.Automata; 10 | 11 | /// 12 | /// Represents a generic transition in a sparse state machine. 13 | /// 14 | /// The state type. 15 | /// The symbol type. 16 | /// The source state. 17 | /// The symbol the transition triggers on. 18 | /// The destination state. 19 | public readonly record struct Transition(TState Source, TSymbol Symbol, TState Destination); 20 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Automata/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/SynKit/Libraries/Automata/key.snk -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/C.Syntax/C.Syntax.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/C.Syntax/IMacro.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System.Collections.Generic; 6 | 7 | namespace Yoakke.SynKit.C.Syntax; 8 | 9 | /// 10 | /// A pre-processor macro. 11 | /// 12 | public interface IMacro 13 | { 14 | /// 15 | /// The name of this . 16 | /// 17 | public string Name { get; } 18 | 19 | /// 20 | /// Retrieves the list of parameter names for this . 21 | /// If null is returned, it means it's a parameterless macro that has to be invoked without parenthesis. 22 | /// A parameterless function-like macro invoked with parenthesis should return an empty array. 23 | /// A variadic macro should have "..." as it's last parameter. 24 | /// 25 | public IReadOnlyList? Parameters { get; } 26 | 27 | /// 28 | /// Calls the with the given arguments. 29 | /// 30 | /// The that called the expansion. 31 | /// The list of token sequences that are considered arguments for this . 32 | /// We need a list of lists because an argument can consist of multiple tokens - or even 0. 33 | /// The s that result from this macro expansion. 34 | public IEnumerable Expand(IPreProcessor preProcessor, IReadOnlyList> arguments); 35 | } 36 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/C.Syntax/Macros/CounterMacro.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System.Collections.Generic; 6 | 7 | namespace Yoakke.SynKit.C.Syntax.Macros; 8 | 9 | /// 10 | /// Implementation of __COUNTER__. 11 | /// 12 | public class CounterMacro : IMacro 13 | { 14 | private int count = 0; 15 | 16 | /// 17 | public string Name => "__COUNTER__"; 18 | 19 | /// 20 | public IReadOnlyList? Parameters => null; 21 | 22 | /// 23 | public IEnumerable Expand(IPreProcessor preProcessor, IReadOnlyList> arguments) 24 | { 25 | var str = (this.count++).ToString(); 26 | // TODO: Proper range? 27 | var token = new CToken(default, str, default, str, CTokenType.IntLiteral); 28 | return new[] { token }; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/C.Syntax/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/SynKit/Libraries/C.Syntax/key.snk -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $(MSBuildProjectDirectory)/bin/doc/Yoakke.SynKit.$(MSBuildProjectName).xml 6 | Yoakke.SynKit.$(MSBuildProjectName) 7 | Yoakke.SynKit.$(MSBuildProjectName) 8 | 9 | 10 | Yoakke.SynKit.$(MSBuildProjectName) 11 | 12 | 13 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Lexer.Generator/InjectedSources/CharSourceAttribute.cs: -------------------------------------------------------------------------------- 1 | // 2 | 3 | // Copyright (c) 2021-2022 Yoakke. 4 | // Licensed under the Apache License, Version 2.0. 5 | // Source repository: https://github.com/LanguageDev/Yoakke 6 | 7 | using System; 8 | 9 | namespace Yoakke.SynKit.Lexer.Attributes; 10 | 11 | /// 12 | /// An attribute to annotate the source character stream for the generated lexer. 13 | /// 14 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] 15 | internal class CharSourceAttribute : Attribute 16 | { 17 | } 18 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Lexer.Generator/InjectedSources/EndAttribute.cs: -------------------------------------------------------------------------------- 1 | // 2 | 3 | // Copyright (c) 2021-2022 Yoakke. 4 | // Licensed under the Apache License, Version 2.0. 5 | // Source repository: https://github.com/LanguageDev/Yoakke 6 | 7 | using System; 8 | 9 | namespace Yoakke.SynKit.Lexer.Attributes; 10 | 11 | /// 12 | /// An attribute to mark an enum value as the end of source token type. 13 | /// 14 | [AttributeUsage(AttributeTargets.Field)] 15 | internal class EndAttribute : Attribute 16 | { 17 | } 18 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Lexer.Generator/InjectedSources/ErrorAttribute.cs: -------------------------------------------------------------------------------- 1 | // 2 | 3 | // Copyright (c) 2021-2022 Yoakke. 4 | // Licensed under the Apache License, Version 2.0. 5 | // Source repository: https://github.com/LanguageDev/Yoakke 6 | 7 | using System; 8 | 9 | namespace Yoakke.SynKit.Lexer.Attributes; 10 | 11 | /// 12 | /// An attribute to mark an enum value as an error token type. 13 | /// 14 | [AttributeUsage(AttributeTargets.Field)] 15 | internal class ErrorAttribute : Attribute 16 | { 17 | } 18 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Lexer.Generator/InjectedSources/IgnoreAttribute.cs: -------------------------------------------------------------------------------- 1 | // 2 | 3 | // Copyright (c) 2021-2022 Yoakke. 4 | // Licensed under the Apache License, Version 2.0. 5 | // Source repository: https://github.com/LanguageDev/Yoakke 6 | 7 | using System; 8 | 9 | namespace Yoakke.SynKit.Lexer.Attributes; 10 | 11 | /// 12 | /// An attribute to mark an enum value to be an ignored token type. 13 | /// 14 | [AttributeUsage(AttributeTargets.Field)] 15 | internal class IgnoreAttribute : Attribute 16 | { 17 | } 18 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Lexer.Generator/InjectedSources/LexerAttribute.cs: -------------------------------------------------------------------------------- 1 | // 2 | 3 | // Copyright (c) 2021-2022 Yoakke. 4 | // Licensed under the Apache License, Version 2.0. 5 | // Source repository: https://github.com/LanguageDev/Yoakke 6 | 7 | using System; 8 | 9 | namespace Yoakke.SynKit.Lexer.Attributes; 10 | 11 | /// 12 | /// An attribute to mark a class to generate a lexer for token types. 13 | /// 14 | [AttributeUsage(AttributeTargets.Class)] 15 | internal class LexerAttribute : Attribute 16 | { 17 | /// 18 | /// The enumeration type that is annotated with token attributes. 19 | /// The lexer will be generated based on the annotations on the enum fields. 20 | /// 21 | public Type TokenType { get; set; } 22 | 23 | /// 24 | /// Initializes a new instance of the class. 25 | /// 26 | /// The token type to generate the lexer for. 27 | public LexerAttribute(Type tokenType) 28 | { 29 | this.TokenType = tokenType; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Lexer.Generator/InjectedSources/RegexAttribute.cs: -------------------------------------------------------------------------------- 1 | // 2 | 3 | // Copyright (c) 2021-2022 Yoakke. 4 | // Licensed under the Apache License, Version 2.0. 5 | // Source repository: https://github.com/LanguageDev/Yoakke 6 | 7 | using System; 8 | 9 | namespace Yoakke.SynKit.Lexer.Attributes; 10 | 11 | /// 12 | /// An attribute to define a token type in terms of a regular expression. 13 | /// 14 | [AttributeUsage(AttributeTargets.Field, AllowMultiple = true)] 15 | internal class RegexAttribute : Attribute 16 | { 17 | /// 18 | /// The regex to match the token. 19 | /// 20 | public string Regex { get; set; } 21 | 22 | /// 23 | /// Initializes a new instance of the class. 24 | /// 25 | /// The regular expression. 26 | public RegexAttribute(string regex) 27 | { 28 | this.Regex = regex; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Lexer.Generator/InjectedSources/TokenAttribute.cs: -------------------------------------------------------------------------------- 1 | // 2 | 3 | // Copyright (c) 2021-2022 Yoakke. 4 | // Licensed under the Apache License, Version 2.0. 5 | // Source repository: https://github.com/LanguageDev/Yoakke 6 | 7 | using System; 8 | 9 | namespace Yoakke.SynKit.Lexer.Attributes; 10 | 11 | /// 12 | /// An attribute to define a token type in terms of a literal string to match. 13 | /// 14 | [AttributeUsage(AttributeTargets.Field, AllowMultiple = true)] 15 | internal class TokenAttribute : Attribute 16 | { 17 | /// 18 | /// The text to match the token. 19 | /// 20 | public string Text { get; set; } 21 | 22 | /// 23 | /// Initializes a new instance of the class. 24 | /// 25 | /// The text to match. 26 | public TokenAttribute(string text) 27 | { 28 | this.Text = text; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Lexer.Generator/Lexer.Generator.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Lexer.Generator/Model/LexerModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System.Collections.Generic; 6 | using Microsoft.CodeAnalysis; 7 | 8 | namespace Yoakke.SynKit.Lexer.Generator.Model; 9 | 10 | /// 11 | /// Describes a declared lexer. 12 | /// 13 | /// The symbol containing the source character stream. 14 | /// The symbol used to define an error/unknown token type. 15 | /// The symbol used to define an end token type. 16 | /// The list of s. 17 | internal record class LexerModel( 18 | INamedTypeSymbol LexerType, 19 | INamedTypeSymbol TokenType, 20 | ISymbol? SourceField, 21 | IFieldSymbol ErrorVariant, 22 | IFieldSymbol EndVariant, 23 | IReadOnlyList Tokens); 24 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Lexer.Generator/Model/TokenModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using Microsoft.CodeAnalysis; 6 | using Yoakke.SynKit.Automata.RegExAst; 7 | 8 | namespace Yoakke.SynKit.Lexer.Generator.Model; 9 | 10 | /// 11 | /// A single description of what a token is. 12 | /// 13 | /// The symbol that defines the token type. 14 | /// The regex that matches the token. 15 | /// True, if the token-type should be ignored while lexing. 16 | internal record class TokenModel( 17 | IFieldSymbol Symbol, 18 | IRegExNode Regex, 19 | bool Ignore); 20 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Lexer.Generator/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/SynKit/Libraries/Lexer.Generator/key.snk -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Lexer/ICharStream.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using Yoakke.Streams; 6 | using Yoakke.SynKit.Text; 7 | 8 | namespace Yoakke.SynKit.Lexer; 9 | 10 | /// 11 | /// A general character stream to read from for lexers. 12 | /// 13 | public interface ICharStream : IPeekableStream 14 | { 15 | public ISourceFile SourceFile { get; } 16 | 17 | /// 18 | /// The current the stream is at. 19 | /// 20 | public Position Position { get; } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Lexer/ILexer.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using Yoakke.SynKit.Text; 6 | 7 | namespace Yoakke.SynKit.Lexer; 8 | 9 | /// 10 | /// Represents a general lexer. 11 | /// It's a stateful iterator-like object that reads in s from a text source. 12 | /// 13 | /// The exact type of token the produces. 14 | public interface ILexer 15 | where TToken : IToken 16 | { 17 | /// 18 | /// The current the is at in the source. 19 | /// 20 | public Position Position { get; } 21 | 22 | /// 23 | /// True, if all of the input has been consumed. 24 | /// 25 | public bool IsEnd { get; } 26 | 27 | /// 28 | /// Lexes the next . If the source text has been depleted, it should produce some default 29 | /// end-signaling . 30 | /// 31 | /// The lexed . 32 | public TToken Next(); 33 | } 34 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Lexer/IToken.Generic.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | 7 | namespace Yoakke.SynKit.Lexer; 8 | 9 | /// 10 | /// Represents an atom in a language grammar as the lowest level element (atom/terminal) of parsing. 11 | /// 12 | /// The kind type this uses. Usually an enumeration type. 13 | public interface IToken : IToken, IEquatable> 14 | { 15 | /// 16 | /// The kind tag of this . 17 | /// 18 | public TKind Kind { get; } 19 | } 20 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Lexer/IToken.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using Range = Yoakke.SynKit.Text.Range; 7 | using Location = Yoakke.SynKit.Text.Location; 8 | 9 | namespace Yoakke.SynKit.Lexer; 10 | 11 | /// 12 | /// Represents an atom in a language grammar as the lowest level element (atom/terminal) of parsing. 13 | /// Usually tokens have a kind/category tag attached to them, for that . 14 | /// 15 | public interface IToken : IEquatable 16 | { 17 | /// 18 | /// The that the token can be found at in the source. 19 | /// 20 | public Range Range { get; } 21 | 22 | /// 23 | /// The that the token can be found at in the source. 24 | /// 25 | public Location Location { get; } 26 | 27 | /// 28 | /// The text this token was parsed from. 29 | /// 30 | public string Text { get; } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Lexer/Lexer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Lexer/LexerExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using Yoakke.Streams; 6 | 7 | namespace Yoakke.SynKit.Lexer; 8 | 9 | /// 10 | /// Extensions for an . 11 | /// 12 | public static class LexerExtensions 13 | { 14 | private class LexerStreamAdapter : IStream 15 | where TToken : IToken 16 | { 17 | public bool IsEnd => this.lexer.IsEnd; 18 | 19 | private readonly ILexer lexer; 20 | 21 | public LexerStreamAdapter(ILexer lexer) 22 | { 23 | this.lexer = lexer; 24 | } 25 | 26 | public bool TryConsume(out TToken item) 27 | { 28 | item = this.lexer.Next(); 29 | return true; 30 | } 31 | 32 | public int Consume(int amount) => StreamExtensions.Consume(this, amount); 33 | } 34 | 35 | /// 36 | /// Adapts an to be a . 37 | /// 38 | /// The token type produced by the lexer. 39 | /// The lexer to adapt. 40 | /// An that reads from . 41 | public static IStream ToStream(this ILexer lexer) 42 | where TToken : IToken => new LexerStreamAdapter(lexer); 43 | } 44 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Lexer/Token.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using Range = Yoakke.SynKit.Text.Range; 7 | using Location = Yoakke.SynKit.Text.Location; 8 | 9 | namespace Yoakke.SynKit.Lexer; 10 | 11 | /// 12 | /// A default implementation for . 13 | /// 14 | /// The kind type this uses. Usually an enumeration type. 15 | public sealed record Token(Range Range, Location Location, string Text, TKind Kind) : IToken, IEquatable> 16 | where TKind : notnull 17 | { 18 | /// 19 | public bool Equals(IToken? other) => this.Equals(other as Token); 20 | 21 | /// 22 | public bool Equals(IToken? other) => this.Equals(other as Token); 23 | public bool Equals(Token? other) => 24 | other is not null 25 | && this.Range == other.Range 26 | && this.Location.File?.Path == other.Location.File?.Path 27 | && this.Text == other.Text 28 | && this.Kind.Equals(other.Kind); 29 | 30 | /// 31 | public override int GetHashCode() => 32 | HashCode.Combine(this.Range, this.Text, this.Kind, this.Location.File?.Path); 33 | } 34 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Lexer/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/SynKit/Libraries/Lexer/key.snk -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Parser.Generator/Ast/BnfAst.Call.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System.Collections.Generic; 6 | using Yoakke.SynKit.Parser.Generator.Model; 7 | 8 | namespace Yoakke.SynKit.Parser.Generator.Ast; 9 | 10 | internal partial class BnfAst 11 | { 12 | /// 13 | /// Represents parsing a sub-rule that is referenced by name. 14 | /// 15 | public class Call : BnfAst 16 | { 17 | /// 18 | /// The name of the sub-rule. 19 | /// 20 | public string Name { get; } 21 | 22 | /// 23 | /// Initializes a new instance of the class. 24 | /// 25 | /// The name of the sub-rule to call. 26 | public Call(string name) 27 | { 28 | this.Name = name; 29 | } 30 | 31 | /// 32 | protected override BnfAst SubstituteByReferenceImpl(BnfAst find, BnfAst replaceWith) => this; 33 | 34 | /// 35 | public override IEnumerable GetFirstCalls() => new[] { this }; 36 | 37 | /// 38 | public override BnfAst Desugar() => this; 39 | 40 | /// 41 | public override string GetParsedType(RuleSet ruleSet, TokenKindSet tokens) 42 | { 43 | var called = ruleSet.GetRule(this.Name); 44 | return called.Ast.GetParsedType(ruleSet, tokens); 45 | } 46 | 47 | /// 48 | public override string ToString() => this.Name; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Parser.Generator/Ast/BnfAst.Group.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System.Collections.Generic; 6 | using Yoakke.SynKit.Parser.Generator.Model; 7 | 8 | namespace Yoakke.SynKit.Parser.Generator.Ast; 9 | 10 | internal partial class BnfAst 11 | { 12 | /// 13 | /// Represents a grouped sub-rule application that won't be unwrapped when transformed. 14 | /// 15 | public class Group : BnfAst 16 | { 17 | /// 18 | /// The sub-rule that won't be unwrapped when transformed. 19 | /// 20 | public BnfAst Subexpr { get; } 21 | 22 | /// 23 | /// Initializes a new instance of the class. 24 | /// 25 | /// The grouped subexpression. 26 | public Group(BnfAst subexpr) 27 | { 28 | this.Subexpr = subexpr; 29 | } 30 | 31 | /// 32 | protected override BnfAst SubstituteByReferenceImpl(BnfAst find, BnfAst replaceWith) => 33 | new Group(this.Subexpr.SubstituteByReference(find, replaceWith)); 34 | 35 | /// 36 | public override IEnumerable GetFirstCalls() => this.Subexpr.GetFirstCalls(); 37 | 38 | /// 39 | public override BnfAst Desugar() => this.Subexpr is Seq 40 | ? new Group(this.Subexpr.Desugar()) 41 | : this.Subexpr.Desugar(); 42 | 43 | /// 44 | public override string GetParsedType(RuleSet ruleSet, TokenKindSet tokens) => 45 | this.Subexpr.GetParsedType(ruleSet, tokens); 46 | 47 | /// 48 | public override string ToString() => $"[{this.Subexpr}]"; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Parser.Generator/Ast/BnfAst.Literal.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using Microsoft.CodeAnalysis; 8 | using Yoakke.SynKit.Parser.Generator.Model; 9 | using RuleSet = Yoakke.SynKit.Parser.Generator.Model.RuleSet; 10 | 11 | namespace Yoakke.SynKit.Parser.Generator.Ast; 12 | 13 | internal partial class BnfAst 14 | { 15 | /// 16 | /// A literal token match, either by text or by token kind. 17 | /// 18 | public class Literal : BnfAst 19 | { 20 | /// 21 | /// The value to match. 22 | /// 23 | public object Value { get; } 24 | 25 | /// 26 | /// Initializes a new instance of the class. 27 | /// 28 | /// The literal value to match. 29 | public Literal(object value) 30 | { 31 | this.Value = value; 32 | } 33 | 34 | /// 35 | protected override BnfAst SubstituteByReferenceImpl(BnfAst find, BnfAst replaceWith) => this; 36 | 37 | /// 38 | public override IEnumerable GetFirstCalls() => Enumerable.Empty(); 39 | 40 | /// 41 | public override BnfAst Desugar() => this; 42 | 43 | /// 44 | public override string GetParsedType(RuleSet ruleSet, TokenKindSet tokens) 45 | { 46 | if (tokens.EnumType == null) return TypeNames.IToken; 47 | else return $"{TypeNames.IToken}<{tokens.EnumType.ToDisplayString()}>"; 48 | } 49 | 50 | /// 51 | public override string ToString() => this.Value is IFieldSymbol field 52 | ? field.Name 53 | : $"\"{this.Value}\""; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Parser.Generator/Ast/BnfAst.MethodCall.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using Microsoft.CodeAnalysis; 8 | using Yoakke.SynKit.Parser.Generator.Model; 9 | using RuleSet = Yoakke.SynKit.Parser.Generator.Model.RuleSet; 10 | 11 | namespace Yoakke.SynKit.Parser.Generator.Ast; 12 | 13 | internal partial class BnfAst 14 | { 15 | /// 16 | /// Represents a method call. 17 | /// 18 | public class MethodCall : BnfAst 19 | { 20 | /// 21 | /// The called method. 22 | /// 23 | public IMethodSymbol Method { get; } 24 | 25 | /// 26 | /// Initializes a new instance of the class. 27 | /// 28 | /// The called method. 29 | public MethodCall(IMethodSymbol method) 30 | { 31 | this.Method = method; 32 | } 33 | 34 | /// 35 | protected override BnfAst SubstituteByReferenceImpl(BnfAst find, BnfAst replaceWith) => this; 36 | 37 | /// 38 | public override IEnumerable GetFirstCalls() => Enumerable.Empty(); 39 | 40 | /// 41 | public override BnfAst Desugar() => this; 42 | 43 | /// 44 | public override string GetParsedType(RuleSet ruleSet, TokenKindSet tokens) => 45 | // NOTE: We assume ParseResult 46 | ((INamedTypeSymbol)this.Method.ReturnType).TypeArguments[0].ToDisplayString(); 47 | 48 | /// 49 | public override string ToString() => $"MethodCall({this.Method.Name})"; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Parser.Generator/Ast/BnfAst.Opt.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System.Collections.Generic; 6 | using Yoakke.SynKit.Parser.Generator.Model; 7 | 8 | namespace Yoakke.SynKit.Parser.Generator.Ast; 9 | 10 | internal partial class BnfAst 11 | { 12 | /// 13 | /// Represents an optional sub-rule application. 14 | /// 15 | public class Opt : BnfAst 16 | { 17 | /// 18 | /// The optional sub-rule. 19 | /// 20 | public BnfAst Subexpr { get; } 21 | 22 | /// 23 | /// Initializes a new instance of the class. 24 | /// 25 | /// The optional subexpression. 26 | public Opt(BnfAst subexpr) 27 | { 28 | this.Subexpr = subexpr; 29 | } 30 | 31 | /// 32 | protected override BnfAst SubstituteByReferenceImpl(BnfAst find, BnfAst replaceWith) => 33 | new Opt(this.Subexpr.SubstituteByReference(find, replaceWith)); 34 | 35 | /// 36 | public override IEnumerable GetFirstCalls() => this.Subexpr.GetFirstCalls(); 37 | 38 | /// 39 | public override BnfAst Desugar() => new Opt(this.Subexpr.Desugar()); 40 | 41 | /// 42 | public override string GetParsedType(RuleSet ruleSet, TokenKindSet tokens) => 43 | $"{this.Subexpr.GetParsedType(ruleSet, tokens)}?"; 44 | 45 | /// 46 | public override string ToString() => $"Opt({this.Subexpr})"; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Parser.Generator/Ast/BnfAst.Placeholder.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using Yoakke.SynKit.Parser.Generator.Model; 8 | 9 | namespace Yoakke.SynKit.Parser.Generator.Ast; 10 | 11 | internal partial class BnfAst 12 | { 13 | /// 14 | /// Represents the placeholder where the fold has to be fed back to. 15 | /// 16 | public class Placeholder : BnfAst 17 | { 18 | /// 19 | /// The referenced AST. Mainly to be able to deduce type. 20 | /// 21 | public BnfAst Reference { get; set; } 22 | 23 | /// 24 | /// Initializes a new instance of the class. 25 | /// 26 | /// The referenced AST. 27 | public Placeholder(BnfAst reference) 28 | { 29 | this.Reference = reference; 30 | } 31 | 32 | /// 33 | public override BnfAst Desugar() => this; 34 | 35 | /// 36 | public override IEnumerable GetFirstCalls() => Enumerable.Empty(); 37 | 38 | /// 39 | public override string GetParsedType(RuleSet ruleSet, TokenKindSet tokens) => 40 | this.Reference.GetParsedType(ruleSet, tokens); 41 | 42 | /// 43 | public override string ToString() => ""; 44 | 45 | /// 46 | protected override BnfAst SubstituteByReferenceImpl(BnfAst find, BnfAst replaceWith) => this; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Parser.Generator/Ast/BnfAst.Rep0.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System.Collections.Generic; 6 | using Yoakke.SynKit.Parser.Generator.Model; 7 | 8 | namespace Yoakke.SynKit.Parser.Generator.Ast; 9 | 10 | internal partial class BnfAst 11 | { 12 | /// 13 | /// Represents a sub-rule that can be repeated 0 or more times. 14 | /// 15 | public class Rep0 : BnfAst 16 | { 17 | /// 18 | /// The sub-rule to repeat. 19 | /// 20 | public BnfAst Subexpr { get; } 21 | 22 | /// 23 | /// Initializes a new instance of the class. 24 | /// 25 | /// The subexpression that can be repeated 0 or more times. 26 | public Rep0(BnfAst subexpr) 27 | { 28 | this.Subexpr = subexpr; 29 | } 30 | 31 | /// 32 | protected override BnfAst SubstituteByReferenceImpl(BnfAst find, BnfAst replaceWith) => 33 | new Rep0(this.Subexpr.SubstituteByReference(find, replaceWith)); 34 | 35 | /// 36 | public override IEnumerable GetFirstCalls() => this.Subexpr.GetFirstCalls(); 37 | 38 | /// 39 | public override BnfAst Desugar() => new Rep0(this.Subexpr.Desugar()); 40 | 41 | /// 42 | public override string GetParsedType(RuleSet ruleSet, TokenKindSet tokens) => 43 | $"{TypeNames.IReadOnlyList}<{this.Subexpr.GetParsedType(ruleSet, tokens)}>"; 44 | 45 | /// 46 | public override string ToString() => $"Rep0({this.Subexpr})"; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Parser.Generator/Ast/BnfAst.Rep1.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System.Collections.Generic; 6 | using Yoakke.SynKit.Parser.Generator.Model; 7 | 8 | namespace Yoakke.SynKit.Parser.Generator.Ast; 9 | 10 | internal partial class BnfAst 11 | { 12 | /// 13 | /// Represents a sub-rule that can be repeated 1 or more times. 14 | /// 15 | public class Rep1 : BnfAst 16 | { 17 | /// 18 | /// The sub-rule to repeat. 19 | /// 20 | public BnfAst Subexpr { get; } 21 | 22 | /// 23 | /// Initializes a new instance of the class. 24 | /// 25 | /// The subexpression that can be repeated 1 or more times. 26 | public Rep1(BnfAst subexpr) 27 | { 28 | this.Subexpr = subexpr; 29 | } 30 | 31 | /// 32 | protected override BnfAst SubstituteByReferenceImpl(BnfAst find, BnfAst replaceWith) => 33 | new Rep1(this.Subexpr.SubstituteByReference(find, replaceWith)); 34 | 35 | /// 36 | public override IEnumerable GetFirstCalls() => this.Subexpr.GetFirstCalls(); 37 | 38 | /// 39 | public override BnfAst Desugar() => new Rep1(this.Subexpr.Desugar()); 40 | 41 | /// 42 | public override string GetParsedType(RuleSet ruleSet, TokenKindSet tokens) => 43 | $"{TypeNames.IReadOnlyList}<{this.Subexpr.GetParsedType(ruleSet, tokens)}>"; 44 | 45 | /// 46 | public override string ToString() => $"Rep1({this.Subexpr})"; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Parser.Generator/Diagnostics.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using Microsoft.CodeAnalysis; 6 | 7 | namespace Yoakke.SynKit.Parser.Generator; 8 | 9 | /// 10 | /// Diagnostics produced by the parser generator. 11 | /// 12 | internal static class Diagnostics 13 | { 14 | #pragma warning disable RS2008 // Enable analyzer release tracking 15 | 16 | /// 17 | /// Happens whan an identifier has no matching rule or token-type. 18 | /// 19 | public static readonly DiagnosticDescriptor UnknownRuleIdentifier = new( 20 | id: "YKPARSERGEN001", 21 | title: "Identifier is neither a rule, nor a terminal", 22 | messageFormat: "The identifier {0} matches no usable rule or token-kind to match", 23 | category: "Parser generation", 24 | DiagnosticSeverity.Error, 25 | isEnabledByDefault: true); 26 | 27 | public static readonly DiagnosticDescriptor NotPartialType = new( 28 | id: "YKPARSERGEN002", 29 | title: "The target parser type is not partial", 30 | messageFormat: "The target parser type {0} or one of its containing types is not marked as partial", 31 | category: "Parser generation", 32 | defaultSeverity: DiagnosticSeverity.Error, 33 | isEnabledByDefault: true); 34 | 35 | #pragma warning restore RS2008 // Enable analyzer release tracking 36 | } 37 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Parser.Generator/InjectedSources/CustomParserAttribute.cs: -------------------------------------------------------------------------------- 1 | // 2 | 3 | // Copyright (c) 2021-2022 Yoakke. 4 | // Licensed under the Apache License, Version 2.0. 5 | // Source repository: https://github.com/LanguageDev/Yoakke 6 | 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Text; 10 | 11 | namespace Yoakke.SynKit.Parser.Attributes; 12 | 13 | /// 14 | /// An attribute to annotate a bustom parser for a rule. 15 | /// 16 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] 17 | internal class CustomParserAttribute : Attribute 18 | { 19 | /// 20 | /// The rule name. 21 | /// 22 | public string Rule { get; set; } 23 | 24 | /// 25 | /// Initializes a new instance of the class. 26 | /// 27 | /// The rule name. 28 | public CustomParserAttribute(string rule) 29 | { 30 | this.Rule = rule; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Parser.Generator/InjectedSources/LeftAttribute.cs: -------------------------------------------------------------------------------- 1 | // 2 | 3 | // Copyright (c) 2021-2022 Yoakke. 4 | // Licensed under the Apache License, Version 2.0. 5 | // Source repository: https://github.com/LanguageDev/Yoakke 6 | 7 | using System; 8 | 9 | namespace Yoakke.SynKit.Parser.Attributes; 10 | 11 | /// 12 | /// An attribute to annotate a left-associative operator. 13 | /// 14 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] 15 | internal class LeftAttribute : Attribute 16 | { 17 | /// 18 | /// The separators that should be left-associative. 19 | /// 20 | public object[] Separators { get; set; } 21 | 22 | /// 23 | /// Initializes a new instance of the class. 24 | /// 25 | /// The separator elements that should be left-associative. 26 | public LeftAttribute(params object[] separators) 27 | { 28 | this.Separators = separators; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Parser.Generator/InjectedSources/ParserAttribute.cs: -------------------------------------------------------------------------------- 1 | // 2 | 3 | // Copyright (c) 2021-2022 Yoakke. 4 | // Licensed under the Apache License, Version 2.0. 5 | // Source repository: https://github.com/LanguageDev/Yoakke 6 | 7 | using System; 8 | 9 | namespace Yoakke.SynKit.Parser.Attributes; 10 | 11 | #nullable enable 12 | 13 | /// 14 | /// An attribute to mark a class as a parser with rule methods inside. 15 | /// 16 | [AttributeUsage(AttributeTargets.Class)] 17 | internal class ParserAttribute : Attribute 18 | { 19 | /// 20 | /// The token kind type to use as a parser element. 21 | /// 22 | public Type? TokenType { get; } 23 | 24 | /// 25 | /// Initializes a new instance of the class. 26 | /// 27 | public ParserAttribute() 28 | { 29 | } 30 | 31 | /// 32 | /// Initializes a new instance of the class. 33 | /// 34 | /// The token kind type to use as a parser element. 35 | public ParserAttribute(Type tokenType) 36 | { 37 | this.TokenType = tokenType; 38 | } 39 | } 40 | 41 | #nullable restore 42 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Parser.Generator/InjectedSources/RightAttribute.cs: -------------------------------------------------------------------------------- 1 | // 2 | 3 | // Copyright (c) 2021-2022 Yoakke. 4 | // Licensed under the Apache License, Version 2.0. 5 | // Source repository: https://github.com/LanguageDev/Yoakke 6 | 7 | using System; 8 | 9 | namespace Yoakke.SynKit.Parser.Attributes; 10 | 11 | /// 12 | /// An attribute to annotate a right-associative operator. 13 | /// 14 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] 15 | internal class RightAttribute : Attribute 16 | { 17 | /// 18 | /// The separators that should be right-associative. 19 | /// 20 | public object[] Separators { get; set; } 21 | 22 | /// 23 | /// Initializes a new instance of the class. 24 | /// 25 | /// The separator elements that should be right-associative. 26 | public RightAttribute(params object[] separators) 27 | { 28 | this.Separators = separators; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Parser.Generator/InjectedSources/RuleAttribute.cs: -------------------------------------------------------------------------------- 1 | // 2 | 3 | // Copyright (c) 2021-2022 Yoakke. 4 | // Licensed under the Apache License, Version 2.0. 5 | // Source repository: https://github.com/LanguageDev/Yoakke 6 | 7 | using System; 8 | 9 | namespace Yoakke.SynKit.Parser.Attributes; 10 | 11 | /// 12 | /// An attribute to annotate a rule over a transformation method. 13 | /// 14 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] 15 | internal class RuleAttribute : Attribute 16 | { 17 | /// 18 | /// The rule in grammar notation. 19 | /// 20 | public string Rule { get; set; } 21 | 22 | /// 23 | /// Initializes a new instance of the class. 24 | /// 25 | /// The rule in grammar notation. 26 | public RuleAttribute(string rule) 27 | { 28 | this.Rule = rule; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Parser.Generator/InjectedSources/TokenSourceAttribute.cs: -------------------------------------------------------------------------------- 1 | // 2 | 3 | // Copyright (c) 2021-2022 Yoakke. 4 | // Licensed under the Apache License, Version 2.0. 5 | // Source repository: https://github.com/LanguageDev/Yoakke 6 | 7 | using System; 8 | 9 | namespace Yoakke.SynKit.Parser.Attributes; 10 | 11 | /// 12 | /// An attribute to mark a field or property as the thing holding onto the token source. 13 | /// 14 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] 15 | internal class TokenSourceAttribute : Attribute 16 | { 17 | } 18 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Parser.Generator/Model/ParserModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | using Microsoft.CodeAnalysis; 9 | 10 | namespace Yoakke.SynKit.Parser.Generator.Model; 11 | 12 | internal record class ParserModel( 13 | INamedTypeSymbol ParserType, 14 | ISymbol? SourceField, 15 | RuleSet RuleSet, 16 | TokenKindSet TokenKinds); 17 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Parser.Generator/Model/PrecedenceEntry.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System.Collections.Generic; 6 | using Microsoft.CodeAnalysis; 7 | 8 | namespace Yoakke.SynKit.Parser.Generator.Model; 9 | 10 | /// 11 | /// A single entry in the precedence-table. 12 | /// 13 | internal class PrecedenceEntry 14 | { 15 | /// 16 | /// True, if the given precedence-level contains left-associative operands. 17 | /// If false, the precedence-level is considered to contain right-associative operands. 18 | /// 19 | public bool Left { get; } 20 | 21 | /// 22 | /// The set of operators on this precedence-level. 23 | /// 24 | public ISet Operators { get; } 25 | 26 | /// 27 | /// The method that transforms the given precedence-level, when parsed. 28 | /// 29 | public IMethodSymbol Method { get; } 30 | 31 | /// 32 | /// Initializes a new instance of the class. 33 | /// 34 | /// True, if the level is left-associative. 35 | /// The operators on the level. 36 | /// The method that transforms the parsed elements of the precedence level. 37 | public PrecedenceEntry(bool left, ISet operators, IMethodSymbol method) 38 | { 39 | this.Left = left; 40 | this.Operators = operators; 41 | this.Method = method; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Parser.Generator/Model/Rule.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using Yoakke.SynKit.Parser.Generator.Ast; 6 | 7 | namespace Yoakke.SynKit.Parser.Generator.Model; 8 | 9 | /// 10 | /// Represents a single BNF rule-definition. 11 | /// 12 | internal class Rule 13 | { 14 | /// 15 | /// The name of the . This is on the left-hand side of the rule-definition, before the colon. 16 | /// 17 | public string Name { get; } 18 | 19 | /// 20 | /// The AST of the grammar to match. 21 | /// 22 | public BnfAst Ast { get; set; } 23 | 24 | /// 25 | /// True, if this should be part of the public API. 26 | /// 27 | public bool PublicApi { get; } 28 | 29 | /// 30 | /// The visual name of this . 31 | /// 32 | public string VisualName { get; set; } 33 | 34 | /// 35 | /// Initializes a new instance of the class. 36 | /// 37 | /// The name of the grammar rule. 38 | /// The AST of the rule. 39 | /// True, if the rule should be part of public API. 40 | public Rule(string name, BnfAst ast, bool publicApi = true) 41 | { 42 | this.Name = name; 43 | this.Ast = ast; 44 | this.PublicApi = publicApi; 45 | this.VisualName = name; 46 | } 47 | 48 | /// 49 | public override string ToString() => $"{this.Name} : {this.Ast}"; 50 | } 51 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Parser.Generator/Parser.Generator.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Parser.Generator/Syntax/BnfToken.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | namespace Yoakke.SynKit.Parser.Generator.Syntax; 6 | 7 | /// 8 | /// A single token (terminal) in the BNF grammar. 9 | /// 10 | internal class BnfToken 11 | { 12 | /// 13 | /// 0-based index in the BNF source. 14 | /// 15 | public int Index { get; } 16 | 17 | /// 18 | /// The textual value of this . 19 | /// 20 | public string Value { get; } 21 | 22 | /// 23 | /// The kind of this . 24 | /// 25 | public BnfTokenType Type { get; } 26 | 27 | /// 28 | /// Initializes a new instance of the class. 29 | /// 30 | /// The start index of the token in the source text. 31 | /// The text value of the token. 32 | /// The of the token. 33 | public BnfToken(int index, string value, BnfTokenType type) 34 | { 35 | this.Index = index; 36 | this.Value = value; 37 | this.Type = type; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Parser.Generator/Syntax/BnfTokenType.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | namespace Yoakke.SynKit.Parser.Generator.Syntax; 6 | 7 | /// 8 | /// The possible different kinds for a . 9 | /// 10 | internal enum BnfTokenType 11 | { 12 | /// 13 | /// End of grammar. 14 | /// 15 | End, 16 | 17 | /// 18 | /// An identifier. 19 | /// 20 | Identifier, 21 | 22 | /// 23 | /// ':'. 24 | /// 25 | Colon, 26 | 27 | /// 28 | /// '|'. 29 | /// 30 | Pipe, 31 | 32 | /// 33 | /// '('. 34 | /// 35 | OpenParen, 36 | 37 | /// 38 | /// ')'. 39 | /// 40 | CloseParen, 41 | 42 | /// 43 | /// A literal for matching token texts. 44 | /// 45 | StringLiteral, 46 | 47 | /// 48 | /// '+' (repeat 1 or more). 49 | /// 50 | Plus, 51 | 52 | /// 53 | /// '*' (repeat 0 or more). 54 | /// 55 | Star, 56 | 57 | /// 58 | /// '?' (optional). 59 | /// 60 | QuestionMark, 61 | } 62 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Parser.Generator/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/SynKit/Libraries/Parser.Generator/key.snk -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Parser/ParseErrorElement.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System.Collections.Generic; 6 | 7 | namespace Yoakke.SynKit.Parser; 8 | 9 | /// 10 | /// A single error case of parsing. 11 | /// 12 | public class ParseErrorElement 13 | { 14 | /// 15 | /// The expected possible inputs. 16 | /// 17 | public ISet Expected { get; } 18 | 19 | /// 20 | /// The context in which the error occurred. 21 | /// 22 | public string Context { get; } 23 | 24 | /// 25 | /// Initializes a new instance of the class. 26 | /// 27 | /// The expected input. 28 | /// The context in which the error occurred. 29 | public ParseErrorElement(object expected, string context) 30 | : this(new HashSet { expected }, context) 31 | { 32 | } 33 | 34 | /// 35 | /// Initializes a new instance of the class. 36 | /// 37 | /// The expected possible inputs. 38 | /// The context in which the error occurred. 39 | public ParseErrorElement(ISet expected, string context) 40 | { 41 | this.Expected = expected; 42 | this.Context = context; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Parser/ParseResult.Factory.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | 7 | namespace Yoakke.SynKit.Parser; 8 | 9 | /// 10 | /// Factory methods for . 11 | /// 12 | public static class ParseResult 13 | { 14 | /// 15 | /// Constructs a . 16 | /// 17 | /// The parsed value type. 18 | /// The parsed value. 19 | /// The offset in the number of tokens. 20 | /// The furthest advanced , if any. 21 | /// The created . 22 | public static ParseOk Ok(T value, int offset, ParseError? furthestError = null) => new(value, offset, furthestError); 23 | 24 | /// 25 | /// Constructs a . 26 | /// 27 | /// The expected element. 28 | /// The token encountered instead. 29 | /// The position where the error occured. 30 | /// The rule context the error occurred in. 31 | /// The created . 32 | public static ParseError Error(object expected, object? got, IComparable position, string context) => 33 | new(expected, got, position, context); 34 | } 35 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Parser/Parser.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Parser/PunctuatedValue.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | namespace Yoakke.SynKit.Parser; 6 | 7 | /// 8 | /// A single, punctuated element. 9 | /// 10 | /// The punctuated element type. 11 | /// The punctuation element type. 12 | public readonly struct PunctuatedValue 13 | { 14 | /// 15 | /// The punctuated element. 16 | /// 17 | public readonly TValue Value; 18 | 19 | /// 20 | /// The punctuation that follows the element. 21 | /// 22 | public readonly TPunct? Punctuation; 23 | 24 | /// 25 | /// Initializes a new instance of the struct. 26 | /// 27 | /// The element that is punctuated. 28 | /// The punctuation element that follows the punctuated one. 29 | public PunctuatedValue(TValue element, TPunct? punctuation) 30 | { 31 | this.Value = element; 32 | this.Punctuation = punctuation; 33 | } 34 | 35 | /// 36 | /// Deconstructs an object into its value and optional punctuation components. 37 | /// 38 | /// Represents the main value extracted from the object. 39 | /// Represents an optional punctuation element associated with the value. 40 | public void Deconstruct(out TValue value, out TPunct? punct) 41 | { 42 | value = this.Value; 43 | punct = this.Punctuation!; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Parser/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/SynKit/Libraries/Parser/key.snk -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Reporting/FootnoteDiagnosticInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | namespace Yoakke.SynKit.Reporting; 6 | 7 | /// 8 | /// A footnote diagnostic information. 9 | /// 10 | public class FootnoteDiagnosticInfo : IDiagnosticInfo 11 | { 12 | /// 13 | public Severity? Severity { get; set; } 14 | 15 | /// 16 | public string? Message { get; set; } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Reporting/IDiagnosticInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | namespace Yoakke.SynKit.Reporting; 6 | 7 | /// 8 | /// A single piece of information for a . 9 | /// 10 | public interface IDiagnosticInfo 11 | { 12 | /// 13 | /// The severity of the information. 14 | /// 15 | public Severity? Severity { get; } 16 | 17 | /// 18 | /// The information message. 19 | /// 20 | public string? Message { get; } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Reporting/Present/ColoredToken.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | namespace Yoakke.SynKit.Reporting.Present; 6 | 7 | /// 8 | /// A single, colored token in the source code. 9 | /// 10 | public readonly struct ColoredToken 11 | { 12 | /// 13 | /// The start index of the token. 14 | /// 15 | public readonly int Start; 16 | 17 | /// 18 | /// The length of the token. 19 | /// 20 | public readonly int Length; 21 | 22 | /// 23 | /// The kind of the token. 24 | /// 25 | public readonly TokenKind Kind; 26 | 27 | /// 28 | /// Initializes a new instance of the struct. 29 | /// 30 | /// The starting index of the token in the line. 31 | /// The length of the token in characters. 32 | /// The of the token. 33 | public ColoredToken(int start, int length, TokenKind kind) 34 | { 35 | this.Start = start; 36 | this.Length = length; 37 | this.Kind = kind; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Reporting/Present/IDiagnosticsPresenter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | namespace Yoakke.SynKit.Reporting.Present; 6 | 7 | /// 8 | /// Interface for objects that can present a for the user in some way. 9 | /// 10 | public interface IDiagnosticsPresenter 11 | { 12 | /// 13 | /// The style to use when presenting. 14 | /// 15 | public DiagnosticsStyle Style { get; set; } 16 | 17 | /// 18 | /// The syntax highlighter to use for source code. 19 | /// 20 | public ISyntaxHighlighter SyntaxHighlighter { get; set; } 21 | 22 | /// 23 | /// Presents the given to the user. 24 | /// 25 | /// The diagnostic to present. 26 | public void Present(Diagnostics diagnostic); 27 | } 28 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Reporting/Present/ISyntaxHighlighter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System.Collections.Generic; 6 | using Yoakke.SynKit.Text; 7 | 8 | namespace Yoakke.SynKit.Reporting.Present; 9 | 10 | /// 11 | /// An interface to provide custom syntax highlighting for source text. 12 | /// 13 | public interface ISyntaxHighlighter 14 | { 15 | /// 16 | /// The style to use. 17 | /// 18 | public SyntaxHighlightStyle Style { get; set; } 19 | 20 | /// 21 | /// Asks for syntax highlighting for a single source line. 22 | /// 23 | /// The source that contains the line. 24 | /// The index of the line in the source. 25 | /// A list of s. Their order does not matter and not all characters have to 26 | /// belong to a token. 27 | public IReadOnlyList GetHighlightingForLine(ISourceFile sourceFile, int line); 28 | } 29 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Reporting/Present/NullSyntaxHighlighter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using Yoakke.SynKit.Text; 8 | 9 | namespace Yoakke.SynKit.Reporting.Present; 10 | 11 | /// 12 | /// A syntax highlighter that does nothing. Serves as a default. 13 | /// 14 | public class NullSyntaxHighlighter : ISyntaxHighlighter 15 | { 16 | /// 17 | /// A default instance for the null syntax highlighter. 18 | /// 19 | public static readonly NullSyntaxHighlighter Instance = new(); 20 | 21 | /// 22 | public SyntaxHighlightStyle Style { get; set; } = SyntaxHighlightStyle.Default; 23 | 24 | /// 25 | public IReadOnlyList GetHighlightingForLine(ISourceFile sourceFile, int line) => 26 | Array.Empty(); 27 | } 28 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Reporting/Present/SyntaxHighlightStyle.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | 8 | namespace Yoakke.SynKit.Reporting.Present; 9 | 10 | /// 11 | /// Styles for s. 12 | /// 13 | public class SyntaxHighlightStyle 14 | { 15 | /// 16 | /// The default syntax highlight style. 17 | /// 18 | public static readonly SyntaxHighlightStyle Default = new(); 19 | 20 | /// 21 | /// The colors for the different token kinds. 22 | /// 23 | public IDictionary TokenColors { get; set; } = new Dictionary 24 | { 25 | { TokenKind.Comment, ConsoleColor.DarkGreen }, 26 | { TokenKind.Keyword, ConsoleColor.Magenta }, 27 | { TokenKind.Literal, ConsoleColor.Blue }, 28 | { TokenKind.Name, ConsoleColor.Cyan }, 29 | { TokenKind.Operator, ConsoleColor.DarkCyan }, 30 | { TokenKind.Punctuation, ConsoleColor.White }, 31 | { TokenKind.Other, ConsoleColor.White }, 32 | }; 33 | 34 | /// 35 | /// The default color to use. 36 | /// 37 | public ConsoleColor DefaultColor { get; set; } = ConsoleColor.White; 38 | 39 | /// 40 | /// Retrieves the appropriate color for the given . 41 | /// 42 | /// The to get the color for. 43 | /// The associated with , or 44 | /// , if none is associated with it. 45 | public ConsoleColor GetTokenColor(TokenKind kind) => 46 | this.TokenColors.TryGetValue(kind, out var col) ? col : this.DefaultColor; 47 | } 48 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Reporting/Present/TokenKind.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | namespace Yoakke.SynKit.Reporting.Present; 6 | 7 | /// 8 | /// Different token categories for presenting. 9 | /// 10 | public enum TokenKind 11 | { 12 | /// 13 | /// A comment. 14 | /// 15 | Comment, 16 | 17 | /// 18 | /// A language keyword. 19 | /// 20 | Keyword, 21 | 22 | /// 23 | /// Some literal. 24 | /// 25 | Literal, 26 | 27 | /// 28 | /// A name or identifier. 29 | /// 30 | Name, 31 | 32 | /// 33 | /// Punctuation token. 34 | /// 35 | Punctuation, 36 | 37 | /// 38 | /// An operator. 39 | /// 40 | Operator, 41 | 42 | /// 43 | /// Something else. 44 | /// 45 | Other, 46 | } 47 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Reporting/Reporting.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Reporting/SourceDiagnosticInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using Yoakke.SynKit.Text; 6 | 7 | namespace Yoakke.SynKit.Reporting; 8 | 9 | /// 10 | /// A that references part of the source code. 11 | /// 12 | public class SourceDiagnosticInfo : IDiagnosticInfo 13 | { 14 | /// 15 | public Severity? Severity { get; set; } 16 | 17 | /// 18 | public string? Message { get; set; } 19 | 20 | /// 21 | /// The location the diagnostic information refers to. 22 | /// 23 | public Location Location { get; set; } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Reporting/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/SynKit/Libraries/Reporting/key.snk -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Text/ISourceFile.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System.IO; 6 | 7 | namespace Yoakke.SynKit.Text; 8 | 9 | /// 10 | /// Represents a source file. 11 | /// 12 | public interface ISourceFile 13 | { 14 | /// 15 | /// Retrieves a path that uniquely identifies this . 16 | /// 17 | public string Path { get; } 18 | 19 | /// 20 | /// Retrieves the currently available amount of lines in the . 21 | /// This means the file might has more, but it has not been read yet. 22 | /// 23 | public int AvailableLines { get; } 24 | 25 | /// 26 | /// The for the contents of the . 27 | /// 28 | public TextReader Reader { get; } 29 | 30 | /// 31 | /// Retrieves a given line from the . 32 | /// 33 | /// The index of the line to retrieve. 34 | /// The line with the given index. 35 | public string GetLine(int index); 36 | } 37 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Text/Location.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | namespace Yoakke.SynKit.Text; 6 | 7 | /// 8 | /// Represents a range in some source file. 9 | /// 10 | /// The source file. 11 | /// The range. 12 | public readonly record struct Location(ISourceFile? File, Range Range); 13 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Text/Metrics/IStringMetric.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | 7 | namespace Yoakke.SynKit.Text.Metrics; 8 | 9 | /// 10 | /// Interface for any string distance metric. 11 | /// 12 | public interface IStringMetric 13 | { 14 | /// 15 | /// Calculates the distance (inverse similarity) between two strings. 16 | /// 17 | /// The first string to compare. 18 | /// The second string to compare. 19 | /// A number describing how dissimilar the two strings are. 0 means that the two strings are 20 | /// identical, bigger numbers mean bigger difference. 21 | public int Distance(ReadOnlySpan str1, ReadOnlySpan str2); 22 | } 23 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Text/Metrics/LevenshteinDistance.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | 7 | namespace Yoakke.SynKit.Text.Metrics; 8 | 9 | /// 10 | /// Implements Levenshtein distance. 11 | /// See: https://en.wikipedia.org/wiki/Levenshtein_distance. 12 | /// 13 | public class LevenshteinDistance : IStringMetric 14 | { 15 | /// 16 | /// A singleton instance to use. 17 | /// 18 | public static readonly LevenshteinDistance Instance = new(); 19 | 20 | /// 21 | public int Distance(ReadOnlySpan str1, ReadOnlySpan str2) 22 | { 23 | var v0 = new int[str2.Length + 1]; 24 | var v1 = new int[str2.Length + 1]; 25 | 26 | for (var i = 0; i <= str2.Length; ++i) v0[i] = i; 27 | 28 | for (var i = 0; i < str1.Length; ++i) 29 | { 30 | v1[0] = i + 1; 31 | 32 | for (var j = 0; j < str2.Length; ++j) 33 | { 34 | var deletionCost = v0[j + 1] + 1; 35 | var insertionCost = v1[j] + 1; 36 | var substitutionCost = v0[j] + (str1[i] == str2[j] ? 0 : 1); 37 | 38 | v1[j + 1] = Math.Min(deletionCost, Math.Min(insertionCost, substitutionCost)); 39 | } 40 | 41 | var tmp = v1; 42 | v1 = v0; 43 | v0 = tmp; 44 | } 45 | 46 | return v0[str2.Length]; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Text/Metrics/OptimalStringAlignmentDistance.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System; 6 | 7 | namespace Yoakke.SynKit.Text.Metrics; 8 | 9 | /// 10 | /// Implements Optimal String Alignment distance. 11 | /// See: https://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance#Optimal_string_alignment_distance. 12 | /// 13 | public class OptimalStringAlignmentDistance : IStringMetric 14 | { 15 | /// 16 | /// A singleton instance to use. 17 | /// 18 | public static readonly OptimalStringAlignmentDistance Instance = new(); 19 | 20 | /// 21 | public int Distance(ReadOnlySpan str1, ReadOnlySpan str2) 22 | { 23 | var d = new int[str1.Length + 1, str2.Length + 1]; 24 | 25 | for (var i = 0; i <= str1.Length; ++i) d[i, 0] = i; 26 | for (var j = 0; j <= str2.Length; ++j) d[0, j] = j; 27 | 28 | for (var i = 1; i <= str1.Length; ++i) 29 | { 30 | for (var j = 1; j <= str2.Length; ++j) 31 | { 32 | var deletionCost = d[i - 1, j] + 1; 33 | var insertionCost = d[i, j - 1] + 1; 34 | var substitutionCost = d[i - 1, j - 1] + (str1[i - 1] == str2[j - 1] ? 0 : 1); 35 | 36 | d[i, j] = Math.Min(deletionCost, Math.Min(insertionCost, substitutionCost)); 37 | 38 | if (i > 1 && j > 1 && str1[i - 1] == str2[j - 2] && str1[i - 2] == str2[j - 1]) 39 | { 40 | var transpositionCost = d[i - 2, j - 2] + 1; 41 | d[i, j] = Math.Min(d[i, j], transpositionCost); 42 | } 43 | } 44 | } 45 | 46 | return d[str1.Length, str2.Length]; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Text/Text.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Sources/SynKit/Libraries/Text/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/SynKit/Libraries/Text/key.snk -------------------------------------------------------------------------------- /Sources/SynKit/README.md: -------------------------------------------------------------------------------- 1 | ## SynKit - The Syntax Toolkit libraries 2 | 3 | SynKit is a subcomponent of Yoakke that collects modules and tools related to syntax. The aim is to cover every general need when it comes to analyzing grammars, generating lexers and parsers or even helping you developing your own syntax tooling. 4 | 5 | ### Components 6 | 7 | - Lexing: Lexers can be defined completely declaratively, as regular expression annotations - inspired by [Logos](https://github.com/maciejhirsz/logos) - over token types. Do not worry, the regular expressions are compiled into _Deterministic Finite Automatas_, so the resulting code is a lot more efficient, than your average RegEx engine. 8 | - Parsing: Parsers are defined using a BNF-like notation as annotations over methods that produce the syntax node for the appropriate rule - inspired by [rply](https://github.com/alex/rply/). The generated parser is a recursive descent one, but supports automatic transformation of direct left-recursion and precedence tables. 9 | - Syntax trees: ASTs usually are a pain to implement because of all the crud that goes on with them in C#. With an annotation you can generate equality and hash implementations for AST nodes, or define visitors for them. 10 | - Error reporting: Nice error messages on console are a pain. You have to align arrows, properly color text segments, number lines and so on. Fortunately, there is a component that provides you a nice fluent API - inspired by the beautiful [codespan](https://github.com/brendanzab/codespan) library - to generate a message, render it however you want to. You can even create a custom syntax-highlighter for source lines! 11 | 12 | TODO: Update the library listing with the other modules too 13 | -------------------------------------------------------------------------------- /Sources/SynKit/Tests/Automata.Tests/Automata.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Sources/SynKit/Tests/Automata.Tests/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/SynKit/Tests/Automata.Tests/key.snk -------------------------------------------------------------------------------- /Sources/SynKit/Tests/C.Syntax.Tests/C.Syntax.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Sources/SynKit/Tests/C.Syntax.Tests/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/SynKit/Tests/C.Syntax.Tests/key.snk -------------------------------------------------------------------------------- /Sources/SynKit/Tests/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Yoakke.SynKit.$(MSBuildProjectName) 7 | 8 | 9 | -------------------------------------------------------------------------------- /Sources/SynKit/Tests/Lexer.Tests/AdvancedLexerGeneratorTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using Xunit; 6 | using Yoakke.SynKit.Lexer.Attributes; 7 | using IgnoreAttribute = Yoakke.SynKit.Lexer.Attributes.IgnoreAttribute; 8 | 9 | namespace Yoakke.SynKit.Lexer.Tests; 10 | 11 | public partial class AdvancedLexerGeneratorTests : TestBase 12 | { 13 | public enum TokenType 14 | { 15 | [Ignore][Regex(Regexes.Whitespace)] Whitespace, 16 | 17 | [Error] Error, 18 | [End] End, 19 | 20 | [Regex("[\\-]")] MinusInRegexGroup, 21 | [Regex("[\\[]")] LeftBracketInRegexGroup, 22 | [Regex("[\\]]")] RightBracketInRegexGroup, 23 | } 24 | 25 | [Lexer(typeof(TokenType))] 26 | internal partial class AdvancedLexer 27 | { 28 | } 29 | 30 | [Fact] 31 | public void AdvancedRulesSequence() 32 | { 33 | var lexer = new AdvancedLexer("-"); 34 | Assert.Equal(Token("-", TokenType.MinusInRegexGroup, Range((0, 0), 1)), lexer.Next()); 35 | Assert.Equal(Token(string.Empty, TokenType.End, Range((0, 1), 0)), lexer.Next()); 36 | } 37 | 38 | [Fact] 39 | public void LeftBracketInRegex() 40 | { 41 | var lexer = new AdvancedLexer("["); 42 | Assert.Equal(Token("[", TokenType.LeftBracketInRegexGroup, Range((0, 0), 1)), lexer.Next()); 43 | Assert.Equal(Token(string.Empty, TokenType.End, Range((0, 1), 0)), lexer.Next()); 44 | } 45 | 46 | [Fact] 47 | public void RightBracketInRegex() 48 | { 49 | var lexer = new AdvancedLexer("]"); 50 | Assert.Equal(Token("]", TokenType.RightBracketInRegexGroup, Range((0, 0), 1)), lexer.Next()); 51 | Assert.Equal(Token(string.Empty, TokenType.End, Range((0, 1), 0)), lexer.Next()); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Sources/SynKit/Tests/Lexer.Tests/Issue140Tests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System.IO; 6 | using Xunit; 7 | using Yoakke.SynKit.Lexer.Attributes; 8 | 9 | namespace Yoakke.SynKit.Lexer.Tests; 10 | 11 | // https://github.com/LanguageDev/Yoakke/issues/140 12 | public partial class Issue140Tests 13 | { 14 | internal enum TokenType 15 | { 16 | [Error] Error, 17 | [End] End, 18 | [Ignore] [Regex(Regexes.Whitespace)] Whitespace, 19 | 20 | [Regex(@"'((\\[^\n\r])|[^\r\n\\'])*'")] Test, 21 | } 22 | 23 | [Lexer(typeof(TokenType))] 24 | internal partial class Lexer 25 | { 26 | } 27 | 28 | [Theory] 29 | [InlineData(@"'hello'")] 30 | [InlineData(@"'hello \' bye'")] 31 | public void Tests(string input) 32 | { 33 | var lexer = new Lexer(input); 34 | var t = lexer.Next(); 35 | Assert.Equal(input, t.Text); 36 | Assert.Equal(TokenType.Test, t.Kind); 37 | Assert.Equal(TokenType.End, lexer.Next().Kind); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/SynKit/Tests/Lexer.Tests/Issue17Tests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System.IO; 6 | using Xunit; 7 | using Yoakke.SynKit.Lexer.Attributes; 8 | 9 | namespace Yoakke.SynKit.Lexer.Tests; 10 | 11 | // https://github.com/LanguageDev/Yoakke/issues/17 12 | public partial class Issue17Tests 13 | { 14 | internal enum TokenType 15 | { 16 | [Error] Error, 17 | [End] End, 18 | } 19 | 20 | [Lexer(typeof(TokenType))] 21 | internal partial class ImplicitCtorLexer 22 | { 23 | } 24 | 25 | [Lexer(typeof(TokenType))] 26 | internal partial class ExplicitCtorLexer 27 | { 28 | [CharSource] 29 | private readonly ICharStream source; 30 | 31 | public ExplicitCtorLexer(string text) 32 | { 33 | this.source = new TextReaderCharStream(new StringReader(text)); 34 | } 35 | } 36 | 37 | [Fact] 38 | public void ImplicitCtors() 39 | { 40 | Assert.Equal(5, typeof(ImplicitCtorLexer).GetConstructors().Length); 41 | Assert.NotNull(typeof(ImplicitCtorLexer).GetConstructor(new[] { typeof(string) })); 42 | Assert.NotNull(typeof(ImplicitCtorLexer).GetConstructor(new[] { typeof(string), typeof(string) })); 43 | Assert.NotNull(typeof(ImplicitCtorLexer).GetConstructor(new[] { typeof(TextReader) })); 44 | Assert.NotNull(typeof(ImplicitCtorLexer).GetConstructor(new[] { typeof(Text.SourceFile) })); 45 | Assert.NotNull(typeof(ImplicitCtorLexer).GetConstructor(new[] { typeof(ICharStream) })); 46 | } 47 | 48 | [Fact] 49 | public void ExplicitCtors() 50 | { 51 | Assert.Single(typeof(ExplicitCtorLexer).GetConstructors()); 52 | Assert.NotNull(typeof(ExplicitCtorLexer).GetConstructor(new[] { typeof(string) })); 53 | Assert.Null(typeof(ExplicitCtorLexer).GetConstructor(new[] { typeof(Text.SourceFile) })); 54 | Assert.Null(typeof(ExplicitCtorLexer).GetConstructor(new[] { typeof(TextReader) })); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Sources/SynKit/Tests/Lexer.Tests/Lexer.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Sources/SynKit/Tests/Lexer.Tests/TestBase.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using Yoakke.SynKit.Text; 6 | 7 | namespace Yoakke.SynKit.Lexer.Tests; 8 | 9 | public abstract class TestBase 10 | where TKind : notnull 11 | { 12 | protected static Token Token(string value, TKind tt, Range r) => new(r, new Location(new SourceFile("", "test"), r), value, tt); 13 | protected static Token Token(string value, Location location, TKind tt, Range r) => new(r, location, value, tt); 14 | 15 | protected static Range Range((int Line, int Column) p1, (int Line, int Column) p2) => 16 | new(new Position(p1.Line, p1.Column), new Position(p2.Line, p2.Column)); 17 | 18 | protected static Range Range((int Line, int Column) p1, int len) => 19 | new(new Position(p1.Line, p1.Column), len); 20 | } 21 | -------------------------------------------------------------------------------- /Sources/SynKit/Tests/Lexer.Tests/TokenTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using Xunit; 6 | 7 | namespace Yoakke.SynKit.Lexer.Tests; 8 | 9 | public class TokenTests : TestBase 10 | { 11 | [Fact] 12 | public void Equality() 13 | { 14 | var t1 = Token("hello", 3, Range((3, 4), 5)); 15 | var t2 = Token("hello", 3, Range((3, 4), 5)); 16 | Assert.Equal(t1, t2); 17 | Assert.Equal(t1.GetHashCode(), t2.GetHashCode()); 18 | } 19 | 20 | [Fact] 21 | public void InequalityContent() 22 | { 23 | var t1 = Token("hello", 3, Range((3, 4), 5)); 24 | var t2 = Token("bye", 3, Range((3, 4), 5)); 25 | Assert.NotEqual(t1, t2); 26 | Assert.NotEqual(t1.GetHashCode(), t2.GetHashCode()); 27 | } 28 | 29 | [Fact] 30 | public void InequalityKind() 31 | { 32 | var t1 = Token("hello", 3, Range((3, 4), 5)); 33 | var t2 = Token("hello", 4, Range((3, 4), 5)); 34 | Assert.NotEqual(t1, t2); 35 | Assert.NotEqual(t1.GetHashCode(), t2.GetHashCode()); 36 | } 37 | 38 | [Fact] 39 | public void InequalityPosition() 40 | { 41 | var t1 = Token("hello", 3, Range((3, 4), 5)); 42 | var t2 = Token("hello", 4, Range((4, 4), 5)); 43 | Assert.NotEqual(t1, t2); 44 | Assert.NotEqual(t1.GetHashCode(), t2.GetHashCode()); 45 | } 46 | 47 | [Fact] 48 | public void InequalityLength() 49 | { 50 | var t1 = Token("hello", 3, Range((3, 4), 5)); 51 | var t2 = Token("hello", 4, Range((3, 4), 6)); 52 | Assert.NotEqual(t1, t2); 53 | Assert.NotEqual(t1.GetHashCode(), t2.GetHashCode()); 54 | } 55 | 56 | [Fact] 57 | public void NoLocation() 58 | { 59 | var t1 = Token("hello", new(), 3, Range((3, 4), 5)); 60 | var t2 = Token("hello", new(), 3, Range((3, 4), 5)); 61 | Assert.Equal(t1, t2); 62 | Assert.Equal(t1.GetHashCode(), t2.GetHashCode()); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Sources/SynKit/Tests/Lexer.Tests/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/SynKit/Tests/Lexer.Tests/key.snk -------------------------------------------------------------------------------- /Sources/SynKit/Tests/Parser.Generator.Tests/ExpressionParserTests.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Microsoft.CodeAnalysis; 3 | using VerifyXunit; 4 | using Xunit; 5 | using Yoakke.SynKit.Parser.Tests; 6 | 7 | namespace Yoakke.SynKit.Parser.Generator.Tests; 8 | 9 | [UsesVerify] 10 | public class ExpressionParserTests : CodeGenerationTestBase 11 | { 12 | [Fact] 13 | public async Task SimpleMathExpression() 14 | { 15 | string source = @" 16 | namespace Foo 17 | { 18 | using Yoakke.SynKit.Parser.Attributes; 19 | 20 | internal enum TokenType 21 | { 22 | End, 23 | Error, 24 | Whitespace, 25 | 26 | Add, 27 | Sub, 28 | Mul, 29 | Div, 30 | Exp, 31 | Number, 32 | Lparen, 33 | Rparen, 34 | } 35 | 36 | [Parser(typeof(TokenType))] 37 | partial class C 38 | { 39 | [Rule(""top_expression : expression End"")] 40 | private static int TopLevel(int n, IToken _) => n; 41 | 42 | [Right(""^"")] 43 | [Left(""*"", ""/"")] 44 | [Left(""+"", ""-"")] 45 | [Rule(""expression"")] 46 | private static int Op(int left, IToken op, int right) => op.Text switch 47 | { 48 | ""+"" => left + right, 49 | ""-"" => left - right, 50 | ""*"" => left * right, 51 | ""/"" => left / right, 52 | ""^"" => (int)Math.Pow(left, right), 53 | _ => throw new InvalidOperationException(), 54 | }; 55 | 56 | [Rule(""expression : '(' expression ')'"")] 57 | private static int Grouping(IToken _1, int n, IToken _2) => n; 58 | 59 | [Rule(""expression : Number"")] 60 | private static int Number(IToken tok) => int.Parse(tok.Text); 61 | } 62 | }"; 63 | await VerifyCSharp(source, NullableContextOptions.Disable); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Sources/SynKit/Tests/Parser.Generator.Tests/Parser.Generator.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Sources/SynKit/Tests/Parser.Generator.Tests/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/SynKit/Tests/Parser.Generator.Tests/key.snk -------------------------------------------------------------------------------- /Sources/SynKit/Tests/Parser.Tests/IndirectLeftRecursionTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using Xunit; 6 | using Yoakke.SynKit.Lexer; 7 | using Yoakke.SynKit.Lexer.Attributes; 8 | using Yoakke.SynKit.Parser.Attributes; 9 | using IgnoreAttribute = Yoakke.SynKit.Lexer.Attributes.IgnoreAttribute; 10 | 11 | namespace Yoakke.SynKit.Parser.Tests; 12 | 13 | public partial class IndirectLeftRecursionTests 14 | { 15 | internal enum TokenType 16 | { 17 | [End] End, 18 | [Error] Error, 19 | [Ignore] [Regex(Regexes.Whitespace)] Whitespace, 20 | 21 | [Regex(Regexes.Identifier)] Identifier, 22 | } 23 | 24 | [Lexer(typeof(TokenType))] 25 | internal partial class Lexer 26 | { 27 | } 28 | 29 | [Parser(typeof(TokenType))] 30 | internal partial class Parser 31 | { 32 | [Rule("grouping : group_element")] 33 | private static string Ident(string s) => s; 34 | 35 | [Rule("group_element : grouping Identifier")] 36 | private static string Group(string group, IToken next) => $"({group}, {next.Text})"; 37 | 38 | [Rule("group_element : Identifier")] 39 | private static string Ident(IToken t) => t.Text; 40 | } 41 | 42 | private static string Parse(string source) => 43 | new Parser(new Lexer(source)).ParseGrouping().Ok.Value; 44 | 45 | [Theory] 46 | [InlineData("a", "a")] 47 | [InlineData("(a, b)", "a b")] 48 | [InlineData("((a, b), c)", "a b c")] 49 | [InlineData("(((a, b), c), d)", "a b c d")] 50 | public void Tests(string expected, string input) => Assert.Equal(expected, Parse(input)); 51 | } 52 | -------------------------------------------------------------------------------- /Sources/SynKit/Tests/Parser.Tests/Issue17Tests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System.Collections.Generic; 6 | using Xunit; 7 | using Yoakke.SynKit.Lexer; 8 | using Yoakke.SynKit.Parser.Attributes; 9 | using Yoakke.Streams; 10 | 11 | namespace Yoakke.SynKit.Parser.Tests; 12 | 13 | // https://github.com/LanguageDev/Yoakke/issues/17 14 | public partial class Issue17Tests 15 | { 16 | [Parser] 17 | internal partial class ImplicitCtorParser 18 | { 19 | } 20 | 21 | [Parser] 22 | internal partial class ExplicitCtorParser 23 | { 24 | [TokenSource] 25 | private readonly IStream tokens; 26 | 27 | public ExplicitCtorParser(IEnumerable tokens) 28 | { 29 | this.tokens = new EnumerableStream(tokens); 30 | } 31 | } 32 | 33 | [Fact] 34 | public void ImplicitCtors() 35 | { 36 | Assert.Equal(3, typeof(ImplicitCtorParser).GetConstructors().Length); 37 | Assert.NotNull(typeof(ImplicitCtorParser).GetConstructor(new[] { typeof(IEnumerable) })); 38 | Assert.NotNull(typeof(ImplicitCtorParser).GetConstructor(new[] { typeof(ILexer) })); 39 | Assert.NotNull(typeof(ImplicitCtorParser).GetConstructor(new[] { typeof(IPeekableStream) })); 40 | } 41 | 42 | [Fact] 43 | public void ExplicitCtors() 44 | { 45 | Assert.Single(typeof(ExplicitCtorParser).GetConstructors()); 46 | Assert.NotNull(typeof(ExplicitCtorParser).GetConstructor(new[] { typeof(IEnumerable) })); 47 | Assert.Null(typeof(ExplicitCtorParser).GetConstructor(new[] { typeof(ILexer) })); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Sources/SynKit/Tests/Parser.Tests/Issue62Tests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System.Collections.Generic; 6 | using Xunit; 7 | using Yoakke.SynKit.Lexer; 8 | using Yoakke.SynKit.Lexer.Attributes; 9 | using Yoakke.SynKit.Parser.Attributes; 10 | using IgnoreAttribute = Yoakke.SynKit.Lexer.Attributes.IgnoreAttribute; 11 | 12 | namespace Yoakke.SynKit.Parser.Tests; 13 | 14 | // https://github.com/LanguageDev/Yoakke/issues/62 15 | public partial class Issue62Tests 16 | { 17 | internal enum TokenType 18 | { 19 | [End] End, 20 | [Error] Error, 21 | [Ignore] [Regex(Regexes.Whitespace)] Whitespace, 22 | 23 | [Regex(Regexes.Identifier)] Identifier, 24 | [Token(";")] Semicolon, 25 | } 26 | 27 | [Lexer(typeof(TokenType))] 28 | internal partial class Lexer 29 | { 30 | } 31 | 32 | [Parser(typeof(TokenType))] 33 | internal partial class Parser 34 | { 35 | [Rule("program : statement*")] 36 | public static string Program(IReadOnlyList idents) => string.Join(", ", idents); 37 | 38 | [Rule("statement : Identifier ';'")] 39 | public static string Statement(IToken identifier, IToken _) => identifier.Text; 40 | } 41 | 42 | private static string Parse(string source) => 43 | new Parser(new Lexer(source)).ParseProgram().Ok.Value; 44 | 45 | [Theory] 46 | [InlineData("", "; ^")] 47 | [InlineData("x", "x ;")] 48 | [InlineData("x, y", "x; y;")] 49 | public void Tests(string expected, string input) => Assert.Equal(expected, Parse(input)); 50 | } 51 | -------------------------------------------------------------------------------- /Sources/SynKit/Tests/Parser.Tests/LeftRecursionTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using Xunit; 6 | using Yoakke.SynKit.Lexer; 7 | using Yoakke.SynKit.Lexer.Attributes; 8 | using Yoakke.SynKit.Parser.Attributes; 9 | using IgnoreAttribute = Yoakke.SynKit.Lexer.Attributes.IgnoreAttribute; 10 | 11 | namespace Yoakke.SynKit.Parser.Tests; 12 | 13 | /** 14 | NOTE: The following typo caused a very big headache 15 | [Rule("gouping: Identifier")] 16 | 17 | Proposal: When we detect direct left-recursion that we can't resolve, error out and suggest that it's a possible typo 18 | */ 19 | public partial class LeftRecursionTests 20 | { 21 | internal enum TokenType 22 | { 23 | [End] End, 24 | [Error] Error, 25 | [Ignore] [Regex(Regexes.Whitespace)] Whitespace, 26 | 27 | [Regex(Regexes.Identifier)] Identifier, 28 | } 29 | 30 | [Lexer(typeof(TokenType))] 31 | internal partial class Lexer 32 | { 33 | } 34 | 35 | [Parser(typeof(TokenType))] 36 | internal partial class Parser 37 | { 38 | [Rule("grouping : grouping Identifier")] 39 | private static string Group(string group, IToken next) => $"({group}, {next.Text})"; 40 | 41 | [Rule("grouping: Identifier")] 42 | private static string Ident(IToken t) => t.Text; 43 | } 44 | 45 | private static string Parse(string source) => 46 | new Parser(new Lexer(source)).ParseGrouping().Ok.Value; 47 | 48 | [Theory] 49 | [InlineData("a", "a")] 50 | [InlineData("(a, b)", "a b")] 51 | [InlineData("((a, b), c)", "a b c")] 52 | [InlineData("(((a, b), c), d)", "a b c d")] 53 | public void Tests(string expected, string input) => Assert.Equal(expected, Parse(input)); 54 | } 55 | -------------------------------------------------------------------------------- /Sources/SynKit/Tests/Parser.Tests/Parser.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Sources/SynKit/Tests/Parser.Tests/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/SynKit/Tests/Parser.Tests/key.snk -------------------------------------------------------------------------------- /Sources/SynKit/Tests/Reporting.Tests/AssertUtils.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using Xunit; 6 | 7 | namespace Yoakke.SynKit.Reporting.Tests; 8 | 9 | /// 10 | /// Assertion helpers. 11 | /// 12 | public static class AssertUtils 13 | { 14 | public static void AreEqualIgnoreNewlineEncoding(string expected, string got) => 15 | Assert.Equal(NormalizeNewlines(expected), NormalizeNewlines(got)); 16 | 17 | private static string NormalizeNewlines(string s) => s.Replace("\r\n", "\n").Replace('\r', '\n'); 18 | } 19 | -------------------------------------------------------------------------------- /Sources/SynKit/Tests/Reporting.Tests/Reporting.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Sources/SynKit/Tests/Reporting.Tests/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/SynKit/Tests/Reporting.Tests/key.snk -------------------------------------------------------------------------------- /Sources/SynKit/Tests/Text.Tests/SourceFileTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using System.IO; 6 | using Xunit; 7 | 8 | namespace Yoakke.SynKit.Text.Tests; 9 | 10 | public class SourceFileTests 11 | { 12 | [Fact] 13 | public void GetAllLinesOfString() 14 | { 15 | var sourceFile = new SourceFile( 16 | "a.txt", 17 | @"abc 18 | xyz 19 | qwe"); 20 | Assert.Equal(3, sourceFile.AvailableLines); 21 | Assert.Equal("abc", sourceFile.GetLine(0).TrimEnd()); 22 | Assert.Equal("xyz", sourceFile.GetLine(1).TrimEnd()); 23 | Assert.Equal("qwe", sourceFile.GetLine(2).TrimEnd()); 24 | Assert.Equal("xyz", sourceFile.GetLine(1).TrimEnd()); 25 | Assert.Equal("abc", sourceFile.GetLine(0).TrimEnd()); 26 | } 27 | 28 | [Fact] 29 | public void GetAllLinesOfStringReader() 30 | { 31 | var sourceFile = new SourceFile( 32 | "a.txt", 33 | new StringReader(@"abc 34 | xyz 35 | qwe")); 36 | Assert.Equal(0, sourceFile.AvailableLines); 37 | Assert.Equal("abc", sourceFile.GetLine(0).TrimEnd()); 38 | Assert.Equal(1, sourceFile.AvailableLines); 39 | Assert.Equal("xyz", sourceFile.GetLine(1).TrimEnd()); 40 | Assert.Equal(2, sourceFile.AvailableLines); 41 | Assert.Equal("qwe", sourceFile.GetLine(2).TrimEnd()); 42 | Assert.Equal(3, sourceFile.AvailableLines); 43 | Assert.Equal("xyz", sourceFile.GetLine(1).TrimEnd()); 44 | Assert.Equal(3, sourceFile.AvailableLines); 45 | Assert.Equal("abc", sourceFile.GetLine(0).TrimEnd()); 46 | Assert.Equal(3, sourceFile.AvailableLines); 47 | } 48 | 49 | [Fact] 50 | public void ReaderPositionUnaffectedByGetLine() 51 | { 52 | var sourceFile = new SourceFile( 53 | "a.txt", 54 | new StringReader(@"abc 55 | xyz 56 | qwe")); 57 | sourceFile.GetLine(2); 58 | Assert.Equal("abc", sourceFile.ReadLine()?.TrimEnd()); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Sources/SynKit/Tests/Text.Tests/StringMetricsTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021-2022 Yoakke. 2 | // Licensed under the Apache License, Version 2.0. 3 | // Source repository: https://github.com/LanguageDev/Yoakke 4 | 5 | using Xunit; 6 | 7 | namespace Yoakke.SynKit.Text.Tests; 8 | 9 | public class StringMetricsTests 10 | { 11 | [Theory] 12 | [InlineData(3, "kitten", "sitting")] 13 | [InlineData(2, "abcd", "acbd")] 14 | [InlineData(3, "abc", "def")] 15 | [InlineData(4, "abcd", "defg")] 16 | [InlineData(2, "apple", "appel")] 17 | [InlineData(2, "mug", "gum")] 18 | [InlineData(3, "mcdonalds", "mcdnoald")] 19 | [InlineData(5, "table", "desk")] 20 | [InlineData(3, "abcd", "badc")] 21 | [InlineData(2, "book", "back")] 22 | [InlineData(4, "pattern", "parent")] 23 | [InlineData(4, "abcd", "")] 24 | [InlineData(0, "abcd", "abcd")] 25 | [InlineData(4, "abcd", "da")] 26 | public void LevenshteinDistance(int expextedDistance, string s1, string s2) => 27 | Assert.Equal(expextedDistance, Metrics.LevenshteinDistance.Instance.Distance(s1, s2)); 28 | 29 | [Theory] 30 | [InlineData(3, "kitten", "sitting")] 31 | [InlineData(1, "abcd", "acbd")] 32 | [InlineData(3, "abc", "def")] 33 | [InlineData(4, "abcd", "defg")] 34 | [InlineData(1, "apple", "appel")] 35 | [InlineData(2, "mug", "gum")] 36 | [InlineData(2, "mcdonalds", "mcdnoald")] 37 | [InlineData(5, "table", "desk")] 38 | [InlineData(2, "abcd", "badc")] 39 | [InlineData(2, "book", "back")] 40 | [InlineData(4, "abcd", "")] 41 | [InlineData(0, "abcd", "abcd")] 42 | [InlineData(4, "abcd", "da")] 43 | public void OptimalStringAlignmentDistance(int expextedDistance, string s1, string s2) => 44 | Assert.Equal(expextedDistance, Metrics.OptimalStringAlignmentDistance.Instance.Distance(s1, s2)); 45 | } 46 | -------------------------------------------------------------------------------- /Sources/SynKit/Tests/Text.Tests/Text.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Sources/SynKit/Tests/Text.Tests/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/SynKit/Tests/Text.Tests/key.snk -------------------------------------------------------------------------------- /Sources/Tests/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/Tests/.gitignore -------------------------------------------------------------------------------- /Sources/Tools/.gitignore: -------------------------------------------------------------------------------- 1 | launchSettings.json 2 | -------------------------------------------------------------------------------- /Sources/Tools/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Sources/Tools/NugetMaintainer/NugetMaintainer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Sources/Tools/NugetMaintainer/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LanguageDev/Yoakke/ccd4ebf30355e451e4c362d594c741303b78cf5f/Sources/Tools/NugetMaintainer/key.snk --------------------------------------------------------------------------------