diff --git a/.editorconfig b/.editorconfig
index 1a2db97..6236ee8 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,74 +1,74 @@
-root = true
-
-[*]
-charset = utf-8
-indent_size = 4
-indent_style = space
-insert_final_newline = true
-trim_trailing_whitespace = true
-
-[*.{yml,props,targets,csproj}]
-indent_size = 2
-
-# IDE0079: Remove unnecessary suppression
-dotnet_remove_unnecessary_suppression_exclusions = category:ReSharper
-
-# IDE0079: Remove unnecessary suppression
-# dotnet_diagnostic.IDE0079.severity = none
-
-# CA2255: The 'ModuleInitializer' attribute should not be used in libraries
-dotnet_diagnostic.CA2255.severity = none
-
-# CS8600: Converting null literal or possible null value to non-nullable type.
-dotnet_diagnostic.CS8600.severity = error
-
-# CS8601: Possible null reference assignment.
-dotnet_diagnostic.CS8601.severity = error
-
-# CS8602: Dereference of a possibly null reference.
-dotnet_diagnostic.CS8602.severity = error
-
-# CS8603: Possible null reference return.
-dotnet_diagnostic.CS8603.severity = error
-
-# CS8604: Possible null reference argument.
-dotnet_diagnostic.CS8604.severity = error
-
-# CS8610: Nullability of reference types in type of parameter doesn't match overridden member.
-dotnet_diagnostic.CS8610.severity = error
-
-# CS8613: Nullability of reference types in return type doesn't match implicitly implemented member.
-dotnet_diagnostic.CS8613.severity = error
-
-# CS8614: Nullability of reference types in type of parameter doesn't match implicitly implemented member.
-dotnet_diagnostic.CS8614.severity = error
-
-# CS8618: Non-nullable field is uninitialized. Consider declaring as nullable.
-dotnet_diagnostic.CS8618.severity = error
-
-# CS8619: Nullability of reference types in value doesn't match target type.
-dotnet_diagnostic.CS8619.severity = error
-
-# CS8620: Argument cannot be used for parameter due to differences in the nullability of reference types.
-dotnet_diagnostic.CS8620.severity = error
-
-# CS8625: Cannot convert null literal to non-nullable reference type.
-dotnet_diagnostic.CS8625.severity = error
-
-# CS8634: The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'class' constraint.
-dotnet_diagnostic.CS8634.severity = error
-
-# CS8643: Nullability of reference types in explicit interface specifier doesn't match interface implemented by the type.
-dotnet_diagnostic.CS8643.severity = error
-
-# CS8653: A default expression introduces a null value for a type parameter.
-dotnet_diagnostic.CS8653.severity = error
-
-# CS8714: The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'notnull' constraint.
-dotnet_diagnostic.CS8714.severity = error
-
-# IDE0059: Unnecessary assigment of a value
-dotnet_diagnostic.IDE0059.severity = none
-
-# IDE0060: Remove unused parameter
-dotnet_diagnostic.IDE0060.severity = none
+root = true
+
+[*]
+charset = utf-8
+indent_size = 4
+indent_style = space
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.{yml,props,targets,csproj}]
+indent_size = 2
+
+# IDE0079: Remove unnecessary suppression
+dotnet_remove_unnecessary_suppression_exclusions = category:ReSharper
+
+# IDE0079: Remove unnecessary suppression
+# dotnet_diagnostic.IDE0079.severity = none
+
+# CA2255: The 'ModuleInitializer' attribute should not be used in libraries
+dotnet_diagnostic.CA2255.severity = none
+
+# CS8600: Converting null literal or possible null value to non-nullable type.
+dotnet_diagnostic.CS8600.severity = error
+
+# CS8601: Possible null reference assignment.
+dotnet_diagnostic.CS8601.severity = error
+
+# CS8602: Dereference of a possibly null reference.
+dotnet_diagnostic.CS8602.severity = error
+
+# CS8603: Possible null reference return.
+dotnet_diagnostic.CS8603.severity = error
+
+# CS8604: Possible null reference argument.
+dotnet_diagnostic.CS8604.severity = error
+
+# CS8610: Nullability of reference types in type of parameter doesn't match overridden member.
+dotnet_diagnostic.CS8610.severity = error
+
+# CS8613: Nullability of reference types in return type doesn't match implicitly implemented member.
+dotnet_diagnostic.CS8613.severity = error
+
+# CS8614: Nullability of reference types in type of parameter doesn't match implicitly implemented member.
+dotnet_diagnostic.CS8614.severity = error
+
+# CS8618: Non-nullable field is uninitialized. Consider declaring as nullable.
+dotnet_diagnostic.CS8618.severity = error
+
+# CS8619: Nullability of reference types in value doesn't match target type.
+dotnet_diagnostic.CS8619.severity = error
+
+# CS8620: Argument cannot be used for parameter due to differences in the nullability of reference types.
+dotnet_diagnostic.CS8620.severity = error
+
+# CS8625: Cannot convert null literal to non-nullable reference type.
+dotnet_diagnostic.CS8625.severity = error
+
+# CS8634: The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'class' constraint.
+dotnet_diagnostic.CS8634.severity = error
+
+# CS8643: Nullability of reference types in explicit interface specifier doesn't match interface implemented by the type.
+dotnet_diagnostic.CS8643.severity = error
+
+# CS8653: A default expression introduces a null value for a type parameter.
+dotnet_diagnostic.CS8653.severity = error
+
+# CS8714: The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'notnull' constraint.
+dotnet_diagnostic.CS8714.severity = error
+
+# IDE0059: Unnecessary assigment of a value
+dotnet_diagnostic.IDE0059.severity = none
+
+# IDE0060: Remove unused parameter
+dotnet_diagnostic.IDE0060.severity = none
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..176a458
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+* text=auto
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 88a7708..d0da5db 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -1,40 +1,40 @@
-name: Publish
-
-on:
- push:
- tags:
- - "[0-9]+.[0-9]+.[0-9]+"
- - "[0-9]+.[0-9]+.[0-9]+-[a-z]+.[0-9]+"
-
-permissions:
- contents: write
-
-jobs:
- publish:
- if: github.repository == 'rameel/ramstack.parsing'
- name: Publish packages
- runs-on: ubuntu-latest
-
- steps:
- - name: Install .NET
- uses: actions/setup-dotnet@v4
- with:
- dotnet-version: 9.0.x
-
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Build Solution
- run: dotnet build -c Release -p:SkipInternalsVisibleTo=true
-
- - name: Create NuGet Packages
- run: dotnet pack -c Release -o ./nuget --no-build
-
- - name: Publish NuGet Packages
- run: dotnet nuget push ./nuget/*.nupkg --api-key ${{secrets.NUGET_API_KEY}} --skip-duplicate -s https://api.nuget.org/v3/index.json
-
- - name: Create GitHub Release
- uses: softprops/action-gh-release@v2
- with:
- draft: true
- files: nuget/*
+name: Publish
+
+on:
+ push:
+ tags:
+ - "[0-9]+.[0-9]+.[0-9]+"
+ - "[0-9]+.[0-9]+.[0-9]+-[a-z]+.[0-9]+"
+
+permissions:
+ contents: write
+
+jobs:
+ publish:
+ if: github.repository == 'rameel/ramstack.parsing'
+ name: Publish packages
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Install .NET
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 9.0.x
+
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Build Solution
+ run: dotnet build -c Release -p:SkipInternalsVisibleTo=true
+
+ - name: Create NuGet Packages
+ run: dotnet pack -c Release -o ./nuget --no-build
+
+ - name: Publish NuGet Packages
+ run: dotnet nuget push ./nuget/*.nupkg --api-key ${{secrets.NUGET_API_KEY}} --skip-duplicate -s https://api.nuget.org/v3/index.json
+
+ - name: Create GitHub Release
+ uses: softprops/action-gh-release@v2
+ with:
+ draft: true
+ files: nuget/*
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index e86448d..c9294e4 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -1,58 +1,58 @@
-name: Build & Test
-
-on:
- pull_request:
- branches: [main]
-
-jobs:
- build-and-test:
- name: build-and-test-${{ matrix.os }}
- runs-on: ${{ matrix.os }}
- strategy:
- matrix:
- os: [ubuntu-latest, ubuntu-24.04-arm]
-
- steps:
- - name: Install .NET
- uses: actions/setup-dotnet@v4
- with:
- dotnet-version: |
- 6.x
- 7.x
- 8.x
- 9.x
-
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Build (Debug)
- run: dotnet build -c Debug
-
- - name: Build (Release)
- run: dotnet build -c Release
-
- - name: Test (Debug)
- run: dotnet test -c Debug --no-build
-
- - name: Test (Release)
- run: dotnet test -c Release --no-build
-
- - name: Test (Debug, AVX2=0)
- env:
- DOTNET_EnableAVX2: "0"
- run: dotnet test -c Debug --no-build
-
- - name: Test (Release, AVX2=0)
- env:
- DOTNET_EnableAVX2: "0"
- run: dotnet test -c Release --no-build
-
- - name: Test (Debug, HWIntrinsic=0)
- env:
- DOTNET_EnableHWIntrinsic: "0"
- run: dotnet test -c Debug --no-build
-
- - name: Test (Release, HWIntrinsic=0)
- env:
- DOTNET_EnableHWIntrinsic: "0"
- run: dotnet test -c Release --no-build
+name: Build & Test
+
+on:
+ pull_request:
+ branches: [main]
+
+jobs:
+ build-and-test:
+ name: build-and-test-${{ matrix.os }}
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ os: [ubuntu-latest, ubuntu-24.04-arm]
+
+ steps:
+ - name: Install .NET
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: |
+ 6.x
+ 7.x
+ 8.x
+ 9.x
+
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Build (Debug)
+ run: dotnet build -c Debug
+
+ - name: Build (Release)
+ run: dotnet build -c Release
+
+ - name: Test (Debug)
+ run: dotnet test -c Debug --no-build
+
+ - name: Test (Release)
+ run: dotnet test -c Release --no-build
+
+ - name: Test (Debug, AVX2=0)
+ env:
+ DOTNET_EnableAVX2: "0"
+ run: dotnet test -c Debug --no-build
+
+ - name: Test (Release, AVX2=0)
+ env:
+ DOTNET_EnableAVX2: "0"
+ run: dotnet test -c Release --no-build
+
+ - name: Test (Debug, HWIntrinsic=0)
+ env:
+ DOTNET_EnableHWIntrinsic: "0"
+ run: dotnet test -c Debug --no-build
+
+ - name: Test (Release, HWIntrinsic=0)
+ env:
+ DOTNET_EnableHWIntrinsic: "0"
+ run: dotnet test -c Release --no-build
diff --git a/.gitignore b/.gitignore
index 4f81b1b..bd6adb1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,37 +1,37 @@
-#Ignore thumbnails created by windows
-[Tt]humbs.db
-
-#Ignore files build by Visual Studio
-*.obj
-*.exe
-*.pdb
-*.user
-*.patch
-*.aps
-*.pch
-*.vspscc
-*_i.c
-*_p.c
-*.ncb
-*.suo
-*.tlb
-*.tlh
-*.bak
-*.cache
-*.ilk
-*.log
-*.lib
-*.sbr
-*.cs.ide
-[Dd]ebug*/
-[Rr]elease*/
-bin/
-obj/
-.vs/
-.vscode/
-*.ReSharper
-*.ReSharper.user
-[Tt]est[Rr]esult*
-
-#Ignore Rider/Idea files
-.idea/
+#Ignore thumbnails created by windows
+[Tt]humbs.db
+
+#Ignore files build by Visual Studio
+*.obj
+*.exe
+*.pdb
+*.user
+*.patch
+*.aps
+*.pch
+*.vspscc
+*_i.c
+*_p.c
+*.ncb
+*.suo
+*.tlb
+*.tlh
+*.bak
+*.cache
+*.ilk
+*.log
+*.lib
+*.sbr
+*.cs.ide
+[Dd]ebug*/
+[Rr]elease*/
+bin/
+obj/
+.vs/
+.vscode/
+*.ReSharper
+*.ReSharper.user
+[Tt]est[Rr]esult*
+
+#Ignore Rider/Idea files
+.idea/
diff --git a/Directory.Build.props b/Directory.Build.props
index bf61882..ed14ea7 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,5 +1,5 @@
-
-
- true
-
-
+
+
+ true
+
+
diff --git a/Directory.Packages.props b/Directory.Packages.props
index b706e27..c8fe71c 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -1,17 +1,17 @@
-
-
-
- true
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
index 6666765..92e3431 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,9 +1,9 @@
-MIT License
-
-Copyright 2024 Rameel (https://github.com/rameel)
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+MIT License
+
+Copyright 2024 Rameel (https://github.com/rameel)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
index 6e4e25f..5413317 100644
--- a/README.md
+++ b/README.md
@@ -1,261 +1,261 @@
-# Ramstack.Parsing
-[](https://nuget.org/packages/Ramstack.Parsing)
-[](https://github.com/rameel/ramstack.parsing/blob/main/LICENSE)
-
-A fast, lightweight parser combinator library for .NET.
-
-## Getting Started
-
-To add the `Ramstack.Parsing` [NuGet package](https://www.nuget.org/packages/Ramstack.Parsing) to your project, run:
-```shell
-dotnet add package Ramstack.Parsing
-```
-
-## Usage
-
-Here's how to define a simple expression parser that parses and evaluates mathematical expressions in one step:
-
-```csharp
-public static Parser Calc { get; } = CreateParser();
-
-private static Parser CreateParser()
-{
- // Grammar:
- // ----------------------------------------
- // Start : S Sum $
- // Sum : Product ([+-] S Product)*
- // Product : Unary ([*/] S Unary)*
- // Unary : '-'? S Primary
- // Primary : Parenthesis / Value
- // Parenthesis : '(' S Sum ')' S
- // Value : Number S
- // S : [ \r\n\t]*
-
- var sum = Deferred();
- var value = Literal.Number().ThenIgnore(S);
-
- var parenthesis = sum.Between(
- Seq(L('('), S),
- Seq(L(')'), S)
- );
-
- var primary = parenthesis.Or(value);
-
- var unary = Seq(
- L('-').Optional(),
- S,
- primary
- ).Do((u, _, d) => u.HasValue ? -d : d);
-
- var product = unary.Fold(
- OneOf("*/").ThenIgnore(S),
- (l, r, op) => op == '*' ? l * r : l / r);
-
- sum.Parser = product.Fold(
- OneOf("+-").ThenIgnore(S),
- (l, r, op) => op == '+' ? l + r : l - r);
-
- return sum.Between(S, Eof);
-}
-```
-
-Use the parser as follows:
-
-```csharp
-var result = Calc.Parse(expression);
-if (result.Success)
-{
- var value = result.Value;
- ...
-}
-else
-{
- Console.WriteLine(result.ErrorMessage);
-
- //
- // result.ToString() returns the parsed value as a string,
- // or an error message if parsing fails.
- //
- // Console.WriteLine(result);
- //
-}
-```
-
-The parser provides detailed error messages when the input does not conform to the specified grammar.
-For example, when parsing the expression `"1 + ("`, the parser expects `'-'`, `'('`, or a `number` after the opening parenthesis.
-The error message clearly indicates this:
-
-```
-(1:6) Expected '-', '(' or number
-```
-
-In addition to the main `Parse` method, there is also a lightweight `bool TryParse(ReadOnlySpan source, out T value)` method.
-This method suppresses diagnostic messages, returning only the parsing success status and the parsed value if successful.
-
-If detailed error messages are not required, using `TryParse` is the preferred choice, as it reduces memory allocations
-and slightly improves performance by avoiding the overhead associated with collecting diagnostic data.
-
-## Documentation
-
-- Documentation can be found in [docs/documentation.md](docs/documentation.md) (Work in Progress).
-- Additional usage samples, see the [samples/Samples](samples) directory.
-
-## Performance
-
-`Ramstack.Parsing` stands out as an exceptionally fast and efficient parsing library, outperforming many alternatives in both speed and memory usage.
-
-### Benchmarks: Regex
-
-Here's a comparison between a regex-based email matcher and an equivalent parser combinator implementation:
-
-**Regular Expression:**
-```csharp
-[GeneratedRegex(@"^[\w.+-]+@[\w-]+\.\w{2,}$")]
-private static partial Regex EmailRegexGenerated();
-```
-
-**Parser**:
-```csharp
-var parser = Seq(
- Choice(LetterOrDigit, OneOf("_-+.")).OneOrMore(),
- L('@'),
- Choice(LetterOrDigit, L('-')).OneOrMore(),
- L('.'),
- LetterOrDigit.AtLeast(2)
-).Text();
-```
-The library supports nearly full character class definitions from regular expressions, allowing grammars to be written in a similar way
-as it written for regular expression. Optimizations ensure that both definitions are internally normalized to an equivalent representation:
-```csharp
-var parser = Seq(
- Set("\\w+.-").OneOrMore(),
- L('@'),
- Set("\\w-").OneOrMore(),
- L('.'),
- Set("\\w").AtLeast(2)
-).Text();
-```
-
-The benchmark results show that `Ramstack.Parsing` outperforms even highly optimized Regex implementations,
-including compiled and source-generated regexes.
-
-```
-BenchmarkDotNet v0.14.0, Windows 11 (10.0.26100.3037)
-AMD Ryzen 9 5900X, 1 CPU, 24 logical and 12 physical cores
-.NET SDK 9.0.200-preview.0.25057.12
- [Host] : .NET 9.0.1 (9.0.124.61010), X64 RyuJIT AVX2
- DefaultJob : .NET 9.0.1 (9.0.124.61010), X64 RyuJIT AVX2
-
-
-| Method | Mean | Error | StdDev | Op/s | Gen0 | Allocated |
-|---------------- |------------:|---------:|---------:|-------------:|-------:|----------:|
-| Ramstack | 34.47 ns | 0.073 ns | 0.065 ns | 29,008,779.8 | - | - |
-| Regex | 107.35 ns | 0.125 ns | 0.117 ns | 9,315,658.6 | - | - |
-| Regex:Compiled | 44.63 ns | 0.093 ns | 0.083 ns | 22,408,327.6 | - | - |
-| Regex:Generated | 41.85 ns | 0.282 ns | 0.250 ns | 23,893,269.4 | - | - |
-| Parlot | 295.05 ns | 0.601 ns | 0.533 ns | 3,389,302.6 | 0.0229 | 384 B |
-| Parlot:Compiled | 228.98 ns | 0.446 ns | 0.417 ns | 4,367,155.0 | 0.0091 | 152 B |
-| Pidgin | 1,602.00 ns | 9.016 ns | 8.434 ns | 624,219.5 | 0.0572 | 976 B |
-```
-
-In this specific scenario, the library simply checks for a match against the email pattern, similar to what `Regex.IsMatch` does,
-without extracting the match result itself. Like with regular expressions, this approach avoids unnecessary memory allocations.
-
-### Benchmarks: Expressions
-
-This benchmarks tests 2 expressions:
-- **Small**: `2.5 * 4.7 - 8.1 / 3`
-- **Large**: `((3.14159 * 2.3 * 4) / (1.5 - 0.3) + (2.71828 * 2.5)) * ((8.1 * 3.2 + 4.7) / 2.1 - ((15.7 + 2.3 * 4) / (1.5 - 0.3))) - (((3.5 * 1.41421) * (2.71828 + 3.14159)) / 2)`
-
-```
-BenchmarkDotNet v0.14.0, Windows 11 (10.0.26100.3037)
-AMD Ryzen 9 5900X, 1 CPU, 24 logical and 12 physical cores
-.NET SDK 9.0.200-preview.0.25057.12
- [Host] : .NET 9.0.1 (9.0.124.61010), X64 RyuJIT AVX2
- DefaultJob : .NET 9.0.1 (9.0.124.61010), X64 RyuJIT AVX2
-
-
-| Method | Mean | Error | StdDev | Op/s | Gen0 | Allocated |
-|---------------------- |------------:|----------:|----------:|------------:|-------:|----------:|
-| Ramstack:Large | 1,600.2 ns | 9.54 ns | 7.96 ns | 624,925.9 | - | - |
-| Ramstack:Diag:Large | 1,699.6 ns | 3.53 ns | 3.13 ns | 588,379.8 | 0.0057 | 104 B |
-| Parlot:Large | 3,520.1 ns | 11.08 ns | 10.37 ns | 284,081.7 | 0.1984 | 3344 B |
-| Parlot:Compiled:Large | 3,356.7 ns | 7.08 ns | 6.27 ns | 297,910.3 | 0.1984 | 3344 B |
-| Pidgin:Large | 39,197.3 ns | 150.13 ns | 140.43 ns | 25,511.9 | 0.2441 | 4464 B |
-| | | | | | | |
-| Ramstack:Small | 209.5 ns | 0.28 ns | 0.25 ns | 4,772,894.8 | - | - |
-| Ramstack:Diag:Small | 260.6 ns | 0.57 ns | 0.50 ns | 3,838,032.3 | 0.0062 | 104 B |
-| Parlot:Small | 410.7 ns | 1.46 ns | 1.36 ns | 2,434,653.7 | 0.0391 | 656 B |
-| Parlot:Compiled:Small | 385.1 ns | 1.22 ns | 0.95 ns | 2,596,891.9 | 0.0391 | 656 B |
-| Pidgin:Small | 4,322.2 ns | 18.28 ns | 17.10 ns | 231,363.9 | 0.0381 | 736 B |
-```
-
-- `Ramstack` diagnostic messages disabled.
-- `Ramstack:Diag` includes diagnostic messages.
-
-Even with diagnostics enabled, `Ramstack.Parsing` outperforms other popular libraries.
-
-### Benchmarks: JSON
-
-This benchmark evaluates JSON parsing performance, including object model construction, across different file sizes.
-
-- **Small**: 1.16KB
-- **Medium**: 11KB
-- **Large**: `twitter.json` (617KB) from [serde-rs/json-benchmark](https://github.com/serde-rs/json-benchmark)
-
-```
-BenchmarkDotNet v0.14.0, Windows 11 (10.0.26100.3037)
-AMD Ryzen 9 5900X, 1 CPU, 24 logical and 12 physical cores
-.NET SDK 9.0.200-preview.0.25057.12
- [Host] : .NET 9.0.1 (9.0.124.61010), X64 RyuJIT AVX2
- DefaultJob : .NET 9.0.1 (9.0.124.61010), X64 RyuJIT AVX2
-
-
-| Method | Input | Mean | Error | StdDev | Op/s | Gen0 | Gen1 | Gen2 | Allocated |
-|----------------- |------- |--------------:|-----------:|-----------:|-----------:|---------:|---------:|---------:|-----------:|
-| Ramstack | big | 1,307.929 us | 12.6067 us | 11.7923 us | 764.57 | 152.3438 | 130.8594 | - | 2498.88 KB |
-| Parlot | big | 3,102.953 us | 9.3441 us | 8.7405 us | 322.27 | 156.2500 | 132.8125 | - | 2554.06 KB |
-| Parlot:Compiled | big | 3,078.931 us | 7.4028 us | 5.7796 us | 324.79 | 156.2500 | 132.8125 | - | 2554.06 KB |
-| Pidgin | big | 16,675.788 us | 40.7050 us | 36.0839 us | 59.97 | 156.2500 | 93.7500 | - | 2570.33 KB |
-| Newtonsoft.Json | big | 3,878.753 us | 18.3372 us | 16.2554 us | 257.81 | 343.7500 | 320.3125 | - | 5638.63 KB |
-| System.Text.Json | big | 1,492.658 us | 10.2347 us | 9.0728 us | 669.95 | 216.7969 | 216.7969 | 216.7969 | 963.67 KB |
-
-| Ramstack | medium | 20.163 us | 0.0968 us | 0.0906 us | 49,595.14 | 2.6245 | 0.2747 | - | 42.94 KB |
-| Parlot | medium | 72.128 us | 0.1193 us | 0.1058 us | 13,864.18 | 2.5635 | 0.2441 | - | 43.09 KB |
-| Parlot:Compiled | medium | 70.931 us | 0.2758 us | 0.2445 us | 14,098.14 | 2.5635 | 0.2441 | - | 43.09 KB |
-| Pidgin | medium | 266.283 us | 0.4172 us | 0.3698 us | 3,755.41 | 2.4414 | - | - | 44.45 KB |
-| Newtonsoft.Json | medium | 52.036 us | 0.4550 us | 0.4257 us | 19,217.47 | 6.0425 | 1.6479 | - | 99.44 KB |
-| System.Text.Json | medium | 24.471 us | 0.0968 us | 0.0756 us | 40,865.15 | 1.0376 | - | - | 17.03 KB |
-
-| Ramstack | small | 3.016 us | 0.0064 us | 0.0053 us | 331,565.28 | 0.3815 | 0.0038 | - | 6.24 KB |
-| Parlot | small | 6.723 us | 0.0313 us | 0.0292 us | 148,732.16 | 0.3891 | - | - | 6.39 KB |
-| Parlot:Compiled | small | 6.661 us | 0.0210 us | 0.0175 us | 150,120.62 | 0.3891 | - | - | 6.39 KB |
-| Pidgin | small | 33.369 us | 0.3909 us | 0.3656 us | 29,968.03 | 0.3662 | - | - | 6.49 KB |
-| Newtonsoft.Json | small | 7.940 us | 0.0226 us | 0.0201 us | 125,951.32 | 1.0529 | 0.0458 | - | 17.26 KB |
-| System.Text.Json | small | 3.477 us | 0.0133 us | 0.0111 us | 287,598.87 | 0.1373 | - | - | 2.25 KB |
-```
-
-`Ramstack.Parsing` demonstrated superior performance, outperforming other parser libraries by at least 2-3 times,
-and even exceeded specialized JSON parsers such as `Newtonsoft.Json` and `System.Text.Json` in terms of both speed and memory efficiency.
-
-### Benchmarked Libraries
-
-1. [x] Parlot 1.3.2
-2. [x] Pidgin 3.3.0
-3. [x] Newtonsoft.Json 13.0.3
-4. [x] System.Text.Json 9.0.0
-
-## Supported Versions
-
-| | Version |
-|------|------------|
-| .NET | 6, 7, 8, 9 |
-
-## Contributions
-
-Bug reports and contributions are welcome.
-
-## License
-
-This package is released under the **MIT License**.
-See the [LICENSE](https://github.com/rameel/ramstack.parsing/blob/main/LICENSE) file for details.
+# Ramstack.Parsing
+[](https://nuget.org/packages/Ramstack.Parsing)
+[](https://github.com/rameel/ramstack.parsing/blob/main/LICENSE)
+
+A fast, lightweight parser combinator library for .NET.
+
+## Getting Started
+
+To add the `Ramstack.Parsing` [NuGet package](https://www.nuget.org/packages/Ramstack.Parsing) to your project, run:
+```shell
+dotnet add package Ramstack.Parsing
+```
+
+## Usage
+
+Here's how to define a simple expression parser that parses and evaluates mathematical expressions in one step:
+
+```csharp
+public static Parser Calc { get; } = CreateParser();
+
+private static Parser CreateParser()
+{
+ // Grammar:
+ // ----------------------------------------
+ // Start : S Sum $
+ // Sum : Product ([+-] S Product)*
+ // Product : Unary ([*/] S Unary)*
+ // Unary : '-'? S Primary
+ // Primary : Parenthesis / Value
+ // Parenthesis : '(' S Sum ')' S
+ // Value : Number S
+ // S : [ \r\n\t]*
+
+ var sum = Deferred();
+ var value = Literal.Number().ThenIgnore(S);
+
+ var parenthesis = sum.Between(
+ Seq(L('('), S),
+ Seq(L(')'), S)
+ );
+
+ var primary = parenthesis.Or(value);
+
+ var unary = Seq(
+ L('-').Optional(),
+ S,
+ primary
+ ).Do((u, _, d) => u.HasValue ? -d : d);
+
+ var product = unary.Fold(
+ OneOf("*/").ThenIgnore(S),
+ (l, r, op) => op == '*' ? l * r : l / r);
+
+ sum.Parser = product.Fold(
+ OneOf("+-").ThenIgnore(S),
+ (l, r, op) => op == '+' ? l + r : l - r);
+
+ return sum.Between(S, Eof);
+}
+```
+
+Use the parser as follows:
+
+```csharp
+var result = Calc.Parse(expression);
+if (result.Success)
+{
+ var value = result.Value;
+ ...
+}
+else
+{
+ Console.WriteLine(result.ErrorMessage);
+
+ //
+ // result.ToString() returns the parsed value as a string,
+ // or an error message if parsing fails.
+ //
+ // Console.WriteLine(result);
+ //
+}
+```
+
+The parser provides detailed error messages when the input does not conform to the specified grammar.
+For example, when parsing the expression `"1 + ("`, the parser expects `'-'`, `'('`, or a `number` after the opening parenthesis.
+The error message clearly indicates this:
+
+```
+(1:6) Expected '-', '(' or number
+```
+
+In addition to the main `Parse` method, there is also a lightweight `bool TryParse(ReadOnlySpan source, out T value)` method.
+This method suppresses diagnostic messages, returning only the parsing success status and the parsed value if successful.
+
+If detailed error messages are not required, using `TryParse` is the preferred choice, as it reduces memory allocations
+and slightly improves performance by avoiding the overhead associated with collecting diagnostic data.
+
+## Documentation
+
+- Documentation can be found in [docs/documentation.md](docs/documentation.md) (Work in Progress).
+- Additional usage samples, see the [samples/Samples](samples) directory.
+
+## Performance
+
+`Ramstack.Parsing` stands out as an exceptionally fast and efficient parsing library, outperforming many alternatives in both speed and memory usage.
+
+### Benchmarks: Regex
+
+Here's a comparison between a regex-based email matcher and an equivalent parser combinator implementation:
+
+**Regular Expression:**
+```csharp
+[GeneratedRegex(@"^[\w.+-]+@[\w-]+\.\w{2,}$")]
+private static partial Regex EmailRegexGenerated();
+```
+
+**Parser**:
+```csharp
+var parser = Seq(
+ Choice(LetterOrDigit, OneOf("_-+.")).OneOrMore(),
+ L('@'),
+ Choice(LetterOrDigit, L('-')).OneOrMore(),
+ L('.'),
+ LetterOrDigit.AtLeast(2)
+).Text();
+```
+The library supports nearly full character class definitions from regular expressions, allowing grammars to be written in a similar way
+as it written for regular expression. Optimizations ensure that both definitions are internally normalized to an equivalent representation:
+```csharp
+var parser = Seq(
+ Set("\\w+.-").OneOrMore(),
+ L('@'),
+ Set("\\w-").OneOrMore(),
+ L('.'),
+ Set("\\w").AtLeast(2)
+).Text();
+```
+
+The benchmark results show that `Ramstack.Parsing` outperforms even highly optimized Regex implementations,
+including compiled and source-generated regexes.
+
+```
+BenchmarkDotNet v0.14.0, Windows 11 (10.0.26100.3037)
+AMD Ryzen 9 5900X, 1 CPU, 24 logical and 12 physical cores
+.NET SDK 9.0.200-preview.0.25057.12
+ [Host] : .NET 9.0.1 (9.0.124.61010), X64 RyuJIT AVX2
+ DefaultJob : .NET 9.0.1 (9.0.124.61010), X64 RyuJIT AVX2
+
+
+| Method | Mean | Error | StdDev | Op/s | Gen0 | Allocated |
+|---------------- |------------:|---------:|---------:|-------------:|-------:|----------:|
+| Ramstack | 34.47 ns | 0.073 ns | 0.065 ns | 29,008,779.8 | - | - |
+| Regex | 107.35 ns | 0.125 ns | 0.117 ns | 9,315,658.6 | - | - |
+| Regex:Compiled | 44.63 ns | 0.093 ns | 0.083 ns | 22,408,327.6 | - | - |
+| Regex:Generated | 41.85 ns | 0.282 ns | 0.250 ns | 23,893,269.4 | - | - |
+| Parlot | 295.05 ns | 0.601 ns | 0.533 ns | 3,389,302.6 | 0.0229 | 384 B |
+| Parlot:Compiled | 228.98 ns | 0.446 ns | 0.417 ns | 4,367,155.0 | 0.0091 | 152 B |
+| Pidgin | 1,602.00 ns | 9.016 ns | 8.434 ns | 624,219.5 | 0.0572 | 976 B |
+```
+
+In this specific scenario, the library simply checks for a match against the email pattern, similar to what `Regex.IsMatch` does,
+without extracting the match result itself. Like with regular expressions, this approach avoids unnecessary memory allocations.
+
+### Benchmarks: Expressions
+
+This benchmarks tests 2 expressions:
+- **Small**: `2.5 * 4.7 - 8.1 / 3`
+- **Large**: `((3.14159 * 2.3 * 4) / (1.5 - 0.3) + (2.71828 * 2.5)) * ((8.1 * 3.2 + 4.7) / 2.1 - ((15.7 + 2.3 * 4) / (1.5 - 0.3))) - (((3.5 * 1.41421) * (2.71828 + 3.14159)) / 2)`
+
+```
+BenchmarkDotNet v0.14.0, Windows 11 (10.0.26100.3037)
+AMD Ryzen 9 5900X, 1 CPU, 24 logical and 12 physical cores
+.NET SDK 9.0.200-preview.0.25057.12
+ [Host] : .NET 9.0.1 (9.0.124.61010), X64 RyuJIT AVX2
+ DefaultJob : .NET 9.0.1 (9.0.124.61010), X64 RyuJIT AVX2
+
+
+| Method | Mean | Error | StdDev | Op/s | Gen0 | Allocated |
+|---------------------- |------------:|----------:|----------:|------------:|-------:|----------:|
+| Ramstack:Large | 1,600.2 ns | 9.54 ns | 7.96 ns | 624,925.9 | - | - |
+| Ramstack:Diag:Large | 1,699.6 ns | 3.53 ns | 3.13 ns | 588,379.8 | 0.0057 | 104 B |
+| Parlot:Large | 3,520.1 ns | 11.08 ns | 10.37 ns | 284,081.7 | 0.1984 | 3344 B |
+| Parlot:Compiled:Large | 3,356.7 ns | 7.08 ns | 6.27 ns | 297,910.3 | 0.1984 | 3344 B |
+| Pidgin:Large | 39,197.3 ns | 150.13 ns | 140.43 ns | 25,511.9 | 0.2441 | 4464 B |
+| | | | | | | |
+| Ramstack:Small | 209.5 ns | 0.28 ns | 0.25 ns | 4,772,894.8 | - | - |
+| Ramstack:Diag:Small | 260.6 ns | 0.57 ns | 0.50 ns | 3,838,032.3 | 0.0062 | 104 B |
+| Parlot:Small | 410.7 ns | 1.46 ns | 1.36 ns | 2,434,653.7 | 0.0391 | 656 B |
+| Parlot:Compiled:Small | 385.1 ns | 1.22 ns | 0.95 ns | 2,596,891.9 | 0.0391 | 656 B |
+| Pidgin:Small | 4,322.2 ns | 18.28 ns | 17.10 ns | 231,363.9 | 0.0381 | 736 B |
+```
+
+- `Ramstack` diagnostic messages disabled.
+- `Ramstack:Diag` includes diagnostic messages.
+
+Even with diagnostics enabled, `Ramstack.Parsing` outperforms other popular libraries.
+
+### Benchmarks: JSON
+
+This benchmark evaluates JSON parsing performance, including object model construction, across different file sizes.
+
+- **Small**: 1.16KB
+- **Medium**: 11KB
+- **Large**: `twitter.json` (617KB) from [serde-rs/json-benchmark](https://github.com/serde-rs/json-benchmark)
+
+```
+BenchmarkDotNet v0.14.0, Windows 11 (10.0.26100.3037)
+AMD Ryzen 9 5900X, 1 CPU, 24 logical and 12 physical cores
+.NET SDK 9.0.200-preview.0.25057.12
+ [Host] : .NET 9.0.1 (9.0.124.61010), X64 RyuJIT AVX2
+ DefaultJob : .NET 9.0.1 (9.0.124.61010), X64 RyuJIT AVX2
+
+
+| Method | Input | Mean | Error | StdDev | Op/s | Gen0 | Gen1 | Gen2 | Allocated |
+|----------------- |------- |--------------:|-----------:|-----------:|-----------:|---------:|---------:|---------:|-----------:|
+| Ramstack | big | 1,307.929 us | 12.6067 us | 11.7923 us | 764.57 | 152.3438 | 130.8594 | - | 2498.88 KB |
+| Parlot | big | 3,102.953 us | 9.3441 us | 8.7405 us | 322.27 | 156.2500 | 132.8125 | - | 2554.06 KB |
+| Parlot:Compiled | big | 3,078.931 us | 7.4028 us | 5.7796 us | 324.79 | 156.2500 | 132.8125 | - | 2554.06 KB |
+| Pidgin | big | 16,675.788 us | 40.7050 us | 36.0839 us | 59.97 | 156.2500 | 93.7500 | - | 2570.33 KB |
+| Newtonsoft.Json | big | 3,878.753 us | 18.3372 us | 16.2554 us | 257.81 | 343.7500 | 320.3125 | - | 5638.63 KB |
+| System.Text.Json | big | 1,492.658 us | 10.2347 us | 9.0728 us | 669.95 | 216.7969 | 216.7969 | 216.7969 | 963.67 KB |
+
+| Ramstack | medium | 20.163 us | 0.0968 us | 0.0906 us | 49,595.14 | 2.6245 | 0.2747 | - | 42.94 KB |
+| Parlot | medium | 72.128 us | 0.1193 us | 0.1058 us | 13,864.18 | 2.5635 | 0.2441 | - | 43.09 KB |
+| Parlot:Compiled | medium | 70.931 us | 0.2758 us | 0.2445 us | 14,098.14 | 2.5635 | 0.2441 | - | 43.09 KB |
+| Pidgin | medium | 266.283 us | 0.4172 us | 0.3698 us | 3,755.41 | 2.4414 | - | - | 44.45 KB |
+| Newtonsoft.Json | medium | 52.036 us | 0.4550 us | 0.4257 us | 19,217.47 | 6.0425 | 1.6479 | - | 99.44 KB |
+| System.Text.Json | medium | 24.471 us | 0.0968 us | 0.0756 us | 40,865.15 | 1.0376 | - | - | 17.03 KB |
+
+| Ramstack | small | 3.016 us | 0.0064 us | 0.0053 us | 331,565.28 | 0.3815 | 0.0038 | - | 6.24 KB |
+| Parlot | small | 6.723 us | 0.0313 us | 0.0292 us | 148,732.16 | 0.3891 | - | - | 6.39 KB |
+| Parlot:Compiled | small | 6.661 us | 0.0210 us | 0.0175 us | 150,120.62 | 0.3891 | - | - | 6.39 KB |
+| Pidgin | small | 33.369 us | 0.3909 us | 0.3656 us | 29,968.03 | 0.3662 | - | - | 6.49 KB |
+| Newtonsoft.Json | small | 7.940 us | 0.0226 us | 0.0201 us | 125,951.32 | 1.0529 | 0.0458 | - | 17.26 KB |
+| System.Text.Json | small | 3.477 us | 0.0133 us | 0.0111 us | 287,598.87 | 0.1373 | - | - | 2.25 KB |
+```
+
+`Ramstack.Parsing` demonstrated superior performance, outperforming other parser libraries by at least 2-3 times,
+and even exceeded specialized JSON parsers such as `Newtonsoft.Json` and `System.Text.Json` in terms of both speed and memory efficiency.
+
+### Benchmarked Libraries
+
+1. [x] Parlot 1.3.2
+2. [x] Pidgin 3.3.0
+3. [x] Newtonsoft.Json 13.0.3
+4. [x] System.Text.Json 9.0.0
+
+## Supported Versions
+
+| | Version |
+|------|------------|
+| .NET | 6, 7, 8, 9 |
+
+## Contributions
+
+Bug reports and contributions are welcome.
+
+## License
+
+This package is released under the **MIT License**.
+See the [LICENSE](https://github.com/rameel/ramstack.parsing/blob/main/LICENSE) file for details.
diff --git a/benchmarks/Data/medium.json b/benchmarks/Data/medium.json
index 158d45b..434c145 100644
--- a/benchmarks/Data/medium.json
+++ b/benchmarks/Data/medium.json
@@ -1,317 +1,317 @@
-[
- {
- "id": "6782fb719850cc2a7e8f5687",
- "index": 0,
- "guid": "39941455-532c-4c27-8952-7f44f7288123",
- "isActive": false,
- "balance": "$3,257.80",
- "picture": "http://placehold.it/32x32",
- "age": 22,
- "eyeColor": "brown",
- "name": "Susanna Kidd",
- "gender": "female",
- "company": "ISOLOGICS",
- "email": "susannakidd@isologics.com",
- "phone": "+1 (827) 420-2998",
- "address": "723 Lafayette Avenue, Sterling, Arkansas, 790",
- "about": "Magna ad minim qui non minim esse et cupidatat elit occaecat eiusmod fugiat dolore. Officia nisi nostrud duis nostrud et ipsum laboris. Commodo laboris ex deserunt sunt ex et mollit eiusmod labore do. Eu ipsum laboris occaecat laborum ex sit occaecat et. Qui est eiusmod labore adipisicing labore tempor do pariatur id dolor reprehenderit cillum. Non veniam incididunt Lorem reprehenderit incididunt. Magna consequat dolor incididunt et non quis ea elit ipsum anim ex magna.",
- "registered": "2017-09-23T04:51:42 -06:00",
- "latitude": -67.71782,
- "longitude": 27.337068,
- "tags": [
- "officia",
- "irure",
- "reprehenderit",
- "proident",
- "deserunt",
- "laborum",
- "duis"
- ],
- "friends": [
- {
- "id": 0,
- "name": "Fleming Chang"
- },
- {
- "id": 1,
- "name": "Horton Alvarado"
- },
- {
- "id": 2,
- "name": "Rosales Stanley"
- }
- ],
- "greeting": "Hello, Susanna Kidd! You have 8 unread messages.",
- "favoriteFruit": "apple"
- },
- {
- "id": "6782fb71927cb4b18a76c5eb",
- "index": 1,
- "guid": "fa3bf5db-3caa-43c9-821b-cd5e126384a3",
- "isActive": false,
- "balance": "$2,378.85",
- "picture": "http://placehold.it/32x32",
- "age": 36,
- "eyeColor": "brown",
- "name": "Letha Navarro",
- "gender": "female",
- "company": "DYMI",
- "email": "lethanavarro@dymi.com",
- "phone": "+1 (992) 537-3991",
- "address": "912 Cadman Plaza, Byrnedale, South Dakota, 1069",
- "about": "Sunt esse amet sit ad nulla enim reprehenderit veniam dolore tempor nostrud dolore. Officia laborum id aliqua sint nulla excepteur aliqua. Nisi ad duis ullamco magna ea amet nostrud eu laboris minim quis voluptate occaecat voluptate.",
- "registered": "2022-12-28T03:49:31 -05:00",
- "latitude": 86.859753,
- "longitude": 179.675296,
- "tags": [
- "aliqua",
- "veniam",
- "consequat",
- "mollit",
- "eu",
- "veniam",
- "do"
- ],
- "friends": [
- {
- "id": 0,
- "name": "Carson Garner"
- },
- {
- "id": 1,
- "name": "Curtis Bird"
- },
- {
- "id": 2,
- "name": "Tisha Robbins"
- }
- ],
- "greeting": "Hello, Letha Navarro! You have 1 unread messages.",
- "favoriteFruit": "strawberry"
- },
- {
- "id": "6782fb716669f6d74a495c08",
- "index": 2,
- "guid": "5fd0dbb8-790a-4ece-80ca-c7ed3d96d2e7",
- "isActive": false,
- "balance": "$3,941.05",
- "picture": "http://placehold.it/32x32",
- "age": 33,
- "eyeColor": "blue",
- "name": "Kane Solomon",
- "gender": "male",
- "company": "INTRADISK",
- "email": "kanesolomon@intradisk.com",
- "phone": "+1 (873) 534-2143",
- "address": "275 McKibben Street, Bangor, Federated States Of Micronesia, 4521",
- "about": "Consectetur ex irure dolor sunt adipisicing. Commodo do qui laboris magna non minim fugiat commodo. Laborum qui cupidatat exercitation laboris sint velit nisi cupidatat eu ipsum pariatur.",
- "registered": "2024-02-07T07:04:09 -05:00",
- "latitude": 69.139384,
- "longitude": -51.308371,
- "tags": [
- "ex",
- "ad",
- "aliqua",
- "consectetur",
- "proident",
- "mollit",
- "et"
- ],
- "friends": [
- {
- "id": 0,
- "name": "Nora Pickett"
- },
- {
- "id": 1,
- "name": "Billie Levine"
- },
- {
- "id": 2,
- "name": "Shields Davenport"
- }
- ],
- "greeting": "Hello, Kane Solomon! You have 7 unread messages.",
- "favoriteFruit": "banana"
- },
- {
- "id": "6782fb710d1e6597d6a463f7",
- "index": 3,
- "guid": "fa0456c4-c686-435e-9a22-9a2b299368f5",
- "isActive": true,
- "balance": "$1,216.21",
- "picture": "http://placehold.it/32x32",
- "age": 27,
- "eyeColor": "blue",
- "name": "Orr Hill",
- "gender": "male",
- "company": "FURNITECH",
- "email": "orrhill@furnitech.com",
- "phone": "+1 (823) 455-3555",
- "address": "152 Hornell Loop, Cawood, Alaska, 5220",
- "about": "Labore dolor sint est culpa Lorem dolore veniam consequat. Officia Lorem eu labore esse esse proident sint consequat Lorem labore esse. In nostrud sint aute commodo ex proident. Nulla labore eiusmod in aliqua in ad. Eiusmod laborum dolor ex est velit incididunt et amet.",
- "registered": "2021-08-22T10:59:13 -05:00",
- "latitude": 53.896296,
- "longitude": -45.046902,
- "tags": [
- "labore",
- "nisi",
- "cupidatat",
- "excepteur",
- "ex",
- "Lorem",
- "do"
- ],
- "friends": [
- {
- "id": 0,
- "name": "Ophelia Villarreal"
- },
- {
- "id": 1,
- "name": "Velazquez Pena"
- },
- {
- "id": 2,
- "name": "Pena Gaines"
- }
- ],
- "greeting": "Hello, Orr Hill! You have 1 unread messages.",
- "favoriteFruit": "apple"
- },
- {
- "id": "6782fb71eb7d28d8981ff9b1",
- "index": 4,
- "guid": "167c126b-71c9-4ece-9b1d-83a593e7a703",
- "isActive": false,
- "balance": "$2,812.13",
- "picture": "http://placehold.it/32x32",
- "age": 31,
- "eyeColor": "brown",
- "name": "Francisca Beard",
- "gender": "female",
- "company": "PHOTOBIN",
- "email": "franciscabeard@photobin.com",
- "phone": "+1 (817) 443-3427",
- "address": "821 Hunterfly Place, Mathews, Iowa, 7047",
- "about": "Magna ex Lorem dolore pariatur laboris ex. Fugiat id ad do occaecat sint ullamco commodo aliquip laborum commodo nisi exercitation Lorem occaecat. Quis excepteur laboris Lorem sint labore aute consectetur quis sint. Qui Lorem aute labore deserunt exercitation excepteur id consectetur eiusmod nisi in.",
- "registered": "2014-10-04T04:47:30 -06:00",
- "latitude": -12.564841,
- "longitude": -81.998082,
- "tags": [
- "pariatur",
- "sint",
- "sit",
- "anim",
- "deserunt",
- "quis",
- "sunt"
- ],
- "friends": [
- {
- "id": 0,
- "name": "Day Wheeler"
- },
- {
- "id": 1,
- "name": "Juana Martin"
- },
- {
- "id": 2,
- "name": "Wells Workman"
- }
- ],
- "greeting": "Hello, Francisca Beard! You have 2 unread messages.",
- "favoriteFruit": "apple"
- },
- {
- "id": "6782fb71accf35c389e2bf14",
- "index": 5,
- "guid": "760e7769-0e65-4583-b3b8-4dee5401be8c",
- "isActive": true,
- "balance": "$3,776.56",
- "picture": "http://placehold.it/32x32",
- "age": 40,
- "eyeColor": "blue",
- "name": "Valentine Sellers",
- "gender": "male",
- "company": "EXOSPACE",
- "email": "valentinesellers@exospace.com",
- "phone": "+1 (918) 428-2199",
- "address": "566 Robert Street, Boykin, Utah, 346",
- "about": "Commodo sint aute esse aute. Id duis aliquip deserunt incididunt Lorem deserunt velit qui esse cillum. Quis occaecat eiusmod esse laboris pariatur fugiat nisi exercitation enim ex nisi. Aliqua magna cupidatat pariatur proident ipsum labore. Irure commodo qui eu dolore aliqua incididunt cillum nostrud.",
- "registered": "2020-03-29T02:44:28 -05:00",
- "latitude": 82.01843,
- "longitude": 60.297166,
- "tags": [
- "nulla",
- "quis",
- "pariatur",
- "esse",
- "irure",
- "eiusmod",
- "nisi"
- ],
- "friends": [
- {
- "id": 0,
- "name": "Rosemarie Delaney"
- },
- {
- "id": 1,
- "name": "Sheila Wade"
- },
- {
- "id": 2,
- "name": "Lawson Castillo"
- }
- ],
- "greeting": "Hello, Valentine Sellers! You have 7 unread messages.",
- "favoriteFruit": "strawberry"
- },
- {
- "id": "6782fb71f5a8b906ba29ba8a",
- "index": 6,
- "guid": "1875e892-73d7-4fd1-b472-4760e5c84a19",
- "isActive": true,
- "balance": "$1,861.10",
- "picture": "http://placehold.it/32x32",
- "age": 37,
- "eyeColor": "brown",
- "name": "Lee Vaughn",
- "gender": "male",
- "company": "TEMORAK",
- "email": "leevaughn@temorak.com",
- "phone": "+1 (947) 509-3320",
- "address": "429 Overbaugh Place, Baker, South Carolina, 4905",
- "about": "Dolore dolor id nisi est elit elit cupidatat velit ut. Labore irure consequat ullamco consequat culpa aliqua voluptate Lorem do. Excepteur ea et mollit voluptate duis ad mollit occaecat nostrud nisi.",
- "registered": "2014-12-25T09:54:15 -06:00",
- "latitude": -18.166264,
- "longitude": -20.595374,
- "tags": [
- "id",
- "minim",
- "velit",
- "ex",
- "commodo",
- "ullamco",
- "nostrud"
- ],
- "friends": [
- {
- "id": 0,
- "name": "Reese Herring"
- },
- {
- "id": 1,
- "name": "Patel Jarvis"
- },
- {
- "id": 2,
- "name": "Blair Lewis"
- }
- ],
- "greeting": "Hello, Lee Vaughn! You have 4 unread messages.",
- "favoriteFruit": "banana"
- }
-]
+[
+ {
+ "id": "6782fb719850cc2a7e8f5687",
+ "index": 0,
+ "guid": "39941455-532c-4c27-8952-7f44f7288123",
+ "isActive": false,
+ "balance": "$3,257.80",
+ "picture": "http://placehold.it/32x32",
+ "age": 22,
+ "eyeColor": "brown",
+ "name": "Susanna Kidd",
+ "gender": "female",
+ "company": "ISOLOGICS",
+ "email": "susannakidd@isologics.com",
+ "phone": "+1 (827) 420-2998",
+ "address": "723 Lafayette Avenue, Sterling, Arkansas, 790",
+ "about": "Magna ad minim qui non minim esse et cupidatat elit occaecat eiusmod fugiat dolore. Officia nisi nostrud duis nostrud et ipsum laboris. Commodo laboris ex deserunt sunt ex et mollit eiusmod labore do. Eu ipsum laboris occaecat laborum ex sit occaecat et. Qui est eiusmod labore adipisicing labore tempor do pariatur id dolor reprehenderit cillum. Non veniam incididunt Lorem reprehenderit incididunt. Magna consequat dolor incididunt et non quis ea elit ipsum anim ex magna.",
+ "registered": "2017-09-23T04:51:42 -06:00",
+ "latitude": -67.71782,
+ "longitude": 27.337068,
+ "tags": [
+ "officia",
+ "irure",
+ "reprehenderit",
+ "proident",
+ "deserunt",
+ "laborum",
+ "duis"
+ ],
+ "friends": [
+ {
+ "id": 0,
+ "name": "Fleming Chang"
+ },
+ {
+ "id": 1,
+ "name": "Horton Alvarado"
+ },
+ {
+ "id": 2,
+ "name": "Rosales Stanley"
+ }
+ ],
+ "greeting": "Hello, Susanna Kidd! You have 8 unread messages.",
+ "favoriteFruit": "apple"
+ },
+ {
+ "id": "6782fb71927cb4b18a76c5eb",
+ "index": 1,
+ "guid": "fa3bf5db-3caa-43c9-821b-cd5e126384a3",
+ "isActive": false,
+ "balance": "$2,378.85",
+ "picture": "http://placehold.it/32x32",
+ "age": 36,
+ "eyeColor": "brown",
+ "name": "Letha Navarro",
+ "gender": "female",
+ "company": "DYMI",
+ "email": "lethanavarro@dymi.com",
+ "phone": "+1 (992) 537-3991",
+ "address": "912 Cadman Plaza, Byrnedale, South Dakota, 1069",
+ "about": "Sunt esse amet sit ad nulla enim reprehenderit veniam dolore tempor nostrud dolore. Officia laborum id aliqua sint nulla excepteur aliqua. Nisi ad duis ullamco magna ea amet nostrud eu laboris minim quis voluptate occaecat voluptate.",
+ "registered": "2022-12-28T03:49:31 -05:00",
+ "latitude": 86.859753,
+ "longitude": 179.675296,
+ "tags": [
+ "aliqua",
+ "veniam",
+ "consequat",
+ "mollit",
+ "eu",
+ "veniam",
+ "do"
+ ],
+ "friends": [
+ {
+ "id": 0,
+ "name": "Carson Garner"
+ },
+ {
+ "id": 1,
+ "name": "Curtis Bird"
+ },
+ {
+ "id": 2,
+ "name": "Tisha Robbins"
+ }
+ ],
+ "greeting": "Hello, Letha Navarro! You have 1 unread messages.",
+ "favoriteFruit": "strawberry"
+ },
+ {
+ "id": "6782fb716669f6d74a495c08",
+ "index": 2,
+ "guid": "5fd0dbb8-790a-4ece-80ca-c7ed3d96d2e7",
+ "isActive": false,
+ "balance": "$3,941.05",
+ "picture": "http://placehold.it/32x32",
+ "age": 33,
+ "eyeColor": "blue",
+ "name": "Kane Solomon",
+ "gender": "male",
+ "company": "INTRADISK",
+ "email": "kanesolomon@intradisk.com",
+ "phone": "+1 (873) 534-2143",
+ "address": "275 McKibben Street, Bangor, Federated States Of Micronesia, 4521",
+ "about": "Consectetur ex irure dolor sunt adipisicing. Commodo do qui laboris magna non minim fugiat commodo. Laborum qui cupidatat exercitation laboris sint velit nisi cupidatat eu ipsum pariatur.",
+ "registered": "2024-02-07T07:04:09 -05:00",
+ "latitude": 69.139384,
+ "longitude": -51.308371,
+ "tags": [
+ "ex",
+ "ad",
+ "aliqua",
+ "consectetur",
+ "proident",
+ "mollit",
+ "et"
+ ],
+ "friends": [
+ {
+ "id": 0,
+ "name": "Nora Pickett"
+ },
+ {
+ "id": 1,
+ "name": "Billie Levine"
+ },
+ {
+ "id": 2,
+ "name": "Shields Davenport"
+ }
+ ],
+ "greeting": "Hello, Kane Solomon! You have 7 unread messages.",
+ "favoriteFruit": "banana"
+ },
+ {
+ "id": "6782fb710d1e6597d6a463f7",
+ "index": 3,
+ "guid": "fa0456c4-c686-435e-9a22-9a2b299368f5",
+ "isActive": true,
+ "balance": "$1,216.21",
+ "picture": "http://placehold.it/32x32",
+ "age": 27,
+ "eyeColor": "blue",
+ "name": "Orr Hill",
+ "gender": "male",
+ "company": "FURNITECH",
+ "email": "orrhill@furnitech.com",
+ "phone": "+1 (823) 455-3555",
+ "address": "152 Hornell Loop, Cawood, Alaska, 5220",
+ "about": "Labore dolor sint est culpa Lorem dolore veniam consequat. Officia Lorem eu labore esse esse proident sint consequat Lorem labore esse. In nostrud sint aute commodo ex proident. Nulla labore eiusmod in aliqua in ad. Eiusmod laborum dolor ex est velit incididunt et amet.",
+ "registered": "2021-08-22T10:59:13 -05:00",
+ "latitude": 53.896296,
+ "longitude": -45.046902,
+ "tags": [
+ "labore",
+ "nisi",
+ "cupidatat",
+ "excepteur",
+ "ex",
+ "Lorem",
+ "do"
+ ],
+ "friends": [
+ {
+ "id": 0,
+ "name": "Ophelia Villarreal"
+ },
+ {
+ "id": 1,
+ "name": "Velazquez Pena"
+ },
+ {
+ "id": 2,
+ "name": "Pena Gaines"
+ }
+ ],
+ "greeting": "Hello, Orr Hill! You have 1 unread messages.",
+ "favoriteFruit": "apple"
+ },
+ {
+ "id": "6782fb71eb7d28d8981ff9b1",
+ "index": 4,
+ "guid": "167c126b-71c9-4ece-9b1d-83a593e7a703",
+ "isActive": false,
+ "balance": "$2,812.13",
+ "picture": "http://placehold.it/32x32",
+ "age": 31,
+ "eyeColor": "brown",
+ "name": "Francisca Beard",
+ "gender": "female",
+ "company": "PHOTOBIN",
+ "email": "franciscabeard@photobin.com",
+ "phone": "+1 (817) 443-3427",
+ "address": "821 Hunterfly Place, Mathews, Iowa, 7047",
+ "about": "Magna ex Lorem dolore pariatur laboris ex. Fugiat id ad do occaecat sint ullamco commodo aliquip laborum commodo nisi exercitation Lorem occaecat. Quis excepteur laboris Lorem sint labore aute consectetur quis sint. Qui Lorem aute labore deserunt exercitation excepteur id consectetur eiusmod nisi in.",
+ "registered": "2014-10-04T04:47:30 -06:00",
+ "latitude": -12.564841,
+ "longitude": -81.998082,
+ "tags": [
+ "pariatur",
+ "sint",
+ "sit",
+ "anim",
+ "deserunt",
+ "quis",
+ "sunt"
+ ],
+ "friends": [
+ {
+ "id": 0,
+ "name": "Day Wheeler"
+ },
+ {
+ "id": 1,
+ "name": "Juana Martin"
+ },
+ {
+ "id": 2,
+ "name": "Wells Workman"
+ }
+ ],
+ "greeting": "Hello, Francisca Beard! You have 2 unread messages.",
+ "favoriteFruit": "apple"
+ },
+ {
+ "id": "6782fb71accf35c389e2bf14",
+ "index": 5,
+ "guid": "760e7769-0e65-4583-b3b8-4dee5401be8c",
+ "isActive": true,
+ "balance": "$3,776.56",
+ "picture": "http://placehold.it/32x32",
+ "age": 40,
+ "eyeColor": "blue",
+ "name": "Valentine Sellers",
+ "gender": "male",
+ "company": "EXOSPACE",
+ "email": "valentinesellers@exospace.com",
+ "phone": "+1 (918) 428-2199",
+ "address": "566 Robert Street, Boykin, Utah, 346",
+ "about": "Commodo sint aute esse aute. Id duis aliquip deserunt incididunt Lorem deserunt velit qui esse cillum. Quis occaecat eiusmod esse laboris pariatur fugiat nisi exercitation enim ex nisi. Aliqua magna cupidatat pariatur proident ipsum labore. Irure commodo qui eu dolore aliqua incididunt cillum nostrud.",
+ "registered": "2020-03-29T02:44:28 -05:00",
+ "latitude": 82.01843,
+ "longitude": 60.297166,
+ "tags": [
+ "nulla",
+ "quis",
+ "pariatur",
+ "esse",
+ "irure",
+ "eiusmod",
+ "nisi"
+ ],
+ "friends": [
+ {
+ "id": 0,
+ "name": "Rosemarie Delaney"
+ },
+ {
+ "id": 1,
+ "name": "Sheila Wade"
+ },
+ {
+ "id": 2,
+ "name": "Lawson Castillo"
+ }
+ ],
+ "greeting": "Hello, Valentine Sellers! You have 7 unread messages.",
+ "favoriteFruit": "strawberry"
+ },
+ {
+ "id": "6782fb71f5a8b906ba29ba8a",
+ "index": 6,
+ "guid": "1875e892-73d7-4fd1-b472-4760e5c84a19",
+ "isActive": true,
+ "balance": "$1,861.10",
+ "picture": "http://placehold.it/32x32",
+ "age": 37,
+ "eyeColor": "brown",
+ "name": "Lee Vaughn",
+ "gender": "male",
+ "company": "TEMORAK",
+ "email": "leevaughn@temorak.com",
+ "phone": "+1 (947) 509-3320",
+ "address": "429 Overbaugh Place, Baker, South Carolina, 4905",
+ "about": "Dolore dolor id nisi est elit elit cupidatat velit ut. Labore irure consequat ullamco consequat culpa aliqua voluptate Lorem do. Excepteur ea et mollit voluptate duis ad mollit occaecat nostrud nisi.",
+ "registered": "2014-12-25T09:54:15 -06:00",
+ "latitude": -18.166264,
+ "longitude": -20.595374,
+ "tags": [
+ "id",
+ "minim",
+ "velit",
+ "ex",
+ "commodo",
+ "ullamco",
+ "nostrud"
+ ],
+ "friends": [
+ {
+ "id": 0,
+ "name": "Reese Herring"
+ },
+ {
+ "id": 1,
+ "name": "Patel Jarvis"
+ },
+ {
+ "id": 2,
+ "name": "Blair Lewis"
+ }
+ ],
+ "greeting": "Hello, Lee Vaughn! You have 4 unread messages.",
+ "favoriteFruit": "banana"
+ }
+]
diff --git a/benchmarks/Data/small.json b/benchmarks/Data/small.json
index d5c359c..42835f3 100644
--- a/benchmarks/Data/small.json
+++ b/benchmarks/Data/small.json
@@ -1,46 +1,46 @@
-{
- "order_id": "40b9a8bc-f679-48ef-92f6-0271295c7daa",
- "customer": {
- "first_name": "Alex",
- "last_name": "Johnson",
- "email": "alex.johnson@example.com",
- "phone": "+1-555-123-4567"
- },
- "shipping_address": {
- "street": "123 Main Street",
- "house": "16",
- "apartment": "7",
- "city": "New York",
- "zip_code": "10001",
- "country": "USA"
- },
- "items": [
- {
- "item_id": "101",
- "name": "Smartphone XYZ",
- "quantity": 1,
- "price": 699.99
- },
- {
- "item_id": "202",
- "name": "Phone Case XYZ",
- "quantity": 1,
- "price": 29.99
- },
- {
- "item_id": "303",
- "name": "Screen Protector XYZ",
- "quantity": 2,
- "price": 14.99
- }
- ],
- "payment": {
- "method": "credit_card",
- "status": "paid",
- "transaction_id": "txn_123456789"
- },
- "order_total": 759.95,
- "status": "shipped",
- "created_at": "2024-08-15T14:45:00Z",
- "shipped_at": "2024-08-16T10:00:00Z"
-}
+{
+ "order_id": "40b9a8bc-f679-48ef-92f6-0271295c7daa",
+ "customer": {
+ "first_name": "Alex",
+ "last_name": "Johnson",
+ "email": "alex.johnson@example.com",
+ "phone": "+1-555-123-4567"
+ },
+ "shipping_address": {
+ "street": "123 Main Street",
+ "house": "16",
+ "apartment": "7",
+ "city": "New York",
+ "zip_code": "10001",
+ "country": "USA"
+ },
+ "items": [
+ {
+ "item_id": "101",
+ "name": "Smartphone XYZ",
+ "quantity": 1,
+ "price": 699.99
+ },
+ {
+ "item_id": "202",
+ "name": "Phone Case XYZ",
+ "quantity": 1,
+ "price": 29.99
+ },
+ {
+ "item_id": "303",
+ "name": "Screen Protector XYZ",
+ "quantity": 2,
+ "price": 14.99
+ }
+ ],
+ "payment": {
+ "method": "credit_card",
+ "status": "paid",
+ "transaction_id": "txn_123456789"
+ },
+ "order_total": 759.95,
+ "status": "shipped",
+ "created_at": "2024-08-15T14:45:00Z",
+ "shipped_at": "2024-08-16T10:00:00Z"
+}
diff --git a/benchmarks/EmailBenchmark.cs b/benchmarks/EmailBenchmark.cs
index 1b844b9..1936fea 100644
--- a/benchmarks/EmailBenchmark.cs
+++ b/benchmarks/EmailBenchmark.cs
@@ -1,62 +1,62 @@
-using System.Text.RegularExpressions;
-
-using BenchmarkDotNet.Attributes;
-
-using Pidgin;
-
-using Ramstack.Parsing.Benchmarks.Parsers;
-
-namespace Ramstack.Parsing.Benchmarks;
-
-[MemoryDiagnoser]
-[OperationsPerSecond]
-public partial class EmailBenchmark
-{
- private static readonly string Email = "development.team-2021@example.com";
-
- private static readonly Regex EmailRegex = new Regex(@"^[\w._+-]+@[\w-]+\.\w{2,}$");
- private static readonly Regex EmailRegexCompiled = new Regex((@"^[\w._+-]+@[\w-]+\.\w{2,}$"), RegexOptions.Compiled);
-
- [GeneratedRegex(@"^[\w._+-]+@[\w-]+\.\w{2,}$")]
- private static partial Regex EmailRegexGenerated();
-
- [GlobalSetup]
- public void Setup()
- {
- if (!EmailRegex.IsMatch(Email)) throw new Exception(nameof(EmailRegex));
- if (!EmailRegexCompiled.IsMatch(Email)) throw new Exception(nameof(EmailRegexCompiled));
- if (!EmailRegexGenerated().IsMatch(Email)) throw new Exception(nameof(EmailRegexGenerated));
- if (!RamstackParsers.EmailParser.TryParse(Email, out _)) throw new Exception("RamstackParsers.EmailParser");
- if (!ParlotParsers.EmailParser.TryParse(Email, out _)) throw new Exception("ParlotParsers.EmailParser");
- if (!ParlotParsers.EmailParserCompiled.TryParse(Email, out _)) throw new Exception("ParlotParsers.EmailParserCompiled");
- PidginParsers.EmailParser.ParseOrThrow(Email);
- }
-
- [Benchmark(Description = "Ramstack")]
- public bool RamstackEmail() =>
- RamstackParsers.EmailVoidParser.TryParse(Email, out _);
-
- [Benchmark(Description = "Regex")]
- public bool RegexEmail() =>
- EmailRegex.IsMatch(Email);
-
- [Benchmark(Description = "Regex:Compiled")]
- public bool RegexEmailCompiled() =>
- EmailRegexCompiled.IsMatch(Email);
-
- [Benchmark(Description = "Regex:Generated")]
- public bool RegexEmailGenerated() =>
- EmailRegexGenerated().IsMatch(Email);
-
- [Benchmark(Description = "Parlot")]
- public bool ParlotEmail() =>
- ParlotParsers.EmailParser.TryParse(Email, out _);
-
- [Benchmark(Description = "Parlot:Compiled")]
- public bool ParlotEmailCompiled() =>
- ParlotParsers.EmailParserCompiled.TryParse(Email, out _);
-
- [Benchmark(Description = "Pidgin")]
- public bool PidginEmail() =>
- PidginParsers.EmailParser.Parse(Email).Success;
-}
+using System.Text.RegularExpressions;
+
+using BenchmarkDotNet.Attributes;
+
+using Pidgin;
+
+using Ramstack.Parsing.Benchmarks.Parsers;
+
+namespace Ramstack.Parsing.Benchmarks;
+
+[MemoryDiagnoser]
+[OperationsPerSecond]
+public partial class EmailBenchmark
+{
+ private static readonly string Email = "development.team-2021@example.com";
+
+ private static readonly Regex EmailRegex = new Regex(@"^[\w._+-]+@[\w-]+\.\w{2,}$");
+ private static readonly Regex EmailRegexCompiled = new Regex((@"^[\w._+-]+@[\w-]+\.\w{2,}$"), RegexOptions.Compiled);
+
+ [GeneratedRegex(@"^[\w._+-]+@[\w-]+\.\w{2,}$")]
+ private static partial Regex EmailRegexGenerated();
+
+ [GlobalSetup]
+ public void Setup()
+ {
+ if (!EmailRegex.IsMatch(Email)) throw new Exception(nameof(EmailRegex));
+ if (!EmailRegexCompiled.IsMatch(Email)) throw new Exception(nameof(EmailRegexCompiled));
+ if (!EmailRegexGenerated().IsMatch(Email)) throw new Exception(nameof(EmailRegexGenerated));
+ if (!RamstackParsers.EmailParser.TryParse(Email, out _)) throw new Exception("RamstackParsers.EmailParser");
+ if (!ParlotParsers.EmailParser.TryParse(Email, out _)) throw new Exception("ParlotParsers.EmailParser");
+ if (!ParlotParsers.EmailParserCompiled.TryParse(Email, out _)) throw new Exception("ParlotParsers.EmailParserCompiled");
+ PidginParsers.EmailParser.ParseOrThrow(Email);
+ }
+
+ [Benchmark(Description = "Ramstack")]
+ public bool RamstackEmail() =>
+ RamstackParsers.EmailVoidParser.TryParse(Email, out _);
+
+ [Benchmark(Description = "Regex")]
+ public bool RegexEmail() =>
+ EmailRegex.IsMatch(Email);
+
+ [Benchmark(Description = "Regex:Compiled")]
+ public bool RegexEmailCompiled() =>
+ EmailRegexCompiled.IsMatch(Email);
+
+ [Benchmark(Description = "Regex:Generated")]
+ public bool RegexEmailGenerated() =>
+ EmailRegexGenerated().IsMatch(Email);
+
+ [Benchmark(Description = "Parlot")]
+ public bool ParlotEmail() =>
+ ParlotParsers.EmailParser.TryParse(Email, out _);
+
+ [Benchmark(Description = "Parlot:Compiled")]
+ public bool ParlotEmailCompiled() =>
+ ParlotParsers.EmailParserCompiled.TryParse(Email, out _);
+
+ [Benchmark(Description = "Pidgin")]
+ public bool PidginEmail() =>
+ PidginParsers.EmailParser.Parse(Email).Success;
+}
diff --git a/benchmarks/ExpressionBenchmark.cs b/benchmarks/ExpressionBenchmark.cs
index 96428c7..5a9c36b 100644
--- a/benchmarks/ExpressionBenchmark.cs
+++ b/benchmarks/ExpressionBenchmark.cs
@@ -1,99 +1,99 @@
-using System.Diagnostics.CodeAnalysis;
-
-using BenchmarkDotNet.Attributes;
-using BenchmarkDotNet.Configs;
-
-using Pidgin;
-
-using Ramstack.Parsing.Benchmarks.Parsers;
-
-namespace Ramstack.Parsing.Benchmarks;
-
-[MemoryDiagnoser]
-[OperationsPerSecond]
-[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]
-public class ExpressionBenchmark
-{
- [SuppressMessage("ReSharper", "ArrangeRedundantParentheses")]
- private const double Large = ((3.14159 * 2.3 * 4) / (1.5 - 0.3) + (2.71828 * 2.5)) * ((8.1 * 3.2 + 4.7) / 2.1 - ((15.7 + 2.3 * 4) / (1.5 - 0.3))) - (((3.5 * 1.41421) * (2.71828 + 3.14159)) / 2);
- private const double Small = 2.5 * 4.7 - 8.1 / 3;
-
- private const string SmallExpression = "2.5 * 4.7 - 8.1 / 3";
- private const string LargeExpression = "(( 3.14159 * 2.3 * 4) / (1.5 - 0.3) + (2.71828 * 2.5) ) * ((8.1 * 3.2 + 4.7) / 2.1 - ((15.7 + 2.3 * 4) / (1.5 - 0.3))) - (((3.5 * 1.41421) * (2.71828 + 3.14159)) / 2)";
-
- [GlobalSetup]
- [SuppressMessage("ReSharper", "CompareOfFloatsByEqualityOperator")]
- public void Setup()
- {
- if (RamstackParsers.ExpressionParser.Parse(SmallExpression).Value != Small) throw new Exception("Ramstack: Small");
- if (RamstackParsers.ExpressionParser.Parse(LargeExpression).Value != Large) throw new Exception("Ramstack: Large");
-
- if (ParlotParsers.ExpressionParser.Parse(SmallExpression) != Small) throw new Exception("Parlot: Small");
- if (ParlotParsers.ExpressionParser.Parse(LargeExpression) != Large) throw new Exception("Parlot: Large");
-
- if (PidginParsers.ExpressionParser.Parse(SmallExpression).Value != Small) throw new Exception("Pidgin: Small");
- if (PidginParsers.ExpressionParser.Parse(LargeExpression).Value != Large) throw new Exception("Pidgin: Large");
- }
-
- [BenchmarkCategory("Small")]
- [Benchmark(Description = "Ramstack:Small")]
- public double RamstackSmall()
- {
- RamstackParsers.ExpressionParser.TryParse(SmallExpression, out var result);
- return result;
- }
-
- [BenchmarkCategory("Small")]
- [Benchmark(Description = "Ramstack:Diag:Small")]
- public double RamstackSmall_Diagnostics() =>
- RamstackParsers.ExpressionParser.Parse(SmallExpression).Value;
-
- [BenchmarkCategory("Large")]
- [Benchmark(Description = "Ramstack:Large")]
- public double RamstackLarge()
- {
- RamstackParsers.ExpressionParser.TryParse(LargeExpression, out var result);
- return result;
- }
-
- [BenchmarkCategory("Large")]
- [Benchmark(Description = "Ramstack:Diag:Large")]
- public double RamstackLarge_Diagnostics() =>
- RamstackParsers.ExpressionParser.Parse(LargeExpression).Value;
-
- [BenchmarkCategory("Small")]
- [Benchmark(Description = "Parlot:Small")]
- public double ParlotSmall() =>
- ParlotParsers.ExpressionParser.Parse(SmallExpression);
-
- [BenchmarkCategory("Small")]
- [Benchmark(Description = "Parlot:Compiled:Small")]
- public double ParlotSmallCompiled() =>
- ParlotParsers.ExpressionParserCompiled.Parse(SmallExpression);
-
- [BenchmarkCategory("Large")]
- [Benchmark(Description = "Parlot:Large")]
- public double ParlotLarge() =>
- ParlotParsers.ExpressionParser.Parse(LargeExpression);
-
- [BenchmarkCategory("Large")]
- [Benchmark(Description = "Parlot:Compiled:Large")]
- public double ParlotLargeCompiled() =>
- ParlotParsers.ExpressionParserCompiled.Parse(LargeExpression);
-
- [BenchmarkCategory("Small")]
- [Benchmark(Description = "Pidgin:Small")]
- public double PidginSmall()
- {
- var result = PidginParsers.ExpressionParser.Parse(SmallExpression);
- return result.Success ? result.Value : 0;
- }
-
- [BenchmarkCategory("Large")]
- [Benchmark(Description = "Pidgin:Large")]
- public double PidginLarge()
- {
- var result = PidginParsers.ExpressionParser.Parse(LargeExpression);
- return result.Success ? result.Value : 0;
- }
-}
+using System.Diagnostics.CodeAnalysis;
+
+using BenchmarkDotNet.Attributes;
+using BenchmarkDotNet.Configs;
+
+using Pidgin;
+
+using Ramstack.Parsing.Benchmarks.Parsers;
+
+namespace Ramstack.Parsing.Benchmarks;
+
+[MemoryDiagnoser]
+[OperationsPerSecond]
+[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]
+public class ExpressionBenchmark
+{
+ [SuppressMessage("ReSharper", "ArrangeRedundantParentheses")]
+ private const double Large = ((3.14159 * 2.3 * 4) / (1.5 - 0.3) + (2.71828 * 2.5)) * ((8.1 * 3.2 + 4.7) / 2.1 - ((15.7 + 2.3 * 4) / (1.5 - 0.3))) - (((3.5 * 1.41421) * (2.71828 + 3.14159)) / 2);
+ private const double Small = 2.5 * 4.7 - 8.1 / 3;
+
+ private const string SmallExpression = "2.5 * 4.7 - 8.1 / 3";
+ private const string LargeExpression = "(( 3.14159 * 2.3 * 4) / (1.5 - 0.3) + (2.71828 * 2.5) ) * ((8.1 * 3.2 + 4.7) / 2.1 - ((15.7 + 2.3 * 4) / (1.5 - 0.3))) - (((3.5 * 1.41421) * (2.71828 + 3.14159)) / 2)";
+
+ [GlobalSetup]
+ [SuppressMessage("ReSharper", "CompareOfFloatsByEqualityOperator")]
+ public void Setup()
+ {
+ if (RamstackParsers.ExpressionParser.Parse(SmallExpression).Value != Small) throw new Exception("Ramstack: Small");
+ if (RamstackParsers.ExpressionParser.Parse(LargeExpression).Value != Large) throw new Exception("Ramstack: Large");
+
+ if (ParlotParsers.ExpressionParser.Parse(SmallExpression) != Small) throw new Exception("Parlot: Small");
+ if (ParlotParsers.ExpressionParser.Parse(LargeExpression) != Large) throw new Exception("Parlot: Large");
+
+ if (PidginParsers.ExpressionParser.Parse(SmallExpression).Value != Small) throw new Exception("Pidgin: Small");
+ if (PidginParsers.ExpressionParser.Parse(LargeExpression).Value != Large) throw new Exception("Pidgin: Large");
+ }
+
+ [BenchmarkCategory("Small")]
+ [Benchmark(Description = "Ramstack:Small")]
+ public double RamstackSmall()
+ {
+ RamstackParsers.ExpressionParser.TryParse(SmallExpression, out var result);
+ return result;
+ }
+
+ [BenchmarkCategory("Small")]
+ [Benchmark(Description = "Ramstack:Diag:Small")]
+ public double RamstackSmall_Diagnostics() =>
+ RamstackParsers.ExpressionParser.Parse(SmallExpression).Value;
+
+ [BenchmarkCategory("Large")]
+ [Benchmark(Description = "Ramstack:Large")]
+ public double RamstackLarge()
+ {
+ RamstackParsers.ExpressionParser.TryParse(LargeExpression, out var result);
+ return result;
+ }
+
+ [BenchmarkCategory("Large")]
+ [Benchmark(Description = "Ramstack:Diag:Large")]
+ public double RamstackLarge_Diagnostics() =>
+ RamstackParsers.ExpressionParser.Parse(LargeExpression).Value;
+
+ [BenchmarkCategory("Small")]
+ [Benchmark(Description = "Parlot:Small")]
+ public double ParlotSmall() =>
+ ParlotParsers.ExpressionParser.Parse(SmallExpression);
+
+ [BenchmarkCategory("Small")]
+ [Benchmark(Description = "Parlot:Compiled:Small")]
+ public double ParlotSmallCompiled() =>
+ ParlotParsers.ExpressionParserCompiled.Parse(SmallExpression);
+
+ [BenchmarkCategory("Large")]
+ [Benchmark(Description = "Parlot:Large")]
+ public double ParlotLarge() =>
+ ParlotParsers.ExpressionParser.Parse(LargeExpression);
+
+ [BenchmarkCategory("Large")]
+ [Benchmark(Description = "Parlot:Compiled:Large")]
+ public double ParlotLargeCompiled() =>
+ ParlotParsers.ExpressionParserCompiled.Parse(LargeExpression);
+
+ [BenchmarkCategory("Small")]
+ [Benchmark(Description = "Pidgin:Small")]
+ public double PidginSmall()
+ {
+ var result = PidginParsers.ExpressionParser.Parse(SmallExpression);
+ return result.Success ? result.Value : 0;
+ }
+
+ [BenchmarkCategory("Large")]
+ [Benchmark(Description = "Pidgin:Large")]
+ public double PidginLarge()
+ {
+ var result = PidginParsers.ExpressionParser.Parse(LargeExpression);
+ return result.Success ? result.Value : 0;
+ }
+}
diff --git a/benchmarks/JsonBenchmark.cs b/benchmarks/JsonBenchmark.cs
index eeb92cd..31910be 100644
--- a/benchmarks/JsonBenchmark.cs
+++ b/benchmarks/JsonBenchmark.cs
@@ -1,60 +1,60 @@
-using BenchmarkDotNet.Attributes;
-
-using Ramstack.Parsing.Benchmarks.Parsers;
-
-namespace Ramstack.Parsing.Benchmarks;
-
-[MemoryDiagnoser]
-[OperationsPerSecond]
-public class JsonBenchmark
-{
- public static readonly string JsonBig = File.ReadAllText("Data/twitter.json");
- public static readonly string JsonMedium = File.ReadAllText("Data/medium.json");
- public static readonly string JsonSmall = File.ReadAllText("Data/small.json");
-
- public IEnumerable Source
- {
- get
- {
- yield return new JsonString(JsonSmall.TrimEnd(), "small");
- yield return new JsonString(JsonMedium.TrimEnd(), "medium");
- yield return new JsonString(JsonBig.TrimEnd(), "big");
- }
- }
-
- [ParamsSource(nameof(Source))]
- public JsonString Input { get; set; }
-
- [Benchmark(Description = "Ramstack")]
- public object? RamstackJson()
- {
- RamstackParsers.JsonParser.TryParse(Input.Value, out var result);
- return result;
- }
-
- [Benchmark(Description = "Parlot")]
- public object? ParlotJson() =>
- ParlotParsers.JsonParser.Parse(Input.Value);
-
- [Benchmark(Description = "Parlot:Compiled")]
- public object? ParlotJsonCompiled() =>
- ParlotParsers.JsonParserCompiled.Parse(Input.Value);
-
- [Benchmark(Description = "Pidgin")]
- public object? PidginJson() =>
- PidginParsers.JsonParser.Parse(Input.Value);
-
- [Benchmark(Description = "Newtonsoft.Json")]
- public object? NewtonsoftJson() =>
- Newtonsoft.Json.JsonConvert.DeserializeObject(Input.Value);
-
- [Benchmark(Description = "System.Text.Json")]
- public object? SystemTextJson() =>
- System.Text.Json.JsonSerializer.Deserialize