Skip to main content

lisette_syntax/parse/
expressions.rs

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; // Start from the name, not the brace
243
244        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 // meaningless fallback
466            }
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(); // consume `mut`
812            (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(); // consume `else`
827            (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}