1use ecow::EcoString;
2
3use super::{MAX_TUPLE_ARITY, ParseError, Parser};
4use crate::ast::{
5 Annotation, Attribute, BinaryOperator, Binding, Expression, FormatStringPart, ImportAlias,
6 Literal, SelectArm, SelectArmPattern, Span, StructFieldAssignment, UnaryOperator, Visibility,
7};
8use crate::lex::TokenKind::{self, *};
9use crate::types::Type;
10
11impl<'source> Parser<'source> {
12 pub fn parse_expression(&mut self) -> Expression {
13 if !self.enter_recursion() {
14 let span = self.span_from_token(self.current_token());
15 self.resync_on_error();
16 return Expression::Unit {
17 ty: Type::uninferred(),
18 span,
19 };
20 }
21 let result = self.pratt_parse(0);
22 self.leave_recursion();
23 result
24 }
25
26 pub fn parse_atomic_expression(&mut self) -> Expression {
27 if self.keyword_in_value_position() {
28 return self.recover_keyword_as_identifier();
29 }
30
31 match self.current_token().kind {
32 Integer | Imaginary | Boolean | Char | String | Float => self.parse_literal(),
33 FormatStringStart => self.parse_format_string(),
34 LeftParen => self.parse_parenthesized_expression(),
35 LeftCurlyBrace => self.parse_block_expression(),
36 LeftSquareBracket => self.parse_slice_literal(),
37 Identifier => self.parse_identifier(),
38 Function => self.parse_function(None, vec![]),
39 Match => self.parse_match(),
40 If => self.parse_if(),
41 Pipe | PipeDouble => self.parse_lambda(),
42 Task => self.parse_task(),
43 Defer => self.parse_defer(),
44 Try => self.parse_try_block(),
45 Recover => self.parse_recover_block(),
46 Select => self.parse_select(),
47 Loop => self.parse_loop(),
48 Return => self.parse_return(),
49 Break => self.parse_break(),
50 Continue => self.parse_continue(),
51 DotDot | DotDotEqual => self.parse_range(None, self.current_token()),
52
53 LeftAngleBracket
54 if self.stream.peek_ahead(1).kind == Minus
55 && self.current_token().byte_offset + self.current_token().byte_length
56 == self.stream.peek_ahead(1).byte_offset =>
57 {
58 let start = self.current_token();
59 let span = Span::new(self.file_id, start.byte_offset, start.byte_length + 1);
60 self.track_error_at(
61 span,
62 "invalid syntax for channel receive",
63 "Use `select { let v = ch.receive() => ... }` to receive from a channel",
64 );
65 self.resync_on_error();
66 Expression::Unit {
67 ty: Type::uninferred(),
68 span,
69 }
70 }
71
72 _ => self.unexpected_token("expr"),
73 }
74 }
75
76 pub fn parse_range(
77 &mut self,
78 start: Option<Box<Expression>>,
79 span_start: crate::lex::Token<'source>,
80 ) -> Expression {
81 if matches!(start.as_deref(), Some(Expression::Range { .. })) {
82 self.track_error("not allowed", "Chained range operators are not supported");
83 }
84
85 let inclusive = self.is(DotDotEqual);
86
87 self.next();
88
89 let has_end = !matches!(
90 self.current_token().kind,
91 RightCurlyBrace
92 | RightSquareBracket
93 | RightParen
94 | LeftCurlyBrace
95 | Semicolon
96 | Comma
97 | EOF
98 );
99
100 if inclusive && !has_end {
101 self.track_error(
102 "expected end value",
103 "Inclusive ranges require an end value.",
104 );
105 }
106
107 let end = if has_end {
108 Some(Box::new(self.parse_range_end()))
109 } else {
110 None
111 };
112
113 Expression::Range {
114 start,
115 end,
116 inclusive,
117 ty: Type::uninferred(),
118 span: self.span_from_tokens(span_start),
119 }
120 }
121
122 fn parse_literal(&mut self) -> Expression {
123 let start = self.current_token();
124
125 let literal = match self.current_token().kind {
126 Integer => {
127 let text = self.current_token().text;
128 let literal = self.parse_integer_text(text);
129 self.next();
130 literal
131 }
132 Float => {
133 let raw = self.current_token().text;
134 let cleaned = raw.replace('_', "");
135 let f: f64 = cleaned.parse().unwrap_or_else(|_| {
136 self.track_error(
137 format!("float literal '{}' is out of range", raw),
138 "Value must be a valid 64-bit floating point number.",
139 );
140 0.0
141 });
142 let text = if raw.contains('e') || raw.contains('E') || raw.contains('_') {
143 Some(raw.to_string())
144 } else {
145 None
146 };
147 self.next();
148 Literal::Float { value: f, text }
149 }
150 Imaginary => {
151 let text = self.current_token().text;
152 let coef: f64 = text[..text.len() - 1]
153 .replace('_', "")
154 .parse()
155 .unwrap_or_else(|_| {
156 self.track_error(
157 format!("imaginary literal '{}' is out of range", text),
158 "Value must be a valid 64-bit floating point number.",
159 );
160 0.0
161 });
162 self.next();
163 Literal::Imaginary(coef)
164 }
165 Boolean => {
166 let b = self.current_token().text == "true";
167 self.next();
168 Literal::Boolean(b)
169 }
170 String => {
171 let s = self.current_token().text;
172 self.next();
173 let s_stripped = if s.len() >= 2 && s.starts_with('"') && s.ends_with('"') {
174 &s[1..s.len() - 1]
175 } else {
176 debug_assert!(false, "lexer produced String token without quotes: {:?}", s);
177 s
178 };
179 Literal::String(s_stripped.to_string())
180 }
181 Char => {
182 let c = self.current_token().text;
183 self.next();
184 let c_stripped = if c.len() >= 2 && c.starts_with('\'') && c.ends_with('\'') {
185 &c[1..c.len() - 1]
186 } else {
187 debug_assert!(false, "lexer produced Char token without quotes: {:?}", c);
188 c
189 };
190 Literal::Char(c_stripped.to_string())
191 }
192 _ => return self.unexpected_token("literal"),
193 };
194
195 Expression::Literal {
196 literal,
197 ty: Type::uninferred(),
198 span: self.span_from_tokens(start),
199 }
200 }
201
202 fn parse_slice_literal(&mut self) -> Expression {
203 let start = self.current_token();
204 let (expressions, _) =
205 self.collect_delimited_expressions(LeftSquareBracket, RightSquareBracket);
206
207 Expression::Literal {
208 literal: Literal::Slice(expressions),
209 ty: Type::uninferred(),
210 span: self.span_from_tokens(start),
211 }
212 }
213
214 fn parse_identifier(&mut self) -> Expression {
215 let start = self.current_token();
216 let text = self.current_token().text;
217
218 if text == "go" {
219 let next = self.stream.peek_ahead(1).kind;
220 if next == LeftCurlyBrace || next == Identifier {
221 self.track_error(
222 "invalid syntax",
223 "Use `task { ... }` or `task my_function()` to spawn a concurrent task.",
224 );
225 }
226 }
227
228 self.ensure(Identifier);
229
230 Expression::Identifier {
231 value: text.into(),
232 ty: Type::uninferred(),
233 span: self.span_from_tokens(start),
234 binding_id: None,
235 qualified: None,
236 }
237 }
238
239 pub fn parse_struct_call(&mut self, expression: Expression) -> Expression {
240 let name = self.make_expression_name(&expression);
241 let name_span = expression.get_span();
242 let start_offset = name_span.byte_offset; self.ensure(LeftCurlyBrace);
245
246 let mut field_assignments = vec![];
247 let mut spread = None;
248 let mut seen_fields: Vec<(EcoString, Span)> = vec![];
249
250 while self.is_not(RightCurlyBrace) {
251 if self.is(DotDot) {
252 if spread.is_some() {
253 self.track_error(
254 "spread must be last",
255 "Move the `..spread` to the end of the struct.",
256 );
257 break;
258 }
259
260 self.ensure(DotDot);
261
262 if self.is(RightCurlyBrace) || self.is(Comma) {
263 self.track_error(
264 "not allowed",
265 "Use `..struct` to spread the fields of one struct into another",
266 );
267 } else {
268 spread = Some(self.parse_expression());
269 }
270
271 self.expect_comma_or(RightCurlyBrace);
272 continue;
273 }
274
275 if spread.is_some() {
276 self.track_error(
277 "field after spread",
278 "The `..spread` must be the last element in a struct expression. Move explicit fields before the spread.",
279 );
280 break;
281 }
282
283 let field_name_token = self.current_token();
284 let field_name_span = self.span_from_token(field_name_token);
285 let field_name = self.read_identifier();
286
287 if let Some((_, first_span)) = seen_fields.iter().find(|(n, _)| n == &field_name) {
288 self.error_duplicate_struct_field(&field_name, *first_span, field_name_span);
289 } else {
290 seen_fields.push((field_name.clone(), field_name_span));
291 }
292
293 let field_value = if self.advance_if(Colon) {
294 self.parse_expression()
295 } else {
296 Expression::Identifier {
297 value: field_name.clone(),
298 ty: Type::uninferred(),
299 span: self.span_from_tokens(field_name_token),
300 binding_id: None,
301 qualified: None,
302 }
303 };
304
305 field_assignments.push(StructFieldAssignment {
306 name: field_name,
307 name_span: field_name_span,
308 value: Box::new(field_value),
309 });
310
311 self.expect_comma_or(RightCurlyBrace);
312 }
313
314 self.ensure(RightCurlyBrace);
315
316 Expression::StructCall {
317 ty: Type::uninferred(),
318 name,
319 field_assignments,
320 spread: spread.into(),
321 span: self.span_from_offset(start_offset),
322 }
323 }
324
325 pub fn parse_index_expression(&mut self, expression: Expression) -> Expression {
326 let start = self.current_token();
327
328 self.ensure(LeftSquareBracket);
329
330 let index = self.parse_expression();
331
332 self.ensure(RightSquareBracket);
333
334 Expression::IndexedAccess {
335 ty: Type::uninferred(),
336 expression: expression.into(),
337 index: index.into(),
338 span: self.span_from_tokens(start),
339 }
340 }
341
342 pub fn parse_function_call(
343 &mut self,
344 expression: Expression,
345 type_args: Vec<Annotation>,
346 ) -> Expression {
347 let start_offset = expression.get_span().byte_offset;
348 let (args, spread) = self.collect_call_args();
349
350 Expression::Call {
351 ty: Type::uninferred(),
352 expression: expression.into(),
353 args,
354 spread: spread.into(),
355 type_args,
356 span: self.span_from_offset(start_offset),
357 call_kind: None,
358 }
359 }
360
361 fn collect_call_args(&mut self) -> (Vec<Expression>, Option<Expression>) {
362 self.ensure(LeftParen);
363 let mut args = vec![];
364
365 while !self.at_eof() && !self.is(RightParen) {
366 if self.handle_fn_as_lambda_in_call(&mut args) {
367 continue;
368 }
369 if self.at_item_boundary()
370 && !matches!(self.stream.peek_ahead(1).kind, RightParen | Comma)
371 {
372 break;
373 }
374 if self.is(DotDot) {
375 return (args, Some(self.parse_spread_arg()));
376 }
377 args.push(self.parse_expression());
378 self.expect_comma_or(RightParen);
379 }
380
381 self.advance_if(RightParen);
382 (args, None)
383 }
384
385 fn handle_fn_as_lambda_in_call(&mut self, args: &mut Vec<Expression>) -> bool {
386 if !(self.is(Function) && self.stream.peek_ahead(1).kind == LeftParen) {
387 return false;
388 }
389 let start = self.current_token();
390 let span = Span::new(self.file_id, start.byte_offset, start.byte_length + 1);
391 let error = ParseError::new("Syntax error", span, "expected a lambda")
392 .with_parse_code("fn_as_lambda")
393 .with_help("Use a lambda instead: `|x| x * 2`");
394 self.errors.push(error);
395 self.resync_on_error();
396 args.push(Expression::Unit {
397 ty: Type::uninferred(),
398 span,
399 });
400 true
401 }
402
403 fn parse_spread_arg(&mut self) -> Expression {
404 self.ensure(DotDot);
405 let spread = self.parse_expression();
406 self.expect_comma_or(RightParen);
407 if !self.is(RightParen) && !self.at_eof() {
408 self.track_error(
409 "argument after spread",
410 "The `..spread` must be the last argument in the call.",
411 );
412 while !self.at_eof() && !self.is(RightParen) {
413 self.next();
414 }
415 }
416 self.advance_if(RightParen);
417 spread
418 }
419
420 pub fn parse_type_args(&mut self) -> Vec<Annotation> {
421 self.ensure(LeftAngleBracket);
422
423 let mut type_args = vec![];
424
425 loop {
426 if self.at_eof() {
427 break;
428 }
429
430 type_args.push(self.parse_annotation());
431
432 if self.is(RightAngleBracket) {
433 break;
434 }
435
436 self.ensure(Comma);
437 }
438
439 self.ensure(RightAngleBracket);
440
441 type_args
442 }
443
444 pub fn parse_binary_operator(&mut self) -> BinaryOperator {
445 let operator = match self.current_token().kind {
446 Plus => BinaryOperator::Addition,
447 Minus => BinaryOperator::Subtraction,
448 Star => BinaryOperator::Multiplication,
449 Slash => BinaryOperator::Division,
450 LeftAngleBracket => BinaryOperator::LessThan,
451 LessThanOrEqual => BinaryOperator::LessThanOrEqual,
452 RightAngleBracket => BinaryOperator::GreaterThan,
453 GreaterThanOrEqual => BinaryOperator::GreaterThanOrEqual,
454 Percent => BinaryOperator::Remainder,
455 EqualDouble => BinaryOperator::Equal,
456 NotEqual => BinaryOperator::NotEqual,
457 AmpersandDouble => BinaryOperator::And,
458 PipeDouble => BinaryOperator::Or,
459 Pipeline => BinaryOperator::Pipeline,
460
461 _ => {
462 self.track_error(format!(
463 "expected binary operator, found {}",
464 self.current_token().kind
465 ), "Binary operators: `+`, `-`, `*`, `/`, `%`, `==`, `!=`, `<`, `>`, `<=`, `>=`, `&&`, `||`.");
466 BinaryOperator::Addition }
468 };
469
470 self.next();
471
472 operator
473 }
474
475 fn parse_parenthesized_expression(&mut self) -> Expression {
476 let start = self.current_token();
477
478 let (expressions, has_trailing_comma) =
479 self.collect_delimited_expressions(LeftParen, RightParen);
480 let span = self.span_from_tokens(start);
481
482 match expressions.len() {
483 0 => Expression::Unit {
484 ty: Type::uninferred(),
485 span,
486 },
487 1 => {
488 if has_trailing_comma {
489 self.error_tuple_arity(1, span);
490 }
491 let expression = expressions.into_iter().next().expect("len is 1");
492 Expression::Paren {
493 ty: Type::uninferred(),
494 expression: expression.into(),
495 span,
496 }
497 }
498 n => {
499 if n > MAX_TUPLE_ARITY {
500 self.error_tuple_arity(n, span);
501 }
502 Expression::Tuple {
503 ty: Type::uninferred(),
504 elements: expressions,
505 span,
506 }
507 }
508 }
509 }
510
511 pub fn parse_try(&mut self, expression: Expression) -> Expression {
512 let start_offset = expression.get_span().byte_offset;
513
514 self.ensure(QuestionMark);
515
516 Expression::Propagate {
517 ty: Type::uninferred(),
518 expression: expression.into(),
519 span: self.span_from_offset(start_offset),
520 }
521 }
522
523 fn parse_lambda(&mut self) -> Expression {
524 let start = self.current_token();
525
526 let params = if self.is(Pipe) {
527 self.parse_lambda_params()
528 } else {
529 self.next();
530 vec![]
531 };
532
533 let has_return_type = self.is(Arrow);
534 let return_annotation = if has_return_type {
535 self.next();
536 self.parse_annotation()
537 } else {
538 Annotation::Unknown
539 };
540
541 if has_return_type && self.current_token().kind != LeftCurlyBrace {
542 self.track_error(
543 "not allowed",
544 "A lambda with a return type requires a block body",
545 );
546 }
547
548 let body = self.parse_expression();
549
550 Expression::Lambda {
551 params,
552 return_annotation,
553 body: body.into(),
554 ty: Type::uninferred(),
555 span: self.span_from_tokens(start),
556 }
557 }
558
559 pub fn parse_block_expression(&mut self) -> Expression {
560 let start = self.current_token();
561
562 self.ensure(LeftCurlyBrace);
563
564 if !self.enter_recursion() {
565 let span = self.span_from_token(self.current_token());
566 let mut brace_depth = 1u32;
567 while brace_depth > 0 && !self.at_eof() {
568 match self.current_token().kind {
569 LeftCurlyBrace => brace_depth += 1,
570 RightCurlyBrace => brace_depth -= 1,
571 _ => {}
572 }
573 if brace_depth > 0 {
574 self.next();
575 }
576 }
577 self.advance_if(RightCurlyBrace);
578 return Expression::Block {
579 ty: Type::uninferred(),
580 items: vec![],
581 span,
582 };
583 }
584
585 let mut items = vec![];
586
587 while self.is_not(RightCurlyBrace) && !self.too_many_errors() {
588 let position = self.position();
589 let item = self.parse_block_item();
590
591 self.advance_if(Semicolon);
592
593 items.push(item);
594 if self.position() == position {
595 self.next();
596 }
597 }
598
599 let span = self.close_brace_span(start, start);
600
601 self.leave_recursion();
602
603 Expression::Block {
604 ty: Type::uninferred(),
605 items,
606 span,
607 }
608 }
609
610 pub fn parse_function_params(&mut self) -> Vec<Binding> {
611 self.ensure(LeftParen);
612
613 let mut params = vec![];
614
615 while self.is_not(RightParen) {
616 params.push(self.parse_binding_with_type());
617 self.expect_comma_or(RightParen);
618 }
619
620 self.ensure(RightParen);
621
622 params
623 }
624
625 pub fn parse_lambda_params(&mut self) -> Vec<Binding> {
626 self.ensure(Pipe);
627
628 let mut params = vec![];
629
630 while self.is_not(Pipe) {
631 params.push(self.parse_binding());
632 self.expect_comma_or(Pipe);
633 }
634
635 self.ensure(Pipe);
636
637 params
638 }
639
640 pub fn parse_function(
641 &mut self,
642 doc: Option<std::string::String>,
643 attributes: Vec<Attribute>,
644 ) -> Expression {
645 let start = self.current_token();
646
647 self.ensure(Function);
648
649 let name_token = self.current_token();
650 let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
651
652 let name = self.read_identifier_sequence();
653
654 let name_span = Span::new(name_span.file_id, name_span.byte_offset, name.len() as u32);
655
656 let generics = self.parse_generics();
657 let params = self.parse_function_params();
658 let return_annotation = self.parse_function_return_annotation();
659
660 let body = if self.is(LeftCurlyBrace) {
661 self.parse_block_expression()
662 } else {
663 Expression::NoOp
664 };
665
666 Expression::Function {
667 doc,
668 attributes,
669 name,
670 name_span,
671 generics,
672 params,
673 return_annotation,
674 return_type: Type::uninferred(),
675 visibility: Visibility::Private,
676 body: body.into(),
677 ty: Type::uninferred(),
678 span: self.span_from_tokens(start),
679 }
680 }
681
682 pub fn parse_field_access(&mut self, expression: Expression) -> Expression {
683 self.ensure(Dot);
684
685 let expression_start = expression.get_span().byte_offset;
686 let start = self.current_token();
687
688 if self.advance_if(Star) {
689 return Expression::Unary {
690 ty: Type::uninferred(),
691 operator: UnaryOperator::Deref,
692 expression: expression.into(),
693 span: self.span_from_tokens(start),
694 };
695 }
696
697 if self.is(Integer) {
698 let text = self.current_token().text;
699 let index: u32 = text.parse().unwrap_or_else(|_| {
700 self.track_error(
701 format!("tuple index '{}' is too large", text),
702 "Maximum index is `4294967295`.",
703 );
704 0
705 });
706
707 self.ensure(Integer);
708
709 return Expression::DotAccess {
710 ty: Type::uninferred(),
711 expression: expression.into(),
712 member: index.to_string().into(),
713 span: self.span_from_offset(expression_start),
714 dot_access_kind: None,
715 receiver_coercion: None,
716 };
717 }
718
719 let field = self.current_token().text;
720
721 self.ensure(Identifier);
722
723 Expression::DotAccess {
724 ty: Type::uninferred(),
725 expression: expression.into(),
726 member: field.into(),
727 span: self.span_from_offset(expression_start),
728 dot_access_kind: None,
729 receiver_coercion: None,
730 }
731 }
732
733 pub fn collect_delimited_expressions(
734 &mut self,
735 open: TokenKind,
736 close: TokenKind,
737 ) -> (Vec<Expression>, bool) {
738 self.ensure(open);
739
740 let mut expressions = vec![];
741 let mut has_trailing_comma = false;
742 loop {
743 if self.at_eof() || self.is(close) {
744 break;
745 }
746
747 if self.is(Function) && self.stream.peek_ahead(1).kind == LeftParen {
748 let start = self.current_token();
749 let span = Span::new(self.file_id, start.byte_offset, start.byte_length + 1);
750 let error = ParseError::new("Syntax error", span, "expected a lambda")
751 .with_parse_code("fn_as_lambda")
752 .with_help("Use a lambda instead: `|x| x * 2`");
753 self.errors.push(error);
754 self.resync_on_error();
755 expressions.push(Expression::Unit {
756 ty: Type::uninferred(),
757 span,
758 });
759 continue;
760 }
761
762 if self.at_item_boundary() {
763 let next = self.stream.peek_ahead(1).kind;
764 if next != close && next != Comma {
765 break;
766 }
767 }
768 expressions.push(self.parse_expression());
769 has_trailing_comma = self.is(Comma);
770 self.expect_comma_or(close);
771 }
772
773 self.advance_if(close);
774
775 (expressions, has_trailing_comma)
776 }
777
778 fn make_expression_name(&mut self, expression: &Expression) -> EcoString {
779 let mut parts = Vec::new();
780 let mut current = expression;
781
782 loop {
783 match current {
784 Expression::Identifier { value, .. } => {
785 parts.push(value.clone());
786 break;
787 }
788 Expression::DotAccess {
789 expression, member, ..
790 } => {
791 parts.push(member.clone());
792 current = expression;
793 }
794 _ => {
795 self.track_error(
796 "unexpected expression",
797 "Expected an identifier or dotted path.",
798 );
799 return "_".into();
800 }
801 }
802 }
803
804 parts.reverse();
805 parts.join(".").into()
806 }
807
808 pub fn parse_let(&mut self) -> Expression {
809 let start = self.current_token();
810
811 self.ensure(Let);
812
813 let (mutable, mut_span) = if self.is(Mut) {
814 let mut_token = self.current_token();
815 let span = Span::new(self.file_id, mut_token.byte_offset, mut_token.byte_length);
816 self.next(); (true, Some(span))
818 } else {
819 (false, None)
820 };
821
822 let binding = self.parse_binding_allowing_or();
823
824 self.ensure(Equal);
825
826 let expression = self.parse_expression();
827
828 let (else_block, else_span) = if self.is(Else) {
829 let else_token = self.current_token();
830 let span = Span::new(self.file_id, else_token.byte_offset, else_token.byte_length);
831 self.next(); (Some(Box::new(self.parse_block_expression())), Some(span))
833 } else {
834 (None, None)
835 };
836
837 Expression::Let {
838 binding: Box::new(binding),
839 value: expression.into(),
840 mutable,
841 mut_span,
842 else_block,
843 else_span,
844 typed_pattern: None,
845 ty: Type::uninferred(),
846 span: self.span_from_tokens(start),
847 }
848 }
849
850 pub fn parse_import(&mut self) -> Expression {
851 let start = self.current_token();
852
853 self.ensure(Import);
854
855 let alias = if self.current_token().kind == Identifier {
856 let alias_token = self.current_token();
857 let alias_text = alias_token.text;
858 let alias_span = Span::new(
859 self.file_id,
860 alias_token.byte_offset,
861 alias_token.byte_length,
862 );
863
864 if alias_text == "_" {
865 self.next();
866 Some(ImportAlias::Blank(alias_span))
867 } else if self.stream.peek_ahead(1).kind == String {
868 self.next();
869 Some(ImportAlias::Named(alias_text.into(), alias_span))
870 } else {
871 None
872 }
873 } else {
874 None
875 };
876
877 let name_token = self.current_token();
878
879 if name_token.kind != String {
880 let (label, help) = if name_token.kind == Identifier
881 && self.stream.peek_ahead(1).kind == Colon
882 {
883 let module_name = name_token.text;
884 (
885 "expected double quotes".to_string(),
886 format!(
887 "Wrap the import path in double quotes: `import \"{0}:...\"`",
888 module_name
889 ),
890 )
891 } else if name_token.kind == Identifier {
892 let module_name = name_token.text;
893 (
894 "expected double quotes".to_string(),
895 format!(
896 "Wrap the import path in double quotes: `import \"{}\"`",
897 module_name
898 ),
899 )
900 } else {
901 (
902 "expected module path".to_string(),
903 "Wrap the import path in double quotes, e.g. `import \"go:os\"`".to_string(),
904 )
905 };
906
907 self.track_error(label, help);
908 self.resync_on_error();
909 return Expression::Unit {
910 ty: Type::uninferred(),
911 span: self.span_from_tokens(start),
912 };
913 }
914
915 self.next();
916
917 let raw = name_token.text;
918 let name: EcoString = if raw.len() >= 2 && raw.starts_with('"') && raw.ends_with('"') {
919 raw[1..raw.len() - 1].into()
920 } else {
921 debug_assert!(
922 false,
923 "lexer produced String token without quotes: {:?}",
924 raw
925 );
926 raw.into()
927 };
928 let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
929
930 Expression::ModuleImport {
931 name,
932 name_span,
933 alias,
934 span: self.span_from_tokens(start),
935 }
936 }
937
938 pub fn parse_assignment(&mut self) -> Expression {
939 let start = self.current_token();
940
941 let lhs = self.parse_expression();
942
943 let compound_operator = match self.current_token().kind {
944 PlusEqual => Some(BinaryOperator::Addition),
945 MinusEqual => Some(BinaryOperator::Subtraction),
946 StarEqual => Some(BinaryOperator::Multiplication),
947 SlashEqual => Some(BinaryOperator::Division),
948 PercentEqual => Some(BinaryOperator::Remainder),
949 _ => None,
950 };
951
952 if let Some(operator) = compound_operator {
953 if !self.is_valid_assignment_target(&lhs) {
954 self.track_error(
955 "invalid assignment target",
956 "Only variables, fields, and indices can be assigned to.",
957 );
958 }
959 self.next();
960 let rhs = self.parse_expression();
961 return Expression::Assignment {
962 target: lhs.clone().into(),
963 value: Expression::Binary {
964 left: lhs.into(),
965 operator,
966 right: rhs.into(),
967 ty: Type::uninferred(),
968 span: self.span_from_tokens(start),
969 }
970 .into(),
971 compound_operator: Some(operator),
972 span: self.span_from_tokens(start),
973 };
974 }
975
976 if self.current_token().kind == Colon && self.stream.peek_ahead(1).kind == Equal {
977 let span = Span::new(self.file_id, self.current_token().byte_offset, 2);
978 self.track_error_at(
979 span,
980 "Go-style short declaration",
981 "Use `let x = ...` instead of `:=` for variable declarations",
982 );
983 self.next();
984 self.next();
985 let _ = self.parse_expression();
986 return lhs;
987 }
988
989 if !self.is(Equal) {
990 return lhs;
991 }
992
993 if !self.is_valid_assignment_target(&lhs) {
994 self.track_error(
995 "invalid assignment target",
996 "Only variables, fields, and indices can be assigned to.",
997 );
998 }
999
1000 self.ensure(Equal);
1001
1002 Expression::Assignment {
1003 target: lhs.into(),
1004 value: self.parse_expression().into(),
1005 compound_operator: None,
1006 span: self.span_from_tokens(start),
1007 }
1008 }
1009
1010 fn is_valid_assignment_target(&self, expression: &Expression) -> bool {
1011 use Expression::*;
1012
1013 matches!(
1014 expression,
1015 Identifier { .. }
1016 | DotAccess { .. }
1017 | IndexedAccess { .. }
1018 | Unary {
1019 operator: UnaryOperator::Deref,
1020 ..
1021 }
1022 )
1023 }
1024
1025 fn parse_format_string(&mut self) -> Expression {
1026 let start = self.current_token();
1027 self.ensure(FormatStringStart);
1028
1029 let mut parts = Vec::new();
1030
1031 loop {
1032 if self.at_eof() || self.at_item_boundary() {
1033 break;
1034 }
1035 match self.current_token().kind {
1036 FormatStringText => {
1037 let text = self.current_token().text;
1038 self.next();
1039 parts.push(FormatStringPart::Text(text.to_string()));
1040 }
1041 FormatStringInterpolationStart => {
1042 self.ensure(FormatStringInterpolationStart);
1043 let expression = self.parse_expression();
1044 parts.push(FormatStringPart::Expression(Box::new(expression)));
1045 if self.is(Colon) {
1046 let start_offset = self.current_token().byte_offset;
1047 self.next();
1048 while !self.at_eof()
1049 && !self.is(FormatStringInterpolationEnd)
1050 && !self.is(FormatStringEnd)
1051 && !self.at_item_boundary()
1052 {
1053 self.next();
1054 }
1055 let span = self.span_from_offset(start_offset);
1056 let error = ParseError::new(
1057 "Format specifiers not supported",
1058 span,
1059 "not supported in format strings",
1060 )
1061 .with_parse_code("format_specifier")
1062 .with_help(
1063 "Use `fmt.Sprintf` for formatted output, e.g. `fmt.Sprintf(\"%02x\", n)`",
1064 );
1065 self.errors.push(error);
1066 }
1067 self.advance_if(FormatStringInterpolationEnd);
1068 }
1069 FormatStringEnd => {
1070 self.ensure(FormatStringEnd);
1071 break;
1072 }
1073 _ => break,
1074 }
1075 }
1076
1077 Expression::Literal {
1078 literal: Literal::FormatString(parts),
1079 ty: Type::uninferred(),
1080 span: self.span_from_tokens(start),
1081 }
1082 }
1083
1084 pub fn parse_task(&mut self) -> Expression {
1085 let start = self.current_token();
1086
1087 self.ensure(Task);
1088
1089 let expression = if self.is(LeftCurlyBrace) {
1090 self.parse_block_expression()
1091 } else {
1092 self.parse_expression()
1093 };
1094
1095 if !matches!(
1096 expression,
1097 Expression::Call { .. } | Expression::Block { .. }
1098 ) {
1099 let span = expression.get_span();
1100 let error = ParseError::new("Invalid `task`", span, "expected `()`")
1101 .with_parse_code("task_missing_parens")
1102 .with_help("Add parens to call the function");
1103
1104 self.errors.push(error);
1105 }
1106
1107 Expression::Task {
1108 expression: Box::new(expression),
1109 ty: Type::uninferred(),
1110 span: self.span_from_tokens(start),
1111 }
1112 }
1113
1114 pub fn parse_defer(&mut self) -> Expression {
1115 let start = self.current_token();
1116
1117 self.ensure(Defer);
1118
1119 let expression = if self.is(LeftCurlyBrace) {
1120 self.parse_block_expression()
1121 } else {
1122 self.parse_expression()
1123 };
1124
1125 if !matches!(
1126 expression,
1127 Expression::Call { .. } | Expression::Block { .. }
1128 ) {
1129 let span = expression.get_span();
1130 let error = ParseError::new("Invalid `defer`", span, "expected `()`")
1131 .with_parse_code("defer_missing_parens")
1132 .with_help("Add parens to call the function");
1133
1134 self.errors.push(error);
1135 }
1136
1137 Expression::Defer {
1138 expression: Box::new(expression),
1139 ty: Type::uninferred(),
1140 span: self.span_from_tokens(start),
1141 }
1142 }
1143
1144 pub fn parse_try_block(&mut self) -> Expression {
1145 let start = self.current_token();
1146 let try_keyword_span = Span::new(self.file_id, start.byte_offset, start.byte_length);
1147
1148 self.ensure(Try);
1149
1150 if !self.is(LeftCurlyBrace) {
1151 let span = self.span_from_tokens(start);
1152 let error = ParseError::new("Invalid `try`", span, "requires a block")
1153 .with_parse_code("syntax_error")
1154 .with_help("Use `try { expression }` instead of `try expression`");
1155 self.errors.push(error);
1156 let expression = self.parse_expression();
1157 return Expression::TryBlock {
1158 items: vec![expression],
1159 ty: Type::uninferred(),
1160 try_keyword_span,
1161 span: self.span_from_tokens(start),
1162 };
1163 }
1164
1165 let brace_token = self.current_token();
1166 self.ensure(LeftCurlyBrace);
1167
1168 if !self.enter_recursion() {
1169 let span = self.span_from_token(self.current_token());
1170 let mut brace_depth = 1u32;
1171 while brace_depth > 0 && !self.at_eof() {
1172 match self.current_token().kind {
1173 LeftCurlyBrace => brace_depth += 1,
1174 RightCurlyBrace => brace_depth -= 1,
1175 _ => {}
1176 }
1177 if brace_depth > 0 {
1178 self.next();
1179 }
1180 }
1181 self.advance_if(RightCurlyBrace);
1182 return Expression::TryBlock {
1183 items: vec![],
1184 ty: Type::uninferred(),
1185 try_keyword_span,
1186 span,
1187 };
1188 }
1189
1190 let mut items = vec![];
1191
1192 while self.is_not(RightCurlyBrace) && !self.too_many_errors() {
1193 let position = self.position();
1194 let item = self.parse_block_item();
1195
1196 self.advance_if(Semicolon);
1197
1198 items.push(item);
1199 if self.position() == position {
1200 self.next();
1201 }
1202 }
1203
1204 let span = self.close_brace_span(start, brace_token);
1205
1206 self.leave_recursion();
1207
1208 Expression::TryBlock {
1209 items,
1210 ty: Type::uninferred(),
1211 try_keyword_span,
1212 span,
1213 }
1214 }
1215
1216 pub fn parse_recover_block(&mut self) -> Expression {
1217 let start = self.current_token();
1218 let recover_keyword_span = Span::new(self.file_id, start.byte_offset, start.byte_length);
1219
1220 self.ensure(Recover);
1221
1222 if !self.is(LeftCurlyBrace) {
1223 let span = self.span_from_tokens(start);
1224 let error = ParseError::new("Invalid `recover`", span, "requires a block")
1225 .with_parse_code("syntax_error")
1226 .with_help("Use `recover { expression }` instead of `recover expression`");
1227 self.errors.push(error);
1228 let expression = self.parse_expression();
1229 return Expression::RecoverBlock {
1230 items: vec![expression],
1231 ty: Type::uninferred(),
1232 recover_keyword_span,
1233 span: self.span_from_tokens(start),
1234 };
1235 }
1236
1237 let brace_token = self.current_token();
1238 self.ensure(LeftCurlyBrace);
1239
1240 if !self.enter_recursion() {
1241 let span = self.span_from_token(self.current_token());
1242 let mut brace_depth = 1u32;
1243 while brace_depth > 0 && !self.at_eof() {
1244 match self.current_token().kind {
1245 LeftCurlyBrace => brace_depth += 1,
1246 RightCurlyBrace => brace_depth -= 1,
1247 _ => {}
1248 }
1249 if brace_depth > 0 {
1250 self.next();
1251 }
1252 }
1253 self.advance_if(RightCurlyBrace);
1254 return Expression::RecoverBlock {
1255 items: vec![],
1256 ty: Type::uninferred(),
1257 recover_keyword_span,
1258 span,
1259 };
1260 }
1261
1262 let mut items = vec![];
1263
1264 while self.is_not(RightCurlyBrace) && !self.too_many_errors() {
1265 let position = self.position();
1266 let item = self.parse_block_item();
1267
1268 self.advance_if(Semicolon);
1269
1270 items.push(item);
1271 if self.position() == position {
1272 self.next();
1273 }
1274 }
1275
1276 let span = self.close_brace_span(start, brace_token);
1277
1278 self.leave_recursion();
1279
1280 Expression::RecoverBlock {
1281 items,
1282 ty: Type::uninferred(),
1283 recover_keyword_span,
1284 span,
1285 }
1286 }
1287
1288 pub fn parse_select(&mut self) -> Expression {
1289 let start = self.current_token();
1290
1291 self.ensure(Select);
1292 self.ensure(LeftCurlyBrace);
1293
1294 let mut arms = Vec::new();
1295
1296 while self.is_not(RightCurlyBrace) {
1297 let arm = self.parse_select_arm();
1298 arms.push(arm);
1299
1300 if self.is(RightCurlyBrace) {
1301 break;
1302 }
1303
1304 self.ensure(Comma);
1305 }
1306
1307 self.ensure(RightCurlyBrace);
1308
1309 Expression::Select {
1310 arms,
1311 ty: Type::uninferred(),
1312 span: self.span_from_tokens(start),
1313 }
1314 }
1315
1316 fn parse_select_arm(&mut self) -> SelectArm {
1317 match self.current_token().kind {
1318 Let => {
1319 self.ensure(Let);
1320 let binding = self.parse_pattern();
1321 self.ensure(Equal);
1322 let receive_expression = Box::new(self.parse_expression());
1323 self.ensure(ArrowDouble);
1324 let body = Box::new(self.parse_expression());
1325 SelectArm {
1326 pattern: SelectArmPattern::Receive {
1327 binding: Box::new(binding),
1328 typed_pattern: None,
1329 receive_expression,
1330 body,
1331 },
1332 }
1333 }
1334 Match => {
1335 let match_expression = self.parse_match();
1336 if let Expression::Match { subject, arms, .. } = match_expression {
1337 SelectArm {
1338 pattern: SelectArmPattern::MatchReceive {
1339 receive_expression: subject,
1340 arms,
1341 },
1342 }
1343 } else {
1344 self.ensure(ArrowDouble);
1345 let body = Box::new(self.parse_expression());
1346 SelectArm {
1347 pattern: SelectArmPattern::Send {
1348 send_expression: Box::new(match_expression),
1349 body,
1350 },
1351 }
1352 }
1353 }
1354 Identifier if self.current_token().text == "_" => {
1355 self.next();
1356 self.ensure(ArrowDouble);
1357 let body = Box::new(self.parse_expression());
1358 SelectArm {
1359 pattern: SelectArmPattern::WildCard { body },
1360 }
1361 }
1362 _ => {
1363 let send_expression = Box::new(self.parse_expression());
1364 self.ensure(ArrowDouble);
1365 let body = Box::new(self.parse_expression());
1366 SelectArm {
1367 pattern: SelectArmPattern::Send {
1368 send_expression,
1369 body,
1370 },
1371 }
1372 }
1373 }
1374 }
1375
1376 pub fn with_control_flow_header<F, R>(&mut self, f: F) -> R
1377 where
1378 F: FnOnce(&mut Self) -> R,
1379 {
1380 let old = self.in_control_flow_header;
1381 self.in_control_flow_header = true;
1382 let result = f(self);
1383 self.in_control_flow_header = old;
1384 result
1385 }
1386
1387 fn keyword_in_value_position(&self) -> bool {
1388 if !self.current_token().kind.is_keyword() {
1389 return false;
1390 }
1391
1392 match self.current_token().kind {
1393 Return | Break | Continue => false,
1394
1395 Match | If | Task | Defer | Try | Recover | Select | Loop | Function => matches!(
1396 self.stream.peek_ahead(1).kind,
1397 RightParen
1398 | Comma
1399 | Dot
1400 | Semicolon
1401 | RightCurlyBrace
1402 | RightSquareBracket
1403 | ArrowDouble
1404 | QuestionMark
1405 | EOF
1406 | Plus
1407 | Star
1408 | Slash
1409 | Percent
1410 | EqualDouble
1411 | NotEqual
1412 | LeftAngleBracket
1413 | RightAngleBracket
1414 | LessThanOrEqual
1415 | GreaterThanOrEqual
1416 | AmpersandDouble
1417 | Pipeline
1418 | Equal
1419 | PlusEqual
1420 | MinusEqual
1421 | StarEqual
1422 | SlashEqual
1423 | PercentEqual
1424 | DotDot
1425 | DotDotEqual
1426 | As
1427 ),
1428
1429 _ => true,
1430 }
1431 }
1432
1433 fn recover_keyword_as_identifier(&mut self) -> Expression {
1434 let token = self.current_token();
1435 let keyword = token.text.to_string();
1436 let span = self.span_from_token(token);
1437 let error = ParseError::new("Reserved keyword", span, "reserved keyword")
1438 .with_parse_code("keyword_as_identifier")
1439 .with_help(format!("Rename `{}`", keyword));
1440 self.errors.push(error);
1441 self.next();
1442 Expression::Identifier {
1443 value: keyword.into(),
1444 ty: Type::uninferred(),
1445 span,
1446 binding_id: None,
1447 qualified: None,
1448 }
1449 }
1450}