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_backtick_as_raw_string(),
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 name: EcoString = if raw.len() >= 2 && raw.starts_with('"') && raw.ends_with('"') {
948 raw[1..raw.len() - 1].into()
949 } else {
950 debug_assert!(
951 false,
952 "lexer produced String token without quotes: {:?}",
953 raw
954 );
955 raw.into()
956 };
957 let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
958
959 Expression::ModuleImport {
960 name,
961 name_span,
962 alias,
963 span: self.span_from_tokens(start),
964 }
965 }
966
967 pub fn parse_assignment(&mut self) -> Expression {
968 let start = self.current_token();
969
970 let lhs = self.parse_expression();
971
972 let compound_operator = match self.current_token().kind {
973 PlusEqual => Some(BinaryOperator::Addition),
974 MinusEqual => Some(BinaryOperator::Subtraction),
975 StarEqual => Some(BinaryOperator::Multiplication),
976 SlashEqual => Some(BinaryOperator::Division),
977 PercentEqual => Some(BinaryOperator::Remainder),
978 _ => None,
979 };
980
981 if let Some(operator) = compound_operator {
982 if !self.is_valid_assignment_target(&lhs) {
983 self.track_error(
984 "invalid assignment target",
985 "Only variables, fields, and indices can be assigned to.",
986 );
987 self.next();
988 let _rhs = self.parse_expression();
989 return lhs;
990 }
991 self.next();
992 let rhs = self.parse_expression();
993 return Expression::Assignment {
994 target: lhs.clone().into(),
995 value: Expression::Binary {
996 left: lhs.into(),
997 operator,
998 right: rhs.into(),
999 ty: Type::uninferred(),
1000 span: self.span_from_tokens(start),
1001 }
1002 .into(),
1003 compound_operator: Some(operator),
1004 span: self.span_from_tokens(start),
1005 };
1006 }
1007
1008 if self.current_token().kind == Colon && self.stream.peek_ahead(1).kind == Equal {
1009 let span = Span::new(self.file_id, self.current_token().byte_offset, 2);
1010 self.track_error_at(
1011 span,
1012 "Go-style short declaration",
1013 "Use `let x = ...` instead of `:=` for variable declarations",
1014 );
1015 self.next();
1016 self.next();
1017 let _ = self.parse_expression();
1018 return lhs;
1019 }
1020
1021 if !self.is(Equal) {
1022 return lhs;
1023 }
1024
1025 if !self.is_valid_assignment_target(&lhs) {
1026 self.track_error(
1027 "invalid assignment target",
1028 "Only variables, fields, and indices can be assigned to.",
1029 );
1030 }
1031
1032 self.ensure(Equal);
1033
1034 Expression::Assignment {
1035 target: lhs.into(),
1036 value: self.parse_expression().into(),
1037 compound_operator: None,
1038 span: self.span_from_tokens(start),
1039 }
1040 }
1041
1042 fn is_valid_assignment_target(&self, expression: &Expression) -> bool {
1043 use Expression::*;
1044
1045 matches!(
1046 expression,
1047 Identifier { .. }
1048 | DotAccess { .. }
1049 | IndexedAccess { .. }
1050 | Unary {
1051 operator: UnaryOperator::Deref,
1052 ..
1053 }
1054 )
1055 }
1056
1057 fn parse_format_string(&mut self) -> Expression {
1058 let start = self.current_token();
1059 self.ensure(FormatStringStart);
1060
1061 let mut parts = Vec::new();
1062
1063 loop {
1064 if self.at_eof() || self.at_item_boundary() {
1065 break;
1066 }
1067 match self.current_token().kind {
1068 FormatStringText => {
1069 let text = self.current_token().text;
1070 self.next();
1071 parts.push(FormatStringPart::Text(cook_string_contents(text)));
1072 }
1073 FormatStringInterpolationStart => {
1074 self.ensure(FormatStringInterpolationStart);
1075 let expression = self.parse_expression();
1076 parts.push(FormatStringPart::Expression(Box::new(expression)));
1077 if self.is(Colon) {
1078 let start_offset = self.current_token().byte_offset;
1079 self.next();
1080 while !self.at_eof()
1081 && !self.is(FormatStringInterpolationEnd)
1082 && !self.is(FormatStringEnd)
1083 && !self.at_item_boundary()
1084 {
1085 self.next();
1086 }
1087 let span = self.span_from_offset(start_offset);
1088 let error = ParseError::new(
1089 "Format specifiers not supported",
1090 span,
1091 "not supported in format strings",
1092 )
1093 .with_parse_code("format_specifier")
1094 .with_help(
1095 "Use `fmt.Sprintf` for formatted output, e.g. `fmt.Sprintf(\"%02x\", n)`",
1096 );
1097 self.errors.push(error);
1098 }
1099 self.advance_if(FormatStringInterpolationEnd);
1100 }
1101 FormatStringEnd => {
1102 self.ensure(FormatStringEnd);
1103 break;
1104 }
1105 _ => break,
1106 }
1107 }
1108
1109 Expression::Literal {
1110 literal: Literal::FormatString(parts),
1111 ty: Type::uninferred(),
1112 span: self.span_from_tokens(start),
1113 }
1114 }
1115
1116 pub fn parse_task(&mut self) -> Expression {
1117 let start = self.current_token();
1118
1119 self.ensure(Task);
1120
1121 let expression = if self.is(LeftCurlyBrace) {
1122 self.parse_block_expression()
1123 } else {
1124 self.parse_expression()
1125 };
1126
1127 if !matches!(
1128 expression,
1129 Expression::Call { .. } | Expression::Block { .. }
1130 ) {
1131 let span = expression.get_span();
1132 let error = ParseError::new("Invalid `task`", span, "expected `()`")
1133 .with_parse_code("task_missing_parens")
1134 .with_help("Add parens to call the function");
1135
1136 self.errors.push(error);
1137 }
1138
1139 Expression::Task {
1140 expression: Box::new(expression),
1141 ty: Type::uninferred(),
1142 span: self.span_from_tokens(start),
1143 }
1144 }
1145
1146 pub fn parse_defer(&mut self) -> Expression {
1147 let start = self.current_token();
1148
1149 self.ensure(Defer);
1150
1151 let expression = if self.is(LeftCurlyBrace) {
1152 self.parse_block_expression()
1153 } else {
1154 self.parse_expression()
1155 };
1156
1157 if !matches!(
1158 expression,
1159 Expression::Call { .. } | Expression::Block { .. }
1160 ) {
1161 let span = expression.get_span();
1162 let error = ParseError::new("Invalid `defer`", span, "expected `()`")
1163 .with_parse_code("defer_missing_parens")
1164 .with_help("Add parens to call the function");
1165
1166 self.errors.push(error);
1167 }
1168
1169 Expression::Defer {
1170 expression: Box::new(expression),
1171 ty: Type::uninferred(),
1172 span: self.span_from_tokens(start),
1173 }
1174 }
1175
1176 pub fn parse_try_block(&mut self) -> Expression {
1177 let start = self.current_token();
1178 let try_keyword_span = Span::new(self.file_id, start.byte_offset, start.byte_length);
1179
1180 self.ensure(Try);
1181
1182 if !self.is(LeftCurlyBrace) {
1183 let span = self.span_from_tokens(start);
1184 let error = ParseError::new("Invalid `try`", span, "requires a block")
1185 .with_parse_code("syntax_error")
1186 .with_help("Use `try { expression }` instead of `try expression`");
1187 self.errors.push(error);
1188 let expression = self.parse_expression();
1189 return Expression::TryBlock {
1190 items: vec![expression],
1191 ty: Type::uninferred(),
1192 try_keyword_span,
1193 span: self.span_from_tokens(start),
1194 };
1195 }
1196
1197 let brace_token = self.current_token();
1198 self.ensure(LeftCurlyBrace);
1199
1200 if !self.enter_recursion() {
1201 let span = self.span_from_token(self.current_token());
1202 let mut brace_depth = 1u32;
1203 while brace_depth > 0 && !self.at_eof() {
1204 match self.current_token().kind {
1205 LeftCurlyBrace => brace_depth += 1,
1206 RightCurlyBrace => brace_depth -= 1,
1207 _ => {}
1208 }
1209 if brace_depth > 0 {
1210 self.next();
1211 }
1212 }
1213 self.advance_if(RightCurlyBrace);
1214 return Expression::TryBlock {
1215 items: vec![],
1216 ty: Type::uninferred(),
1217 try_keyword_span,
1218 span,
1219 };
1220 }
1221
1222 let mut items = vec![];
1223
1224 while self.is_not(RightCurlyBrace) && !self.too_many_errors() {
1225 let position = self.position();
1226 let item = self.parse_block_item();
1227
1228 self.advance_if(Semicolon);
1229
1230 items.push(item);
1231 if self.position() == position {
1232 self.next();
1233 }
1234 }
1235
1236 let span = self.close_brace_span(start, brace_token);
1237
1238 self.leave_recursion();
1239
1240 Expression::TryBlock {
1241 items,
1242 ty: Type::uninferred(),
1243 try_keyword_span,
1244 span,
1245 }
1246 }
1247
1248 pub fn parse_recover_block(&mut self) -> Expression {
1249 let start = self.current_token();
1250 let recover_keyword_span = Span::new(self.file_id, start.byte_offset, start.byte_length);
1251
1252 self.ensure(Recover);
1253
1254 if !self.is(LeftCurlyBrace) {
1255 let span = self.span_from_tokens(start);
1256 let error = ParseError::new("Invalid `recover`", span, "requires a block")
1257 .with_parse_code("syntax_error")
1258 .with_help("Use `recover { expression }` instead of `recover expression`");
1259 self.errors.push(error);
1260 let expression = self.parse_expression();
1261 return Expression::RecoverBlock {
1262 items: vec![expression],
1263 ty: Type::uninferred(),
1264 recover_keyword_span,
1265 span: self.span_from_tokens(start),
1266 };
1267 }
1268
1269 let brace_token = self.current_token();
1270 self.ensure(LeftCurlyBrace);
1271
1272 if !self.enter_recursion() {
1273 let span = self.span_from_token(self.current_token());
1274 let mut brace_depth = 1u32;
1275 while brace_depth > 0 && !self.at_eof() {
1276 match self.current_token().kind {
1277 LeftCurlyBrace => brace_depth += 1,
1278 RightCurlyBrace => brace_depth -= 1,
1279 _ => {}
1280 }
1281 if brace_depth > 0 {
1282 self.next();
1283 }
1284 }
1285 self.advance_if(RightCurlyBrace);
1286 return Expression::RecoverBlock {
1287 items: vec![],
1288 ty: Type::uninferred(),
1289 recover_keyword_span,
1290 span,
1291 };
1292 }
1293
1294 let mut items = vec![];
1295
1296 while self.is_not(RightCurlyBrace) && !self.too_many_errors() {
1297 let position = self.position();
1298 let item = self.parse_block_item();
1299
1300 self.advance_if(Semicolon);
1301
1302 items.push(item);
1303 if self.position() == position {
1304 self.next();
1305 }
1306 }
1307
1308 let span = self.close_brace_span(start, brace_token);
1309
1310 self.leave_recursion();
1311
1312 Expression::RecoverBlock {
1313 items,
1314 ty: Type::uninferred(),
1315 recover_keyword_span,
1316 span,
1317 }
1318 }
1319
1320 pub fn parse_select(&mut self) -> Expression {
1321 let start = self.current_token();
1322
1323 self.ensure(Select);
1324 self.ensure(LeftCurlyBrace);
1325
1326 let mut arms = Vec::new();
1327
1328 while self.is_not(RightCurlyBrace) {
1329 let arm = self.parse_select_arm();
1330 arms.push(arm);
1331
1332 if self.is(RightCurlyBrace) {
1333 break;
1334 }
1335
1336 self.ensure(Comma);
1337 }
1338
1339 self.ensure(RightCurlyBrace);
1340
1341 Expression::Select {
1342 arms,
1343 ty: Type::uninferred(),
1344 span: self.span_from_tokens(start),
1345 }
1346 }
1347
1348 fn parse_select_arm(&mut self) -> SelectArm {
1349 match self.current_token().kind {
1350 Let => {
1351 self.ensure(Let);
1352 let binding = self.parse_pattern();
1353 self.ensure(Equal);
1354 let receive_expression = Box::new(self.parse_expression());
1355 self.ensure(ArrowDouble);
1356 let body = Box::new(self.parse_expression());
1357 SelectArm {
1358 pattern: SelectArmPattern::Receive {
1359 binding: Box::new(binding),
1360 typed_pattern: None,
1361 receive_expression,
1362 body,
1363 },
1364 }
1365 }
1366 Match => {
1367 let match_expression = self.parse_match();
1368 if let Expression::Match { subject, arms, .. } = match_expression {
1369 SelectArm {
1370 pattern: SelectArmPattern::MatchReceive {
1371 receive_expression: subject,
1372 arms,
1373 },
1374 }
1375 } else {
1376 self.ensure(ArrowDouble);
1377 let body = Box::new(self.parse_expression());
1378 SelectArm {
1379 pattern: SelectArmPattern::Send {
1380 send_expression: Box::new(match_expression),
1381 body,
1382 },
1383 }
1384 }
1385 }
1386 Identifier if self.current_token().text == "_" => {
1387 self.next();
1388 self.ensure(ArrowDouble);
1389 let body = Box::new(self.parse_expression());
1390 SelectArm {
1391 pattern: SelectArmPattern::WildCard { body },
1392 }
1393 }
1394 _ => {
1395 let send_expression = Box::new(self.parse_expression());
1396 self.ensure(ArrowDouble);
1397 let body = Box::new(self.parse_expression());
1398 SelectArm {
1399 pattern: SelectArmPattern::Send {
1400 send_expression,
1401 body,
1402 },
1403 }
1404 }
1405 }
1406 }
1407
1408 pub fn with_control_flow_header<F, R>(&mut self, f: F) -> R
1409 where
1410 F: FnOnce(&mut Self) -> R,
1411 {
1412 let old = self.in_control_flow_header;
1413 self.in_control_flow_header = true;
1414 let result = f(self);
1415 self.in_control_flow_header = old;
1416 result
1417 }
1418
1419 fn keyword_in_value_position(&self) -> bool {
1420 if !self.current_token().kind.is_keyword() {
1421 return false;
1422 }
1423
1424 match self.current_token().kind {
1425 Return | Break | Continue => false,
1426
1427 Match | If | Task | Defer | Try | Recover | Select | Loop | Function => matches!(
1428 self.stream.peek_ahead(1).kind,
1429 RightParen
1430 | Comma
1431 | Dot
1432 | Semicolon
1433 | RightCurlyBrace
1434 | RightSquareBracket
1435 | ArrowDouble
1436 | QuestionMark
1437 | EOF
1438 | Plus
1439 | Star
1440 | Slash
1441 | Percent
1442 | EqualDouble
1443 | NotEqual
1444 | LeftAngleBracket
1445 | RightAngleBracket
1446 | LessThanOrEqual
1447 | GreaterThanOrEqual
1448 | AmpersandDouble
1449 | Pipeline
1450 | Equal
1451 | PlusEqual
1452 | MinusEqual
1453 | StarEqual
1454 | SlashEqual
1455 | PercentEqual
1456 | DotDot
1457 | DotDotEqual
1458 | As
1459 ),
1460
1461 _ => true,
1462 }
1463 }
1464
1465 fn recover_keyword_as_identifier(&mut self) -> Expression {
1466 let token = self.current_token();
1467 let keyword = token.text.to_string();
1468 let span = self.span_from_token(token);
1469 let error = ParseError::new("Reserved keyword", span, "reserved keyword")
1470 .with_parse_code("keyword_as_identifier")
1471 .with_help(format!("Rename `{}`", keyword));
1472 self.errors.push(error);
1473 self.next();
1474 Expression::Identifier {
1475 value: keyword.into(),
1476 ty: Type::uninferred(),
1477 span,
1478 binding_id: None,
1479 qualified: None,
1480 }
1481 }
1482
1483 fn recover_backtick_as_raw_string(&mut self) -> Expression {
1484 let token = self.current_token();
1485 let span = self.span_from_token(token);
1486 let raw = token.text;
1487 let inner = if raw.len() >= 2 && raw.starts_with('`') && raw.ends_with('`') {
1488 &raw[1..raw.len() - 1]
1489 } else {
1490 raw
1491 };
1492 let help = if inner.contains('"') {
1493 "Lisette uses `r\"...\"` for raw strings, not backticks like Go".to_string()
1494 } else {
1495 format!(
1496 "Lisette uses `r\"...\"` for raw strings, not backticks like Go, so replace with `r\"{}\"`",
1497 inner
1498 )
1499 };
1500 let error = ParseError::new(
1501 "Backticks are not raw strings in Lisette",
1502 span,
1503 "expected `r\"...\"`",
1504 )
1505 .with_parse_code("backtick_in_expression")
1506 .with_help(help);
1507 self.errors.push(error);
1508 self.next();
1509 Expression::Literal {
1510 literal: Literal::String {
1511 value: inner.to_string(),
1512 raw: true,
1513 },
1514 ty: Type::uninferred(),
1515 span,
1516 }
1517 }
1518}