Skip to main content

zoisite/
grammar.rs

1use crate::hir::{BinaryOp, OpKind, PostfixOp, UnaryOp};
2use crate::parser::{CompletedMarker, Parser};
3use crate::syntax_kind::SyntaxKind;
4use crate::token_set::TokenSet;
5
6const RECOVERY_SET: TokenSet = TokenSet::new(&[SyntaxKind::Semicolon]);
7const BOOL_SET: TokenSet = TokenSet::new(&[SyntaxKind::TrueKw, SyntaxKind::FalseKw]);
8
9pub fn root(p: &mut Parser<'_>) {
10    let m = p.start();
11    p.eat_trivia();
12    while !p.at(SyntaxKind::Eof) {
13        let (_, semicolon) = stmt(p);
14        if semicolon {
15            p.expect(SyntaxKind::Semicolon);
16        }
17    }
18    m.complete(p, SyntaxKind::Root);
19}
20
21pub fn stmt(p: &mut Parser<'_>) -> (CompletedMarker, bool) {
22    match p.current() {
23        SyntaxKind::Semicolon => (empty_stmt(p), true),
24        SyntaxKind::LetKw => (let_stmt(p), true),
25        SyntaxKind::WhileKw => (while_stmt(p), false),
26        SyntaxKind::BreakKw => (break_stmt(p), true),
27        SyntaxKind::ContinueKw => (continue_stmt(p), true),
28        SyntaxKind::FunKw => (func_stmt(p), false),
29        _ => expr_stmt(p),
30    }
31}
32
33pub fn empty_stmt(p: &mut Parser<'_>) -> CompletedMarker {
34    let m = p.start();
35    m.complete(p, SyntaxKind::EmptyStmt)
36}
37
38pub fn func_stmt(p: &mut Parser<'_>) -> CompletedMarker {
39    assert!(p.at(SyntaxKind::FunKw));
40    let m = p.start();
41    p.bump();
42    p.expect(SyntaxKind::Ident);
43    param_list(p);
44    p.expect(SyntaxKind::Colon);
45    type_spec(p);
46    block_expr(p);
47    m.complete(p, SyntaxKind::FuncDef)
48}
49
50pub fn while_stmt(p: &mut Parser<'_>) -> CompletedMarker {
51    assert!(p.at(SyntaxKind::WhileKw));
52    let m = p.start();
53    p.bump();
54    p.expect(SyntaxKind::OpenParen);
55    expr(p, 0);
56    p.expect(SyntaxKind::CloseParen);
57    expr(p, 0);
58    m.complete(p, SyntaxKind::WhileStmt)
59}
60
61pub fn break_stmt(p: &mut Parser<'_>) -> CompletedMarker {
62    assert!(p.at(SyntaxKind::BreakKw));
63    let m = p.start();
64    p.bump();
65    m.complete(p, SyntaxKind::BreakStmt)
66}
67
68pub fn continue_stmt(p: &mut Parser<'_>) -> CompletedMarker {
69    assert!(p.at(SyntaxKind::ContinueKw));
70    let m = p.start();
71    p.bump();
72    m.complete(p, SyntaxKind::ContinueStmt)
73}
74
75pub fn expr_stmt(p: &mut Parser<'_>) -> (CompletedMarker, bool) {
76    let m = p.start();
77    let res = expr(p, 0);
78    let ends_with_block = res.is_some_and(|r| r.1);
79    (m.complete(p, SyntaxKind::ExprStmt), !ends_with_block)
80}
81
82pub fn typed_ident(p: &mut Parser<'_>, optional: bool) -> CompletedMarker {
83    let m = p.start();
84    p.expect(SyntaxKind::Ident);
85    if optional {
86        if p.eat(SyntaxKind::Colon) {
87            type_spec(p);
88        }
89    } else {
90        p.expect(SyntaxKind::Colon);
91        type_spec(p);
92    }
93    m.complete(p, SyntaxKind::TypedIdent)
94}
95
96pub fn type_spec(p: &mut Parser<'_>) -> Option<CompletedMarker> {
97    match p.current() {
98        SyntaxKind::OpenParen => {
99            let m = p.start();
100            p.bump();
101            type_spec(p);
102            p.expect(SyntaxKind::Comma);
103            type_spec(p);
104            while p.eat(SyntaxKind::Comma) {
105                type_spec(p);
106            }
107            p.expect(SyntaxKind::CloseParen);
108            Some(m.complete(p, SyntaxKind::TupleTypeSpec))
109        },
110        SyntaxKind::Ident => {
111            let m = p.start();
112            p.expect(SyntaxKind::Ident);
113            let mut c = m.complete(p, SyntaxKind::IdentTypeSpec);
114            loop {
115                match p.current() {
116                    SyntaxKind::OpenBracket => {
117                        let m = c.precede(p);
118                        p.bump();
119                        p.expect(SyntaxKind::CloseBracket);
120                        c = m.complete(p, SyntaxKind::ArrayTypeSpec);
121                    },
122                    SyntaxKind::Question => {
123                        let m = c.precede(p);
124                        p.bump();
125                        c = m.complete(p, SyntaxKind::OptionTypeSpec);
126                    },
127                    _ => break
128                }
129            }
130            Some(c)
131        },
132        _ => {
133            p.error_and_recover(&[SyntaxKind::OpenParen, SyntaxKind::Ident], &RECOVERY_SET);
134            None
135        }
136    }
137}
138
139pub fn param_list(p: &mut Parser<'_>) -> CompletedMarker {
140    let m = p.start();
141    p.expect(SyntaxKind::OpenParen);
142    if !p.at(SyntaxKind::CloseParen) {
143        typed_ident(p, false);
144        while p.eat(SyntaxKind::Comma) {
145            typed_ident(p, false);
146        }
147    }
148    p.expect(SyntaxKind::CloseParen);
149    m.complete(p, SyntaxKind::ParamList)
150}
151
152pub fn let_stmt(p: &mut Parser<'_>) -> CompletedMarker {
153    assert!(p.at(SyntaxKind::LetKw));
154    let m = p.start();
155    p.bump();
156    typed_ident(p, true);
157    p.expect(SyntaxKind::Equals);
158    expr(p, 0);
159    m.complete(p, SyntaxKind::LetStmt)
160}
161
162pub fn expr(p: &mut Parser<'_>, min_binding_power: i8) -> Option<(CompletedMarker, bool)> {
163    let (mut lhs, mut ends_with_block) = lhs(p)?;
164    loop {
165        let op: OpKind = match p.current() {
166            SyntaxKind::Plus => OpKind::BinaryOp(BinaryOp::Add),
167            SyntaxKind::Minus => OpKind::BinaryOp(BinaryOp::Sub),
168            SyntaxKind::Star => OpKind::BinaryOp(BinaryOp::Mul),
169            SyntaxKind::Slash => OpKind::BinaryOp(BinaryOp::Div),
170            SyntaxKind::Percent => OpKind::BinaryOp(BinaryOp::Rem),
171            SyntaxKind::Equals => OpKind::BinaryOp(BinaryOp::Assign),
172            SyntaxKind::EqEq => OpKind::BinaryOp(BinaryOp::EqEq),
173            SyntaxKind::Neq => OpKind::BinaryOp(BinaryOp::Neq),
174            SyntaxKind::Ge => OpKind::BinaryOp(BinaryOp::Ge),
175            SyntaxKind::Le => OpKind::BinaryOp(BinaryOp::Le),
176            SyntaxKind::Gt => OpKind::BinaryOp(BinaryOp::Gt),
177            SyntaxKind::Lt => OpKind::BinaryOp(BinaryOp::Lt),
178            SyntaxKind::And => OpKind::BinaryOp(BinaryOp::And),
179            SyntaxKind::Or => OpKind::BinaryOp(BinaryOp::Or),
180            SyntaxKind::OpenBracket => OpKind::PostfixOp(PostfixOp::Index),
181            _ => break,
182        };
183        let (left_binding_power, right_binding_power) = op.binding_power();
184        if left_binding_power < min_binding_power {
185            break;
186        }
187        p.bump();
188        ends_with_block = false;
189        let m = lhs.precede(p);
190        if matches!(op, OpKind::PostfixOp(PostfixOp::Index)) {
191            expr(p, 0);
192            p.expect(SyntaxKind::CloseBracket);
193            lhs = m.complete(p, SyntaxKind::IndexExpr);
194        } else {
195            let rhs = expr(p, right_binding_power);
196            lhs = m.complete(p, SyntaxKind::BinaryExpr);
197            if rhs.is_none() {
198                break;
199            }
200        }
201    }
202    Some((lhs, ends_with_block))
203}
204
205pub fn lhs(p: &mut Parser<'_>) -> Option<(CompletedMarker, bool)> {
206    match p.current() {
207        SyntaxKind::NoneKw => Some((none_literal(p), false)),
208        SyntaxKind::Integer => Some((integer_literal(p), false)),
209        SyntaxKind::Float => Some((float_literal(p), false)),
210        SyntaxKind::TrueKw | SyntaxKind::FalseKw => Some((bool_literal(p), false)),
211        SyntaxKind::String => Some((string_literal(p), false)),
212        SyntaxKind::Char => Some((char_literal(p), false)),
213        SyntaxKind::OpenBracket => Some((array_literal(p), false)),
214        SyntaxKind::Minus => Some((prefix_expr(p), false)),
215        SyntaxKind::OpenParen => Some((paren_expr(p), false)),
216        SyntaxKind::OpenBrace => Some((block_expr(p), true)),
217        SyntaxKind::Ident if p.nth_at(1, SyntaxKind::OpenParen) => Some((fn_call_expr(p), false)),
218        SyntaxKind::Ident => Some((ref_expr(p), false)),
219        SyntaxKind::IfKw => Some(if_expr(p)),
220        _ => {
221            p.error_and_recover(&[SyntaxKind::Integer, SyntaxKind::Float, SyntaxKind::String, SyntaxKind::Char, SyntaxKind::TrueKw, SyntaxKind::FalseKw, SyntaxKind::OpenBracket, SyntaxKind::Minus, SyntaxKind::OpenParen, SyntaxKind::OpenBrace, SyntaxKind::Ident, SyntaxKind::IfKw], &RECOVERY_SET);
222            None
223        }
224    }
225}
226
227pub fn prefix_expr(p: &mut Parser<'_>) -> CompletedMarker {
228    assert!(p.at(SyntaxKind::Minus));
229    let m = p.start();
230    p.bump();
231    let op = OpKind::UnaryOp(UnaryOp::Neg);
232    let (_, right_binding_power) = op.binding_power();
233    expr(p, right_binding_power);
234    m.complete(p, SyntaxKind::PrefixExpr)
235}
236
237pub fn paren_expr(p: &mut Parser<'_>) -> CompletedMarker {
238    assert!(p.at(SyntaxKind::OpenParen));
239    let m = p.start();
240    p.bump();
241    expr(p, 0);
242    let mut comma = false;
243    while p.eat(SyntaxKind::Comma) {
244        expr(p, 0);
245        comma = true;
246    }
247    p.expect(SyntaxKind::CloseParen);
248    if comma {
249        m.complete(p, SyntaxKind::TupleExpr)
250    } else {
251        m.complete(p, SyntaxKind::ParenExpr)
252    }
253}
254
255pub fn ref_expr(p: &mut Parser<'_>) -> CompletedMarker {
256    assert!(p.at(SyntaxKind::Ident));
257    let m = p.start();
258    p.bump();
259    m.complete(p, SyntaxKind::RefExpr)
260}
261
262pub fn if_expr(p: &mut Parser<'_>) -> (CompletedMarker, bool) {
263    assert!(p.at(SyntaxKind::IfKw));
264    let m = p.start();
265    p.bump();
266    p.expect(SyntaxKind::OpenParen);
267    expr(p, 0);
268    p.expect(SyntaxKind::CloseParen);
269    let res = expr(p, 0);
270    let mut ends_with_block = res.is_some_and(|r| r.1);
271    if p.eat(SyntaxKind::ElseKw) {
272        let res = expr(p, 0);
273        ends_with_block = res.is_some_and(|r| r.1);
274    }
275    (m.complete(p, SyntaxKind::IfExpr), ends_with_block)
276}
277
278pub fn fn_call_expr(p: &mut Parser<'_>) -> CompletedMarker {
279    assert!(p.at(SyntaxKind::Ident));
280    let m = p.start();
281    p.bump();
282    p.expect(SyntaxKind::OpenParen);
283    if !p.at(SyntaxKind::CloseParen) {
284        expr(p, 0);
285        while p.eat(SyntaxKind::Comma) {
286            expr(p, 0);
287        }
288    }
289    p.expect(SyntaxKind::CloseParen);
290    m.complete(p, SyntaxKind::FnCallExpr)
291}
292
293pub fn block_expr(p: &mut Parser<'_>) -> CompletedMarker {
294    let m = p.start();
295    p.expect(SyntaxKind::OpenBrace);
296    while !p.at(SyntaxKind::Eof) {
297        if p.at(SyntaxKind::CloseBrace) {
298            empty_stmt(p);
299            break;
300        }
301        let (_, semicolon) = stmt(p);
302        if p.at(SyntaxKind::CloseBrace) {
303            break;
304        }
305        if semicolon {
306            p.expect(SyntaxKind::Semicolon);
307        }
308    }
309    p.expect(SyntaxKind::CloseBrace);
310    m.complete(p, SyntaxKind::BlockExpr)
311}
312
313pub fn none_literal(p: &mut Parser<'_>) -> CompletedMarker {
314    assert!(p.at(SyntaxKind::NoneKw));
315    let m = p.start();
316    p.bump();
317    m.complete(p, SyntaxKind::NoneLiteral)
318}
319
320pub fn integer_literal(p: &mut Parser<'_>) -> CompletedMarker {
321    assert!(p.at(SyntaxKind::Integer));
322    let m = p.start();
323    p.bump();
324    m.complete(p, SyntaxKind::IntLiteral)
325}
326
327pub fn float_literal(p: &mut Parser<'_>) -> CompletedMarker {
328    assert!(p.at(SyntaxKind::Float));
329    let m = p.start();
330    p.bump();
331    m.complete(p, SyntaxKind::FloatLiteral)
332}
333
334pub fn string_literal(p: &mut Parser<'_>) -> CompletedMarker {
335    assert!(p.at(SyntaxKind::String));
336    let m = p.start();
337    p.bump();
338    m.complete(p, SyntaxKind::StringLiteral)
339}
340
341pub fn char_literal(p: &mut Parser<'_>) -> CompletedMarker {
342    assert!(p.at(SyntaxKind::Char));
343    let m = p.start();
344    p.bump();
345    m.complete(p, SyntaxKind::CharLiteral)
346}
347
348pub fn bool_literal(p: &mut Parser<'_>) -> CompletedMarker {
349    assert!(p.at_set(&BOOL_SET));
350    let m = p.start();
351    p.bump();
352    m.complete(p, SyntaxKind::BoolLiteral)
353}
354
355pub fn array_literal(p: &mut Parser<'_>) -> CompletedMarker {
356    assert!(p.at(SyntaxKind::OpenBracket));
357    let m = p.start();
358    p.bump();
359    expr(p, 0);
360    p.expect(SyntaxKind::Semicolon);
361    expr(p, 0);
362    while p.eat(SyntaxKind::Comma) {
363        expr(p, 0);
364    }
365    p.expect(SyntaxKind::CloseBracket);
366    m.complete(p, SyntaxKind::ArrayLiteral)
367}
368
369#[cfg(test)]
370mod tests {
371    use crate::diagnostic::Diagnostic;
372    use crate::language::SyntaxNode;
373    use crate::lexer::Lexer;
374    use crate::parser::Parser;
375
376    fn parse(text: &str) -> (SyntaxNode, Vec<Diagnostic>) {
377        let lexer = Lexer::new(text);
378        let (tokens, _) = lexer.tokenize();
379        let parser = Parser::new(tokens);
380        parser.parse()
381    }
382
383    #[test]
384    fn multi_stmt() {
385        insta::assert_debug_snapshot!(parse("1; 2; 3;"));
386    }
387
388    #[test]
389    fn func_def() {
390        insta::assert_debug_snapshot!(parse("fun f(n: int): int { 1 }"));
391    }
392
393    #[test]
394    fn let_stmt() {
395        insta::assert_debug_snapshot!(parse("let a: int = 1;"));
396    }
397
398    #[test]
399    fn expr_stmt() {
400        insta::assert_debug_snapshot!(parse("1 + 2 * 3;"));
401    }
402
403    #[test]
404    fn unary() {
405        insta::assert_debug_snapshot!(parse("-1 * -2;"));
406    }
407
408    #[test]
409    fn paren() {
410        insta::assert_debug_snapshot!(parse("(1 + 2) * 3;"));
411    }
412
413    #[test]
414    fn let_array() {
415        insta::assert_debug_snapshot!(parse("let a: int[][] = [[1; 2]; 3];"));
416    }
417
418    #[test]
419    fn ref_expr() {
420        insta::assert_debug_snapshot!(parse("a + bc;"));
421    }
422
423    #[test]
424    fn fn_call_expr() {
425        insta::assert_debug_snapshot!(parse("f(a, 1);"));
426    }
427
428    #[test]
429    fn assign_expr() {
430        insta::assert_debug_snapshot!(parse("a = b[0] = 1;"));
431    }
432
433    #[test]
434    fn block_expr() {
435        insta::assert_debug_snapshot!(parse("{1} + {2};"));
436    }
437
438    #[test]
439    fn type_spec() {
440        insta::assert_debug_snapshot!(parse("let a: (int[]?, str, (char?, unit)) = 0;"));
441    }
442}