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