A Tree-sitter grammar for the Parol parser generator language.
This project provides a complete Tree-sitter grammar for parsing Parol grammar files (.par extension). Parol is a powerful LL(k) and LALR(1) parser generator written in Rust that supports advanced features like scanner states, AST generation, and error recovery.
-
Complete Language Support: Handles all Parol language constructs including:
- Grammar productions with alternations and factors
- Terminal and non-terminal symbols
- AST control operators (
^cut operator,:identifiermember names) - Scanner directives (
%scanner,%auto_newline_off,%auto_ws_off) - Scanner states for lexical modes
- User type declarations
- Comments (line
//and block/* */) - All repetition operators (
{},[],()) - Token expressions with regex, strings, and raw strings
-
Robust Parsing: Handles edge cases like:
- Empty productions (
A: ;) - Productions starting with empty alternatives (
A: | B) - Productions ending with empty alternatives (
A: B |) - Mixed line and block comments
- Complex scanner state transitions
- Empty productions (
-
Multiple Bindings: Supports integration with:
- Node.js/JavaScript
- Python
- Rust
- Go
- Swift
- C/C++
npm install tree-sitter-parolgit clone https://github.com/jsinger67/tree-sitter-parol.git
cd tree-sitter-parol
npm install
npx tree-sitter generateParse a Parol grammar file:
npx tree-sitter parse examples/example.parconst Parser = require('tree-sitter');
const Parol = require('tree-sitter-parol');
const parser = new Parser();
parser.setLanguage(Parol);
const sourceCode = `
%start Expr
%title "Simple Calculator"
%%
Expr: Term { ('+' | '-') Term };
Term: Factor { ('*' | '/') Factor };
Factor: Number | '(' Expr ')';
Number: /\d+/;
`;
const tree = parser.parse(sourceCode);
console.log(tree.rootNode.toString());import tree_sitter_parol as ts_parol
from tree_sitter import Language, Parser
PAROL_LANGUAGE = Language(ts_parol.language(), 'parol')
parser = Parser()
parser.set_language(PAROL_LANGUAGE)
source_code = b"""
%start Expr
%title "Simple Calculator"
%%
Expr: Term { ('+' | '-') Term };
Term: Factor { ('*' | '/') Factor };
Factor: Number | '(' Expr ')';
Number: /\d+/;
"""
tree = parser.parse(source_code)
print(tree.root_node.sexp())use tree_sitter::{Language, Parser};
extern "C" { fn tree_sitter_parol() -> Language; }
fn main() {
let language = unsafe { tree_sitter_parol() };
let mut parser = Parser::new();
parser.set_language(language).expect("Error loading Parol grammar");
let source_code = r#"
%start Expr
%title "Simple Calculator"
%%
Expr: Term { ('+' | '-') Term };
Term: Factor { ('*' | '/') Factor };
Factor: Number | '(' Expr ')';
Number: /\d+/;
"#;
let tree = parser.parse(source_code, None).unwrap();
println!("{}", tree.root_node().to_sexp());
}The Parol language consists of two main sections:
%startdeclaration (required)%titlefor grammar title%commentfor version info%line_commentand%block_commentfor comment syntax%scannerdirectives for additional scanner states%ondeclarations for transitions from scanner state INITIAL- Scanner states for lexical modes
- Productions with identifiers and alternations
- Factors including symbols, groups, repeats, and optionals
- Terminal symbols (strings, regex, raw strings)
- Non-terminal symbols (identifiers)
- AST control operators for tree shaping
%start Calculator
%title "Simple Calculator Grammar"
%comment "A basic arithmetic calculator"
%line_comment '//'
%block_comment '/*' '*/'
%%
Calculator: Expr;
Expr: Term { ('+' | '-')^ Term };
Term: Factor { ('*' | '/')^ Factor };
Factor
: Number
| '(' Expr ')'
| '-' Factor
;
Number: /\d+(\.\d+)?/;
The grammar generates various AST node types including:
parol- Root nodeprolog- Declaration sectiongrammar_definition- Grammar rules sectionproduction- Individual grammar rulealternations- Alternative patternsalternation- Single alternativefactor- Grammar elementsymbol- Terminal or non-terminalast_control- AST manipulation operatorsscanner_state- Lexical state definition
The grammar has been tested against:
- The complete Parol self-hosting grammar
- Expanded grammar formats with numbered productions
- Complex examples with scanner states
- Edge cases with empty alternatives
- All test cases in the Parol repository
Run tests:
# Test against Parol's own grammar
npx tree-sitter parse ../parol/crates/parol/src/parser/parol.par
# Test against expanded format
npx tree-sitter parse ../parol/crates/parol/src/parser/parol-exp.par
# Test edge cases
npx tree-sitter parse ../parol/crates/parol/data/valid/test.par
# Test scanner states
npx tree-sitter parse ../parol/examples/scanner_states_lr/scanner_states.parContributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
- Clone the repository
- Make changes to
grammar.js - Regenerate the parser:
npx tree-sitter generate - Test your changes:
npx tree-sitter test - Test against real Parol files
This project is licensed under the MIT License - see the LICENSE file for details.
- Parol - The Parol parser generator
- Tree-sitter - The incremental parsing framework
- tree-sitter-rust - Tree-sitter grammar for Rust
- Thanks to the Tree-sitter team for the excellent parsing framework
- Thanks to Jörg Singer for creating the Parol parser generator
- Inspired by other Tree-sitter grammar implementations