Installation:
composer require jakubledl/dissect
Add to composer.json under require or require-dev depending on your use case.
First Use Case:
Parse a simple arithmetic expression (e.g., "3 + 5 * 2"):
use Dissect\Lexer\Lexer;
use Dissect\Parser\Parser;
$lexer = new Lexer();
$tokens = $lexer->tokenize('3 + 5 * 2');
$parser = new Parser();
$ast = $parser->parse($tokens);
Where to Look First:
src/Dissect/Lexer/ for tokenization logic (e.g., Lexer.php, Token.php).src/Dissect/Parser/ for parsing rules (e.g., Parser.php, Node.php).Lexing:
Lexer or implementing TokenStream:
$lexer = new Lexer();
$lexer->addPattern('/\d+/', 'NUMBER'); // Custom token type
$tokens = $lexer->tokenize($input);
IDENTIFIER, STRING, OPERATOR).Parsing:
$parser = new Parser();
$ast = $parser->parse($tokens); // Returns a Node object
Parser to support custom grammars (e.g., for domain-specific languages).Integration with Laravel:
$lexer = new Lexer();
$tokens = $lexer->tokenize(request('query'));
if ($tokens->hasErrors()) {
return back()->withErrors(['query' => 'Invalid syntax']);
}
AST Traversal:
$ast->accept(new class implements NodeVisitor {
public function visit(Node $node) {
// Custom logic (e.g., code generation, optimization)
}
});
LexerException or ParserException:
try {
$ast = $parser->parse($tokens);
} catch (\Exception $e) {
report($e); // Log via Laravel's error handler
}
class QueryParserService {
public function parse(string $query): Node {
$lexer = new Lexer();
$parser = new Parser();
return $parser->parse($lexer->tokenize($query));
}
}
Performance:
Lexer instances).Recursive Descent Limits:
Parser::parseIterative() if available).xdebug.max_nesting_level (temporarily) during development.Token Ambiguity:
/=/ vs /==/) may cause unexpected tokens. Order matters:
$lexer->addPattern('/==/', 'EQUALS'); // Must come before /=/
$lexer->addPattern('/=/', 'ASSIGN');
AST Mutability:
$newAst = clone $ast;
$newAst->setChild(0, new NumberNode(42));
foreach ($tokens as $token) {
dump($token->getValue(), $token->getType());
}
$ast->accept(new class implements NodeVisitor {
public function visit(Node $node) {
info("Node: {$node->getClass()}, Value: {$node->getValue()}");
}
});
Lexer to support new languages:
class CustomLexer extends Lexer {
public function __construct() {
$this->addPattern('/#include\s+(.*)/', 'INCLUDE');
}
}
ParserInterface for domain-specific grammars:
class JsonParser implements ParserInterface {
public function parse(TokenStream $tokens) {
// Custom parsing logic
}
}
class CodeGeneratorVisitor implements NodeVisitor {
public function visit(Node $node) {
// Generate code from AST nodes
}
}
$this->app->singleton(Lexer::class, function () {
return new Lexer();
});
Lexer/Parser in unit tests:
$mockLexer = Mockery::mock(Lexer::class);
$mockLexer->shouldReceive('tokenize')->andReturn($tokens);
How can I help you explore Laravel packages today?