Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
f42f790
Implement source generation
sebastienros Dec 5, 2025
4cf01e9
Implement sourcegen for more parsers
sebastienros Dec 5, 2025
6051abe
Add some usage tests
sebastienros Dec 6, 2025
531a221
Update build workflow to include sourcegen
sebastienros Dec 6, 2025
ec38f12
Fix NuGet package generation
sebastienros Dec 6, 2025
9724ecf
Complete Expression parser
sebastienros Dec 6, 2025
427ba7b
Declar variables closer to their usage
sebastienros Dec 6, 2025
8aba763
Improve allocations
sebastienros Dec 7, 2025
d8c4b59
Simplify generated code
sebastienros Dec 7, 2025
a6d3650
Refactor Numbers parsing to share code between Fluent and Generated
sebastienros Dec 7, 2025
7d440ff
Prevent code duplication in SkipWhiteSpace
sebastienros Dec 7, 2025
e1317fe
Grouped Lookup, and WS
sebastienros Dec 7, 2025
0e4a457
Helper methods for OneOf
sebastienros Dec 7, 2025
c78027b
Checkpoint from VS Code for coding agent session
sebastienros Dec 7, 2025
b561996
Add ISourceable and GenerateSource to SequenceAndSkip (all arities)
Copilot Dec 7, 2025
1cb2ec1
Add ISourceable and GenerateSource to Sequence and SequenceSkipAnd (a…
Copilot Dec 7, 2025
0d01f0e
Add ISourceable and GenerateSource to ZeroOrOne and OneOrMany
Copilot Dec 7, 2025
818ad25
Checkpoint from VS Code for coding agent session
sebastienros Dec 7, 2025
2969f8d
Refactor LeftAssociative, Unary, Then, SkipWhiteSpace to use helper r…
Copilot Dec 7, 2025
00acd04
Successfully refactored LeftAssociative, Unary, Then, SkipWhiteSpace …
Copilot Dec 7, 2025
327ac3a
Fix Then parser
sebastienros Dec 8, 2025
4d8b4ee
Implement ISourceable for remaining Fluent parsers (#295)
Copilot Dec 8, 2025
854f41f
Add tests
sebastienros Dec 8, 2025
f667f36
Implement configurable parsers
sebastienros Dec 8, 2025
ea634e2
Cleanup TextLiteral
sebastienros Dec 13, 2025
06c15d0
Fix returns text range
sebastienros Dec 13, 2025
f098efc
Remove special case handling for specific parameter types in scoring …
sebastienros Dec 13, 2025
562fc17
Refactor position initialization in parser classes to use cursor posi…
sebastienros Dec 13, 2025
37bed96
Refactor parser helpers to use out parameters for improved clarity an…
sebastienros Dec 13, 2025
6ad70e6
Refactor parser implementations to utilize helper methods for improve…
sebastienros Dec 13, 2025
88d2eef
Optimize early return handling in parser implementations for improved…
sebastienros Dec 14, 2025
ae3414e
Refactor LeftAssociative and SkipWhiteSpace parsers to use output par…
sebastienros Dec 14, 2025
6ba8b67
Enhance SkipWhiteSpace parser to track content start offset and impro…
sebastienros Dec 14, 2025
7dae5e5
Enhance parser implementations to utilize direct lambda invocation an…
sebastienros Dec 14, 2025
1480206
feat: Add support for discarding parser results in various parser imp…
sebastienros Dec 14, 2025
2002a6c
Add comprehensive tests for source-generated parsers covering various…
sebastienros Dec 14, 2025
ef123cf
Use interceptors
sebastienros Dec 14, 2025
6fb606c
Update readone
sebastienros Dec 14, 2025
4903ba1
Update publish workflow
sebastienros Dec 14, 2025
4f3c6e2
Fix push
sebastienros Dec 14, 2025
d3eb4ad
Fix version extraction
sebastienros Dec 15, 2025
3a963d3
Update ListOfChars/SearchValuesCharLiteral
sebastienros Dec 15, 2025
7109e34
Refactor parsers to utilize LiteralHelper for string escaping and key…
sebastienros Dec 16, 2025
c7a16db
Fix ReadOnlySpan to string conversion on net48
sebastienros Dec 16, 2025
96c903c
Implement number literal parsers and tests for various formats and cu…
sebastienros Dec 16, 2025
1bfe25a
Refactor Then class to eliminate temporary variable usage and streaml…
sebastienros Dec 16, 2025
978fda6
Add IncludeUsings attribute and enhance parser generation with class-…
sebastienros Dec 16, 2025
ba228cf
Improve host compilation
sebastienros Dec 17, 2025
a260367
Use host compilation
sebastienros Dec 17, 2025
42ebc7a
Bypass partial methods that require source generation
sebastienros Dec 17, 2025
8239ca7
Update source generation context to include target framework details
sebastienros Dec 18, 2025
b1054c1
Add IncludeGenerators attribute
sebastienros Dec 18, 2025
98f3800
Refactor parser selection methods to use index-based selection for im…
sebastienros Dec 30, 2025
8806713
Add cancellation token support
sebastienros Dec 31, 2025
dd6abe2
Fix left associative position reset
sebastienros Dec 31, 2025
fc2e77b
Merge remote-tracking branch 'origin/main' into sebros/sourcegen
sebastienros Dec 31, 2025
328e8e3
Add test for generic grammar
sebastienros Dec 31, 2025
4ef653d
Merge branch 'main' into sebros/sourcegen
sebastienros Dec 31, 2025
02c2dbe
Optimize source-generated code
sebastienros Dec 31, 2025
24c44c2
Don't emit source in IDE context
sebastienros Jan 6, 2026
a319d51
Handle compiled parsers as ISourceable
sebastienros Jan 6, 2026
286651f
Document lambdas support
sebastienros Jan 6, 2026
b1cb939
Redirect debugger to source lambdas
sebastienros Jan 6, 2026
03a041f
Emit debug line numbers for each line
sebastienros Jan 6, 2026
fb8fe93
Use DesignTimeBuild property instead of environment variables
sebastienros Jan 7, 2026
baa56c6
Fix ctor versioning
sebastienros Jan 7, 2026
345d900
Merge branch 'main' into sebros/sourcegen
sebastienros Feb 17, 2026
0d79226
Improve IDE detection
sebastienros Feb 24, 2026
db36e1f
Merge branch 'main' into sebros/sourcegen
sebastienros Jul 29, 2026
02e62bc
Avoid Roslyn dependency in generated number parser
sebastienros Jul 29, 2026
9ed4cbe
Escape source-generated character literals
sebastienros Jul 29, 2026
bb25ce8
Port hot parsing optimizations to generated parsers
sebastienros Jul 29, 2026
a1e1580
Update source generation benchmark results
sebastienros Jul 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ csharp_style_prefer_range_operator = false
dotnet_diagnostic.IDE1006.severity = silent
csharp_prefer_system_threading_lock = true:suggestion

# xUnit1051: Calls to methods which accept CancellationToken should use TestContext.Current.CancellationToken
dotnet_diagnostic.xUnit1051.severity = silent

[*.{cs,vb}]
#### Naming styles ####

Expand Down
25 changes: 12 additions & 13 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,31 @@ Parlot is a fast, lightweight and simple to use .NET parser combinator library.
## Target Frameworks and Build Strategy

### Primary Development Framework
- **Use .NET 9.0 (`net9.0`) as the primary target for development, testing, and validation**
- All new features should be developed and tested against `net9.0` first
- Performance optimizations and benchmarks should target `net9.0`
- **Use .NET 10.0 (`net10.0`) as the primary target for development, testing, and validation**
- All new features should be developed and tested against `net10.0` first
- Performance optimizations and benchmarks should target `net10.0`

### Multi-Target Framework Support
The library supports multiple target frameworks:
- `net472` - .NET Framework 4.7.2
- `netstandard2.0` - .NET Standard 2.0
- `net8.0` - .NET 8.0
- `net9.0` - .NET 9.0
- `net10.0` - .NET 10.0 (primary development target)

**Important**: Only build and test other target frameworks once functionality is proven to work correctly on `net9.0`. This approach improves development velocity and performance.
**Important**: Only build and test other target frameworks once functionality is proven to work correctly on `net10.0`. This approach improves development velocity and performance.

## Build and Test Commands

### Preferred Commands (Performance Optimized)
```bash
# Build targeting net9.0 only
dotnet build -f net9.0
# Build targeting net10.0 only
dotnet build -f net10.0

# Run tests targeting net9.0 only
dotnet test -f net9.0
# Run tests targeting net10.0 only
dotnet test -f net10.0

# Run benchmarks (net9.0 only)
dotnet run -p test/Parlot.Benchmarks -f net9.0
# Run benchmarks (net10.0 only)
dotnet run -p test/Parlot.Benchmarks -f net10.0
```

### Full Multi-Target Build (Use Only When Required)
Expand Down Expand Up @@ -76,7 +75,7 @@ dotnet test

### Creating New Parsers
1. Define the grammar using fluent API
2. Write unit tests targeting `net9.0`
2. Write unit tests targeting `net10.0`
3. Add benchmarks if performance is critical
4. Add documentation with examples

Expand Down Expand Up @@ -179,7 +178,7 @@ var optionalParser = Terms.Integer().Optional().Then(x => x.HasValue ? x.Value :
- Separate logical changes into separate commits

### Pull Request Requirements
- Ensure all tests pass on `net9.0`
- Ensure all tests pass on `net10.0`
- Include benchmarks for performance-sensitive changes
- Update documentation for new features
- Validate multi-target compilation before merging
Expand Down
9 changes: 5 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@ jobs:
DOTNET_CLI_TELEMETRY_OPTOUT: 1

steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
- uses: actions/checkout@v6
- uses: actions/setup-dotnet@v5
with:
dotnet-version: |
8.0.x
10.0.x
global-json-file: global.json

- name: Build
run: dotnet build --configuration Release
- name: Test
run: dotnet test --project test/Parlot.Tests/Parlot.Tests.csproj --configuration Release
run: dotnet test --configuration Release --no-build
8 changes: 4 additions & 4 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ jobs:
DOTNET_CLI_TELEMETRY_OPTOUT: 1

steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
- uses: actions/checkout@v6
- uses: actions/setup-dotnet@v5
with:
dotnet-version: |
8.0.x
Expand All @@ -29,9 +29,9 @@ jobs:
run: |
arrTag=(${GITHUB_REF//\// })
VERSION="${arrTag[2]}"
VERSION="${VERSION//v}"
VERSION="${VERSION#v}"
echo "$VERSION"
dotnet pack --output artifacts --configuration Release -p:Version=$VERSION -p:ContinuousIntegrationBuild=True

- name: Push with dotnet
run: dotnet nuget push artifacts/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json
run: dotnet nuget push artifacts/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
6 changes: 6 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"cSpell.words": [
"Parlot",
"Xunit"
]
}
94 changes: 54 additions & 40 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -1,42 +1,56 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/test/Parlot.Tests/Parlot.Tests.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/test/Parlot.Tests/Parlot.Tests.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"${workspaceFolder}/test/Parlot.Tests/Parlot.Tests.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
}
]
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/test/Parlot.Tests/Parlot.Tests.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/test/Parlot.Tests/Parlot.Tests.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"${workspaceFolder}/test/Parlot.Tests/Parlot.Tests.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "test: sourcegen",
"type": "shell",
"command": "dotnet",
"args": [
"test",
"--project",
"test/Parlot.SourceGenerator.Tests/Parlot.SourceGenerator.Tests.csproj",
"--framework",
"net10.0"
],
"isBackground": false,
"problemMatcher": []
}
]
}
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<PackageVersion Include="System.Memory" Version="4.6.3" />
<PackageVersion Include="System.Collections.Immutable" Version="10.0.8" />
<PackageVersion Include="FastExpressionCompiler.Internal.src" Version="5.4.1" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" />
<!-- Benchmarks -->
<PackageVersion Include="BenchmarkDotNet" Version="0.15.8" />
<PackageVersion Include="Pidgin" Version="3.5.1" />
Expand Down
32 changes: 31 additions & 1 deletion Parlot.sln
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{02EA681E-C
docs\writing.md = docs\writing.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Parlot.SourceGenerator", "src\Parlot.SourceGenerator\Parlot.SourceGenerator.csproj", "{22D5C924-AA73-4505-AC6F-47CFCBF01773}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Parlot.SourceGenerator.Tests", "test\Parlot.SourceGenerator.Tests\Parlot.SourceGenerator.Tests.csproj", "{76531D93-84F7-47BE-8C08-E0983913F35B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -90,6 +94,30 @@ Global
{B9A796FE-4BEB-499A-B506-25F20C749527}.Release|x64.Build.0 = Release|Any CPU
{B9A796FE-4BEB-499A-B506-25F20C749527}.Release|x86.ActiveCfg = Release|Any CPU
{B9A796FE-4BEB-499A-B506-25F20C749527}.Release|x86.Build.0 = Release|Any CPU
{22D5C924-AA73-4505-AC6F-47CFCBF01773}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{76531D93-84F7-47BE-8C08-E0983913F35B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{22D5C924-AA73-4505-AC6F-47CFCBF01773}.Debug|Any CPU.Build.0 = Debug|Any CPU
{76531D93-84F7-47BE-8C08-E0983913F35B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{22D5C924-AA73-4505-AC6F-47CFCBF01773}.Debug|x64.ActiveCfg = Debug|Any CPU
{76531D93-84F7-47BE-8C08-E0983913F35B}.Debug|x64.ActiveCfg = Debug|Any CPU
{22D5C924-AA73-4505-AC6F-47CFCBF01773}.Debug|x64.Build.0 = Debug|Any CPU
{76531D93-84F7-47BE-8C08-E0983913F35B}.Debug|x64.Build.0 = Debug|Any CPU
{22D5C924-AA73-4505-AC6F-47CFCBF01773}.Debug|x86.ActiveCfg = Debug|Any CPU
{76531D93-84F7-47BE-8C08-E0983913F35B}.Debug|x86.ActiveCfg = Debug|Any CPU
{22D5C924-AA73-4505-AC6F-47CFCBF01773}.Debug|x86.Build.0 = Debug|Any CPU
{76531D93-84F7-47BE-8C08-E0983913F35B}.Debug|x86.Build.0 = Debug|Any CPU
{22D5C924-AA73-4505-AC6F-47CFCBF01773}.Release|Any CPU.ActiveCfg = Release|Any CPU
{76531D93-84F7-47BE-8C08-E0983913F35B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{22D5C924-AA73-4505-AC6F-47CFCBF01773}.Release|Any CPU.Build.0 = Release|Any CPU
{76531D93-84F7-47BE-8C08-E0983913F35B}.Release|Any CPU.Build.0 = Release|Any CPU
{22D5C924-AA73-4505-AC6F-47CFCBF01773}.Release|x64.ActiveCfg = Release|Any CPU
{76531D93-84F7-47BE-8C08-E0983913F35B}.Release|x64.ActiveCfg = Release|Any CPU
{22D5C924-AA73-4505-AC6F-47CFCBF01773}.Release|x64.Build.0 = Release|Any CPU
{76531D93-84F7-47BE-8C08-E0983913F35B}.Release|x64.Build.0 = Release|Any CPU
{22D5C924-AA73-4505-AC6F-47CFCBF01773}.Release|x86.ActiveCfg = Release|Any CPU
{76531D93-84F7-47BE-8C08-E0983913F35B}.Release|x86.ActiveCfg = Release|Any CPU
{22D5C924-AA73-4505-AC6F-47CFCBF01773}.Release|x86.Build.0 = Release|Any CPU
{76531D93-84F7-47BE-8C08-E0983913F35B}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -99,8 +127,10 @@ Global
{9452A111-5A01-4D3C-AA9F-F3AE4F1255C2} = {5E61AAE8-0C62-47A5-B218-A3235253710E}
{3DF3E827-7AEE-4130-9925-D6DB26C420CC} = {5E61AAE8-0C62-47A5-B218-A3235253710E}
{B9A796FE-4BEB-499A-B506-25F20C749527} = {0D1E6480-3C81-4951-8F44-BF74398BA8D4}
{22D5C924-AA73-4505-AC6F-47CFCBF01773} = {0D1E6480-3C81-4951-8F44-BF74398BA8D4}
{76531D93-84F7-47BE-8C08-E0983913F35B} = {5E61AAE8-0C62-47A5-B218-A3235253710E}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E81DADB4-B5AD-452A-A308-813B0618F303}
EndGlobalSection
EndGlobal
EndGlobal
100 changes: 78 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,64 @@ static FluentParser()

- [Existing parsers and usage examples](docs/parsers.md)
- [Best practices for custom parsers](docs/writing.md)
- [Source generation guide](docs/source-generation.md)

## Source-generated parsers

Parlot can generate parsers at **compile time** using C# interceptors, avoiding runtime graph construction and yielding **~20% faster parsing** with **faster startup**.

### How it works

- Annotate static, **parameterless** methods returning `Parlot.Fluent.Parser<T>` with `[GenerateParser]`.
- The source generator executes the method at compile time to build the parser graph.
- Uses C# interceptors to replace calls to the method with the generated, optimized code.
- For parser variants (e.g., different keywords), create separate methods instead of using parameters.

```csharp
using Parlot.SourceGenerator;
using Parlot.Fluent;
using static Parlot.Fluent.Parsers;

public static partial class MyGrammar
{
// Simple parser
[GenerateParser]
public static Parser<string> HelloParser() => Terms.Text("hello");

// For variants, create separate methods
[GenerateParser]
public static Parser<string> FooParser() => Terms.Text("foo");

[GenerateParser]
public static Parser<string> BarParser() => Terms.Text("bar");
}

// Usage - calls are automatically intercepted
var hello = MyGrammar.HelloParser(); // Uses generated code
var foo = MyGrammar.FooParser(); // Uses generated code
```

### Requirements

- Add `<InterceptorsNamespaces>$(InterceptorsNamespaces);YourNamespace</InterceptorsNamespaces>` to your project file.
- Methods must be static and parameterless.
- The containing class should be `partial` (optional but recommended).

### Advanced Configuration

Additional attributes can be combined with `[GenerateParser]`:

- `[IncludeFiles("*.cs")]` – Include source files (supports globs) for types used by your parser.
- `[IncludeUsings("Namespace")]` – Add extra using directives to generated code.
- `[IncludeGenerators("AssemblyName")]` – Run other source generators before parser generation.

For detailed documentation, see [Source Generation Guide](docs/source-generation.md).

> **Why use source generation?**
> - ~20% faster parsing vs. runtime-compiled graphs (see benchmarks)
> - Faster startup (no runtime graph building/compilation)
> - AOT-friendly, deterministic parser code
> - Zero runtime overhead from method interception

## Compilation

Expand Down Expand Up @@ -122,30 +180,28 @@ This benchmark creates an expression tree (AST) representing mathematical expres

Only Pidgin and Parlot are benchmarked here. These benchmarks don't evaluate the expressions but only parse them to create the same AST.

In this benchmark, Parlot Fluent is more than 10 times faster than Pidgin, and Parlot Raw gives another 2 times boost. Allocations are also smaller with Parlot.
When compiled, the Parlot grammar shows even better results, without losing its simplicity.
In this benchmark, Parlot Fluent is more than 14 times faster than Pidgin, and Parlot Raw gives another 2 times boost. Allocations are also smaller with Parlot.
The source-generated grammar is 14% faster for the small expression and 20% faster for the big expression than the runtime-compiled grammar, while allocating the same amount or less.

```
BenchmarkDotNet v0.15.0, Windows 11 (10.0.26100.4770/24H2/2024Update/HudsonValley)
12th Gen Intel Core i7-1260P 2.10GHz, 1 CPU, 16 logical and 12 physical cores
.NET SDK 10.0.100-preview.6.25358.103
[Host] : .NET 9.0.7 (9.0.725.31616), X64 RyuJIT AVX2
ShortRun : .NET 9.0.7 (9.0.725.31616), X64 RyuJIT AVX2

Job=ShortRun IterationCount=3 LaunchCount=1
WarmupCount=3

| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio |
|-------------------- |------------:|------------:|----------:|------:|--------:|-------:|----------:|------------:|
| ParlotRawSmall | 234.0 ns | 133.27 ns | 7.31 ns | 0.49 | 0.01 | 0.0322 | 304 B | 0.43 |
| ParlotCompiledSmall | 481.6 ns | 89.48 ns | 4.90 ns | 1.00 | 0.01 | 0.0753 | 712 B | 1.00 |
| ParlotFluentSmall | 486.7 ns | 219.33 ns | 12.02 ns | 1.01 | 0.02 | 0.0753 | 712 B | 1.00 |
| PidginSmall | 5,301.9 ns | 1,864.01 ns | 102.17 ns | 11.01 | 0.21 | 0.0839 | 832 B | 1.17 |
| | | | | | | | | |
| ParlotRawBig | 1,074.4 ns | 115.56 ns | 6.33 ns | 0.45 | 0.01 | 0.1259 | 1200 B | 0.39 |
| ParlotCompiledBig | 2,403.9 ns | 777.57 ns | 42.62 ns | 1.00 | 0.02 | 0.3281 | 3104 B | 1.00 |
| ParlotFluentBig | 2,443.7 ns | 204.37 ns | 11.20 ns | 1.02 | 0.02 | 0.3281 | 3104 B | 1.00 |
| PidginBig | 26,210.1 ns | 3,920.26 ns | 214.88 ns | 10.91 | 0.19 | 0.4272 | 4152 B | 1.34 |
BenchmarkDotNet v0.15.8, macOS Sequoia 15.7.8 (24G824) [Darwin 24.6.0]
Apple M4 Pro, 1 CPU, 14 logical and 14 physical cores
.NET SDK 10.0.301
[Host] : .NET 10.0.9 (10.0.9, 10.0.926.27113), Arm64 RyuJIT armv8.0-a

| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio |
|--------------------- |------------:|---------:|---------:|------:|--------:|-------:|----------:|------------:|
| ParlotRawSmall | 130.2 ns | 1.42 ns | 1.33 ns | 0.61 | 0.01 | 0.0362 | 304 B | 0.73 |
| ParlotCompiledSmall | 212.6 ns | 0.63 ns | 0.56 ns | 1.00 | 0.00 | 0.0496 | 416 B | 1.00 |
| ParlotFluentSmall | 219.6 ns | 0.54 ns | 0.50 ns | 1.03 | 0.00 | 0.0668 | 560 B | 1.35 |
| ParlotGeneratedSmall | 182.5 ns | 1.32 ns | 1.17 ns | 0.86 | 0.01 | 0.0496 | 416 B | 1.00 |
| PidginSmall | 3,473.7 ns | 49.78 ns | 46.57 ns | 16.34 | 0.22 | 0.0992 | 832 B | 2.00 |
| | | | | | | | | |
| ParlotRawBig | 665.1 ns | 3.19 ns | 2.83 ns | 0.54 | 0.00 | 0.1431 | 1200 B | 0.82 |
| ParlotCompiledBig | 1,242.3 ns | 3.17 ns | 2.65 ns | 1.00 | 0.00 | 0.1736 | 1456 B | 1.00 |
| ParlotFluentBig | 1,215.8 ns | 6.70 ns | 5.94 ns | 0.98 | 0.01 | 0.1736 | 1456 B | 1.00 |
| ParlotGeneratedBig | 997.3 ns | 2.77 ns | 2.46 ns | 0.80 | 0.00 | 0.1564 | 1312 B | 0.90 |
| PidginBig | 17,498.6 ns | 89.52 ns | 83.74 ns | 14.09 | 0.07 | 0.4883 | 4152 B | 2.85 |
```

### JSON Benchmarks
Expand Down
Loading