Superpower 3.2.2-dev-00214
dotnet add package Superpower --version 3.2.2-dev-00214
NuGet\Install-Package Superpower -Version 3.2.2-dev-00214
<PackageReference Include="Superpower" Version="3.2.2-dev-00214" />
<PackageVersion Include="Superpower" Version="3.2.2-dev-00214" />
<PackageReference Include="Superpower" />
paket add Superpower --version 3.2.2-dev-00214
#r "nuget: Superpower, 3.2.2-dev-00214"
#:package Superpower@3.2.2-dev-00214
#addin nuget:?package=Superpower&version=3.2.2-dev-00214&prerelease
#tool nuget:?package=Superpower&version=3.2.2-dev-00214&prerelease
Superpower 
A parser combinator library based on Sprache. Superpower generates friendlier error messages through its support for token-driven parsers.

What is Superpower?
The job of a parser is to take a sequence of characters as input, and produce a data structure that's easier
for a program to analyze, manipulate, or transform. From this point of view, a parser is just a function from string
to T - where T might be anything from a simple number, a list of fields in a data format, or the abstract syntax
tree of some kind of programming language.
Just like other kinds of functions, parsers can be built by hand, from scratch. This is-or-isn't a lot of fun, depending on the complexity of the parser you need to build (and how you plan to spend your next few dozen nights and weekends).
Superpower is a library for writing parsers in a declarative style that mirrors the structure of the target grammar. Parsers built with Superpower are fast, robust, and report precise and informative errors when invalid input is encountered.
Usage
Superpower is embedded directly into your C# program, without the need for any additional tools or build-time code generation tasks.
dotnet add package Superpower
The simplest text parsers consume characters directly from the source text:
// Parse any number of capital 'A's in a row
var parseA = Character.EqualTo('A').AtLeastOnce();
The Character.EqualTo() method is a built-in parser. The AtLeastOnce() method is a combinator, that builds a more
complex parser for a sequence of 'A' characters out of the simple parser for a single 'A'.
Superpower includes a library of simple parsers and combinators from which more sophisticated parsers can be built:
TextParser<string> identifier =
from first in Character.Letter
from rest in Character.LetterOrDigit.Or(Character.EqualTo('_')).Many()
select first + new string(rest);
var id = identifier.Parse("abc123");
Assert.Equal("abc123", id);
Parsers are highly modular, so smaller parsers can be built and tested independently of the larger parsers that use them.
Tokenization
Along with text parsers that consume input character-by-character, Superpower supports token parsers.
A token parser consumes elements from a list of tokens. A token is a fragment of the input text, tagged with the
kind of item that fragment represents - usually specified using an enum:
public enum ArithmeticExpressionToken
{
None,
Number,
Plus,
A major benefit of driving parsing from tokens, instead of individual characters, is that errors can be reported in terms of tokens - unexpected identifier `frm`, expected keyword `from` - instead of the cryptic unexpected `m`.
Token-driven parsing takes place in two distinct steps:
- Tokenization, using a class derived from
Tokenizer<TKind>, then - Parsing, using a function of type
TokenListParser<TKind>.
var expression = "1 * (2 + 3)";
// 1.
var tokenizer = new ArithmeticExpressionTokenizer();
var tokenList = tokenizer.Tokenize(expression);
// 2.
var parser = ArithmeticExpressionParser.Lambda; // parser built with combinators
var expressionTree = parser.Parse(tokenList);
// Use the result
var eval = expressionTree.Compile();
Console.WriteLine(eval()); // -> 5
Assembling tokenizers with TokenizerBuilder<TKind>
The job of a tokenizer is to split the input into a list of tokens - numbers, keywords, identifiers, operators - while discarding irrelevant trivia such as whitespace or comments.
Superpower provides the TokenizerBuilder<TKind> class to quickly assemble tokenizers from recognizers,
text parsers that match the various kinds of tokens required by the grammar.
A simple arithmetic expression tokenizer is shown below:
var tokenizer = new TokenizerBuilder<ArithmeticExpressionToken>()
.Ignore(Span.WhiteSpace)
.Match(Character.EqualTo('+'), ArithmeticExpressionToken.Plus)
.Match(Character.EqualTo('-'), ArithmeticExpressionToken.Minus)
.Match(Character.EqualTo('*'), ArithmeticExpressionToken.Times)
.Match(Character.EqualTo('/'), ArithmeticExpressionToken.Divide)
.Match(Character.EqualTo('('), ArithmeticExpressionToken.LParen)
.Match(Character.EqualTo(')'), ArithmeticExpressionToken.RParen)
.Match(Numerics.Natural, ArithmeticExpressionToken.Number)
.Build();
Tokenizers constructed this way produce a list of tokens by repeatedly attempting to match recognizers against the input in top-to-bottom order.
Writing tokenizers by hand
Tokenizers can alternatively be written by hand; this can provide the most flexibility, performance, and control, at the expense of more complicated code. A handwritten arithmetic expression tokenizer is included in the test suite, and a more complete example can be found here.
Writing token list parsers
Token parsers are defined in the same manner as text parsers, using combinators to build up more sophisticated parsers out of simpler ones.
class ArithmeticExpressionParser
{
static readonly TokenListParser<ArithmeticExpressionToken, ExpressionType> Add =
Token.EqualTo(ArithmeticExpressionToken.Plus).Value(ExpressionType.AddChecked);
static readonly TokenListParser<ArithmeticExpressionToken, ExpressionType> Subtract =
Token.EqualTo(ArithmeticExpressionToken.Minus).Value(ExpressionType.SubtractChecked);
static readonly TokenListParser<ArithmeticExpressionToken, ExpressionType> Multiply =
Token.EqualTo(ArithmeticExpressionToken.Times).Value(ExpressionType.MultiplyChecked);
static readonly TokenListParser<ArithmeticExpressionToken, ExpressionType> Divide =
Token.EqualTo(ArithmeticExpressionToken.Divide).Value(ExpressionType.Divide);
static readonly TokenListParser<ArithmeticExpressionToken, Expression> Constant =
Token.EqualTo(ArithmeticExpressionToken.Number)
.Apply(Numerics.IntegerInt32)
.Select(n => (Expression)Expression.Constant(n));
static readonly TokenListParser<ArithmeticExpressionToken, Expression> Factor =
(from lparen in Token.EqualTo(ArithmeticExpressionToken.LParen)
from expr in Parse.Ref(() => Expr)
from rparen in Token.EqualTo(ArithmeticExpressionToken.RParen)
select expr)
.Or(Constant);
static readonly TokenListParser<ArithmeticExpressionToken, Expression> Operand =
(from sign in Token.EqualTo(ArithmeticExpressionToken.Minus)
from factor in Factor
select (Expression)Expression.Negate(factor))
.Or(Factor).Named("expression");
static readonly TokenListParser<ArithmeticExpressionToken, Expression> Term =
Parse.Chain(Multiply.Or(Divide), Operand, Expression.MakeBinary);
static readonly TokenListParser<ArithmeticExpressionToken, Expression> Expr =
Parse.Chain(Add.Or(Subtract), Term, Expression.MakeBinary);
public static readonly TokenListParser<ArithmeticExpressionToken, Expression<Func<int>>>
Lambda = Expr.AtEnd().Select(body => Expression.Lambda<Func<int>>(body));
}
Error messages
The error scenario tests demonstrate some of the error message formatting capabilities of Superpower. Check out the parsers referenced in the tests for some examples.
ArithmeticExpressionParser.Lambda.Parse(new ArithmeticExpressionTokenizer().Tokenize("1 + * 3"));
// -> Syntax error (line 1, column 5): unexpected operator `*`, expected expression.
To improve the error reporting for a particular token type, apply the [Token] attribute:
public enum ArithmeticExpressionToken
{
None,
Number,
[Token(Category = "operator", Example = "+")]
Plus,
Performance
Superpower is built with performance as a priority. Less frequent backtracking, combined with the avoidance of allocations and indirect dispatch, mean that Superpower can be quite a bit faster than Sprache.
Recent benchmark for parsing a long arithmetic expression:
Host Process Environment Information:
BenchmarkDotNet.Core=v0.9.9.0
OS=Windows
Processor=?, ProcessorCount=8
Frequency=2533306 ticks, Resolution=394.7411 ns, Timer=TSC
CLR=CORE, Arch=64-bit ? [RyuJIT]
GC=Concurrent Workstation
dotnet cli version: 1.0.0-preview2-003121
Type=ArithmeticExpressionBenchmark Mode=Throughput
| Method | Median | StdDev | Scaled | Scaled-SD |
|---|---|---|---|---|
| Sprache | 283.8618 µs | 10.0276 µs | 1.00 | 0.00 |
| Superpower (Token) | 81.1563 µs | 2.8775 µs | 0.29 | 0.01 |
Benchmarks and results are included in the repository.
Tips: if you find you need more throughput: 1) consider a hand-written tokenizer, and 2) avoid the use of LINQ comprehensions and instead use chained combinators like Then() and especially IgnoreThen() - these allocate fewer delegates (closures) during parsing.
Examples
Superpower is introduced, with a worked example, in this blog post.
Example parsers to learn from:
- JsonParser is a complete, annotated example implementing the JSON spec with good error reporting
- DateTimeTextParser shows how Superpower's text parsers work, parsing ISO-8601 date-times
- IntCalc is a simple arithmetic expresion parser (
1 + 2 * 3) included in the repository, demonstrating how Superpower token parsing works - Plotty implements an instruction set for a RISC virtual machine
- tcalc is an example expression language that computes durations (
1d / 12m)
Real-world projects built with Superpower:
- Serilog.Expressions uses Superpower to implement an expression and templating language for structured log events
- The query language of Seq is implemented using Superpower
seqcliextraction patterns use Superpower for plain-text log parsing- PromQL.Parser is a parser for the Prometheus Query Language
Have an example we can add to this list? Let us know.
Getting help
Please post issues to the issue tracker, or tag your question on StackOverflow with superpower.
The repository's title arose out of a talk "Parsing Text: the Programming Superpower You Need at Your Fingertips" given at DDD Brisbane 2015.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- System.Memory (>= 4.6.3)
-
net6.0
- No dependencies.
-
net8.0
- No dependencies.
NuGet packages (46)
Showing the top 5 NuGet packages that depend on Superpower:
| Package | Downloads |
|---|---|
|
Serilog.Filters.Expressions
Expression-based event filtering for Serilog. |
|
|
DotNetEnv
A .NET library to load environment variables from .env files |
|
|
OctoNotes.Generator.ReleaseNotesSource.GitHub
OctoNotes is a tool for generating release notes from Git repositories. In a perfect, trunk-based world, there would be a single, linear graph between versions of an application. In the real world, however, that's almost never the case. Many releases will have hotfixes; many applications will have LTS branches or maintenance releases; not to mention pull requests and other reasons for branches, both short-lived and long. OctoNotes takes a slightly different view of release notes. OctoNotes views the Git revision graph as the single source of truth. If a bug was fixed in a commit, that bug is only fixed in revisions containing that commit. If a feature was added between versions X and Y, it will appear in the Git revision graph as a commit somwehere between those two points. By leveraging Git tags, OctoNotes can pinpoint precisely where in a Git revision graph a change was introduced, and provide the release notes for just the commits between two points on that graph. |
|
|
SelectParser
Package Description |
|
|
Octopus.OctoNotes.Generator.ReleaseNotesSource.GitHub
OctoNotes is a tool for generating release notes from Git repositories. In a perfect, trunk-based world, there would be a single, linear graph between versions of an application. In the real world, however, that's almost never the case. Many releases will have hotfixes; many applications will have LTS branches or maintenance releases; not to mention pull requests and other reasons for branches, both short-lived and long. OctoNotes takes a slightly different view of release notes. OctoNotes views the Git revision graph as the single source of truth. If a bug was fixed in a commit, that bug is only fixed in revisions containing that commit. If a feature was added between versions X and Y, it will appear in the Git revision graph as a commit somwehere between those two points. By leveraging Git tags, OctoNotes can pinpoint precisely where in a Git revision graph a change was introduced, and provide the release notes for just the commits between two points on that graph. |
GitHub repositories (18)
Showing the top 18 popular GitHub repositories that depend on Superpower:
| Repository | Stars |
|---|---|
|
Tyrrrz/DiscordChatExporter
Saves Discord chat logs to a file
|
|
|
velopack/velopack
Installer and automatic update framework for cross-platform desktop applications
|
|
|
tonybaloney/CSnakes
Embed Python in .NET
|
|
|
benjamin-hodgson/Pidgin
A lightweight and fast parsing library for C#.
|
|
|
WOA-Project/WOA-Deployer-Rpi
WOA Deployer for Raspberry Pi
|
|
|
moq/labs
The most popular and friendly mocking framework for .NET
|
|
|
tonerdo/dotnet-env
A .NET library to load environment variables from .env files
|
|
|
sebastienros/parlot
Fast and lightweight parser creation tools
|
|
|
LANCommander/LANCommander
|
|
|
Suchiman/SerilogAnalyzer
Roslyn-based analysis for code using the Serilog logging library. Checks for common mistakes and usage problems.
|
|
|
patriksvensson/ghostly
Ghostly is a GitHub notification client for Windows 10/11
|
|
|
daohainam/mini-web-server
A simple but full-featured web server, supports HTTP/1, HTTP/2, MVC, API, Authentication, Authorization...
|
|
|
csinkers/ualbion
A remake of the 1995 RPG Albion (requires data from an install of the original game)
|
|
|
datalust/seqcli
The Seq command-line client. Administer, log, ingest, search, from any OS.
|
|
|
madewokherd/xalia
Service adding gamepad UI to traditional desktop applications
|
|
|
devlooped/avatar
A modern compile-time generated interception/proxy library
|
|
|
surrealdb/surrealdb.net
SurrealDB SDK for .NET
|
|
|
Shazwazza/UmbracoIdentity
ASP.NET Identity implementation for Umbraco's native member data
|
| Version | Downloads | Last Updated |
|---|---|---|
| 3.2.2-dev-00214 | 30 | 5/20/2026 |
| 3.2.1 | 29,586 | 4/29/2026 |
| 3.2.1-dev-00211 | 133 | 4/29/2026 |
| 3.2.1-dev-00210 | 116 | 4/28/2026 |
| 3.2.0 | 7,153 | 4/27/2026 |
| 3.2.0-dev-00207 | 119 | 4/27/2026 |
| 3.2.0-dev-00206 | 101 | 4/27/2026 |
| 3.2.0-dev-00204 | 102 | 4/27/2026 |
| 3.2.0-dev-00203 | 112 | 4/27/2026 |
| 3.1.1-dev-00257 | 1,646 | 9/7/2025 |
| 3.1.1-dev-00201 | 114 | 4/25/2026 |
| 3.1.0 | 391,463 | 6/18/2025 |
| 3.1.0-dev-00250 | 276 | 6/18/2025 |
| 3.1.0-dev-00247 | 1,540 | 9/30/2024 |
| 3.1.0-dev-00245 | 351 | 9/4/2024 |
| 3.1.0-dev-00241 | 913 | 6/12/2024 |
| 3.1.0-dev-00239 | 461 | 6/10/2024 |
| 3.0.0-dev-00236 | 1,009 | 6/23/2022 |
| 3.0.0-dev-00233 | 1,190 | 1/26/2022 |
| 3.0.0-dev-00231 | 930 | 12/24/2021 |