Skip to main content

proof_engine/scripting/
parser.rs

1//! Recursive-descent parser — converts token stream into AST.
2
3use super::lexer::{Token, TokenWithSpan};
4use super::ast::*;
5use std::fmt;
6
7#[derive(Debug)]
8pub struct ParseError {
9    pub message: String,
10    pub line:    u32,
11}
12
13impl fmt::Display for ParseError {
14    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15        write!(f, "Parse error at line {}: {}", self.line, self.message)
16    }
17}
18
19pub struct Parser {
20    tokens:  Vec<TokenWithSpan>,
21    pos:     usize,
22    in_match_head: bool,
23    in_ternary: bool,
24    in_match_arm: bool,
25}
26
27impl Parser {
28    pub fn new(tokens: Vec<TokenWithSpan>) -> Self {
29        Self { tokens, pos: 0, in_match_head: false, in_ternary: false, in_match_arm: false }
30    }
31
32    /// Convenience: lex + parse from source in one call.
33    pub fn from_source(name: &str, source: &str) -> Result<Script, ParseError> {
34        let mut lexer = super::lexer::Lexer::new(source);
35        let tokens = lexer.tokenize();
36        let mut parser = Parser::new(tokens);
37        parser.parse_script(name)
38    }
39
40    fn peek(&self) -> &Token {
41        self.tokens.get(self.pos).map(|t| &t.token).unwrap_or(&Token::Eof)
42    }
43
44    fn peek_span_line(&self) -> u32 {
45        self.tokens.get(self.pos).map(|t| t.span.line).unwrap_or(0)
46    }
47
48    fn advance(&mut self) -> &Token {
49        let t = self.tokens.get(self.pos).map(|t| &t.token).unwrap_or(&Token::Eof);
50        if self.pos < self.tokens.len() { self.pos += 1; }
51        t
52    }
53
54    fn expect(&mut self, expected: &Token) -> Result<(), ParseError> {
55        if self.peek() == expected {
56            self.advance();
57            Ok(())
58        } else {
59            Err(ParseError {
60                message: format!("expected {:?}, got {:?}", expected, self.peek()),
61                line: self.peek_span_line(),
62            })
63        }
64    }
65
66    fn expect_ident(&mut self) -> Result<String, ParseError> {
67        match self.peek().clone() {
68            Token::Ident(s) => { self.advance(); Ok(s) }
69            t => Err(ParseError { message: format!("expected identifier, got {:?}", t), line: self.peek_span_line() })
70        }
71    }
72
73    fn check(&self, t: &Token) -> bool { self.peek() == t }
74
75    fn consume_if(&mut self, t: &Token) -> bool {
76        if self.peek() == t { self.advance(); true }
77        else { false }
78    }
79
80    // ── Statement parsing ─────────────────────────────────────────────────
81
82    pub fn parse_script(&mut self, name: &str) -> Result<Script, ParseError> {
83        let stmts = self.parse_block()?;
84        Ok(Script { name: name.to_string(), stmts })
85    }
86
87    fn parse_block(&mut self) -> Result<Vec<Stmt>, ParseError> {
88        let mut stmts = Vec::new();
89        loop {
90            self.consume_if(&Token::Semicolon);
91            match self.peek() {
92                Token::Eof | Token::End | Token::Else | Token::ElseIf | Token::Until => break,
93                _ => {}
94            }
95            stmts.push(self.parse_stmt()?);
96        }
97        Ok(stmts)
98    }
99
100    fn parse_stmt(&mut self) -> Result<Stmt, ParseError> {
101        match self.peek().clone() {
102            Token::Local    => self.parse_local(),
103            Token::Function => self.parse_func_decl(),
104            Token::If       => self.parse_if(),
105            Token::While    => self.parse_while(),
106            Token::For      => self.parse_for(),
107            Token::Repeat   => self.parse_repeat_until(),
108            Token::Do       => { self.advance(); let b = self.parse_block()?; self.expect(&Token::End)?; Ok(Stmt::Do(b)) }
109            Token::Return   => self.parse_return(),
110            Token::Break    => { self.advance(); Ok(Stmt::Break) }
111            Token::Continue => { self.advance(); Ok(Stmt::Continue) }
112            Token::Match    => self.parse_match(),
113            Token::Import   => self.parse_import(),
114            Token::Export   => { self.advance(); let name = self.expect_ident()?; Ok(Stmt::Export(name)) }
115            _               => self.parse_expr_stmt(),
116        }
117    }
118
119    fn parse_local(&mut self) -> Result<Stmt, ParseError> {
120        self.advance(); // consume 'local'
121        if self.check(&Token::Function) {
122            self.advance();
123            let name = self.expect_ident()?;
124            let (params, vararg, body) = self.parse_func_body()?;
125            return Ok(Stmt::LocalFunc { name, params, vararg, body });
126        }
127        let mut names = vec![self.expect_ident()?];
128        while self.consume_if(&Token::Comma) {
129            names.push(self.expect_ident()?);
130        }
131        let inits = if self.consume_if(&Token::Eq) {
132            self.parse_expr_list()?
133        } else { Vec::new() };
134
135        if names.len() == 1 && inits.len() <= 1 {
136            Ok(Stmt::LocalDecl { name: names.remove(0), init: inits.into_iter().next() })
137        } else {
138            Ok(Stmt::LocalMulti { names, inits })
139        }
140    }
141
142    fn parse_func_decl(&mut self) -> Result<Stmt, ParseError> {
143        self.advance(); // consume 'function'
144        let mut name = vec![self.expect_ident()?];
145        while self.consume_if(&Token::Dot) {
146            name.push(self.expect_ident()?);
147        }
148        let (params, vararg, body) = self.parse_func_body()?;
149        Ok(Stmt::FuncDecl { name, params, vararg, body })
150    }
151
152    fn parse_func_body(&mut self) -> Result<(Vec<String>, bool, Vec<Stmt>), ParseError> {
153        self.expect(&Token::LParen)?;
154        let mut params = Vec::new();
155        let mut vararg = false;
156        if !self.check(&Token::RParen) {
157            loop {
158                if self.check(&Token::DotDotDot) {
159                    self.advance();
160                    vararg = true;
161                    break;
162                }
163                params.push(self.expect_ident()?);
164                if !self.consume_if(&Token::Comma) { break; }
165            }
166        }
167        self.expect(&Token::RParen)?;
168        let body = self.parse_block()?;
169        self.expect(&Token::End)?;
170        Ok((params, vararg, body))
171    }
172
173    fn parse_if(&mut self) -> Result<Stmt, ParseError> {
174        self.advance(); // if
175        let cond = self.parse_expr(0)?;
176        self.expect(&Token::Then)?;
177        let then_body = self.parse_block()?;
178        let mut elseif_branches = Vec::new();
179        let mut else_body = None;
180        loop {
181            if self.consume_if(&Token::ElseIf) {
182                let ec = self.parse_expr(0)?;
183                self.expect(&Token::Then)?;
184                let eb = self.parse_block()?;
185                elseif_branches.push((ec, eb));
186            } else if self.consume_if(&Token::Else) {
187                else_body = Some(self.parse_block()?);
188                break;
189            } else { break; }
190        }
191        self.expect(&Token::End)?;
192        Ok(Stmt::If { cond, then_body, elseif_branches, else_body })
193    }
194
195    fn parse_while(&mut self) -> Result<Stmt, ParseError> {
196        self.advance();
197        let cond = self.parse_expr(0)?;
198        self.expect(&Token::Do)?;
199        let body = self.parse_block()?;
200        self.expect(&Token::End)?;
201        Ok(Stmt::While { cond, body })
202    }
203
204    fn parse_for(&mut self) -> Result<Stmt, ParseError> {
205        self.advance();
206        let first = self.expect_ident()?;
207        if self.consume_if(&Token::Eq) {
208            // numeric for
209            let start = self.parse_expr(0)?;
210            self.expect(&Token::Comma)?;
211            let limit = self.parse_expr(0)?;
212            let step = if self.consume_if(&Token::Comma) { Some(self.parse_expr(0)?) } else { None };
213            self.expect(&Token::Do)?;
214            let body = self.parse_block()?;
215            self.expect(&Token::End)?;
216            Ok(Stmt::NumericFor { var: first, start, limit, step, body })
217        } else {
218            // generic for
219            let mut vars = vec![first];
220            while self.consume_if(&Token::Comma) { vars.push(self.expect_ident()?); }
221            self.expect(&Token::In)?;
222            let iter = self.parse_expr_list()?;
223            self.expect(&Token::Do)?;
224            let body = self.parse_block()?;
225            self.expect(&Token::End)?;
226            Ok(Stmt::GenericFor { vars, iter, body })
227        }
228    }
229
230    fn parse_repeat_until(&mut self) -> Result<Stmt, ParseError> {
231        self.advance();
232        let body = self.parse_block()?;
233        self.expect(&Token::Until)?;
234        let cond = self.parse_expr(0)?;
235        Ok(Stmt::RepeatUntil { body, cond })
236    }
237
238    fn parse_return(&mut self) -> Result<Stmt, ParseError> {
239        self.advance();
240        let vals = match self.peek() {
241            Token::End | Token::Else | Token::ElseIf | Token::Until | Token::Eof | Token::Semicolon => Vec::new(),
242            _ => self.parse_expr_list()?,
243        };
244        self.consume_if(&Token::Semicolon);
245        Ok(Stmt::Return(vals))
246    }
247
248    fn parse_match(&mut self) -> Result<Stmt, ParseError> {
249        self.advance();
250        self.in_match_head = true;
251        let expr = self.parse_expr(0)?;
252        self.in_match_head = false;
253        self.expect(&Token::LBrace)?;
254        let mut arms = Vec::new();
255        while !self.check(&Token::RBrace) && !self.check(&Token::Eof) {
256            self.consume_if(&Token::Case);
257            let pattern = self.parse_match_pattern()?;
258            if !self.consume_if(&Token::FatArrow) { self.expect(&Token::Arrow)?; }
259            let body = if self.check(&Token::LBrace) {
260                self.advance();
261                let b = self.parse_block()?;
262                self.expect(&Token::RBrace)?;
263                b
264            } else {
265                let old = self.in_match_arm;
266                self.in_match_arm = true;
267                let s = vec![self.parse_stmt()?];
268                self.in_match_arm = old;
269                s
270            };
271            arms.push(MatchArm { pattern, body });
272            self.consume_if(&Token::Comma);
273        }
274        self.expect(&Token::RBrace)?;
275        Ok(Stmt::Match { expr, arms })
276    }
277
278    fn parse_match_pattern(&mut self) -> Result<MatchPattern, ParseError> {
279        match self.peek().clone() {
280            Token::Ident(s) if s == "_" => { self.advance(); Ok(MatchPattern::Wildcard) }
281            Token::Default => { self.advance(); Ok(MatchPattern::Wildcard) }
282            _ => Ok(MatchPattern::Literal(self.parse_expr(0)?)),
283        }
284    }
285
286    fn parse_import(&mut self) -> Result<Stmt, ParseError> {
287        self.advance();
288        let path = match self.advance().clone() {
289            Token::Str(s) => s,
290            Token::Ident(s) => s,
291            t => return Err(ParseError { message: format!("expected module path, got {:?}", t), line: self.peek_span_line() }),
292        };
293        let alias = if self.consume_if(&Token::Ident("as".to_string())) {
294            Some(self.expect_ident()?)
295        } else { None };
296        Ok(Stmt::Import { path, alias })
297    }
298
299    fn parse_expr_stmt(&mut self) -> Result<Stmt, ParseError> {
300        let expr = self.parse_expr(0)?;
301
302        // Check for assignment
303        if self.check(&Token::Eq) || self.check(&Token::Comma) {
304            let mut targets = vec![expr];
305            while self.consume_if(&Token::Comma) {
306                targets.push(self.parse_expr(0)?);
307            }
308            self.expect(&Token::Eq)?;
309            let values = self.parse_expr_list()?;
310            return Ok(Stmt::Assign { target: targets, value: values });
311        }
312
313        // Compound assignments
314        let op = match self.peek() {
315            Token::PlusEq  => Some(BinOp::Add),
316            Token::MinusEq => Some(BinOp::Sub),
317            Token::StarEq  => Some(BinOp::Mul),
318            Token::SlashEq => Some(BinOp::Div),
319            _ => None,
320        };
321        if let Some(op) = op {
322            self.advance();
323            let value = self.parse_expr(0)?;
324            return Ok(Stmt::CompoundAssign { target: expr, op, value });
325        }
326
327        Ok(Stmt::Call(expr))
328    }
329
330    fn parse_expr_list(&mut self) -> Result<Vec<Expr>, ParseError> {
331        let mut exprs = vec![self.parse_expr(0)?];
332        while !self.in_match_arm && self.consume_if(&Token::Comma) {
333            exprs.push(self.parse_expr(0)?);
334        }
335        Ok(exprs)
336    }
337
338    // ── Expression parsing (Pratt) ────────────────────────────────────────
339
340    fn parse_expr(&mut self, min_prec: u8) -> Result<Expr, ParseError> {
341        let mut lhs = self.parse_unary()?;
342
343        loop {
344            let op = match self.peek() {
345                Token::Plus     => Some(BinOp::Add),
346                Token::Minus    => Some(BinOp::Sub),
347                Token::Star     => Some(BinOp::Mul),
348                Token::Slash    => Some(BinOp::Div),
349                Token::SlashSlash => Some(BinOp::IDiv),
350                Token::Percent  => Some(BinOp::Mod),
351                Token::Caret    => Some(BinOp::Pow),
352                Token::DotDot   => Some(BinOp::Concat),
353                Token::EqEq     => Some(BinOp::Eq),
354                Token::NotEq    => Some(BinOp::NotEq),
355                Token::Lt       => Some(BinOp::Lt),
356                Token::LtEq     => Some(BinOp::LtEq),
357                Token::Gt       => Some(BinOp::Gt),
358                Token::GtEq     => Some(BinOp::GtEq),
359                Token::And      => Some(BinOp::And),
360                Token::Or       => Some(BinOp::Or),
361                Token::Amp      => Some(BinOp::BitAnd),
362                Token::Pipe     => Some(BinOp::BitOr),
363                Token::Tilde    => Some(BinOp::BitXor),
364                Token::ShiftLeft  => Some(BinOp::Shl),
365                Token::ShiftRight => Some(BinOp::Shr),
366                _ => None,
367            };
368            if let Some(op) = op {
369                let prec = op.precedence();
370                if prec <= min_prec { break; }
371                self.advance();
372                let next_min = if op.is_right_assoc() { prec - 1 } else { prec };
373                let rhs = self.parse_expr(next_min)?;
374                lhs = Expr::Binary { op, lhs: Box::new(lhs), rhs: Box::new(rhs) };
375            } else { break; }
376        }
377        // Ternary: expr ? then_val : else_val
378        if self.check(&Token::Question) {
379            self.advance();
380            let old = self.in_ternary;
381            self.in_ternary = true;
382            let then_val = self.parse_expr(0)?;
383            self.in_ternary = old;
384            self.expect(&Token::Colon)?;
385            let else_val = self.parse_expr(0)?;
386            lhs = Expr::Ternary {
387                cond: Box::new(lhs),
388                then_val: Box::new(then_val),
389                else_val: Box::new(else_val),
390            };
391        }
392        Ok(lhs)
393    }
394
395    fn parse_unary(&mut self) -> Result<Expr, ParseError> {
396        match self.peek().clone() {
397            Token::Minus => { self.advance(); let e = self.parse_unary()?; Ok(Expr::Unary { op: UnOp::Neg, expr: Box::new(e) }) }
398            Token::Not | Token::Bang => { self.advance(); let e = self.parse_unary()?; Ok(Expr::Unary { op: UnOp::Not, expr: Box::new(e) }) }
399            Token::Hash  => { self.advance(); let e = self.parse_unary()?; Ok(Expr::Unary { op: UnOp::Len, expr: Box::new(e) }) }
400            Token::Tilde => { self.advance(); let e = self.parse_unary()?; Ok(Expr::Unary { op: UnOp::BitNot, expr: Box::new(e) }) }
401            _ => self.parse_postfix(),
402        }
403    }
404
405    fn parse_postfix(&mut self) -> Result<Expr, ParseError> {
406        let mut expr = self.parse_primary()?;
407        loop {
408            match self.peek().clone() {
409                Token::Dot => {
410                    self.advance();
411                    let name = self.expect_ident()?;
412                    expr = Expr::Field { table: Box::new(expr), name };
413                    // If followed by call args, it becomes a regular call (no self)
414                    if self.check(&Token::LParen) {
415                        let args = self.parse_args()?;
416                        expr = Expr::Call { callee: Box::new(expr), args };
417                    }
418                }
419                Token::Colon if !self.in_ternary => {
420                    self.advance();
421                    let method = self.expect_ident()?;
422                    let args = self.parse_args()?;
423                    expr = Expr::MethodCall { obj: Box::new(expr), method, args };
424                }
425                Token::LBracket => {
426                    self.advance();
427                    let key = self.parse_expr(0)?;
428                    self.expect(&Token::RBracket)?;
429                    expr = Expr::Index { table: Box::new(expr), key: Box::new(key) };
430                }
431                Token::LParen | Token::Str(_) => {
432                    let args = self.parse_args()?;
433                    expr = Expr::Call { callee: Box::new(expr), args };
434                }
435                Token::LBrace if !self.in_match_head => {
436                    let args = self.parse_args()?;
437                    expr = Expr::Call { callee: Box::new(expr), args };
438                }
439                _ => break,
440            }
441        }
442        Ok(expr)
443    }
444
445    fn parse_args(&mut self) -> Result<Vec<Expr>, ParseError> {
446        match self.peek().clone() {
447            Token::LParen => {
448                self.advance();
449                if self.check(&Token::RParen) { self.advance(); return Ok(Vec::new()); }
450                let args = self.parse_expr_list()?;
451                self.expect(&Token::RParen)?;
452                Ok(args)
453            }
454            Token::LBrace => {
455                let t = self.parse_table_ctor()?;
456                Ok(vec![t])
457            }
458            Token::Str(s) => { self.advance(); Ok(vec![Expr::Str(s)]) }
459            t => Err(ParseError { message: format!("expected args, got {:?}", t), line: self.peek_span_line() })
460        }
461    }
462
463    fn parse_primary(&mut self) -> Result<Expr, ParseError> {
464        match self.peek().clone() {
465            Token::Nil       => { self.advance(); Ok(Expr::Nil) }
466            Token::True      => { self.advance(); Ok(Expr::Bool(true)) }
467            Token::False     => { self.advance(); Ok(Expr::Bool(false)) }
468            Token::Int(v)    => { self.advance(); Ok(Expr::Int(v)) }
469            Token::Float(v)  => { self.advance(); Ok(Expr::Float(v)) }
470            Token::Str(s)    => { self.advance(); Ok(Expr::Str(s)) }
471            Token::DotDotDot => { self.advance(); Ok(Expr::Vararg) }
472            Token::Ident(s)  => { self.advance(); Ok(Expr::Ident(s)) }
473            Token::LParen    => {
474                self.advance();
475                let e = self.parse_expr(0)?;
476                self.expect(&Token::RParen)?;
477                Ok(e)
478            }
479            Token::LBrace    => self.parse_table_ctor(),
480            Token::Function  => {
481                self.advance();
482                let (params, vararg, body) = self.parse_func_body()?;
483                Ok(Expr::FuncExpr { params, vararg, body })
484            }
485            t => Err(ParseError { message: format!("unexpected token: {:?}", t), line: self.peek_span_line() })
486        }
487    }
488
489    fn parse_table_ctor(&mut self) -> Result<Expr, ParseError> {
490        self.expect(&Token::LBrace)?;
491        let mut fields = Vec::new();
492        while !self.check(&Token::RBrace) && !self.check(&Token::Eof) {
493            let field = if self.check(&Token::LBracket) {
494                self.advance();
495                let key = self.parse_expr(0)?;
496                self.expect(&Token::RBracket)?;
497                self.expect(&Token::Eq)?;
498                let val = self.parse_expr(0)?;
499                TableField::ExprKey(key, val)
500            } else if let Token::Ident(name) = self.peek().clone() {
501                if self.tokens.get(self.pos + 1).map(|t| &t.token) == Some(&Token::Eq) {
502                    self.advance(); self.advance();
503                    let val = self.parse_expr(0)?;
504                    TableField::NameKey(name, val)
505                } else {
506                    TableField::Value(self.parse_expr(0)?)
507                }
508            } else {
509                TableField::Value(self.parse_expr(0)?)
510            };
511            fields.push(field);
512            if !self.consume_if(&Token::Comma) && !self.consume_if(&Token::Semicolon) { break; }
513        }
514        self.expect(&Token::RBrace)?;
515        Ok(Expr::TableCtor(fields))
516    }
517}
518
519/// Parse a script from source text (name, source order).
520pub fn parse_named(name: &str, source: &str) -> Result<Script, ParseError> {
521    parse(source, name)
522}
523
524/// Parse a script from source text.
525pub fn parse(source: &str, name: &str) -> Result<Script, ParseError> {
526    let mut lexer = super::lexer::Lexer::new(source);
527    let tokens = lexer.tokenize();
528    let mut parser = Parser::new(tokens);
529    parser.parse_script(name)
530}
531
532#[cfg(test)]
533mod tests {
534    use super::*;
535
536    fn parse_ok(src: &str) -> Script {
537        parse(src, "test").unwrap_or_else(|e| panic!("Parse failed: {}", e))
538    }
539
540    #[test]
541    fn test_parse_local_assign() {
542        let s = parse_ok("local x = 42");
543        assert_eq!(s.stmts.len(), 1);
544        assert!(matches!(&s.stmts[0], Stmt::LocalDecl { name, init: Some(Expr::Int(42)) } if name == "x"));
545    }
546
547    #[test]
548    fn test_parse_function() {
549        let s = parse_ok("function greet(name) return name end");
550        assert!(matches!(&s.stmts[0], Stmt::FuncDecl { .. }));
551    }
552
553    #[test]
554    fn test_parse_if_else() {
555        let s = parse_ok("if x > 0 then return 1 else return -1 end");
556        assert!(matches!(&s.stmts[0], Stmt::If { .. }));
557    }
558
559    #[test]
560    fn test_parse_while() {
561        let s = parse_ok("while i < 10 do i = i + 1 end");
562        assert!(matches!(&s.stmts[0], Stmt::While { .. }));
563    }
564
565    #[test]
566    fn test_parse_table_ctor() {
567        let s = parse_ok("local t = {x = 1, y = 2, 3}");
568        assert!(matches!(&s.stmts[0], Stmt::LocalDecl { init: Some(Expr::TableCtor(_)), .. }));
569    }
570
571    #[test]
572    fn test_parse_binary_expr() {
573        let s = parse_ok("local z = a + b * c");
574        if let Stmt::LocalDecl { init: Some(expr), .. } = &s.stmts[0] {
575            assert!(matches!(expr, Expr::Binary { op: BinOp::Add, .. }));
576        }
577    }
578
579    #[test]
580    fn test_parse_for_numeric() {
581        let s = parse_ok("for i = 1, 10, 2 do end");
582        assert!(matches!(&s.stmts[0], Stmt::NumericFor { var, .. } if var == "i"));
583    }
584
585    #[test]
586    fn test_parse_error() {
587        let result = parse("local = 123", "test");
588        assert!(result.is_err());
589    }
590}