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_right_angle_like() {
515 break;
516 }
517
518 self.ensure(Comma);
519 }
520
521 if !self.advance_if_right_angle() {
522 self.ensure(RightAngleBracket);
523 }
524
525 type_args
526 }
527
528 pub fn parse_binary_operator(&mut self) -> BinaryOperator {
529 let operator = match self.current_token().kind {
530 Plus => BinaryOperator::Addition,
531 Minus => BinaryOperator::Subtraction,
532 Star => BinaryOperator::Multiplication,
533 Slash => BinaryOperator::Division,
534 Ampersand => BinaryOperator::BitwiseAnd,
535 Pipe => BinaryOperator::BitwiseOr,
536 Caret => BinaryOperator::BitwiseXor,
537 AndNot => BinaryOperator::BitwiseAndNot,
538 ShiftLeft => BinaryOperator::ShiftLeft,
539 ShiftRight => BinaryOperator::ShiftRight,
540 LeftAngleBracket => BinaryOperator::LessThan,
541 LessThanOrEqual => BinaryOperator::LessThanOrEqual,
542 RightAngleBracket => BinaryOperator::GreaterThan,
543 GreaterThanOrEqual => BinaryOperator::GreaterThanOrEqual,
544 Percent => BinaryOperator::Remainder,
545 EqualDouble => BinaryOperator::Equal,
546 NotEqual => BinaryOperator::NotEqual,
547 AmpersandDouble => BinaryOperator::And,
548 PipeDouble => BinaryOperator::Or,
549 Pipeline => {
550 self.has_desugarables = true;
551 BinaryOperator::Pipeline
552 }
553
554 _ => {
555 self.track_error(format!(
556 "expected binary operator, found {}",
557 self.current_token().kind
558 ), "Binary operators: `+`, `-`, `*`, `/`, `%`, `&`, `|`, `^`, `&^`, `<<`, `>>`, `==`, `!=`, `<`, `>`, `<=`, `>=`, `&&`, `||`.");
559 BinaryOperator::Addition }
561 };
562
563 self.next();
564
565 operator
566 }
567
568 fn parse_parenthesized_expression(&mut self) -> Expression {
569 let start = self.current_token();
570
571 let (expressions, has_trailing_comma) =
572 self.collect_delimited_expressions(LeftParen, RightParen);
573 let span = self.span_from_tokens(start);
574
575 match expressions.len() {
576 0 => Expression::Unit {
577 ty: Type::uninferred(),
578 span,
579 },
580 1 => {
581 if has_trailing_comma {
582 self.error_tuple_arity(1, span);
583 }
584 let expression = expressions.into_iter().next().expect("len is 1");
585 Expression::Paren {
586 ty: Type::uninferred(),
587 expression: expression.into(),
588 span,
589 }
590 }
591 n => {
592 if n > MAX_TUPLE_ARITY {
593 self.error_tuple_arity(n, span);
594 }
595 Expression::Tuple {
596 ty: Type::uninferred(),
597 elements: expressions,
598 span,
599 }
600 }
601 }
602 }
603
604 pub fn parse_try(&mut self, expression: Expression) -> Expression {
605 let start_offset = expression.get_span().byte_offset;
606
607 self.ensure(QuestionMark);
608
609 Expression::Propagate {
610 ty: Type::uninferred(),
611 expression: expression.into(),
612 span: self.span_from_offset(start_offset),
613 }
614 }
615
616 fn parse_lambda(&mut self) -> Expression {
617 let start = self.current_token();
618
619 let params = if self.is(Pipe) {
620 self.parse_lambda_params()
621 } else {
622 self.next();
623 vec![]
624 };
625
626 let has_return_type = self.is(Arrow);
627 let return_annotation = if has_return_type {
628 self.next();
629 self.parse_annotation()
630 } else {
631 Annotation::Unknown
632 };
633
634 if has_return_type && self.current_token().kind != LeftCurlyBrace {
635 self.track_error(
636 "not allowed",
637 "A lambda with a return type requires a block body",
638 );
639 }
640
641 let body = self.parse_expression();
642
643 Expression::Lambda {
644 params,
645 return_annotation,
646 body: body.into(),
647 ty: Type::uninferred(),
648 span: self.span_from_tokens(start),
649 }
650 }
651
652 pub fn parse_block_expression(&mut self) -> Expression {
653 let start = self.current_token();
654
655 self.ensure(LeftCurlyBrace);
656
657 if self.looks_like_map_literal() {
658 let key_span = self.span_from_token(self.current_token());
659 self.consume_to_matching_close_brace();
660 self.error_map_literal_not_supported(key_span);
661 return Expression::Block {
662 ty: Type::uninferred(),
663 items: vec![],
664 span: self.span_from_tokens(start),
665 };
666 }
667
668 if !self.enter_recursion() {
669 let span = self.span_from_token(self.current_token());
670 let mut brace_depth = 1u32;
671 while brace_depth > 0 && !self.at_eof() {
672 match self.current_token().kind {
673 LeftCurlyBrace => brace_depth += 1,
674 RightCurlyBrace => brace_depth -= 1,
675 _ => {}
676 }
677 if brace_depth > 0 {
678 self.next();
679 }
680 }
681 self.advance_if(RightCurlyBrace);
682 return Expression::Block {
683 ty: Type::uninferred(),
684 items: vec![],
685 span,
686 };
687 }
688
689 let mut items = vec![];
690
691 while self.is_not(RightCurlyBrace) && !self.too_many_errors() {
692 let position = self.position();
693 let item = self.parse_block_item();
694
695 self.advance_if(Semicolon);
696
697 items.push(item);
698 if self.position() == position {
699 self.next();
700 }
701 }
702
703 let span = self.close_brace_span(start, start);
704
705 self.leave_recursion();
706
707 Expression::Block {
708 ty: Type::uninferred(),
709 items,
710 span,
711 }
712 }
713
714 pub fn parse_function_params(&mut self) -> Vec<Binding> {
715 self.ensure(LeftParen);
716
717 let mut params = vec![];
718
719 while self.is_not(RightParen) {
720 params.push(self.parse_binding_with_type());
721 self.expect_comma_or(RightParen);
722 }
723
724 self.ensure(RightParen);
725
726 params
727 }
728
729 pub fn parse_lambda_params(&mut self) -> Vec<Binding> {
730 self.ensure(Pipe);
731
732 let mut params = vec![];
733
734 while self.is_not(Pipe) {
735 params.push(self.parse_binding());
736 self.expect_comma_or(Pipe);
737 }
738
739 self.ensure(Pipe);
740
741 params
742 }
743
744 pub fn parse_function(
745 &mut self,
746 doc: Option<std::string::String>,
747 attributes: Vec<Attribute>,
748 ) -> Expression {
749 let start = self.current_token();
750
751 self.ensure(Function);
752
753 let name_token = self.current_token();
754 let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
755
756 let name = self.read_identifier_sequence();
757
758 let name_span = Span::new(name_span.file_id, name_span.byte_offset, name.len() as u32);
759
760 let generics = self.parse_generics();
761 let params = self.parse_function_params();
762 let return_annotation = self.parse_function_return_annotation();
763
764 let body = if self.is(LeftCurlyBrace) {
765 self.parse_block_expression()
766 } else {
767 Expression::NoOp
768 };
769
770 Expression::Function {
771 doc,
772 attributes,
773 name,
774 name_span,
775 generics,
776 params,
777 return_annotation,
778 return_type: Type::uninferred(),
779 visibility: Visibility::Private,
780 body: body.into(),
781 ty: Type::uninferred(),
782 span: self.span_from_tokens(start),
783 }
784 }
785
786 pub fn parse_field_access(&mut self, expression: Expression) -> Expression {
787 self.ensure(Dot);
788
789 let expression_start = expression.get_span().byte_offset;
790 let start = self.current_token();
791
792 if self.advance_if(Star) {
793 return Expression::Unary {
794 ty: Type::uninferred(),
795 operator: UnaryOperator::Deref,
796 expression: expression.into(),
797 span: self.span_from_tokens(start),
798 };
799 }
800
801 if self.is(Integer) {
802 let text = self.current_token().text;
803 let index: u32 = text.parse().unwrap_or_else(|_| {
804 self.track_error(
805 format!("tuple index '{}' is too large", text),
806 "Maximum index is `4294967295`.",
807 );
808 0
809 });
810
811 self.ensure(Integer);
812
813 return Expression::DotAccess {
814 ty: Type::uninferred(),
815 expression: expression.into(),
816 member: index.to_string().into(),
817 span: self.span_from_offset(expression_start),
818 dot_access_kind: None,
819 receiver_coercion: None,
820 };
821 }
822
823 let field = self.current_token().text;
824
825 self.ensure(Identifier);
826
827 Expression::DotAccess {
828 ty: Type::uninferred(),
829 expression: expression.into(),
830 member: field.into(),
831 span: self.span_from_offset(expression_start),
832 dot_access_kind: None,
833 receiver_coercion: None,
834 }
835 }
836
837 pub fn collect_delimited_expressions(
838 &mut self,
839 open: TokenKind,
840 close: TokenKind,
841 ) -> (Vec<Expression>, bool) {
842 self.ensure(open);
843
844 let mut expressions = vec![];
845 let mut has_trailing_comma = false;
846 loop {
847 if self.at_eof() || self.is(close) {
848 break;
849 }
850
851 if self.is(Function) && self.stream.peek_ahead(1).kind == LeftParen {
852 let span = self.track_fn_as_lambda_error();
853 self.resync_on_error();
854 expressions.push(Expression::Unit {
855 ty: Type::uninferred(),
856 span,
857 });
858 continue;
859 }
860
861 if self.at_item_boundary() {
862 let next = self.stream.peek_ahead(1).kind;
863 if next != close && next != Comma {
864 break;
865 }
866 }
867 expressions.push(self.parse_expression());
868 has_trailing_comma = self.is(Comma);
869 self.expect_comma_or(close);
870 }
871
872 self.advance_if(close);
873
874 (expressions, has_trailing_comma)
875 }
876
877 fn make_expression_name(&mut self, expression: &Expression) -> EcoString {
878 let mut parts = Vec::new();
879 let mut current = expression;
880
881 loop {
882 match current {
883 Expression::Identifier { value, .. } => {
884 parts.push(value.clone());
885 break;
886 }
887 Expression::DotAccess {
888 expression, member, ..
889 } => {
890 parts.push(member.clone());
891 current = expression;
892 }
893 _ => {
894 self.track_error(
895 "unexpected expression",
896 "Expected an identifier or dotted path.",
897 );
898 return "_".into();
899 }
900 }
901 }
902
903 parts.reverse();
904 parts.join(".").into()
905 }
906
907 pub fn parse_let(&mut self) -> Expression {
908 let start = self.current_token();
909
910 self.ensure(Let);
911
912 let (mutable, mut_span) = if self.is(Mut) {
913 let mut_token = self.current_token();
914 let span = Span::new(self.file_id, mut_token.byte_offset, mut_token.byte_length);
915 self.next(); (true, Some(span))
917 } else {
918 (false, None)
919 };
920
921 let binding = self.parse_binding_allowing_or();
922
923 if !self.is(Equal)
924 && let Some(Annotation::Constructor { span, .. }) = binding.annotation.as_ref()
925 {
926 self.error_missing_initializer(*span);
927 let stub_span = self.span_from_tokens(start);
928 return Expression::Let {
929 binding: Box::new(binding),
930 value: Box::new(Expression::Block {
931 ty: Type::uninferred(),
932 items: vec![],
933 span: stub_span,
934 }),
935 mutable,
936 mut_span,
937 else_block: None,
938 else_span: None,
939 typed_pattern: None,
940 ty: Type::uninferred(),
941 span: stub_span,
942 };
943 }
944
945 self.ensure(Equal);
946
947 let expression = self.parse_expression();
948
949 let (else_block, else_span) = if self.is(Else) {
950 let else_token = self.current_token();
951 let span = Span::new(self.file_id, else_token.byte_offset, else_token.byte_length);
952 self.next(); (Some(Box::new(self.parse_block_expression())), Some(span))
954 } else {
955 (None, None)
956 };
957
958 Expression::Let {
959 binding: Box::new(binding),
960 value: expression.into(),
961 mutable,
962 mut_span,
963 else_block,
964 else_span,
965 typed_pattern: None,
966 ty: Type::uninferred(),
967 span: self.span_from_tokens(start),
968 }
969 }
970
971 pub fn parse_import(&mut self) -> Expression {
972 let start = self.current_token();
973
974 self.ensure(Import);
975
976 let alias = if self.current_token().kind == Identifier {
977 let alias_token = self.current_token();
978 let alias_text = alias_token.text;
979 let alias_span = Span::new(
980 self.file_id,
981 alias_token.byte_offset,
982 alias_token.byte_length,
983 );
984
985 if alias_text == "_" {
986 self.next();
987 Some(ImportAlias::Blank(alias_span))
988 } else if self.stream.peek_ahead(1).kind == String {
989 self.next();
990 Some(ImportAlias::Named(alias_text.into(), alias_span))
991 } else {
992 None
993 }
994 } else {
995 None
996 };
997
998 let name_token = self.current_token();
999
1000 if name_token.kind != String {
1001 let (label, help) = if name_token.kind == Identifier
1002 && self.stream.peek_ahead(1).kind == Colon
1003 {
1004 let module_name = name_token.text;
1005 (
1006 "expected double quotes".to_string(),
1007 format!(
1008 "Wrap the import path in double quotes: `import \"{0}:...\"`",
1009 module_name
1010 ),
1011 )
1012 } else if name_token.kind == Identifier {
1013 let module_name = name_token.text;
1014 (
1015 "expected double quotes".to_string(),
1016 format!(
1017 "Wrap the import path in double quotes: `import \"{}\"`",
1018 module_name
1019 ),
1020 )
1021 } else {
1022 (
1023 "expected module path".to_string(),
1024 "Wrap the import path in double quotes, e.g. `import \"go:os\"`".to_string(),
1025 )
1026 };
1027
1028 self.track_error(label, help);
1029 self.resync_on_error();
1030 return Expression::Unit {
1031 ty: Type::uninferred(),
1032 span: self.span_from_tokens(start),
1033 };
1034 }
1035
1036 self.next();
1037
1038 let raw = name_token.text;
1039 let unquoted: &str = if raw.len() >= 2 && raw.starts_with('"') && raw.ends_with('"') {
1040 &raw[1..raw.len() - 1]
1041 } else {
1042 debug_assert!(
1043 false,
1044 "lexer produced String token without quotes: {:?}",
1045 raw
1046 );
1047 raw
1048 };
1049
1050 if alias.is_none() && self.is(As) && self.stream.peek_ahead(1).kind == Identifier {
1051 let as_token = self.current_token();
1052 let alias_identifier = self.stream.peek_ahead(1);
1053 self.next();
1054 self.next();
1055 self.error_import_alias_after_path(
1056 self.span_from_tokens(as_token),
1057 alias_identifier.text,
1058 unquoted,
1059 );
1060 }
1061
1062 let name: EcoString = unquoted.into();
1063 let name_span = Span::new(self.file_id, name_token.byte_offset, name_token.byte_length);
1064
1065 Expression::ModuleImport {
1066 name,
1067 name_span,
1068 alias,
1069 span: self.span_from_tokens(start),
1070 }
1071 }
1072
1073 pub fn parse_assignment(&mut self) -> Expression {
1074 let start = self.current_token();
1075
1076 let lhs = self.parse_expression();
1077
1078 let compound_operator = match self.current_token().kind {
1079 PlusEqual => Some(BinaryOperator::Addition),
1080 MinusEqual => Some(BinaryOperator::Subtraction),
1081 StarEqual => Some(BinaryOperator::Multiplication),
1082 SlashEqual => Some(BinaryOperator::Division),
1083 PercentEqual => Some(BinaryOperator::Remainder),
1084 AmpersandEqual => Some(BinaryOperator::BitwiseAnd),
1085 PipeEqual => Some(BinaryOperator::BitwiseOr),
1086 CaretEqual => Some(BinaryOperator::BitwiseXor),
1087 AndNotEqual => Some(BinaryOperator::BitwiseAndNot),
1088 ShiftLeftEqual => Some(BinaryOperator::ShiftLeft),
1089 ShiftRightEqual => Some(BinaryOperator::ShiftRight),
1090 _ => None,
1091 };
1092
1093 if let Some(operator) = compound_operator {
1094 if !self.is_valid_assignment_target(&lhs) {
1095 self.track_error(
1096 "invalid assignment target",
1097 "Only variables, fields, and indices can be assigned to.",
1098 );
1099 self.next();
1100 let _rhs = self.parse_expression();
1101 return lhs;
1102 }
1103 self.next();
1104 let rhs = self.parse_expression();
1105 return Expression::Assignment {
1106 target: lhs.clone().into(),
1107 value: Expression::Binary {
1108 left: lhs.into(),
1109 operator,
1110 right: rhs.into(),
1111 ty: Type::uninferred(),
1112 span: self.span_from_tokens(start),
1113 }
1114 .into(),
1115 compound_operator: Some(operator),
1116 span: self.span_from_tokens(start),
1117 };
1118 }
1119
1120 if self.current_token().kind == Colon && self.stream.peek_ahead(1).kind == Equal {
1121 let span = Span::new(self.file_id, self.current_token().byte_offset, 2);
1122 self.track_error_at(
1123 span,
1124 "Go-style short declaration",
1125 "Use `let x = ...` instead of `:=` for variable declarations",
1126 );
1127 self.next();
1128 self.next();
1129 let _ = self.parse_expression();
1130 return lhs;
1131 }
1132
1133 if !self.is(Equal) {
1134 return lhs;
1135 }
1136
1137 if !self.is_valid_assignment_target(&lhs) {
1138 self.track_error(
1139 "invalid assignment target",
1140 "Only variables, fields, and indices can be assigned to.",
1141 );
1142 }
1143
1144 self.ensure(Equal);
1145
1146 Expression::Assignment {
1147 target: lhs.into(),
1148 value: self.parse_expression().into(),
1149 compound_operator: None,
1150 span: self.span_from_tokens(start),
1151 }
1152 }
1153
1154 fn is_valid_assignment_target(&self, expression: &Expression) -> bool {
1155 use Expression::*;
1156
1157 matches!(
1158 expression,
1159 Identifier { .. }
1160 | DotAccess { .. }
1161 | IndexedAccess { .. }
1162 | Unary {
1163 operator: UnaryOperator::Deref,
1164 ..
1165 }
1166 )
1167 }
1168
1169 fn parse_format_string(&mut self) -> Expression {
1170 let start = self.current_token();
1171 self.ensure(FormatStringStart);
1172
1173 let mut parts = Vec::new();
1174
1175 loop {
1176 if self.at_eof() || self.at_item_boundary() {
1177 break;
1178 }
1179 match self.current_token().kind {
1180 FormatStringText => {
1181 let text = self.current_token().text;
1182 self.next();
1183 parts.push(FormatStringPart::Text(cook_string_contents(text)));
1184 }
1185 FormatStringInterpolationStart => {
1186 self.ensure(FormatStringInterpolationStart);
1187 let expression = self.parse_expression();
1188 parts.push(FormatStringPart::Expression(Box::new(expression)));
1189 if self.is(Colon) {
1190 let start_offset = self.current_token().byte_offset;
1191 self.next();
1192 while !self.at_eof()
1193 && !self.is(FormatStringInterpolationEnd)
1194 && !self.is(FormatStringEnd)
1195 && !self.at_item_boundary()
1196 {
1197 self.next();
1198 }
1199 let span = self.span_from_offset(start_offset);
1200 let error = ParseError::new(
1201 "Format specifiers not supported",
1202 span,
1203 "not supported in format strings",
1204 )
1205 .with_parse_code("format_specifier")
1206 .with_help(
1207 "Use `fmt.Sprintf` for formatted output, e.g. `fmt.Sprintf(\"%02x\", n)`",
1208 );
1209 self.errors.push(error);
1210 }
1211 self.advance_if(FormatStringInterpolationEnd);
1212 }
1213 FormatStringEnd => {
1214 self.ensure(FormatStringEnd);
1215 break;
1216 }
1217 _ => break,
1218 }
1219 }
1220
1221 Expression::Literal {
1222 literal: Literal::FormatString(parts),
1223 ty: Type::uninferred(),
1224 span: self.span_from_tokens(start),
1225 }
1226 }
1227
1228 pub fn parse_task(&mut self) -> Expression {
1229 let start = self.current_token();
1230
1231 self.ensure(Task);
1232
1233 let expression = if self.is(LeftCurlyBrace) {
1234 self.parse_block_expression()
1235 } else {
1236 self.parse_expression()
1237 };
1238
1239 if !matches!(
1240 expression,
1241 Expression::Call { .. } | Expression::Block { .. }
1242 ) {
1243 let span = expression.get_span();
1244 let error = ParseError::new("Invalid `task`", span, "expected `()`")
1245 .with_parse_code("task_missing_parens")
1246 .with_help("Add parens to call the function");
1247
1248 self.errors.push(error);
1249 }
1250
1251 Expression::Task {
1252 expression: Box::new(expression),
1253 ty: Type::uninferred(),
1254 span: self.span_from_tokens(start),
1255 }
1256 }
1257
1258 pub fn parse_defer(&mut self) -> Expression {
1259 let start = self.current_token();
1260
1261 self.ensure(Defer);
1262
1263 let expression = if self.is(LeftCurlyBrace) {
1264 self.parse_block_expression()
1265 } else {
1266 self.parse_expression()
1267 };
1268
1269 if !matches!(
1270 expression,
1271 Expression::Call { .. } | Expression::Block { .. }
1272 ) {
1273 let span = expression.get_span();
1274 let error = ParseError::new("Invalid `defer`", span, "expected `()`")
1275 .with_parse_code("defer_missing_parens")
1276 .with_help("Add parens to call the function");
1277
1278 self.errors.push(error);
1279 }
1280
1281 Expression::Defer {
1282 expression: Box::new(expression),
1283 ty: Type::uninferred(),
1284 span: self.span_from_tokens(start),
1285 }
1286 }
1287
1288 pub fn parse_try_block(&mut self) -> Expression {
1289 let start = self.current_token();
1290 let try_keyword_span = Span::new(self.file_id, start.byte_offset, start.byte_length);
1291
1292 self.ensure(Try);
1293
1294 if !self.is(LeftCurlyBrace) {
1295 let span = self.span_from_tokens(start);
1296 let error = ParseError::new("Invalid `try`", span, "requires a block")
1297 .with_parse_code("syntax_error")
1298 .with_help("Use `try { expression }` instead of `try expression`");
1299 self.errors.push(error);
1300 let expression = self.parse_expression();
1301 return Expression::TryBlock {
1302 items: vec![expression],
1303 ty: Type::uninferred(),
1304 try_keyword_span,
1305 span: self.span_from_tokens(start),
1306 };
1307 }
1308
1309 let brace_token = self.current_token();
1310 self.ensure(LeftCurlyBrace);
1311
1312 if !self.enter_recursion() {
1313 let span = self.span_from_token(self.current_token());
1314 let mut brace_depth = 1u32;
1315 while brace_depth > 0 && !self.at_eof() {
1316 match self.current_token().kind {
1317 LeftCurlyBrace => brace_depth += 1,
1318 RightCurlyBrace => brace_depth -= 1,
1319 _ => {}
1320 }
1321 if brace_depth > 0 {
1322 self.next();
1323 }
1324 }
1325 self.advance_if(RightCurlyBrace);
1326 return Expression::TryBlock {
1327 items: vec![],
1328 ty: Type::uninferred(),
1329 try_keyword_span,
1330 span,
1331 };
1332 }
1333
1334 let mut items = vec![];
1335
1336 while self.is_not(RightCurlyBrace) && !self.too_many_errors() {
1337 let position = self.position();
1338 let item = self.parse_block_item();
1339
1340 self.advance_if(Semicolon);
1341
1342 items.push(item);
1343 if self.position() == position {
1344 self.next();
1345 }
1346 }
1347
1348 let span = self.close_brace_span(start, brace_token);
1349
1350 self.leave_recursion();
1351
1352 Expression::TryBlock {
1353 items,
1354 ty: Type::uninferred(),
1355 try_keyword_span,
1356 span,
1357 }
1358 }
1359
1360 pub fn parse_recover_block(&mut self) -> Expression {
1361 let start = self.current_token();
1362 let recover_keyword_span = Span::new(self.file_id, start.byte_offset, start.byte_length);
1363
1364 self.ensure(Recover);
1365
1366 if !self.is(LeftCurlyBrace) {
1367 let span = self.span_from_tokens(start);
1368 let error = ParseError::new("Invalid `recover`", span, "requires a block")
1369 .with_parse_code("syntax_error")
1370 .with_help("Use `recover { expression }` instead of `recover expression`");
1371 self.errors.push(error);
1372 let expression = self.parse_expression();
1373 return Expression::RecoverBlock {
1374 items: vec![expression],
1375 ty: Type::uninferred(),
1376 recover_keyword_span,
1377 span: self.span_from_tokens(start),
1378 };
1379 }
1380
1381 let brace_token = self.current_token();
1382 self.ensure(LeftCurlyBrace);
1383
1384 if !self.enter_recursion() {
1385 let span = self.span_from_token(self.current_token());
1386 let mut brace_depth = 1u32;
1387 while brace_depth > 0 && !self.at_eof() {
1388 match self.current_token().kind {
1389 LeftCurlyBrace => brace_depth += 1,
1390 RightCurlyBrace => brace_depth -= 1,
1391 _ => {}
1392 }
1393 if brace_depth > 0 {
1394 self.next();
1395 }
1396 }
1397 self.advance_if(RightCurlyBrace);
1398 return Expression::RecoverBlock {
1399 items: vec![],
1400 ty: Type::uninferred(),
1401 recover_keyword_span,
1402 span,
1403 };
1404 }
1405
1406 let mut items = vec![];
1407
1408 while self.is_not(RightCurlyBrace) && !self.too_many_errors() {
1409 let position = self.position();
1410 let item = self.parse_block_item();
1411
1412 self.advance_if(Semicolon);
1413
1414 items.push(item);
1415 if self.position() == position {
1416 self.next();
1417 }
1418 }
1419
1420 let span = self.close_brace_span(start, brace_token);
1421
1422 self.leave_recursion();
1423
1424 Expression::RecoverBlock {
1425 items,
1426 ty: Type::uninferred(),
1427 recover_keyword_span,
1428 span,
1429 }
1430 }
1431
1432 pub fn parse_select(&mut self) -> Expression {
1433 let start = self.current_token();
1434
1435 self.ensure(Select);
1436 self.ensure(LeftCurlyBrace);
1437
1438 let mut arms = Vec::new();
1439
1440 while self.is_not(RightCurlyBrace) {
1441 let arm = self.parse_select_arm();
1442 arms.push(arm);
1443
1444 if self.is(RightCurlyBrace) {
1445 break;
1446 }
1447
1448 self.ensure(Comma);
1449 }
1450
1451 self.ensure(RightCurlyBrace);
1452
1453 Expression::Select {
1454 arms,
1455 ty: Type::uninferred(),
1456 span: self.span_from_tokens(start),
1457 }
1458 }
1459
1460 fn parse_select_arm(&mut self) -> SelectArm {
1461 match self.current_token().kind {
1462 Let => {
1463 self.ensure(Let);
1464 let binding = self.parse_pattern();
1465 self.ensure(Equal);
1466 let receive_expression = Box::new(self.parse_expression());
1467 self.ensure(ArrowDouble);
1468 let body = Box::new(self.parse_expression());
1469 SelectArm {
1470 pattern: SelectArmPattern::Receive {
1471 binding: Box::new(binding),
1472 typed_pattern: None,
1473 receive_expression,
1474 body,
1475 },
1476 }
1477 }
1478 Match => {
1479 let match_expression = self.parse_match();
1480 if let Expression::Match { subject, arms, .. } = match_expression {
1481 SelectArm {
1482 pattern: SelectArmPattern::MatchReceive {
1483 receive_expression: subject,
1484 arms,
1485 },
1486 }
1487 } else {
1488 self.ensure(ArrowDouble);
1489 let body = Box::new(self.parse_expression());
1490 SelectArm {
1491 pattern: SelectArmPattern::Send {
1492 send_expression: Box::new(match_expression),
1493 body,
1494 },
1495 }
1496 }
1497 }
1498 Identifier if self.current_token().text == "_" => {
1499 self.next();
1500 self.ensure(ArrowDouble);
1501 let body = Box::new(self.parse_expression());
1502 SelectArm {
1503 pattern: SelectArmPattern::WildCard { body },
1504 }
1505 }
1506 _ => {
1507 let send_expression = Box::new(self.parse_expression());
1508 self.ensure(ArrowDouble);
1509 let body = Box::new(self.parse_expression());
1510 SelectArm {
1511 pattern: SelectArmPattern::Send {
1512 send_expression,
1513 body,
1514 },
1515 }
1516 }
1517 }
1518 }
1519
1520 pub fn with_control_flow_header<F, R>(&mut self, f: F) -> R
1521 where
1522 F: FnOnce(&mut Self) -> R,
1523 {
1524 let old = self.in_control_flow_header;
1525 self.in_control_flow_header = true;
1526 let result = f(self);
1527 self.in_control_flow_header = old;
1528 result
1529 }
1530
1531 fn keyword_in_value_position(&self) -> bool {
1532 if !self.current_token().kind.is_keyword() {
1533 return false;
1534 }
1535
1536 match self.current_token().kind {
1537 Return | Break | Continue => false,
1538
1539 Match | If | Task | Defer | Try | Recover | Select | Loop | Function => matches!(
1540 self.stream.peek_ahead(1).kind,
1541 RightParen
1542 | Comma
1543 | Dot
1544 | Semicolon
1545 | RightCurlyBrace
1546 | RightSquareBracket
1547 | ArrowDouble
1548 | QuestionMark
1549 | EOF
1550 | Plus
1551 | Star
1552 | Slash
1553 | Percent
1554 | EqualDouble
1555 | NotEqual
1556 | LeftAngleBracket
1557 | RightAngleBracket
1558 | LessThanOrEqual
1559 | GreaterThanOrEqual
1560 | AmpersandDouble
1561 | Ampersand
1562 | Pipe
1563 | Caret
1564 | AndNot
1565 | ShiftLeft
1566 | ShiftRight
1567 | Pipeline
1568 | Equal
1569 | PlusEqual
1570 | MinusEqual
1571 | StarEqual
1572 | SlashEqual
1573 | PercentEqual
1574 | AmpersandEqual
1575 | PipeEqual
1576 | CaretEqual
1577 | AndNotEqual
1578 | ShiftLeftEqual
1579 | ShiftRightEqual
1580 | DotDot
1581 | DotDotEqual
1582 | As
1583 ),
1584
1585 _ => true,
1586 }
1587 }
1588
1589 fn recover_keyword_as_identifier(&mut self) -> Expression {
1590 let token = self.current_token();
1591 let keyword = token.text.to_string();
1592 let span = self.span_from_token(token);
1593 let error = ParseError::new("Reserved keyword", span, "reserved keyword")
1594 .with_parse_code("keyword_as_identifier")
1595 .with_help(format!("Rename `{}`", keyword));
1596 self.errors.push(error);
1597 self.next();
1598 Expression::Identifier {
1599 value: keyword.into(),
1600 ty: Type::uninferred(),
1601 span,
1602 binding_id: None,
1603 qualified: None,
1604 }
1605 }
1606
1607 fn looks_like_map_literal(&self) -> bool {
1608 let first = self.current_token().kind;
1609 let second = self.stream.peek_ahead(1).kind;
1610 matches!(first, String | RawString | Integer | Float) && second == Colon
1611 }
1612
1613 fn consume_to_matching_close_brace(&mut self) {
1614 let mut brace_depth = 1u32;
1615 while brace_depth > 0 && !self.at_eof() {
1616 match self.current_token().kind {
1617 LeftCurlyBrace => brace_depth += 1,
1618 RightCurlyBrace => brace_depth -= 1,
1619 _ => {}
1620 }
1621 if brace_depth > 0 {
1622 self.next();
1623 }
1624 }
1625 self.advance_if(RightCurlyBrace);
1626 }
1627
1628 fn recover_unexpected_backtick(&mut self) -> Expression {
1629 let token = self.current_token();
1630 let token_span = self.span_from_token(token);
1631 let opening_span = Span::new(self.file_id, token.byte_offset, 1);
1632 let error = ParseError::new("Unexpected backtick", opening_span, "not allowed here")
1633 .with_parse_code("unexpected_backtick")
1634 .with_help(
1635 "Use a regular string `\"...\"` or a raw string `r\"...\"` for single- or multi-line strings. Backticks in Lisette are reserved for struct-tag attributes.",
1636 );
1637 self.errors.push(error);
1638 self.next();
1639 Expression::Literal {
1640 literal: Literal::String {
1641 value: std::string::String::new(),
1642 raw: true,
1643 },
1644 ty: Type::uninferred(),
1645 span: token_span,
1646 }
1647 }
1648}