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 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(); 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 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(); 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(); 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; }
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 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 fn parse_expression(&mut self) -> Result<Expression, ParseError> {
272 self.parse_expr_bp(0)
273 }
274
275 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(); 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 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 fn parse_prefix(&mut self) -> Result<Expression, ParseError> {
352 match self.peek_kind() {
353 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 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 TokenKind::LParen => {
373 self.bump();
374 let inner = self.parse_expr_bp(0)?;
375 self.consume(&TokenKind::RParen)?;
376 Ok(inner)
377 }
378 TokenKind::Fn => {
380 self.bump();
381 self.parse_fn_body()
382 }
383 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 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 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 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 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 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 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}