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 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 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}