Skip to main content

vyre_libs/parsing/rust/parse/
mod.rs

1//! Nano-subset Rust parser.
2
3use crate::parsing::rust::lex::lexer::core::Token;
4use crate::parsing::rust::lex::tokens::*;
5
6/// Expression AST.
7#[derive(Debug, Clone, PartialEq)]
8pub enum Expr {
9    /// Integer literal with source offset and value.
10    LiteralInt(u32, u64),
11    /// Boolean literal with source offset and value.
12    LiteralBool(u32, bool),
13    /// Variable reference by source offset.
14    Var(u32),
15    /// Binary operation.
16    Binary {
17        /// Operator token kind.
18        op: u16,
19        /// Left-hand side.
20        lhs: Box<Expr>,
21        /// Right-hand side.
22        rhs: Box<Expr>,
23    },
24    /// Borrow expression.
25    Borrow {
26        /// Whether the borrow is mutable.
27        mutable: bool,
28        /// Borrowed expression.
29        expr: Box<Expr>,
30    },
31    /// Dereference.
32    Deref(Box<Expr>),
33    /// Logical negation (`!expr`).
34    Not(Box<Expr>),
35    /// Arithmetic negation (`-expr`).
36    Neg(Box<Expr>),
37    /// Function call.
38    Call {
39        /// Function name source offset.
40        name: u32,
41        /// Arguments.
42        args: Vec<Expr>,
43    },
44    /// Block expression.
45    Block(Vec<Stmt>),
46    /// Conditional.
47    If {
48        /// Condition.
49        cond: Box<Expr>,
50        /// Then block.
51        then_block: Box<Expr>,
52        /// Else block (optional).
53        else_block: Option<Box<Expr>>,
54    },
55}
56
57/// Statement AST.
58#[derive(Debug, Clone, PartialEq)]
59pub enum Stmt {
60    /// Let binding.
61    Let {
62        /// Whether the binding is mutable.
63        mutable: bool,
64        /// Name source offset.
65        name: u32,
66        /// Declared type.
67        ty: Type,
68        /// Initializer expression.
69        init: Expr,
70    },
71    /// Expression statement.
72    Expr(Expr),
73    /// Assignment to an existing binding (`name = value;`).
74    Assign {
75        /// Target name source offset.
76        name: u32,
77        /// Assigned value.
78        value: Expr,
79    },
80    /// Return statement.
81    Return(Option<Expr>),
82    /// While loop (`while cond { body }`).
83    While {
84        /// Loop condition.
85        cond: Expr,
86        /// Loop body.
87        body: Vec<Stmt>,
88    },
89    /// Half-open range loop (`for name in start..end { body }`).
90    For {
91        /// Loop variable name source offset.
92        name: u32,
93        /// Inclusive start expression.
94        start: Expr,
95        /// Exclusive end expression.
96        end: Expr,
97        /// Loop body.
98        body: Vec<Stmt>,
99    },
100}
101
102/// Types in the nano-subset.
103#[derive(Debug, Clone, PartialEq)]
104pub enum Type {
105    /// 32-bit signed integer.
106    I32,
107    /// Boolean.
108    Bool,
109    /// Unit type.
110    Unit,
111    /// Reference type.
112    Ref {
113        /// Whether the reference is mutable.
114        mutable: bool,
115        /// Inner type.
116        inner: Box<Type>,
117    },
118}
119
120/// Function definition.
121#[derive(Debug, Clone, PartialEq)]
122pub struct Function {
123    /// Name source offset.
124    pub name: u32,
125    /// Parameters: (name offset, type).
126    pub params: Vec<(u32, Type)>,
127    /// Return type.
128    pub ret: Type,
129    /// Body statements.
130    pub body: Vec<Stmt>,
131}
132
133/// A parsed module.
134#[derive(Debug, Clone, PartialEq)]
135pub struct Module {
136    /// Functions in the module.
137    pub functions: Vec<Function>,
138}
139
140/// Parse error.
141#[derive(Debug, Clone, PartialEq)]
142pub struct ParseError {
143    /// Error message.
144    pub message: String,
145    /// Token index where the error occurred.
146    pub token_index: usize,
147}
148
149/// Maximum recursive-descent nesting depth. Hostile input (e.g. thousands of
150/// nested parens or `* ! &mut` chains) would otherwise recurse until the native
151/// stack overflows, an uncatchable process abort and a clean algorithmic-DoS
152/// vector for the frontend. We fail closed with a typed `ParseError` well below
153/// any stack limit; real programs never approach this depth.
154const MAX_PARSE_DEPTH: usize = 256;
155
156/// Parse a token stream into a `Module`.
157pub fn parse(source: &[u8], tokens: &[Token]) -> Result<Module, ParseError> {
158    let mut p = Parser {
159        source,
160        tokens,
161        pos: 0,
162        depth: 0,
163    };
164    p.parse_module()
165}
166
167struct Parser<'a> {
168    source: &'a [u8],
169    tokens: &'a [Token],
170    pos: usize,
171    depth: usize,
172}
173
174impl<'a> Parser<'a> {
175    fn peek(&self) -> &Token {
176        &self.tokens[self.pos.min(self.tokens.len() - 1)]
177    }
178
179    fn advance(&mut self) -> &Token {
180        let tok = &self.tokens[self.pos.min(self.tokens.len() - 1)];
181        if self.pos + 1 < self.tokens.len() {
182            self.pos += 1;
183        }
184        tok
185    }
186
187    fn expect_token(&mut self, kind: u16) -> Result<&Token, ParseError> {
188        let tok = self.peek();
189        if tok.kind == kind {
190            Ok(self.advance())
191        } else {
192            Err(ParseError {
193                message: format!("expected token kind {}, got {}", kind, tok.kind),
194                token_index: self.pos,
195            })
196        }
197    }
198
199    fn parse_module(&mut self) -> Result<Module, ParseError> {
200        let mut functions = Vec::new();
201        while self.peek().kind != EOF {
202            functions.push(self.parse_function()?);
203        }
204        Ok(Module { functions })
205    }
206
207    fn parse_function(&mut self) -> Result<Function, ParseError> {
208        self.expect_token(KW_FN)?;
209        let name = self.expect_token(IDENT)?.start;
210        self.expect_token(LPAREN)?;
211        let params = self.parse_params()?;
212        self.expect_token(RPAREN)?;
213        let ret = if self.peek().kind == ARROW {
214            self.advance();
215            self.parse_type()?
216        } else {
217            Type::Unit
218        };
219        let body = self.parse_block()?;
220        Ok(Function {
221            name,
222            params,
223            ret,
224            body,
225        })
226    }
227
228    fn parse_params(&mut self) -> Result<Vec<(u32, Type)>, ParseError> {
229        let mut params = Vec::new();
230        if self.peek().kind == RPAREN {
231            return Ok(params);
232        }
233        loop {
234            let name = self.expect_token(IDENT)?.start;
235            self.expect_token(COLON)?;
236            let ty = self.parse_type()?;
237            params.push((name, ty));
238            if self.peek().kind == COMMA {
239                self.advance();
240            } else {
241                break;
242            }
243        }
244        Ok(params)
245    }
246
247    fn parse_type(&mut self) -> Result<Type, ParseError> {
248        // `&mut &mut ... T` right-recurses here; guard it on the shared counter.
249        self.depth += 1;
250        let r = if self.depth > MAX_PARSE_DEPTH {
251            Err(ParseError {
252                message: "type nesting too deep".into(),
253                token_index: self.pos,
254            })
255        } else {
256            self.parse_type_inner()
257        };
258        self.depth -= 1;
259        r
260    }
261
262    fn parse_type_inner(&mut self) -> Result<Type, ParseError> {
263        match self.peek().kind {
264            KW_I32 => {
265                self.advance();
266                Ok(Type::I32)
267            }
268            KW_BOOL => {
269                self.advance();
270                Ok(Type::Bool)
271            }
272            AMP | AMP_MUT => {
273                let mutable = self.peek().kind == AMP_MUT;
274                self.advance();
275                let inner = self.parse_type()?;
276                Ok(Type::Ref {
277                    mutable,
278                    inner: Box::new(inner),
279                })
280            }
281            _ => Err(ParseError {
282                message: "expected type".into(),
283                token_index: self.pos,
284            }),
285        }
286    }
287
288    fn parse_block(&mut self) -> Result<Vec<Stmt>, ParseError> {
289        // `parse_block` is the single convergence point for ALL block nesting:
290        // `while`/`loop` bodies, `if`/`else` arms, the fn body, and bare block
291        // expressions. The `while` body in particular is reached by a direct
292        // `parse_block` call (the cond's `parse_expr` has already decremented),
293        // so without guarding here, `while c { while c { ... } }` recurses
294        // unbounded and overflows the native stack. Guard at the block so every
295        // nesting construct (present and future (fails closed)).
296        self.depth += 1;
297        let r = if self.depth > MAX_PARSE_DEPTH {
298            Err(ParseError {
299                message: "block nesting too deep".into(),
300                token_index: self.pos,
301            })
302        } else {
303            self.parse_block_inner()
304        };
305        self.depth -= 1;
306        r
307    }
308
309    fn parse_block_inner(&mut self) -> Result<Vec<Stmt>, ParseError> {
310        self.expect_token(LBRACE)?;
311        let mut stmts = Vec::new();
312        while self.peek().kind != RBRACE && self.peek().kind != EOF {
313            stmts.push(self.parse_stmt()?);
314        }
315        self.expect_token(RBRACE)?;
316        Ok(stmts)
317    }
318
319    fn parse_stmt(&mut self) -> Result<Stmt, ParseError> {
320        match self.peek().kind {
321            KW_LET => self.parse_let(),
322            KW_RETURN => self.parse_return(),
323            KW_WHILE => {
324                self.advance();
325                let cond = self.parse_expr()?;
326                let body = self.parse_block()?;
327                Ok(Stmt::While { cond, body })
328            }
329            KW_FOR => self.parse_for(),
330            _ => {
331                let expr = self.parse_expr()?;
332                // `name = value;` is an assignment to an existing binding.
333                if let Expr::Var(name) = expr {
334                    if self.peek().kind == ASSIGN {
335                        self.advance();
336                        let value = self.parse_expr()?;
337                        self.expect_token(SEMI)?;
338                        return Ok(Stmt::Assign { name, value });
339                    }
340                    // Compound assignment `name += e` / `name -= e` desugars to
341                    // `name = name <op> e`, mirroring rustc's i32 semantics with
342                    // no new AST/IR surface. The synthetic `Var(name)` read
343                    // reuses the target offset; this is sound for the i32-only
344                    // subset because `+=`/`-=` never operate on references, so
345                    // the read can never register a borrow loan.
346                    if matches!(self.peek().kind, PLUS_EQ | MINUS_EQ) {
347                        let op = if self.advance().kind == PLUS_EQ {
348                            PLUS
349                        } else {
350                            MINUS
351                        };
352                        let rhs = self.parse_expr()?;
353                        self.expect_token(SEMI)?;
354                        let value = Expr::Binary {
355                            op,
356                            lhs: Box::new(Expr::Var(name)),
357                            rhs: Box::new(rhs),
358                        };
359                        return Ok(Stmt::Assign { name, value });
360                    }
361                }
362                // Block-like expression statements (`if`/`else`, `{ ... }`) are
363                // valid without a trailing semicolon, matching Rust; any other
364                // expression statement still requires one.
365                if matches!(expr, Expr::If { .. } | Expr::Block(_)) {
366                    if self.peek().kind == SEMI {
367                        self.advance();
368                    }
369                } else {
370                    self.expect_token(SEMI)?;
371                }
372                Ok(Stmt::Expr(expr))
373            }
374        }
375    }
376
377    fn parse_let(&mut self) -> Result<Stmt, ParseError> {
378        self.expect_token(KW_LET)?;
379        let mutable = if self.peek().kind == KW_MUT {
380            self.advance();
381            true
382        } else {
383            false
384        };
385        let name = self.expect_token(IDENT)?.start;
386        self.expect_token(COLON)?;
387        let ty = self.parse_type()?;
388        self.expect_token(ASSIGN)?;
389        let init = self.parse_expr()?;
390        self.expect_token(SEMI)?;
391        Ok(Stmt::Let {
392            mutable,
393            name,
394            ty,
395            init,
396        })
397    }
398
399    fn parse_for(&mut self) -> Result<Stmt, ParseError> {
400        self.expect_token(KW_FOR)?;
401        let name = self.expect_token(IDENT)?.start;
402        self.expect_token(KW_IN)?;
403        let start = self.parse_expr()?;
404        self.expect_token(DOTDOT)?;
405        let end = self.parse_expr()?;
406        let body = self.parse_block()?;
407        Ok(Stmt::For {
408            name,
409            start,
410            end,
411            body,
412        })
413    }
414
415    fn parse_return(&mut self) -> Result<Stmt, ParseError> {
416        self.expect_token(KW_RETURN)?;
417        let expr = if self.peek().kind != SEMI {
418            Some(self.parse_expr()?)
419        } else {
420            None
421        };
422        self.expect_token(SEMI)?;
423        Ok(Stmt::Return(expr))
424    }
425
426    fn parse_expr(&mut self) -> Result<Expr, ParseError> {
427        // Depth-guard the single transitive recursion point for all
428        // paren/call/if/block/while nesting; fail closed before the native
429        // stack overflows on hostile input.
430        self.depth += 1;
431        let r = if self.depth > MAX_PARSE_DEPTH {
432            Err(ParseError {
433                message: "expression nesting too deep".into(),
434                token_index: self.pos,
435            })
436        } else {
437            self.parse_or()
438        };
439        self.depth -= 1;
440        r
441    }
442
443    fn parse_or(&mut self) -> Result<Expr, ParseError> {
444        let mut lhs = self.parse_and()?;
445        while self.peek().kind == OROR {
446            let op = self.advance().kind;
447            lhs = Expr::Binary {
448                op,
449                lhs: Box::new(lhs),
450                rhs: Box::new(self.parse_and()?),
451            };
452        }
453        Ok(lhs)
454    }
455
456    fn parse_and(&mut self) -> Result<Expr, ParseError> {
457        let mut lhs = self.parse_cmp()?;
458        while self.peek().kind == ANDAND {
459            let op = self.advance().kind;
460            lhs = Expr::Binary {
461                op,
462                lhs: Box::new(lhs),
463                rhs: Box::new(self.parse_cmp()?),
464            };
465        }
466        Ok(lhs)
467    }
468
469    fn parse_cmp(&mut self) -> Result<Expr, ParseError> {
470        let mut lhs = self.parse_term()?;
471        while matches!(self.peek().kind, EQ | LT | NE | GT | LE | GE) {
472            let op = self.advance().kind;
473            lhs = Expr::Binary {
474                op,
475                lhs: Box::new(lhs),
476                rhs: Box::new(self.parse_term()?),
477            };
478        }
479        Ok(lhs)
480    }
481
482    fn parse_term(&mut self) -> Result<Expr, ParseError> {
483        let mut lhs = self.parse_factor()?;
484        while matches!(self.peek().kind, PLUS | MINUS) {
485            let op = self.advance().kind;
486            lhs = Expr::Binary {
487                op,
488                lhs: Box::new(lhs),
489                rhs: Box::new(self.parse_factor()?),
490            };
491        }
492        Ok(lhs)
493    }
494
495    fn parse_factor(&mut self) -> Result<Expr, ParseError> {
496        let mut lhs = self.parse_unary()?;
497        while matches!(self.peek().kind, STAR | SLASH | PERCENT) {
498            let op = self.advance().kind;
499            lhs = Expr::Binary {
500                op,
501                lhs: Box::new(lhs),
502                rhs: Box::new(self.parse_unary()?),
503            };
504        }
505        Ok(lhs)
506    }
507
508    fn parse_unary(&mut self) -> Result<Expr, ParseError> {
509        // `* ! &` chains right-recurse here without going through parse_expr,
510        // so this self-recursion needs its own depth guard (shared counter).
511        self.depth += 1;
512        let r = if self.depth > MAX_PARSE_DEPTH {
513            Err(ParseError {
514                message: "expression nesting too deep".into(),
515                token_index: self.pos,
516            })
517        } else {
518            self.parse_unary_inner()
519        };
520        self.depth -= 1;
521        r
522    }
523
524    fn parse_unary_inner(&mut self) -> Result<Expr, ParseError> {
525        match self.peek().kind {
526            AMP | AMP_MUT => {
527                let mutable = self.peek().kind == AMP_MUT;
528                self.advance();
529                Ok(Expr::Borrow {
530                    mutable,
531                    expr: Box::new(self.parse_unary()?),
532                })
533            }
534            STAR => {
535                self.advance();
536                Ok(Expr::Deref(Box::new(self.parse_unary()?)))
537            }
538            BANG => {
539                self.advance();
540                Ok(Expr::Not(Box::new(self.parse_unary()?)))
541            }
542            MINUS => {
543                self.advance();
544                Ok(Expr::Neg(Box::new(self.parse_unary()?)))
545            }
546            _ => self.parse_primary(),
547        }
548    }
549
550    fn parse_primary(&mut self) -> Result<Expr, ParseError> {
551        match self.peek().kind {
552            LPAREN => {
553                self.advance();
554                let inner = self.parse_expr()?;
555                self.expect_token(RPAREN)?;
556                Ok(inner)
557            }
558            LITERAL_INT => {
559                let tok = *self.advance();
560                // rustc treats a literal exceeding u128 as an unconditional hard
561                // error ("integer literal is too large"), which `--cap-lints
562                // allow` cannot suppress; literals within u128 are merely the
563                // capped `overflowing_literals` lint (accepted, then wrapped to
564                // the target type). Match that boundary exactly: parse as u128,
565                // reject on overflow. Storing the low 64 bits is value-faithful
566                // for the i32-only subset because `v as u64 as i32 == v as i32`.
567                let text = tok.try_text(self.source).map_err(|offset| ParseError {
568                    message: format!("invalid token text span at byte {offset}"),
569                    token_index: self.pos,
570                })?;
571                match text.parse::<u128>() {
572                    Ok(v) => Ok(Expr::LiteralInt(tok.start, v as u64)),
573                    Err(_) => Err(ParseError {
574                        message: "integer literal is too large".into(),
575                        token_index: self.pos,
576                    }),
577                }
578            }
579            LITERAL_BOOL => {
580                let tok = *self.advance();
581                let b = tok.try_text(self.source).map_err(|offset| ParseError {
582                    message: format!("invalid token text span at byte {offset}"),
583                    token_index: self.pos,
584                })? == "true";
585                Ok(Expr::LiteralBool(tok.start, b))
586            }
587            IDENT => {
588                let name = self.advance().start;
589                if self.peek().kind == LPAREN {
590                    self.advance();
591                    let mut args = Vec::new();
592                    if self.peek().kind != RPAREN {
593                        loop {
594                            args.push(self.parse_expr()?);
595                            if self.peek().kind == COMMA {
596                                self.advance();
597                            } else {
598                                break;
599                            }
600                        }
601                    }
602                    self.expect_token(RPAREN)?;
603                    Ok(Expr::Call { name, args })
604                } else {
605                    Ok(Expr::Var(name))
606                }
607            }
608            LBRACE => Ok(Expr::Block(self.parse_block()?)),
609            KW_IF => {
610                self.advance();
611                let cond = Box::new(self.parse_expr()?);
612                let then_block = Box::new(Expr::Block(self.parse_block()?));
613                let else_block = if self.peek().kind == KW_ELSE {
614                    self.advance();
615                    if self.peek().kind == KW_IF {
616                        Some(Box::new(self.parse_expr()?))
617                    } else {
618                        Some(Box::new(Expr::Block(self.parse_block()?)))
619                    }
620                } else {
621                    None
622                };
623                Ok(Expr::If {
624                    cond,
625                    then_block,
626                    else_block,
627                })
628            }
629            _ => Err(ParseError {
630                message: "unexpected token in expression".into(),
631                token_index: self.pos,
632            }),
633        }
634    }
635}