Dart
Rumil
0.10.0Parser combinators with lossless syntax trees
A parser combinator library that represents parsers as data, not functions. You describe what to parse; a separate interpreter handles backtracking, operator precedence, and error reporting. Because parsers are values, left-recursive grammars work without rewriting, and deep input stays stack-safe, bounded by memory rather than the call stack. Beyond a parse result, rumil can produce lossless green/red syntax trees with resilient error recovery and incremental reparse, so language tooling can keep a tree in sync as the source is edited.
Examples
Parsers are values you compose, not functions you call
final id = letter & (letter | digit).many;
final assign = id & char('=').trim & expr;
final result = assign.parse('x = 42');
Left-recursive grammars work directly
final expr = rule(() =>
expr.zip(char('+').trim).zip(term).map(add)
| term
);
Parse real formats with rumil_parsers
import 'package:rumil_parsers/rumil_parsers.dart';
final yaml = parseYaml('name: rumil\nversion: 0.10.0');
final json = parseJson('{"key": [1, 2, 3]}');
final toml = parseToml('[server]\nport = 8080');
final csv = parseCsv('name,age\nAlice,30\nBob,25');
Three-way results. Success, partial, or failure
final result = parser.run(input);
switch (result) {
case Success(:final value):
print(value);
case Partial(:final value, :final errors):
print('$value (with ${errors.length} warnings)');
case Failure(:final errors):
print('Failed: $errors');
}
Typed decoders turn ASTs into Dart objects
final config = parseYaml(source).decode(
field('host', string) &
field('port', integer) &
field('debug', boolean),
);
Features
Lossless green/red syntax trees with resilient recovery and incremental reparse
Operator precedence through `pratt`, a Pratt parser expressed as a combinator
Stack-safe to arbitrary depth, bounded by memory rather than the call stack
Success, Partial, Failure. Error recovery is part of the result type
Paired with rumil_parsers (JSON, YAML, TOML, XML, CSV, HCL, Proto3, Markdown) and rumil_tokens
Packages
6 packages, all at 0.10.0.
Core combinator framework
The parser combinator library at the foundation. Parsers are a sealed type. You build them from combinators, and an external interpreter runs them. The interpreter handles backtracking, memoization, and the Warth seed-growth algorithm for left recursion. Errors carry source locations. Nothing executes until you ask it to.
- Left recursion via the Warth seed-growth algorithm
- Typed errors with line, column, and offset
- Stack-safe to arbitrary depth via defunctionalized trampolining
Format parsers and serializers
Parsers and serializers for JSON, CSV, XML, TOML, YAML, Proto3, and HCL, built on the core combinators. Each format produces a typed AST. You can parse a file, transform the tree, and serialize it back. Tested against the official conformance suite for every format that has one.
- Seven formats, each with a typed AST
- Round-trip parsing and serialization
- Typed encoders for converting Dart objects to format ASTs
- Conformance-tested against RFC and spec suites
Lossless source tokenizer
A lossless tokenizer for source code, built on the core combinators. It classifies spans into tokens for syntax highlighting, and concatenating the spans reproduces the input exactly. Ships with grammars for Dart, Scala, YAML, JSON, and shell.
- Classified, position-tracked token spans
- Lossless. The token spans reconstruct the source byte for byte
- Built-in grammars for Dart, Scala, YAML, JSON, and shell
Formula evaluation
A formula evaluator built on the core combinators. Parses expressions into a typed AST that you can inspect or transform before evaluating. Supports arithmetic, comparisons, boolean logic, string operations, variables, and custom functions.
- Typed expression AST, available before evaluation
- User-defined variables and custom functions
- Source-accurate error locations
Binary serialization
Binary codecs for encoding and decoding Dart values. Small codecs for primitives compose into codecs for complex types using Dart records. One definition handles both directions.
- Compose codecs from primitives to complex types
- Encode and decode with the same definition
- ZigZag and LEB128 variable-length encoding
Code generation for binary codecs
Derives binary codec implementations from annotated Dart classes at build time. Handles sealed class hierarchies and enums. Runs through standard Dart build_runner.
- Derive codecs from annotated classes
- Sealed class and enum support
- Standard build_runner integration