xdl_parser/
parser.rs

1//! XDL Parser implementation
2
3use crate::ast::*;
4use crate::lexer::Token;
5use xdl_core::{XdlError, XdlResult, XdlValue};
6
7/// Parser state tracking current position in token stream
8struct Parser<'a> {
9    tokens: &'a [Token],
10    current: usize,
11}
12
13impl<'a> Parser<'a> {
14    fn new(tokens: &'a [Token]) -> Self {
15        Self { tokens, current: 0 }
16    }
17
18    /// Get current token without consuming it
19    fn peek(&self) -> &Token {
20        self.tokens.get(self.current).unwrap_or(&Token::EOF)
21    }
22
23    /// Get current token and advance
24    fn advance(&mut self) -> &Token {
25        if self.current < self.tokens.len() {
26            let token = &self.tokens[self.current];
27            self.current += 1;
28            token
29        } else {
30            &Token::EOF
31        }
32    }
33
34    /// Check if current token matches expected token
35    fn check(&self, expected: &Token) -> bool {
36        std::mem::discriminant(self.peek()) == std::mem::discriminant(expected)
37    }
38
39    /// Consume token if it matches expected, otherwise error
40    fn consume(&mut self, expected: Token, message: &str) -> XdlResult<()> {
41        if self.check(&expected) {
42            self.advance();
43            Ok(())
44        } else {
45            Err(XdlError::ParseError {
46                message: format!("{}, got {:?}", message, self.peek()),
47                line: 1, // TODO: track line numbers
48                column: self.current,
49            })
50        }
51    }
52
53    /// Check if we're at end of tokens
54    fn is_at_end(&self) -> bool {
55        matches!(self.peek(), Token::EOF)
56    }
57
58    /// Parse the entire program
59    fn parse_program(&mut self) -> XdlResult<Program> {
60        let mut statements = Vec::new();
61
62        loop {
63            // Skip leading/trailing newlines
64            while matches!(self.peek(), Token::Newline) {
65                self.advance();
66            }
67            // Check if we've reached the end
68            if self.is_at_end() {
69                break;
70            }
71            statements.push(self.parse_statement()?);
72        }
73
74        Ok(Program {
75            statements,
76            location: Location::unknown(),
77        })
78    }
79
80    /// Parse a block (begin...end) or statements until terminator
81    fn parse_block_or_statement(&mut self, terminators: &[Token]) -> XdlResult<Vec<Statement>> {
82        // Check if this is a begin...end block
83        if self.check(&Token::Begin) {
84            self.advance(); // consume 'begin'
85            let mut statements = Vec::new();
86
87            // GDL/IDL allows both 'end' and specific terminators (endif, endfor, endwhile)
88            // to close a begin block. E.g., "for i=1,3 do begin ... endfor" is valid.
89            while !self.is_at_end() {
90                // Skip newlines before checking for END or terminators
91                while matches!(self.peek(), Token::Newline) {
92                    self.advance();
93                }
94
95                // Check if we hit 'end' or any of the terminators
96                if self.check(&Token::End) {
97                    self.advance(); // consume 'end'
98                    break;
99                }
100
101                // Check if we hit a terminator (like endif, endfor, endwhile)
102                let is_terminator = terminators.iter().any(|term| {
103                    std::mem::discriminant(self.peek()) == std::mem::discriminant(term)
104                });
105                if is_terminator {
106                    // Don't consume the terminator - let the caller handle it
107                    break;
108                }
109
110                statements.push(self.parse_statement()?);
111            }
112            Ok(statements)
113        } else {
114            // Parse statements until we hit a terminator
115            // The key insight: parse_statement() handles nested constructs recursively
116            let mut statements = Vec::new();
117            while !self.is_at_end() {
118                // Skip newlines before checking terminators
119                while matches!(self.peek(), Token::Newline) {
120                    self.advance();
121                }
122
123                let is_terminator = terminators.iter().any(|term| {
124                    std::mem::discriminant(self.peek()) == std::mem::discriminant(term)
125                });
126                if is_terminator {
127                    break;
128                }
129                statements.push(self.parse_statement()?);
130            }
131            Ok(statements)
132        }
133    }
134
135    /// Parse a statement
136    fn parse_statement(&mut self) -> XdlResult<Statement> {
137        // Skip leading newlines
138        while matches!(self.peek(), Token::Newline) {
139            self.advance();
140        }
141
142        // If we've reached EOF after skipping newlines, return an error
143        if self.is_at_end() {
144            return Err(XdlError::ParseError {
145                message: "Unexpected end of file".to_string(),
146                line: 0,
147                column: self.current,
148            });
149        }
150
151        match self.peek() {
152            Token::If => self.parse_if_statement(),
153            Token::For => self.parse_for_statement(),
154            Token::Foreach => self.parse_foreach_statement(),
155            Token::While => self.parse_while_statement(),
156            Token::Repeat => self.parse_repeat_statement(),
157            Token::Return => self.parse_return_statement(),
158            Token::Goto => self.parse_goto_statement(),
159            Token::Label(name) => {
160                let label_name = name.clone();
161                self.advance();
162                Ok(Statement::Label {
163                    name: label_name,
164                    location: Location::unknown(),
165                })
166            }
167            Token::Break => {
168                self.advance();
169                Ok(Statement::Break {
170                    location: Location::unknown(),
171                })
172            }
173            Token::Continue => {
174                self.advance();
175                Ok(Statement::Continue {
176                    location: Location::unknown(),
177                })
178            }
179            Token::Pro | Token::Procedure => self.parse_procedure_definition(),
180            Token::Function => self.parse_function_definition(),
181            Token::Case => self.parse_case_statement(),
182            Token::Switch => self.parse_switch_statement(),
183            _ => {
184                // Try to parse as procedure call, expression statement, or assignment
185                if let Token::Identifier(name) = self.peek() {
186                    let name = name.clone();
187                    let start_pos = self.current;
188                    self.advance(); // consume identifier
189
190                    // Check if this is a procedure call (identifier followed by comma, newline, or end of statement)
191                    if self.check(&Token::Comma)
192                        || self.is_at_end()
193                        || matches!(self.peek(), Token::EOF | Token::Newline)
194                    {
195                        return self.parse_procedure_call(name);
196                    }
197
198                    // Not a procedure call, backtrack and parse as expression
199                    self.current = start_pos;
200                }
201
202                let expr = self.parse_expression()?;
203
204                // Check if this is an assignment
205                if self.check(&Token::Assign) {
206                    self.advance(); // consume '='
207                    let value = self.parse_expression()?;
208                    Ok(Statement::Assignment {
209                        target: expr,
210                        value,
211                        location: Location::unknown(),
212                    })
213                } else {
214                    Ok(Statement::Expression {
215                        expr,
216                        location: Location::unknown(),
217                    })
218                }
219            }
220        }
221    }
222
223    /// Parse if statement
224    /// Supports:
225    /// - Single-line: IF x THEN statement (no ENDIF needed)
226    /// - Single-line with else: IF x THEN statement ELSE statement
227    /// - Multi-line: IF x THEN\n statement(s) ENDIF
228    /// - Block form: IF x THEN BEGIN ... END
229    fn parse_if_statement(&mut self) -> XdlResult<Statement> {
230        self.consume(Token::If, "Expected 'if'")?;
231        let condition = self.parse_expression()?;
232        self.consume(Token::Then, "Expected 'then' after if condition")?;
233
234        // Check if this is a block (BEGIN) or single-line form
235        let is_block = self.check(&Token::Begin);
236
237        // Check for single-line IF: if no newline after THEN, parse only one statement
238        // Single-line: IF x THEN statement (no ENDIF needed)
239        // Multi-line: IF x THEN\n statements... ENDIF
240        let is_single_line = !is_block && !matches!(self.peek(), Token::Newline);
241
242        let then_block = if is_block {
243            // Multi-line form: IF x THEN BEGIN ... END/ENDIF
244            self.parse_block_or_statement(&[Token::Else, Token::Endif])?
245        } else if is_single_line {
246            // Single-line form: IF x THEN statement (no ENDIF)
247            // Parse just ONE statement
248            let stmt = self.parse_statement()?;
249            vec![stmt]
250        } else {
251            // Non-block multi-line form: IF x THEN\n statement(s) ENDIF
252            // Parse statements until we hit ELSE or ENDIF
253            let mut stmts = Vec::new();
254            loop {
255                // Skip newlines before checking for ELSE/ENDIF
256                while matches!(self.peek(), Token::Newline) {
257                    self.advance();
258                }
259                if matches!(self.peek(), Token::Else | Token::Endif | Token::EOF) {
260                    break;
261                }
262                stmts.push(self.parse_statement()?);
263            }
264            stmts
265        };
266
267        // For single-line IF, check for optional ELSE on the same line
268        let else_block = if is_single_line {
269            if self.check(&Token::Else) {
270                self.advance(); // consume 'else'
271                // Single-line ELSE: parse one statement
272                let stmt = self.parse_statement()?;
273                Some(vec![stmt])
274            } else {
275                None
276            }
277        } else {
278            // Skip newlines before ELSE check
279            while matches!(self.peek(), Token::Newline) {
280                self.advance();
281            }
282
283            if self.check(&Token::Else) {
284                self.advance(); // consume 'else'
285                if is_block || self.check(&Token::Begin) {
286                    // Multi-line else block
287                    Some(self.parse_block_or_statement(&[Token::Endif])?)
288                } else {
289                    // Non-block else: parse until ENDIF
290                    let mut stmts = Vec::new();
291                    loop {
292                        while matches!(self.peek(), Token::Newline) {
293                            self.advance();
294                        }
295                        if matches!(self.peek(), Token::Endif | Token::EOF) {
296                            break;
297                        }
298                        stmts.push(self.parse_statement()?);
299                    }
300                    Some(stmts)
301                }
302            } else {
303                None
304            }
305        };
306
307        // Skip newlines before ENDIF check (only for multi-line forms)
308        if !is_single_line {
309            while matches!(self.peek(), Token::Newline) {
310                self.advance();
311            }
312        }
313
314        // Consume ENDIF if present (not required for single-line form)
315        if self.check(&Token::Endif) {
316            self.advance(); // consume 'endif'
317        }
318
319        Ok(Statement::If {
320            condition,
321            then_block,
322            else_block,
323            location: Location::unknown(),
324        })
325    }
326
327    /// Parse for statement
328    fn parse_for_statement(&mut self) -> XdlResult<Statement> {
329        self.consume(Token::For, "Expected 'for'")?;
330
331        // Parse variable = start, end [, step]
332        let variable = if let Token::Identifier(name) = self.advance() {
333            name.clone()
334        } else {
335            return Err(XdlError::ParseError {
336                message: "Expected variable name in for loop".to_string(),
337                line: 1,
338                column: self.current,
339            });
340        };
341
342        self.consume(Token::Assign, "Expected '=' after for variable")?;
343        let start = self.parse_expression()?;
344        self.consume(Token::Comma, "Expected ',' after for start value")?;
345        let end = self.parse_expression()?;
346
347        let step = if self.check(&Token::Comma) {
348            self.advance(); // consume ','
349            Some(self.parse_expression()?)
350        } else {
351            None
352        };
353
354        // Check for 'do' keyword (optional)
355        if matches!(self.peek(), Token::Identifier(s) if s.to_uppercase() == "DO") {
356            self.advance(); // consume 'do'
357        }
358
359        // Parse body - support both 'begin...end' and multiple statements until endfor
360        let body = if self.check(&Token::Begin) {
361            self.parse_block_or_statement(&[Token::Endfor])?
362        } else {
363            // Parse statements until ENDFOR
364            let mut stmts = Vec::new();
365            loop {
366                while matches!(self.peek(), Token::Newline) {
367                    self.advance();
368                }
369                if matches!(self.peek(), Token::Endfor | Token::EOF) {
370                    break;
371                }
372                stmts.push(self.parse_statement()?);
373            }
374            stmts
375        };
376
377        // Skip newlines before ENDFOR
378        while matches!(self.peek(), Token::Newline) {
379            self.advance();
380        }
381
382        self.consume(Token::Endfor, "Expected 'endfor' to close for loop")?;
383
384        Ok(Statement::For {
385            variable,
386            start,
387            end,
388            step,
389            body,
390            location: Location::unknown(),
391        })
392    }
393
394    /// Parse procedure call
395    fn parse_procedure_call(&mut self, name: String) -> XdlResult<Statement> {
396        let mut args = Vec::new();
397        let mut keywords = Vec::new();
398
399        // Parse comma-separated arguments
400        while self.check(&Token::Comma) {
401            self.advance(); // consume comma
402
403            // Check if this is a trailing comma (end of line or statement)
404            if matches!(self.peek(), Token::Newline | Token::EOF) {
405                break;
406            }
407
408            // Check for /KEYWORD syntax (shorthand for KEYWORD=1)
409            if matches!(self.peek(), Token::Divide) {
410                let next_pos = self.current + 1;
411                if next_pos < self.tokens.len() {
412                    if let Token::Identifier(kw_name) = &self.tokens[next_pos] {
413                        let kw_name = kw_name.clone();
414                        self.advance(); // consume '/'
415                        self.advance(); // consume identifier
416                        keywords.push(Keyword {
417                            name: kw_name,
418                            value: Some(Expression::Literal {
419                                value: XdlValue::Long(1),
420                                location: Location::unknown(),
421                            }),
422                            location: Location::unknown(),
423                        });
424                        continue;
425                    }
426                }
427            }
428
429            // Check for keyword argument (identifier = expression)
430
431            if let Token::Identifier(kw_name) = self.peek() {
432                let kw_name = kw_name.clone();
433                let next_pos = self.current + 1;
434
435                if next_pos < self.tokens.len() && matches!(self.tokens[next_pos], Token::Assign) {
436                    // This is a keyword argument
437                    self.advance(); // consume identifier
438                    self.advance(); // consume '='
439                    let value = self.parse_expression()?;
440                    keywords.push(Keyword {
441                        name: kw_name,
442                        value: Some(value),
443                        location: Location::unknown(),
444                    });
445                    continue;
446                }
447            }
448
449            // Regular positional argument
450            args.push(self.parse_expression()?);
451        }
452
453        // Check if this is OBJ_DESTROY
454        if name.to_uppercase() == "OBJ_DESTROY" {
455            return Ok(Statement::ObjectDestroy {
456                objects: args,
457                location: Location::unknown(),
458            });
459        }
460
461        Ok(Statement::ProcedureCall {
462            name,
463            args,
464            keywords,
465            location: Location::unknown(),
466        })
467    }
468
469    /// Parse foreach statement
470    fn parse_foreach_statement(&mut self) -> XdlResult<Statement> {
471        self.consume(Token::Foreach, "Expected 'foreach'")?;
472
473        // Parse variable name
474        let variable = if let Token::Identifier(name) = self.advance() {
475            name.clone()
476        } else {
477            return Err(XdlError::ParseError {
478                message: "Expected variable name in foreach loop".to_string(),
479                line: 1,
480                column: self.current,
481            });
482        };
483
484        self.consume(Token::Comma, "Expected ',' after foreach variable")?;
485        let iterable = self.parse_expression()?;
486
487        // Optional index variable
488        let index_var = if self.check(&Token::Comma) {
489            self.advance(); // consume ','
490            if let Token::Identifier(name) = self.advance() {
491                Some(name.clone())
492            } else {
493                return Err(XdlError::ParseError {
494                    message: "Expected index variable name".to_string(),
495                    line: 1,
496                    column: self.current,
497                });
498            }
499        } else {
500            None
501        };
502
503        // Check for 'do' keyword (optional)
504        if matches!(self.peek(), Token::Identifier(s) if s.to_uppercase() == "DO") {
505            self.advance(); // consume 'do'
506        }
507
508        // Parse body - support both 'begin...end' and multiple statements
509        let body = self.parse_block_or_statement(&[Token::Endfor])?;
510
511        self.consume(
512            Token::Endfor,
513            "Expected 'endfor' or 'endforeach' to close foreach loop",
514        )?;
515
516        Ok(Statement::Foreach {
517            variable,
518            iterable,
519            index_var,
520            body,
521            location: Location::unknown(),
522        })
523    }
524
525    /// Parse while statement
526    fn parse_while_statement(&mut self) -> XdlResult<Statement> {
527        self.consume(Token::While, "Expected 'while'")?;
528        let condition = self.parse_expression()?;
529
530        // Check for 'do' keyword (optional)
531        if matches!(self.peek(), Token::Identifier(s) if s.to_uppercase() == "DO") {
532            self.advance(); // consume 'do'
533        }
534
535        // Parse body - support both 'begin...end' and multiple statements
536        let body = self.parse_block_or_statement(&[Token::Endwhile])?;
537
538        self.consume(Token::Endwhile, "Expected 'endwhile' to close while loop")?;
539
540        Ok(Statement::While {
541            condition,
542            body,
543            location: Location::unknown(),
544        })
545    }
546
547    /// Parse repeat statement
548    fn parse_repeat_statement(&mut self) -> XdlResult<Statement> {
549        self.consume(Token::Repeat, "Expected 'repeat'")?;
550
551        // Check if we have a 'begin' block
552        let body = self.parse_block_or_statement(&[Token::Until])?;
553
554        self.consume(Token::Until, "Expected 'until' to close repeat loop")?;
555        let condition = self.parse_expression()?;
556
557        Ok(Statement::Repeat {
558            body,
559            condition,
560            location: Location::unknown(),
561        })
562    }
563
564    /// Parse return statement
565    fn parse_return_statement(&mut self) -> XdlResult<Statement> {
566        self.consume(Token::Return, "Expected 'return'")?;
567
568        // IDL syntax: RETURN or RETURN, value (comma is optional)
569        let value = if matches!(self.peek(), Token::Newline | Token::EOF) {
570            None
571        } else {
572            // Skip optional comma after RETURN
573            if self.check(&Token::Comma) {
574                self.advance();
575            }
576            // Check again after comma - might be end of statement
577            if matches!(self.peek(), Token::Newline | Token::EOF) {
578                None
579            } else {
580                Some(self.parse_expression()?)
581            }
582        };
583
584        Ok(Statement::Return {
585            value,
586            location: Location::unknown(),
587        })
588    }
589
590    /// Parse GOTO statement
591    /// IDL syntax: GOTO, label (comma is optional)
592    fn parse_goto_statement(&mut self) -> XdlResult<Statement> {
593        self.consume(Token::Goto, "Expected 'goto'")?;
594
595        // Skip optional comma after GOTO
596        if self.check(&Token::Comma) {
597            self.advance();
598        }
599
600        // Get the label name
601        let label = if let Token::Identifier(name) = self.peek() {
602            name.clone()
603        } else {
604            return Err(XdlError::ParseError {
605                message: "Expected label name after GOTO".to_string(),
606                line: 1,
607                column: self.current,
608            });
609        };
610
611        self.advance(); // consume label identifier
612
613        Ok(Statement::Goto {
614            label,
615            location: Location::unknown(),
616        })
617    }
618
619    /// Parse CASE statement
620    /// CASE expr OF
621    ///     value1: statement
622    ///     value2: BEGIN ... END
623    ///     ELSE: statement
624    /// ENDCASE
625    fn parse_case_statement(&mut self) -> XdlResult<Statement> {
626        self.consume(Token::Case, "Expected 'case'")?;
627        let expr = self.parse_expression()?;
628        self.consume(Token::Of, "Expected 'of' after case expression")?;
629
630        // Skip newlines after OF
631        while matches!(self.peek(), Token::Newline) {
632            self.advance();
633        }
634
635        let mut branches = Vec::new();
636        let mut else_block = None;
637
638        // Parse case branches until we hit ENDCASE
639        while !matches!(self.peek(), Token::Endcase | Token::EOF) {
640            // Skip newlines between branches
641            while matches!(self.peek(), Token::Newline) {
642                self.advance();
643            }
644
645            if matches!(self.peek(), Token::Endcase) {
646                break;
647            }
648
649            // Check for ELSE branch
650            if matches!(self.peek(), Token::Else) {
651                self.advance(); // consume ELSE
652                self.consume(Token::Colon, "Expected ':' after ELSE")?;
653
654                // Parse ELSE body
655                let body = if matches!(self.peek(), Token::Begin) {
656                    self.parse_block_or_statement(&[Token::Endcase])?
657                } else {
658                    vec![self.parse_statement()?]
659                };
660                else_block = Some(body);
661
662                // Skip to ENDCASE
663                while matches!(self.peek(), Token::Newline) {
664                    self.advance();
665                }
666                break;
667            }
668
669            // Parse case value(s) - can be comma-separated
670            let mut values = Vec::new();
671            loop {
672                values.push(self.parse_expression()?);
673                if matches!(self.peek(), Token::Comma) {
674                    self.advance(); // consume comma
675                } else {
676                    break;
677                }
678            }
679
680            self.consume(Token::Colon, "Expected ':' after case value")?;
681
682            // Parse the body for this branch
683            let body = if matches!(self.peek(), Token::Begin) {
684                self.parse_block_or_statement(&[Token::Endcase])?
685            } else {
686                vec![self.parse_statement()?]
687            };
688
689            branches.push(CaseBranch { values, body, location: Location::unknown() });
690
691            // Skip newlines after the statement
692            while matches!(self.peek(), Token::Newline) {
693                self.advance();
694            }
695        }
696
697        self.consume(Token::Endcase, "Expected 'endcase' to close case statement")?;
698
699        Ok(Statement::Case {
700            expr,
701            branches,
702            else_block,
703            location: Location::unknown(),
704        })
705    }
706
707    /// Parse SWITCH statement (alias for CASE)
708    fn parse_switch_statement(&mut self) -> XdlResult<Statement> {
709        self.consume(Token::Switch, "Expected 'switch'")?;
710        let expr = self.parse_expression()?;
711        self.consume(Token::Of, "Expected 'of' after switch expression")?;
712
713        // Skip newlines after OF
714        while matches!(self.peek(), Token::Newline) {
715            self.advance();
716        }
717
718        let mut branches = Vec::new();
719        let mut else_block = None;
720
721        // Parse switch branches until we hit ENDSWITCH
722        while !matches!(self.peek(), Token::Endswitch | Token::EOF) {
723            while matches!(self.peek(), Token::Newline) {
724                self.advance();
725            }
726
727            if matches!(self.peek(), Token::Endswitch) {
728                break;
729            }
730
731            if matches!(self.peek(), Token::Else) {
732                self.advance();
733                self.consume(Token::Colon, "Expected ':' after ELSE")?;
734                let body = if matches!(self.peek(), Token::Begin) {
735                    self.parse_block_or_statement(&[Token::Endswitch])?
736                } else {
737                    vec![self.parse_statement()?]
738                };
739                else_block = Some(body);
740                while matches!(self.peek(), Token::Newline) {
741                    self.advance();
742                }
743                break;
744            }
745
746            let mut values = Vec::new();
747            loop {
748                values.push(self.parse_expression()?);
749                if matches!(self.peek(), Token::Comma) {
750                    self.advance();
751                } else {
752                    break;
753                }
754            }
755
756            self.consume(Token::Colon, "Expected ':' after case value")?;
757
758            let body = if matches!(self.peek(), Token::Begin) {
759                self.parse_block_or_statement(&[Token::Endswitch])?
760            } else {
761                vec![self.parse_statement()?]
762            };
763
764            branches.push(CaseBranch { values, body, location: Location::unknown() });
765
766            while matches!(self.peek(), Token::Newline) {
767                self.advance();
768            }
769        }
770
771        self.consume(Token::Endswitch, "Expected 'endswitch' to close switch statement")?;
772
773        Ok(Statement::Switch {
774            expr,
775            branches,
776            else_block,
777            location: Location::unknown(),
778        })
779    }
780
781    /// Parse procedure definition
782    fn parse_procedure_definition(&mut self) -> XdlResult<Statement> {
783        self.advance(); // consume 'pro' or 'procedure'
784
785        let name = if let Token::Identifier(name) = self.advance() {
786            name.clone()
787        } else {
788            return Err(XdlError::ParseError {
789                message: "Expected procedure name".to_string(),
790                line: 1,
791                column: self.current,
792            });
793        };
794
795        // Check if this is a class definition (ends with __define)
796        if name.ends_with("__define") {
797            return self.parse_class_definition_body(name);
798        }
799
800        // Check if this is a method definition (contains ::)
801        if name.contains("::") {
802            return self.parse_method_definition_body(name, false); // false = procedure
803        }
804
805        // Parse parameters and keywords
806        let mut params = Vec::new();
807        let mut keywords = Vec::new();
808
809        // Check if there's a comma after the procedure name
810        if self.check(&Token::Comma) {
811            self.advance(); // consume first comma
812
813            // Parse comma-separated parameters and keywords
814            loop {
815                // Check if we've reached the end of the parameter list
816                if matches!(self.peek(), Token::Newline | Token::EOF) {
817                    break;
818                }
819
820                // Get the parameter/keyword name
821                let param_name = if let Token::Identifier(name) = self.peek() {
822                    name.clone()
823                } else {
824                    break; // No more parameters
825                };
826
827                self.advance(); // consume identifier
828
829                // Check if this is a keyword (has '=' after it)
830                if self.check(&Token::Assign) {
831                    self.advance(); // consume '='
832                                    // For keyword declarations in procedure definitions,
833                                    // we don't parse the default value at definition time
834                                    // (IDL doesn't support default values in PRO declarations)
835                    keywords.push(KeywordDecl {
836                        name: param_name,
837                        by_reference: false,
838                        location: Location::unknown(),
839                    });
840                } else {
841                    // Regular parameter
842                    params.push(Parameter {
843                        name: param_name,
844                        by_reference: false,
845                        optional: false,
846                        location: Location::unknown(),
847                    });
848                }
849
850                // Check for next comma
851                if !self.check(&Token::Comma) {
852                    break;
853                }
854                self.advance(); // consume comma
855            }
856        }
857
858        // Consume any remaining tokens until we hit a newline or start of body
859        while matches!(self.peek(), Token::Comma | Token::Newline) {
860            self.advance();
861        }
862
863        // Parse body
864        let mut body = Vec::new();
865        // Accept both ENDPRO and END as procedure terminators (IDL compatibility)
866        loop {
867            // Skip newlines before checking for terminator
868            while matches!(self.peek(), Token::Newline) {
869                self.advance();
870            }
871            if matches!(self.peek(), Token::Endpro | Token::End | Token::EOF) {
872                break;
873            }
874            body.push(self.parse_statement()?);
875        }
876
877        // Consume either ENDPRO or END
878        if !matches!(self.peek(), Token::Endpro | Token::End) {
879            return Err(XdlError::ParseError {
880                message: "Expected 'END' or 'ENDPRO' to close procedure".to_string(),
881                line: 1,
882                column: self.current,
883            });
884        }
885        self.advance(); // consume ENDPRO or END
886
887        Ok(Statement::ProcedureDef {
888            name,
889            params,
890            keywords,
891            body,
892            location: Location::unknown(),
893        })
894    }
895
896    /// Parse function definition
897    fn parse_function_definition(&mut self) -> XdlResult<Statement> {
898        self.consume(Token::Function, "Expected 'function'")?;
899
900        let name = if let Token::Identifier(name) = self.advance() {
901            name.clone()
902        } else {
903            return Err(XdlError::ParseError {
904                message: "Expected function name".to_string(),
905                line: 1,
906                column: self.current,
907            });
908        };
909
910        // Check if this is a method definition (contains ::)
911        if name.contains("::") {
912            return self.parse_method_definition_body(name, true); // true = function
913        }
914
915        // Parse parameters and keywords
916        let mut params = Vec::new();
917        let mut keywords = Vec::new();
918
919        // Check if there's an opening paren or comma after the function name
920        let has_paren = self.check(&Token::LeftParen);
921        if has_paren {
922            self.advance(); // consume '('
923        }
924
925        // Check if there's a comma (for comma-separated params without parens)
926        if has_paren || self.check(&Token::Comma) {
927            if self.check(&Token::Comma) {
928                self.advance(); // consume first comma
929            }
930
931            // Parse comma-separated parameters and keywords
932            loop {
933                // Check if we've reached the end of the parameter list
934                if has_paren && self.check(&Token::RightParen) {
935                    self.advance(); // consume ')'
936                    break;
937                }
938                if !has_paren && matches!(self.peek(), Token::Newline | Token::EOF) {
939                    break;
940                }
941
942                // Get the parameter/keyword name
943                let param_name = if let Token::Identifier(name) = self.peek() {
944                    name.clone()
945                } else {
946                    break; // No more parameters
947                };
948
949                self.advance(); // consume identifier
950
951                // Check if this is a keyword (has '=' after it)
952                if self.check(&Token::Assign) {
953                    self.advance(); // consume '='
954                    keywords.push(KeywordDecl {
955                        name: param_name,
956                        by_reference: false,
957                        location: Location::unknown(),
958                    });
959                } else {
960                    // Regular parameter
961                    params.push(Parameter {
962                        name: param_name,
963                        by_reference: false,
964                        optional: false,
965                        location: Location::unknown(),
966                    });
967                }
968
969                // Check for next comma
970                if !self.check(&Token::Comma) {
971                    if has_paren && self.check(&Token::RightParen) {
972                        self.advance(); // consume ')'
973                    }
974                    break;
975                }
976                self.advance(); // consume comma
977            }
978        }
979
980        // Consume any remaining tokens until we hit a newline or start of body
981        while matches!(self.peek(), Token::Comma | Token::Newline) {
982            self.advance();
983        }
984
985        // Parse body
986        let mut body = Vec::new();
987        // Accept both ENDFUNCTION and END as function terminators (IDL compatibility)
988        loop {
989            // Skip newlines before checking for terminator
990            while matches!(self.peek(), Token::Newline) {
991                self.advance();
992            }
993            if matches!(self.peek(), Token::Endfunction | Token::End | Token::EOF) {
994                break;
995            }
996            body.push(self.parse_statement()?);
997        }
998
999        // Consume either ENDFUNCTION or END
1000        if !matches!(self.peek(), Token::Endfunction | Token::End) {
1001            return Err(XdlError::ParseError {
1002                message: "Expected 'END' or 'ENDFUNCTION' to close function".to_string(),
1003                line: 1,
1004                column: self.current,
1005            });
1006        }
1007        self.advance(); // consume ENDFUNCTION or END
1008
1009        Ok(Statement::FunctionDef {
1010            name,
1011            params,
1012            keywords,
1013            body,
1014            location: Location::unknown(),
1015        })
1016    }
1017
1018    /// Parse class definition body (PRO ClassName__define)
1019    fn parse_class_definition_body(&mut self, full_name: String) -> XdlResult<Statement> {
1020        // Extract class name by removing __define suffix
1021        let class_name = full_name.trim_end_matches("__define").to_string();
1022
1023        // Skip parameters/keywords if any (usually class definitions don't have params)
1024        while matches!(self.peek(), Token::Comma) {
1025            self.advance();
1026            if matches!(self.peek(), Token::Identifier(_)) {
1027                self.advance(); // skip parameter
1028            }
1029        }
1030
1031        // Skip until newline
1032        while matches!(self.peek(), Token::Comma | Token::Newline) {
1033            self.advance();
1034        }
1035
1036        // Parse body until ENDPRO
1037        let mut body = Vec::new();
1038        while !matches!(self.peek(), Token::Endpro | Token::EOF) {
1039            body.push(self.parse_statement()?);
1040        }
1041
1042        self.consume(Token::Endpro, "Expected 'endpro' to close class definition")?;
1043
1044        Ok(Statement::ClassDefinition {
1045            name: class_name,
1046            body,
1047            location: Location::unknown(),
1048        })
1049    }
1050
1051    /// Parse method definition body (PRO/FUNCTION ClassName::MethodName)
1052    fn parse_method_definition_body(
1053        &mut self,
1054        full_name: String,
1055        is_function: bool,
1056    ) -> XdlResult<Statement> {
1057        // Split on :: to get class name and method name
1058        let parts: Vec<&str> = full_name.split("::").collect();
1059        if parts.len() != 2 {
1060            return Err(XdlError::ParseError {
1061                message: format!(
1062                    "Invalid method name format '{}'. Expected ClassName::MethodName",
1063                    full_name
1064                ),
1065                line: 1,
1066                column: self.current,
1067            });
1068        }
1069
1070        let class_name = parts[0].to_string();
1071        let method_name = parts[1].to_string();
1072
1073        // Parse parameters and keywords (same as regular procedure/function)
1074        let mut params = Vec::new();
1075        let mut keywords = Vec::new();
1076
1077        if self.check(&Token::Comma) {
1078            self.advance(); // consume first comma
1079
1080            loop {
1081                if matches!(self.peek(), Token::Newline | Token::EOF) {
1082                    break;
1083                }
1084
1085                let param_name = if let Token::Identifier(name) = self.peek() {
1086                    name.clone()
1087                } else {
1088                    break;
1089                };
1090
1091                self.advance();
1092
1093                if self.check(&Token::Assign) {
1094                    self.advance(); // consume '='
1095                    keywords.push(KeywordDecl {
1096                        name: param_name,
1097                        by_reference: false,
1098                        location: Location::unknown(),
1099                    });
1100                } else {
1101                    params.push(Parameter {
1102                        name: param_name,
1103                        by_reference: false,
1104                        optional: false,
1105                        location: Location::unknown(),
1106                    });
1107                }
1108
1109                if !self.check(&Token::Comma) {
1110                    break;
1111                }
1112                self.advance();
1113            }
1114        }
1115
1116        // Skip remaining tokens until body
1117        while matches!(self.peek(), Token::Comma | Token::Newline) {
1118            self.advance();
1119        }
1120
1121        // Parse body
1122        let mut body = Vec::new();
1123
1124        while !self.is_at_end() {
1125            // Check for end token
1126            if is_function && self.check(&Token::Endfunction) {
1127                break;
1128            }
1129            if !is_function && self.check(&Token::Endpro) {
1130                break;
1131            }
1132
1133            body.push(self.parse_statement()?);
1134        }
1135
1136        // Consume the appropriate end token
1137        if is_function {
1138            self.consume(
1139                Token::Endfunction,
1140                "Expected 'endfunction' to close method definition",
1141            )?;
1142        } else {
1143            self.consume(
1144                Token::Endpro,
1145                "Expected 'endpro' to close method definition",
1146            )?;
1147        }
1148
1149        Ok(Statement::MethodDefinition {
1150            class_name,
1151            method_name,
1152            is_function,
1153            params,
1154            keywords,
1155            body,
1156            location: Location::unknown(),
1157        })
1158    }
1159
1160    /// Parse expression with precedence
1161    fn parse_expression(&mut self) -> XdlResult<Expression> {
1162        self.parse_ternary()
1163    }
1164
1165    /// Parse ternary operator (condition ? if_true : if_false)
1166    fn parse_ternary(&mut self) -> XdlResult<Expression> {
1167        let condition = self.parse_logical_or()?;
1168
1169        // Check for ternary operator
1170        if self.check(&Token::QuestionMark) {
1171            self.advance(); // consume '?'
1172            let if_true = self.parse_expression()?;
1173            self.consume(Token::Colon, "Expected ':' in ternary expression")?;
1174            let if_false = self.parse_expression()?;
1175
1176            Ok(Expression::Ternary {
1177                condition: Box::new(condition),
1178                if_true: Box::new(if_true),
1179                if_false: Box::new(if_false),
1180                location: Location::unknown(),
1181            })
1182        } else {
1183            Ok(condition)
1184        }
1185    }
1186
1187    /// Parse logical OR expressions
1188    fn parse_logical_or(&mut self) -> XdlResult<Expression> {
1189        let mut expr = self.parse_logical_and()?;
1190
1191        while self.check(&Token::Or) {
1192            self.advance();
1193            let right = self.parse_logical_and()?;
1194            expr = Expression::Binary {
1195                op: BinaryOp::Or,
1196                left: Box::new(expr),
1197                right: Box::new(right),
1198                location: Location::unknown(),
1199            };
1200        }
1201
1202        Ok(expr)
1203    }
1204
1205    /// Parse logical AND expressions
1206    fn parse_logical_and(&mut self) -> XdlResult<Expression> {
1207        let mut expr = self.parse_equality()?;
1208
1209        while self.check(&Token::And) {
1210            self.advance();
1211            let right = self.parse_equality()?;
1212            expr = Expression::Binary {
1213                op: BinaryOp::And,
1214                left: Box::new(expr),
1215                right: Box::new(right),
1216                location: Location::unknown(),
1217            };
1218        }
1219
1220        Ok(expr)
1221    }
1222
1223    /// Parse equality expressions (EQ, NE)
1224    fn parse_equality(&mut self) -> XdlResult<Expression> {
1225        let mut expr = self.parse_comparison()?;
1226
1227        loop {
1228            let op = match self.peek() {
1229                Token::Equal => BinaryOp::Equal,
1230                Token::NotEqual => BinaryOp::NotEqual,
1231                _ => break,
1232            };
1233
1234            self.advance();
1235            let right = self.parse_comparison()?;
1236            expr = Expression::Binary {
1237                op,
1238                left: Box::new(expr),
1239                right: Box::new(right),
1240                location: Location::unknown(),
1241            };
1242        }
1243
1244        Ok(expr)
1245    }
1246
1247    /// Parse comparison expressions (LT, GT, LE, GE)
1248    fn parse_comparison(&mut self) -> XdlResult<Expression> {
1249        let mut expr = self.parse_addition()?;
1250
1251        loop {
1252            let op = match self.peek() {
1253                Token::Less => BinaryOp::Less,
1254                Token::Greater => BinaryOp::Greater,
1255                Token::LessEqual => BinaryOp::LessEqual,
1256                Token::GreaterEqual => BinaryOp::GreaterEqual,
1257                _ => break,
1258            };
1259
1260            self.advance();
1261            let right = self.parse_addition()?;
1262            expr = Expression::Binary {
1263                op,
1264                left: Box::new(expr),
1265                right: Box::new(right),
1266                location: Location::unknown(),
1267            };
1268        }
1269
1270        Ok(expr)
1271    }
1272
1273    /// Parse addition and subtraction
1274    fn parse_addition(&mut self) -> XdlResult<Expression> {
1275        let mut expr = self.parse_multiplication()?;
1276
1277        loop {
1278            let op = match self.peek() {
1279                Token::Plus => BinaryOp::Add,
1280                Token::Minus => BinaryOp::Subtract,
1281                _ => break,
1282            };
1283
1284            self.advance();
1285            let right = self.parse_multiplication()?;
1286            expr = Expression::Binary {
1287                op,
1288                left: Box::new(expr),
1289                right: Box::new(right),
1290                location: Location::unknown(),
1291            };
1292        }
1293
1294        Ok(expr)
1295    }
1296
1297    /// Parse multiplication, division, and modulo
1298    fn parse_multiplication(&mut self) -> XdlResult<Expression> {
1299        let mut expr = self.parse_power()?;
1300
1301        loop {
1302            let op = match self.peek() {
1303                Token::Multiply => BinaryOp::Multiply,
1304                Token::Divide => BinaryOp::Divide,
1305                Token::Modulo => BinaryOp::Modulo,
1306                Token::MatrixMultiply => BinaryOp::MatrixMultiply,
1307                _ => break,
1308            };
1309
1310            self.advance();
1311            let right = self.parse_power()?;
1312            expr = Expression::Binary {
1313                op,
1314                left: Box::new(expr),
1315                right: Box::new(right),
1316                location: Location::unknown(),
1317            };
1318        }
1319
1320        Ok(expr)
1321    }
1322
1323    /// Parse power expressions (right associative)
1324    fn parse_power(&mut self) -> XdlResult<Expression> {
1325        let mut expr = self.parse_unary()?;
1326
1327        if self.check(&Token::Power) {
1328            self.advance();
1329            let right = self.parse_power()?; // Right associative
1330            expr = Expression::Binary {
1331                op: BinaryOp::Power,
1332                left: Box::new(expr),
1333                right: Box::new(right),
1334                location: Location::unknown(),
1335            };
1336        }
1337
1338        Ok(expr)
1339    }
1340
1341    /// Parse unary expressions
1342    fn parse_unary(&mut self) -> XdlResult<Expression> {
1343        match self.peek() {
1344            Token::Not => {
1345                self.advance();
1346                let expr = self.parse_unary()?;
1347                Ok(Expression::Unary {
1348                    op: UnaryOp::Not,
1349                    expr: Box::new(expr),
1350                    location: Location::unknown(),
1351                })
1352            }
1353            Token::Minus => {
1354                self.advance();
1355                let expr = self.parse_unary()?;
1356                Ok(Expression::Unary {
1357                    op: UnaryOp::Minus,
1358                    expr: Box::new(expr),
1359                    location: Location::unknown(),
1360                })
1361            }
1362            Token::Plus => {
1363                self.advance();
1364                let expr = self.parse_unary()?;
1365                Ok(Expression::Unary {
1366                    op: UnaryOp::Plus,
1367                    expr: Box::new(expr),
1368                    location: Location::unknown(),
1369                })
1370            }
1371            _ => self.parse_postfix(),
1372        }
1373    }
1374
1375    /// Parse postfix expressions (array indexing, function calls, etc.)
1376    fn parse_postfix(&mut self) -> XdlResult<Expression> {
1377        let mut expr = self.parse_primary()?;
1378
1379        // Handle postfix operations like array indexing, method calls, and field access
1380        loop {
1381            if self.check(&Token::LeftBracket) {
1382                // Array indexing: expr[index]
1383                self.advance(); // consume '['
1384                let indices = self.parse_array_indices()?;
1385                self.consume(Token::RightBracket, "Expected ']' after array indices")?;
1386
1387                expr = Expression::ArrayRef {
1388                    array: Box::new(expr),
1389                    indices,
1390                    location: Location::unknown(),
1391                };
1392            } else if self.check(&Token::Arrow) {
1393                // Method call: expr->method(args)
1394                self.advance(); // consume '->'
1395
1396                // Get method name
1397                let method = match self.advance() {
1398                    Token::Identifier(name) => name.clone(),
1399                    _ => {
1400                        return Err(XdlError::ParseError {
1401                            message: "Expected method name after '->'".to_string(),
1402                            line: 1, // TODO: track line numbers
1403                            column: self.current,
1404                        });
1405                    }
1406                };
1407
1408                // Check if method has arguments
1409                if self.check(&Token::LeftParen) {
1410                    self.advance(); // consume '('
1411                    let mut args = Vec::new();
1412
1413                    if !self.check(&Token::RightParen) {
1414                        loop {
1415                            args.push(self.parse_expression()?);
1416                            if self.check(&Token::Comma) {
1417                                self.advance();
1418                            } else {
1419                                break;
1420                            }
1421                        }
1422                    }
1423
1424                    self.consume(Token::RightParen, "Expected ')' after method arguments")?;
1425
1426                    expr = Expression::MethodCall {
1427                        object: Box::new(expr),
1428                        method,
1429                        args,
1430                        keywords: Vec::new(), // TODO: implement keyword arguments
1431                        location: Location::unknown(),
1432                    };
1433                } else {
1434                    // Method call without parentheses (treat as property access that returns a value)
1435                    expr = Expression::MethodCall {
1436                        object: Box::new(expr),
1437                        method,
1438                        args: vec![],
1439                        keywords: vec![],
1440                        location: Location::unknown(),
1441                    };
1442                }
1443            } else if self.check(&Token::Dot) {
1444                // Struct field access: expr.field
1445                self.advance(); // consume '.'
1446
1447                // Get field name
1448                let field = match self.advance() {
1449                    Token::Identifier(name) => name.clone(),
1450                    _ => {
1451                        return Err(XdlError::ParseError {
1452                            message: "Expected field name after '.'".to_string(),
1453                            line: 1, // TODO: track line numbers
1454                            column: self.current,
1455                        });
1456                    }
1457                };
1458
1459                expr = Expression::StructRef {
1460                    object: Box::new(expr),
1461                    field,
1462                    location: Location::unknown(),
1463                };
1464            } else {
1465                break;
1466            }
1467        }
1468
1469        Ok(expr)
1470    }
1471
1472    /// Parse array indices (single index or range)
1473    fn parse_array_indices(&mut self) -> XdlResult<Vec<ArrayIndex>> {
1474        let mut indices = Vec::new();
1475
1476        loop {
1477            // Check for wildcard * (means all elements)
1478            if self.check(&Token::Multiply) {
1479                self.advance(); // consume '*'
1480                indices.push(ArrayIndex::All);
1481            } else if self.check(&Token::Colon) {
1482                // Range with leading colon (e.g., [:5])
1483                self.advance(); // consume ':'
1484
1485                // Check for * wildcard as end
1486                let end = if self.check(&Token::Multiply) {
1487                    self.advance(); // consume '*'
1488                    None // * means "to end"
1489                } else if self.check(&Token::RightBracket)
1490                    || self.check(&Token::Comma)
1491                    || self.check(&Token::Colon)
1492                {
1493                    None
1494                } else {
1495                    Some(self.parse_expression()?)
1496                };
1497
1498                // Check for step (e.g., [:*:2] or [:10:2])
1499                let step = if self.check(&Token::Colon) {
1500                    self.advance();
1501                    if self.check(&Token::RightBracket) || self.check(&Token::Comma) {
1502                        None
1503                    } else {
1504                        Some(self.parse_expression()?)
1505                    }
1506                } else {
1507                    None
1508                };
1509
1510                indices.push(ArrayIndex::Range {
1511                    start: None,
1512                    end: end.map(Box::new),
1513                    step: step.map(Box::new),
1514                });
1515            } else {
1516                // Parse first expression
1517                let first_expr = self.parse_expression()?;
1518
1519                // Check if this is a range
1520                if self.check(&Token::Colon) {
1521                    self.advance(); // consume ':'
1522
1523                    // Check for * wildcard as end
1524                    let end = if self.check(&Token::Multiply) {
1525                        self.advance(); // consume '*'
1526                        None // * means "to end"
1527                    } else if self.check(&Token::RightBracket)
1528                        || self.check(&Token::Comma)
1529                        || self.check(&Token::Colon)
1530                    {
1531                        None
1532                    } else {
1533                        Some(self.parse_expression()?)
1534                    };
1535
1536                    // Check for step (e.g., 0:*:2 or 0:10:2)
1537                    let step = if self.check(&Token::Colon) {
1538                        self.advance();
1539                        if self.check(&Token::RightBracket) || self.check(&Token::Comma) {
1540                            None
1541                        } else {
1542                            Some(self.parse_expression()?)
1543                        }
1544                    } else {
1545                        None
1546                    };
1547
1548                    indices.push(ArrayIndex::Range {
1549                        start: Some(Box::new(first_expr)),
1550                        end: end.map(Box::new),
1551                        step: step.map(Box::new),
1552                    });
1553                } else {
1554                    // Single index
1555                    indices.push(ArrayIndex::Single(Box::new(first_expr)));
1556                }
1557            }
1558
1559            // Check for multiple dimensions (e.g., arr[i, j])
1560            if self.check(&Token::Comma) {
1561                self.advance();
1562            } else {
1563                break;
1564            }
1565        }
1566
1567        Ok(indices)
1568    }
1569
1570    /// Parse primary expressions (literals, identifiers, parenthesized expressions)
1571    fn parse_primary(&mut self) -> XdlResult<Expression> {
1572        match self.advance() {
1573            Token::Integer(value) => Ok(Expression::Literal {
1574                value: XdlValue::Long(*value as i32),
1575                location: Location::unknown(),
1576            }),
1577            Token::Float(value) => Ok(Expression::Literal {
1578                value: XdlValue::Double(*value),
1579                location: Location::unknown(),
1580            }),
1581            Token::String(value) => Ok(Expression::Literal {
1582                value: XdlValue::String(value.clone()),
1583                location: Location::unknown(),
1584            }),
1585            Token::Identifier(name) => {
1586                let name = name.clone();
1587                // Check if this is a function call
1588                if self.check(&Token::LeftParen) {
1589                    self.advance(); // consume '('
1590                    let mut args = Vec::new();
1591                    let mut keywords = Vec::new();
1592
1593                    if !self.check(&Token::RightParen) {
1594                        loop {
1595                            // Check for /FLAG keyword (e.g., /INDEX)
1596                            if self.check(&Token::Divide) {
1597                                self.advance(); // consume '/'
1598                                if let Token::Identifier(kw_name) = self.peek() {
1599                                    let kw_name = kw_name.clone();
1600                                    self.advance(); // consume keyword name
1601                                    keywords.push(Keyword {
1602                                        name: kw_name,
1603                                        value: Some(Expression::Literal {
1604                                            value: XdlValue::Long(1),
1605                                            location: Location::unknown(),
1606                                        }),
1607                                        location: Location::unknown(),
1608                                    });
1609                                    if self.check(&Token::Comma) {
1610                                        self.advance();
1611                                        continue;
1612                                    } else {
1613                                        break;
1614                                    }
1615                                }
1616                            }
1617
1618                            // Check for keyword argument (identifier = expression)
1619                            if let Token::Identifier(kw_name) = self.peek() {
1620                                let kw_name_clone = kw_name.clone();
1621                                let next_pos = self.current + 1;
1622
1623                                if next_pos < self.tokens.len()
1624                                    && matches!(self.tokens[next_pos], Token::Assign)
1625                                {
1626                                    // This is a keyword argument
1627                                    self.advance(); // consume identifier
1628                                    self.advance(); // consume '='
1629                                    let value = self.parse_expression()?;
1630                                    keywords.push(Keyword {
1631                                        name: kw_name_clone,
1632                                        value: Some(value),
1633                                        location: Location::unknown(),
1634                                    });
1635                                    if self.check(&Token::Comma) {
1636                                        self.advance();
1637                                        continue;
1638                                    } else {
1639                                        break;
1640                                    }
1641                                }
1642                            }
1643
1644                            // Regular positional argument
1645                            args.push(self.parse_expression()?);
1646                            if self.check(&Token::Comma) {
1647                                self.advance();
1648                            } else {
1649                                break;
1650                            }
1651                        }
1652                    }
1653
1654                    self.consume(Token::RightParen, "Expected ')' after function arguments")?;
1655
1656                    // Check if this is OBJ_NEW
1657                    if name.to_uppercase() == "OBJ_NEW" {
1658                        // First argument should be the class name (string literal)
1659                        let class_name = if !args.is_empty() {
1660                            match &args[0] {
1661                                Expression::Literal {
1662                                    value: XdlValue::String(s),
1663                                    ..
1664                                } => s.clone(),
1665                                _ => {
1666                                    // If not a string literal, we'll handle this at runtime
1667                                    return Err(XdlError::ParseError {
1668                                        message: "OBJ_NEW requires a string literal class name as first argument".to_string(),
1669                                        line: 1,
1670                                        column: self.current,
1671                                    });
1672                                }
1673                            }
1674                        } else {
1675                            // Empty OBJ_NEW() returns NULL object
1676                            String::new()
1677                        };
1678
1679                        // Remaining arguments are constructor arguments
1680                        let constructor_args = if args.len() > 1 {
1681                            args[1..].to_vec()
1682                        } else {
1683                            Vec::new()
1684                        };
1685
1686                        Ok(Expression::ObjectNew {
1687                            class_name,
1688                            args: constructor_args,
1689                            keywords: keywords.clone(), // Pass through keywords
1690                            location: Location::unknown(),
1691                        })
1692                    } else {
1693                        Ok(Expression::FunctionCall {
1694                            name,
1695                            args,
1696                            keywords, // Use parsed keywords
1697                            location: Location::unknown(),
1698                        })
1699                    }
1700                } else {
1701                    Ok(Expression::Variable {
1702                        name,
1703                        location: Location::unknown(),
1704                    })
1705                }
1706            }
1707            Token::SystemVariable(name) => {
1708                let name = name.clone();
1709                Ok(Expression::SystemVariable {
1710                    name,
1711                    location: Location::unknown(),
1712                })
1713            }
1714            Token::LeftParen => {
1715                let expr = self.parse_expression()?;
1716                self.consume(Token::RightParen, "Expected ')' after expression")?;
1717                Ok(expr)
1718            }
1719            Token::LeftBracket => {
1720                // Array definition [1, 2, 3]
1721                let mut elements = Vec::new();
1722
1723                if !self.check(&Token::RightBracket) {
1724                    loop {
1725                        elements.push(self.parse_expression()?);
1726                        if self.check(&Token::Comma) {
1727                            self.advance();
1728                        } else {
1729                            break;
1730                        }
1731                    }
1732                }
1733
1734                self.consume(Token::RightBracket, "Expected ']' after array elements")?;
1735
1736                Ok(Expression::ArrayDef {
1737                    elements,
1738                    location: Location::unknown(),
1739                })
1740            }
1741            token => Err(XdlError::ParseError {
1742                message: format!("Unexpected token: {:?}", token),
1743                line: 1,
1744                column: self.current,
1745            }),
1746        }
1747    }
1748}
1749
1750// Public interface functions
1751pub fn parse_program(tokens: &[Token]) -> XdlResult<Program> {
1752    let mut parser = Parser::new(tokens);
1753    parser.parse_program()
1754}
1755
1756pub fn parse_expression(tokens: &[Token]) -> XdlResult<Expression> {
1757    let mut parser = Parser::new(tokens);
1758    parser.parse_expression()
1759}
1760
1761#[cfg(test)]
1762mod tests {
1763    use super::*;
1764    use crate::lexer::tokenize;
1765
1766    #[test]
1767    fn test_parse_simple_assignment() {
1768        let input = "x = 42";
1769        let tokens = tokenize(input).unwrap();
1770        let program = parse_program(&tokens).unwrap();
1771
1772        assert_eq!(program.statements.len(), 1);
1773        match &program.statements[0] {
1774            Statement::Assignment { target, value, .. } => {
1775                assert!(matches!(target, Expression::Variable { name, .. } if name == "x"));
1776                assert!(matches!(
1777                    value,
1778                    Expression::Literal {
1779                        value: XdlValue::Long(42),
1780                        ..
1781                    }
1782                ));
1783            }
1784            _ => panic!("Expected assignment statement"),
1785        }
1786    }
1787
1788    #[test]
1789    fn test_parse_arithmetic_expression() {
1790        let input = "2 + 3 * 4";
1791        let tokens = tokenize(input).unwrap();
1792        let expr = parse_expression(&tokens).unwrap();
1793
1794        match expr {
1795            Expression::Binary {
1796                op: BinaryOp::Add,
1797                left,
1798                right,
1799                ..
1800            } => {
1801                assert!(matches!(
1802                    left.as_ref(),
1803                    Expression::Literal {
1804                        value: XdlValue::Long(2),
1805                        ..
1806                    }
1807                ));
1808                match right.as_ref() {
1809                    Expression::Binary {
1810                        op: BinaryOp::Multiply,
1811                        ..
1812                    } => {}
1813                    _ => panic!("Expected multiplication on right side"),
1814                }
1815            }
1816            _ => panic!("Expected binary addition expression"),
1817        }
1818    }
1819
1820    #[test]
1821    fn test_parse_function_call() {
1822        let input = "sin(x)";
1823        let tokens = tokenize(input).unwrap();
1824        let expr = parse_expression(&tokens).unwrap();
1825
1826        match expr {
1827            Expression::FunctionCall { name, args, .. } => {
1828                assert_eq!(name, "sin");
1829                assert_eq!(args.len(), 1);
1830                assert!(matches!(args[0], Expression::Variable { name: ref n, .. } if n == "x"));
1831            }
1832            _ => panic!("Expected function call expression"),
1833        }
1834    }
1835
1836    #[test]
1837    fn test_parse_if_statement() {
1838        let input = "if x eq 42 then\n  y = 1\nendif";
1839        let tokens = tokenize(input).unwrap();
1840        let program = parse_program(&tokens).unwrap();
1841
1842        assert_eq!(program.statements.len(), 1);
1843        match &program.statements[0] {
1844            Statement::If {
1845                condition,
1846                then_block,
1847                else_block,
1848                ..
1849            } => {
1850                assert!(matches!(
1851                    condition,
1852                    Expression::Binary {
1853                        op: BinaryOp::Equal,
1854                        ..
1855                    }
1856                ));
1857                assert_eq!(then_block.len(), 1);
1858                assert!(else_block.is_none());
1859            }
1860            _ => panic!("Expected if statement"),
1861        }
1862    }
1863
1864    #[test]
1865    fn test_parse_for_loop() {
1866        let input = "for i = 0, 10\n  x = i\nendfor";
1867        let tokens = tokenize(input).unwrap();
1868        let program = parse_program(&tokens).unwrap();
1869
1870        assert_eq!(program.statements.len(), 1);
1871        match &program.statements[0] {
1872            Statement::For {
1873                variable,
1874                start,
1875                end,
1876                step,
1877                body,
1878                ..
1879            } => {
1880                assert_eq!(variable, "i");
1881                assert!(matches!(
1882                    start,
1883                    Expression::Literal {
1884                        value: XdlValue::Long(0),
1885                        ..
1886                    }
1887                ));
1888                assert!(matches!(
1889                    end,
1890                    Expression::Literal {
1891                        value: XdlValue::Long(10),
1892                        ..
1893                    }
1894                ));
1895                assert!(step.is_none());
1896                assert_eq!(body.len(), 1);
1897            }
1898            _ => panic!("Expected for statement"),
1899        }
1900    }
1901}