Participle

A dead-simple Go library for building parsers straight from annotated struct tags.

Library
Go
vv2.1.4
3,882stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
68/100Good
Development Activity68
Maintenance36
Community68
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
77/100Good
Architecture80
Code Quality88
Innovation85
Learning Curve55

Participle lets Go developers define a grammar as a plain annotated struct and get a working parser for free, with no separate grammar file, code generator, or hand-rolled parser-combinator boilerplate required. Struct tags describe an EBNF-like grammar, and parsing directly populates an AST of your own Go types, much like encoding/json unmarshals JSON into a struct.

Version 2 targets Go generics (participle.Build[G]), ships a configurable stateful lexer for handling nested or interpolated tokens, and supports advanced grammar features like union types, custom Capture/Parseable interfaces, positive/negative lookahead, and detailed positional error reporting, making it a practical choice for building DSLs, config-file parsers, and small custom languages entirely in Go.

What You Get

  • Struct-tag grammars - Define an EBNF-like grammar directly in Go struct tags and parse straight into typed AST nodes.
  • Generics-based API - participle.Build[G] and MustBuild[G] construct a fully typed Parser[G] for your grammar type.
  • Configurable lexing - Ships with a default text/scanner-based lexer, or drop in the built-in stateful/modal lexer for nested or interpolated tokens.
  • Union type support - Model sum types with participle.Union[T], trying each member production in declaration order.
  • Custom capture hooks - Implement Capture, Parseable, or ParseTypeWith to hand-roll parsing for individual fields or productions.
  • Detailed error reporting - Parse errors report the deepest failure position reached during backtracking, not just the first mismatch.

Common Use Cases

  • Domain-specific languages - Parsing custom DSLs (query languages, expression languages, config formats) directly into Go structs.
  • Config file formats - Building parsers for INI-like, HCL-like, or bespoke configuration syntaxes.
  • Toy and teaching languages - Prototyping small interpreters and compilers, as shown in the repo’s SQL, GraphQL, Thrift, and TOML example parsers.
  • Structured query parsing - Parsing structured query-style grammars such as JSONPath expressions or precedence-climbing arithmetic.

Under The Hood

Architecture The parser is built via a two-phase pipeline: Build[G] (parser.go) walks the target grammar type G via reflection inside a generatorContext (grammar.go/context.go), constructing a tree of node implementations (nodes.go, struct.go) that mirror the struct-tag EBNF, and validate.go checks the resulting node tree for well-formedness before parsing begins. At parse time, ParseFromLexer drives tokens from a lexer.PeekingLexer through a parseContext (context.go) into that node tree, which recursively populates the target struct via reflect.Value, while error.go tracks the “deepest” failure position across backtracking branches for reporting, and disjunction-style nodes implement Union[T] alternation. Lexing (the lexer package’s pluggable Definition/Lexer/PeekingLexer interfaces) is cleanly separated from grammar-tree construction (grammar.go) and tree execution (nodes.go), though the design keeps coupling non-trivial: changing the core node interface ripples through nodes.go, struct.go, grammar.go, and validate.go simultaneously.

Tech Stack A pure Go module (go.mod declares go 1.24) with only two direct third-party dependencies — github.com/alecthomas/assert/v2 (test assertions) and github.com/alecthomas/repr (pretty-printing used in tests and tutorials) — plus github.com/hexops/gotextdiff as an indirect test dependency; there are no runtime dependencies beyond the standard library (text/scanner, regexp, reflect). Lexing defaults to a text/scanner-based lexer with an optional hand-rolled stateful/modal lexer built on compiled regexp.Regexp state machines, plus a lower-level lexer/internal package. A companion cmd/participle Go module hosts a small code-generation CLI for compiling stateful lexers ahead of time, and cmd/railroad renders grammars to railroad-diagram assets. Release tooling uses Hermit for toolchain pinning and GoReleaser for release artifacts.

Code Quality The repo carries an extensive test suite (33 _test.go files across the root, lexer, and ebnf packages, with parser_test.go alone covering capture semantics, lookahead, error messages, unions, and stateful lexing), using assert/v2 for assertions. A separate _examples/ module is exercised end-to-end by CI’s dedicated “Test Examples” step, giving executable documentation for real grammars (SQL, GraphQL, Thrift, TOML, JSONPath). Error handling is explicit and typed, with dedicated Error/ParseError/UnexpectedTokenError types carrying position info, and CI runs both go test ./... and a golangci-lint job driven by an extensive lint configuration.

API Design The public API is small and idiomatic: a single generic entry point (Build[G]/MustBuild[G]) turns any annotated Go struct into a typed Parser[G], so the grammar and the AST are the same type, mirroring encoding/json’s tag-based approach that Go developers already know. Getting started requires no boilerplate beyond defining the struct and calling Build; advanced needs (custom captures, union types, custom lexers, case-insensitivity) are opt-in via a compact, well-documented functional-options set rather than expanding the core surface. Naming is consistent across Parse/ParseString/ParseBytes/ParseFromLexer, and documentation is strong, with a dedicated tutorial walking through building an INI parser end-to-end and a wide range of worked examples covering realistic grammars.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search