Skip to main content

fiddler_script/
parser.rs

1//! Parser for FiddlerScript.
2//!
3//! This module implements a recursive descent parser with Pratt parsing
4//! for expression precedence handling.
5//!
6//! The parser transforms a token stream into an Abstract Syntax Tree (AST).
7
8use crate::ast::{BinaryOp, Block, ElseClause, Expression, Program, Statement, UnaryOp};
9use crate::error::ParseError;
10use crate::lexer::{Token, TokenKind};
11
12/// The parser for FiddlerScript.
13pub struct Parser {
14    /// The tokens to parse
15    tokens: Vec<Token>,
16    /// Current position in the token stream
17    current: usize,
18}
19
20impl Parser {
21    /// Create a new parser for the given tokens.
22    pub fn new(tokens: Vec<Token>) -> Self {
23        Self { tokens, current: 0 }
24    }
25
26    /// Parse a complete program.
27    pub fn parse(&mut self) -> Result<Program, ParseError> {
28        let mut statements = Vec::new();
29
30        while !self.is_at_end() {
31            statements.push(self.parse_statement()?);
32        }
33
34        Ok(Program::new(statements))
35    }
36
37    // === Helper methods ===
38
39    /// Check if we've reached the end of the token stream.
40    fn is_at_end(&self) -> bool {
41        self.peek().kind == TokenKind::Eof
42    }
43
44    /// Get the current token without consuming it.
45    fn peek(&self) -> &Token {
46        self.tokens.get(self.current).unwrap_or_else(|| {
47            self.tokens
48                .last()
49                .expect("Token stream should have at least EOF")
50        })
51    }
52
53    /// Get the previous token.
54    fn previous(&self) -> &Token {
55        &self.tokens[self.current.saturating_sub(1)]
56    }
57
58    /// Advance to the next token and return the current one.
59    fn advance(&mut self) -> &Token {
60        if !self.is_at_end() {
61            self.current += 1;
62        }
63        self.previous()
64    }
65
66    /// Check if the current token matches the given kind.
67    fn check(&self, kind: &TokenKind) -> bool {
68        if self.is_at_end() {
69            return false;
70        }
71        std::mem::discriminant(&self.peek().kind) == std::mem::discriminant(kind)
72    }
73
74    /// Consume the current token if it matches the given kind.
75    fn match_token(&mut self, kind: &TokenKind) -> bool {
76        if self.check(kind) {
77            self.advance();
78            true
79        } else {
80            false
81        }
82    }
83
84    /// Expect the current token to match the given kind, or return an error.
85    fn expect(&mut self, kind: &TokenKind, expected: &str) -> Result<&Token, ParseError> {
86        if self.check(kind) {
87            Ok(self.advance())
88        } else {
89            Err(ParseError::UnexpectedToken(
90                self.peek().kind.to_string(),
91                self.peek().position,
92                expected.to_string(),
93            ))
94        }
95    }
96
97    // === Statement parsing ===
98
99    /// Parse a statement.
100    fn parse_statement(&mut self) -> Result<Statement, ParseError> {
101        match &self.peek().kind {
102            TokenKind::Let => self.parse_let_statement(),
103            TokenKind::If => self.parse_if_statement(),
104            TokenKind::For => self.parse_for_statement(),
105            TokenKind::Return => self.parse_return_statement(),
106            TokenKind::Fn => self.parse_function_definition(),
107            TokenKind::LeftBrace => {
108                // Check if this is a dictionary literal (expression) or a block statement
109                if self.is_dictionary_literal() {
110                    self.parse_expression_statement()
111                } else {
112                    let block = self.parse_block()?;
113                    Ok(Statement::Block(block))
114                }
115            }
116            _ => self.parse_expression_statement(),
117        }
118    }
119
120    /// Parse a let statement: `let x = expr;`
121    fn parse_let_statement(&mut self) -> Result<Statement, ParseError> {
122        let position = self.peek().position;
123        self.advance(); // consume 'let'
124
125        let name = match &self.peek().kind {
126            TokenKind::Identifier(name) => name.clone(),
127            _ => return Err(ParseError::ExpectedIdentifier(self.peek().position)),
128        };
129        self.advance();
130
131        self.expect(&TokenKind::Assign, "=")?;
132        let value = self.parse_expression()?;
133        self.expect(&TokenKind::Semicolon, ";")?;
134
135        Ok(Statement::Let {
136            name,
137            value,
138            position,
139        })
140    }
141
142    /// Parse an if statement: `if (condition) { ... } else { ... }`
143    fn parse_if_statement(&mut self) -> Result<Statement, ParseError> {
144        let position = self.peek().position;
145        self.advance(); // consume 'if'
146
147        self.expect(&TokenKind::LeftParen, "(")?;
148        let condition = self.parse_expression()?;
149        self.expect(&TokenKind::RightParen, ")")?;
150
151        let then_block = self.parse_block()?;
152
153        let else_block = if self.match_token(&TokenKind::Else) {
154            if self.check(&TokenKind::If) {
155                // else if
156                Some(ElseClause::ElseIf(Box::new(self.parse_if_statement()?)))
157            } else {
158                // else block
159                Some(ElseClause::Block(self.parse_block()?))
160            }
161        } else {
162            None
163        };
164
165        Ok(Statement::If {
166            condition,
167            then_block,
168            else_block,
169            position,
170        })
171    }
172
173    /// Parse a for statement: `for (init; condition; update) { ... }`
174    fn parse_for_statement(&mut self) -> Result<Statement, ParseError> {
175        let position = self.peek().position;
176        self.advance(); // consume 'for'
177
178        self.expect(&TokenKind::LeftParen, "(")?;
179
180        // Init clause
181        let init = if self.match_token(&TokenKind::Semicolon) {
182            None
183        } else if self.check(&TokenKind::Let) {
184            Some(Box::new(self.parse_let_statement()?))
185        } else {
186            let expr = self.parse_expression()?;
187            let pos = expr.position();
188            self.expect(&TokenKind::Semicolon, ";")?;
189            Some(Box::new(Statement::Expression {
190                expression: expr,
191                position: pos,
192            }))
193        };
194
195        // Condition clause
196        let condition = if self.check(&TokenKind::Semicolon) {
197            None
198        } else {
199            Some(self.parse_expression()?)
200        };
201        self.expect(&TokenKind::Semicolon, ";")?;
202
203        // Update clause
204        let update = if self.check(&TokenKind::RightParen) {
205            None
206        } else {
207            Some(self.parse_expression()?)
208        };
209        self.expect(&TokenKind::RightParen, ")")?;
210
211        let body = self.parse_block()?;
212
213        Ok(Statement::For {
214            init,
215            condition,
216            update,
217            body,
218            position,
219        })
220    }
221
222    /// Parse a return statement: `return expr;`
223    fn parse_return_statement(&mut self) -> Result<Statement, ParseError> {
224        let position = self.peek().position;
225        self.advance(); // consume 'return'
226
227        let value = if self.check(&TokenKind::Semicolon) {
228            None
229        } else {
230            Some(self.parse_expression()?)
231        };
232
233        self.expect(&TokenKind::Semicolon, ";")?;
234
235        Ok(Statement::Return { value, position })
236    }
237
238    /// Parse a function definition: `fn name(params) { ... }`
239    fn parse_function_definition(&mut self) -> Result<Statement, ParseError> {
240        let position = self.peek().position;
241        self.advance(); // consume 'fn'
242
243        let name = match &self.peek().kind {
244            TokenKind::Identifier(name) => name.clone(),
245            _ => return Err(ParseError::ExpectedIdentifier(self.peek().position)),
246        };
247        self.advance();
248
249        self.expect(&TokenKind::LeftParen, "(")?;
250        let params = self.parse_parameters()?;
251        self.expect(&TokenKind::RightParen, ")")?;
252
253        let body = self.parse_block()?;
254
255        Ok(Statement::Function {
256            name,
257            params,
258            body,
259            position,
260        })
261    }
262
263    /// Parse function parameters.
264    fn parse_parameters(&mut self) -> Result<Vec<String>, ParseError> {
265        let mut params = Vec::new();
266
267        if !self.check(&TokenKind::RightParen) {
268            loop {
269                let pos = self.peek().position;
270                let name = match &self.peek().kind {
271                    TokenKind::Identifier(name) => name.clone(),
272                    _ => return Err(ParseError::ExpectedIdentifier(self.peek().position)),
273                };
274                self.advance();
275
276                // Check for duplicate parameter
277                if params.contains(&name) {
278                    return Err(ParseError::UnexpectedToken(
279                        name,
280                        pos,
281                        "unique parameter name (duplicate parameter)".to_string(),
282                    ));
283                }
284
285                params.push(name);
286
287                if !self.match_token(&TokenKind::Comma) {
288                    break;
289                }
290            }
291        }
292
293        Ok(params)
294    }
295
296    /// Parse an expression statement: `expr;`
297    fn parse_expression_statement(&mut self) -> Result<Statement, ParseError> {
298        let expression = self.parse_expression()?;
299        let position = expression.position();
300        self.expect(&TokenKind::Semicolon, ";")?;
301        Ok(Statement::Expression {
302            expression,
303            position,
304        })
305    }
306
307    /// Parse a block: `{ statements }`
308    fn parse_block(&mut self) -> Result<Block, ParseError> {
309        let position = self.peek().position;
310        self.expect(&TokenKind::LeftBrace, "{")?;
311
312        let mut statements = Vec::new();
313        while !self.check(&TokenKind::RightBrace) && !self.is_at_end() {
314            statements.push(self.parse_statement()?);
315        }
316
317        self.expect(&TokenKind::RightBrace, "}")?;
318        Ok(Block::new(statements, position))
319    }
320
321    // === Expression parsing (Pratt parsing) ===
322
323    /// Parse an expression.
324    pub fn parse_expression(&mut self) -> Result<Expression, ParseError> {
325        self.parse_assignment()
326    }
327
328    /// Parse assignment expression.
329    fn parse_assignment(&mut self) -> Result<Expression, ParseError> {
330        let expr = self.parse_or()?;
331
332        if self.match_token(&TokenKind::Assign) {
333            let position = self.previous().position;
334            let value = self.parse_assignment()?;
335
336            match expr {
337                Expression::Identifier { name, .. } => {
338                    return Ok(Expression::Assignment {
339                        name,
340                        value: Box::new(value),
341                        position,
342                    });
343                }
344                _ => return Err(ParseError::InvalidAssignmentTarget(position)),
345            }
346        }
347
348        Ok(expr)
349    }
350
351    /// Parse logical OR expression.
352    fn parse_or(&mut self) -> Result<Expression, ParseError> {
353        let mut left = self.parse_and()?;
354
355        while self.match_token(&TokenKind::Or) {
356            let position = self.previous().position;
357            let right = self.parse_and()?;
358            left = Expression::Binary {
359                left: Box::new(left),
360                operator: BinaryOp::Or,
361                right: Box::new(right),
362                position,
363            };
364        }
365
366        Ok(left)
367    }
368
369    /// Parse logical AND expression.
370    fn parse_and(&mut self) -> Result<Expression, ParseError> {
371        let mut left = self.parse_equality()?;
372
373        while self.match_token(&TokenKind::And) {
374            let position = self.previous().position;
375            let right = self.parse_equality()?;
376            left = Expression::Binary {
377                left: Box::new(left),
378                operator: BinaryOp::And,
379                right: Box::new(right),
380                position,
381            };
382        }
383
384        Ok(left)
385    }
386
387    /// Parse equality expression.
388    fn parse_equality(&mut self) -> Result<Expression, ParseError> {
389        let mut left = self.parse_comparison()?;
390
391        loop {
392            let op = if self.match_token(&TokenKind::Equal) {
393                BinaryOp::Equal
394            } else if self.match_token(&TokenKind::NotEqual) {
395                BinaryOp::NotEqual
396            } else {
397                break;
398            };
399
400            let position = self.previous().position;
401            let right = self.parse_comparison()?;
402            left = Expression::Binary {
403                left: Box::new(left),
404                operator: op,
405                right: Box::new(right),
406                position,
407            };
408        }
409
410        Ok(left)
411    }
412
413    /// Parse comparison expression.
414    fn parse_comparison(&mut self) -> Result<Expression, ParseError> {
415        let mut left = self.parse_addition()?;
416
417        loop {
418            let op = if self.match_token(&TokenKind::LessThan) {
419                BinaryOp::LessThan
420            } else if self.match_token(&TokenKind::LessEqual) {
421                BinaryOp::LessEqual
422            } else if self.match_token(&TokenKind::GreaterThan) {
423                BinaryOp::GreaterThan
424            } else if self.match_token(&TokenKind::GreaterEqual) {
425                BinaryOp::GreaterEqual
426            } else {
427                break;
428            };
429
430            let position = self.previous().position;
431            let right = self.parse_addition()?;
432            left = Expression::Binary {
433                left: Box::new(left),
434                operator: op,
435                right: Box::new(right),
436                position,
437            };
438        }
439
440        Ok(left)
441    }
442
443    /// Parse addition/subtraction expression.
444    fn parse_addition(&mut self) -> Result<Expression, ParseError> {
445        let mut left = self.parse_multiplication()?;
446
447        loop {
448            let op = if self.match_token(&TokenKind::Plus) {
449                BinaryOp::Add
450            } else if self.match_token(&TokenKind::Minus) {
451                BinaryOp::Subtract
452            } else {
453                break;
454            };
455
456            let position = self.previous().position;
457            let right = self.parse_multiplication()?;
458            left = Expression::Binary {
459                left: Box::new(left),
460                operator: op,
461                right: Box::new(right),
462                position,
463            };
464        }
465
466        Ok(left)
467    }
468
469    /// Parse multiplication/division/modulo expression.
470    fn parse_multiplication(&mut self) -> Result<Expression, ParseError> {
471        let mut left = self.parse_unary()?;
472
473        loop {
474            let op = if self.match_token(&TokenKind::Star) {
475                BinaryOp::Multiply
476            } else if self.match_token(&TokenKind::Slash) {
477                BinaryOp::Divide
478            } else if self.match_token(&TokenKind::Percent) {
479                BinaryOp::Modulo
480            } else {
481                break;
482            };
483
484            let position = self.previous().position;
485            let right = self.parse_unary()?;
486            left = Expression::Binary {
487                left: Box::new(left),
488                operator: op,
489                right: Box::new(right),
490                position,
491            };
492        }
493
494        Ok(left)
495    }
496
497    /// Parse unary expression.
498    fn parse_unary(&mut self) -> Result<Expression, ParseError> {
499        if self.match_token(&TokenKind::Bang) {
500            let position = self.previous().position;
501            let operand = self.parse_unary()?;
502            return Ok(Expression::Unary {
503                operator: UnaryOp::Not,
504                operand: Box::new(operand),
505                position,
506            });
507        }
508
509        if self.match_token(&TokenKind::Minus) {
510            let position = self.previous().position;
511            let operand = self.parse_unary()?;
512            return Ok(Expression::Unary {
513                operator: UnaryOp::Negate,
514                operand: Box::new(operand),
515                position,
516            });
517        }
518
519        self.parse_call()
520    }
521
522    /// Parse function call or method call.
523    ///
524    /// Handles both regular function calls `func(args)` and method calls `expr.method(args)`.
525    /// Method calls can be chained: `expr.method1().method2()`.
526    fn parse_call(&mut self) -> Result<Expression, ParseError> {
527        let mut expr = self.parse_primary()?;
528
529        loop {
530            if self.match_token(&TokenKind::Dot) {
531                // Parse method call: expr.method(args)
532                expr = self.parse_method_call_continuation(expr)?;
533            } else if self.is_function_call_start(&expr) {
534                // Parse function call: identifier(args)
535                expr = self.parse_function_call_continuation(expr)?;
536            } else {
537                // No more calls/method calls
538                break;
539            }
540        }
541
542        Ok(expr)
543    }
544
545    /// Check if the current position starts a function call on an identifier.
546    fn is_function_call_start(&self, expr: &Expression) -> bool {
547        matches!(expr, Expression::Identifier { .. }) && self.check(&TokenKind::LeftParen)
548    }
549
550    /// Parse the continuation of a method call after the dot has been consumed.
551    ///
552    /// Expects: `method(args)` where the dot has already been consumed.
553    fn parse_method_call_continuation(
554        &mut self,
555        receiver: Expression,
556    ) -> Result<Expression, ParseError> {
557        let method_pos = self.previous().position;
558
559        // Expect method name (identifier) with context-specific error
560        let method = match &self.peek().kind {
561            TokenKind::Identifier(name) => name.clone(),
562            _ => {
563                return Err(ParseError::UnexpectedToken(
564                    self.peek().kind.to_string(),
565                    self.peek().position,
566                    "method name".to_string(),
567                ))
568            }
569        };
570        self.advance();
571
572        // Expect opening parenthesis
573        self.expect(&TokenKind::LeftParen, "(")?;
574        let arguments = self.parse_arguments()?;
575        self.expect(&TokenKind::RightParen, ")")?;
576
577        Ok(Expression::MethodCall {
578            receiver: Box::new(receiver),
579            method,
580            arguments,
581            position: method_pos,
582        })
583    }
584
585    /// Parse the continuation of a function call on an identifier.
586    ///
587    /// Expects: `(args)` where the identifier has already been parsed.
588    fn parse_function_call_continuation(
589        &mut self,
590        expr: Expression,
591    ) -> Result<Expression, ParseError> {
592        let Expression::Identifier { name, position } = expr else {
593            // This should not happen if is_function_call_start was checked first
594            return Err(ParseError::ExpectedIdentifier(self.peek().position));
595        };
596
597        self.advance(); // consume LeftParen
598        let arguments = self.parse_arguments()?;
599        self.expect(&TokenKind::RightParen, ")")?;
600
601        Ok(Expression::Call {
602            function: name,
603            arguments,
604            position,
605        })
606    }
607
608    /// Parse function arguments.
609    fn parse_arguments(&mut self) -> Result<Vec<Expression>, ParseError> {
610        let mut args = Vec::new();
611
612        if !self.check(&TokenKind::RightParen) {
613            loop {
614                args.push(self.parse_expression()?);
615                if !self.match_token(&TokenKind::Comma) {
616                    break;
617                }
618            }
619        }
620
621        Ok(args)
622    }
623
624    /// Parse primary expression.
625    fn parse_primary(&mut self) -> Result<Expression, ParseError> {
626        let position = self.peek().position;
627
628        match &self.peek().kind {
629            TokenKind::Integer(value) => {
630                let value = *value;
631                self.advance();
632                Ok(Expression::Integer { value, position })
633            }
634            TokenKind::Float(value) => {
635                let value = *value;
636                self.advance();
637                Ok(Expression::Float { value, position })
638            }
639            TokenKind::String(value) => {
640                let value = value.clone();
641                self.advance();
642                Ok(Expression::String { value, position })
643            }
644            TokenKind::True => {
645                self.advance();
646                Ok(Expression::Boolean {
647                    value: true,
648                    position,
649                })
650            }
651            TokenKind::False => {
652                self.advance();
653                Ok(Expression::Boolean {
654                    value: false,
655                    position,
656                })
657            }
658            TokenKind::Identifier(name) => {
659                let name = name.clone();
660                self.advance();
661                Ok(Expression::Identifier { name, position })
662            }
663            TokenKind::LeftParen => {
664                self.advance();
665                let expression = self.parse_expression()?;
666                self.expect(&TokenKind::RightParen, ")")?;
667                Ok(Expression::Grouped {
668                    expression: Box::new(expression),
669                    position,
670                })
671            }
672            TokenKind::LeftBracket => self.parse_array_literal(),
673            TokenKind::LeftBrace => {
674                // Check if this is a dictionary literal or a block
675                // Dictionary literals start with { followed by a string or }
676                // We need to peek ahead to distinguish
677                if self.is_dictionary_literal() {
678                    self.parse_dictionary_literal()
679                } else {
680                    Err(ParseError::ExpectedExpression(position))
681                }
682            }
683            TokenKind::Eof => Err(ParseError::UnexpectedEof(position)),
684            _ => Err(ParseError::ExpectedExpression(position)),
685        }
686    }
687
688    /// Check if the current position starts a dictionary literal.
689    /// Dictionary literals are `{` followed by `}` or a string/identifier then `:`.
690    fn is_dictionary_literal(&self) -> bool {
691        if !self.check(&TokenKind::LeftBrace) {
692            return false;
693        }
694
695        // Look ahead: { } is empty dict, { "key": or { identifier: is dict
696        let mut lookahead = self.current + 1;
697
698        // Skip the {
699        if lookahead >= self.tokens.len() {
700            return false;
701        }
702
703        // Empty dict: {}
704        if matches!(
705            self.tokens.get(lookahead).map(|t| &t.kind),
706            Some(TokenKind::RightBrace)
707        ) {
708            return true;
709        }
710
711        // Check for string/identifier followed by colon
712        match self.tokens.get(lookahead).map(|t| &t.kind) {
713            Some(TokenKind::String(_)) | Some(TokenKind::Identifier(_)) => {
714                lookahead += 1;
715                matches!(
716                    self.tokens.get(lookahead).map(|t| &t.kind),
717                    Some(TokenKind::Colon)
718                )
719            }
720            _ => false,
721        }
722    }
723
724    /// Parse array literal: `[expr, expr, ...]`
725    fn parse_array_literal(&mut self) -> Result<Expression, ParseError> {
726        let position = self.peek().position;
727        self.expect(&TokenKind::LeftBracket, "[")?;
728
729        let mut elements = Vec::new();
730
731        if !self.check(&TokenKind::RightBracket) {
732            loop {
733                elements.push(self.parse_expression()?);
734                if !self.match_token(&TokenKind::Comma) {
735                    break;
736                }
737                // Allow trailing comma
738                if self.check(&TokenKind::RightBracket) {
739                    break;
740                }
741            }
742        }
743
744        self.expect(&TokenKind::RightBracket, "]")?;
745        Ok(Expression::ArrayLiteral { elements, position })
746    }
747
748    /// Parse dictionary literal: `{"key": value, "key2": value2, ...}`
749    fn parse_dictionary_literal(&mut self) -> Result<Expression, ParseError> {
750        let position = self.peek().position;
751        self.expect(&TokenKind::LeftBrace, "{")?;
752
753        let mut pairs = Vec::new();
754
755        if !self.check(&TokenKind::RightBrace) {
756            loop {
757                // Key must be a string or identifier
758                let key = match &self.peek().kind {
759                    TokenKind::String(s) => {
760                        let key_pos = self.peek().position;
761                        let s = s.clone();
762                        self.advance();
763                        Expression::String {
764                            value: s,
765                            position: key_pos,
766                        }
767                    }
768                    TokenKind::Identifier(name) => {
769                        // Allow identifier as shorthand for string key
770                        let key_pos = self.peek().position;
771                        let name = name.clone();
772                        self.advance();
773                        Expression::String {
774                            value: name,
775                            position: key_pos,
776                        }
777                    }
778                    _ => {
779                        return Err(ParseError::UnexpectedToken(
780                            self.peek().kind.to_string(),
781                            self.peek().position,
782                            "string key".to_string(),
783                        ))
784                    }
785                };
786
787                self.expect(&TokenKind::Colon, ":")?;
788                let value = self.parse_expression()?;
789                pairs.push((key, value));
790
791                if !self.match_token(&TokenKind::Comma) {
792                    break;
793                }
794                // Allow trailing comma
795                if self.check(&TokenKind::RightBrace) {
796                    break;
797                }
798            }
799        }
800
801        self.expect(&TokenKind::RightBrace, "}")?;
802        Ok(Expression::DictionaryLiteral { pairs, position })
803    }
804}
805
806#[cfg(test)]
807mod tests {
808    use super::*;
809    use crate::lexer::Lexer;
810
811    fn parse(source: &str) -> Result<Program, ParseError> {
812        let mut lexer = Lexer::new(source);
813        let tokens = lexer.tokenize().expect("Lexer error");
814        let mut parser = Parser::new(tokens);
815        parser.parse()
816    }
817
818    #[test]
819    fn test_let_statement() {
820        let program = parse("let x = 10;").unwrap();
821        assert_eq!(program.statements.len(), 1);
822        assert!(matches!(
823            &program.statements[0],
824            Statement::Let { name, .. } if name == "x"
825        ));
826    }
827
828    #[test]
829    fn test_expression_statement() {
830        let program = parse("42;").unwrap();
831        assert_eq!(program.statements.len(), 1);
832        assert!(matches!(
833            &program.statements[0],
834            Statement::Expression { .. }
835        ));
836    }
837
838    #[test]
839    fn test_binary_expression() {
840        let program = parse("1 + 2 * 3;").unwrap();
841        // Should parse as 1 + (2 * 3) due to precedence
842        if let Statement::Expression { expression, .. } = &program.statements[0] {
843            assert!(matches!(
844                expression,
845                Expression::Binary {
846                    operator: BinaryOp::Add,
847                    ..
848                }
849            ));
850        } else {
851            panic!("Expected expression statement");
852        }
853    }
854
855    #[test]
856    fn test_if_statement() {
857        let program = parse("if (x > 0) { let y = 1; }").unwrap();
858        assert!(matches!(&program.statements[0], Statement::If { .. }));
859    }
860
861    #[test]
862    fn test_if_else_statement() {
863        let program = parse("if (x > 0) { let y = 1; } else { let y = 2; }").unwrap();
864        if let Statement::If { else_block, .. } = &program.statements[0] {
865            assert!(else_block.is_some());
866        } else {
867            panic!("Expected if statement");
868        }
869    }
870
871    #[test]
872    fn test_for_statement() {
873        let program = parse("for (let i = 0; i < 10; i = i + 1) { print(i); }").unwrap();
874        assert!(matches!(&program.statements[0], Statement::For { .. }));
875    }
876
877    #[test]
878    fn test_function_definition() {
879        let program = parse("fn add(a, b) { return a + b; }").unwrap();
880        if let Statement::Function { name, params, .. } = &program.statements[0] {
881            assert_eq!(name, "add");
882            assert_eq!(params, &["a", "b"]);
883        } else {
884            panic!("Expected function definition");
885        }
886    }
887
888    #[test]
889    fn test_function_call() {
890        let program = parse("print(42);").unwrap();
891        if let Statement::Expression { expression, .. } = &program.statements[0] {
892            assert!(matches!(expression, Expression::Call { function, .. } if function == "print"));
893        } else {
894            panic!("Expected expression statement");
895        }
896    }
897
898    #[test]
899    fn test_unary_expression() {
900        let program = parse("-42;").unwrap();
901        if let Statement::Expression { expression, .. } = &program.statements[0] {
902            assert!(matches!(
903                expression,
904                Expression::Unary {
905                    operator: UnaryOp::Negate,
906                    ..
907                }
908            ));
909        } else {
910            panic!("Expected expression statement");
911        }
912    }
913
914    #[test]
915    fn test_grouped_expression() {
916        let program = parse("(1 + 2) * 3;").unwrap();
917        if let Statement::Expression { expression, .. } = &program.statements[0] {
918            if let Expression::Binary {
919                left,
920                operator: BinaryOp::Multiply,
921                ..
922            } = expression
923            {
924                assert!(matches!(left.as_ref(), Expression::Grouped { .. }));
925            } else {
926                panic!("Expected multiply expression");
927            }
928        } else {
929            panic!("Expected expression statement");
930        }
931    }
932
933    #[test]
934    fn test_assignment_expression() {
935        let program = parse("x = 10;").unwrap();
936        if let Statement::Expression { expression, .. } = &program.statements[0] {
937            assert!(matches!(expression, Expression::Assignment { name, .. } if name == "x"));
938        } else {
939            panic!("Expected expression statement");
940        }
941    }
942
943    #[test]
944    fn test_return_statement() {
945        let program = parse("return 42;").unwrap();
946        assert!(matches!(
947            &program.statements[0],
948            Statement::Return { value: Some(_), .. }
949        ));
950    }
951
952    #[test]
953    fn test_empty_return() {
954        let program = parse("return;").unwrap();
955        assert!(matches!(
956            &program.statements[0],
957            Statement::Return { value: None, .. }
958        ));
959    }
960
961    #[test]
962    fn test_method_call() {
963        let program = parse(r#""hello".len();"#).unwrap();
964        if let Statement::Expression { expression, .. } = &program.statements[0] {
965            assert!(matches!(
966                expression,
967                Expression::MethodCall { method, .. } if method == "len"
968            ));
969        } else {
970            panic!("Expected expression statement with method call");
971        }
972    }
973
974    #[test]
975    fn test_method_call_with_args() {
976        let program = parse(r#"arr.push(1);"#).unwrap();
977        if let Statement::Expression { expression, .. } = &program.statements[0] {
978            if let Expression::MethodCall {
979                method, arguments, ..
980            } = expression
981            {
982                assert_eq!(method, "push");
983                assert_eq!(arguments.len(), 1);
984            } else {
985                panic!("Expected method call");
986            }
987        } else {
988            panic!("Expected expression statement");
989        }
990    }
991
992    #[test]
993    fn test_chained_method_calls() {
994        let program = parse(r#"arr.push(1).len();"#).unwrap();
995        if let Statement::Expression { expression, .. } = &program.statements[0] {
996            // The outer call should be .len()
997            if let Expression::MethodCall {
998                method, receiver, ..
999            } = expression
1000            {
1001                assert_eq!(method, "len");
1002                // The receiver should be .push(1)
1003                assert!(matches!(
1004                    receiver.as_ref(),
1005                    Expression::MethodCall { method, .. } if method == "push"
1006                ));
1007            } else {
1008                panic!("Expected method call");
1009            }
1010        } else {
1011            panic!("Expected expression statement");
1012        }
1013    }
1014
1015    #[test]
1016    fn test_method_call_on_literal() {
1017        let program = parse(r#"[1, 2, 3].len();"#).unwrap();
1018        if let Statement::Expression { expression, .. } = &program.statements[0] {
1019            if let Expression::MethodCall {
1020                method, receiver, ..
1021            } = expression
1022            {
1023                assert_eq!(method, "len");
1024                assert!(matches!(receiver.as_ref(), Expression::ArrayLiteral { .. }));
1025            } else {
1026                panic!("Expected method call");
1027            }
1028        } else {
1029            panic!("Expected expression statement");
1030        }
1031    }
1032
1033    #[test]
1034    fn test_method_call_invalid_method_name_error() {
1035        // Test that invalid method name gives helpful error message
1036        let result = parse(r#""hello".123();"#);
1037        assert!(matches!(
1038            result,
1039            Err(ParseError::UnexpectedToken(_, _, expected)) if expected == "method name"
1040        ));
1041    }
1042
1043    #[test]
1044    fn test_method_call_missing_parens_error() {
1045        // Test that missing parentheses gives error
1046        let result = parse(r#""hello".len;"#);
1047        assert!(matches!(result, Err(ParseError::UnexpectedToken(_, _, _))));
1048    }
1049}