goaop/dissect
A set of tools for lexical and syntactical analysis written in pure PHP
Maintainers
Fund package maintenance!
Requires
- php: ^8.4.0
Requires (Dev)
- phpstan/phpstan: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- phpunit/phpunit: ^13.0
- rector/rector: ^2.0
- symfony/console: ^7.4 || ^8.0
Suggests
- symfony/console: for the command-line tool
Provides
None
Conflicts
None
Replaces
None
MIT b37e69cebd2c4f4359371a7d98b349f3983ebcdf
- Jakub Lรฉdl <jakubledl.woop@gmail.com>
- WalterWoshid <wotschel.valentin.woop@googlemail.com>
This package is auto-updated.
Last update: 2026-05-27 23:26:53 UTC
README
A pure-PHP toolkit for building custom lexers and LALR(1) parsers โ fast, type-safe, and dependency-free.
๐ GitHub Actions Workflow Status
๐ PHPStan Badge
๐ Total Downloads
๐ Daily Downloads
๐ PHP Version
๐ GitHub License
๐ Sponsor
โจ What is Dissect?
Dissect is a pure-PHP library for lexical and syntactical analysis โ the foundational building blocks for any language tooling: expression evaluators, template engines, DSL interpreters, query parsers, and more.
It powers the GoAOP framework, where it parses pointcut DSL expressions into an AST for aspect-oriented programming.
Data flow
Input String
โ
โผ
โโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ
โ Lexer โ โโโโถ โ TokenStream โ โโโโถ โ LALR(1) Parser โ โโโโถ Result / AST
โโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ
โฒ
Grammar (rules
+ callbacks)
๐ Key Features
๐ค Flexible Lexers
| Lexer | Description |
|---|---|
SimpleLexer |
Fluent builder API โ define tokens with strings or regex, mark skippable tokens |
StatefulLexer |
Context-aware tokenization with explicit state transitions (e.g. for string interpolation) |
RegexLexer |
Abstract base class adapted from Doctrine โ ultra-fast single-pass regex lexing |
๐ LALR(1) Parser
- Full LALR(1) grammar support โ handles the vast majority of real-world grammars
- Fluent grammar API โ define productions and semantic actions with readable PHP closures
- Operator precedence & associativity โ built-in
left(),right(),nonassoc()declarations - Conflict resolution โ configurable strategies: shift-wins, longer-reduce, earlier-reduce
- Precomputed parse tables โ analyze once, serialize to PHP file, load instantly in production
๐ณ AST Construction
CommonNodeโ ready-to-use tree node with named children and arbitrary attributes- Countable & iterable โ traverse subtrees with standard PHP constructs
๐ Developer Experience
- Zero runtime dependencies โ only Symfony Console as an optional CLI dep
- PHPStan level 10 โ fully typed with generics, array shapes, and readonly properties
- CLI tool โ dump parse tables and visualize automaton states as Graphviz graphs
๐ฆ Installation
composer require goaop/dissect
โก Quick Example
use Dissect\Lexer\SimpleLexer; use Dissect\Parser\Grammar; use Dissect\Parser\LALR1\Parser; // 1. Define a lexer $lexer = new SimpleLexer(); $lexer->regex('INT', '/[0-9]+/') ->token('PLUS', '+') ->token('MINUS', '-') ->regex('WS', '/\s+/') ->skip('WS'); // 2. Define a grammar $grammar = new Grammar(); $grammar('Expr') ->is('Expr', 'PLUS', 'Expr') ->call(fn($l, $_, $r) => $l + $r) ->is('Expr', 'MINUS', 'Expr') ->call(fn($l, $_, $r) => $l - $r) ->is('INT') ->call(fn($t) => (int) $t->getValue()); $grammar->operators('PLUS', 'MINUS')->left()->prec(1); $grammar->start('Expr'); // 3. Parse! $parser = new Parser($grammar); $result = $parser->parse($lexer->lex('3 + 5 - 2')); // โ 6
๐ Documentation
| Topic | Description |
|---|---|
| Lexical analysis | SimpleLexer, StatefulLexer, RegexLexer, performance tips |
| Writing a grammar | Productions, callbacks, operator precedence, conflict resolution |
| Building an AST | CommonNode, tree traversal |
| Common patterns | Lists, comma-separated sequences, expression grammars |
| CLI tool | Precomputing parse tables, exporting automaton graphs |
๐งช Testing & Quality
# Run tests composer test # Run tests with coverage composer test-coverage # Static analysis (PHPStan level 10) composer phpstan
๐ Credits
Originally created by @jakubledl, extended by @WalterWoshid, maintained by the GoAOP team.
Give a โญ if Dissect saved you from writing a parser by hand!
