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