A C# port of the Acorn JavaScript parser, targeting .NET 10. It parses JavaScript/ECMAScript source into ESTree-compatible abstract syntax trees — the same trees the original JavaScript library produces.
This is a fork/port. The original JavaScript sources are kept in the repository
root (acorn/, acorn-loose/, acorn-walk/) so the port can be kept in sync
with upstream; all C# code lives under dotnet/.
| Package | Description |
|---|---|
Acorn |
The main parser and tokenizer. |
Acorn.Loose |
An error-tolerant parser that repairs broken input. |
Acorn.Walk |
A syntax-tree walker for ESTree trees. |
using Acorn;
// Parse a whole program
var options = new Options { EcmaVersion = 2020, Locations = true };
Node ast = Parser.ParseStatic("let answer = 6 * 7;", options);
Console.WriteLine(ast.Type); // "Program"
var body = (List<object?>)ast["body"]!;
var decl = (Node)body[0]!;
Console.WriteLine(decl.Type); // "VariableDeclaration"
// Parse a single expression at an offset
Node expr = Parser.ParseExpressionAt("1 + 2", 0, new Options { EcmaVersion = 2020 });
// Tokenize
var tokenizer = Parser.Tokenizer("a + b", new Options { EcmaVersion = 2020 });
for (Token t = tokenizer.GetToken(); t.Type != TokenTypes.Eof; t = tokenizer.GetToken())
Console.WriteLine($"{t.Type.Label} {t.Start}..{t.End}");Acorn.Options mirrors the JavaScript options: EcmaVersion (an int such as
5, 2015, 2020, or Options.Latest), SourceType ("script",
"module", "commonjs"), Locations, Ranges, PreserveParens,
AllowReturnOutsideFunction, AllowImportExportEverywhere,
AllowAwaitOutsideFunction, AllowReserved, OnComment, OnToken, and more.
Because acorn assigns node properties dynamically, Node is a property bag:
Type, Start, End, Loc, Range are strongly-typed members; all other
properties are reached through the string indexer, e.g. node["name"],
node["body"], node["value"]. Child arrays are List<object?>; nested
locations are SourceLocation/Position.
using Acorn.Loose;
Node ast = AcornLoose.Parse("foo(", new Options { EcmaVersion = 2020 });
// Produces a best-effort tree instead of throwing.using Acorn.Walk;
AstWalker.Simple(ast, new Dictionary<string, Action<Node, object?>>
{
["CallExpression"] = (node, state) => Console.WriteLine("call at " + node.Start)
});cd dotnet
dotnet build Acorn.sln -c Release
dotnet test test/Acorn.Tests/Acorn.Tests.csprojThe test suite runs the C# parser against 3530 conformance cases generated
from acorn's own JavaScript test suite (see ../CLAUDE.md for how). To
regenerate the fixtures after an upstream sync:
node tools/gen-fixtures.jsMIT, the same as upstream Acorn. See ../acorn/LICENSE.