Skip to main content

zuzu_rust/
parser.rs

1use crate::ast::{
2    BlockStatement, CallArgument, CatchBinding, CatchClause, ClassDeclaration, ClassMember,
3    DeclarationBindingEntry, DeclarationBindingPattern, DictEntry, DictKey, DieStatement,
4    Expression, ExpressionStatement, FieldDeclaration, ForStatement, FunctionDeclaration,
5    IfStatement, ImportDeclaration, ImportSpecifier, KeywordStatement, LoopControlStatement,
6    MethodDeclaration, Parameter, PostfixCondition, PostfixConditionalStatement, Program,
7    ReturnStatement, Statement, SwitchCase, SwitchStatement, TemplatePart as AstTemplatePart,
8    ThrowStatement, TraitDeclaration, TryStatement, VariableDeclaration, VariableUnpackDeclaration,
9    WhileStatement,
10};
11use crate::error::{Result, ZuzuRustError};
12use crate::token::{TemplatePart as TokenTemplatePart, Token, TokenKind};
13use std::collections::HashSet;
14
15pub struct Parser {
16    tokens: Vec<Token>,
17    index: usize,
18    source_file: Option<String>,
19    // Closers of set literals currently being parsed: ">>" and "»" are
20    // also shift operators, so the innermost pending closer must not be
21    // consumed as an infix operator.
22    pending_set_closers: Vec<&'static str>,
23}
24
25const PREC_ASSIGNMENT: u8 = 1;
26const PREC_CHAIN: u8 = 2;
27const PREC_TERNARY: u8 = 3;
28const PREC_OR: u8 = 4;
29const PREC_ONLYIF: u8 = 5;
30const PREC_XOR: u8 = 6;
31const PREC_AND: u8 = 7;
32const PREC_EQUALITY: u8 = 8;
33const PREC_COMPARISON: u8 = 9;
34const PREC_BITWISE_OR: u8 = 10;
35const PREC_BITWISE_XOR: u8 = 11;
36const PREC_BITWISE_AND: u8 = 12;
37const PREC_SHIFT: u8 = 13;
38const PREC_SET: u8 = 14;
39const PREC_CONCAT: u8 = 15;
40const PREC_ADDITIVE: u8 = 16;
41const PREC_MULTIPLICATIVE: u8 = 17;
42const PREC_EXPONENT: u8 = 18;
43const PREC_PREFIX: u8 = 19;
44
45impl Parser {
46    pub fn new(tokens: Vec<Token>) -> Self {
47        Self {
48            tokens,
49            index: 0,
50            source_file: None,
51            pending_set_closers: Vec::new(),
52        }
53    }
54
55    pub fn with_source_file(tokens: Vec<Token>, source_file: impl Into<String>) -> Self {
56        Self {
57            tokens,
58            index: 0,
59            source_file: Some(source_file.into()),
60            pending_set_closers: Vec::new(),
61        }
62    }
63
64    fn source_file(&self) -> Option<String> {
65        self.source_file.clone()
66    }
67
68    pub fn parse_program(&mut self) -> Result<Program> {
69        let line = self.current_line();
70        let mut statements = Vec::new();
71        while !self.at_eof() {
72            self.consume_semicolons();
73            if self.at_eof() {
74                break;
75            }
76            statements.push(self.parse_statement()?);
77            self.consume_semicolons();
78        }
79        Ok(Program {
80            line,
81            source_file: self.source_file(),
82            statements,
83        })
84    }
85
86    pub fn parse_expression_root(mut self) -> Result<Expression> {
87        let expression = self.parse_expression()?;
88        if !self.at_eof() {
89            return Err(self.error_current("Unexpected token after expression"));
90        }
91        Ok(expression)
92    }
93
94    fn parse_statement(&mut self) -> Result<Statement> {
95        let mut statement = match self.current_kind() {
96            TokenKind::Punct('{') => Statement::Block(self.parse_block_statement()?),
97            TokenKind::Keyword("from") => {
98                Statement::ImportDeclaration(self.parse_import_declaration()?)
99            }
100            TokenKind::Keyword("let") | TokenKind::Keyword("const") => {
101                self.parse_variable_declaration_statement()?
102            }
103            TokenKind::Keyword("function") | TokenKind::Keyword("async") => {
104                Statement::FunctionDeclaration(self.parse_function_declaration()?)
105            }
106            TokenKind::Keyword("class") => {
107                Statement::ClassDeclaration(self.parse_class_declaration()?)
108            }
109            TokenKind::Keyword("trait") => {
110                Statement::TraitDeclaration(self.parse_trait_declaration()?)
111            }
112            TokenKind::Keyword("if") => Statement::IfStatement(self.parse_if_statement()?),
113            TokenKind::Keyword("while") => Statement::WhileStatement(self.parse_while_statement()?),
114            TokenKind::Keyword("for") => Statement::ForStatement(self.parse_for_statement()?),
115            TokenKind::Keyword("switch") => {
116                Statement::SwitchStatement(self.parse_switch_statement()?)
117            }
118            TokenKind::Keyword("try") => Statement::TryStatement(self.parse_try_statement()?),
119            TokenKind::Keyword("return") => {
120                Statement::ReturnStatement(self.parse_return_statement()?)
121            }
122            TokenKind::Keyword("next")
123            | TokenKind::Keyword("continue")
124            | TokenKind::Keyword("last") => {
125                Statement::LoopControlStatement(self.parse_loop_control_statement()?)
126            }
127            TokenKind::Keyword("throw") => Statement::ThrowStatement(self.parse_throw_statement()?),
128            TokenKind::Keyword("die") => Statement::DieStatement(self.parse_die_statement()?),
129            TokenKind::Keyword("say")
130            | TokenKind::Keyword("print")
131            | TokenKind::Keyword("warn")
132            | TokenKind::Keyword("assert")
133            | TokenKind::Keyword("debug") => {
134                Statement::KeywordStatement(self.parse_keyword_statement()?)
135            }
136            _ => Statement::ExpressionStatement(self.parse_expression_statement()?),
137        };
138
139        let needs_separator = statement_needs_separator(&statement);
140        if statement_supports_postfix_condition(&statement) {
141            if self.match_keyword("for") {
142                let iterable = self.parse_expression()?;
143                statement = Statement::ForStatement(ForStatement {
144                    line: statement.line(),
145                    source_file: statement.source_file().map(str::to_owned),
146                    binding_kind: Some("const".to_owned()),
147                    variable: "^^".to_owned(),
148                    iterable,
149                    body: BlockStatement {
150                        line: statement.line(),
151                        source_file: statement.source_file().map(str::to_owned),
152                        statements: vec![statement],
153                        needs_lexical_scope: false,
154                    },
155                    else_block: None,
156                });
157            } else if let Some(keyword) = self.match_postfix_condition_keyword() {
158                let test = self.parse_expression()?;
159                statement = Statement::PostfixConditionalStatement(PostfixConditionalStatement {
160                    line: statement.line(),
161                    source_file: statement.source_file().map(str::to_owned),
162                    statement: Box::new(statement),
163                    keyword,
164                    test,
165                });
166            }
167        }
168
169        if needs_separator {
170            self.expect_statement_separator("Expected ; after simple statement")?;
171        }
172
173        Ok(statement)
174    }
175
176    fn parse_block_statement(&mut self) -> Result<BlockStatement> {
177        let line = self.current_line();
178        self.expect_punct('{', "Expected '{'")?;
179        let mut statements = Vec::new();
180        self.consume_semicolons();
181        while !self.check_punct('}') {
182            statements.push(self.parse_statement()?);
183            self.consume_semicolons();
184        }
185        self.expect_punct('}', "Expected '}' after block")?;
186        Ok(BlockStatement {
187            line,
188            source_file: self.source_file(),
189            statements,
190            needs_lexical_scope: true,
191        })
192    }
193
194    fn empty_block_statement(&self, line: usize) -> BlockStatement {
195        BlockStatement {
196            line,
197            source_file: self.source_file(),
198            statements: Vec::new(),
199            needs_lexical_scope: true,
200        }
201    }
202
203    fn parse_variable_declaration_statement(&mut self) -> Result<Statement> {
204        let line = self.current_line();
205        let kind = self.expect_keyword_any(&["let", "const"])?;
206        if self.check_punct('{') {
207            Ok(Statement::VariableUnpackDeclaration(
208                self.parse_variable_unpack_declaration_after_kind(line, kind)?,
209            ))
210        } else {
211            Ok(Statement::VariableDeclaration(
212                self.parse_variable_declaration_after_kind(line, kind)?,
213            ))
214        }
215    }
216
217    fn parse_variable_declaration_after_kind(
218        &mut self,
219        line: usize,
220        kind: String,
221    ) -> Result<VariableDeclaration> {
222        let (declared_type, name) = self.parse_typed_name()?;
223        let mut is_weak_storage = self.parse_optional_weak_modifier("declaration")?;
224        let init = if self.match_operator(":=") {
225            let init = self.parse_expression()?;
226            is_weak_storage |= self.parse_optional_weak_modifier("declaration")?;
227            Some(init)
228        } else {
229            None
230        };
231        Ok(VariableDeclaration {
232            line,
233            source_file: self.source_file(),
234            kind,
235            declared_type,
236            name,
237            init,
238            is_weak_storage,
239            runtime_typecheck_required: None,
240        })
241    }
242
243    fn parse_variable_unpack_declaration_after_kind(
244        &mut self,
245        line: usize,
246        kind: String,
247    ) -> Result<VariableUnpackDeclaration> {
248        let pattern = self.parse_declaration_binding_pattern()?;
249        self.expect_operator(":=", "Expected ':=' after declaration binding pattern")?;
250        let init = self.parse_expression()?;
251        Ok(VariableUnpackDeclaration {
252            line,
253            source_file: self.source_file(),
254            kind,
255            pattern,
256            init,
257        })
258    }
259
260    fn parse_declaration_binding_pattern(&mut self) -> Result<DeclarationBindingPattern> {
261        let line = self.current_line();
262        self.expect_punct('{', "Expected '{' in declaration binding pattern")?;
263        let mut entries = Vec::new();
264        self.consume_commas();
265        if !self.check_punct('}') {
266            loop {
267                entries.push(self.parse_declaration_binding_entry()?);
268                self.consume_commas();
269                if self.check_punct('}') {
270                    break;
271                }
272                if !self.previous_was_comma() {
273                    break;
274                }
275            }
276        }
277        self.expect_punct('}', "Expected '}' after declaration binding pattern")?;
278        let mut names = HashSet::new();
279        for entry in &entries {
280            if !names.insert(entry.name.clone()) {
281                return Err(ZuzuRustError::semantic(
282                    format!("Duplicate unpacked binding '{}' in declaration", entry.name),
283                    entry.line,
284                ));
285            }
286        }
287        Ok(DeclarationBindingPattern::Keyed {
288            line,
289            source_file: self.source_file(),
290            entries,
291        })
292    }
293
294    fn parse_declaration_binding_entry(&mut self) -> Result<DeclarationBindingEntry> {
295        let line = self.current_line();
296        let source_file = self.source_file();
297        let (key, declared_type, name) = self.parse_declaration_binding_key_and_name()?;
298        let default_value = if self.match_operator(":=") {
299            Some(self.parse_expression()?)
300        } else {
301            None
302        };
303        let is_weak_storage = self.parse_optional_weak_modifier("declaration")?;
304        Ok(DeclarationBindingEntry {
305            line,
306            source_file,
307            key,
308            declared_type,
309            name,
310            default_value,
311            is_weak_storage,
312            runtime_typecheck_required: None,
313        })
314    }
315
316    fn parse_declaration_binding_key_and_name(
317        &mut self,
318    ) -> Result<(DictKey, Option<String>, String)> {
319        match self.current_kind() {
320            TokenKind::Identifier(first) => {
321                let first = first.clone();
322                let key_line = self.current_line();
323                let key_source = self.source_file();
324                self.advance();
325                if self.match_operator(":") {
326                    let (declared_type, name) = self.parse_typed_name()?;
327                    Ok((
328                        DictKey::Identifier {
329                            line: key_line,
330                            source_file: key_source,
331                            name: first,
332                        },
333                        declared_type,
334                        name,
335                    ))
336                } else if self.check_identifier() {
337                    let name = self.expect_name("Expected identifier")?;
338                    Ok((
339                        DictKey::Identifier {
340                            line: self.previous_line(),
341                            source_file: self.source_file(),
342                            name: name.clone(),
343                        },
344                        Some(first),
345                        name,
346                    ))
347                } else {
348                    Ok((
349                        DictKey::Identifier {
350                            line: key_line,
351                            source_file: key_source,
352                            name: first.clone(),
353                        },
354                        None,
355                        first,
356                    ))
357                }
358            }
359            TokenKind::Keyword(_) => {
360                let key = self.parse_dict_key_before_colon()?;
361                self.expect_operator(":", "Expected ':' after declaration binding key")?;
362                let (declared_type, name) = self.parse_typed_name()?;
363                Ok((key, declared_type, name))
364            }
365            TokenKind::String(_) => {
366                let key = self.parse_dict_key_before_colon()?;
367                self.expect_operator(":", "Expected ':' after declaration binding key")?;
368                let (declared_type, name) = self.parse_typed_name()?;
369                Ok((key, declared_type, name))
370            }
371            TokenKind::Template(_) => {
372                let expression = self.parse_primary_expression()?;
373                let line = expression.line();
374                let source_file = expression.source_file().map(str::to_owned);
375                self.expect_operator(":", "Expected ':' after declaration binding key")?;
376                let (declared_type, name) = self.parse_typed_name()?;
377                Ok((
378                    DictKey::Expression {
379                        line,
380                        source_file,
381                        expression: Box::new(expression),
382                    },
383                    declared_type,
384                    name,
385                ))
386            }
387            TokenKind::Punct('(') => {
388                let key = self.parse_dict_key_before_colon()?;
389                self.expect_operator(":", "Expected ':' after declaration binding key")?;
390                let (declared_type, name) = self.parse_typed_name()?;
391                Ok((key, declared_type, name))
392            }
393            _ => Err(self.error_current("Expected unpacked binding in declaration")),
394        }
395    }
396
397    fn parse_function_declaration(&mut self) -> Result<FunctionDeclaration> {
398        let line = self.current_line();
399        let is_async = self.match_keyword("async");
400        self.expect_keyword("function")?;
401        let name = self.expect_name("Expected function name")?;
402        if self.match_punct(';') {
403            return Ok(FunctionDeclaration {
404                line,
405                source_file: self.source_file(),
406                name,
407                params: Vec::new(),
408                return_type: None,
409                body: self.empty_block_statement(line),
410                is_async,
411                is_predeclared: true,
412            });
413        }
414        let params = self.parse_parameter_list()?;
415        let return_type = self.parse_optional_return_type()?;
416        let body = self.parse_block_statement()?;
417        Ok(FunctionDeclaration {
418            line,
419            source_file: self.source_file(),
420            name,
421            params,
422            return_type,
423            body,
424            is_async,
425            is_predeclared: false,
426        })
427    }
428
429    fn parse_class_declaration(&mut self) -> Result<ClassDeclaration> {
430        let line = self.current_line();
431        self.expect_keyword("class")?;
432        let name = self.expect_identifier("Expected class name")?;
433        let base = if self.match_keyword("extends") {
434            Some(self.expect_identifier("Expected base class name after extends")?)
435        } else {
436            None
437        };
438        let traits = self.parse_trait_composition_list()?;
439        if self.match_punct(';') {
440            return Ok(ClassDeclaration {
441                line,
442                source_file: self.source_file(),
443                name,
444                base,
445                traits,
446                body: Vec::new(),
447                shorthand: true,
448            });
449        }
450
451        self.expect_punct('{', "Expected '{' to start class body")?;
452        let mut body = Vec::new();
453        self.consume_semicolons();
454        while !self.check_punct('}') {
455            body.push(self.parse_class_member()?);
456            self.consume_semicolons();
457        }
458        self.expect_punct('}', "Expected '}' after class body")?;
459        Ok(ClassDeclaration {
460            line,
461            source_file: self.source_file(),
462            name,
463            base,
464            traits,
465            body,
466            shorthand: false,
467        })
468    }
469
470    fn parse_trait_declaration(&mut self) -> Result<TraitDeclaration> {
471        let line = self.current_line();
472        self.expect_keyword("trait")?;
473        let name = self.expect_identifier("Expected trait name")?;
474        if self.match_punct(';') {
475            return Ok(TraitDeclaration {
476                line,
477                source_file: self.source_file(),
478                name,
479                body: Vec::new(),
480                shorthand: true,
481            });
482        }
483        self.expect_punct('{', "Expected '{' to start trait body")?;
484        let mut body = Vec::new();
485        self.consume_semicolons();
486        while !self.check_punct('}') {
487            body.push(self.parse_trait_member()?);
488            self.consume_semicolons();
489        }
490        self.expect_punct('}', "Expected '}' after trait body")?;
491        Ok(TraitDeclaration {
492            line,
493            source_file: self.source_file(),
494            name,
495            body,
496            shorthand: false,
497        })
498    }
499
500    fn parse_class_member(&mut self) -> Result<ClassMember> {
501        match self.current_kind() {
502            TokenKind::Keyword("static")
503            | TokenKind::Keyword("async")
504            | TokenKind::Keyword("method") => {
505                Ok(ClassMember::Method(self.parse_method_declaration(true)?))
506            }
507            TokenKind::Keyword("let") | TokenKind::Keyword("const") => {
508                Ok(ClassMember::Field(self.parse_field_declaration()?))
509            }
510            TokenKind::Keyword("class") => Ok(ClassMember::Class(self.parse_class_declaration()?)),
511            TokenKind::Keyword("trait") => Ok(ClassMember::Trait(self.parse_trait_declaration()?)),
512            _ => Err(self.error_current("Unsupported class member")),
513        }
514    }
515
516    fn parse_trait_member(&mut self) -> Result<ClassMember> {
517        match self.current_kind() {
518            TokenKind::Keyword("async") | TokenKind::Keyword("method") => {
519                Ok(ClassMember::Method(self.parse_method_declaration(false)?))
520            }
521            TokenKind::Keyword("class") => Ok(ClassMember::Class(self.parse_class_declaration()?)),
522            TokenKind::Keyword("trait") => Ok(ClassMember::Trait(self.parse_trait_declaration()?)),
523            _ => Err(self.error_current("Unsupported trait member")),
524        }
525    }
526
527    fn parse_method_declaration(&mut self, allow_static: bool) -> Result<MethodDeclaration> {
528        let line = self.current_line();
529        let mut is_static = false;
530        let mut is_async = false;
531        while self.check_keyword("static") || self.check_keyword("async") {
532            if self.match_keyword("static") {
533                if !allow_static {
534                    return Err(self.error_current("static methods are not allowed here"));
535                }
536                if is_static {
537                    return Err(self.error_current("Duplicate static method modifier"));
538                }
539                is_static = true;
540                continue;
541            }
542            if self.match_keyword("async") {
543                if is_async {
544                    return Err(self.error_current("Duplicate async method modifier"));
545                }
546                is_async = true;
547            }
548        }
549        self.expect_keyword("method")?;
550        let name = self.expect_name("Expected method name")?;
551        if self.match_punct(';') {
552            return Ok(MethodDeclaration {
553                line,
554                source_file: self.source_file(),
555                name,
556                params: Vec::new(),
557                return_type: None,
558                body: self.empty_block_statement(line),
559                is_static,
560                is_async,
561                is_predeclared: true,
562            });
563        }
564        let params = self.parse_parameter_list()?;
565        let return_type = self.parse_optional_return_type()?;
566        let body = self.parse_block_statement()?;
567        Ok(MethodDeclaration {
568            line,
569            source_file: self.source_file(),
570            name,
571            params,
572            return_type,
573            body,
574            is_static,
575            is_async,
576            is_predeclared: false,
577        })
578    }
579
580    fn parse_field_declaration(&mut self) -> Result<FieldDeclaration> {
581        let line = self.current_line();
582        let kind = self.expect_keyword_any(&["let", "const"])?;
583        let (declared_type, name) = self.parse_typed_name()?;
584        let mut accessors = Vec::new();
585        if self.match_keyword("with") {
586            loop {
587                accessors.push(self.expect_name("Expected accessor name")?);
588                if !self.match_punct(',') {
589                    break;
590                }
591            }
592        }
593        let mut is_weak_storage = self.parse_optional_weak_modifier("field declaration")?;
594        let default_value = if self.match_operator(":=") {
595            let value = self.parse_expression()?;
596            is_weak_storage |= self.parse_optional_weak_modifier("field declaration")?;
597            Some(value)
598        } else {
599            None
600        };
601        Ok(FieldDeclaration {
602            line,
603            source_file: self.source_file(),
604            kind,
605            declared_type,
606            name,
607            accessors,
608            default_value,
609            is_weak_storage,
610            runtime_typecheck_required: None,
611        })
612    }
613
614    fn parse_import_declaration(&mut self) -> Result<ImportDeclaration> {
615        let line = self.current_line();
616        self.expect_keyword("from")?;
617        let mut source = String::new();
618        while !self.check_keyword("import") && !self.check_keyword("try") {
619            source.push_str(&self.current_text());
620            self.advance();
621        }
622        let try_mode = self.match_keyword("try");
623        self.expect_keyword("import")?;
624        let mut specifiers = Vec::new();
625        let import_all = if self.match_operator("*") {
626            true
627        } else {
628            loop {
629                let spec_line = self.current_line();
630                let imported = self.expect_identifier("Expected imported name")?;
631                let local = if self.match_keyword("as") {
632                    self.expect_identifier("Expected alias name after as")?
633                } else {
634                    imported.clone()
635                };
636                specifiers.push(ImportSpecifier {
637                    line: spec_line,
638                    source_file: self.source_file(),
639                    imported,
640                    local,
641                });
642                if !self.match_punct(',') {
643                    break;
644                }
645            }
646            false
647        };
648        let condition = if let Some(keyword) = self.match_postfix_condition_keyword() {
649            Some(PostfixCondition {
650                line: self.current_line(),
651                source_file: self.source_file(),
652                keyword,
653                test: self.parse_expression()?,
654            })
655        } else {
656            None
657        };
658        Ok(ImportDeclaration {
659            line,
660            source_file: self.source_file(),
661            source,
662            try_mode,
663            import_all,
664            specifiers,
665            condition,
666        })
667    }
668
669    fn parse_if_statement(&mut self) -> Result<IfStatement> {
670        let line = self.current_line();
671        self.expect_keyword("if")?;
672        let test = self.parse_parenthesized_expression()?;
673        let consequent = self.parse_block_statement()?;
674        let alternate = if self.match_keyword("else") {
675            if self.check_keyword("if") {
676                Some(Box::new(Statement::IfStatement(self.parse_if_statement()?)))
677            } else {
678                Some(Box::new(Statement::Block(self.parse_block_statement()?)))
679            }
680        } else {
681            None
682        };
683        Ok(IfStatement {
684            line,
685            source_file: self.source_file(),
686            test,
687            consequent,
688            alternate,
689        })
690    }
691
692    fn parse_while_statement(&mut self) -> Result<WhileStatement> {
693        let line = self.current_line();
694        self.expect_keyword("while")?;
695        let test = self.parse_parenthesized_expression()?;
696        let body = self.parse_block_statement()?;
697        Ok(WhileStatement {
698            line,
699            source_file: self.source_file(),
700            test,
701            body,
702        })
703    }
704
705    fn parse_for_statement(&mut self) -> Result<ForStatement> {
706        let line = self.current_line();
707        self.expect_keyword("for")?;
708        self.expect_punct('(', "Expected '(' after for")?;
709        let (binding_kind, variable, iterable) = if self.match_keyword("let") {
710            let variable = self.expect_identifier("Expected loop variable")?;
711            self.expect_keyword("in")?;
712            (Some("let".to_owned()), variable, self.parse_expression()?)
713        } else if self.match_keyword("const") {
714            let variable = self.expect_identifier("Expected loop variable")?;
715            self.expect_keyword("in")?;
716            (Some("const".to_owned()), variable, self.parse_expression()?)
717        } else if self.check_identifier() && self.peek_keyword("in") {
718            let variable = self.expect_identifier("Expected loop variable")?;
719            self.expect_keyword("in")?;
720            (None, variable, self.parse_expression()?)
721        } else {
722            (
723                Some("const".to_owned()),
724                "^^".to_owned(),
725                self.parse_expression()?,
726            )
727        };
728        self.expect_punct(')', "Expected ')' after for header")?;
729        let body = self.parse_block_statement()?;
730        let else_block = if self.match_keyword("else") {
731            Some(self.parse_block_statement()?)
732        } else {
733            None
734        };
735        Ok(ForStatement {
736            line,
737            source_file: self.source_file(),
738            binding_kind,
739            variable,
740            iterable,
741            body,
742            else_block,
743        })
744    }
745
746    fn parse_switch_statement(&mut self) -> Result<SwitchStatement> {
747        let line = self.current_line();
748        self.expect_keyword("switch")?;
749        self.expect_punct('(', "Expected '(' after switch")?;
750        let discriminant = self.parse_expression()?;
751        let comparator = if self.match_operator(":") {
752            Some(self.expect_switch_comparator_text("Expected switch comparator operator")?)
753        } else {
754            None
755        };
756        self.expect_punct(')', "Expected ')' after switch header")?;
757        self.expect_punct('{', "Expected '{' before switch body")?;
758        let mut cases = Vec::new();
759        let mut default = None;
760        self.consume_semicolons();
761        while !self.check_punct('}') {
762            if self.match_keyword("case") {
763                let case_line = self.previous_line();
764                let (operator, value) = self.parse_switch_case_value()?;
765                let mut values = vec![value];
766                let mut operators = vec![operator];
767                while self.match_punct(',') {
768                    let (operator, value) = self.parse_switch_case_value()?;
769                    values.push(value);
770                    operators.push(operator);
771                }
772                self.expect_operator(":", "Expected ':' after case values")?;
773                let consequent = self.parse_switch_consequent()?;
774                cases.push(SwitchCase {
775                    line: case_line,
776                    source_file: self.source_file(),
777                    values,
778                    operators,
779                    consequent,
780                });
781            } else if self.match_keyword("default") {
782                self.expect_operator(":", "Expected ':' after default")?;
783                default = Some(self.parse_switch_consequent()?);
784            } else {
785                return Err(self.error_current("Expected case or default in switch"));
786            }
787            self.consume_semicolons();
788        }
789        self.expect_punct('}', "Expected '}' after switch")?;
790        Ok(SwitchStatement {
791            line,
792            source_file: self.source_file(),
793            discriminant,
794            comparator,
795            cases,
796            default,
797            index: None,
798        })
799    }
800
801    fn parse_switch_case_value(&mut self) -> Result<(Option<String>, Expression)> {
802        let operator = self.match_switch_comparator_text();
803        let value = self.parse_expression()?;
804        Ok((operator, value))
805    }
806
807    fn parse_switch_consequent(&mut self) -> Result<Vec<Statement>> {
808        let mut statements = Vec::new();
809        self.consume_semicolons();
810        while !self.check_keyword("case")
811            && !self.check_keyword("default")
812            && !self.check_punct('}')
813        {
814            statements.push(self.parse_statement()?);
815            self.consume_semicolons();
816        }
817        Ok(statements)
818    }
819
820    fn parse_try_statement(&mut self) -> Result<TryStatement> {
821        let line = self.current_line();
822        self.expect_keyword("try")?;
823        let body = self.parse_block_statement()?;
824        let mut handlers = Vec::new();
825        while self.match_keyword("catch") {
826            handlers.push(self.parse_catch_clause()?);
827        }
828        if handlers.is_empty() {
829            return Err(self.error_current("Expected at least one catch block"));
830        }
831        Ok(TryStatement {
832            line,
833            source_file: self.source_file(),
834            body,
835            handlers,
836        })
837    }
838
839    fn parse_catch_clause(&mut self) -> Result<CatchClause> {
840        let line = self.previous_line();
841        let binding = if self.match_punct('(') {
842            let binding = if self.match_punct(')') {
843                None
844            } else {
845                let first = self.expect_identifier("Expected catch binding")?;
846                let binding = if self.check_identifier() {
847                    let name = self.expect_identifier("Expected catch variable name")?;
848                    CatchBinding {
849                        line,
850                        source_file: self.source_file(),
851                        declared_type: Some(first),
852                        name: Some(name),
853                    }
854                } else {
855                    CatchBinding {
856                        line,
857                        source_file: self.source_file(),
858                        declared_type: None,
859                        name: Some(first),
860                    }
861                };
862                self.expect_punct(')', "Expected ')' after catch binding")?;
863                Some(binding)
864            };
865            binding
866        } else {
867            None
868        };
869        let body = self.parse_block_statement()?;
870        Ok(CatchClause {
871            line,
872            source_file: self.source_file(),
873            binding,
874            body,
875        })
876    }
877
878    fn parse_return_statement(&mut self) -> Result<ReturnStatement> {
879        let line = self.current_line();
880        self.expect_keyword("return")?;
881        let argument = if self.statement_terminator_here()
882            || self.check_keyword("if")
883            || self.check_keyword("unless")
884        {
885            None
886        } else {
887            Some(self.parse_expression()?)
888        };
889        Ok(ReturnStatement {
890            line,
891            source_file: self.source_file(),
892            argument,
893            runtime_typecheck_required: None,
894        })
895    }
896
897    fn parse_loop_control_statement(&mut self) -> Result<LoopControlStatement> {
898        let line = self.current_line();
899        let keyword = self.expect_keyword_any(&["next", "continue", "last"])?;
900        Ok(LoopControlStatement {
901            line,
902            source_file: self.source_file(),
903            keyword,
904        })
905    }
906
907    fn parse_throw_statement(&mut self) -> Result<ThrowStatement> {
908        let line = self.current_line();
909        self.expect_keyword("throw")?;
910        let argument = self.parse_expression()?;
911        Ok(ThrowStatement {
912            line,
913            source_file: self.source_file(),
914            argument,
915        })
916    }
917
918    fn parse_die_statement(&mut self) -> Result<DieStatement> {
919        let line = self.current_line();
920        self.expect_keyword("die")?;
921        let argument = self.parse_expression()?;
922        Ok(DieStatement {
923            line,
924            source_file: self.source_file(),
925            argument,
926        })
927    }
928
929    fn parse_keyword_statement(&mut self) -> Result<KeywordStatement> {
930        let line = self.current_line();
931        let keyword = self.expect_keyword_any(&["say", "print", "warn", "assert", "debug"])?;
932        let mut arguments = Vec::new();
933        if !self.statement_terminator_here() {
934            arguments.push(self.parse_expression()?);
935            while self.match_punct(',') {
936                arguments.push(self.parse_expression()?);
937            }
938        }
939        Ok(KeywordStatement {
940            line,
941            source_file: self.source_file(),
942            keyword,
943            arguments,
944        })
945    }
946
947    fn parse_expression_statement(&mut self) -> Result<ExpressionStatement> {
948        let expression = self.parse_expression()?;
949        Ok(ExpressionStatement {
950            line: expression.line(),
951            source_file: expression.source_file().map(str::to_owned),
952            expression,
953        })
954    }
955
956    fn parse_expression(&mut self) -> Result<Expression> {
957        self.parse_expression_prec(PREC_ASSIGNMENT)
958    }
959
960    fn parse_expression_prec(&mut self, min_prec: u8) -> Result<Expression> {
961        let mut left = self.parse_prefix_expression()?;
962
963        loop {
964            if min_prec <= PREC_ASSIGNMENT {
965                if let Some(operator) = self.current_assignment_operator() {
966                    self.advance();
967                    let right = self.parse_expression_prec(PREC_ASSIGNMENT)?;
968                    let is_weak_write = self.parse_optional_weak_modifier("assignment")?;
969                    if !Self::is_assignable_expression(&left) {
970                        return Err(self.error_current("invalid assignment target"));
971                    }
972                    if is_weak_write && operator != ":=" {
973                        return Err(
974                            self.error_current("but weak is only valid on ':=' assignments")
975                        );
976                    }
977                    if is_weak_write && Self::is_maybe_path_expression(&left) {
978                        return Err(
979                            self.error_current("but weak is not valid on @? path assignments")
980                        );
981                    }
982                    left = Expression::Assignment {
983                        line: left.line(),
984                        source_file: left.source_file().map(str::to_owned),
985                        operator,
986                        left: Box::new(left),
987                        right: Box::new(right),
988                        is_weak_write,
989                        inferred_type: None,
990                        runtime_typecheck_required: None,
991                    };
992                    continue;
993                }
994            }
995
996            if min_prec <= PREC_TERNARY && self.match_operator("?") {
997                let consequent = self.parse_expression()?;
998                self.expect_operator(":", "Expected ':' in ternary expression")?;
999                let alternate = self.parse_expression_prec(PREC_TERNARY)?;
1000                left = Expression::Ternary {
1001                    line: left.line(),
1002                    source_file: left.source_file().map(str::to_owned),
1003                    test: Box::new(left),
1004                    consequent: Box::new(consequent),
1005                    alternate: Box::new(alternate),
1006                    inferred_type: None,
1007                };
1008                continue;
1009            }
1010
1011            if min_prec <= PREC_TERNARY && self.match_operator("?:") {
1012                let right = self.parse_expression_prec(PREC_TERNARY)?;
1013                left = Expression::DefinedOr {
1014                    line: left.line(),
1015                    source_file: left.source_file().map(str::to_owned),
1016                    left: Box::new(left),
1017                    right: Box::new(right),
1018                    inferred_type: None,
1019                };
1020                continue;
1021            }
1022
1023            let Some((operator, precedence, right_assoc)) = self.current_infix_operator() else {
1024                break;
1025            };
1026            if precedence < min_prec {
1027                break;
1028            }
1029            self.advance();
1030            let next_prec = if right_assoc {
1031                precedence
1032            } else {
1033                precedence + 1
1034            };
1035            let right = self.parse_expression_prec(next_prec)?;
1036            if let Some(direction) = chain_direction(&operator) {
1037                if expression_chain_direction(&left)
1038                    .is_some_and(|left_direction| left_direction != direction)
1039                    || expression_chain_direction(&right)
1040                        .is_some_and(|right_direction| right_direction != direction)
1041                {
1042                    return Err(self.error_current("Mixed chain directions require parentheses"));
1043                }
1044            }
1045            left = Expression::Binary {
1046                line: left.line(),
1047                source_file: left.source_file().map(str::to_owned),
1048                operator,
1049                left: Box::new(left),
1050                right: Box::new(right),
1051                inferred_type: None,
1052            };
1053        }
1054
1055        Ok(left)
1056    }
1057
1058    fn parse_prefix_expression(&mut self) -> Result<Expression> {
1059        match self.current_kind() {
1060            TokenKind::Keyword("let") | TokenKind::Keyword("const") => self.parse_let_expression(),
1061            TokenKind::Keyword("try") => self.parse_try_expression(),
1062            TokenKind::Keyword("do") => self.parse_do_expression(),
1063            TokenKind::Keyword("await") => self.parse_await_expression(),
1064            TokenKind::Keyword("spawn") => self.parse_spawn_expression(),
1065            TokenKind::Keyword("new") => self.parse_new_expression(),
1066            TokenKind::Keyword("fn") => self.parse_lambda_expression(),
1067            TokenKind::Operator(op) if op == "->" => self.parse_arrow_lambda_expression(),
1068            TokenKind::Keyword("async") => self.parse_async_expression(),
1069            TokenKind::Operator(op)
1070                if ["+", "-", "!", "~", "++", "--", "¬", "√", "\\"].contains(&op.as_str()) =>
1071            {
1072                let operator = op.clone();
1073                self.advance();
1074                let argument = self.parse_expression_prec(PREC_PREFIX)?;
1075                if (operator == "++" || operator == "--")
1076                    && !Self::is_assignable_expression(&argument)
1077                {
1078                    return Err(self.error_current(format!(
1079                        "invalid target for unary operator '{}'",
1080                        operator
1081                    )));
1082                }
1083                Ok(Expression::Unary {
1084                    line: self.previous_line(),
1085                    source_file: self.source_file(),
1086                    operator,
1087                    argument: Box::new(argument),
1088                    traits: Vec::new(),
1089                    inferred_type: None,
1090                })
1091            }
1092            TokenKind::Keyword("not")
1093            | TokenKind::Keyword("abs")
1094            | TokenKind::Keyword("sqrt")
1095            | TokenKind::Keyword("floor")
1096            | TokenKind::Keyword("ceil")
1097            | TokenKind::Keyword("round")
1098            | TokenKind::Keyword("int")
1099            | TokenKind::Keyword("uc")
1100            | TokenKind::Keyword("lc")
1101            | TokenKind::Keyword("length")
1102            | TokenKind::Keyword("typeof") => {
1103                let operator = self.current_text();
1104                self.advance();
1105                let argument = self.parse_expression_prec(PREC_PREFIX)?;
1106                Ok(Expression::Unary {
1107                    line: self.previous_line(),
1108                    source_file: self.source_file(),
1109                    operator,
1110                    argument: Box::new(argument),
1111                    traits: Vec::new(),
1112                    inferred_type: None,
1113                })
1114            }
1115            _ => self.parse_postfix_expression(),
1116        }
1117    }
1118
1119    fn parse_new_expression(&mut self) -> Result<Expression> {
1120        let line = self.current_line();
1121        self.expect_keyword("new")?;
1122        let mut callee = self.parse_primary_expression()?;
1123        loop {
1124            if self.match_operator(".") {
1125                let member = self.expect_name("Expected member name after '.'")?;
1126                callee = Expression::MemberAccess {
1127                    line: callee.line(),
1128                    source_file: callee.source_file().map(str::to_owned),
1129                    object: Box::new(callee),
1130                    member,
1131                    inferred_type: None,
1132                };
1133                continue;
1134            }
1135            if self.match_punct('{') {
1136                let key = self.parse_dict_key_until_rbrace()?;
1137                self.expect_punct('}', "Expected '}' after dict access")?;
1138                callee = Expression::DictAccess {
1139                    line: callee.line(),
1140                    source_file: callee.source_file().map(str::to_owned),
1141                    object: Box::new(callee),
1142                    key: Box::new(key),
1143                    inferred_type: None,
1144                };
1145                continue;
1146            }
1147            break;
1148        }
1149        let traits = self.parse_trait_composition_list()?;
1150        self.expect_punct('(', "Expected '(' after class name in new expression")?;
1151        let arguments = self.parse_call_arguments_after_open()?;
1152        let argument = Expression::Call {
1153            line: callee.line(),
1154            source_file: callee.source_file().map(str::to_owned),
1155            callee: Box::new(callee),
1156            arguments,
1157            inferred_type: None,
1158        };
1159        let expr = Expression::Unary {
1160            line,
1161            source_file: self.source_file(),
1162            operator: "new".to_owned(),
1163            argument: Box::new(argument),
1164            traits,
1165            inferred_type: None,
1166        };
1167        self.parse_postfix_suffixes(expr)
1168    }
1169
1170    fn parse_postfix_expression(&mut self) -> Result<Expression> {
1171        let expr = self.parse_primary_expression()?;
1172        self.parse_postfix_suffixes(expr)
1173    }
1174
1175    fn parse_postfix_suffixes(&mut self, mut expr: Expression) -> Result<Expression> {
1176        loop {
1177            if self.match_punct('(') {
1178                let arguments = self.parse_call_arguments_after_open()?;
1179                expr = Expression::Call {
1180                    line: expr.line(),
1181                    source_file: expr.source_file().map(str::to_owned),
1182                    callee: Box::new(expr),
1183                    arguments,
1184                    inferred_type: None,
1185                };
1186                continue;
1187            }
1188            if self.match_operator(".(") {
1189                let member = self.parse_expression()?;
1190                self.expect_punct(')', "Expected ')' after dynamic member expression")?;
1191                self.expect_punct('(', "Expected '(' after dynamic member")?;
1192                let arguments = self.parse_call_arguments_after_open()?;
1193                expr = Expression::DynamicMemberCall {
1194                    line: expr.line(),
1195                    source_file: expr.source_file().map(str::to_owned),
1196                    object: Box::new(expr),
1197                    member: Box::new(member),
1198                    arguments,
1199                    inferred_type: None,
1200                };
1201                continue;
1202            }
1203            if self.match_operator(".") {
1204                let member = self.expect_name("Expected member name after '.'")?;
1205                expr = Expression::MemberAccess {
1206                    line: expr.line(),
1207                    source_file: expr.source_file().map(str::to_owned),
1208                    object: Box::new(expr),
1209                    member,
1210                    inferred_type: None,
1211                };
1212                continue;
1213            }
1214            if self.match_punct('[') {
1215                if self.match_operator(":") {
1216                    let end = if self.check_punct(']') {
1217                        None
1218                    } else {
1219                        Some(Box::new(self.parse_expression()?))
1220                    };
1221                    self.expect_punct(']', "Expected ']' after slice")?;
1222                    expr = Expression::Slice {
1223                        line: expr.line(),
1224                        source_file: expr.source_file().map(str::to_owned),
1225                        object: Box::new(expr),
1226                        start: None,
1227                        end,
1228                        inferred_type: None,
1229                    };
1230                    continue;
1231                }
1232                let first = self.parse_expression()?;
1233                if self.match_operator(":") {
1234                    let end = if self.check_punct(']') {
1235                        None
1236                    } else {
1237                        Some(Box::new(self.parse_expression()?))
1238                    };
1239                    self.expect_punct(']', "Expected ']' after slice")?;
1240                    expr = Expression::Slice {
1241                        line: expr.line(),
1242                        source_file: expr.source_file().map(str::to_owned),
1243                        object: Box::new(expr),
1244                        start: Some(Box::new(first)),
1245                        end,
1246                        inferred_type: None,
1247                    };
1248                    continue;
1249                }
1250                self.expect_punct(']', "Expected ']' after index")?;
1251                expr = Expression::Index {
1252                    line: expr.line(),
1253                    source_file: expr.source_file().map(str::to_owned),
1254                    object: Box::new(expr),
1255                    index: Box::new(first),
1256                    inferred_type: None,
1257                };
1258                continue;
1259            }
1260            if self.match_punct('{') {
1261                let key = self.parse_dict_key_until_rbrace()?;
1262                self.expect_punct('}', "Expected '}' after dict access")?;
1263                expr = Expression::DictAccess {
1264                    line: expr.line(),
1265                    source_file: expr.source_file().map(str::to_owned),
1266                    object: Box::new(expr),
1267                    key: Box::new(key),
1268                    inferred_type: None,
1269                };
1270                continue;
1271            }
1272            if self.match_operator("++") || self.match_operator("--") {
1273                let operator = self.previous_text();
1274                if !Self::is_assignable_expression(&expr) {
1275                    return Err(self.error_current(format!(
1276                        "invalid target for unary operator '{}'",
1277                        operator
1278                    )));
1279                }
1280                expr = Expression::PostfixUpdate {
1281                    line: expr.line(),
1282                    source_file: expr.source_file().map(str::to_owned),
1283                    operator,
1284                    argument: Box::new(expr),
1285                    inferred_type: None,
1286                };
1287                continue;
1288            }
1289            break;
1290        }
1291        Ok(expr)
1292    }
1293
1294    fn parse_primary_expression(&mut self) -> Result<Expression> {
1295        match self.current_kind() {
1296            TokenKind::Identifier(name) => {
1297                let value = name.clone();
1298                self.advance();
1299                Ok(Expression::Identifier {
1300                    line: self.previous_line(),
1301                    source_file: self.source_file(),
1302                    name: value,
1303                    inferred_type: None,
1304                    binding_depth: None,
1305                })
1306            }
1307            TokenKind::Number(value) => {
1308                let value = value.clone();
1309                self.advance();
1310                Ok(Expression::NumberLiteral {
1311                    line: self.previous_line(),
1312                    source_file: self.source_file(),
1313                    value,
1314                    inferred_type: None,
1315                })
1316            }
1317            TokenKind::String(value) => {
1318                let value = value.clone();
1319                self.advance();
1320                Ok(Expression::StringLiteral {
1321                    line: self.previous_line(),
1322                    source_file: self.source_file(),
1323                    value,
1324                    inferred_type: None,
1325                })
1326            }
1327            TokenKind::BinaryString(bytes) => {
1328                let bytes = bytes.clone();
1329                self.advance();
1330                Ok(Expression::BinaryStringLiteral {
1331                    line: self.previous_line(),
1332                    source_file: self.source_file(),
1333                    bytes,
1334                    inferred_type: None,
1335                })
1336            }
1337            TokenKind::Regex {
1338                pattern,
1339                parts,
1340                flags,
1341            } => {
1342                let pattern = pattern.clone();
1343                let parts = parts.clone();
1344                let flags = flags.clone();
1345                self.advance();
1346                let parts = self.parse_template_parts(parts)?;
1347                Ok(Expression::RegexLiteral {
1348                    line: self.previous_line(),
1349                    source_file: self.source_file(),
1350                    pattern,
1351                    parts,
1352                    flags,
1353                    cache_key: None,
1354                    inferred_type: None,
1355                })
1356            }
1357            TokenKind::Template(parts) => {
1358                let line = self.current_line();
1359                let parts = parts.clone();
1360                self.advance();
1361                let ast_parts = self.parse_template_parts(parts)?;
1362                Ok(Expression::TemplateLiteral {
1363                    line,
1364                    source_file: self.source_file(),
1365                    parts: ast_parts,
1366                    inferred_type: None,
1367                })
1368            }
1369            TokenKind::Keyword("true") => {
1370                self.advance();
1371                Ok(Expression::BooleanLiteral {
1372                    line: self.previous_line(),
1373                    source_file: self.source_file(),
1374                    value: true,
1375                    inferred_type: None,
1376                })
1377            }
1378            TokenKind::Keyword("false") => {
1379                self.advance();
1380                Ok(Expression::BooleanLiteral {
1381                    line: self.previous_line(),
1382                    source_file: self.source_file(),
1383                    value: false,
1384                    inferred_type: None,
1385                })
1386            }
1387            TokenKind::Keyword("null") => {
1388                self.advance();
1389                Ok(Expression::NullLiteral {
1390                    line: self.previous_line(),
1391                    source_file: self.source_file(),
1392                    inferred_type: None,
1393                })
1394            }
1395            TokenKind::Keyword("super") => self.parse_super_call_expression(),
1396            TokenKind::Keyword("function") => self.parse_function_expression(),
1397            TokenKind::Punct('(') => {
1398                self.advance();
1399                let expr = self.parse_expression()?;
1400                self.expect_punct(')', "Expected ')' after expression")?;
1401                Ok(expr)
1402            }
1403            TokenKind::Punct('[') => self.parse_array_literal(),
1404            TokenKind::Punct('{') if self.peek_punct('{') => self.parse_pairlist_literal(),
1405            TokenKind::Punct('{') => self.parse_dict_literal(),
1406            TokenKind::Operator(op) if op == "<<" || op == "«" => self.parse_set_literal(),
1407            TokenKind::Operator(op) if op == "<<<" => self.parse_bag_literal(),
1408            TokenKind::Operator(op) if op == "⌊" => self.parse_grouped_unary("floor", "⌋"),
1409            TokenKind::Operator(op) if op == "⌈" => self.parse_grouped_unary("ceil", "⌉"),
1410            _ => Err(self.error_current("Expected expression")),
1411        }
1412    }
1413
1414    fn parse_template_parts(&self, parts: Vec<TokenTemplatePart>) -> Result<Vec<AstTemplatePart>> {
1415        let mut ast_parts = Vec::new();
1416        for part in parts {
1417            match part {
1418                TokenTemplatePart::Text { line, value } => ast_parts.push(AstTemplatePart::Text {
1419                    line,
1420                    source_file: self.source_file(),
1421                    value,
1422                }),
1423                TokenTemplatePart::Expr { line, source } => {
1424                    let padded_source =
1425                        format!("{}{}", "\n".repeat(line.saturating_sub(1)), source);
1426                    let expression = crate::parse_expression_with_source_file(
1427                        &padded_source,
1428                        self.source_file.as_deref(),
1429                    )
1430                    .map_err(|_| ZuzuRustError::semantic("invalid template interpolation", line))?;
1431                    ast_parts.push(AstTemplatePart::Expression {
1432                        line: expression.line(),
1433                        source_file: expression.source_file().map(str::to_owned),
1434                        expression: Box::new(expression),
1435                    });
1436                }
1437            }
1438        }
1439        Ok(ast_parts)
1440    }
1441
1442    fn parse_super_call_expression(&mut self) -> Result<Expression> {
1443        let line = self.current_line();
1444        self.expect_keyword("super")?;
1445        self.expect_punct('(', "Expected '(' after super")?;
1446        let arguments = self.parse_call_arguments_after_open()?;
1447        Ok(Expression::SuperCall {
1448            line,
1449            source_file: self.source_file(),
1450            arguments,
1451            inferred_type: None,
1452        })
1453    }
1454
1455    fn parse_array_literal(&mut self) -> Result<Expression> {
1456        let line = self.current_line();
1457        self.expect_punct('[', "Expected '['")?;
1458        let mut elements = Vec::new();
1459        self.consume_commas();
1460        if !self.check_punct(']') {
1461            loop {
1462                elements.push(self.parse_expression()?);
1463                self.consume_commas();
1464                if self.check_punct(']') {
1465                    break;
1466                }
1467                if !self.previous_was_comma() {
1468                    break;
1469                }
1470            }
1471        }
1472        self.expect_punct(']', "Expected ']' after array literal")?;
1473        Ok(Expression::ArrayLiteral {
1474            line,
1475            source_file: self.source_file(),
1476            elements,
1477            capacity_hint: None,
1478            inferred_type: None,
1479        })
1480    }
1481
1482    fn parse_set_literal(&mut self) -> Result<Expression> {
1483        let line = self.current_line();
1484        let close = if self.match_operator("<<") {
1485            ">>"
1486        } else {
1487            self.expect_operator("«", "Expected set literal start")?;
1488            "»"
1489        };
1490        let elements = self.parse_expression_list_until_operator(close)?;
1491        Ok(Expression::SetLiteral {
1492            line,
1493            source_file: self.source_file(),
1494            elements,
1495            capacity_hint: None,
1496            inferred_type: None,
1497        })
1498    }
1499
1500    fn parse_bag_literal(&mut self) -> Result<Expression> {
1501        let line = self.current_line();
1502        self.expect_operator("<<<", "Expected bag literal start")?;
1503        let elements = self.parse_expression_list_until_operator(">>>")?;
1504        Ok(Expression::BagLiteral {
1505            line,
1506            source_file: self.source_file(),
1507            elements,
1508            capacity_hint: None,
1509            inferred_type: None,
1510        })
1511    }
1512
1513    fn parse_dict_literal(&mut self) -> Result<Expression> {
1514        let line = self.current_line();
1515        self.expect_punct('{', "Expected '{'")?;
1516        let mut entries = Vec::new();
1517        self.consume_commas();
1518        if !self.check_punct('}') {
1519            loop {
1520                let key = self.parse_dict_key_before_colon()?;
1521                self.expect_operator(":", "Expected ':' after dict key")?;
1522                let value = self.parse_expression()?;
1523                entries.push(DictEntry {
1524                    line: key.line(),
1525                    source_file: key.source_file().map(str::to_owned),
1526                    key,
1527                    value,
1528                });
1529                self.consume_commas();
1530                if self.check_punct('}') {
1531                    break;
1532                }
1533                if !self.previous_was_comma() {
1534                    break;
1535                }
1536            }
1537        }
1538        self.expect_punct('}', "Expected '}' after dict literal")?;
1539        Ok(Expression::DictLiteral {
1540            line,
1541            source_file: self.source_file(),
1542            entries,
1543            capacity_hint: None,
1544            inferred_type: None,
1545        })
1546    }
1547
1548    fn parse_pairlist_literal(&mut self) -> Result<Expression> {
1549        let line = self.current_line();
1550        self.expect_punct('{', "Expected '{'")?;
1551        self.expect_punct('{', "Expected second '{' in pairlist literal")?;
1552        let mut entries = Vec::new();
1553        self.consume_commas();
1554        if !(self.check_punct('}') && self.peek_punct('}')) {
1555            loop {
1556                let key = self.parse_dict_key_before_colon()?;
1557                self.expect_operator(":", "Expected ':' after pairlist key")?;
1558                let value = self.parse_expression()?;
1559                entries.push(DictEntry {
1560                    line: key.line(),
1561                    source_file: key.source_file().map(str::to_owned),
1562                    key,
1563                    value,
1564                });
1565                self.consume_commas();
1566                if self.check_punct('}') && self.peek_punct('}') {
1567                    break;
1568                }
1569                if !self.previous_was_comma() {
1570                    break;
1571                }
1572            }
1573        }
1574        self.expect_punct('}', "Expected '}' after pairlist literal")?;
1575        self.expect_punct('}', "Expected second '}' after pairlist literal")?;
1576        Ok(Expression::PairListLiteral {
1577            line,
1578            source_file: self.source_file(),
1579            entries,
1580            capacity_hint: None,
1581            inferred_type: None,
1582        })
1583    }
1584
1585    fn parse_let_expression(&mut self) -> Result<Expression> {
1586        let line = self.current_line();
1587        let kind = self.expect_keyword_any(&["let", "const"])?;
1588        let (declared_type, name) = self.parse_typed_name()?;
1589        let mut is_weak_storage = self.parse_optional_weak_modifier("declaration")?;
1590        let init = if self.match_operator(":=") {
1591            let init = self.parse_expression()?;
1592            is_weak_storage |= self.parse_optional_weak_modifier("declaration")?;
1593            Some(Box::new(init))
1594        } else {
1595            None
1596        };
1597        Ok(Expression::LetExpression {
1598            line,
1599            source_file: self.source_file(),
1600            kind,
1601            declared_type,
1602            name,
1603            init,
1604            is_weak_storage,
1605            inferred_type: None,
1606            runtime_typecheck_required: None,
1607        })
1608    }
1609
1610    fn parse_try_expression(&mut self) -> Result<Expression> {
1611        let line = self.current_line();
1612        self.expect_keyword("try")?;
1613        let body = self.parse_block_statement()?;
1614        let mut handlers = Vec::new();
1615        while self.match_keyword("catch") {
1616            handlers.push(self.parse_catch_clause()?);
1617        }
1618        if handlers.is_empty() {
1619            return Err(self.error_current("Expected at least one catch block"));
1620        }
1621        Ok(Expression::TryExpression {
1622            line,
1623            source_file: self.source_file(),
1624            body,
1625            handlers,
1626            inferred_type: None,
1627        })
1628    }
1629
1630    fn parse_do_expression(&mut self) -> Result<Expression> {
1631        let line = self.current_line();
1632        self.expect_keyword("do")?;
1633        let body = self.parse_block_statement()?;
1634        Ok(Expression::DoExpression {
1635            line,
1636            source_file: self.source_file(),
1637            body,
1638            inferred_type: None,
1639        })
1640    }
1641
1642    fn parse_await_expression(&mut self) -> Result<Expression> {
1643        let line = self.current_line();
1644        self.expect_keyword("await")?;
1645        let body = self.parse_block_statement()?;
1646        Ok(Expression::AwaitExpression {
1647            line,
1648            source_file: self.source_file(),
1649            body,
1650            inferred_type: None,
1651        })
1652    }
1653
1654    fn parse_spawn_expression(&mut self) -> Result<Expression> {
1655        let line = self.current_line();
1656        self.expect_keyword("spawn")?;
1657        let body = self.parse_block_statement()?;
1658        Ok(Expression::SpawnExpression {
1659            line,
1660            source_file: self.source_file(),
1661            body,
1662            inferred_type: None,
1663        })
1664    }
1665
1666    fn parse_async_expression(&mut self) -> Result<Expression> {
1667        self.expect_keyword("async")?;
1668        match self.current_kind() {
1669            TokenKind::Keyword("fn") => self.parse_lambda_expression_with_async(true),
1670            TokenKind::Keyword("function") => self.parse_function_expression_with_async(true),
1671            _ => Err(self.error_current("Expected function or fn after async")),
1672        }
1673    }
1674
1675    fn parse_lambda_expression(&mut self) -> Result<Expression> {
1676        self.parse_lambda_expression_with_async(false)
1677    }
1678
1679    fn parse_lambda_expression_with_async(&mut self, is_async: bool) -> Result<Expression> {
1680        let line = self.current_line();
1681        self.expect_keyword("fn")?;
1682        let params = if self.check_punct('(') {
1683            self.parse_parameter_list()?
1684        } else {
1685            vec![self.parse_parameter()?]
1686        };
1687        self.expect_operator("->", "Expected '->' after lambda parameters")?;
1688        let body = self.parse_expression()?;
1689        Ok(Expression::Lambda {
1690            line,
1691            source_file: self.source_file(),
1692            params,
1693            body: Box::new(body),
1694            is_async,
1695            inferred_type: None,
1696        })
1697    }
1698
1699    fn parse_arrow_lambda_expression(&mut self) -> Result<Expression> {
1700        let line = self.current_line();
1701        self.expect_operator("->", "Expected '->'")?;
1702        let body = self.parse_expression()?;
1703        Ok(Expression::Lambda {
1704            line,
1705            source_file: self.source_file(),
1706            params: vec![Parameter {
1707                line,
1708                source_file: self.source_file(),
1709                declared_type: None,
1710                name: "^^".to_owned(),
1711                optional: true,
1712                variadic: false,
1713                default_value: None,
1714            }],
1715            body: Box::new(body),
1716            is_async: false,
1717            inferred_type: None,
1718        })
1719    }
1720
1721    fn parse_function_expression(&mut self) -> Result<Expression> {
1722        self.parse_function_expression_with_async(false)
1723    }
1724
1725    fn parse_function_expression_with_async(&mut self, is_async: bool) -> Result<Expression> {
1726        let line = self.current_line();
1727        self.expect_keyword("function")?;
1728        let params = self.parse_parameter_list()?;
1729        let return_type = self.parse_optional_return_type()?;
1730        let body = self.parse_block_statement()?;
1731        Ok(Expression::FunctionExpression {
1732            line,
1733            source_file: self.source_file(),
1734            params,
1735            return_type,
1736            body,
1737            is_async,
1738            inferred_type: None,
1739        })
1740    }
1741
1742    fn parse_parameter_list(&mut self) -> Result<Vec<Parameter>> {
1743        self.expect_punct('(', "Expected '('")?;
1744        let mut params = Vec::new();
1745        if !self.check_punct(')') {
1746            loop {
1747                if self.match_punct(',') {
1748                    continue;
1749                }
1750                params.push(self.parse_parameter()?);
1751                if self.check_operator("...") {
1752                    params.push(self.parse_parameter()?);
1753                }
1754                if !self.match_punct(',') {
1755                    break;
1756                }
1757                if self.check_punct(')') {
1758                    break;
1759                }
1760            }
1761        }
1762        self.expect_punct(')', "Expected ')' after parameter list")?;
1763        Ok(params)
1764    }
1765
1766    fn parse_parameter(&mut self) -> Result<Parameter> {
1767        let line = self.current_line();
1768        let variadic = self.match_operator("...");
1769        let (declared_type, name) = self.parse_typed_name()?;
1770        let optional = self.match_operator("?");
1771        let default_value = if self.match_operator(":=") {
1772            Some(self.parse_expression()?)
1773        } else {
1774            None
1775        };
1776        Ok(Parameter {
1777            line,
1778            source_file: self.source_file(),
1779            declared_type,
1780            name,
1781            optional,
1782            variadic,
1783            default_value,
1784        })
1785    }
1786
1787    fn parse_optional_return_type(&mut self) -> Result<Option<String>> {
1788        if self.match_operator("->") {
1789            Ok(Some(
1790                self.expect_identifier("Expected return type after '->'")?,
1791            ))
1792        } else {
1793            Ok(None)
1794        }
1795    }
1796
1797    fn parse_parenthesized_expression(&mut self) -> Result<Expression> {
1798        self.expect_punct('(', "Expected '('")?;
1799        let expr = self.parse_expression()?;
1800        self.expect_punct(')', "Expected ')' after expression")?;
1801        Ok(expr)
1802    }
1803
1804    fn parse_call_arguments_after_open(&mut self) -> Result<Vec<CallArgument>> {
1805        let mut arguments = Vec::new();
1806        if !self.check_punct(')') {
1807            loop {
1808                if self.match_punct(',') {
1809                    continue;
1810                }
1811                arguments.push(self.parse_call_argument()?);
1812                if self.match_punct(',') {
1813                    if self.check_punct(')') {
1814                        break;
1815                    }
1816                    continue;
1817                }
1818                if self.starts_named_argument() {
1819                    continue;
1820                }
1821                break;
1822            }
1823        }
1824        self.expect_punct(')', "Expected ')' after arguments")?;
1825        Ok(arguments)
1826    }
1827
1828    fn parse_call_argument(&mut self) -> Result<CallArgument> {
1829        if self.match_operator("...") {
1830            let line = self.previous_line();
1831            let value = self.parse_expression()?;
1832            return Ok(CallArgument::Spread {
1833                line,
1834                source_file: self.source_file(),
1835                value,
1836            });
1837        }
1838
1839        if self.starts_named_argument() {
1840            let key = self.parse_dict_key_before_colon()?;
1841            self.expect_operator(":", "Expected ':' in named argument")?;
1842            let value = self.parse_expression()?;
1843            return Ok(CallArgument::Named {
1844                line: key.line(),
1845                source_file: key.source_file().map(str::to_owned),
1846                name: key,
1847                value,
1848            });
1849        }
1850
1851        let expr = self.parse_expression()?;
1852        let line = expr.line();
1853        if self.match_operator(":") {
1854            let value = self.parse_expression()?;
1855            let key = match expr {
1856                Expression::Identifier {
1857                    line,
1858                    source_file,
1859                    name,
1860                    ..
1861                } => DictKey::Identifier {
1862                    line,
1863                    source_file,
1864                    name,
1865                },
1866                Expression::StringLiteral {
1867                    line,
1868                    source_file,
1869                    value,
1870                    ..
1871                } => DictKey::StringLiteral {
1872                    line,
1873                    source_file,
1874                    value,
1875                },
1876                other => DictKey::Expression {
1877                    line: other.line(),
1878                    source_file: other.source_file().map(str::to_owned),
1879                    expression: Box::new(other),
1880                },
1881            };
1882            Ok(CallArgument::Named {
1883                line,
1884                source_file: key.source_file().map(str::to_owned),
1885                name: key,
1886                value,
1887            })
1888        } else {
1889            Ok(CallArgument::Positional {
1890                line,
1891                source_file: expr.source_file().map(str::to_owned),
1892                value: expr,
1893            })
1894        }
1895    }
1896
1897    fn parse_typed_name(&mut self) -> Result<(Option<String>, String)> {
1898        let first = self.expect_name("Expected name")?;
1899        if self.check_identifier() {
1900            let second = self.expect_name("Expected identifier")?;
1901            Ok((Some(first), second))
1902        } else {
1903            Ok((None, first))
1904        }
1905    }
1906
1907    fn parse_trait_composition_list(&mut self) -> Result<Vec<String>> {
1908        let mut traits = Vec::new();
1909        if self.match_keyword("with") || self.match_keyword("but") {
1910            loop {
1911                traits.push(self.expect_identifier("Expected trait name")?);
1912                if !self.match_punct(',') {
1913                    break;
1914                }
1915            }
1916        }
1917        Ok(traits)
1918    }
1919
1920    fn parse_dict_key_before_colon(&mut self) -> Result<DictKey> {
1921        match self.current_kind() {
1922            TokenKind::Identifier(name) => {
1923                let name = name.clone();
1924                self.advance();
1925                Ok(DictKey::Identifier {
1926                    line: self.previous_line(),
1927                    source_file: self.source_file(),
1928                    name,
1929                })
1930            }
1931            TokenKind::Keyword(value) => {
1932                let name = (*value).to_owned();
1933                self.advance();
1934                Ok(DictKey::Identifier {
1935                    line: self.previous_line(),
1936                    source_file: self.source_file(),
1937                    name,
1938                })
1939            }
1940            TokenKind::String(value) => {
1941                let value = value.clone();
1942                self.advance();
1943                Ok(DictKey::StringLiteral {
1944                    line: self.previous_line(),
1945                    source_file: self.source_file(),
1946                    value,
1947                })
1948            }
1949            TokenKind::Punct('(') => {
1950                let line = self.current_line();
1951                self.advance();
1952                let expr = self.parse_expression()?;
1953                self.expect_punct(')', "Expected ')' after dict key expression")?;
1954                Ok(DictKey::Expression {
1955                    line,
1956                    source_file: self.source_file(),
1957                    expression: Box::new(expr),
1958                })
1959            }
1960            _ => Err(self.error_current("Expected dict key")),
1961        }
1962    }
1963
1964    fn parse_dict_key_until_rbrace(&mut self) -> Result<DictKey> {
1965        match self.current_kind() {
1966            TokenKind::Identifier(name) => {
1967                if self
1968                    .tokens
1969                    .get(self.index + 1)
1970                    .map(|token| matches!(token.kind, TokenKind::Punct('}')))
1971                    .unwrap_or(false)
1972                {
1973                    let name = name.clone();
1974                    self.advance();
1975                    Ok(DictKey::Identifier {
1976                        line: self.previous_line(),
1977                        source_file: self.source_file(),
1978                        name,
1979                    })
1980                } else {
1981                    let line = self.current_line();
1982                    let expr = self.parse_expression()?;
1983                    Ok(DictKey::Expression {
1984                        line,
1985                        source_file: self.source_file(),
1986                        expression: Box::new(expr),
1987                    })
1988                }
1989            }
1990            TokenKind::Keyword(value) => {
1991                if self
1992                    .tokens
1993                    .get(self.index + 1)
1994                    .map(|token| matches!(token.kind, TokenKind::Punct('}')))
1995                    .unwrap_or(false)
1996                {
1997                    let name = (*value).to_owned();
1998                    self.advance();
1999                    Ok(DictKey::Identifier {
2000                        line: self.previous_line(),
2001                        source_file: self.source_file(),
2002                        name,
2003                    })
2004                } else {
2005                    let line = self.current_line();
2006                    let expr = self.parse_expression()?;
2007                    Ok(DictKey::Expression {
2008                        line,
2009                        source_file: self.source_file(),
2010                        expression: Box::new(expr),
2011                    })
2012                }
2013            }
2014            TokenKind::String(value) => {
2015                if self
2016                    .tokens
2017                    .get(self.index + 1)
2018                    .map(|token| matches!(token.kind, TokenKind::Punct('}')))
2019                    .unwrap_or(false)
2020                {
2021                    let value = value.clone();
2022                    self.advance();
2023                    Ok(DictKey::StringLiteral {
2024                        line: self.previous_line(),
2025                        source_file: self.source_file(),
2026                        value,
2027                    })
2028                } else {
2029                    let line = self.current_line();
2030                    let expr = self.parse_expression()?;
2031                    Ok(DictKey::Expression {
2032                        line,
2033                        source_file: self.source_file(),
2034                        expression: Box::new(expr),
2035                    })
2036                }
2037            }
2038            TokenKind::Punct('(') => {
2039                let line = self.current_line();
2040                self.advance();
2041                let expr = self.parse_expression()?;
2042                self.expect_punct(')', "Expected ')' after dict key expression")?;
2043                Ok(DictKey::Expression {
2044                    line,
2045                    source_file: self.source_file(),
2046                    expression: Box::new(expr),
2047                })
2048            }
2049            _ => Err(self.error_current("Expected dict access key")),
2050        }
2051    }
2052
2053    fn parse_expression_list_until_operator(&mut self, close: &str) -> Result<Vec<Expression>> {
2054        let suppressed = match close {
2055            ">>" => Some(">>"),
2056            "»" => Some("»"),
2057            _ => None,
2058        };
2059        if let Some(closer) = suppressed {
2060            self.pending_set_closers.push(closer);
2061        }
2062        let parsed: Result<Vec<Expression>> = (|| {
2063            let mut elements = Vec::new();
2064            if !self.check_operator(close) {
2065                loop {
2066                    elements.push(self.parse_expression()?);
2067                    if !self.match_punct(',') {
2068                        break;
2069                    }
2070                    if self.check_operator(close) {
2071                        break;
2072                    }
2073                }
2074            }
2075            Ok(elements)
2076        })();
2077        if suppressed.is_some() {
2078            self.pending_set_closers.pop();
2079        }
2080        let elements = parsed?;
2081        self.expect_operator(close, "Expected collection literal terminator")?;
2082        Ok(elements)
2083    }
2084
2085    fn parse_grouped_unary(&mut self, operator: &str, close: &str) -> Result<Expression> {
2086        let line = self.current_line();
2087        self.expect_operator(&self.current_text(), "Expected grouped unary opener")?;
2088        let argument = self.parse_expression()?;
2089        self.expect_operator(close, "Expected grouped unary closer")?;
2090        Ok(Expression::Unary {
2091            line,
2092            source_file: self.source_file(),
2093            operator: operator.to_owned(),
2094            argument: Box::new(argument),
2095            traits: Vec::new(),
2096            inferred_type: None,
2097        })
2098    }
2099
2100    fn current_assignment_operator(&self) -> Option<String> {
2101        match self.current_kind() {
2102            TokenKind::Operator(op)
2103                if [
2104                    ":=", "+=", "-=", "*=", "×=", "/=", "÷=", "_=", "~=", "**=", "?:=",
2105                ]
2106                .contains(&op.as_str()) =>
2107            {
2108                Some(op.clone())
2109            }
2110            _ => None,
2111        }
2112    }
2113
2114    fn is_assignable_expression(expr: &Expression) -> bool {
2115        match expr {
2116            Expression::Identifier { .. }
2117            | Expression::Index { .. }
2118            | Expression::Slice { .. }
2119            | Expression::DictAccess { .. } => true,
2120            Expression::Binary {
2121                operator,
2122                left: _,
2123                right: _,
2124                ..
2125            } if operator == "@" || operator == "@@" || operator == "@?" => true,
2126            _ => false,
2127        }
2128    }
2129
2130    fn parse_optional_weak_modifier(&mut self, context: &str) -> Result<bool> {
2131        if !self.match_keyword("but") {
2132            return Ok(false);
2133        }
2134        let modifier = self.current_text();
2135        if modifier != "weak" {
2136            return Err(self.error_current(format!(
2137                "Unknown but modifier '{modifier}' in {context}; expected 'but weak'"
2138            )));
2139        }
2140        self.advance();
2141        Ok(true)
2142    }
2143
2144    fn is_maybe_path_expression(expr: &Expression) -> bool {
2145        matches!(
2146            expr,
2147            Expression::Binary {
2148                operator,
2149                ..
2150            } if operator == "@?"
2151        )
2152    }
2153
2154    fn current_infix_operator(&self) -> Option<(String, u8, bool)> {
2155        let text = self.current_text();
2156        if let Some(closer) = self.pending_set_closers.last() {
2157            // Inside << ... >> or « ... » the closer ends the literal
2158            // instead of acting as a shift operator.
2159            if text == *closer {
2160                return None;
2161            }
2162        }
2163        let entry = match text.as_str() {
2164            "or" | "⋁" | "or?" | "⋁?" => Some((PREC_OR, false)),
2165            "▷" | "|>" => Some((PREC_CHAIN, false)),
2166            "◁" | "<|" => Some((PREC_CHAIN, true)),
2167            "onlyif" | "⊨" | "onlyif?" | "⊨?" => Some((PREC_ONLYIF, true)),
2168            "xor" | "⊻" | "xor?" | "⊻?" | "nor" | "⊽" | "nor?" | "⊽?" | "xnor" | "↔" | "xnor?"
2169            | "↔?" => Some((PREC_XOR, false)),
2170            "and" | "⋀" | "and?" | "⋀?" | "nand" | "⊼" | "nand?" | "⊼?" | "butnot" | "⊭"
2171            | "butnot?" | "⊭?" => Some((PREC_AND, false)),
2172            "==" | "≡" | "!=" | "≢" | "default" => Some((PREC_EQUALITY, false)),
2173            "=" | "≠" | "<" | ">" | "<=" | "≤" | ">=" | "≥" | "<=>" | "≶" | "≷" | "eq" | "ne"
2174            | "gt" | "ge" | "lt" | "le" | "cmp" | "eqi" | "nei" | "gti" | "gei" | "lti" | "lei"
2175            | "cmpi" | "in" | "∈" | "∉" | "subsetof" | "⊂" | "supersetof" | "⊃"
2176            | "equivalentof" | "⊂⊃" | "instanceof" | "does" | "can" | "~" | "->" | "@" | "@?"
2177            | "@@" | "∣" | "divides" | "∤" => Some((PREC_COMPARISON, false)),
2178            "|" => Some((PREC_BITWISE_OR, false)),
2179            "^" => Some((PREC_BITWISE_XOR, false)),
2180            "&" => Some((PREC_BITWISE_AND, false)),
2181            "<<" | "«" | ">>" | "»" => Some((PREC_SHIFT, false)),
2182            "union" | "⋃" | "intersection" | "⋂" | "\\" | "∖" => Some((PREC_SET, false)),
2183            "..." => Some((PREC_SET, false)),
2184            "_" => Some((PREC_CONCAT, false)),
2185            "+" | "-" => Some((PREC_ADDITIVE, false)),
2186            "*" | "/" | "×" | "÷" | "mod" => Some((PREC_MULTIPLICATIVE, false)),
2187            "**" => Some((PREC_EXPONENT, true)),
2188            _ => None,
2189        }?;
2190        Some((text, entry.0, entry.1))
2191    }
2192
2193    fn match_postfix_condition_keyword(&mut self) -> Option<String> {
2194        if self.match_keyword("if") {
2195            Some("if".to_owned())
2196        } else if self.match_keyword("unless") {
2197            Some("unless".to_owned())
2198        } else {
2199            None
2200        }
2201    }
2202
2203    fn statement_terminator_here(&self) -> bool {
2204        matches!(
2205            self.current_kind(),
2206            TokenKind::Punct(';') | TokenKind::Punct('}') | TokenKind::Eof
2207        )
2208    }
2209
2210    fn expect_statement_separator(&mut self, message: &str) -> Result<()> {
2211        if self.match_punct(';') || self.check_punct('}') || self.at_eof() {
2212            Ok(())
2213        } else {
2214            Err(self.error_current(message))
2215        }
2216    }
2217
2218    fn current_kind(&self) -> &TokenKind {
2219        &self.tokens[self.index].kind
2220    }
2221
2222    fn current_line(&self) -> usize {
2223        self.tokens[self.index].span.line
2224    }
2225
2226    fn previous_line(&self) -> usize {
2227        if self.index == 0 {
2228            self.tokens[0].span.line
2229        } else {
2230            self.tokens[self.index - 1].span.line
2231        }
2232    }
2233
2234    fn current_text(&self) -> String {
2235        token_text(self.current_kind())
2236    }
2237
2238    fn previous_text(&self) -> String {
2239        token_text(&self.tokens[self.index - 1].kind)
2240    }
2241
2242    fn at_eof(&self) -> bool {
2243        matches!(self.current_kind(), TokenKind::Eof)
2244    }
2245
2246    fn advance(&mut self) {
2247        if !self.at_eof() {
2248            self.index += 1;
2249        }
2250    }
2251
2252    fn consume_semicolons(&mut self) {
2253        while self.match_punct(';') {}
2254    }
2255
2256    fn consume_commas(&mut self) {
2257        while self.match_punct(',') {}
2258    }
2259
2260    fn previous_was_comma(&self) -> bool {
2261        self.index > 0 && matches!(self.tokens[self.index - 1].kind, TokenKind::Punct(','))
2262    }
2263
2264    fn check_identifier(&self) -> bool {
2265        matches!(self.current_kind(), TokenKind::Identifier(_))
2266    }
2267
2268    fn starts_named_argument(&self) -> bool {
2269        let Some(next) = self.tokens.get(self.index + 1) else {
2270            return false;
2271        };
2272        matches!(
2273            self.current_kind(),
2274            TokenKind::Identifier(_)
2275                | TokenKind::Keyword(_)
2276                | TokenKind::String(_)
2277                | TokenKind::Punct('(')
2278        ) && matches!(&next.kind, TokenKind::Operator(value) if value == ":")
2279    }
2280
2281    #[allow(dead_code)]
2282    fn check_name(&self) -> bool {
2283        matches!(
2284            self.current_kind(),
2285            TokenKind::Identifier(_) | TokenKind::Keyword(_)
2286        )
2287    }
2288
2289    fn check_keyword(&self, keyword: &str) -> bool {
2290        matches!(self.current_kind(), TokenKind::Keyword(value) if *value == keyword)
2291    }
2292
2293    fn check_punct(&self, punct: char) -> bool {
2294        matches!(self.current_kind(), TokenKind::Punct(value) if *value == punct)
2295    }
2296
2297    fn peek_punct(&self, punct: char) -> bool {
2298        matches!(
2299            self.tokens.get(self.index + 1).map(|token| &token.kind),
2300            Some(TokenKind::Punct(value)) if *value == punct
2301        )
2302    }
2303
2304    fn peek_keyword(&self, keyword: &str) -> bool {
2305        matches!(
2306            self.tokens.get(self.index + 1).map(|token| &token.kind),
2307            Some(TokenKind::Keyword(value)) if *value == keyword
2308        )
2309    }
2310
2311    fn check_operator(&self, operator: &str) -> bool {
2312        matches!(self.current_kind(), TokenKind::Operator(value) if value == operator)
2313    }
2314
2315    fn match_keyword(&mut self, keyword: &str) -> bool {
2316        if self.check_keyword(keyword) {
2317            self.advance();
2318            true
2319        } else {
2320            false
2321        }
2322    }
2323
2324    fn match_punct(&mut self, punct: char) -> bool {
2325        if self.check_punct(punct) {
2326            self.advance();
2327            true
2328        } else {
2329            false
2330        }
2331    }
2332
2333    fn match_operator(&mut self, operator: &str) -> bool {
2334        match self.current_kind() {
2335            TokenKind::Operator(value) if value == operator => {
2336                self.advance();
2337                true
2338            }
2339            _ => false,
2340        }
2341    }
2342
2343    fn expect_keyword(&mut self, keyword: &str) -> Result<()> {
2344        if self.match_keyword(keyword) {
2345            Ok(())
2346        } else {
2347            Err(self.error_current(format!("Expected keyword '{}'", keyword)))
2348        }
2349    }
2350
2351    fn expect_keyword_any(&mut self, keywords: &[&str]) -> Result<String> {
2352        for keyword in keywords {
2353            if self.match_keyword(keyword) {
2354                return Ok((*keyword).to_owned());
2355            }
2356        }
2357        Err(self.error_current("Expected keyword"))
2358    }
2359
2360    fn expect_identifier(&mut self, message: &str) -> Result<String> {
2361        match self.current_kind() {
2362            TokenKind::Identifier(value) => {
2363                let value = value.clone();
2364                if value == "^^" {
2365                    return Err(self.error_current("'^^' is reserved for the chain placeholder"));
2366                }
2367                self.advance();
2368                Ok(value)
2369            }
2370            _ => Err(self.error_current(message)),
2371        }
2372    }
2373
2374    fn expect_name(&mut self, message: &str) -> Result<String> {
2375        match self.current_kind() {
2376            TokenKind::Identifier(value) => {
2377                let value = value.clone();
2378                if value == "^^" {
2379                    return Err(self.error_current("'^^' is reserved for the chain placeholder"));
2380                }
2381                self.advance();
2382                Ok(value)
2383            }
2384            TokenKind::Keyword(value) => {
2385                let value = (*value).to_owned();
2386                self.advance();
2387                Ok(value)
2388            }
2389            _ => Err(self.error_current(message)),
2390        }
2391    }
2392
2393    fn expect_punct(&mut self, punct: char, message: &str) -> Result<()> {
2394        if self.match_punct(punct) {
2395            Ok(())
2396        } else {
2397            Err(self.error_current(message))
2398        }
2399    }
2400
2401    fn expect_operator(&mut self, operator: &str, message: &str) -> Result<()> {
2402        if self.match_operator(operator) {
2403            Ok(())
2404        } else {
2405            Err(self.error_current(message))
2406        }
2407    }
2408
2409    fn expect_switch_comparator_text(&mut self, message: &str) -> Result<String> {
2410        self.match_switch_comparator_text()
2411            .ok_or_else(|| self.error_current(message))
2412    }
2413
2414    fn match_switch_comparator_text(&mut self) -> Option<String> {
2415        let value = match self.current_kind() {
2416            TokenKind::Operator(value) if is_switch_comparator(value) => value.clone(),
2417            TokenKind::Keyword(value) if is_switch_comparator(value) => (*value).to_owned(),
2418            _ => return None,
2419        };
2420        self.advance();
2421        Some(value)
2422    }
2423
2424    fn error_current(&self, message: impl Into<String>) -> ZuzuRustError {
2425        let token = &self.tokens[self.index];
2426        let err = match token.kind {
2427            TokenKind::Eof => ZuzuRustError::incomplete_parse(message, token.span),
2428            _ => ZuzuRustError::parse(message, token.span),
2429        };
2430        err.with_source_file(self.source_file.as_deref())
2431    }
2432}
2433
2434fn is_switch_comparator(value: &str) -> bool {
2435    matches!(
2436        value,
2437        ">" | "<"
2438            | ">="
2439            | "≤"
2440            | "<="
2441            | "≥"
2442            | "="
2443            | "!="
2444            | "≠"
2445            | "=="
2446            | "≡"
2447            | "≢"
2448            | "<=>"
2449            | "≶"
2450            | "≷"
2451            | "eq"
2452            | "ne"
2453            | "gt"
2454            | "ge"
2455            | "lt"
2456            | "le"
2457            | "cmp"
2458            | "eqi"
2459            | "nei"
2460            | "gti"
2461            | "gei"
2462            | "lti"
2463            | "lei"
2464            | "cmpi"
2465            | "in"
2466            | "∈"
2467            | "∉"
2468            | "subsetof"
2469            | "⊂"
2470            | "supersetof"
2471            | "⊃"
2472            | "equivalentof"
2473            | "⊂⊃"
2474            | "instanceof"
2475            | "does"
2476            | "can"
2477            | "~"
2478            | "@?"
2479            | "∣"
2480            | "divides"
2481            | "∤"
2482    )
2483}
2484
2485fn token_text(kind: &TokenKind) -> String {
2486    match kind {
2487        TokenKind::Keyword(value) => (*value).to_owned(),
2488        TokenKind::Identifier(value) => value.clone(),
2489        TokenKind::Number(value) => value.clone(),
2490        TokenKind::String(value) => value.clone(),
2491        TokenKind::BinaryString(bytes) => String::from_utf8_lossy(bytes).into_owned(),
2492        TokenKind::Regex { pattern, flags, .. } => format!("/{pattern}/{flags}"),
2493        TokenKind::Template(_) => "<template>".to_owned(),
2494        TokenKind::Operator(value) => value.clone(),
2495        TokenKind::Punct(value) => value.to_string(),
2496        TokenKind::Eof => "<eof>".to_owned(),
2497    }
2498}
2499
2500fn chain_direction(operator: &str) -> Option<&'static str> {
2501    match operator {
2502        "▷" | "|>" => Some("right"),
2503        "◁" | "<|" => Some("left"),
2504        _ => None,
2505    }
2506}
2507
2508fn expression_chain_direction(expression: &Expression) -> Option<&'static str> {
2509    match expression {
2510        Expression::Binary { operator, .. } => chain_direction(operator),
2511        _ => None,
2512    }
2513}
2514
2515fn statement_supports_postfix_condition(statement: &Statement) -> bool {
2516    matches!(
2517        statement,
2518        Statement::ExpressionStatement(_)
2519            | Statement::ReturnStatement(_)
2520            | Statement::LoopControlStatement(_)
2521            | Statement::ThrowStatement(_)
2522            | Statement::DieStatement(_)
2523            | Statement::KeywordStatement(_)
2524    )
2525}
2526
2527fn statement_needs_separator(statement: &Statement) -> bool {
2528    matches!(
2529        statement,
2530        Statement::VariableDeclaration(_)
2531            | Statement::VariableUnpackDeclaration(_)
2532            | Statement::ImportDeclaration(_)
2533            | Statement::ReturnStatement(_)
2534            | Statement::LoopControlStatement(_)
2535            | Statement::ThrowStatement(_)
2536            | Statement::DieStatement(_)
2537            | Statement::KeywordStatement(_)
2538            | Statement::ExpressionStatement(_)
2539    )
2540}