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