Skip to main content

meow_meow_script/
parser.rs

1use crate::ast::{
2    AssignmentStatement, BinOpKind, BlockStatement, CallExpression, ComponentExpression,
3    ConstructorCall, ElseBranch, Expression, Ident, IfStatement, ImportItem, ReturnStatement, Span,
4    Statement, TableFieldValue, UnaryOpKind,
5};
6use crate::token::{Token, TokenKind};
7use std::collections::HashSet;
8
9#[derive(Debug, Clone, PartialEq)]
10pub struct ParseError {
11    pub message: String,
12    pub token_index: usize,
13    pub span: Span,
14}
15
16pub struct MeowMeowParser {
17    tokens: Vec<Token>,
18    pos: usize,
19    component_names: Option<HashSet<String>>,
20}
21
22impl MeowMeowParser {
23    pub fn new(tokens: Vec<Token>) -> Self {
24        Self { tokens, pos: 0, component_names: None }
25    }
26
27    /// Construct a parser whose component-expression disambiguation is driven
28    /// by a runtime catalog. Names are matched case-insensitively.
29    pub fn with_component_names(
30        tokens: Vec<Token>,
31        names: impl IntoIterator<Item = impl Into<String>>,
32    ) -> Self {
33        Self {
34            tokens,
35            pos: 0,
36            component_names: Some(
37                names
38                    .into_iter()
39                    .map(|name| name.into().to_lowercase())
40                    .collect(),
41            ),
42        }
43    }
44
45    fn is_component_name(&self, name: &str) -> bool {
46        self.component_names.as_ref().map_or_else(
47            || name.chars().next().is_some_and(char::is_uppercase),
48            |names| names.contains(&name.to_lowercase()),
49        )
50    }
51
52    pub fn parse_program(mut self) -> Result<Vec<Statement>, ParseError> {
53        let mut statements = Vec::new();
54        while !self.is_eof() {
55            if self.try_consume(&TokenKind::Semicolon) {
56                continue;
57            }
58            statements.push(self.parse_statement()?);
59        }
60        Ok(statements)
61    }
62
63    fn parse_statement(&mut self) -> Result<Statement, ParseError> {
64        match self.peek_kind() {
65            TokenKind::Let => {
66                self.consume(&TokenKind::Let)?;
67                let name = self.expect_ident()?;
68                self.consume(&TokenKind::Eq)?;
69                let value = self.parse_expression()?;
70                self.try_consume(&TokenKind::Semicolon);
71                Ok(Statement::Assignment(AssignmentStatement {
72                    name,
73                    value,
74                    exported: false,
75                }))
76            }
77            TokenKind::Fn => {
78                self.bump(); // consume `fn`
79                // `fn name(params) { body }` — named function sugar for `let name = fn(params) { body }`
80                if matches!(self.peek_kind(), TokenKind::Ident(_)) {
81                    let name = self.expect_ident()?;
82                    let func = self.parse_fn_body()?;
83                    self.try_consume(&TokenKind::Semicolon);
84                    Ok(Statement::Assignment(AssignmentStatement {
85                        name,
86                        value: func,
87                        exported: false,
88                    }))
89                } else {
90                    // anonymous fn in statement position — unusual but valid
91                    let func = self.parse_fn_body()?;
92                    self.try_consume(&TokenKind::Semicolon);
93                    Ok(Statement::Expression(func))
94                }
95            }
96            TokenKind::Export => {
97                self.bump(); // consume 'export'
98                let exported = true;
99                match self.peek_kind() {
100                    TokenKind::Let => {
101                        self.bump();
102                        let name = self.expect_ident()?;
103                        self.consume(&TokenKind::Eq)?;
104                        let value = self.parse_expression()?;
105                        self.try_consume(&TokenKind::Semicolon);
106                        Ok(Statement::Assignment(AssignmentStatement {
107                            name,
108                            value,
109                            exported,
110                        }))
111                    }
112                    TokenKind::Fn => {
113                        self.bump();
114                        let name = self.expect_ident()?;
115                        let func = self.parse_fn_body()?;
116                        self.try_consume(&TokenKind::Semicolon);
117                        Ok(Statement::Assignment(AssignmentStatement {
118                            name,
119                            value: func,
120                            exported,
121                        }))
122                    }
123                    _ => Err(self.err("Expected 'let' or 'fn' after 'export'")),
124                }
125            }
126            TokenKind::Import => {
127                self.bump(); // consume 'import'
128                self.consume(&TokenKind::LBrace)?;
129                let mut items = Vec::new();
130                if !self.try_consume(&TokenKind::RBrace) {
131                    loop {
132                        match self.peek_kind().clone() {
133                            TokenKind::Number(n) => {
134                                self.bump();
135                                let index = n as usize;
136                                self.consume(&TokenKind::As)?;
137                                let alias = self.expect_ident()?;
138                                items.push(ImportItem::PositionalAlias { index, alias });
139                            }
140                            TokenKind::Ident(_) => {
141                                let name = self.expect_ident()?;
142                                if self.try_consume(&TokenKind::As) {
143                                    let alias = self.expect_ident()?;
144                                    items.push(ImportItem::NamedAlias { name, alias });
145                                } else {
146                                    items.push(ImportItem::Named(name));
147                                }
148                            }
149                            _ => {
150                                return Err(
151                                    self.err("Expected identifier or number in import list")
152                                );
153                            }
154                        }
155                        if !self.try_consume(&TokenKind::Comma) {
156                            break;
157                        }
158                        if matches!(self.peek_kind(), TokenKind::RBrace) {
159                            break; // trailing comma
160                        }
161                    }
162                    self.consume(&TokenKind::RBrace)?;
163                }
164                self.consume(&TokenKind::From)?;
165                let path = match self.peek_kind().clone() {
166                    TokenKind::String(s) => {
167                        self.bump();
168                        s
169                    }
170                    _ => return Err(self.err("Expected string path after 'from'")),
171                };
172                self.try_consume(&TokenKind::Semicolon);
173                Ok(Statement::Import { items, path })
174            }
175            TokenKind::Return => {
176                self.consume(&TokenKind::Return)?;
177                if matches!(self.peek_kind(), TokenKind::Semicolon | TokenKind::RBrace) {
178                    self.try_consume(&TokenKind::Semicolon);
179                    return Ok(Statement::Return(ReturnStatement { value: None }));
180                }
181                let value = self.parse_expression()?;
182                self.try_consume(&TokenKind::Semicolon);
183                Ok(Statement::Return(ReturnStatement { value: Some(value) }))
184            }
185            TokenKind::If => Ok(Statement::If(self.parse_if_statement()?)),
186            TokenKind::For => {
187                self.consume(&TokenKind::For)?;
188                let binding = self.expect_ident()?;
189                self.consume(&TokenKind::In)?;
190                let iterable = self.parse_expression()?;
191                let body = self.parse_block_statement()?;
192                Ok(Statement::ForIn {
193                    binding,
194                    iterable,
195                    body,
196                })
197            }
198            TokenKind::While => {
199                self.consume(&TokenKind::While)?;
200                let condition = self.parse_expression()?;
201                let body = self.parse_block_statement()?;
202                Ok(Statement::While { condition, body })
203            }
204            TokenKind::Break => {
205                self.bump();
206                self.try_consume(&TokenKind::Semicolon);
207                Ok(Statement::Break)
208            }
209            TokenKind::Continue => {
210                self.bump();
211                self.try_consume(&TokenKind::Semicolon);
212                Ok(Statement::Continue)
213            }
214            TokenKind::LBrace => Ok(Statement::Block(self.parse_block_statement()?)),
215            _ => {
216                let expr = self.parse_expression()?;
217                if self.try_consume(&TokenKind::Eq) {
218                    if !is_assignable_target(&expr) {
219                        return Err(self.err("invalid reassignment target"));
220                    }
221                    let value = self.parse_expression()?;
222                    self.try_consume(&TokenKind::Semicolon);
223                    return Ok(Statement::Reassign {
224                        target: expr,
225                        value,
226                    });
227                }
228                self.try_consume(&TokenKind::Semicolon);
229                Ok(Statement::Expression(expr))
230            }
231        }
232    }
233
234    fn parse_block_statement(&mut self) -> Result<BlockStatement, ParseError> {
235        self.consume(&TokenKind::LBrace)?;
236        let mut statements = Vec::new();
237        while !self.try_consume(&TokenKind::RBrace) {
238            if self.is_eof() {
239                return Err(self.err("Unterminated block"));
240            }
241            if self.try_consume(&TokenKind::Semicolon) {
242                continue;
243            }
244            statements.push(self.parse_statement()?);
245        }
246        Ok(BlockStatement { statements })
247    }
248
249    fn parse_if_statement(&mut self) -> Result<IfStatement, ParseError> {
250        self.consume(&TokenKind::If)?;
251        // No parentheses: `if condition { }` — condition is everything up to `{`
252        let condition = self.parse_expression()?;
253        let then_branch = self.parse_block_statement()?;
254        let else_branch = if self.try_consume(&TokenKind::Else) {
255            if matches!(self.peek_kind(), TokenKind::If) {
256                Some(ElseBranch::If(Box::new(self.parse_if_statement()?)))
257            } else {
258                Some(ElseBranch::Block(self.parse_block_statement()?))
259            }
260        } else {
261            None
262        };
263        Ok(IfStatement {
264            condition,
265            then_branch,
266            else_branch,
267        })
268    }
269
270    /// Pratt parser entry point.
271    fn parse_expression(&mut self) -> Result<Expression, ParseError> {
272        self.parse_expr_bp(0)
273    }
274
275    /// Pratt/precedence-climbing expression parser.
276    /// `min_bp`: minimum binding power for the left side of the next infix op.
277    fn parse_expr_bp(&mut self, min_bp: u8) -> Result<Expression, ParseError> {
278        let mut lhs = self.parse_prefix()?;
279
280        loop {
281            if self.try_consume(&TokenKind::LBracket) {
282                let index = self.parse_expression()?;
283                self.consume(&TokenKind::RBracket)?;
284                lhs = Expression::Index {
285                    base: Box::new(lhs),
286                    index: Box::new(index),
287                };
288                continue;
289            }
290
291            if self.try_consume(&TokenKind::Dot) {
292                let member = self.expect_ident()?;
293                let dot_expr = Expression::BinaryOp {
294                    op: BinOpKind::Dot,
295                    lhs: Box::new(lhs),
296                    rhs: Box::new(Expression::Identifier(member)),
297                };
298                lhs = if self.try_consume(&TokenKind::LParen) {
299                    Expression::Call(CallExpression {
300                        callee: Box::new(dot_expr),
301                        args: self.parse_call_args()?,
302                    })
303                } else {
304                    dot_expr
305                };
306                continue;
307            }
308
309            let Some((l_bp, r_bp, op)) = self.peek_infix_op() else {
310                break;
311            };
312            if l_bp < min_bp {
313                break;
314            }
315            self.bump(); // consume the operator token
316            let rhs = self.parse_expr_bp(r_bp)?;
317            lhs = Expression::BinaryOp {
318                op,
319                lhs: Box::new(lhs),
320                rhs: Box::new(rhs),
321            };
322        }
323
324        Ok(lhs)
325    }
326
327    /// Binding powers for infix operators. Returns (left_bp, right_bp, op).
328    /// Left-associative: l_bp == r_bp - 1.
329    fn peek_infix_op(&self) -> Option<(u8, u8, BinOpKind)> {
330        match self.peek_kind() {
331            TokenKind::Arrow => Some((0, 1, BinOpKind::Query)),
332            TokenKind::PipeGt => Some((2, 3, BinOpKind::Pipe)),
333            TokenKind::PipePipe => Some((4, 5, BinOpKind::Or)),
334            TokenKind::AmpAmp => Some((6, 7, BinOpKind::And)),
335            TokenKind::EqEq => Some((8, 9, BinOpKind::Eq)),
336            TokenKind::BangEq => Some((8, 9, BinOpKind::NotEq)),
337            TokenKind::Lt => Some((10, 11, BinOpKind::Lt)),
338            TokenKind::Gt => Some((10, 11, BinOpKind::Gt)),
339            TokenKind::LtEq => Some((10, 11, BinOpKind::LtEq)),
340            TokenKind::GtEq => Some((10, 11, BinOpKind::GtEq)),
341            TokenKind::Plus => Some((12, 13, BinOpKind::Add)),
342            TokenKind::Minus => Some((12, 13, BinOpKind::Sub)),
343            TokenKind::Star => Some((14, 15, BinOpKind::Mul)),
344            TokenKind::Slash => Some((14, 15, BinOpKind::Div)),
345            TokenKind::Percent => Some((14, 15, BinOpKind::Rem)),
346            _ => None,
347        }
348    }
349
350    /// Parse prefix / atom expressions (nud).
351    fn parse_prefix(&mut self) -> Result<Expression, ParseError> {
352        match self.peek_kind() {
353            // Unary minus
354            TokenKind::Minus => {
355                self.bump();
356                let operand = self.parse_expr_bp(17)?;
357                Ok(Expression::UnaryOp {
358                    op: UnaryOpKind::Neg,
359                    operand: Box::new(operand),
360                })
361            }
362            // Logical not
363            TokenKind::Bang => {
364                self.bump();
365                let operand = self.parse_expr_bp(17)?;
366                Ok(Expression::UnaryOp {
367                    op: UnaryOpKind::Not,
368                    operand: Box::new(operand),
369                })
370            }
371            // Grouped expression
372            TokenKind::LParen => {
373                self.bump();
374                let inner = self.parse_expr_bp(0)?;
375                self.consume(&TokenKind::RParen)?;
376                Ok(inner)
377            }
378            // Function expression
379            TokenKind::Fn => {
380                self.bump();
381                self.parse_fn_body()
382            }
383            // Literals
384            TokenKind::String(_) => {
385                if let TokenKind::String(s) = self.bump().kind {
386                    Ok(Expression::String(s))
387                } else {
388                    unreachable!()
389                }
390            }
391            TokenKind::Number(_) => {
392                if let TokenKind::Number(n) = self.bump().kind {
393                    Ok(Expression::Number(n))
394                } else {
395                    unreachable!()
396                }
397            }
398            TokenKind::Dimension(_, _) => {
399                if let TokenKind::Dimension(n, unit) = self.bump().kind {
400                    Ok(Expression::Dimension(n, unit))
401                } else {
402                    unreachable!()
403                }
404            }
405            TokenKind::True => {
406                self.bump();
407                Ok(Expression::Bool(true))
408            }
409            TokenKind::False => {
410                self.bump();
411                Ok(Expression::Bool(false))
412            }
413            TokenKind::Null => {
414                self.bump();
415                Ok(Expression::Null)
416            }
417            TokenKind::LBrace => self.parse_table(),
418            TokenKind::LBracket => self.parse_array(),
419            TokenKind::Ident(_) => self.parse_ident_leading_expression(),
420            _ => Err(self.err("Unexpected token in expression")),
421        }
422    }
423
424    /// Parse `(params) { body }` — the part of a function after the `fn` keyword (and optional name).
425    fn parse_fn_body(&mut self) -> Result<Expression, ParseError> {
426        self.consume(&TokenKind::LParen)?;
427        let mut params = Vec::new();
428        if !matches!(self.peek_kind(), TokenKind::RParen) {
429            loop {
430                params.push(self.expect_ident()?);
431                if !self.try_consume(&TokenKind::Comma) {
432                    break;
433                }
434                if matches!(self.peek_kind(), TokenKind::RParen) {
435                    break;
436                }
437            }
438        }
439        self.consume(&TokenKind::RParen)?;
440        let body = self.parse_block_statement()?;
441        Ok(Expression::Function { params, body })
442    }
443
444    fn parse_array(&mut self) -> Result<Expression, ParseError> {
445        self.consume(&TokenKind::LBracket)?;
446        let mut items = Vec::new();
447        if self.try_consume(&TokenKind::RBracket) {
448            return Ok(Expression::Array(items));
449        }
450        loop {
451            items.push(self.parse_expression()?);
452            if self.try_consume(&TokenKind::Comma) {
453                if self.try_consume(&TokenKind::RBracket) {
454                    break;
455                }
456                continue;
457            }
458            self.consume(&TokenKind::RBracket)?;
459            break;
460        }
461        Ok(Expression::Array(items))
462    }
463
464    fn parse_table(&mut self) -> Result<Expression, ParseError> {
465        self.consume(&TokenKind::LBrace)?;
466        let mut fields = Vec::new();
467        if self.try_consume(&TokenKind::RBrace) {
468            return Ok(Expression::Table(fields));
469        }
470        loop {
471            let name = self.expect_ident()?;
472            self.consume(&TokenKind::Eq)?;
473            let value = self.parse_expression()?;
474            fields.push(TableFieldValue { name, value });
475
476            if self.try_consume(&TokenKind::Comma) {
477                if self.try_consume(&TokenKind::RBrace) {
478                    break;
479                }
480                continue;
481            }
482            if self.try_consume(&TokenKind::RBrace) {
483                break;
484            }
485        }
486        Ok(Expression::Table(fields))
487    }
488
489    /// Parse an expression that starts with an identifier.
490    ///
491    /// Disambiguates:
492    /// - Uppercase `Type.method(args)[.method2(args2)...] [{body}]` → ComponentExpression
493    /// - `ident(args)`                                              → free CallExpression
494    /// - `UpperType { body }`                                       → ComponentExpression, no ctor
495    /// - `ident`                                                    → bare Identifier
496    fn parse_ident_leading_expression(&mut self) -> Result<Expression, ParseError> {
497        let ident = self.expect_ident()?;
498        let is_builtin_table = matches!(ident.0.as_str(), "Math" | "MusicNote");
499        let is_component_type = self.is_component_name(&ident.0);
500
501        if !is_builtin_table && is_component_type && self.try_consume(&TokenKind::Dot) {
502            let method = self.expect_ident()?;
503            self.consume(&TokenKind::LParen)?;
504            let args = self.parse_call_args()?;
505
506            // `Type.method(args)[.chain(args)...] [{body}]` → ComponentExpression
507            let mut constructors = vec![ConstructorCall { method, args }];
508            while self.try_consume(&TokenKind::Dot) {
509                let chained = self.expect_ident()?;
510                self.consume(&TokenKind::LParen)?;
511                let chained_args = self.parse_call_args()?;
512                constructors.push(ConstructorCall {
513                    method: chained,
514                    args: chained_args,
515                });
516            }
517            let body = if matches!(self.peek_kind(), TokenKind::LBrace) {
518                self.parse_block_statement()?
519            } else {
520                BlockStatement { statements: vec![] }
521            };
522            return Ok(Expression::Component(ComponentExpression {
523                component_type: ident,
524                constructors,
525                body,
526            }));
527        }
528
529        // `ident(args)` → free call expression
530        if self.try_consume(&TokenKind::LParen) {
531            let args = self.parse_call_args()?;
532            return Ok(Expression::Call(CallExpression {
533                callee: Box::new(Expression::Identifier(ident)),
534                args,
535            }));
536        }
537
538        // `ident { body }` → component expression, no constructor.
539        // Convention: component type names always start uppercase; lowercase = variable.
540        // This prevents `if flag { ... }` from consuming `flag {` as a component expression.
541        let is_component_type = self.is_component_name(&ident.0);
542        if !is_builtin_table && is_component_type && matches!(self.peek_kind(), TokenKind::LBrace) {
543            let body = self.parse_block_statement()?;
544            return Ok(Expression::Component(ComponentExpression {
545                component_type: ident,
546                constructors: vec![],
547                body,
548            }));
549        }
550
551        // bare identifier
552        Ok(Expression::Identifier(ident))
553    }
554
555    fn parse_call_args(&mut self) -> Result<Vec<Expression>, ParseError> {
556        let mut args = Vec::new();
557        if self.try_consume(&TokenKind::RParen) {
558            return Ok(args);
559        }
560        loop {
561            args.push(self.parse_expression()?);
562            if self.try_consume(&TokenKind::Comma) {
563                if self.try_consume(&TokenKind::RParen) {
564                    break;
565                }
566                continue;
567            }
568            self.consume(&TokenKind::RParen)?;
569            break;
570        }
571        Ok(args)
572    }
573
574    fn expect_ident(&mut self) -> Result<Ident, ParseError> {
575        match self.bump().kind {
576            TokenKind::Ident(s) => Ok(Ident(s)),
577            _ => Err(self.err("Expected identifier")),
578        }
579    }
580
581    fn consume(&mut self, kind: &TokenKind) -> Result<(), ParseError> {
582        if self.try_consume(kind) {
583            Ok(())
584        } else {
585            Err(self.err(&format!("Expected {:?}", kind)))
586        }
587    }
588
589    fn try_consume(&mut self, kind: &TokenKind) -> bool {
590        if std::mem::discriminant(self.peek_kind()) == std::mem::discriminant(kind) {
591            self.pos += 1;
592            true
593        } else {
594            false
595        }
596    }
597
598    fn bump(&mut self) -> Token {
599        let t = self.tokens.get(self.pos).cloned().unwrap_or(Token {
600            kind: TokenKind::Eof,
601            span: crate::ast::Span::new(0, 0),
602        });
603        self.pos += 1;
604        t
605    }
606
607    fn peek_kind(&self) -> &TokenKind {
608        self.tokens
609            .get(self.pos)
610            .map(|t| &t.kind)
611            .unwrap_or(&TokenKind::Eof)
612    }
613
614    fn is_eof(&self) -> bool {
615        matches!(self.peek_kind(), TokenKind::Eof)
616    }
617
618    fn err(&self, message: &str) -> ParseError {
619        let span = self
620            .tokens
621            .get(self.pos)
622            .map(|t| t.span.clone())
623            .unwrap_or(Span::new(0, 0));
624        ParseError {
625            message: message.to_string(),
626            token_index: self.pos,
627            span,
628        }
629    }
630}
631
632fn is_assignable_target(expr: &Expression) -> bool {
633    match expr {
634        Expression::Identifier(_) => true,
635        Expression::Index { base, .. } => is_assignable_target(base),
636        Expression::BinaryOp {
637            op: crate::ast::BinOpKind::Dot,
638            lhs,
639            rhs,
640        } => is_assignable_target(lhs) && matches!(rhs.as_ref(), Expression::Identifier(_)),
641        _ => false,
642    }
643}