Skip to content

C#

The C# target generates a standalone partial PTParser class for .NET 8 projects with nullable reference types enabled.

Minimal working example

Create a console project in an empty directory:

powershell
dotnet new console --framework net8.0

Keep the generated project file, create identifier.peg, and replace Program.cs with the content below. Parser.cs is generated by pegtool.

identifier.peg

peg
Start = value:<Identifier> !. { return value; }
Identifier = [\pL_] [\pL\p{Nd}_]*

Program.cs

csharp
var value = (string)PTParser.Parse("name_世界")!;
Console.WriteLine(value);

Generate and run it:

powershell
pegtool -t cs -o Parser.cs identifier.peg
dotnet run

Output:

text
name_世界

Public API

PTParser.Parse returns object?. On failure it throws PTParseException, which contains Position and Expected. A complete options call looks like:

csharp
var value = PTParser.Parse(source, new PTParser.ParserOptions
{
    Filename = "input.txt",
    Entrypoint = "Start",
    MaxExpressions = 1_000_000,
    CustomData = context,
});

Initializers and actions

The C# initializer is placed inside the generated partial PTParser class. Declare nested types, fields, and helper methods there, not namespaces or top-level statements:

peg
{
private static int ToInteger(string text) => int.Parse(text);
}

Integer = [0-9]+ { return ToInteger(c.Text); }

Labels have type object?. When a PEG label is also a C# keyword, generated actions use a verbatim identifier. For example, access the label operator as @operator.

Allocation behavior

The current runtime does not create a List<object?> for an ordinary sequence. Repetition allocates a result collection only when its child returns a non-null value. In tests, an action-free long-repetition workload was about 18%-19% faster than the old implementation, and useless collection allocations remained essentially constant as input length increased. This optimization is automatic and needs no additional option.

-optimize-parser currently has no C#-specific effect. Rule indexing still carries a diff-stability cost; use the performance guide to decide.

Released under the BSD 3-Clause License