Golang parser combinator library inspired by haskell parsec.
But what is parser combinator?
In the parse combinatorial framework, a "parser" is a function that takes some semistructured input and produces some structured output, and "combinator" is a function that allows combining / composing things. So "parser combinators" is a way of expressing a system where you write a lot of small parsing functions and compose then together.
Requires Go 1.26 or newer.
go get github.com/okneniz/parsecpackage main
import (
"fmt"
"github.com/okneniz/parsec/strings"
)
func main() {
// parse an unsigned integer, allowing surrounding whitespaces
parser := strings.Padded(
strings.Try(strings.Space("whitespace")),
strings.Unsigned[int](),
)
result, err := strings.ParseString(" 42 ", parser)
fmt.Println(result, err) // 42 <nil>
}Small parsing functions are combined into bigger ones: Padded wraps Unsigned
with optional whitespace skipping, Try makes backtracking possible, and
ParseString feeds the input text through the resulting combinator.
The root package is the generic core: the Combinator function type,
the Buffer input abstraction, parse errors with positions, and every
combinator implemented once for an arbitrary item type. The satellite
packages build on it:
| Package | Purpose |
|---|---|
| parsec | generic core: combinators, buffers, errors |
| parsec/strings | rune input, line/column positions, text helpers |
| parsec/bytes | binary input, big/little-endian readers |
| parsec/tokens | token streams for two-stage parsers |
| parsec/lang | lexers and expression machinery from a declarative Definition |
Greedy combinators (Satisfy, Eq, Range, OneOf and others) consume one input item even when they fail. Combinators that try alternatives (Choice, Or) or repeat parsing in a loop (Many and similar) do not restore the buffer position on their own. So whenever a combinator can fail inside such a branch, wrap it in Try — it is the backtracking primitive that rewinds the buffer on failure:
choice := strings.Choice(
"expected number or parens",
strings.Try(parseNumber()),
strings.Try(strings.Parens(parseExpr)),
)- text
- json
- xml - a streaming SAX parser: the document is a lazy
iter.Seq2of events, one combinator step per event, with a shape-checkingParseon top - timestamps
- credit cards
- binary
- lang
- tiny ml - a minimal Standard ML dialect (let, recursive functions, if-then-else, numbers and booleans): the two-stage parsing pipeline in miniature, with a Hindley-Milner typechecker and an interpreter on top
- assembly - low-level toolkit to assemble and disassemble machine code (ARM64, RISC-V, LoongArch); its self-contained ELF and Mach-O container parsers are built with parsec.
- cliche - regular expressions engine for batch processing; it compiles many patterns into a shared tree and matches them in a single pass, with regex syntax parsed by parsec.
make test # run all tests
make lint # format code and run golangci-lint + style checks
make fmt # format code only
Formatting conventions beyond gofmt, enforced by make lint:
no one-line function bodies, and a blank line between declarations.The linter version is pinned in go.mod as a Go tool dependency, so make lint uses exactly the same version locally and in CI. To bump it:
make install-linter # or: go get -tool github.com/golangci/golangci-lint/v2/cmd/golangci-lint@<version>See the open issues for a list of proposed features (and known issues).
Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are greatly appreciated.
- If you have suggestions for adding or removing projects, feel free to open an issue to discuss it, or directly create a pull request after you edit the README.md file with necessary changes.
- Please make sure you check your spelling and grammar.
- Create individual PR for each suggestion.
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature) - Commit your Changes (
git commit -m 'Add some AmazingFeature') - Push to the Branch (
git push origin feature/AmazingFeature) - Open a Pull Request