Skip to main content

leekscript_core/grammar/
mod.rs

1//! `LeekScript` grammar built with sipha.
2//!
3//! Phase 1: token stream (lexer).
4//! Phases 2–4: expressions, statements, top-level.
5
6mod expressions;
7mod keywords;
8mod literals;
9mod operators;
10mod signature;
11mod statements;
12
13pub use signature::build_signature_grammar;
14mod token_stream;
15mod trivia;
16
17use sipha::prelude::*;
18
19/// Build the `LeekScript` grammar (Phase 1: token stream).
20#[must_use]
21pub fn build_grammar() -> sipha::builder::BuiltGraph {
22    let mut g = GrammarBuilder::new();
23    g.set_trivia_rule("ws");
24
25    g.begin_rule("start");
26    g.skip();
27    g.call("token_stream");
28    g.skip();
29    g.end_of_input();
30    g.accept();
31
32    trivia::add_ws(&mut g);
33    literals::add_string_lit(&mut g);
34    literals::add_escape(&mut g);
35    literals::add_number_lit_full(&mut g);
36    operators::add_operator(&mut g);
37    operators::add_arrow(&mut g);
38    operators::add_dot_dot(&mut g);
39    operators::add_dot(&mut g);
40    operators::add_bracket(&mut g);
41    keywords::add_keyword_or_ident_token(&mut g);
42    literals::add_special_lit(&mut g);
43    token_stream::add_token_rule(&mut g);
44    token_stream::add_token_stream(&mut g);
45
46    g.finish().expect("grammar must be valid")
47}
48
49/// Build a grammar that parses a single expression (Phase 2).
50/// Start rule is "start" → ws expr ws eof.
51#[must_use]
52pub fn build_expression_grammar() -> sipha::builder::BuiltGraph {
53    let mut g = GrammarBuilder::new();
54    g.set_trivia_rule("ws");
55
56    g.begin_rule("start");
57    g.skip();
58    g.call("expr");
59    g.skip();
60    g.end_of_input();
61    g.accept();
62
63    g.allow_rule_cycles(true); // expr -> expr via ( expr ) is intentional; use with memo
64    trivia::add_ws(&mut g);
65    literals::add_number_lit(&mut g);
66    literals::add_string_lit(&mut g);
67    literals::add_escape(&mut g);
68    keywords::add_ident(&mut g);
69    operators::add_lparen_rparen(&mut g);
70    expressions::add_expr_minimal(&mut g);
71
72    g.finish().expect("expression grammar must be valid")
73}
74
75/// Build a grammar that parses a program (Phase 3/4: list of statements).
76/// Start rule is "start" → node(NodeRoot, ws program ws eof) so the parse tree has a single root.
77#[must_use]
78pub fn build_program_grammar() -> sipha::builder::BuiltGraph {
79    let mut g = GrammarBuilder::new();
80    g.set_trivia_rule("ws");
81
82    g.begin_rule("start");
83    g.node(crate::syntax::Kind::NodeRoot.into_syntax_kind(), |g| {
84        g.skip();
85        g.call("program");
86        g.skip();
87        g.end_of_input();
88    });
89    g.accept();
90
91    g.allow_rule_cycles(true); // expr chain has intentional indirect recursion; use with memo
92    trivia::add_ws(&mut g);
93    add_literals_program(&mut g);
94    add_keywords_program(&mut g);
95    add_operators_program(&mut g);
96    statements::add_block(&mut g); // before expressions (block used by anon fn, etc.)
97    add_expressions(&mut g);
98    add_statements(&mut g);
99
100    g.finish().expect("program grammar must be valid")
101}
102
103// ─── Program grammar: literals, keywords, operators, expressions, statements ──
104
105fn add_literals_program(g: &mut sipha::builder::GrammarBuilder) {
106    literals::add_number_lit(g);
107    literals::add_string_lit(g);
108    literals::add_escape(g);
109    literals::add_special_lit(g);
110}
111
112fn add_keywords_program(g: &mut sipha::builder::GrammarBuilder) {
113    keywords::add_ident(g);
114    keywords::add_and_kw(g);
115    keywords::add_or_kw(g);
116    keywords::add_xor_kw(g);
117    keywords::add_abstract_kw(g);
118    keywords::add_constructor_kw(g);
119    keywords::add_extends_kw(g);
120    keywords::add_static_kw(g);
121    keywords::add_final_kw(g);
122    keywords::add_public_kw(g);
123    keywords::add_private_kw(g);
124    keywords::add_protected_kw(g);
125    keywords::add_not_kw(g);
126    keywords::add_as_kw(g);
127    keywords::add_in_kw(g);
128    keywords::add_instanceof_kw(g);
129}
130
131fn add_operators_program(g: &mut sipha::builder::GrammarBuilder) {
132    operators::add_program_brackets(g);
133    operators::add_arrow(g);
134    operators::add_program_operators(g);
135    operators::add_op_colon(g);
136    keywords::add_keyword_or_ident_program(g);
137}
138
139fn add_expressions(g: &mut sipha::builder::GrammarBuilder) {
140    expressions::add_interval_literal(g);
141    expressions::add_bracket_literal(g);
142    expressions::add_map_pair(g);
143    expressions::add_primary(g);
144    expressions::add_object_pair(g);
145    expressions::add_postfix(g);
146    expressions::add_unary(g);
147    expressions::add_expr_power(g);
148    expressions::add_expr_mul(g);
149    expressions::add_expr_add(g);
150    expressions::add_expr_interval(g);
151    expressions::add_expr_compare(g);
152    expressions::add_expr_equality(g);
153    expressions::add_expr_in(g);
154    expressions::add_expr_instanceof(g);
155    expressions::add_expr_and(g);
156    expressions::add_expr_or(g);
157    expressions::add_expr_xor(g);
158    expressions::add_expr_ternary(g);
159    expressions::add_type_params(g);
160    expressions::add_type_primary(g);
161    expressions::add_type_optional(g);
162    expressions::add_type_expr(g);
163    expressions::add_expr_as(g);
164    expressions::add_expr(g);
165}
166
167// ─── Statements and program ──────────────────────────────────────────────────
168
169fn add_statements(g: &mut sipha::builder::GrammarBuilder) {
170    statements::add_var_decl(g);
171    statements::add_global_decl(g);
172    statements::add_const_decl(g);
173    statements::add_let_decl(g);
174    statements::add_param(g);
175    statements::add_if_stmt(g);
176    statements::add_while_stmt(g);
177    statements::add_return_stmt(g);
178    statements::add_break_stmt(g);
179    statements::add_continue_stmt(g);
180    statements::add_expr_stmt(g);
181    statements::add_include_stmt(g);
182    statements::add_function_decl(g);
183    statements::add_class_method(g);
184    statements::add_constructor_decl(g);
185    statements::add_class_field(g);
186    statements::add_class_decl(g);
187    statements::add_for_init(g);
188    statements::add_for_stmt(g);
189    statements::add_for_in_stmt(g);
190    statements::add_do_while_stmt(g);
191    statements::add_statement(g);
192    statements::add_statement_sync(g);
193    statements::add_program(g);
194}