Skip to main content

aver/parser/
core.rs

1use super::*;
2
3impl Parser {
4    pub fn new(tokens: Vec<Token>) -> Self {
5        Parser {
6            tokens,
7            pos: 0,
8            recursion_depth: 0,
9        }
10    }
11
12    /// Iron — B4: bump the recursion counter and surface a normal
13    /// parse error if it crosses [`MAX_PARSE_DEPTH`]. Callers MUST
14    /// pair this with [`Self::exit_recursion`] on every return path
15    /// (use `?` early-return + match-and-exit pattern, or hold a
16    /// scope guard if the recursion grows multiple call sites).
17    pub(super) fn enter_recursion(&mut self) -> Result<(), ParseError> {
18        if self.recursion_depth >= super::MAX_PARSE_DEPTH {
19            return Err(self.error(format!(
20                "Expression too deeply nested (max {} levels). Refactor with named bindings or smaller sub-expressions.",
21                super::MAX_PARSE_DEPTH
22            )));
23        }
24        self.recursion_depth += 1;
25        Ok(())
26    }
27
28    pub(super) fn exit_recursion(&mut self) {
29        self.recursion_depth = self.recursion_depth.saturating_sub(1);
30    }
31
32    pub(super) fn error(&self, msg: impl Into<String>) -> ParseError {
33        let tok = self.current();
34        ParseError::Error {
35            msg: msg.into(),
36            line: tok.line,
37            col: tok.col,
38        }
39    }
40
41    pub(super) fn current(&self) -> &Token {
42        if self.pos < self.tokens.len() {
43            &self.tokens[self.pos]
44        } else {
45            self.tokens.last().unwrap()
46        }
47    }
48
49    #[allow(dead_code)]
50    pub(super) fn peek(&self, offset: usize) -> &Token {
51        let idx = self.pos + offset;
52        if idx < self.tokens.len() {
53            &self.tokens[idx]
54        } else {
55            self.tokens.last().unwrap()
56        }
57    }
58
59    /// Peek at the nth non-formatting token (skips Newline/Indent/Dedent).
60    pub(super) fn peek_skip_formatting(&self, nth: usize) -> &Token {
61        let mut count = 0;
62        let mut idx = self.pos;
63        while idx < self.tokens.len() {
64            if !matches!(
65                self.tokens[idx].kind,
66                TokenKind::Newline | TokenKind::Indent | TokenKind::Dedent
67            ) {
68                if count == nth {
69                    return &self.tokens[idx];
70                }
71                count += 1;
72            }
73            idx += 1;
74        }
75        self.tokens.last().unwrap()
76    }
77
78    pub(super) fn advance(&mut self) -> &Token {
79        let tok = if self.pos < self.tokens.len() {
80            &self.tokens[self.pos]
81        } else {
82            self.tokens.last().unwrap()
83        };
84        if self.pos < self.tokens.len() {
85            self.pos += 1;
86        }
87        tok
88    }
89
90    pub(super) fn check_exact(&self, kind: &TokenKind) -> bool {
91        &self.current().kind == kind
92    }
93
94    pub(super) fn is_newline(&self) -> bool {
95        matches!(self.current().kind, TokenKind::Newline)
96    }
97
98    pub(super) fn is_indent(&self) -> bool {
99        matches!(self.current().kind, TokenKind::Indent)
100    }
101
102    pub(super) fn is_dedent(&self) -> bool {
103        matches!(self.current().kind, TokenKind::Dedent)
104    }
105
106    pub(super) fn is_eof(&self) -> bool {
107        matches!(self.current().kind, TokenKind::Eof)
108    }
109
110    #[allow(dead_code)]
111    pub(super) fn match_token(&mut self, kind: &TokenKind) -> Option<Token> {
112        if std::mem::discriminant(&self.current().kind) == std::mem::discriminant(kind) {
113            Some(self.advance().clone())
114        } else {
115            None
116        }
117    }
118
119    pub(super) fn expect_kind(&mut self, kind: &TokenKind, msg: &str) -> Result<Token, ParseError> {
120        if std::mem::discriminant(&self.current().kind) == std::mem::discriminant(kind) {
121            Ok(self.advance().clone())
122        } else {
123            Err(self.error(format!("{}, found {}", msg, self.current().kind)))
124        }
125    }
126
127    pub(super) fn expect_exact(&mut self, kind: &TokenKind) -> Result<Token, ParseError> {
128        if &self.current().kind == kind {
129            Ok(self.advance().clone())
130        } else {
131            Err(self.error(format!("Expected {}, found {}", kind, self.current().kind)))
132        }
133    }
134
135    pub(super) fn skip_formatting(&mut self) {
136        while matches!(
137            self.current().kind,
138            TokenKind::Newline | TokenKind::Indent | TokenKind::Dedent
139        ) {
140            self.advance();
141        }
142    }
143
144    pub(super) fn skip_newlines(&mut self) {
145        while self.is_newline() {
146            self.advance();
147        }
148    }
149
150    pub fn parse(&mut self) -> Result<Vec<TopLevel>, ParseError> {
151        let mut items = Vec::new();
152        self.skip_newlines();
153
154        while !self.is_eof() {
155            if let Some(item) = self.parse_top_level()? {
156                items.push(item);
157            }
158            self.skip_newlines();
159        }
160
161        Ok(items)
162    }
163
164    pub(super) fn parse_top_level(&mut self) -> Result<Option<TopLevel>, ParseError> {
165        match &self.current().kind {
166            TokenKind::Module => Ok(Some(TopLevel::Module(self.parse_module()?))),
167            TokenKind::Fn => Ok(Some(TopLevel::FnDef(self.parse_fn()?))),
168            TokenKind::Verify => Ok(Some(TopLevel::Verify(self.parse_verify()?))),
169            TokenKind::Decision => Ok(Some(TopLevel::Decision(self.parse_decision()?))),
170            TokenKind::Type => Ok(Some(TopLevel::TypeDef(self.parse_sum_type_def()?))),
171            TokenKind::Record => Ok(Some(TopLevel::TypeDef(self.parse_record_def()?))),
172            TokenKind::Effects => Err(self.error(
173                "`effects [...]` is a module-level declaration — it must be \
174                 indented inside a `module` block. For files without a module \
175                 header, the per-fn `! [...]` annotations already cover the \
176                 effect surface; drop the top-level `effects` line.",
177            )),
178            TokenKind::Ident(s) if s == "val" || s == "var" => {
179                let kw = s.clone();
180                Err(self.error(format!(
181                    "Unknown keyword '{}'. Bindings are just: x = 5",
182                    kw
183                )))
184            }
185            TokenKind::Ident(_)
186                if matches!(&self.peek(1).kind, TokenKind::Assign | TokenKind::Colon) =>
187            {
188                let stmt = self.parse_binding()?;
189                Ok(Some(TopLevel::Stmt(stmt)))
190            }
191            TokenKind::Newline | TokenKind::Dedent | TokenKind::Indent => {
192                self.advance();
193                Ok(None)
194            }
195            TokenKind::Eof => Ok(None),
196            _ => {
197                let expr = self.parse_expr()?;
198                self.skip_newlines();
199                Ok(Some(TopLevel::Stmt(Stmt::Expr(expr))))
200            }
201        }
202    }
203}