plotnik_compiler/parser/grammar/
items.rs

1use rowan::TextRange;
2
3use crate::diagnostics::DiagnosticKind;
4use crate::parser::Parser;
5use crate::parser::cst::SyntaxKind;
6use crate::parser::cst::token_sets::{EXPR_FIRST_TOKENS, ROOT_EXPR_FIRST_TOKENS};
7use crate::parser::lexer::token_text;
8
9impl Parser<'_, '_> {
10    pub fn parse_root(&mut self) {
11        self.start_node(SyntaxKind::Root);
12
13        while !self.should_stop() && !self.currently_is(SyntaxKind::Error) {
14            // LL(2): Id followed by Equals → named definition (if PascalCase)
15            if self.currently_is(SyntaxKind::Id) && self.next_is(SyntaxKind::Equals) {
16                self.parse_def();
17                continue;
18            }
19
20            let start = self.current_span().start();
21            self.start_node(SyntaxKind::Def);
22            let success = self.parse_expr_or_error();
23            if !success {
24                self.error_until_next_def();
25            }
26            self.finish_node();
27            if success {
28                let end = self.last_non_trivia_end().unwrap_or(start);
29                let span = TextRange::new(start, end);
30                let def_text = &self.source[usize::from(start)..usize::from(end)];
31                self.diagnostics
32                    .report(self.source_id, DiagnosticKind::UnnamedDef, span)
33                    .hint(format!("give it a name like `Name = {}`", def_text.trim()))
34                    .emit();
35            }
36        }
37
38        self.eat_trivia();
39        self.finish_node();
40    }
41
42    pub(crate) fn error_until_next_def(&mut self) {
43        if self.should_stop() {
44            return;
45        }
46
47        // Check if already at a sync point
48        if self.currently_at_def_start() {
49            return;
50        }
51
52        self.start_node(SyntaxKind::Error);
53        while !self.should_stop() && !self.currently_at_def_start() {
54            self.bump();
55            self.skip_trivia_to_buffer();
56        }
57        self.finish_node();
58    }
59
60    pub(crate) fn currently_at_def_start(&mut self) -> bool {
61        if self.currently_is(SyntaxKind::Id) && self.next_is(SyntaxKind::Equals) {
62            return true;
63        }
64        self.currently_is_one_of(ROOT_EXPR_FIRST_TOKENS)
65    }
66
67    /// Named expression definition: `Name = expr`
68    fn parse_def(&mut self) {
69        self.start_node(SyntaxKind::Def);
70
71        let span = self.current_span();
72        let name = token_text(self.source, &self.tokens[self.pos]);
73        self.bump();
74        self.validate_def_name(name, span);
75
76        let ate_equals = self.eat_token(SyntaxKind::Equals);
77        assert!(
78            ate_equals,
79            "parse_def: expected '=' but found {:?} (caller should verify Equals is present)",
80            self.current()
81        );
82
83        if self.currently_is_one_of(EXPR_FIRST_TOKENS) {
84            self.parse_expr();
85        } else {
86            self.error(DiagnosticKind::ExpectedExpression);
87        }
88
89        self.finish_node();
90    }
91}