md / syn
A high-level parser combinator based PHP preprocessor with macro system
Requires
- php: ^8.2 || ^8.3 || ^8.4 || ^8.5
- nikic/php-parser: ^5.0
- symfony/console: ^7.0
- symfony/finder: ^7.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.0
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^11
This package is not auto-updated.
Last update: 2026-08-03 19:50:22 UTC
README
Syn is a high-level parser combinator based PHP preprocessor that allows developers to augment PHP with custom syntax through macros. Language features can be distributed as Composer packages, as long as the macro-based implementations can be expressed in pure PHP code and are fast enough.
Features
- Parser Combinator Based: Built on robust parser combinators for reliable syntax parsing
- Macro System: Define custom syntax rules that transform into valid PHP
- Composer Integration: Distribute language features as packages
- Plugin System: Extend Syn with custom rule evaluators
- Line Number Preservation: Maintain debugging information through transformations
- Clear Error Messages: Helpful diagnostics for invalid syntax
- CLI Tool: Command-line interface for preprocessing files
Installation
composer require md/syn
Quick Start
1. Create a Macro File
Create a .syn file with your custom syntax rules:
// macros.syn $(macro) { unless ($(layer() as condition)) { $(layer() as body) } } >> { if (!($(condition))) { $(body) } } $(macro) { __swap($(T_VARIABLE as a), $(T_VARIABLE as b)) } >> { (list($(a), $(b)) = [$(b), $(a)]) }
2. Use Custom Syntax
Write PHP files with your custom syntax:
// example.syn.php <?php class Example { public function test() { unless ($x === 1) { echo "x is not 1"; } __swap($foo, $bar); } }
3. Compile with Sync
sync example.syn.php --macro-dir=./macros --out=./output
This will generate valid PHP code in the output directory.
CLI Usage
The sync command-line tool provides various options for preprocessing files:
# Basic usage sync input.syn.php --out=output.php # Process directory with macro definitions sync src/ --macro-dir=macros/ --out=compiled/ # Use specific macro file sync src/ --macro-file=my-macros.syn --out=compiled/ # Verbose output for debugging sync src/ --macro-dir=macros/ --out=compiled/ --verbose # Show help sync --help
Macro DSL
Syn provides a powerful DSL for defining macros:
Basic Syntax
$(macro) { // pattern to match } >> { // transformation }
Pattern Matching
- Literals:
unless,__swap,$ - Token Types:
$(T_VARIABLE as name),$(T_STRING as class) - Layers:
$(layer() as expression)for balanced parentheses/braces - Lists:
$(ls(label() as item, token(',')) as items) - Sequences:
$(chain(token1, token2, token3))
Examples
Simple Replacement
$(macro) { $ // literal '$' token } >> { $this }
Conditional Logic
$(macro) { unless ($(layer() as condition)) { $(layer() as body) } } >> { if (!($(condition))) { $(body) } }
Variable Swapping
$(macro) { __swap($(T_VARIABLE as a), $(T_VARIABLE as b)) } >> { (list($(a), $(b)) = [$(b), $(a)]) }
Plugin System
Extend Syn with custom rule evaluators:
// CustomPlugin.php class CustomPlugin implements Syn\Plugin\PluginInterface { public function getName(): string { return 'custom'; } public function getMacros(): array { return [ // your custom macros ]; } }
Register plugins in your composer.json:
{
"extra": {
"syn-plugins": [
"MyNamespace\\CustomPlugin"
]
}
}
Architecture
Syn is built on top of Nikic's PHP-Parser and extends it with:
- Parser Combinators: For reliable and composable syntax parsing
- AST Extensions: Support for custom token types defined in macros
- Macro Engine: Pattern matching and transformation system
- Plugin Architecture: Extensible macro system
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
- Inspired by Yay by Márcio Almada
- Built on PHP-Parser by Nikita Popov
- Parser combinator concepts from functional programming
Documentation
For detailed documentation, see the docs/ directory: