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