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