Skip to main content

pine_parser/
lib.rs

1pub use pine_ast::{Argument, BinOp, Expr, Literal, Loc, Program, Stmt, UnOp, VarKind};
2use pine_lexer::{Token, TokenType};
3use thiserror::Error;
4
5#[derive(Error, Debug)]
6pub enum ParserError {
7    #[error("Unexpected token: {0:?} at line {1}")]
8    UnexpectedToken(TokenType, usize),
9
10    #[error("Expected {expected} but found {found:?} at line {line}")]
11    ExpectedToken {
12        expected: String,
13        found: TokenType,
14        line: usize,
15    },
16
17    #[error("Expected variable name at line {0}")]
18    ExpectedVariableName(usize),
19
20    #[error("Expected parameter name at line {0}")]
21    ExpectedParameterName(usize),
22
23    #[error("Can only call identifiers or member access at line {0}")]
24    InvalidCallTarget(usize),
25
26    #[error("Expected identifier after '.' at line {0}")]
27    ExpectedIdentifierAfterDot(usize),
28}
29
30impl From<ParserError> for String {
31    fn from(err: ParserError) -> String {
32        err.to_string()
33    }
34}
35
36/// Helper trait to convert TokenType to operators
37trait TokenTypeExt {
38    fn to_binop(&self) -> Option<BinOp>;
39}
40
41impl TokenTypeExt for TokenType {
42    /// Convert token type to binary operator, if applicable
43    fn to_binop(&self) -> Option<BinOp> {
44        match self {
45            TokenType::Plus => Some(BinOp::Add),
46            TokenType::Minus => Some(BinOp::Sub),
47            TokenType::Star => Some(BinOp::Mul),
48            TokenType::Slash => Some(BinOp::Div),
49            TokenType::Percent => Some(BinOp::Mod),
50            TokenType::Equal => Some(BinOp::Eq),
51            TokenType::NotEqual => Some(BinOp::NotEq),
52            TokenType::Less => Some(BinOp::Less),
53            TokenType::Greater => Some(BinOp::Greater),
54            TokenType::LessEqual => Some(BinOp::LessEq),
55            TokenType::GreaterEqual => Some(BinOp::GreaterEq),
56            TokenType::And => Some(BinOp::And),
57            TokenType::Or => Some(BinOp::Or),
58            TokenType::PlusAssign => Some(BinOp::Add),
59            TokenType::MinusAssign => Some(BinOp::Sub),
60            TokenType::StarAssign => Some(BinOp::Mul),
61            TokenType::SlashAssign => Some(BinOp::Div),
62            _ => None,
63        }
64    }
65}
66
67pub struct Parser {
68    tokens: Vec<Token>,
69    current: usize,
70    next_call_id: u32,
71}
72
73impl Parser {
74    pub fn new(tokens: Vec<Token>) -> Self {
75        Self {
76            tokens,
77            current: 0,
78            next_call_id: 1,
79        }
80    }
81
82    fn next_call_id(&mut self) -> u32 {
83        let id = self.next_call_id;
84        self.next_call_id += 1;
85        id
86    }
87
88    fn peek(&self) -> &Token {
89        &self.tokens[self.current]
90    }
91
92    fn is_at_end(&self) -> bool {
93        matches!(self.peek().typ, TokenType::Eof)
94    }
95
96    fn advance(&mut self) -> &Token {
97        if !self.is_at_end() {
98            self.current += 1;
99        }
100        &self.tokens[self.current - 1]
101    }
102
103    fn check(&self, typ: &TokenType) -> bool {
104        !self.is_at_end() && &self.peek().typ == typ
105    }
106
107    fn match_token(&mut self, types: &[TokenType]) -> bool {
108        for typ in types {
109            if self.check(typ) {
110                self.advance();
111                return true;
112            }
113        }
114        false
115    }
116
117    /// Try to parse something speculatively. If parsing fails, restore position and return None.
118    /// This is useful for lookahead/backtracking scenarios.
119    fn try_parse<T, F>(&mut self, f: F) -> Option<T>
120    where
121        F: FnOnce(&mut Self) -> Result<T, ParserError>,
122    {
123        let saved_pos = self.current;
124        match f(self) {
125            Ok(val) => Some(val),
126            Err(_) => {
127                self.current = saved_pos;
128                None
129            }
130        }
131    }
132
133    /// Try to parse type arguments: <type1, type2, ...>
134    /// Returns None if this isn't actually type arguments (e.g., it's a comparison)
135    fn try_parse_type_args(&mut self) -> Option<Vec<String>> {
136        self.try_parse(|p| {
137            p.consume(TokenType::Less, "Expected '<'")?;
138
139            let mut type_args = vec![];
140
141            loop {
142                // Parse type name (identifier or type keyword like int/float)
143                let type_name = match &p.peek().typ {
144                    TokenType::Ident(name) => name.clone(),
145                    TokenType::Int => "int".to_string(),
146                    TokenType::Float => "float".to_string(),
147                    _ => {
148                        return Err(ParserError::UnexpectedToken(
149                            p.peek().typ.clone(),
150                            p.peek().line,
151                        ))
152                    }
153                };
154                p.advance();
155                type_args.push(type_name);
156
157                // Check for comma (more types) or end
158                if p.match_token(&[TokenType::Comma]) {
159                    continue;
160                } else if p.match_token(&[TokenType::Greater]) {
161                    break;
162                } else {
163                    return Err(ParserError::UnexpectedToken(
164                        p.peek().typ.clone(),
165                        p.peek().line,
166                    ));
167                }
168            }
169
170            Ok(type_args)
171        })
172    }
173
174    /// Skip any newline tokens
175    fn skip_newlines(&mut self) {
176        while self.match_token(&[TokenType::Newline]) {}
177    }
178
179    /// Skip newlines, indents, and dedents (whitespace tokens)
180    fn skip_whitespace(&mut self) {
181        while self.match_token(&[TokenType::Newline, TokenType::Indent, TokenType::Dedent]) {}
182    }
183
184    /// Parse optional array suffix [] and append to type name if present
185    fn parse_array_suffix(&mut self, type_name: String) -> Result<String, ParserError> {
186        if self.match_token(&[TokenType::LBracket]) {
187            self.consume(TokenType::RBracket, "Expected ']' after '[' in array type")?;
188            Ok(format!("{}[]", type_name))
189        } else {
190            Ok(type_name)
191        }
192    }
193
194    /// Parse an expression that may be on an indented continuation line.
195    /// Handles: newlines + optional indent + expression + optional dedent
196    fn parse_indented_expression(&mut self) -> Result<Expr, ParserError> {
197        self.skip_newlines();
198
199        // Check if expression is on an indented line
200        let has_indent = self.match_token(&[TokenType::Indent]);
201
202        let expr = self.expression()?;
203
204        // Consume dedent if we had indent
205        if has_indent {
206            self.match_token(&[TokenType::Dedent]);
207        }
208
209        Ok(expr)
210    }
211
212    fn consume(&mut self, typ: TokenType, message: &str) -> Result<&Token, ParserError> {
213        if self.check(&typ) {
214            Ok(self.advance())
215        } else {
216            Err(ParserError::ExpectedToken {
217                expected: message.to_string(),
218                found: self.peek().typ.clone(),
219                line: self.peek().line,
220            })
221        }
222    }
223
224    /// Helper to extract an identifier from the current token and advance
225    fn expect_identifier(&mut self) -> Result<String, ParserError> {
226        if let TokenType::Ident(name) = &self.peek().typ {
227            let name = name.clone();
228            self.advance();
229            Ok(name)
230        } else {
231            Err(ParserError::ExpectedVariableName(self.peek().line))
232        }
233    }
234
235    /// Generic helper to parse indented field blocks
236    fn parse_indented_fields<T, F>(&mut self, parse_field: F) -> Result<Vec<T>, ParserError>
237    where
238        F: Fn(&mut Self) -> Result<T, ParserError>,
239    {
240        let mut fields = Vec::new();
241
242        loop {
243            // Skip newlines between fields
244            self.skip_newlines();
245
246            // Check for dedent (end of field block)
247            if self.check(&TokenType::Dedent) {
248                self.advance();
249                break;
250            }
251
252            // Check for end of file
253            if self.is_at_end() {
254                break;
255            }
256
257            // Parse a field using the provided parser
258            fields.push(parse_field(self)?);
259        }
260
261        Ok(fields)
262    }
263
264    /// Helper to skip newlines and optionally match indent
265    fn skip_newlines_and_indent(&mut self) {
266        self.skip_newlines();
267        self.match_token(&[TokenType::Indent]);
268    }
269
270    /// Helper to skip newlines and optionally match dedent
271    fn skip_newlines_and_dedent(&mut self) {
272        self.skip_newlines();
273        self.match_token(&[TokenType::Dedent]);
274    }
275
276    /// Helper to speculatively consume indent only if followed by expected token
277    fn try_consume_indent_if_followed_by(&mut self, expected: &TokenType) {
278        if self.check(&TokenType::Indent) {
279            self.try_parse(|p| {
280                p.advance(); // consume indent
281                if p.check(expected) {
282                    Ok(())
283                } else {
284                    Err(ParserError::UnexpectedToken(
285                        p.peek().typ.clone(),
286                        p.peek().line,
287                    ))
288                }
289            });
290        }
291    }
292
293    /// Helper to speculatively consume indent/dedent only if followed by one of the expected operators
294    fn try_consume_layout_token_if_followed_by(&mut self, expected: &[TokenType]) {
295        if self.check(&TokenType::Indent) || self.check(&TokenType::Dedent) {
296            self.try_parse(|p| {
297                p.advance(); // consume indent or dedent
298                for typ in expected {
299                    if p.check(typ) {
300                        return Ok(());
301                    }
302                }
303                Err(ParserError::UnexpectedToken(
304                    p.peek().typ.clone(),
305                    p.peek().line,
306                ))
307            });
308        }
309    }
310
311    /// Helper to parse optional type qualifier (const, input, simple, series)
312    fn parse_optional_type_qualifier(&mut self) -> Option<pine_ast::TypeQualifier> {
313        use pine_ast::TypeQualifier;
314        if self.match_token(&[TokenType::Const]) {
315            Some(TypeQualifier::Const)
316        } else if let TokenType::Ident(name) = &self.peek().typ {
317            match name.as_str() {
318                "input" => {
319                    self.advance();
320                    Some(TypeQualifier::Input)
321                }
322                "simple" => {
323                    self.advance();
324                    Some(TypeQualifier::Simple)
325                }
326                "series" => {
327                    self.advance();
328                    Some(TypeQualifier::Series)
329                }
330                _ => None,
331            }
332        } else {
333            None
334        }
335    }
336
337    /// Helper to parse optional type annotation with array suffix
338    /// Returns None if no type annotation is found
339    /// Supports: int, float, or custom identifier types with optional [] suffix
340    fn parse_optional_type_annotation(&mut self) -> Option<String> {
341        if self.match_token(&[TokenType::Int, TokenType::Float]) {
342            let type_name = self.tokens[self.current - 1].lexeme.clone();
343            // Check for array type: int[] or float[]
344            self.parse_array_suffix(type_name).ok()
345        } else if let TokenType::Ident(type_name) = &self.peek().typ {
346            let type_name = type_name.clone();
347            self.try_parse(|p| {
348                p.advance(); // consume potential type name
349
350                // Check for array type: TypeName[]
351                let final_type = p.parse_array_suffix(type_name.clone())?;
352
353                // Must be followed by identifier to be a type annotation
354                if !matches!(p.peek().typ, TokenType::Ident(_)) {
355                    return Err(ParserError::ExpectedVariableName(p.peek().line));
356                }
357
358                Ok(final_type)
359            })
360        } else {
361            None
362        }
363    }
364
365    /// Generic helper to parse comma-separated lists
366    /// Handles newlines and optional indentation around commas
367    fn parse_comma_separated<T, F>(
368        &mut self,
369        closing_delimiter: &TokenType,
370        parse_item: F,
371    ) -> Result<Vec<T>, ParserError>
372    where
373        F: Fn(&mut Self) -> Result<T, ParserError>,
374    {
375        let mut items = vec![];
376
377        if !self.check(closing_delimiter) {
378            loop {
379                items.push(parse_item(self)?);
380
381                // Skip newlines after each item
382                self.skip_newlines();
383
384                if !self.match_token(&[TokenType::Comma]) {
385                    break;
386                }
387
388                // Skip newlines after comma
389                self.skip_newlines_and_indent();
390            }
391        }
392
393        Ok(items)
394    }
395
396    // Parse a program (top-level)
397    pub fn parse(&mut self) -> Result<Vec<Stmt>, ParserError> {
398        let mut statements = vec![];
399
400        while !self.is_at_end() {
401            // Skip any leading newlines and dedents (dedents at top level are from EOF)
402            self.skip_whitespace();
403
404            // Check if we reached EOF after skipping
405            if self.is_at_end() {
406                break;
407            }
408
409            statements.push(self.declaration()?);
410        }
411
412        Ok(statements)
413    }
414
415    // Declarations (var declarations, assignments, etc.)
416    fn declaration(&mut self) -> Result<Stmt, ParserError> {
417        // Check for type qualifier first (const, input, simple, series)
418        let type_qualifier = self.parse_optional_type_qualifier();
419
420        // Check for var or varip keyword (can be followed by type annotation)
421        let var_kind = if self.match_token(&[TokenType::Varip]) {
422            VarKind::Varip
423        } else if self.match_token(&[TokenType::Var]) {
424            VarKind::Var
425        } else if type_qualifier.is_some() {
426            // If we have a type qualifier but no var/varip, it's still a variable declaration
427            // e.g., const int x = 5
428            VarKind::Plain
429        } else {
430            // Not a var/varip declaration, continue to other statement types
431            return self.check_type_annotated_declaration();
432        };
433
434        // Check if followed by type annotation: var int x = ..., var float y = ..., var label l = ...
435        let type_annotation = self.parse_optional_type_annotation();
436        self.typed_var_declaration_with_qualifier(type_qualifier, type_annotation, var_kind)
437    }
438
439    fn check_type_annotated_declaration(&mut self) -> Result<Stmt, ParserError> {
440        // Check for type declaration: type TypeName
441        if self.match_token(&[TokenType::Type]) {
442            return self.type_declaration(false);
443        }
444
445        // Check for enum declaration: enum EnumName
446        if self.match_token(&[TokenType::Enum]) {
447            return self.enum_declaration(false);
448        }
449
450        // Check for method declaration: method methodName(params) =>
451        if self.match_token(&[TokenType::Method]) {
452            return self.method_declaration(false);
453        }
454
455        // Check for type-annotated declaration without var: int x = ..., float y = ..., int[] x = ...
456        if self.match_token(&[TokenType::Int, TokenType::Float]) {
457            let type_name = self.tokens[self.current - 1].lexeme.clone();
458            // Check for array type: int[] or float[]
459            let type_name = self.parse_array_suffix(type_name)?;
460            return self.typed_var_declaration(Some(type_name), VarKind::Plain);
461        }
462
463        // Check for identifier type with optional []: string x = ..., string[] x = ...
464        if let Some(type_annotation) = self.parse_optional_type_annotation() {
465            return self.typed_var_declaration(Some(type_annotation), VarKind::Plain);
466        }
467
468        self.statement()
469    }
470
471    fn type_declaration(&mut self, export: bool) -> Result<Stmt, ParserError> {
472        // Parse type name
473        let type_name = self.expect_identifier()?;
474
475        // Expect newline before fields
476        self.consume(TokenType::Newline, "Expected newline after type name")?;
477
478        // Expect indent to start field block
479        self.consume(TokenType::Indent, "Expected indent for type fields")?;
480
481        // Parse fields using generic helper
482        let fields = self.parse_indented_fields(|p| {
483            // Parse optional type qualifier (const, input, simple, series)
484            let type_qualifier = p.parse_optional_type_qualifier();
485
486            // Parse field: type_annotation field_name [= default_value]
487            // First, get the type annotation (int, float, or identifier)
488            let field_type = if p.match_token(&[TokenType::Int, TokenType::Float]) {
489                p.tokens[p.current - 1].lexeme.clone()
490            } else if let TokenType::Ident(type_name) = &p.peek().typ {
491                let type_name = type_name.clone();
492                p.advance();
493                type_name
494            } else {
495                return Err(ParserError::UnexpectedToken(
496                    p.peek().typ.clone(),
497                    p.peek().line,
498                ));
499            };
500
501            // Parse field name
502            let field_name = p.expect_identifier()?;
503
504            // Parse optional default value
505            let default_value = if p.match_token(&[TokenType::Assign]) {
506                Some(p.expression()?)
507            } else {
508                None
509            };
510
511            Ok(pine_ast::TypeField {
512                name: field_name,
513                type_qualifier,
514                type_annotation: field_type,
515                default_value,
516            })
517        })?;
518
519        Ok(Stmt::TypeDecl {
520            name: type_name,
521            fields,
522            export,
523        })
524    }
525
526    fn enum_declaration(&mut self, export: bool) -> Result<Stmt, ParserError> {
527        // Parse enum name
528        let enum_name = self.expect_identifier()?;
529
530        // Expect newline before fields
531        self.consume(TokenType::Newline, "Expected newline after enum name")?;
532
533        // Expect indent to start field block
534        self.consume(TokenType::Indent, "Expected indent for enum fields")?;
535
536        // Parse fields using generic helper
537        let fields = self.parse_indented_fields(|p| {
538            // Parse field: field_name [= "title"]
539            let field_name = p.expect_identifier()?;
540
541            // Parse optional title
542            let title = if p.match_token(&[TokenType::Assign]) {
543                // Expect a string literal for the title
544                if let TokenType::String(s) = &p.peek().typ {
545                    let s = s.clone();
546                    p.advance();
547                    Some(s)
548                } else {
549                    return Err(ParserError::UnexpectedToken(
550                        p.peek().typ.clone(),
551                        p.peek().line,
552                    ));
553                }
554            } else {
555                None
556            };
557
558            Ok(pine_ast::EnumField {
559                name: field_name,
560                title,
561            })
562        })?;
563
564        Ok(Stmt::EnumDecl {
565            name: enum_name,
566            fields,
567            export,
568        })
569    }
570
571    fn export_statement(&mut self) -> Result<Stmt, ParserError> {
572        // export type typename - delegate to type_declaration
573        if self.match_token(&[TokenType::Type]) {
574            return self.type_declaration(true);
575        }
576
577        // export enum enumname - delegate to enum_declaration
578        if self.match_token(&[TokenType::Enum]) {
579            return self.enum_declaration(true);
580        }
581
582        // export [method] functionname(params) => body
583        // Check if it's a method
584        let is_method = self.match_token(&[TokenType::Method]);
585
586        if is_method {
587            return self.method_declaration(true);
588        }
589
590        // Parse function name
591        let func_name = self.expect_identifier()?;
592
593        // Check if this is a function declaration (followed by '(')
594        if self.check(&TokenType::LParen) {
595            // export functionname(params) => body
596            self.advance(); // consume '('
597
598            let params = self.function_params()?;
599            self.consume(TokenType::RParen, "Expected ')' after function parameters")?;
600            self.consume(TokenType::Arrow, "Expected '=>'")?;
601
602            // Skip optional newline after =>
603            self.match_token(&[TokenType::Newline]);
604
605            // Parse function body (can be a block or single expression)
606            let body = self.parse_block()?;
607
608            Ok(Stmt::FunctionDecl {
609                name: func_name,
610                params,
611                body,
612                export: true,
613            })
614        } else {
615            // Just export functionname (old style - keeping for backward compatibility)
616            Ok(Stmt::Export {
617                item: pine_ast::ExportItem::Type(func_name),
618            })
619        }
620    }
621
622    fn import_statement(&mut self) -> Result<Stmt, ParserError> {
623        // import userName/libraryName/version as alias
624        let path = if let TokenType::Ident(p) = &self.peek().typ {
625            let mut path_parts = vec![p.clone()];
626            self.advance();
627
628            // Parse path segments separated by /
629            while self.match_token(&[TokenType::Slash]) {
630                if let TokenType::Ident(part) = &self.peek().typ {
631                    path_parts.push(part.clone());
632                    self.advance();
633                } else if let TokenType::IntLiteral(n) = &self.peek().typ {
634                    // Version number (an integer path segment)
635                    path_parts.push(n.to_string());
636                    self.advance();
637                } else {
638                    return Err(ParserError::UnexpectedToken(
639                        self.peek().typ.clone(),
640                        self.peek().line,
641                    ));
642                }
643            }
644
645            path_parts.join("/")
646        } else {
647            return Err(ParserError::ExpectedVariableName(self.peek().line));
648        };
649
650        // Expect 'as' keyword - for now we'll check for an identifier "as"
651        if let TokenType::Ident(kw) = &self.peek().typ {
652            if kw != "as" {
653                return Err(ParserError::UnexpectedToken(
654                    self.peek().typ.clone(),
655                    self.peek().line,
656                ));
657            }
658            self.advance();
659        } else {
660            return Err(ParserError::UnexpectedToken(
661                self.peek().typ.clone(),
662                self.peek().line,
663            ));
664        }
665
666        // Parse alias
667        let alias = self.expect_identifier()?;
668
669        Ok(Stmt::Import { path, alias })
670    }
671
672    fn method_declaration(&mut self, export: bool) -> Result<Stmt, ParserError> {
673        // Parse method name
674        let method_name = self.expect_identifier()?;
675
676        // Expect '('
677        self.consume(TokenType::LParen, "Expected '(' after method name")?;
678
679        // Parse parameters
680        let mut params = Vec::new();
681
682        if !self.check(&TokenType::RParen) {
683            loop {
684                // Parse optional type qualifier (const, input, simple, series)
685                let type_qualifier = self.parse_optional_type_qualifier();
686
687                // Parse optional type annotation
688                let type_annotation = self.parse_optional_type_annotation();
689
690                // Parse parameter name
691                let param_name = self.expect_identifier()?;
692
693                // Parse optional default value
694                let default_value = if self.match_token(&[TokenType::Assign]) {
695                    Some(self.expression()?)
696                } else {
697                    None
698                };
699
700                params.push(pine_ast::MethodParam {
701                    type_qualifier,
702                    type_annotation,
703                    name: param_name,
704                    default_value,
705                });
706
707                if !self.match_token(&[TokenType::Comma]) {
708                    break;
709                }
710            }
711        }
712
713        self.consume(TokenType::RParen, "Expected ')' after parameters")?;
714
715        // Expect '=>'
716        self.consume(TokenType::Arrow, "Expected '=>' after method parameters")?;
717
718        // Skip optional newline after =>
719        self.match_token(&[TokenType::Newline]);
720
721        // Parse method body (can be a block or single expression)
722        let body = self.parse_block()?;
723
724        Ok(Stmt::MethodDecl {
725            name: method_name,
726            params,
727            body,
728            export,
729        })
730    }
731
732    fn typed_var_declaration(
733        &mut self,
734        type_annotation: Option<String>,
735        var_kind: VarKind,
736    ) -> Result<Stmt, ParserError> {
737        self.typed_var_declaration_with_qualifier(None, type_annotation, var_kind)
738    }
739
740    fn typed_var_declaration_with_qualifier(
741        &mut self,
742        type_qualifier: Option<pine_ast::TypeQualifier>,
743        type_annotation: Option<String>,
744        var_kind: VarKind,
745    ) -> Result<Stmt, ParserError> {
746        let name = self.expect_identifier()?;
747
748        let initializer = if self.match_token(&[TokenType::Assign]) {
749            Some(self.parse_indented_expression()?)
750        } else {
751            None
752        };
753
754        Ok(Stmt::VarDecl {
755            name,
756            type_qualifier,
757            type_annotation,
758            initializer,
759            var_kind,
760        })
761    }
762
763    fn statement(&mut self) -> Result<Stmt, ParserError> {
764        // Check for export statement
765        if self.match_token(&[TokenType::Export]) {
766            return self.export_statement();
767        }
768
769        // Check for import statement
770        if self.match_token(&[TokenType::Import]) {
771            return self.import_statement();
772        }
773
774        // Check for if statement
775        if self.match_token(&[TokenType::If]) {
776            return self.if_statement();
777        }
778
779        // Check for for loop
780        if self.match_token(&[TokenType::For]) {
781            return self.for_statement();
782        }
783
784        // Check for while loop
785        if self.match_token(&[TokenType::While]) {
786            return self.while_statement();
787        }
788
789        // Check for break
790        if self.match_token(&[TokenType::Break]) {
791            return Ok(Stmt::Break);
792        }
793
794        // Check for continue
795        if self.match_token(&[TokenType::Continue]) {
796            return Ok(Stmt::Continue);
797        }
798
799        // Check for tuple destructuring: [a, b, c] = func()
800        // But only if followed by = (otherwise it's an array literal)
801        if self.check(&TokenType::LBracket) {
802            if let Some((names, value)) = self.try_parse(|p| {
803                p.advance(); // consume [
804
805                let mut names = vec![];
806
807                // Parse identifiers separated by commas
808                if !p.check(&TokenType::RBracket) {
809                    loop {
810                        if let TokenType::Ident(name) = &p.peek().typ {
811                            names.push(name.clone());
812                            p.advance();
813                        } else {
814                            // Not all identifiers, not tuple destructuring
815                            return Err(ParserError::ExpectedVariableName(p.peek().line));
816                        }
817
818                        if !p.match_token(&[TokenType::Comma]) {
819                            break;
820                        }
821                    }
822                }
823
824                p.consume(TokenType::RBracket, "Expected ']' in tuple destructuring")?;
825                p.consume(TokenType::Assign, "Expected '=' after tuple pattern")?;
826
827                // Skip newlines after =
828                p.skip_newlines();
829
830                let value = p.expression()?;
831
832                Ok((names, value))
833            }) {
834                return Ok(Stmt::TupleAssignment { names, value });
835            }
836        }
837
838        // Check for implicit variable declaration, reassignment, or function definition
839        // name = expr (declaration)
840        // name := expr (reassignment)
841        // name(params) => body (function definition)
842        if let TokenType::Ident(name) = &self.peek().typ {
843            let name = name.clone();
844
845            // Check for function definition: name(params) =>
846            if let Some((param_structs, body)) = self.try_parse(|p| {
847                p.advance(); // consume identifier
848                p.consume(TokenType::LParen, "Expected '('")?;
849
850                let params = p.function_params()?;
851                p.consume(TokenType::RParen, "Expected ')' after function parameters")?;
852                p.consume(TokenType::Arrow, "Expected '=>'")?;
853
854                // Skip optional newline after =>
855                p.match_token(&[TokenType::Newline]);
856
857                // Parse function body (can be a block or single expression)
858                let body = p.parse_block()?;
859
860                Ok((params, body))
861            }) {
862                // Use the full FunctionParam structs for Expr::Function
863                let initializer = Some(Expr::Function {
864                    params: param_structs,
865                    body,
866                });
867                return Ok(Stmt::VarDecl {
868                    name,
869                    type_qualifier: None,
870                    type_annotation: None,
871                    initializer,
872                    var_kind: VarKind::Plain,
873                });
874            }
875
876            // Try to parse as assignment/declaration
877            if let Some(stmt) = self.try_parse(|p| {
878                p.advance(); // consume identifier
879
880                if p.match_token(&[TokenType::Assign]) {
881                    // This is an assignment with =, treat it as a var declaration
882                    let initializer = Some(p.parse_indented_expression()?);
883
884                    Ok(Stmt::VarDecl {
885                        name: name.clone(),
886                        type_qualifier: None,
887                        type_annotation: None,
888                        initializer,
889                        var_kind: VarKind::Plain,
890                    })
891                } else if p.match_token(&[TokenType::ColonAssign]) {
892                    // This is a reassignment with :=
893                    let value = p.parse_indented_expression()?;
894
895                    Ok(Stmt::Assignment {
896                        target: Expr::Variable(name.clone()),
897                        value,
898                    })
899                } else if p.match_token(&[
900                    TokenType::PlusAssign,
901                    TokenType::MinusAssign,
902                    TokenType::StarAssign,
903                    TokenType::SlashAssign,
904                ]) {
905                    // Compound assignment: x += 5 is equivalent to x := x + 5
906                    let op_tok = &p.tokens[p.current - 1];
907                    let op_loc = Loc::new(op_tok.line as u32, op_tok.column as u32);
908                    let op = op_tok
909                        .typ
910                        .to_binop()
911                        .expect("compound assign token should convert to binop");
912
913                    let right = p.parse_indented_expression()?;
914
915                    let value = Expr::Binary {
916                        left: Box::new(Expr::Variable(name.clone())),
917                        op,
918                        right: Box::new(right),
919                        loc: op_loc,
920                    };
921                    Ok(Stmt::Assignment {
922                        target: Expr::Variable(name.clone()),
923                        value,
924                    })
925                } else {
926                    // Not an assignment operator, fail
927                    Err(ParserError::UnexpectedToken(
928                        p.peek().typ.clone(),
929                        p.peek().line,
930                    ))
931                }
932            }) {
933                return Ok(stmt);
934            }
935        }
936
937        self.expression_statement()
938    }
939
940    fn function_params(&mut self) -> Result<Vec<pine_ast::FunctionParam>, ParserError> {
941        self.parse_comma_separated(&TokenType::RParen, |p| {
942            // Parse optional type qualifier (const, input, simple, series)
943            let type_qualifier = p.parse_optional_type_qualifier();
944
945            // Parse optional type annotation
946            let type_annotation = p.parse_optional_type_annotation();
947
948            let name = p.expect_identifier()?;
949
950            // Check for default value: param = value
951            let default_value = if p.match_token(&[TokenType::Assign]) {
952                Some(p.expression()?)
953            } else {
954                None
955            };
956
957            Ok(pine_ast::FunctionParam {
958                type_qualifier,
959                type_annotation,
960                name,
961                default_value,
962            })
963        })
964    }
965
966    fn for_statement(&mut self) -> Result<Stmt, ParserError> {
967        // Check if it's a tuple form: for [index, item] in collection
968        if self.check(&TokenType::LBracket) {
969            self.advance(); // consume [
970
971            let index_var = self.expect_identifier()?;
972
973            self.consume(TokenType::Comma, "Expected ',' in for...in tuple")?;
974
975            let item_var = self.expect_identifier()?;
976
977            self.consume(TokenType::RBracket, "Expected ']' after for...in tuple")?;
978            self.consume(TokenType::In, "Expected 'in' in for...in loop")?;
979
980            let collection = self.expression()?;
981
982            // Skip optional newline
983            self.match_token(&[TokenType::Newline]);
984
985            let body = self.parse_block()?;
986
987            return Ok(Stmt::ForIn {
988                index_var: Some(index_var),
989                item_var,
990                collection,
991                body,
992            });
993        }
994
995        // Parse variable name
996        let var_name = self.expect_identifier()?;
997
998        // Check if it's for...in (simple form) or for...to
999        if self.check(&TokenType::In) {
1000            self.advance(); // consume 'in'
1001
1002            let collection = self.expression()?;
1003
1004            // Skip optional newline
1005            self.match_token(&[TokenType::Newline]);
1006
1007            let body = self.parse_block()?;
1008
1009            Ok(Stmt::ForIn {
1010                index_var: None,
1011                item_var: var_name,
1012                collection,
1013                body,
1014            })
1015        } else {
1016            // Traditional for...to loop
1017            self.consume(TokenType::Assign, "Expected '=' in for loop")?;
1018            let from = self.expression()?;
1019            self.consume(TokenType::To, "Expected 'to' in for loop")?;
1020            let to = self.expression()?;
1021
1022            // Skip optional newline after to
1023            self.match_token(&[TokenType::Newline]);
1024
1025            // Parse the body - multiple statements
1026            let body = self.parse_block()?;
1027
1028            Ok(Stmt::For {
1029                var_name,
1030                from,
1031                to,
1032                body,
1033            })
1034        }
1035    }
1036
1037    fn while_statement(&mut self) -> Result<Stmt, ParserError> {
1038        // Parse: while condition
1039        let condition = self.expression()?;
1040
1041        // Skip optional newline after condition
1042        self.match_token(&[TokenType::Newline]);
1043
1044        // Parse the body - multiple statements
1045        let body = self.parse_block()?;
1046
1047        Ok(Stmt::While { condition, body })
1048    }
1049
1050    fn if_statement(&mut self) -> Result<Stmt, ParserError> {
1051        // Parse the condition (no parentheses required in PineScript)
1052        let condition = self.expression()?;
1053
1054        // Skip optional newline after condition
1055        self.match_token(&[TokenType::Newline]);
1056
1057        // Parse the then branch - multiple statements until we hit 'else', dedent, or certain keywords
1058        let then_branch = self.parse_block()?;
1059
1060        // Parse else if branches
1061        let mut else_if_branches = Vec::new();
1062
1063        loop {
1064            // Skip any newlines before else
1065            self.skip_newlines();
1066
1067            // Check if we have "else if"
1068            if self.check(&TokenType::Else) {
1069                if let Some((else_if_condition, else_if_body)) = self.try_parse(|p| {
1070                    p.advance(); // consume 'else'
1071                                 // Check if next token is 'if'
1072                    if p.match_token(&[TokenType::If]) {
1073                        // This is an else if
1074                        let else_if_condition = p.expression()?;
1075                        p.match_token(&[TokenType::Newline]);
1076                        let else_if_body = p.parse_block()?;
1077                        Ok((else_if_condition, else_if_body))
1078                    } else {
1079                        Err(ParserError::UnexpectedToken(
1080                            p.peek().typ.clone(),
1081                            p.peek().line,
1082                        ))
1083                    }
1084                }) {
1085                    else_if_branches.push((else_if_condition, else_if_body));
1086                } else {
1087                    break;
1088                }
1089            } else {
1090                break;
1091            }
1092        }
1093
1094        // Check for final else branch
1095        self.skip_newlines();
1096
1097        let else_branch = if self.match_token(&[TokenType::Else]) {
1098            // Skip optional newline after else
1099            self.match_token(&[TokenType::Newline]);
1100
1101            Some(self.parse_block()?)
1102        } else {
1103            None
1104        };
1105
1106        Ok(Stmt::If {
1107            condition,
1108            then_branch,
1109            else_if_branches,
1110            else_branch,
1111        })
1112    }
1113
1114    fn if_expression(&mut self) -> Result<Expr, ParserError> {
1115        // Consume 'if' token
1116        self.consume(TokenType::If, "Expected 'if'")?;
1117
1118        // Parse the condition
1119        let condition = self.expression()?;
1120
1121        // Skip optional newline after condition
1122        self.match_token(&[TokenType::Newline]);
1123
1124        // Skip optional indent
1125        self.match_token(&[TokenType::Indent]);
1126
1127        // Parse the then expression (single expression, not a block of statements)
1128        let then_expr = self.expression()?;
1129
1130        // Skip newlines and dedent
1131        self.skip_newlines();
1132        self.match_token(&[TokenType::Dedent]);
1133
1134        // Parse else if branches
1135        let mut else_if_branches = Vec::new();
1136
1137        loop {
1138            // Skip any newlines before else
1139            self.skip_newlines();
1140
1141            // Check if we have "else if"
1142            if self.check(&TokenType::Else) {
1143                if let Some((else_if_condition, else_if_expr)) = self.try_parse(|p| {
1144                    p.advance(); // consume 'else'
1145                                 // Check if next token is 'if'
1146                    if p.match_token(&[TokenType::If]) {
1147                        // This is an else if
1148                        let else_if_condition = p.expression()?;
1149                        p.match_token(&[TokenType::Newline]);
1150                        p.match_token(&[TokenType::Indent]);
1151                        let else_if_expr = p.expression()?;
1152                        p.skip_newlines();
1153                        p.match_token(&[TokenType::Dedent]);
1154                        Ok((else_if_condition, else_if_expr))
1155                    } else {
1156                        Err(ParserError::UnexpectedToken(
1157                            p.peek().typ.clone(),
1158                            p.peek().line,
1159                        ))
1160                    }
1161                }) {
1162                    else_if_branches.push((else_if_condition, else_if_expr));
1163                } else {
1164                    break;
1165                }
1166            } else {
1167                break;
1168            }
1169        }
1170
1171        // Parse final else branch (optional - if not present, returns na)
1172        self.skip_newlines();
1173        let else_expr = if self.match_token(&[TokenType::Else]) {
1174            // Skip optional newline after else
1175            self.match_token(&[TokenType::Newline]);
1176
1177            // Skip optional indent
1178            self.match_token(&[TokenType::Indent]);
1179
1180            // Parse else expression
1181            let expr = self.expression()?;
1182
1183            // Skip newlines and optional dedent
1184            self.skip_newlines();
1185            self.match_token(&[TokenType::Dedent]);
1186
1187            Some(Box::new(expr))
1188        } else {
1189            None // Will return na if no branch matches
1190        };
1191
1192        Ok(Expr::IfExpr {
1193            condition: Box::new(condition),
1194            then_expr: Box::new(then_expr),
1195            else_if_branches,
1196            else_expr,
1197        })
1198    }
1199
1200    fn parse_block(&mut self) -> Result<Vec<Stmt>, ParserError> {
1201        let mut stmts = vec![];
1202
1203        // Expect an indent token to start the block
1204        if !self.match_token(&[TokenType::Indent]) {
1205            // No indent means single-line block or empty block
1206            // Try to parse a single statement on the same line
1207            if !self.check(&TokenType::Newline)
1208                && !self.check(&TokenType::Else)
1209                && !self.is_at_end()
1210            {
1211                stmts.push(self.declaration()?);
1212            }
1213            return Ok(stmts);
1214        }
1215
1216        // Parse statements until we hit a dedent
1217        loop {
1218            // Skip leading newlines
1219            self.skip_newlines();
1220
1221            // Check for else (which ends the then branch)
1222            if self.check(&TokenType::Else) {
1223                break;
1224            }
1225
1226            // Check for end of block
1227            if self.check(&TokenType::Dedent) {
1228                self.advance(); // consume the dedent
1229
1230                // Check if else follows the dedent
1231                self.skip_newlines();
1232                if self.check(&TokenType::Else) {
1233                    break;
1234                }
1235
1236                // If not else, we're truly done
1237                break;
1238            }
1239
1240            // Stop at EOF
1241            if self.is_at_end() {
1242                break;
1243            }
1244
1245            // Parse a statement
1246            stmts.push(self.declaration()?);
1247        }
1248
1249        Ok(stmts)
1250    }
1251
1252    fn expression_statement(&mut self) -> Result<Stmt, ParserError> {
1253        let expr = self.expression()?;
1254
1255        // Check if this is an assignment statement (e.g., obj.field := value)
1256        if self.match_token(&[TokenType::ColonAssign]) {
1257            let value = self.parse_indented_expression()?;
1258            return Ok(Stmt::Assignment {
1259                target: expr,
1260                value,
1261            });
1262        }
1263
1264        Ok(Stmt::Expression(expr))
1265    }
1266
1267    // Expression parsing with precedence
1268    fn expression(&mut self) -> Result<Expr, ParserError> {
1269        self.ternary()
1270    }
1271
1272    /// Generic binary operator parser using left-associativity
1273    fn binary_left_assoc(
1274        &mut self,
1275        operators: &[TokenType],
1276        next_precedence: fn(&mut Self) -> Result<Expr, ParserError>,
1277    ) -> Result<Expr, ParserError> {
1278        let mut expr = next_precedence(self)?;
1279
1280        loop {
1281            // Skip newlines before operators (for leading operators on continuation lines)
1282            self.skip_newlines();
1283
1284            if !self.match_token(operators) {
1285                break;
1286            }
1287
1288            let op_tok = &self.tokens[self.current - 1];
1289            let op_loc = Loc::new(op_tok.line as u32, op_tok.column as u32);
1290            let op = op_tok
1291                .typ
1292                .to_binop()
1293                .expect("matched operator token should convert to binop");
1294
1295            // Skip newlines after binary operators (for multi-line expressions)
1296            self.skip_newlines_and_indent();
1297
1298            let right = next_precedence(self)?;
1299            expr = Expr::Binary {
1300                left: Box::new(expr),
1301                op,
1302                right: Box::new(right),
1303                loc: op_loc,
1304            };
1305        }
1306
1307        Ok(expr)
1308    }
1309
1310    fn ternary(&mut self) -> Result<Expr, ParserError> {
1311        // Check for if expression first
1312        if self.check(&TokenType::If) {
1313            return self.if_expression();
1314        }
1315
1316        let mut expr = self.logical_or()?;
1317
1318        // Skip newlines before '?' for multi-line ternaries
1319        self.skip_newlines();
1320
1321        // Skip indent if followed by '?' (for multiline ternaries)
1322        self.try_consume_indent_if_followed_by(&TokenType::Question);
1323
1324        if self.match_token(&[TokenType::Question]) {
1325            // Skip newlines after '?'
1326            self.skip_newlines_and_indent();
1327
1328            let then_expr = self.expression()?;
1329
1330            // Skip newlines before ':'
1331            self.skip_newlines();
1332
1333            // Skip indent if followed by ':' (for multiline ternaries)
1334            self.try_consume_indent_if_followed_by(&TokenType::Colon);
1335
1336            self.consume(TokenType::Colon, "Expected ':' in ternary expression")?;
1337
1338            // Skip newlines after ':'
1339            self.skip_newlines_and_indent();
1340
1341            let else_expr = self.expression()?;
1342            expr = Expr::Ternary {
1343                condition: Box::new(expr),
1344                then_expr: Box::new(then_expr),
1345                else_expr: Box::new(else_expr),
1346            };
1347        }
1348
1349        Ok(expr)
1350    }
1351
1352    fn logical_or(&mut self) -> Result<Expr, ParserError> {
1353        self.binary_left_assoc(&[TokenType::Or], Self::logical_and)
1354    }
1355
1356    fn logical_and(&mut self) -> Result<Expr, ParserError> {
1357        self.binary_left_assoc(&[TokenType::And], Self::equality)
1358    }
1359
1360    fn equality(&mut self) -> Result<Expr, ParserError> {
1361        self.binary_left_assoc(&[TokenType::Equal, TokenType::NotEqual], Self::comparison)
1362    }
1363
1364    fn comparison(&mut self) -> Result<Expr, ParserError> {
1365        self.binary_left_assoc(
1366            &[
1367                TokenType::Greater,
1368                TokenType::Less,
1369                TokenType::GreaterEqual,
1370                TokenType::LessEqual,
1371            ],
1372            Self::term,
1373        )
1374    }
1375
1376    fn term(&mut self) -> Result<Expr, ParserError> {
1377        let mut expr = self.factor()?;
1378
1379        loop {
1380            // Skip newlines before operators (for leading operators on continuation lines)
1381            self.skip_newlines();
1382
1383            // Skip indent/dedent if followed by an operator (for leading operators on continuation lines)
1384            self.try_consume_layout_token_if_followed_by(&[TokenType::Plus, TokenType::Minus]);
1385
1386            if !self.match_token(&[TokenType::Plus, TokenType::Minus]) {
1387                break;
1388            }
1389
1390            let op_tok = &self.tokens[self.current - 1];
1391            let op_loc = Loc::new(op_tok.line as u32, op_tok.column as u32);
1392            let op = op_tok
1393                .typ
1394                .to_binop()
1395                .expect("term token should convert to binop");
1396            // Skip newlines after binary operators (for multi-line expressions)
1397            self.skip_newlines_and_indent();
1398            let right = self.factor()?;
1399            expr = Expr::Binary {
1400                left: Box::new(expr),
1401                op,
1402                right: Box::new(right),
1403                loc: op_loc,
1404            };
1405        }
1406
1407        Ok(expr)
1408    }
1409
1410    fn factor(&mut self) -> Result<Expr, ParserError> {
1411        self.binary_left_assoc(
1412            &[TokenType::Star, TokenType::Slash, TokenType::Percent],
1413            Self::unary,
1414        )
1415    }
1416
1417    fn unary(&mut self) -> Result<Expr, ParserError> {
1418        if self.match_token(&[TokenType::Minus]) {
1419            let expr = self.unary()?;
1420            return Ok(Expr::Unary {
1421                op: UnOp::Neg,
1422                expr: Box::new(expr),
1423            });
1424        }
1425
1426        if self.match_token(&[TokenType::Not]) {
1427            let expr = self.unary()?;
1428            return Ok(Expr::Unary {
1429                op: UnOp::Not,
1430                expr: Box::new(expr),
1431            });
1432        }
1433
1434        self.postfix()
1435    }
1436
1437    fn postfix(&mut self) -> Result<Expr, ParserError> {
1438        let mut expr = self.primary()?;
1439
1440        loop {
1441            if self.match_token(&[TokenType::Dot]) {
1442                // Member access: expr.member
1443                // Allow keywords as member names (e.g., input.int, color.new)
1444                let member = match &self.peek().typ {
1445                    TokenType::Ident(name) => {
1446                        let name = name.clone();
1447                        self.advance();
1448                        name
1449                    }
1450                    TokenType::Int => {
1451                        self.advance();
1452                        "int".to_string()
1453                    }
1454                    TokenType::Float => {
1455                        self.advance();
1456                        "float".to_string()
1457                    }
1458                    _ => {
1459                        // Try to use the lexeme if it's a keyword
1460                        let lexeme = self.peek().lexeme.clone();
1461                        if !lexeme.is_empty() {
1462                            self.advance();
1463                            lexeme
1464                        } else {
1465                            return Err(ParserError::ExpectedIdentifierAfterDot(self.peek().line));
1466                        }
1467                    }
1468                };
1469                expr = Expr::MemberAccess {
1470                    object: Box::new(expr),
1471                    member,
1472                };
1473            } else if self.match_token(&[TokenType::LBracket]) {
1474                // Historical reference: expr[index]
1475                let index = self.expression()?;
1476                self.consume(TokenType::RBracket, "Expected ']'")?;
1477                expr = Expr::Index {
1478                    expr: Box::new(expr),
1479                    index: Box::new(index),
1480                };
1481            } else if self.check(&TokenType::Less) {
1482                // Try to parse type arguments: <type>
1483                // This is tricky because < can also be a comparison operator
1484                // We use try_parse to backtrack if it's not actually type args
1485                let type_args = self.try_parse_type_args().unwrap_or_default();
1486
1487                // After type args, we must have a function call
1488                if self.match_token(&[TokenType::LParen]) {
1489                    let lparen = &self.tokens[self.current - 1];
1490                    let call_loc = Loc::new(lparen.line as u32, lparen.column as u32);
1491                    let id = self.next_call_id();
1492                    let args = self.arguments()?;
1493                    self.consume(TokenType::RParen, "Expected ')'")?;
1494                    expr = Expr::Call {
1495                        callee: Box::new(expr),
1496                        type_args,
1497                        args,
1498                        id,
1499                        loc: call_loc,
1500                    };
1501                } else {
1502                    // Not a function call, just break
1503                    break;
1504                }
1505            } else if self.match_token(&[TokenType::LParen]) {
1506                // Function call without type arguments
1507                let lparen = &self.tokens[self.current - 1];
1508                let call_loc = Loc::new(lparen.line as u32, lparen.column as u32);
1509                let id = self.next_call_id();
1510                let args = self.arguments()?;
1511                self.consume(TokenType::RParen, "Expected ')'")?;
1512                expr = Expr::Call {
1513                    callee: Box::new(expr),
1514                    type_args: vec![],
1515                    args,
1516                    id,
1517                    loc: call_loc,
1518                };
1519            } else {
1520                break;
1521            }
1522        }
1523
1524        Ok(expr)
1525    }
1526
1527    fn arguments(&mut self) -> Result<Vec<Argument>, ParserError> {
1528        let mut args = vec![];
1529
1530        if !self.check(&TokenType::RParen) {
1531            loop {
1532                // Check for named argument: name=value
1533                // In PineScript, function calls can have named arguments like plot(x, title="foo", color=red)
1534                // `type` is a keyword (v5 UDTs) but is also v3/v4's `input(..., type=...)`
1535                // parameter name, so accept it as a key too.
1536                let key_name = match &self.peek().typ {
1537                    TokenType::Ident(name) => Some(name.clone()),
1538                    TokenType::Type => Some("type".to_string()),
1539                    _ => None,
1540                };
1541                if let Some(name) = key_name {
1542                    if let Some((name, value)) = self.try_parse(|p| {
1543                        p.advance(); // consume identifier
1544                        if p.check(&TokenType::Assign) {
1545                            // This is a named argument
1546                            p.advance(); // consume =
1547                            let value = p.expression()?;
1548                            Ok((name.clone(), value))
1549                        } else {
1550                            Err(ParserError::UnexpectedToken(
1551                                p.peek().typ.clone(),
1552                                p.peek().line,
1553                            ))
1554                        }
1555                    }) {
1556                        args.push(Argument::Named { name, value });
1557                    } else {
1558                        // Not a named argument, parse as expression
1559                        let expr = self.expression()?;
1560                        args.push(Argument::Positional(expr));
1561                    }
1562                } else {
1563                    let expr = self.expression()?;
1564                    args.push(Argument::Positional(expr));
1565                }
1566
1567                if !self.match_token(&[TokenType::Comma]) {
1568                    break;
1569                }
1570            }
1571        }
1572
1573        Ok(args)
1574    }
1575
1576    fn primary(&mut self) -> Result<Expr, ParserError> {
1577        if let TokenType::IntLiteral(n) = self.peek().typ {
1578            self.advance();
1579            return Ok(Expr::Literal(Literal::Int(n)));
1580        }
1581
1582        if let TokenType::Number(n) = self.peek().typ {
1583            self.advance();
1584            return Ok(Expr::Literal(Literal::Number(n)));
1585        }
1586
1587        if let TokenType::String(ref s) = self.peek().typ {
1588            let s = s.clone();
1589            self.advance();
1590            return Ok(Expr::Literal(Literal::String(s)));
1591        }
1592
1593        if let TokenType::Bool(b) = self.peek().typ {
1594            self.advance();
1595            return Ok(Expr::Literal(Literal::Bool(b)));
1596        }
1597
1598        if let TokenType::HexColor(ref hex) = self.peek().typ {
1599            let hex = hex.clone();
1600            self.advance();
1601            return Ok(Expr::Literal(Literal::HexColor(hex)));
1602        }
1603
1604        // Handle na as a literal
1605        if self.match_token(&[TokenType::Na]) {
1606            return Ok(Expr::Literal(Literal::Na));
1607        }
1608
1609        // Handle keywords that can be used as identifiers (int, float)
1610        // These can be function names (e.g., int(), float())
1611        if self.match_token(&[TokenType::Int, TokenType::Float]) {
1612            let name = self.tokens[self.current - 1].lexeme.clone();
1613            return Ok(Expr::Variable(name));
1614        }
1615
1616        if let TokenType::Ident(ref name) = self.peek().typ {
1617            let name = name.clone();
1618            self.advance();
1619            return Ok(Expr::Variable(name));
1620        }
1621
1622        if self.match_token(&[TokenType::LParen]) {
1623            // Skip newlines and indents after opening parenthesis for multiline expressions
1624            self.skip_newlines();
1625            let had_indent = self.match_token(&[TokenType::Indent]);
1626
1627            let expr = self.expression()?;
1628
1629            // Skip newlines and consume dedent if we had indent
1630            self.skip_newlines();
1631            if had_indent {
1632                self.match_token(&[TokenType::Dedent]);
1633            }
1634
1635            self.consume(TokenType::RParen, "Expected ')'")?;
1636            return Ok(expr);
1637        }
1638
1639        // Switch expression: switch value \n case => result
1640        if self.match_token(&[TokenType::Switch]) {
1641            let value = Box::new(self.expression()?);
1642
1643            // Skip newline after switch value
1644            self.match_token(&[TokenType::Newline]);
1645
1646            // Skip indent for switch block
1647            let has_indent = self.match_token(&[TokenType::Indent]);
1648
1649            let mut cases = vec![];
1650
1651            // Parse cases until we can't parse any more
1652            loop {
1653                // Skip leading newlines
1654                self.skip_newlines();
1655
1656                // Check for dedent (end of switch block)
1657                if self.check(&TokenType::Dedent) {
1658                    if has_indent {
1659                        self.advance(); // consume dedent
1660                    }
1661                    break;
1662                }
1663
1664                // Check if we're done (end of block or EOF)
1665                if self.is_at_end() {
1666                    break;
1667                }
1668
1669                // Check for default case: => result (no pattern)
1670                if self.match_token(&[TokenType::Arrow]) {
1671                    // Skip newlines after =>
1672                    self.skip_newlines();
1673
1674                    // Parse the result expression
1675                    let result = self.expression()?;
1676
1677                    // Use a special "default" literal as the pattern
1678                    let default_pattern = Expr::Literal(Literal::Bool(true));
1679                    cases.push((default_pattern, result));
1680                    continue;
1681                }
1682
1683                // Try to parse a case
1684                if let Some((pattern, result)) = self.try_parse(|p| {
1685                    // Parse the pattern (could be a string, number, identifier, etc.)
1686                    let pattern = p.expression()?;
1687
1688                    // Expect =>
1689                    if !p.match_token(&[TokenType::Arrow]) {
1690                        return Err(ParserError::UnexpectedToken(
1691                            p.peek().typ.clone(),
1692                            p.peek().line,
1693                        ));
1694                    }
1695
1696                    // Skip newlines after =>
1697                    p.skip_newlines();
1698
1699                    // Parse the result expression
1700                    let result = p.expression()?;
1701                    Ok((pattern, result))
1702                }) {
1703                    cases.push((pattern, result));
1704                } else {
1705                    break;
1706                }
1707            }
1708
1709            return Ok(Expr::Switch { value, cases });
1710        }
1711
1712        // Array literal: [1, 2, 3]
1713        if self.match_token(&[TokenType::LBracket]) {
1714            // Skip leading newlines
1715            self.skip_newlines_and_indent();
1716
1717            let elements = self.parse_comma_separated(&TokenType::RBracket, |p| p.expression())?;
1718
1719            // Skip trailing newlines and dedent
1720            self.skip_newlines_and_dedent();
1721
1722            self.consume(TokenType::RBracket, "Expected ']'")?;
1723            return Ok(Expr::Array(elements));
1724        }
1725
1726        Err(ParserError::UnexpectedToken(
1727            self.peek().typ.clone(),
1728            self.peek().line,
1729        ))
1730    }
1731}
1732
1733#[cfg(test)]
1734mod tests {
1735    use super::*;
1736    use pine_lexer::Lexer;
1737
1738    fn parse_expr(input: &str) -> eyre::Result<Expr> {
1739        let mut lexer = Lexer::new(input);
1740        let tokens = lexer.tokenize()?;
1741        let mut parser = Parser::new(tokens);
1742        let stmts = parser.parse()?;
1743
1744        if let Some(Stmt::Expression(expr)) = stmts.first() {
1745            Ok(expr.clone())
1746        } else {
1747            Err(eyre::eyre!("Expected expression statement".to_string()))
1748        }
1749    }
1750
1751    #[test]
1752    fn test_literals() {
1753        // Numbers
1754        let expr = parse_expr("42").unwrap();
1755        assert_eq!(expr, Expr::Literal(Literal::Int(42)));
1756
1757        // Strings
1758        let expr = parse_expr(r#""hello""#).unwrap();
1759        assert_eq!(expr, Expr::Literal(Literal::String("hello".to_string())));
1760
1761        // Booleans
1762        let expr = parse_expr("true").unwrap();
1763        assert_eq!(expr, Expr::Literal(Literal::Bool(true)));
1764    }
1765
1766    #[test]
1767    fn test_variables() {
1768        let expr = parse_expr("close").unwrap();
1769        assert_eq!(expr, Expr::Variable("close".to_string()));
1770
1771        let expr = parse_expr("my_var").unwrap();
1772        assert_eq!(expr, Expr::Variable("my_var".to_string()));
1773    }
1774
1775    #[test]
1776    fn test_historical_references() {
1777        // close[1] - previous close
1778        let expr = parse_expr("close[1]").unwrap();
1779        assert!(matches!(expr, Expr::Index { .. }));
1780        if let Expr::Index { expr: base, index } = expr {
1781            assert_eq!(*base, Expr::Variable("close".to_string()));
1782            assert_eq!(*index, Expr::Literal(Literal::Int(1)));
1783        }
1784
1785        // high[5] - 5 bars ago
1786        let expr = parse_expr("high[5]").unwrap();
1787        if let Expr::Index { expr: base, index } = expr {
1788            assert_eq!(*base, Expr::Variable("high".to_string()));
1789            assert_eq!(*index, Expr::Literal(Literal::Int(5)));
1790        }
1791    }
1792
1793    #[test]
1794    fn test_function_calls() {
1795        // Simple function call
1796        let expr = parse_expr("sma(close, 14)").unwrap();
1797        if let Expr::Call {
1798            callee,
1799            type_args,
1800            args,
1801            ..
1802        } = expr
1803        {
1804            assert_eq!(*callee, Expr::Variable("sma".to_string()));
1805            assert_eq!(type_args.len(), 0);
1806            assert_eq!(args.len(), 2);
1807            assert_eq!(
1808                args[0],
1809                Argument::Positional(Expr::Variable("close".to_string()))
1810            );
1811            assert_eq!(
1812                args[1],
1813                Argument::Positional(Expr::Literal(Literal::Int(14)))
1814            );
1815        } else {
1816            panic!("Expected function call");
1817        }
1818
1819        // No arguments
1820        let expr = parse_expr("foo()").unwrap();
1821        if let Expr::Call {
1822            callee,
1823            type_args,
1824            args,
1825            ..
1826        } = expr
1827        {
1828            assert_eq!(*callee, Expr::Variable("foo".to_string()));
1829            assert_eq!(type_args.len(), 0);
1830            assert_eq!(args.len(), 0);
1831        }
1832    }
1833
1834    #[test]
1835    fn test_arithmetic_expressions() {
1836        // Addition
1837        let expr = parse_expr("2 + 3").unwrap();
1838        if let Expr::Binary {
1839            left, op, right, ..
1840        } = expr
1841        {
1842            assert_eq!(*left, Expr::Literal(Literal::Int(2)));
1843            assert_eq!(op, BinOp::Add);
1844            assert_eq!(*right, Expr::Literal(Literal::Int(3)));
1845        }
1846
1847        // Multiplication has higher precedence: 2 + 3 * 4 = 2 + (3 * 4)
1848        let expr = parse_expr("2 + 3 * 4").unwrap();
1849        if let Expr::Binary {
1850            left,
1851            op: op1,
1852            right,
1853            ..
1854        } = expr
1855        {
1856            assert_eq!(*left, Expr::Literal(Literal::Int(2)));
1857            assert_eq!(op1, BinOp::Add);
1858            if let Expr::Binary {
1859                left: l2,
1860                op: op2,
1861                right: r2,
1862                ..
1863            } = *right
1864            {
1865                assert_eq!(*l2, Expr::Literal(Literal::Int(3)));
1866                assert_eq!(op2, BinOp::Mul);
1867                assert_eq!(*r2, Expr::Literal(Literal::Int(4)));
1868            }
1869        }
1870
1871        // Division
1872        let expr = parse_expr("10 / 2").unwrap();
1873        if let Expr::Binary {
1874            left, op, right, ..
1875        } = expr
1876        {
1877            assert_eq!(*left, Expr::Literal(Literal::Int(10)));
1878            assert_eq!(op, BinOp::Div);
1879            assert_eq!(*right, Expr::Literal(Literal::Int(2)));
1880        }
1881
1882        // Subtraction
1883        let expr = parse_expr("5 - 3").unwrap();
1884        if let Expr::Binary {
1885            left, op, right, ..
1886        } = expr
1887        {
1888            assert_eq!(*left, Expr::Literal(Literal::Int(5)));
1889            assert_eq!(op, BinOp::Sub);
1890            assert_eq!(*right, Expr::Literal(Literal::Int(3)));
1891        }
1892    }
1893
1894    #[test]
1895    fn test_comparison_expressions() {
1896        // Greater than
1897        let expr = parse_expr("close > open").unwrap();
1898        if let Expr::Binary {
1899            left, op, right, ..
1900        } = expr
1901        {
1902            assert_eq!(*left, Expr::Variable("close".to_string()));
1903            assert_eq!(op, BinOp::Greater);
1904            assert_eq!(*right, Expr::Variable("open".to_string()));
1905        }
1906
1907        // Less than
1908        let expr = parse_expr("rsi < 30").unwrap();
1909        if let Expr::Binary {
1910            left, op, right, ..
1911        } = expr
1912        {
1913            assert_eq!(*left, Expr::Variable("rsi".to_string()));
1914            assert_eq!(op, BinOp::Less);
1915            assert_eq!(*right, Expr::Literal(Literal::Int(30)));
1916        }
1917
1918        // Equality
1919        let expr = parse_expr("x == 5").unwrap();
1920        if let Expr::Binary {
1921            left, op, right, ..
1922        } = expr
1923        {
1924            assert_eq!(*left, Expr::Variable("x".to_string()));
1925            assert_eq!(op, BinOp::Eq);
1926            assert_eq!(*right, Expr::Literal(Literal::Int(5)));
1927        }
1928    }
1929
1930    #[test]
1931    fn test_unary_expressions() {
1932        // Negation
1933        let expr = parse_expr("-5").unwrap();
1934        if let Expr::Unary { op, expr } = expr {
1935            assert_eq!(op, UnOp::Neg);
1936            assert_eq!(*expr, Expr::Literal(Literal::Int(5)));
1937        }
1938
1939        // Double negation
1940        let expr = parse_expr("--10").unwrap();
1941        if let Expr::Unary { op: op1, expr: e1 } = expr {
1942            assert_eq!(op1, UnOp::Neg);
1943            if let Expr::Unary { op: op2, expr: e2 } = *e1 {
1944                assert_eq!(op2, UnOp::Neg);
1945                assert_eq!(*e2, Expr::Literal(Literal::Int(10)));
1946            }
1947        }
1948    }
1949
1950    #[test]
1951    fn test_var_declarations() {
1952        let mut lexer = Lexer::new("var x = 10");
1953        let tokens = lexer.tokenize().unwrap();
1954        let mut parser = Parser::new(tokens);
1955        let stmts = parser.parse().unwrap();
1956
1957        assert_eq!(stmts.len(), 1);
1958        if let Stmt::VarDecl {
1959            name,
1960            type_qualifier,
1961            type_annotation,
1962            initializer,
1963            var_kind,
1964        } = &stmts[0]
1965        {
1966            assert_eq!(name, "x");
1967            assert_eq!(*type_qualifier, None);
1968            assert_eq!(*type_annotation, None);
1969            assert_eq!(*var_kind, VarKind::Var, "var x = 10 must be Var");
1970            assert_eq!(
1971                initializer.as_ref().unwrap(),
1972                &Expr::Literal(Literal::Int(10))
1973            );
1974        } else {
1975            panic!("Expected VarDecl");
1976        }
1977
1978        // Var without initializer
1979        let mut lexer = Lexer::new("var y");
1980        let tokens = lexer.tokenize().unwrap();
1981        let mut parser = Parser::new(tokens);
1982        let stmts = parser.parse().unwrap();
1983
1984        if let Stmt::VarDecl {
1985            name, initializer, ..
1986        } = &stmts[0]
1987        {
1988            assert_eq!(name, "y");
1989            assert!(initializer.is_none());
1990        }
1991    }
1992
1993    #[test]
1994    fn test_pinescript_examples() {
1995        // PineScript: close[1] > close[2]
1996        let expr = parse_expr("close[1] > close[2]").unwrap();
1997        assert!(matches!(
1998            expr,
1999            Expr::Binary {
2000                op: BinOp::Greater,
2001                ..
2002            }
2003        ));
2004
2005        // PineScript: sma(close, 14) > sma(close, 28)
2006        let expr = parse_expr("sma(close, 14) > sma(close, 28)").unwrap();
2007        if let Expr::Binary {
2008            left, op, right, ..
2009        } = expr
2010        {
2011            assert_eq!(op, BinOp::Greater);
2012            assert!(matches!(*left, Expr::Call { .. }));
2013            assert!(matches!(*right, Expr::Call { .. }));
2014        }
2015
2016        // PineScript: (high + low) / 2
2017        let expr = parse_expr("(high + low) / 2").unwrap();
2018        if let Expr::Binary {
2019            left,
2020            op: div_op,
2021            right,
2022            ..
2023        } = expr
2024        {
2025            assert_eq!(div_op, BinOp::Div);
2026            assert!(matches!(*left, Expr::Binary { op: BinOp::Add, .. }));
2027            assert_eq!(*right, Expr::Literal(Literal::Int(2)));
2028        }
2029    }
2030
2031    /// Helper function to recursively collect all .pine files in a directory
2032    fn collect_pine_files_recursive(dir: &std::path::Path) -> Vec<std::path::PathBuf> {
2033        walkdir::WalkDir::new(dir)
2034            .into_iter()
2035            .filter_map(|e| e.ok())
2036            .filter(|e| e.path().extension().and_then(|s| s.to_str()) == Some("pine"))
2037            .map(|e| e.path().to_path_buf())
2038            .collect()
2039    }
2040
2041    #[test]
2042    fn test_parse_testdata_files() -> eyre::Result<()> {
2043        use std::fs;
2044        use std::path::Path;
2045
2046        let testdata_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("testdata");
2047
2048        let filter = std::env::var("TEST_FILE").ok();
2049        let debug = std::env::var("DEBUG").is_ok();
2050        let generate_ast = std::env::var("GENERATE_AST").is_ok();
2051
2052        let pine_files = collect_pine_files_recursive(&testdata_dir);
2053
2054        let process_file = |path: &std::path::PathBuf| -> eyre::Result<()> {
2055            let content = fs::read_to_string(path)?;
2056
2057            let mut lexer = Lexer::new(&content);
2058            let tokens = lexer.tokenize()?;
2059
2060            if debug {
2061                println!("Tokens: {:#?}", tokens);
2062            }
2063
2064            let mut parser = Parser::new(tokens);
2065            let ast = parser.parse()?;
2066
2067            if debug {
2068                let ast_json = serde_json::to_string(&ast)?;
2069                println!("AST JSON: {:?}", ast_json);
2070            }
2071
2072            // Check for corresponding _ast.json file
2073            let json_path = path.with_file_name(format!(
2074                "{}_ast.json",
2075                path.file_stem().unwrap().to_str().unwrap()
2076            ));
2077
2078            if generate_ast {
2079                // Generate/overwrite AST JSON file
2080                let json = serde_json::to_string_pretty(&ast)?;
2081                fs::write(&json_path, &json)?;
2082            } else if json_path.exists() {
2083                // Compare with expected AST
2084                let expected_json = fs::read_to_string(&json_path)?;
2085                let expected_ast: Vec<Stmt> = serde_json::from_str(&expected_json)?;
2086
2087                if ast != expected_ast {
2088                    return Err(eyre::eyre!(
2089                        "AST mismatch, expected AST from {:?}",
2090                        json_path
2091                    ));
2092                }
2093            }
2094
2095            Ok(())
2096        };
2097
2098        for path in pine_files {
2099            let filename = path.file_name().unwrap().to_str().unwrap();
2100
2101            // Skip if filter is set and doesn't match
2102            if let Some(ref filter_name) = filter {
2103                if filename != filter_name {
2104                    continue;
2105                }
2106            }
2107
2108            if let Err(e) = process_file(&path) {
2109                return Err(eyre::eyre!("Failed to process {}: {}", filename, e));
2110            }
2111        }
2112
2113        Ok(())
2114    }
2115
2116    #[test]
2117    #[ignore]
2118    fn test_parse_external_pinescript_indicators() -> eyre::Result<()> {
2119        use std::fs;
2120        use std::path::Path;
2121
2122        let testdata_dir =
2123            Path::new(env!("CARGO_MANIFEST_DIR")).join("tradingview-pinescript-indicators");
2124
2125        let filter = std::env::var("TEST_FILE").ok();
2126        let debug = std::env::var("DEBUG").is_ok();
2127
2128        let pine_files = collect_pine_files_recursive(&testdata_dir);
2129
2130        let process_file = |path: &std::path::PathBuf| -> eyre::Result<()> {
2131            let content = fs::read_to_string(path)?;
2132
2133            let mut lexer = Lexer::new(&content);
2134            let tokens = lexer.tokenize()?;
2135
2136            if debug {
2137                println!("Tokens: {:#?}", tokens);
2138            }
2139
2140            let mut parser = Parser::new(tokens);
2141            let ast = parser.parse()?;
2142
2143            let ast_json = serde_json::to_string(&ast)?;
2144
2145            if debug {
2146                println!("AST JSON: {:?}", ast_json);
2147            }
2148
2149            Ok(())
2150        };
2151
2152        for path in pine_files {
2153            let filename = path.file_name().unwrap().to_str().unwrap();
2154
2155            // Skip if filter is set and doesn't match
2156            if let Some(ref filter_name) = filter {
2157                if filename != filter_name {
2158                    continue;
2159                }
2160            }
2161
2162            if let Err(e) = process_file(&path) {
2163                return Err(eyre::eyre!("Failed to process {}: {}", filename, e));
2164            }
2165        }
2166
2167        Ok(())
2168    }
2169}