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 }
358 }
359
360 fn collect_call_args(&mut self) -> (Vec<Expression>, Option<Expression>) {
361 self.ensure(LeftParen);
362 let mut args = vec![];
363
364 while !self.at_eof() && !self.is(RightParen) {
365 if self.handle_fn_as_lambda_in_call(&mut args) {
366 continue;
367 }
368 if self.at_item_boundary()
369 && !matches!(self.stream.peek_ahead(1).kind, RightParen | Comma)
370 {
371 break;
372 }
373 if self.is(DotDot) {
374 return (args, Some(self.parse_spread_arg()));
375 }
376 args.push(self.parse_expression());
377 self.expect_comma_or(RightParen);
378 }
379
380 self.advance_if(RightParen);
381 (args, None)
382 }
383
384 fn handle_fn_as_lambda_in_call(&mut self, args: &mut Vec<Expression>) -> bool {
385 if !(self.is(Function) && self.stream.peek_ahead(1).kind == LeftParen) {
386 return false;
387 }
388 let start = self.current_token();
389 let span = Span::new(self.file_id, start.byte_offset, start.byte_length + 1);
390 let error = ParseError::new("Syntax error", span, "expected a lambda")
391 .with_parse_code("fn_as_lambda")
392 .with_help("Use a lambda instead: `|x| x * 2`");
393 self.errors.push(error);
394 self.resync_on_error();
395 args.push(Expression::Unit {
396 ty: Type::uninferred(),
397 span,
398 });
399 true
400 }
401
402 fn parse_spread_arg(&mut self) -> Expression {
403 self.ensure(DotDot);
404 let spread = self.parse_expression();
405 self.expect_comma_or(RightParen);
406 if !self.is(RightParen) && !self.at_eof() {
407 self.track_error(
408 "argument after spread",
409 "The `..spread` must be the last argument in the call.",
410 );
411 while !self.at_eof() && !self.is(RightParen) {
412 self.next();
413 }
414 }
415 self.advance_if(RightParen);
416 spread
417 }
418
419 pub fn parse_type_args(&mut self) -> Vec<Annotation> {
420 self.ensure(LeftAngleBracket);
421
422 let mut type_args = vec![];
423
424 loop {
425 if self.at_eof() {
426 break;
427 }
428
429 type_args.push(self.parse_annotation());
430
431 if self.is(RightAngleBracket) {
432 break;
433 }
434
435 self.ensure(Comma);
436 }
437
438 self.ensure(RightAngleBracket);
439
440 type_args
441 }
442
443 pub fn parse_binary_operator(&mut self) -> BinaryOperator {
444 let operator = match self.current_token().kind {
445 Plus => BinaryOperator::Addition,
446 Minus => BinaryOperator::Subtraction,
447 Star => BinaryOperator::Multiplication,
448 Slash => BinaryOperator::Division,
449 LeftAngleBracket => BinaryOperator::LessThan,
450 LessThanOrEqual => BinaryOperator::LessThanOrEqual,
451 RightAngleBracket => BinaryOperator::GreaterThan,
452 GreaterThanOrEqual => BinaryOperator::GreaterThanOrEqual,
453 Percent => BinaryOperator::Remainder,
454 EqualDouble => BinaryOperator::Equal,
455 NotEqual => BinaryOperator::NotEqual,
456 AmpersandDouble => BinaryOperator::And,
457 PipeDouble => BinaryOperator::Or,
458 Pipeline => BinaryOperator::Pipeline,
459
460 _ => {
461 self.track_error(format!(
462 "expected binary operator, found {}",
463 self.current_token().kind
464 ), "Binary operators: `+`, `-`, `*`, `/`, `%`, `==`, `!=`, `<`, `>`, `<=`, `>=`, `&&`, `||`.");
465 BinaryOperator::Addition }
467 };
468
469 self.next();
470
471 operator
472 }
473
474 fn parse_parenthesized_expression(&mut self) -> Expression {
475 let start = self.current_token();
476
477 let (expressions, has_trailing_comma) =
478 self.collect_delimited_expressions(LeftParen, RightParen);
479 let span = self.span_from_tokens(start);
480
481 match expressions.len() {
482 0 => Expression::Unit {
483 ty: Type::uninferred(),
484 span,
485 },
486 1 => {
487 if has_trailing_comma {
488 self.error_tuple_arity(1, span);
489 }
490 let expression = expressions.into_iter().next().expect("len is 1");
491 Expression::Paren {
492 ty: Type::uninferred(),
493 expression: expression.into(),
494 span,
495 }
496 }
497 n => {
498 if n > MAX_TUPLE_ARITY {
499 self.error_tuple_arity(n, span);
500 }
501 Expression::Tuple {
502 ty: Type::uninferred(),
503 elements: expressions,
504 span,
505 }
506 }
507 }
508 }
509
510 pub fn parse_try(&mut self, expression: Expression) -> Expression {
511 let start_offset = expression.get_span().byte_offset;
512
513 self.ensure(QuestionMark);
514
515 Expression::Propagate {
516 ty: Type::uninferred(),
517 expression: expression.into(),
518 span: self.span_from_offset(start_offset),
519 }
520 }
521
522 fn parse_lambda(&mut self) -> Expression {
523 let start = self.current_token();
524
525 let params = if self.is(Pipe) {
526 self.parse_lambda_params()
527 } else {
528 self.next();
529 vec![]
530 };
531
532 let has_return_type = self.is(Arrow);
533 let return_annotation = if has_return_type {
534 self.next();
535 self.parse_annotation()
536 } else {
537 Annotation::Unknown
538 };
539
540 if has_return_type && self.current_token().kind != LeftCurlyBrace {
541 self.track_error(
542 "not allowed",
543 "A lambda with a return type requires a block body",
544 );
545 }
546
547 let body = self.parse_expression();
548
549 Expression::Lambda {
550 params,
551 return_annotation,
552 body: body.into(),
553 ty: Type::uninferred(),
554 span: self.span_from_tokens(start),
555 }
556 }
557
558 pub fn parse_block_expression(&mut self) -> Expression {
559 let start = self.current_token();
560
561 self.ensure(LeftCurlyBrace);
562
563 if !self.enter_recursion() {
564 let span = self.span_from_token(self.current_token());
565 let mut brace_depth = 1u32;
566 while brace_depth > 0 && !self.at_eof() {
567 match self.current_token().kind {
568 LeftCurlyBrace => brace_depth += 1,
569 RightCurlyBrace => brace_depth -= 1,
570 _ => {}
571 }
572 if brace_depth > 0 {
573 self.next();
574 }
575 }
576 self.advance_if(RightCurlyBrace);
577 return Expression::Block {
578 ty: Type::uninferred(),
579 items: vec![],
580 span,
581 };
582 }
583
584 let mut items = vec![];
585
586 while self.is_not(RightCurlyBrace) && !self.too_many_errors() {
587 let position = self.position();
588 let item = self.parse_block_item();
589
590 self.advance_if(Semicolon);
591
592 items.push(item);
593 if self.position() == position {
594 self.next();
595 }
596 }
597
598 let span = self.close_brace_span(start, start);
599
600 self.leave_recursion();
601
602 Expression::Block {
603 ty: Type::uninferred(),
604 items,
605 span,
606 }
607 }
608
609 pub fn parse_function_params(&mut self) -> Vec<Binding> {
610 self.ensure(LeftParen);
611
612 let mut params = vec![];
613
614 while self.is_not(RightParen) {
615 params.push(self.parse_binding_with_type());
616 self.expect_comma_or(RightParen);
617 }
618
619 self.ensure(RightParen);
620
621 params
622 }
623
624 pub fn parse_lambda_params(&mut self) -> Vec<Binding> {
625 self.ensure(Pipe);
626
627 let mut params = vec![];
628
629 while self.is_not(Pipe) {
630 params.push(self.parse_binding());
631 self.expect_comma_or(Pipe);
632 }
633
634 self.ensure(Pipe);
635
636 params
637 }
638
639 pub fn parse_function(
640 &mut self,
641 doc: Option<std::string::String>,
642 attributes: Vec<Attribute>,
643 ) -> Expression {
644 let start = self.current_token();
645
646 self.ensure(Function);
647
648 let name_token = self.current_token();
649 let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
650
651 let name = self.read_identifier_sequence();
652
653 let name_span = Span::new(name_span.file_id, name_span.byte_offset, name.len() as u32);
654
655 let generics = self.parse_generics();
656 let params = self.parse_function_params();
657 let return_annotation = self.parse_function_return_annotation();
658
659 let body = if self.is(LeftCurlyBrace) {
660 self.parse_block_expression()
661 } else {
662 Expression::NoOp
663 };
664
665 Expression::Function {
666 doc,
667 attributes,
668 name,
669 name_span,
670 generics,
671 params,
672 return_annotation,
673 return_type: Type::uninferred(),
674 visibility: Visibility::Private,
675 body: body.into(),
676 ty: Type::uninferred(),
677 span: self.span_from_tokens(start),
678 }
679 }
680
681 pub fn parse_field_access(&mut self, expression: Expression) -> Expression {
682 self.ensure(Dot);
683
684 let expression_start = expression.get_span().byte_offset;
685 let start = self.current_token();
686
687 if self.advance_if(Star) {
688 return Expression::Unary {
689 ty: Type::uninferred(),
690 operator: UnaryOperator::Deref,
691 expression: expression.into(),
692 span: self.span_from_tokens(start),
693 };
694 }
695
696 if self.is(Integer) {
697 let text = self.current_token().text;
698 let index: u32 = text.parse().unwrap_or_else(|_| {
699 self.track_error(
700 format!("tuple index '{}' is too large", text),
701 "Maximum index is `4294967295`.",
702 );
703 0
704 });
705
706 self.ensure(Integer);
707
708 return Expression::DotAccess {
709 ty: Type::uninferred(),
710 expression: expression.into(),
711 member: index.to_string().into(),
712 span: self.span_from_offset(expression_start),
713 };
714 }
715
716 let field = self.current_token().text;
717
718 self.ensure(Identifier);
719
720 Expression::DotAccess {
721 ty: Type::uninferred(),
722 expression: expression.into(),
723 member: field.into(),
724 span: self.span_from_offset(expression_start),
725 }
726 }
727
728 pub fn collect_delimited_expressions(
729 &mut self,
730 open: TokenKind,
731 close: TokenKind,
732 ) -> (Vec<Expression>, bool) {
733 self.ensure(open);
734
735 let mut expressions = vec![];
736 let mut has_trailing_comma = false;
737 loop {
738 if self.at_eof() || self.is(close) {
739 break;
740 }
741
742 if self.is(Function) && self.stream.peek_ahead(1).kind == LeftParen {
743 let start = self.current_token();
744 let span = Span::new(self.file_id, start.byte_offset, start.byte_length + 1);
745 let error = ParseError::new("Syntax error", span, "expected a lambda")
746 .with_parse_code("fn_as_lambda")
747 .with_help("Use a lambda instead: `|x| x * 2`");
748 self.errors.push(error);
749 self.resync_on_error();
750 expressions.push(Expression::Unit {
751 ty: Type::uninferred(),
752 span,
753 });
754 continue;
755 }
756
757 if self.at_item_boundary() {
758 let next = self.stream.peek_ahead(1).kind;
759 if next != close && next != Comma {
760 break;
761 }
762 }
763 expressions.push(self.parse_expression());
764 has_trailing_comma = self.is(Comma);
765 self.expect_comma_or(close);
766 }
767
768 self.advance_if(close);
769
770 (expressions, has_trailing_comma)
771 }
772
773 fn make_expression_name(&mut self, expression: &Expression) -> EcoString {
774 let mut parts = Vec::new();
775 let mut current = expression;
776
777 loop {
778 match current {
779 Expression::Identifier { value, .. } => {
780 parts.push(value.clone());
781 break;
782 }
783 Expression::DotAccess {
784 expression, member, ..
785 } => {
786 parts.push(member.clone());
787 current = expression;
788 }
789 _ => {
790 self.track_error(
791 "unexpected expression",
792 "Expected an identifier or dotted path.",
793 );
794 return "_".into();
795 }
796 }
797 }
798
799 parts.reverse();
800 parts.join(".").into()
801 }
802
803 pub fn parse_let(&mut self) -> Expression {
804 let start = self.current_token();
805
806 self.ensure(Let);
807
808 let (mutable, mut_span) = if self.is(Mut) {
809 let mut_token = self.current_token();
810 let span = Span::new(self.file_id, mut_token.byte_offset, mut_token.byte_length);
811 self.next(); (true, Some(span))
813 } else {
814 (false, None)
815 };
816
817 let binding = self.parse_binding_allowing_or();
818
819 self.ensure(Equal);
820
821 let expression = self.parse_expression();
822
823 let (else_block, else_span) = if self.is(Else) {
824 let else_token = self.current_token();
825 let span = Span::new(self.file_id, else_token.byte_offset, else_token.byte_length);
826 self.next(); (Some(Box::new(self.parse_block_expression())), Some(span))
828 } else {
829 (None, None)
830 };
831
832 Expression::Let {
833 binding: Box::new(binding),
834 value: expression.into(),
835 mutable,
836 mut_span,
837 else_block,
838 else_span,
839 typed_pattern: None,
840 ty: Type::uninferred(),
841 span: self.span_from_tokens(start),
842 }
843 }
844
845 pub fn parse_import(&mut self) -> Expression {
846 let start = self.current_token();
847
848 self.ensure(Import);
849
850 let alias = if self.current_token().kind == Identifier {
851 let alias_token = self.current_token();
852 let alias_text = alias_token.text;
853 let alias_span = Span::new(
854 self.file_id,
855 alias_token.byte_offset,
856 alias_token.byte_length,
857 );
858
859 if alias_text == "_" {
860 self.next();
861 Some(ImportAlias::Blank(alias_span))
862 } else if self.stream.peek_ahead(1).kind == String {
863 self.next();
864 Some(ImportAlias::Named(alias_text.into(), alias_span))
865 } else {
866 None
867 }
868 } else {
869 None
870 };
871
872 let name_token = self.current_token();
873
874 if name_token.kind != String {
875 let (label, help) = if name_token.kind == Identifier
876 && self.stream.peek_ahead(1).kind == Colon
877 {
878 let module_name = name_token.text;
879 (
880 "expected double quotes".to_string(),
881 format!(
882 "Wrap the import path in double quotes: `import \"{0}:...\"`",
883 module_name
884 ),
885 )
886 } else if name_token.kind == Identifier {
887 let module_name = name_token.text;
888 (
889 "expected double quotes".to_string(),
890 format!(
891 "Wrap the import path in double quotes: `import \"{}\"`",
892 module_name
893 ),
894 )
895 } else {
896 (
897 "expected module path".to_string(),
898 "Wrap the import path in double quotes, e.g. `import \"go:os\"`".to_string(),
899 )
900 };
901
902 self.track_error(label, help);
903 self.resync_on_error();
904 return Expression::Unit {
905 ty: Type::uninferred(),
906 span: self.span_from_tokens(start),
907 };
908 }
909
910 self.next();
911
912 let raw = name_token.text;
913 let name: EcoString = if raw.len() >= 2 && raw.starts_with('"') && raw.ends_with('"') {
914 raw[1..raw.len() - 1].into()
915 } else {
916 debug_assert!(
917 false,
918 "lexer produced String token without quotes: {:?}",
919 raw
920 );
921 raw.into()
922 };
923 let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
924
925 Expression::ModuleImport {
926 name,
927 name_span,
928 alias,
929 span: self.span_from_tokens(start),
930 }
931 }
932
933 pub fn parse_assignment(&mut self) -> Expression {
934 let start = self.current_token();
935
936 let lhs = self.parse_expression();
937
938 let compound_operator = match self.current_token().kind {
939 PlusEqual => Some(BinaryOperator::Addition),
940 MinusEqual => Some(BinaryOperator::Subtraction),
941 StarEqual => Some(BinaryOperator::Multiplication),
942 SlashEqual => Some(BinaryOperator::Division),
943 PercentEqual => Some(BinaryOperator::Remainder),
944 _ => None,
945 };
946
947 if let Some(operator) = compound_operator {
948 if !self.is_valid_assignment_target(&lhs) {
949 self.track_error(
950 "invalid assignment target",
951 "Only variables, fields, and indices can be assigned to.",
952 );
953 }
954 self.next();
955 let rhs = self.parse_expression();
956 return Expression::Assignment {
957 target: lhs.clone().into(),
958 value: Expression::Binary {
959 left: lhs.into(),
960 operator,
961 right: rhs.into(),
962 ty: Type::uninferred(),
963 span: self.span_from_tokens(start),
964 }
965 .into(),
966 compound_operator: Some(operator),
967 span: self.span_from_tokens(start),
968 };
969 }
970
971 if self.current_token().kind == Colon && self.stream.peek_ahead(1).kind == Equal {
972 let span = Span::new(self.file_id, self.current_token().byte_offset, 2);
973 self.track_error_at(
974 span,
975 "Go-style short declaration",
976 "Use `let x = ...` instead of `:=` for variable declarations",
977 );
978 self.next();
979 self.next();
980 let _ = self.parse_expression();
981 return lhs;
982 }
983
984 if !self.is(Equal) {
985 return lhs;
986 }
987
988 if !self.is_valid_assignment_target(&lhs) {
989 self.track_error(
990 "invalid assignment target",
991 "Only variables, fields, and indices can be assigned to.",
992 );
993 }
994
995 self.ensure(Equal);
996
997 Expression::Assignment {
998 target: lhs.into(),
999 value: self.parse_expression().into(),
1000 compound_operator: None,
1001 span: self.span_from_tokens(start),
1002 }
1003 }
1004
1005 fn is_valid_assignment_target(&self, expression: &Expression) -> bool {
1006 use Expression::*;
1007
1008 matches!(
1009 expression,
1010 Identifier { .. }
1011 | DotAccess { .. }
1012 | IndexedAccess { .. }
1013 | Unary {
1014 operator: UnaryOperator::Deref,
1015 ..
1016 }
1017 )
1018 }
1019
1020 fn parse_format_string(&mut self) -> Expression {
1021 let start = self.current_token();
1022 self.ensure(FormatStringStart);
1023
1024 let mut parts = Vec::new();
1025
1026 loop {
1027 if self.at_eof() || self.at_item_boundary() {
1028 break;
1029 }
1030 match self.current_token().kind {
1031 FormatStringText => {
1032 let text = self.current_token().text;
1033 self.next();
1034 parts.push(FormatStringPart::Text(text.to_string()));
1035 }
1036 FormatStringInterpolationStart => {
1037 self.ensure(FormatStringInterpolationStart);
1038 let expression = self.parse_expression();
1039 parts.push(FormatStringPart::Expression(Box::new(expression)));
1040 if self.is(Colon) {
1041 let start_offset = self.current_token().byte_offset;
1042 self.next();
1043 while !self.at_eof()
1044 && !self.is(FormatStringInterpolationEnd)
1045 && !self.is(FormatStringEnd)
1046 && !self.at_item_boundary()
1047 {
1048 self.next();
1049 }
1050 let span = self.span_from_offset(start_offset);
1051 let error = ParseError::new(
1052 "Format specifiers not supported",
1053 span,
1054 "not supported in format strings",
1055 )
1056 .with_parse_code("format_specifier")
1057 .with_help(
1058 "Use `fmt.Sprintf` for formatted output, e.g. `fmt.Sprintf(\"%02x\", n)`",
1059 );
1060 self.errors.push(error);
1061 }
1062 self.advance_if(FormatStringInterpolationEnd);
1063 }
1064 FormatStringEnd => {
1065 self.ensure(FormatStringEnd);
1066 break;
1067 }
1068 _ => break,
1069 }
1070 }
1071
1072 Expression::Literal {
1073 literal: Literal::FormatString(parts),
1074 ty: Type::uninferred(),
1075 span: self.span_from_tokens(start),
1076 }
1077 }
1078
1079 pub fn parse_task(&mut self) -> Expression {
1080 let start = self.current_token();
1081
1082 self.ensure(Task);
1083
1084 let expression = if self.is(LeftCurlyBrace) {
1085 self.parse_block_expression()
1086 } else {
1087 self.parse_expression()
1088 };
1089
1090 if !matches!(
1091 expression,
1092 Expression::Call { .. } | Expression::Block { .. }
1093 ) {
1094 let span = expression.get_span();
1095 let error = ParseError::new("Invalid `task`", span, "expected `()`")
1096 .with_parse_code("task_missing_parens")
1097 .with_help("Add parens to call the function");
1098
1099 self.errors.push(error);
1100 }
1101
1102 Expression::Task {
1103 expression: Box::new(expression),
1104 ty: Type::uninferred(),
1105 span: self.span_from_tokens(start),
1106 }
1107 }
1108
1109 pub fn parse_defer(&mut self) -> Expression {
1110 let start = self.current_token();
1111
1112 self.ensure(Defer);
1113
1114 let expression = if self.is(LeftCurlyBrace) {
1115 self.parse_block_expression()
1116 } else {
1117 self.parse_expression()
1118 };
1119
1120 if !matches!(
1121 expression,
1122 Expression::Call { .. } | Expression::Block { .. }
1123 ) {
1124 let span = expression.get_span();
1125 let error = ParseError::new("Invalid `defer`", span, "expected `()`")
1126 .with_parse_code("defer_missing_parens")
1127 .with_help("Add parens to call the function");
1128
1129 self.errors.push(error);
1130 }
1131
1132 Expression::Defer {
1133 expression: Box::new(expression),
1134 ty: Type::uninferred(),
1135 span: self.span_from_tokens(start),
1136 }
1137 }
1138
1139 pub fn parse_try_block(&mut self) -> Expression {
1140 let start = self.current_token();
1141 let try_keyword_span = Span::new(self.file_id, start.byte_offset, start.byte_length);
1142
1143 self.ensure(Try);
1144
1145 if !self.is(LeftCurlyBrace) {
1146 let span = self.span_from_tokens(start);
1147 let error = ParseError::new("Invalid `try`", span, "requires a block")
1148 .with_parse_code("syntax_error")
1149 .with_help("Use `try { expression }` instead of `try expression`");
1150 self.errors.push(error);
1151 let expression = self.parse_expression();
1152 return Expression::TryBlock {
1153 items: vec![expression],
1154 ty: Type::uninferred(),
1155 try_keyword_span,
1156 span: self.span_from_tokens(start),
1157 };
1158 }
1159
1160 let brace_token = self.current_token();
1161 self.ensure(LeftCurlyBrace);
1162
1163 if !self.enter_recursion() {
1164 let span = self.span_from_token(self.current_token());
1165 let mut brace_depth = 1u32;
1166 while brace_depth > 0 && !self.at_eof() {
1167 match self.current_token().kind {
1168 LeftCurlyBrace => brace_depth += 1,
1169 RightCurlyBrace => brace_depth -= 1,
1170 _ => {}
1171 }
1172 if brace_depth > 0 {
1173 self.next();
1174 }
1175 }
1176 self.advance_if(RightCurlyBrace);
1177 return Expression::TryBlock {
1178 items: vec![],
1179 ty: Type::uninferred(),
1180 try_keyword_span,
1181 span,
1182 };
1183 }
1184
1185 let mut items = vec![];
1186
1187 while self.is_not(RightCurlyBrace) && !self.too_many_errors() {
1188 let position = self.position();
1189 let item = self.parse_block_item();
1190
1191 self.advance_if(Semicolon);
1192
1193 items.push(item);
1194 if self.position() == position {
1195 self.next();
1196 }
1197 }
1198
1199 let span = self.close_brace_span(start, brace_token);
1200
1201 self.leave_recursion();
1202
1203 Expression::TryBlock {
1204 items,
1205 ty: Type::uninferred(),
1206 try_keyword_span,
1207 span,
1208 }
1209 }
1210
1211 pub fn parse_recover_block(&mut self) -> Expression {
1212 let start = self.current_token();
1213 let recover_keyword_span = Span::new(self.file_id, start.byte_offset, start.byte_length);
1214
1215 self.ensure(Recover);
1216
1217 if !self.is(LeftCurlyBrace) {
1218 let span = self.span_from_tokens(start);
1219 let error = ParseError::new("Invalid `recover`", span, "requires a block")
1220 .with_parse_code("syntax_error")
1221 .with_help("Use `recover { expression }` instead of `recover expression`");
1222 self.errors.push(error);
1223 let expression = self.parse_expression();
1224 return Expression::RecoverBlock {
1225 items: vec![expression],
1226 ty: Type::uninferred(),
1227 recover_keyword_span,
1228 span: self.span_from_tokens(start),
1229 };
1230 }
1231
1232 let brace_token = self.current_token();
1233 self.ensure(LeftCurlyBrace);
1234
1235 if !self.enter_recursion() {
1236 let span = self.span_from_token(self.current_token());
1237 let mut brace_depth = 1u32;
1238 while brace_depth > 0 && !self.at_eof() {
1239 match self.current_token().kind {
1240 LeftCurlyBrace => brace_depth += 1,
1241 RightCurlyBrace => brace_depth -= 1,
1242 _ => {}
1243 }
1244 if brace_depth > 0 {
1245 self.next();
1246 }
1247 }
1248 self.advance_if(RightCurlyBrace);
1249 return Expression::RecoverBlock {
1250 items: vec![],
1251 ty: Type::uninferred(),
1252 recover_keyword_span,
1253 span,
1254 };
1255 }
1256
1257 let mut items = vec![];
1258
1259 while self.is_not(RightCurlyBrace) && !self.too_many_errors() {
1260 let position = self.position();
1261 let item = self.parse_block_item();
1262
1263 self.advance_if(Semicolon);
1264
1265 items.push(item);
1266 if self.position() == position {
1267 self.next();
1268 }
1269 }
1270
1271 let span = self.close_brace_span(start, brace_token);
1272
1273 self.leave_recursion();
1274
1275 Expression::RecoverBlock {
1276 items,
1277 ty: Type::uninferred(),
1278 recover_keyword_span,
1279 span,
1280 }
1281 }
1282
1283 pub fn parse_select(&mut self) -> Expression {
1284 let start = self.current_token();
1285
1286 self.ensure(Select);
1287 self.ensure(LeftCurlyBrace);
1288
1289 let mut arms = Vec::new();
1290
1291 while self.is_not(RightCurlyBrace) {
1292 let arm = self.parse_select_arm();
1293 arms.push(arm);
1294
1295 if self.is(RightCurlyBrace) {
1296 break;
1297 }
1298
1299 self.ensure(Comma);
1300 }
1301
1302 self.ensure(RightCurlyBrace);
1303
1304 Expression::Select {
1305 arms,
1306 ty: Type::uninferred(),
1307 span: self.span_from_tokens(start),
1308 }
1309 }
1310
1311 fn parse_select_arm(&mut self) -> SelectArm {
1312 match self.current_token().kind {
1313 Let => {
1314 self.ensure(Let);
1315 let binding = self.parse_pattern();
1316 self.ensure(Equal);
1317 let receive_expression = Box::new(self.parse_expression());
1318 self.ensure(ArrowDouble);
1319 let body = Box::new(self.parse_expression());
1320 SelectArm {
1321 pattern: SelectArmPattern::Receive {
1322 binding: Box::new(binding),
1323 typed_pattern: None,
1324 receive_expression,
1325 body,
1326 },
1327 }
1328 }
1329 Match => {
1330 let match_expression = self.parse_match();
1331 if let Expression::Match { subject, arms, .. } = match_expression {
1332 SelectArm {
1333 pattern: SelectArmPattern::MatchReceive {
1334 receive_expression: subject,
1335 arms,
1336 },
1337 }
1338 } else {
1339 self.ensure(ArrowDouble);
1340 let body = Box::new(self.parse_expression());
1341 SelectArm {
1342 pattern: SelectArmPattern::Send {
1343 send_expression: Box::new(match_expression),
1344 body,
1345 },
1346 }
1347 }
1348 }
1349 Identifier if self.current_token().text == "_" => {
1350 self.next();
1351 self.ensure(ArrowDouble);
1352 let body = Box::new(self.parse_expression());
1353 SelectArm {
1354 pattern: SelectArmPattern::WildCard { body },
1355 }
1356 }
1357 _ => {
1358 let send_expression = Box::new(self.parse_expression());
1359 self.ensure(ArrowDouble);
1360 let body = Box::new(self.parse_expression());
1361 SelectArm {
1362 pattern: SelectArmPattern::Send {
1363 send_expression,
1364 body,
1365 },
1366 }
1367 }
1368 }
1369 }
1370
1371 pub fn with_control_flow_header<F, R>(&mut self, f: F) -> R
1372 where
1373 F: FnOnce(&mut Self) -> R,
1374 {
1375 let old = self.in_control_flow_header;
1376 self.in_control_flow_header = true;
1377 let result = f(self);
1378 self.in_control_flow_header = old;
1379 result
1380 }
1381
1382 fn keyword_in_value_position(&self) -> bool {
1383 if !self.current_token().kind.is_keyword() {
1384 return false;
1385 }
1386
1387 match self.current_token().kind {
1388 Return | Break | Continue => false,
1389
1390 Match | If | Task | Defer | Try | Recover | Select | Loop | Function => matches!(
1391 self.stream.peek_ahead(1).kind,
1392 RightParen
1393 | Comma
1394 | Dot
1395 | Semicolon
1396 | RightCurlyBrace
1397 | RightSquareBracket
1398 | ArrowDouble
1399 | QuestionMark
1400 | EOF
1401 | Plus
1402 | Star
1403 | Slash
1404 | Percent
1405 | EqualDouble
1406 | NotEqual
1407 | LeftAngleBracket
1408 | RightAngleBracket
1409 | LessThanOrEqual
1410 | GreaterThanOrEqual
1411 | AmpersandDouble
1412 | Pipeline
1413 | Equal
1414 | PlusEqual
1415 | MinusEqual
1416 | StarEqual
1417 | SlashEqual
1418 | PercentEqual
1419 | DotDot
1420 | DotDotEqual
1421 | As
1422 ),
1423
1424 _ => true,
1425 }
1426 }
1427
1428 fn recover_keyword_as_identifier(&mut self) -> Expression {
1429 let token = self.current_token();
1430 let keyword = token.text.to_string();
1431 let span = self.span_from_token(token);
1432 let error = ParseError::new("Reserved keyword", span, "reserved keyword")
1433 .with_parse_code("keyword_as_identifier")
1434 .with_help(format!("Rename `{}`", keyword));
1435 self.errors.push(error);
1436 self.next();
1437 Expression::Identifier {
1438 value: keyword.into(),
1439 ty: Type::uninferred(),
1440 span,
1441 binding_id: None,
1442 qualified: None,
1443 }
1444 }
1445}