1use ecow::EcoString;
2
3use super::strings::cook_string_contents;
4use super::{MAX_TUPLE_ARITY, ParseError, Parser};
5use crate::ast::{
6 Annotation, Attribute, BinaryOperator, Binding, Expression, FormatStringPart, ImportAlias,
7 Literal, SelectArm, SelectArmPattern, Span, StructFieldAssignment, StructSpread, UnaryOperator,
8 Visibility,
9};
10use crate::lex::TokenKind::{self, *};
11use crate::types::Type;
12
13impl<'source> Parser<'source> {
14 pub fn parse_expression(&mut self) -> Expression {
15 if !self.enter_recursion() {
16 let span = self.span_from_token(self.current_token());
17 self.resync_on_error();
18 return Expression::Unit {
19 ty: Type::uninferred(),
20 span,
21 };
22 }
23 let result = self.pratt_parse(0);
24 self.leave_recursion();
25 result
26 }
27
28 pub fn parse_atomic_expression(&mut self) -> Expression {
29 if self.keyword_in_value_position() {
30 return self.recover_keyword_as_identifier();
31 }
32
33 match self.current_token().kind {
34 Integer | Imaginary | Boolean | Char | String | RawString | Float => {
35 self.parse_literal()
36 }
37 FormatStringStart => self.parse_format_string(),
38 LeftParen => self.parse_parenthesized_expression(),
39 LeftCurlyBrace => self.parse_block_expression(),
40 LeftSquareBracket => self.parse_slice_literal(),
41 Identifier => self.parse_identifier(),
42 Function => self.parse_function(None, vec![]),
43 Match => self.parse_match(),
44 If => self.parse_if(),
45 Pipe | PipeDouble => self.parse_lambda(),
46 Task => self.parse_task(),
47 Defer => self.parse_defer(),
48 Try => self.parse_try_block(),
49 Recover => self.parse_recover_block(),
50 Select => self.parse_select(),
51 Loop => self.parse_loop(),
52 Return => self.parse_return(),
53 Break => self.parse_break(),
54 Continue => self.parse_continue(),
55 DotDot | DotDotEqual => self.parse_range(None, self.current_token()),
56
57 LeftAngleBracket
58 if self.stream.peek_ahead(1).kind == Minus
59 && self.current_token().byte_offset + self.current_token().byte_length
60 == self.stream.peek_ahead(1).byte_offset =>
61 {
62 let start = self.current_token();
63 let span = Span::new(self.file_id, start.byte_offset, start.byte_length + 1);
64 self.track_error_at(
65 span,
66 "invalid syntax for channel receive",
67 "Use `select { let v = ch.receive() => ... }` to receive from a channel",
68 );
69 self.resync_on_error();
70 Expression::Unit {
71 ty: Type::uninferred(),
72 span,
73 }
74 }
75
76 Backtick => self.recover_unexpected_backtick(),
77
78 _ => self.unexpected_token("expr"),
79 }
80 }
81
82 pub fn parse_range(
83 &mut self,
84 start: Option<Box<Expression>>,
85 span_start: crate::lex::Token<'source>,
86 ) -> Expression {
87 if matches!(start.as_deref(), Some(Expression::Range { .. })) {
88 self.track_error("not allowed", "Chained range operators are not supported");
89 }
90
91 let inclusive = self.is(DotDotEqual);
92
93 self.next();
94
95 let has_end = !matches!(
96 self.current_token().kind,
97 RightCurlyBrace
98 | RightSquareBracket
99 | RightParen
100 | LeftCurlyBrace
101 | Semicolon
102 | Comma
103 | EOF
104 );
105
106 if inclusive && !has_end {
107 self.track_error(
108 "expected end value",
109 "Inclusive ranges require an end value.",
110 );
111 }
112
113 let end = if has_end {
114 Some(Box::new(self.parse_range_end()))
115 } else {
116 None
117 };
118
119 Expression::Range {
120 start,
121 end,
122 inclusive,
123 ty: Type::uninferred(),
124 span: self.span_from_tokens(span_start),
125 }
126 }
127
128 fn parse_literal(&mut self) -> Expression {
129 let start = self.current_token();
130
131 let literal = match self.current_token().kind {
132 Integer => {
133 let text = self.current_token().text;
134 let literal = self.parse_integer_text(text);
135 self.next();
136 literal
137 }
138 Float => {
139 let raw = self.current_token().text;
140 let cleaned = raw.replace('_', "");
141 let f: f64 = cleaned.parse().unwrap_or_else(|_| {
142 self.track_error(
143 format!("float literal '{}' is out of range", raw),
144 "Value must be a valid 64-bit floating point number.",
145 );
146 0.0
147 });
148 let text = if raw.contains('e') || raw.contains('E') || raw.contains('_') {
149 Some(raw.to_string())
150 } else {
151 None
152 };
153 self.next();
154 Literal::Float { value: f, text }
155 }
156 Imaginary => {
157 let text = self.current_token().text;
158 let coef: f64 = text[..text.len() - 1]
159 .replace('_', "")
160 .parse()
161 .unwrap_or_else(|_| {
162 self.track_error(
163 format!("imaginary literal '{}' is out of range", text),
164 "Value must be a valid 64-bit floating point number.",
165 );
166 0.0
167 });
168 self.next();
169 Literal::Imaginary(coef)
170 }
171 Boolean => {
172 let b = self.current_token().text == "true";
173 self.next();
174 Literal::Boolean(b)
175 }
176 String => {
177 let s = self.current_token().text;
178 self.next();
179 let s_stripped = if s.len() >= 2 && s.starts_with('"') && s.ends_with('"') {
180 &s[1..s.len() - 1]
181 } else {
182 debug_assert!(false, "lexer produced String token without quotes: {:?}", s);
183 s
184 };
185 Literal::String {
186 value: cook_string_contents(s_stripped),
187 raw: false,
188 }
189 }
190 RawString => {
191 let s = self.current_token().text;
192 self.next();
193 let s_stripped = if s.len() >= 3 && s.starts_with("r\"") && s.ends_with('"') {
194 &s[2..s.len() - 1]
195 } else if s.len() >= 2 && s.starts_with("r\"") {
196 &s[2..]
198 } else {
199 debug_assert!(
200 false,
201 "lexer produced RawString token without prefix: {:?}",
202 s
203 );
204 s
205 };
206 Literal::String {
207 value: cook_string_contents(s_stripped),
208 raw: true,
209 }
210 }
211 Char => {
212 let c = self.current_token().text;
213 self.next();
214 let c_stripped = if c.len() >= 2 && c.starts_with('\'') && c.ends_with('\'') {
215 &c[1..c.len() - 1]
216 } else {
217 debug_assert!(false, "lexer produced Char token without quotes: {:?}", c);
218 c
219 };
220 Literal::Char(c_stripped.to_string())
221 }
222 _ => return self.unexpected_token("literal"),
223 };
224
225 Expression::Literal {
226 literal,
227 ty: Type::uninferred(),
228 span: self.span_from_tokens(start),
229 }
230 }
231
232 fn parse_slice_literal(&mut self) -> Expression {
233 let start = self.current_token();
234 let (expressions, _) =
235 self.collect_delimited_expressions(LeftSquareBracket, RightSquareBracket);
236
237 Expression::Literal {
238 literal: Literal::Slice(expressions),
239 ty: Type::uninferred(),
240 span: self.span_from_tokens(start),
241 }
242 }
243
244 fn parse_identifier(&mut self) -> Expression {
245 let start = self.current_token();
246 let text = self.current_token().text;
247
248 if text == "go" {
249 let next = self.stream.peek_ahead(1).kind;
250 if next == LeftCurlyBrace || next == Identifier {
251 self.track_error(
252 "invalid syntax",
253 "Use `task { ... }` or `task my_function()` to spawn a concurrent task.",
254 );
255 }
256 }
257
258 self.ensure(Identifier);
259
260 Expression::Identifier {
261 value: text.into(),
262 ty: Type::uninferred(),
263 span: self.span_from_tokens(start),
264 binding_id: None,
265 qualified: None,
266 }
267 }
268
269 pub fn parse_struct_call(&mut self, expression: Expression) -> Expression {
270 let name = self.make_expression_name(&expression);
271 let name_span = expression.get_span();
272 let start_offset = name_span.byte_offset; self.ensure(LeftCurlyBrace);
275
276 let mut field_assignments = vec![];
277 let mut spread = StructSpread::None;
278 let mut seen_fields: Vec<(EcoString, Span)> = vec![];
279
280 while self.is_not(RightCurlyBrace) {
281 if self.is(DotDot) {
282 if spread.is_some() {
283 self.track_error(
284 "spread must be last",
285 "Move the `..spread` to the end of the struct.",
286 );
287 break;
288 }
289
290 let dotdot_token = self.current_token();
291 let dotdot_span = self.span_from_token(dotdot_token);
292 self.ensure(DotDot);
293
294 if self.is(RightCurlyBrace) || self.is(Comma) {
295 spread = StructSpread::ZeroFill { span: dotdot_span };
296 } else {
297 spread = StructSpread::From(Box::new(self.parse_expression()));
298 }
299
300 self.expect_comma_or(RightCurlyBrace);
301 continue;
302 }
303
304 if spread.is_some() {
305 self.track_error(
306 "field after spread",
307 "The `..spread` must be the last element in a struct expression. Move explicit fields before the spread.",
308 );
309 break;
310 }
311
312 let field_name_token = self.current_token();
313 let field_name_span = self.span_from_token(field_name_token);
314 let field_name = self.read_identifier();
315
316 if let Some((_, first_span)) = seen_fields.iter().find(|(n, _)| n == &field_name) {
317 self.error_duplicate_struct_field(&field_name, *first_span, field_name_span);
318 } else {
319 seen_fields.push((field_name.clone(), field_name_span));
320 }
321
322 let field_value = if self.advance_if(Colon) {
323 self.parse_expression()
324 } else {
325 Expression::Identifier {
326 value: field_name.clone(),
327 ty: Type::uninferred(),
328 span: self.span_from_tokens(field_name_token),
329 binding_id: None,
330 qualified: None,
331 }
332 };
333
334 field_assignments.push(StructFieldAssignment {
335 name: field_name,
336 name_span: field_name_span,
337 value: Box::new(field_value),
338 });
339
340 self.expect_comma_or(RightCurlyBrace);
341 }
342
343 self.ensure(RightCurlyBrace);
344
345 Expression::StructCall {
346 ty: Type::uninferred(),
347 name,
348 field_assignments,
349 spread,
350 span: self.span_from_offset(start_offset),
351 }
352 }
353
354 pub fn parse_index_expression(&mut self, expression: Expression) -> Expression {
355 let start = self.current_token();
356
357 self.ensure(LeftSquareBracket);
358
359 let index = self.parse_expression();
360
361 self.ensure(RightSquareBracket);
362
363 Expression::IndexedAccess {
364 ty: Type::uninferred(),
365 expression: expression.into(),
366 index: index.into(),
367 span: self.span_from_tokens(start),
368 }
369 }
370
371 pub fn parse_function_call(
372 &mut self,
373 expression: Expression,
374 type_args: Vec<Annotation>,
375 ) -> Expression {
376 let start_offset = expression.get_span().byte_offset;
377 let (args, spread) = self.collect_call_args();
378
379 Expression::Call {
380 ty: Type::uninferred(),
381 expression: expression.into(),
382 args,
383 spread: spread.into(),
384 type_args,
385 span: self.span_from_offset(start_offset),
386 call_kind: None,
387 }
388 }
389
390 fn collect_call_args(&mut self) -> (Vec<Expression>, Option<Expression>) {
391 self.ensure(LeftParen);
392 let mut args = vec![];
393
394 while !self.at_eof() && !self.is(RightParen) {
395 if self.handle_fn_as_lambda_in_call(&mut args) {
396 continue;
397 }
398 if self.at_item_boundary()
399 && !matches!(self.stream.peek_ahead(1).kind, RightParen | Comma)
400 {
401 break;
402 }
403 if self.is(DotDot) {
404 return (args, Some(self.parse_spread_arg()));
405 }
406 args.push(self.parse_expression());
407 self.expect_comma_or(RightParen);
408 }
409
410 self.advance_if(RightParen);
411 (args, None)
412 }
413
414 fn handle_fn_as_lambda_in_call(&mut self, args: &mut Vec<Expression>) -> bool {
415 if !(self.is(Function) && self.stream.peek_ahead(1).kind == LeftParen) {
416 return false;
417 }
418 let start = self.current_token();
419 let span = Span::new(self.file_id, start.byte_offset, start.byte_length + 1);
420 let error = ParseError::new("Syntax error", span, "expected a lambda")
421 .with_parse_code("fn_as_lambda")
422 .with_help("Use a lambda instead: `|x| x * 2`");
423 self.errors.push(error);
424 self.resync_on_error();
425 args.push(Expression::Unit {
426 ty: Type::uninferred(),
427 span,
428 });
429 true
430 }
431
432 fn parse_spread_arg(&mut self) -> Expression {
433 self.ensure(DotDot);
434 let spread = self.parse_expression();
435 self.expect_comma_or(RightParen);
436 if !self.is(RightParen) && !self.at_eof() {
437 self.track_error(
438 "argument after spread",
439 "The `..spread` must be the last argument in the call.",
440 );
441 while !self.at_eof() && !self.is(RightParen) {
442 self.next();
443 }
444 }
445 self.advance_if(RightParen);
446 spread
447 }
448
449 pub fn parse_type_args(&mut self) -> Vec<Annotation> {
450 self.ensure(LeftAngleBracket);
451
452 let mut type_args = vec![];
453
454 loop {
455 if self.at_eof() {
456 break;
457 }
458
459 type_args.push(self.parse_annotation());
460
461 if self.is(RightAngleBracket) {
462 break;
463 }
464
465 self.ensure(Comma);
466 }
467
468 self.ensure(RightAngleBracket);
469
470 type_args
471 }
472
473 pub fn parse_binary_operator(&mut self) -> BinaryOperator {
474 let operator = match self.current_token().kind {
475 Plus => BinaryOperator::Addition,
476 Minus => BinaryOperator::Subtraction,
477 Star => BinaryOperator::Multiplication,
478 Slash => BinaryOperator::Division,
479 LeftAngleBracket => BinaryOperator::LessThan,
480 LessThanOrEqual => BinaryOperator::LessThanOrEqual,
481 RightAngleBracket => BinaryOperator::GreaterThan,
482 GreaterThanOrEqual => BinaryOperator::GreaterThanOrEqual,
483 Percent => BinaryOperator::Remainder,
484 EqualDouble => BinaryOperator::Equal,
485 NotEqual => BinaryOperator::NotEqual,
486 AmpersandDouble => BinaryOperator::And,
487 PipeDouble => BinaryOperator::Or,
488 Pipeline => BinaryOperator::Pipeline,
489
490 _ => {
491 self.track_error(format!(
492 "expected binary operator, found {}",
493 self.current_token().kind
494 ), "Binary operators: `+`, `-`, `*`, `/`, `%`, `==`, `!=`, `<`, `>`, `<=`, `>=`, `&&`, `||`.");
495 BinaryOperator::Addition }
497 };
498
499 self.next();
500
501 operator
502 }
503
504 fn parse_parenthesized_expression(&mut self) -> Expression {
505 let start = self.current_token();
506
507 let (expressions, has_trailing_comma) =
508 self.collect_delimited_expressions(LeftParen, RightParen);
509 let span = self.span_from_tokens(start);
510
511 match expressions.len() {
512 0 => Expression::Unit {
513 ty: Type::uninferred(),
514 span,
515 },
516 1 => {
517 if has_trailing_comma {
518 self.error_tuple_arity(1, span);
519 }
520 let expression = expressions.into_iter().next().expect("len is 1");
521 Expression::Paren {
522 ty: Type::uninferred(),
523 expression: expression.into(),
524 span,
525 }
526 }
527 n => {
528 if n > MAX_TUPLE_ARITY {
529 self.error_tuple_arity(n, span);
530 }
531 Expression::Tuple {
532 ty: Type::uninferred(),
533 elements: expressions,
534 span,
535 }
536 }
537 }
538 }
539
540 pub fn parse_try(&mut self, expression: Expression) -> Expression {
541 let start_offset = expression.get_span().byte_offset;
542
543 self.ensure(QuestionMark);
544
545 Expression::Propagate {
546 ty: Type::uninferred(),
547 expression: expression.into(),
548 span: self.span_from_offset(start_offset),
549 }
550 }
551
552 fn parse_lambda(&mut self) -> Expression {
553 let start = self.current_token();
554
555 let params = if self.is(Pipe) {
556 self.parse_lambda_params()
557 } else {
558 self.next();
559 vec![]
560 };
561
562 let has_return_type = self.is(Arrow);
563 let return_annotation = if has_return_type {
564 self.next();
565 self.parse_annotation()
566 } else {
567 Annotation::Unknown
568 };
569
570 if has_return_type && self.current_token().kind != LeftCurlyBrace {
571 self.track_error(
572 "not allowed",
573 "A lambda with a return type requires a block body",
574 );
575 }
576
577 let body = self.parse_expression();
578
579 Expression::Lambda {
580 params,
581 return_annotation,
582 body: body.into(),
583 ty: Type::uninferred(),
584 span: self.span_from_tokens(start),
585 }
586 }
587
588 pub fn parse_block_expression(&mut self) -> Expression {
589 let start = self.current_token();
590
591 self.ensure(LeftCurlyBrace);
592
593 if !self.enter_recursion() {
594 let span = self.span_from_token(self.current_token());
595 let mut brace_depth = 1u32;
596 while brace_depth > 0 && !self.at_eof() {
597 match self.current_token().kind {
598 LeftCurlyBrace => brace_depth += 1,
599 RightCurlyBrace => brace_depth -= 1,
600 _ => {}
601 }
602 if brace_depth > 0 {
603 self.next();
604 }
605 }
606 self.advance_if(RightCurlyBrace);
607 return Expression::Block {
608 ty: Type::uninferred(),
609 items: vec![],
610 span,
611 };
612 }
613
614 let mut items = vec![];
615
616 while self.is_not(RightCurlyBrace) && !self.too_many_errors() {
617 let position = self.position();
618 let item = self.parse_block_item();
619
620 self.advance_if(Semicolon);
621
622 items.push(item);
623 if self.position() == position {
624 self.next();
625 }
626 }
627
628 let span = self.close_brace_span(start, start);
629
630 self.leave_recursion();
631
632 Expression::Block {
633 ty: Type::uninferred(),
634 items,
635 span,
636 }
637 }
638
639 pub fn parse_function_params(&mut self) -> Vec<Binding> {
640 self.ensure(LeftParen);
641
642 let mut params = vec![];
643
644 while self.is_not(RightParen) {
645 params.push(self.parse_binding_with_type());
646 self.expect_comma_or(RightParen);
647 }
648
649 self.ensure(RightParen);
650
651 params
652 }
653
654 pub fn parse_lambda_params(&mut self) -> Vec<Binding> {
655 self.ensure(Pipe);
656
657 let mut params = vec![];
658
659 while self.is_not(Pipe) {
660 params.push(self.parse_binding());
661 self.expect_comma_or(Pipe);
662 }
663
664 self.ensure(Pipe);
665
666 params
667 }
668
669 pub fn parse_function(
670 &mut self,
671 doc: Option<std::string::String>,
672 attributes: Vec<Attribute>,
673 ) -> Expression {
674 let start = self.current_token();
675
676 self.ensure(Function);
677
678 let name_token = self.current_token();
679 let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
680
681 let name = self.read_identifier_sequence();
682
683 let name_span = Span::new(name_span.file_id, name_span.byte_offset, name.len() as u32);
684
685 let generics = self.parse_generics();
686 let params = self.parse_function_params();
687 let return_annotation = self.parse_function_return_annotation();
688
689 let body = if self.is(LeftCurlyBrace) {
690 self.parse_block_expression()
691 } else {
692 Expression::NoOp
693 };
694
695 Expression::Function {
696 doc,
697 attributes,
698 name,
699 name_span,
700 generics,
701 params,
702 return_annotation,
703 return_type: Type::uninferred(),
704 visibility: Visibility::Private,
705 body: body.into(),
706 ty: Type::uninferred(),
707 span: self.span_from_tokens(start),
708 }
709 }
710
711 pub fn parse_field_access(&mut self, expression: Expression) -> Expression {
712 self.ensure(Dot);
713
714 let expression_start = expression.get_span().byte_offset;
715 let start = self.current_token();
716
717 if self.advance_if(Star) {
718 return Expression::Unary {
719 ty: Type::uninferred(),
720 operator: UnaryOperator::Deref,
721 expression: expression.into(),
722 span: self.span_from_tokens(start),
723 };
724 }
725
726 if self.is(Integer) {
727 let text = self.current_token().text;
728 let index: u32 = text.parse().unwrap_or_else(|_| {
729 self.track_error(
730 format!("tuple index '{}' is too large", text),
731 "Maximum index is `4294967295`.",
732 );
733 0
734 });
735
736 self.ensure(Integer);
737
738 return Expression::DotAccess {
739 ty: Type::uninferred(),
740 expression: expression.into(),
741 member: index.to_string().into(),
742 span: self.span_from_offset(expression_start),
743 dot_access_kind: None,
744 receiver_coercion: None,
745 };
746 }
747
748 let field = self.current_token().text;
749
750 self.ensure(Identifier);
751
752 Expression::DotAccess {
753 ty: Type::uninferred(),
754 expression: expression.into(),
755 member: field.into(),
756 span: self.span_from_offset(expression_start),
757 dot_access_kind: None,
758 receiver_coercion: None,
759 }
760 }
761
762 pub fn collect_delimited_expressions(
763 &mut self,
764 open: TokenKind,
765 close: TokenKind,
766 ) -> (Vec<Expression>, bool) {
767 self.ensure(open);
768
769 let mut expressions = vec![];
770 let mut has_trailing_comma = false;
771 loop {
772 if self.at_eof() || self.is(close) {
773 break;
774 }
775
776 if self.is(Function) && self.stream.peek_ahead(1).kind == LeftParen {
777 let start = self.current_token();
778 let span = Span::new(self.file_id, start.byte_offset, start.byte_length + 1);
779 let error = ParseError::new("Syntax error", span, "expected a lambda")
780 .with_parse_code("fn_as_lambda")
781 .with_help("Use a lambda instead: `|x| x * 2`");
782 self.errors.push(error);
783 self.resync_on_error();
784 expressions.push(Expression::Unit {
785 ty: Type::uninferred(),
786 span,
787 });
788 continue;
789 }
790
791 if self.at_item_boundary() {
792 let next = self.stream.peek_ahead(1).kind;
793 if next != close && next != Comma {
794 break;
795 }
796 }
797 expressions.push(self.parse_expression());
798 has_trailing_comma = self.is(Comma);
799 self.expect_comma_or(close);
800 }
801
802 self.advance_if(close);
803
804 (expressions, has_trailing_comma)
805 }
806
807 fn make_expression_name(&mut self, expression: &Expression) -> EcoString {
808 let mut parts = Vec::new();
809 let mut current = expression;
810
811 loop {
812 match current {
813 Expression::Identifier { value, .. } => {
814 parts.push(value.clone());
815 break;
816 }
817 Expression::DotAccess {
818 expression, member, ..
819 } => {
820 parts.push(member.clone());
821 current = expression;
822 }
823 _ => {
824 self.track_error(
825 "unexpected expression",
826 "Expected an identifier or dotted path.",
827 );
828 return "_".into();
829 }
830 }
831 }
832
833 parts.reverse();
834 parts.join(".").into()
835 }
836
837 pub fn parse_let(&mut self) -> Expression {
838 let start = self.current_token();
839
840 self.ensure(Let);
841
842 let (mutable, mut_span) = if self.is(Mut) {
843 let mut_token = self.current_token();
844 let span = Span::new(self.file_id, mut_token.byte_offset, mut_token.byte_length);
845 self.next(); (true, Some(span))
847 } else {
848 (false, None)
849 };
850
851 let binding = self.parse_binding_allowing_or();
852
853 self.ensure(Equal);
854
855 let expression = self.parse_expression();
856
857 let (else_block, else_span) = if self.is(Else) {
858 let else_token = self.current_token();
859 let span = Span::new(self.file_id, else_token.byte_offset, else_token.byte_length);
860 self.next(); (Some(Box::new(self.parse_block_expression())), Some(span))
862 } else {
863 (None, None)
864 };
865
866 Expression::Let {
867 binding: Box::new(binding),
868 value: expression.into(),
869 mutable,
870 mut_span,
871 else_block,
872 else_span,
873 typed_pattern: None,
874 ty: Type::uninferred(),
875 span: self.span_from_tokens(start),
876 }
877 }
878
879 pub fn parse_import(&mut self) -> Expression {
880 let start = self.current_token();
881
882 self.ensure(Import);
883
884 let alias = if self.current_token().kind == Identifier {
885 let alias_token = self.current_token();
886 let alias_text = alias_token.text;
887 let alias_span = Span::new(
888 self.file_id,
889 alias_token.byte_offset,
890 alias_token.byte_length,
891 );
892
893 if alias_text == "_" {
894 self.next();
895 Some(ImportAlias::Blank(alias_span))
896 } else if self.stream.peek_ahead(1).kind == String {
897 self.next();
898 Some(ImportAlias::Named(alias_text.into(), alias_span))
899 } else {
900 None
901 }
902 } else {
903 None
904 };
905
906 let name_token = self.current_token();
907
908 if name_token.kind != String {
909 let (label, help) = if name_token.kind == Identifier
910 && self.stream.peek_ahead(1).kind == Colon
911 {
912 let module_name = name_token.text;
913 (
914 "expected double quotes".to_string(),
915 format!(
916 "Wrap the import path in double quotes: `import \"{0}:...\"`",
917 module_name
918 ),
919 )
920 } else if name_token.kind == Identifier {
921 let module_name = name_token.text;
922 (
923 "expected double quotes".to_string(),
924 format!(
925 "Wrap the import path in double quotes: `import \"{}\"`",
926 module_name
927 ),
928 )
929 } else {
930 (
931 "expected module path".to_string(),
932 "Wrap the import path in double quotes, e.g. `import \"go:os\"`".to_string(),
933 )
934 };
935
936 self.track_error(label, help);
937 self.resync_on_error();
938 return Expression::Unit {
939 ty: Type::uninferred(),
940 span: self.span_from_tokens(start),
941 };
942 }
943
944 self.next();
945
946 let raw = name_token.text;
947 let unquoted: &str = if raw.len() >= 2 && raw.starts_with('"') && raw.ends_with('"') {
948 &raw[1..raw.len() - 1]
949 } else {
950 debug_assert!(
951 false,
952 "lexer produced String token without quotes: {:?}",
953 raw
954 );
955 raw
956 };
957
958 if alias.is_none() && self.is(As) && self.stream.peek_ahead(1).kind == Identifier {
959 let as_token = self.current_token();
960 let alias_identifier = self.stream.peek_ahead(1);
961 self.next();
962 self.next();
963 self.error_import_alias_after_path(
964 self.span_from_tokens(as_token),
965 alias_identifier.text,
966 unquoted,
967 );
968 }
969
970 let name: EcoString = unquoted.into();
971 let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
972
973 Expression::ModuleImport {
974 name,
975 name_span,
976 alias,
977 span: self.span_from_tokens(start),
978 }
979 }
980
981 pub fn parse_assignment(&mut self) -> Expression {
982 let start = self.current_token();
983
984 let lhs = self.parse_expression();
985
986 let compound_operator = match self.current_token().kind {
987 PlusEqual => Some(BinaryOperator::Addition),
988 MinusEqual => Some(BinaryOperator::Subtraction),
989 StarEqual => Some(BinaryOperator::Multiplication),
990 SlashEqual => Some(BinaryOperator::Division),
991 PercentEqual => Some(BinaryOperator::Remainder),
992 _ => None,
993 };
994
995 if let Some(operator) = compound_operator {
996 if !self.is_valid_assignment_target(&lhs) {
997 self.track_error(
998 "invalid assignment target",
999 "Only variables, fields, and indices can be assigned to.",
1000 );
1001 self.next();
1002 let _rhs = self.parse_expression();
1003 return lhs;
1004 }
1005 self.next();
1006 let rhs = self.parse_expression();
1007 return Expression::Assignment {
1008 target: lhs.clone().into(),
1009 value: Expression::Binary {
1010 left: lhs.into(),
1011 operator,
1012 right: rhs.into(),
1013 ty: Type::uninferred(),
1014 span: self.span_from_tokens(start),
1015 }
1016 .into(),
1017 compound_operator: Some(operator),
1018 span: self.span_from_tokens(start),
1019 };
1020 }
1021
1022 if self.current_token().kind == Colon && self.stream.peek_ahead(1).kind == Equal {
1023 let span = Span::new(self.file_id, self.current_token().byte_offset, 2);
1024 self.track_error_at(
1025 span,
1026 "Go-style short declaration",
1027 "Use `let x = ...` instead of `:=` for variable declarations",
1028 );
1029 self.next();
1030 self.next();
1031 let _ = self.parse_expression();
1032 return lhs;
1033 }
1034
1035 if !self.is(Equal) {
1036 return lhs;
1037 }
1038
1039 if !self.is_valid_assignment_target(&lhs) {
1040 self.track_error(
1041 "invalid assignment target",
1042 "Only variables, fields, and indices can be assigned to.",
1043 );
1044 }
1045
1046 self.ensure(Equal);
1047
1048 Expression::Assignment {
1049 target: lhs.into(),
1050 value: self.parse_expression().into(),
1051 compound_operator: None,
1052 span: self.span_from_tokens(start),
1053 }
1054 }
1055
1056 fn is_valid_assignment_target(&self, expression: &Expression) -> bool {
1057 use Expression::*;
1058
1059 matches!(
1060 expression,
1061 Identifier { .. }
1062 | DotAccess { .. }
1063 | IndexedAccess { .. }
1064 | Unary {
1065 operator: UnaryOperator::Deref,
1066 ..
1067 }
1068 )
1069 }
1070
1071 fn parse_format_string(&mut self) -> Expression {
1072 let start = self.current_token();
1073 self.ensure(FormatStringStart);
1074
1075 let mut parts = Vec::new();
1076
1077 loop {
1078 if self.at_eof() || self.at_item_boundary() {
1079 break;
1080 }
1081 match self.current_token().kind {
1082 FormatStringText => {
1083 let text = self.current_token().text;
1084 self.next();
1085 parts.push(FormatStringPart::Text(cook_string_contents(text)));
1086 }
1087 FormatStringInterpolationStart => {
1088 self.ensure(FormatStringInterpolationStart);
1089 let expression = self.parse_expression();
1090 parts.push(FormatStringPart::Expression(Box::new(expression)));
1091 if self.is(Colon) {
1092 let start_offset = self.current_token().byte_offset;
1093 self.next();
1094 while !self.at_eof()
1095 && !self.is(FormatStringInterpolationEnd)
1096 && !self.is(FormatStringEnd)
1097 && !self.at_item_boundary()
1098 {
1099 self.next();
1100 }
1101 let span = self.span_from_offset(start_offset);
1102 let error = ParseError::new(
1103 "Format specifiers not supported",
1104 span,
1105 "not supported in format strings",
1106 )
1107 .with_parse_code("format_specifier")
1108 .with_help(
1109 "Use `fmt.Sprintf` for formatted output, e.g. `fmt.Sprintf(\"%02x\", n)`",
1110 );
1111 self.errors.push(error);
1112 }
1113 self.advance_if(FormatStringInterpolationEnd);
1114 }
1115 FormatStringEnd => {
1116 self.ensure(FormatStringEnd);
1117 break;
1118 }
1119 _ => break,
1120 }
1121 }
1122
1123 Expression::Literal {
1124 literal: Literal::FormatString(parts),
1125 ty: Type::uninferred(),
1126 span: self.span_from_tokens(start),
1127 }
1128 }
1129
1130 pub fn parse_task(&mut self) -> Expression {
1131 let start = self.current_token();
1132
1133 self.ensure(Task);
1134
1135 let expression = if self.is(LeftCurlyBrace) {
1136 self.parse_block_expression()
1137 } else {
1138 self.parse_expression()
1139 };
1140
1141 if !matches!(
1142 expression,
1143 Expression::Call { .. } | Expression::Block { .. }
1144 ) {
1145 let span = expression.get_span();
1146 let error = ParseError::new("Invalid `task`", span, "expected `()`")
1147 .with_parse_code("task_missing_parens")
1148 .with_help("Add parens to call the function");
1149
1150 self.errors.push(error);
1151 }
1152
1153 Expression::Task {
1154 expression: Box::new(expression),
1155 ty: Type::uninferred(),
1156 span: self.span_from_tokens(start),
1157 }
1158 }
1159
1160 pub fn parse_defer(&mut self) -> Expression {
1161 let start = self.current_token();
1162
1163 self.ensure(Defer);
1164
1165 let expression = if self.is(LeftCurlyBrace) {
1166 self.parse_block_expression()
1167 } else {
1168 self.parse_expression()
1169 };
1170
1171 if !matches!(
1172 expression,
1173 Expression::Call { .. } | Expression::Block { .. }
1174 ) {
1175 let span = expression.get_span();
1176 let error = ParseError::new("Invalid `defer`", span, "expected `()`")
1177 .with_parse_code("defer_missing_parens")
1178 .with_help("Add parens to call the function");
1179
1180 self.errors.push(error);
1181 }
1182
1183 Expression::Defer {
1184 expression: Box::new(expression),
1185 ty: Type::uninferred(),
1186 span: self.span_from_tokens(start),
1187 }
1188 }
1189
1190 pub fn parse_try_block(&mut self) -> Expression {
1191 let start = self.current_token();
1192 let try_keyword_span = Span::new(self.file_id, start.byte_offset, start.byte_length);
1193
1194 self.ensure(Try);
1195
1196 if !self.is(LeftCurlyBrace) {
1197 let span = self.span_from_tokens(start);
1198 let error = ParseError::new("Invalid `try`", span, "requires a block")
1199 .with_parse_code("syntax_error")
1200 .with_help("Use `try { expression }` instead of `try expression`");
1201 self.errors.push(error);
1202 let expression = self.parse_expression();
1203 return Expression::TryBlock {
1204 items: vec![expression],
1205 ty: Type::uninferred(),
1206 try_keyword_span,
1207 span: self.span_from_tokens(start),
1208 };
1209 }
1210
1211 let brace_token = self.current_token();
1212 self.ensure(LeftCurlyBrace);
1213
1214 if !self.enter_recursion() {
1215 let span = self.span_from_token(self.current_token());
1216 let mut brace_depth = 1u32;
1217 while brace_depth > 0 && !self.at_eof() {
1218 match self.current_token().kind {
1219 LeftCurlyBrace => brace_depth += 1,
1220 RightCurlyBrace => brace_depth -= 1,
1221 _ => {}
1222 }
1223 if brace_depth > 0 {
1224 self.next();
1225 }
1226 }
1227 self.advance_if(RightCurlyBrace);
1228 return Expression::TryBlock {
1229 items: vec![],
1230 ty: Type::uninferred(),
1231 try_keyword_span,
1232 span,
1233 };
1234 }
1235
1236 let mut items = vec![];
1237
1238 while self.is_not(RightCurlyBrace) && !self.too_many_errors() {
1239 let position = self.position();
1240 let item = self.parse_block_item();
1241
1242 self.advance_if(Semicolon);
1243
1244 items.push(item);
1245 if self.position() == position {
1246 self.next();
1247 }
1248 }
1249
1250 let span = self.close_brace_span(start, brace_token);
1251
1252 self.leave_recursion();
1253
1254 Expression::TryBlock {
1255 items,
1256 ty: Type::uninferred(),
1257 try_keyword_span,
1258 span,
1259 }
1260 }
1261
1262 pub fn parse_recover_block(&mut self) -> Expression {
1263 let start = self.current_token();
1264 let recover_keyword_span = Span::new(self.file_id, start.byte_offset, start.byte_length);
1265
1266 self.ensure(Recover);
1267
1268 if !self.is(LeftCurlyBrace) {
1269 let span = self.span_from_tokens(start);
1270 let error = ParseError::new("Invalid `recover`", span, "requires a block")
1271 .with_parse_code("syntax_error")
1272 .with_help("Use `recover { expression }` instead of `recover expression`");
1273 self.errors.push(error);
1274 let expression = self.parse_expression();
1275 return Expression::RecoverBlock {
1276 items: vec![expression],
1277 ty: Type::uninferred(),
1278 recover_keyword_span,
1279 span: self.span_from_tokens(start),
1280 };
1281 }
1282
1283 let brace_token = self.current_token();
1284 self.ensure(LeftCurlyBrace);
1285
1286 if !self.enter_recursion() {
1287 let span = self.span_from_token(self.current_token());
1288 let mut brace_depth = 1u32;
1289 while brace_depth > 0 && !self.at_eof() {
1290 match self.current_token().kind {
1291 LeftCurlyBrace => brace_depth += 1,
1292 RightCurlyBrace => brace_depth -= 1,
1293 _ => {}
1294 }
1295 if brace_depth > 0 {
1296 self.next();
1297 }
1298 }
1299 self.advance_if(RightCurlyBrace);
1300 return Expression::RecoverBlock {
1301 items: vec![],
1302 ty: Type::uninferred(),
1303 recover_keyword_span,
1304 span,
1305 };
1306 }
1307
1308 let mut items = vec![];
1309
1310 while self.is_not(RightCurlyBrace) && !self.too_many_errors() {
1311 let position = self.position();
1312 let item = self.parse_block_item();
1313
1314 self.advance_if(Semicolon);
1315
1316 items.push(item);
1317 if self.position() == position {
1318 self.next();
1319 }
1320 }
1321
1322 let span = self.close_brace_span(start, brace_token);
1323
1324 self.leave_recursion();
1325
1326 Expression::RecoverBlock {
1327 items,
1328 ty: Type::uninferred(),
1329 recover_keyword_span,
1330 span,
1331 }
1332 }
1333
1334 pub fn parse_select(&mut self) -> Expression {
1335 let start = self.current_token();
1336
1337 self.ensure(Select);
1338 self.ensure(LeftCurlyBrace);
1339
1340 let mut arms = Vec::new();
1341
1342 while self.is_not(RightCurlyBrace) {
1343 let arm = self.parse_select_arm();
1344 arms.push(arm);
1345
1346 if self.is(RightCurlyBrace) {
1347 break;
1348 }
1349
1350 self.ensure(Comma);
1351 }
1352
1353 self.ensure(RightCurlyBrace);
1354
1355 Expression::Select {
1356 arms,
1357 ty: Type::uninferred(),
1358 span: self.span_from_tokens(start),
1359 }
1360 }
1361
1362 fn parse_select_arm(&mut self) -> SelectArm {
1363 match self.current_token().kind {
1364 Let => {
1365 self.ensure(Let);
1366 let binding = self.parse_pattern();
1367 self.ensure(Equal);
1368 let receive_expression = Box::new(self.parse_expression());
1369 self.ensure(ArrowDouble);
1370 let body = Box::new(self.parse_expression());
1371 SelectArm {
1372 pattern: SelectArmPattern::Receive {
1373 binding: Box::new(binding),
1374 typed_pattern: None,
1375 receive_expression,
1376 body,
1377 },
1378 }
1379 }
1380 Match => {
1381 let match_expression = self.parse_match();
1382 if let Expression::Match { subject, arms, .. } = match_expression {
1383 SelectArm {
1384 pattern: SelectArmPattern::MatchReceive {
1385 receive_expression: subject,
1386 arms,
1387 },
1388 }
1389 } else {
1390 self.ensure(ArrowDouble);
1391 let body = Box::new(self.parse_expression());
1392 SelectArm {
1393 pattern: SelectArmPattern::Send {
1394 send_expression: Box::new(match_expression),
1395 body,
1396 },
1397 }
1398 }
1399 }
1400 Identifier if self.current_token().text == "_" => {
1401 self.next();
1402 self.ensure(ArrowDouble);
1403 let body = Box::new(self.parse_expression());
1404 SelectArm {
1405 pattern: SelectArmPattern::WildCard { body },
1406 }
1407 }
1408 _ => {
1409 let send_expression = Box::new(self.parse_expression());
1410 self.ensure(ArrowDouble);
1411 let body = Box::new(self.parse_expression());
1412 SelectArm {
1413 pattern: SelectArmPattern::Send {
1414 send_expression,
1415 body,
1416 },
1417 }
1418 }
1419 }
1420 }
1421
1422 pub fn with_control_flow_header<F, R>(&mut self, f: F) -> R
1423 where
1424 F: FnOnce(&mut Self) -> R,
1425 {
1426 let old = self.in_control_flow_header;
1427 self.in_control_flow_header = true;
1428 let result = f(self);
1429 self.in_control_flow_header = old;
1430 result
1431 }
1432
1433 fn keyword_in_value_position(&self) -> bool {
1434 if !self.current_token().kind.is_keyword() {
1435 return false;
1436 }
1437
1438 match self.current_token().kind {
1439 Return | Break | Continue => false,
1440
1441 Match | If | Task | Defer | Try | Recover | Select | Loop | Function => matches!(
1442 self.stream.peek_ahead(1).kind,
1443 RightParen
1444 | Comma
1445 | Dot
1446 | Semicolon
1447 | RightCurlyBrace
1448 | RightSquareBracket
1449 | ArrowDouble
1450 | QuestionMark
1451 | EOF
1452 | Plus
1453 | Star
1454 | Slash
1455 | Percent
1456 | EqualDouble
1457 | NotEqual
1458 | LeftAngleBracket
1459 | RightAngleBracket
1460 | LessThanOrEqual
1461 | GreaterThanOrEqual
1462 | AmpersandDouble
1463 | Pipeline
1464 | Equal
1465 | PlusEqual
1466 | MinusEqual
1467 | StarEqual
1468 | SlashEqual
1469 | PercentEqual
1470 | DotDot
1471 | DotDotEqual
1472 | As
1473 ),
1474
1475 _ => true,
1476 }
1477 }
1478
1479 fn recover_keyword_as_identifier(&mut self) -> Expression {
1480 let token = self.current_token();
1481 let keyword = token.text.to_string();
1482 let span = self.span_from_token(token);
1483 let error = ParseError::new("Reserved keyword", span, "reserved keyword")
1484 .with_parse_code("keyword_as_identifier")
1485 .with_help(format!("Rename `{}`", keyword));
1486 self.errors.push(error);
1487 self.next();
1488 Expression::Identifier {
1489 value: keyword.into(),
1490 ty: Type::uninferred(),
1491 span,
1492 binding_id: None,
1493 qualified: None,
1494 }
1495 }
1496
1497 fn recover_unexpected_backtick(&mut self) -> Expression {
1498 let token = self.current_token();
1499 let token_span = self.span_from_token(token);
1500 let opening_span = Span::new(self.file_id, token.byte_offset, 1);
1501 let error = ParseError::new("Unexpected backtick", opening_span, "not allowed here")
1502 .with_parse_code("unexpected_backtick")
1503 .with_help(
1504 "Use a regular string `\"...\"` or a raw string `r\"...\"` for single- or multi-line strings. Backticks in Lisette are reserved for struct-tag attributes.",
1505 );
1506 self.errors.push(error);
1507 self.next();
1508 Expression::Literal {
1509 literal: Literal::String {
1510 value: std::string::String::new(),
1511 raw: true,
1512 },
1513 ty: Type::uninferred(),
1514 span: token_span,
1515 }
1516 }
1517}