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