product_farm_farmscript/
parser.rs

1//! Parser for FarmScript
2//!
3//! Uses Pratt parsing for operator precedence handling.
4
5use crate::ast::*;
6use crate::lexer::Lexer;
7use crate::token::{Token, TokenKind, Span, TemplatePart};
8use thiserror::Error;
9
10/// Parse error
11#[derive(Debug, Error, Clone)]
12pub enum ParseError {
13    #[error("Unexpected token: expected {expected}, found {found} at position {position}")]
14    UnexpectedToken {
15        expected: String,
16        found: String,
17        position: usize,
18    },
19
20    #[error("Unexpected end of input")]
21    UnexpectedEof,
22
23    #[error("Invalid expression: {0}")]
24    InvalidExpression(String),
25
26    #[error("Lexer error: {0}")]
27    LexerError(String),
28}
29
30/// The FarmScript parser
31pub struct Parser<'a> {
32    lexer: Lexer<'a>,
33    current: Token,
34    previous: Token,
35}
36
37impl<'a> Parser<'a> {
38    /// Create a new parser
39    pub fn new(mut lexer: Lexer<'a>) -> Self {
40        let current = lexer.next_token();
41        Self {
42            lexer,
43            current: current.clone(),
44            previous: current,
45        }
46    }
47
48    /// Parse the entire expression
49    pub fn parse(&mut self) -> Result<Expr, ParseError> {
50        let expr = self.parse_expression()?;
51
52        if !self.is_at_end() {
53            return Err(ParseError::UnexpectedToken {
54                expected: "end of expression".into(),
55                found: format!("{}", self.current.kind),
56                position: self.current.span.start,
57            });
58        }
59
60        Ok(expr)
61    }
62
63    /// Parse an expression with minimum precedence
64    fn parse_expression(&mut self) -> Result<Expr, ParseError> {
65        self.parse_null_coalesce()
66    }
67
68    /// Parse null coalescing: a ?? b
69    fn parse_null_coalesce(&mut self) -> Result<Expr, ParseError> {
70        let mut expr = self.parse_or()?;
71
72        while self.match_token(TokenKind::QuestionQuestion) {
73            let right = self.parse_or()?;
74            expr = Expr::NullCoalesce(Box::new(expr), Box::new(right));
75        }
76
77        Ok(expr)
78    }
79
80    /// Parse OR: a or b
81    fn parse_or(&mut self) -> Result<Expr, ParseError> {
82        let mut expr = self.parse_and()?;
83
84        while self.match_token(TokenKind::Or) {
85            let right = self.parse_and()?;
86            expr = Expr::binary(expr, BinaryOp::Or, right);
87        }
88
89        Ok(expr)
90    }
91
92    /// Parse AND: a and b
93    fn parse_and(&mut self) -> Result<Expr, ParseError> {
94        let mut expr = self.parse_equality()?;
95
96        while self.match_token(TokenKind::And) {
97            let right = self.parse_equality()?;
98            expr = Expr::binary(expr, BinaryOp::And, right);
99        }
100
101        Ok(expr)
102    }
103
104    /// Parse equality: ==, ===, !=, !==, is, isnt, etc.
105    fn parse_equality(&mut self) -> Result<Expr, ParseError> {
106        let mut expr = self.parse_comparison()?;
107
108        loop {
109            let op = if self.match_token(TokenKind::EqEq) {
110                BinaryOp::Eq
111            } else if self.match_token(TokenKind::EqEqEq)
112                || self.match_token(TokenKind::Is)
113                || self.match_token(TokenKind::Eq)
114                || self.match_token(TokenKind::Equals)
115                || self.match_token(TokenKind::SameAs)
116            {
117                BinaryOp::StrictEq
118            } else if self.match_token(TokenKind::NotEq) || self.match_token(TokenKind::LtGt) {
119                BinaryOp::NotEq
120            } else if self.match_token(TokenKind::NotEqEq)
121                || self.match_token(TokenKind::Isnt)
122                || self.match_token(TokenKind::IsNot)
123                || self.match_token(TokenKind::NotEqKw)
124            {
125                BinaryOp::StrictNotEq
126            } else {
127                break;
128            };
129
130            let right = self.parse_comparison()?;
131            expr = Expr::binary(expr, op, right);
132        }
133
134        Ok(expr)
135    }
136
137    /// Parse comparison: <, >, <=, >=, in
138    fn parse_comparison(&mut self) -> Result<Expr, ParseError> {
139        let mut expr = self.parse_additive()?;
140
141        loop {
142            let op = if self.match_token(TokenKind::Lt) {
143                BinaryOp::Lt
144            } else if self.match_token(TokenKind::Gt) {
145                BinaryOp::Gt
146            } else if self.match_token(TokenKind::LtEq) {
147                BinaryOp::LtEq
148            } else if self.match_token(TokenKind::GtEq) {
149                BinaryOp::GtEq
150            } else if self.check(TokenKind::In) {
151                // Check for 'in' keyword used as operator
152                self.advance();
153                BinaryOp::In
154            } else {
155                break;
156            };
157
158            let right = self.parse_additive()?;
159            expr = Expr::binary(expr, op, right);
160        }
161
162        Ok(expr)
163    }
164
165    /// Parse additive: +, -
166    fn parse_additive(&mut self) -> Result<Expr, ParseError> {
167        let mut expr = self.parse_multiplicative()?;
168
169        loop {
170            let op = if self.match_token(TokenKind::Plus) {
171                BinaryOp::Add
172            } else if self.match_token(TokenKind::Minus) {
173                BinaryOp::Sub
174            } else {
175                break;
176            };
177
178            let right = self.parse_multiplicative()?;
179            expr = Expr::binary(expr, op, right);
180        }
181
182        Ok(expr)
183    }
184
185    /// Parse multiplicative: *, /, %, /?, /!
186    fn parse_multiplicative(&mut self) -> Result<Expr, ParseError> {
187        let mut expr = self.parse_power()?;
188
189        loop {
190            let op = if self.match_token(TokenKind::Star) {
191                BinaryOp::Mul
192            } else if self.match_token(TokenKind::Slash) {
193                BinaryOp::Div
194            } else if self.match_token(TokenKind::Percent) {
195                BinaryOp::Mod
196            } else if self.match_token(TokenKind::SlashQuestion) {
197                BinaryOp::SafeDivZero
198            } else if self.match_token(TokenKind::SlashBang) {
199                BinaryOp::SafeDivNull
200            } else {
201                break;
202            };
203
204            let right = self.parse_power()?;
205            expr = Expr::binary(expr, op, right);
206        }
207
208        Ok(expr)
209    }
210
211    /// Parse power: ^ (right-associative)
212    fn parse_power(&mut self) -> Result<Expr, ParseError> {
213        let expr = self.parse_unary()?;
214
215        if self.match_token(TokenKind::Caret) {
216            let right = self.parse_power()?; // Right-associative
217            return Ok(Expr::binary(expr, BinaryOp::Pow, right));
218        }
219
220        Ok(expr)
221    }
222
223    /// Parse unary: not, !, -, +
224    fn parse_unary(&mut self) -> Result<Expr, ParseError> {
225        if self.match_token(TokenKind::Not) {
226            let expr = self.parse_unary()?;
227            return Ok(Expr::unary(UnaryOp::Not, expr));
228        }
229
230        if self.match_token(TokenKind::Minus) {
231            let expr = self.parse_unary()?;
232            return Ok(Expr::unary(UnaryOp::Neg, expr));
233        }
234
235        if self.match_token(TokenKind::Plus) {
236            let expr = self.parse_unary()?;
237            return Ok(Expr::unary(UnaryOp::Plus, expr));
238        }
239
240        self.parse_postfix()
241    }
242
243    /// Parse postfix: x?, method calls, property access, indexing
244    fn parse_postfix(&mut self) -> Result<Expr, ParseError> {
245        let mut expr = self.parse_primary()?;
246
247        loop {
248            if self.match_token(TokenKind::Question) {
249                // Truthy postfix: x?
250                expr = Expr::Postfix(Box::new(PostfixExpr {
251                    expr,
252                    op: PostfixOp::Truthy,
253                    span: self.previous.span,
254                }));
255            } else if self.match_token(TokenKind::Dot) {
256                // Property access or method call
257                let name = self.expect_identifier()?;
258
259                if self.match_token(TokenKind::LParen) {
260                    // Method call: obj.method(args...)
261                    let args = self.parse_args()?;
262                    expr = Expr::MethodCall(Box::new(MethodCallExpr {
263                        object: expr,
264                        method: name,
265                        args,
266                        span: self.previous.span,
267                    }));
268                } else {
269                    // Property access: obj.prop
270                    expr = Expr::Property(Box::new(PropertyExpr {
271                        object: expr,
272                        property: name,
273                        span: self.previous.span,
274                    }));
275                }
276            } else if self.match_token(TokenKind::LBracket) {
277                // Index access: arr[idx]
278                let index = self.parse_expression()?;
279                self.expect(TokenKind::RBracket)?;
280                expr = Expr::Index(Box::new(IndexExpr {
281                    object: expr,
282                    index,
283                    span: self.previous.span,
284                }));
285            } else {
286                break;
287            }
288        }
289
290        Ok(expr)
291    }
292
293    /// Parse primary expressions
294    fn parse_primary(&mut self) -> Result<Expr, ParseError> {
295        // Literals
296        if let TokenKind::Integer(n) = self.current.kind {
297            self.advance();
298            return Ok(Expr::int(n));
299        }
300
301        if let TokenKind::Float(n) = self.current.kind {
302            self.advance();
303            return Ok(Expr::float(n));
304        }
305
306        if let TokenKind::String(ref s) = self.current.kind {
307            let s = s.clone();
308            self.advance();
309            return Ok(Expr::string(s));
310        }
311
312        if let TokenKind::TemplateString(ref parts) = self.current.kind {
313            let parts = parts.clone();
314            self.advance();
315            return self.parse_template_parts(parts);
316        }
317
318        if self.match_token(TokenKind::True) {
319            return Ok(Expr::bool(true));
320        }
321
322        if self.match_token(TokenKind::False) {
323            return Ok(Expr::bool(false));
324        }
325
326        if self.match_token(TokenKind::Null) {
327            return Ok(Expr::null());
328        }
329
330        // If expression
331        if self.match_token(TokenKind::If) {
332            return self.parse_if_expression();
333        }
334
335        // Let expression
336        if self.match_token(TokenKind::Let) {
337            return self.parse_let_expression();
338        }
339
340        // SQL-like query
341        if self.match_token(TokenKind::From) {
342            return self.parse_query_expression();
343        }
344
345        // Array literal
346        if self.match_token(TokenKind::LBracket) {
347            return self.parse_array_literal();
348        }
349
350        // Grouped expression or lambda
351        if self.match_token(TokenKind::LParen) {
352            return self.parse_grouped_or_lambda();
353        }
354
355        // Identifier or function call
356        if let TokenKind::Ident(ref name) = self.current.kind {
357            let name = name.clone();
358            let span = self.current.span;
359            self.advance();
360
361            // Check for lambda: x => ...
362            if self.match_token(TokenKind::Arrow) {
363                let body = self.parse_expression()?;
364                return Ok(Expr::Lambda(Box::new(LambdaExpr {
365                    params: vec![name],
366                    body,
367                    span,
368                })));
369            }
370
371            // Check for function call
372            if self.match_token(TokenKind::LParen) {
373                let args = self.parse_args()?;
374                return Ok(Expr::Call(Box::new(CallExpr {
375                    function: name,
376                    args,
377                    span,
378                })));
379            }
380
381            // Simple variable reference
382            return Ok(Expr::Var(VarExpr { name, span }));
383        }
384
385        // Handle keyword-based function names (map, filter, etc.)
386        if self.is_array_function_keyword() {
387            let name = format!("{}", self.current.kind);
388            let span = self.current.span;
389            self.advance();
390
391            if self.match_token(TokenKind::LParen) {
392                let args = self.parse_args()?;
393                return Ok(Expr::Call(Box::new(CallExpr {
394                    function: name,
395                    args,
396                    span,
397                })));
398            }
399
400            return Err(ParseError::InvalidExpression(
401                format!("'{}' requires arguments", name),
402            ));
403        }
404
405        Err(ParseError::UnexpectedToken {
406            expected: "expression".into(),
407            found: format!("{}", self.current.kind),
408            position: self.current.span.start,
409        })
410    }
411
412    /// Check if current token is an array function keyword
413    fn is_array_function_keyword(&self) -> bool {
414        matches!(
415            self.current.kind,
416            TokenKind::Map
417                | TokenKind::Filter
418                | TokenKind::Reduce
419                | TokenKind::All
420                | TokenKind::Some
421                | TokenKind::Merge
422                | TokenKind::Missing
423                | TokenKind::MissingSome
424                | TokenKind::Log
425                | TokenKind::Contains
426        )
427    }
428
429    /// Parse template string parts
430    fn parse_template_parts(&mut self, parts: Vec<TemplatePart>) -> Result<Expr, ParseError> {
431        let mut exprs = Vec::new();
432
433        for part in parts {
434            match part {
435                TemplatePart::Literal(s) => {
436                    exprs.push(TemplateExpr::Literal(s));
437                }
438                TemplatePart::Expr(expr_str) => {
439                    // Parse the expression string
440                    let mut inner_parser = Parser::new(Lexer::new(&expr_str));
441                    let expr = inner_parser.parse()?;
442                    exprs.push(TemplateExpr::Expr(expr));
443                }
444            }
445        }
446
447        Ok(Expr::Template(exprs))
448    }
449
450    /// Parse if expression: if cond then a else b
451    fn parse_if_expression(&mut self) -> Result<Expr, ParseError> {
452        let span = self.previous.span;
453        let condition = self.parse_expression()?;
454
455        self.expect(TokenKind::Then)?;
456        let then_branch = self.parse_expression()?;
457
458        let mut else_ifs = Vec::new();
459        let mut else_branch = None;
460
461        // Parse else if / else chains
462        while self.match_token(TokenKind::Else) {
463            if self.match_token(TokenKind::If) {
464                // else if
465                let cond = self.parse_expression()?;
466                self.expect(TokenKind::Then)?;
467                let then = self.parse_expression()?;
468                else_ifs.push((cond, then));
469            } else {
470                // final else
471                else_branch = Some(self.parse_expression()?);
472                break;
473            }
474        }
475
476        Ok(Expr::If(Box::new(IfExpr {
477            condition,
478            then_branch,
479            else_branch,
480            else_ifs,
481            span,
482        })))
483    }
484
485    /// Parse let expression: let x = expr in body
486    /// Note: For complex expressions with comparison/in operators, use parentheses
487    fn parse_let_expression(&mut self) -> Result<Expr, ParseError> {
488        let span = self.previous.span;
489        let name = self.expect_identifier()?;
490
491        self.expect_kind(TokenKind::Assign)?; // Use = for assignment
492
493        // Parse value - use parse_additive to stop before 'in' keyword
494        // For comparisons in value, use parentheses: let x = (a > b) in ...
495        let value = self.parse_additive()?;
496
497        // 'in' is required to separate value from body
498        self.expect_kind(TokenKind::In)?;
499
500        let body = self.parse_expression()?;
501
502        Ok(Expr::Let(Box::new(LetExpr {
503            name,
504            value,
505            body,
506            span,
507        })))
508    }
509
510    /// Parse SQL-like query: from items where cond select expr
511    fn parse_query_expression(&mut self) -> Result<Expr, ParseError> {
512        let span = self.previous.span;
513        let source = self.parse_primary()?; // Source is a simple expression
514
515        let filter = if self.match_token(TokenKind::Where) {
516            Some(self.parse_expression()?)
517        } else {
518            None
519        };
520
521        self.expect(TokenKind::Select)?;
522        let projection = self.parse_expression()?;
523
524        Ok(Expr::Query(Box::new(QueryExpr {
525            source,
526            filter,
527            projection,
528            span,
529        })))
530    }
531
532    /// Parse array literal: [a, b, c]
533    fn parse_array_literal(&mut self) -> Result<Expr, ParseError> {
534        let mut items = Vec::new();
535
536        if !self.check(TokenKind::RBracket) {
537            loop {
538                items.push(self.parse_expression()?);
539                if !self.match_token(TokenKind::Comma) {
540                    break;
541                }
542                // Allow trailing comma
543                if self.check(TokenKind::RBracket) {
544                    break;
545                }
546            }
547        }
548
549        self.expect(TokenKind::RBracket)?;
550        Ok(Expr::Array(items))
551    }
552
553    /// Parse grouped expression or lambda
554    fn parse_grouped_or_lambda(&mut self) -> Result<Expr, ParseError> {
555        // Check if this is a lambda with multiple params: (x, y) => ...
556        if self.check_ident() {
557            let first_name = self.expect_identifier()?;
558
559            if self.match_token(TokenKind::Comma) {
560                // Multiple params lambda
561                let mut params = vec![first_name];
562
563                loop {
564                    params.push(self.expect_identifier()?);
565                    if !self.match_token(TokenKind::Comma) {
566                        break;
567                    }
568                }
569
570                self.expect(TokenKind::RParen)?;
571                self.expect(TokenKind::Arrow)?;
572                let body = self.parse_expression()?;
573
574                return Ok(Expr::Lambda(Box::new(LambdaExpr {
575                    params,
576                    body,
577                    span: Span::new(0, 0),
578                })));
579            }
580
581            // Check for single-param lambda with parens: (x) => ...
582            if self.match_token(TokenKind::RParen) {
583                if self.match_token(TokenKind::Arrow) {
584                    let body = self.parse_expression()?;
585                    return Ok(Expr::Lambda(Box::new(LambdaExpr {
586                        params: vec![first_name],
587                        body,
588                        span: Span::new(0, 0),
589                    })));
590                }
591
592                // Just a grouped identifier
593                return Ok(Expr::Var(VarExpr {
594                    name: first_name,
595                    span: Span::new(0, 0),
596                }));
597            }
598
599            // It's a grouped expression starting with an identifier
600            // We need to "unread" the identifier...
601            // This is tricky. Let's just parse a fresh expression.
602            let var = Expr::Var(VarExpr {
603                name: first_name,
604                span: Span::new(0, 0),
605            });
606
607            // Continue parsing the rest of the expression
608            let expr = self.continue_expression(var)?;
609            self.expect(TokenKind::RParen)?;
610            return Ok(expr);
611        }
612
613        // Regular grouped expression
614        let expr = self.parse_expression()?;
615        self.expect(TokenKind::RParen)?;
616        Ok(expr)
617    }
618
619    /// Continue parsing an expression after we've already parsed part of it
620    fn continue_expression(&mut self, left: Expr) -> Result<Expr, ParseError> {
621        // This is called when we've consumed an identifier inside parens
622        // and need to continue parsing as if it was a normal expression
623        let mut expr = left;
624
625        // Handle postfix operators on the initial expression
626        loop {
627            if self.match_token(TokenKind::Question) {
628                expr = Expr::Postfix(Box::new(PostfixExpr {
629                    expr,
630                    op: PostfixOp::Truthy,
631                    span: self.previous.span,
632                }));
633            } else if self.match_token(TokenKind::Dot) {
634                let name = self.expect_identifier()?;
635                if self.match_token(TokenKind::LParen) {
636                    let args = self.parse_args()?;
637                    expr = Expr::MethodCall(Box::new(MethodCallExpr {
638                        object: expr,
639                        method: name,
640                        args,
641                        span: self.previous.span,
642                    }));
643                } else {
644                    expr = Expr::Property(Box::new(PropertyExpr {
645                        object: expr,
646                        property: name,
647                        span: self.previous.span,
648                    }));
649                }
650            } else if self.match_token(TokenKind::LBracket) {
651                let index = self.parse_expression()?;
652                self.expect(TokenKind::RBracket)?;
653                expr = Expr::Index(Box::new(IndexExpr {
654                    object: expr,
655                    index,
656                    span: self.previous.span,
657                }));
658            } else {
659                break;
660            }
661        }
662
663        // Now handle binary operators
664        // We need to handle all precedence levels
665        expr = self.parse_binary_rest(expr, 0)?;
666
667        Ok(expr)
668    }
669
670    /// Parse the rest of a binary expression given a left operand
671    fn parse_binary_rest(&mut self, mut left: Expr, min_prec: u8) -> Result<Expr, ParseError> {
672        loop {
673            let (op, prec) = match &self.current.kind {
674                TokenKind::Or => (BinaryOp::Or, 1),
675                TokenKind::And => (BinaryOp::And, 2),
676                TokenKind::EqEq => (BinaryOp::Eq, 3),
677                TokenKind::EqEqEq | TokenKind::Is | TokenKind::Eq
678                | TokenKind::Equals | TokenKind::SameAs => (BinaryOp::StrictEq, 3),
679                TokenKind::NotEq | TokenKind::LtGt => (BinaryOp::NotEq, 3),
680                TokenKind::NotEqEq | TokenKind::Isnt
681                | TokenKind::IsNot | TokenKind::NotEqKw => (BinaryOp::StrictNotEq, 3),
682                TokenKind::Lt => (BinaryOp::Lt, 4),
683                TokenKind::Gt => (BinaryOp::Gt, 4),
684                TokenKind::LtEq => (BinaryOp::LtEq, 4),
685                TokenKind::GtEq => (BinaryOp::GtEq, 4),
686                TokenKind::Plus => (BinaryOp::Add, 5),
687                TokenKind::Minus => (BinaryOp::Sub, 5),
688                TokenKind::Star => (BinaryOp::Mul, 6),
689                TokenKind::Slash => (BinaryOp::Div, 6),
690                TokenKind::Percent => (BinaryOp::Mod, 6),
691                TokenKind::SlashQuestion => (BinaryOp::SafeDivZero, 6),
692                TokenKind::SlashBang => (BinaryOp::SafeDivNull, 6),
693                TokenKind::Caret => (BinaryOp::Pow, 7),
694                _ => break,
695            };
696
697            if prec < min_prec {
698                break;
699            }
700
701            self.advance();
702            let right = self.parse_unary()?;
703            let next_min = if op.is_right_assoc() { prec } else { prec + 1 };
704            let right = self.parse_binary_rest(right, next_min)?;
705            left = Expr::binary(left, op, right);
706        }
707
708        Ok(left)
709    }
710
711    /// Parse function arguments
712    fn parse_args(&mut self) -> Result<Vec<Expr>, ParseError> {
713        let mut args = Vec::new();
714
715        if !self.check(TokenKind::RParen) {
716            loop {
717                args.push(self.parse_expression()?);
718                if !self.match_token(TokenKind::Comma) {
719                    break;
720                }
721            }
722        }
723
724        self.expect(TokenKind::RParen)?;
725        Ok(args)
726    }
727
728    /// Expect a specific token kind
729    fn expect(&mut self, kind: TokenKind) -> Result<(), ParseError> {
730        if self.check(kind.clone()) {
731            self.advance();
732            Ok(())
733        } else {
734            Err(ParseError::UnexpectedToken {
735                expected: format!("{}", kind),
736                found: format!("{}", self.current.kind),
737                position: self.current.span.start,
738            })
739        }
740    }
741
742    /// Expect a specific token kind (with owned kind)
743    fn expect_kind(&mut self, kind: TokenKind) -> Result<(), ParseError> {
744        self.expect(kind)
745    }
746
747    /// Expect an identifier and return its name
748    /// Also accepts keywords that can be used as method names (filter, map, etc.)
749    fn expect_identifier(&mut self) -> Result<String, ParseError> {
750        // First check for actual identifier
751        if let TokenKind::Ident(name) = &self.current.kind {
752            let name = name.clone();
753            self.advance();
754            return Ok(name);
755        }
756
757        // Allow keywords as method/property names
758        let name = match &self.current.kind {
759            TokenKind::Map => "map",
760            TokenKind::Filter => "filter",
761            TokenKind::Reduce => "reduce",
762            TokenKind::All => "all",
763            TokenKind::Some => "some",
764            TokenKind::Merge => "merge",
765            TokenKind::Contains => "contains",
766            TokenKind::Missing => "missing",
767            TokenKind::MissingSome => "missing_some",
768            TokenKind::Log => "log",
769            TokenKind::In => "in",
770            _ => {
771                return Err(ParseError::UnexpectedToken {
772                    expected: "identifier".into(),
773                    found: format!("{}", self.current.kind),
774                    position: self.current.span.start,
775                });
776            }
777        };
778
779        self.advance();
780        Ok(name.to_string())
781    }
782
783    /// Check if current token is an identifier
784    fn check_ident(&self) -> bool {
785        matches!(self.current.kind, TokenKind::Ident(_))
786    }
787
788    /// Check if current token matches the expected kind
789    fn check(&self, kind: TokenKind) -> bool {
790        std::mem::discriminant(&self.current.kind) == std::mem::discriminant(&kind)
791    }
792
793    /// Match and consume if current token matches
794    fn match_token(&mut self, kind: TokenKind) -> bool {
795        if self.check(kind) {
796            self.advance();
797            true
798        } else {
799            false
800        }
801    }
802
803    /// Advance to the next token
804    fn advance(&mut self) {
805        self.previous = self.current.clone();
806        self.current = self.lexer.next_token();
807    }
808
809    /// Check if at end of input
810    fn is_at_end(&self) -> bool {
811        matches!(self.current.kind, TokenKind::Eof)
812    }
813}
814
815#[cfg(test)]
816mod tests {
817    use super::*;
818
819    fn parse(source: &str) -> Result<Expr, ParseError> {
820        let lexer = Lexer::new(source);
821        let mut parser = Parser::new(lexer);
822        parser.parse()
823    }
824
825    #[test]
826    fn test_simple_literal() {
827        assert_eq!(parse("42").unwrap(), Expr::int(42));
828        assert_eq!(parse("3.14").unwrap(), Expr::float(3.14));
829        assert_eq!(parse("true").unwrap(), Expr::bool(true));
830        assert_eq!(parse("null").unwrap(), Expr::null());
831    }
832
833    #[test]
834    fn test_variable() {
835        let expr = parse("foo").unwrap();
836        match expr {
837            Expr::Var(v) => assert_eq!(v.name, "foo"),
838            _ => panic!("Expected variable"),
839        }
840    }
841
842    #[test]
843    fn test_path_variable() {
844        let expr = parse("/users/count").unwrap();
845        match expr {
846            Expr::Var(v) => assert_eq!(v.name, "/users/count"),
847            _ => panic!("Expected variable"),
848        }
849    }
850
851    #[test]
852    fn test_binary_operators() {
853        let expr = parse("a + b").unwrap();
854        match expr {
855            Expr::Binary(b) => {
856                assert_eq!(b.op, BinaryOp::Add);
857            }
858            _ => panic!("Expected binary"),
859        }
860    }
861
862    #[test]
863    fn test_operator_precedence() {
864        // a + b * c should parse as a + (b * c)
865        let expr = parse("a + b * c").unwrap();
866        match expr {
867            Expr::Binary(b) => {
868                assert_eq!(b.op, BinaryOp::Add);
869                match &b.right {
870                    Expr::Binary(inner) => {
871                        assert_eq!(inner.op, BinaryOp::Mul);
872                    }
873                    _ => panic!("Expected nested binary"),
874                }
875            }
876            _ => panic!("Expected binary"),
877        }
878    }
879
880    #[test]
881    fn test_comparison() {
882        let expr = parse("x < 10").unwrap();
883        match expr {
884            Expr::Binary(b) => {
885                assert_eq!(b.op, BinaryOp::Lt);
886            }
887            _ => panic!("Expected binary"),
888        }
889    }
890
891    #[test]
892    fn test_logical_and() {
893        let expr = parse("a and b").unwrap();
894        match expr {
895            Expr::Binary(b) => {
896                assert_eq!(b.op, BinaryOp::And);
897            }
898            _ => panic!("Expected binary"),
899        }
900    }
901
902    #[test]
903    fn test_equality_synonyms() {
904        // All should parse to StrictEq
905        for source in &["a === b", "a is b", "a eq b", "a equals b", "a same_as b"] {
906            let expr = parse(source).unwrap();
907            match expr {
908                Expr::Binary(b) => {
909                    assert_eq!(b.op, BinaryOp::StrictEq, "Failed for: {}", source);
910                }
911                _ => panic!("Expected binary for: {}", source),
912            }
913        }
914    }
915
916    #[test]
917    fn test_if_expression() {
918        let expr = parse("if x > 0 then 1 else 0").unwrap();
919        match expr {
920            Expr::If(i) => {
921                assert!(i.else_branch.is_some());
922            }
923            _ => panic!("Expected if"),
924        }
925    }
926
927    #[test]
928    fn test_function_call() {
929        let expr = parse("max(a, b, c)").unwrap();
930        match expr {
931            Expr::Call(c) => {
932                assert_eq!(c.function, "max");
933                assert_eq!(c.args.len(), 3);
934            }
935            _ => panic!("Expected call"),
936        }
937    }
938
939    #[test]
940    fn test_method_call() {
941        let expr = parse("items.filter(x => x > 0)").unwrap();
942        match expr {
943            Expr::MethodCall(m) => {
944                assert_eq!(m.method, "filter");
945            }
946            _ => panic!("Expected method call"),
947        }
948    }
949
950    #[test]
951    fn test_lambda() {
952        let expr = parse("x => x * 2").unwrap();
953        match expr {
954            Expr::Lambda(l) => {
955                assert_eq!(l.params, vec!["x"]);
956            }
957            _ => panic!("Expected lambda"),
958        }
959    }
960
961    #[test]
962    fn test_array_literal() {
963        let expr = parse("[1, 2, 3]").unwrap();
964        match expr {
965            Expr::Array(items) => {
966                assert_eq!(items.len(), 3);
967            }
968            _ => panic!("Expected array"),
969        }
970    }
971
972    #[test]
973    fn test_in_operator() {
974        let expr = parse("x in [1, 2, 3]").unwrap();
975        match expr {
976            Expr::Binary(b) => {
977                assert_eq!(b.op, BinaryOp::In);
978            }
979            _ => panic!("Expected binary"),
980        }
981    }
982
983    #[test]
984    fn test_safe_division() {
985        let expr = parse("a /? b").unwrap();
986        match expr {
987            Expr::Binary(b) => {
988                assert_eq!(b.op, BinaryOp::SafeDivZero);
989            }
990            _ => panic!("Expected binary"),
991        }
992
993        let expr = parse("a /! b").unwrap();
994        match expr {
995            Expr::Binary(b) => {
996                assert_eq!(b.op, BinaryOp::SafeDivNull);
997            }
998            _ => panic!("Expected binary"),
999        }
1000    }
1001
1002    #[test]
1003    fn test_truthy_postfix() {
1004        let expr = parse("x?").unwrap();
1005        match expr {
1006            Expr::Postfix(p) => {
1007                assert_eq!(p.op, PostfixOp::Truthy);
1008            }
1009            _ => panic!("Expected postfix"),
1010        }
1011    }
1012
1013    #[test]
1014    fn test_null_coalesce() {
1015        let expr = parse("a ?? b").unwrap();
1016        match expr {
1017            Expr::NullCoalesce(_, _) => {}
1018            _ => panic!("Expected null coalesce"),
1019        }
1020    }
1021
1022    #[test]
1023    fn test_complex_expression() {
1024        // This is a real expression from the fixtures
1025        let expr = parse("alert_acknowledged and time_since_alert_secs < 120").unwrap();
1026        match expr {
1027            Expr::Binary(b) => {
1028                assert_eq!(b.op, BinaryOp::And);
1029            }
1030            _ => panic!("Expected binary"),
1031        }
1032    }
1033
1034    #[test]
1035    fn test_clamp_expression() {
1036        let expr = parse("clamp(0, 100, raw_score)").unwrap();
1037        match expr {
1038            Expr::Call(c) => {
1039                assert_eq!(c.function, "clamp");
1040                assert_eq!(c.args.len(), 3);
1041            }
1042            _ => panic!("Expected call"),
1043        }
1044    }
1045}