1use crate::ast::*;
2use harn_lexer::{Span, TokenKind};
3
4use super::error::ParserError;
5use super::state::Parser;
6
7impl Parser {
8 pub fn parse_single_expression(&mut self) -> Result<SNode, ParserError> {
10 self.skip_newlines();
11 self.parse_expression()
12 }
13
14 pub(super) fn parse_expression(&mut self) -> Result<SNode, ParserError> {
15 self.skip_newlines();
16 self.parse_pipe()
17 }
18
19 pub(super) fn parse_pipe(&mut self) -> Result<SNode, ParserError> {
20 let mut left = self.parse_range()?;
21 while self.check_skip_newlines(&TokenKind::Pipe) {
22 let start = left.span;
23 self.advance();
24 self.skip_newlines();
25 let right = self.parse_range()?;
26 left = spanned(
27 Node::BinaryOp {
28 op: "|>".into(),
29 left: Box::new(left),
30 right: Box::new(right),
31 },
32 Span::merge(start, self.prev_span()),
33 );
34 }
35 Ok(left)
36 }
37
38 pub(super) fn parse_range(&mut self) -> Result<SNode, ParserError> {
39 let left = self.parse_ternary()?;
40 if self.check(&TokenKind::To) {
41 let start = left.span;
42 self.advance();
43 let right = self.parse_ternary()?;
44 let inclusive = if self.check(&TokenKind::Exclusive) {
45 self.advance();
46 false
47 } else {
48 true
49 };
50 return Ok(spanned(
51 Node::RangeExpr {
52 start: Box::new(left),
53 end: Box::new(right),
54 inclusive,
55 },
56 Span::merge(start, self.prev_span()),
57 ));
58 }
59 Ok(left)
60 }
61
62 pub(super) fn parse_ternary(&mut self) -> Result<SNode, ParserError> {
63 let condition = self.parse_logical_or()?;
64 if !self.check(&TokenKind::Question) {
65 return Ok(condition);
66 }
67 let start = condition.span;
68 self.advance(); let true_val = self.parse_logical_or()?;
70 self.consume(&TokenKind::Colon, ":")?;
71 let false_val = self.parse_logical_or()?;
72 Ok(spanned(
73 Node::Ternary {
74 condition: Box::new(condition),
75 true_expr: Box::new(true_val),
76 false_expr: Box::new(false_val),
77 },
78 Span::merge(start, self.prev_span()),
79 ))
80 }
81
82 pub(super) fn parse_nil_coalescing(&mut self) -> Result<SNode, ParserError> {
85 let mut left = self.parse_multiplicative()?;
86 while self.check_skip_newlines(&TokenKind::NilCoal) {
87 let start = left.span;
88 self.advance();
89 self.skip_newlines();
90 let right = self.parse_multiplicative()?;
91 left = spanned(
92 Node::BinaryOp {
93 op: "??".into(),
94 left: Box::new(left),
95 right: Box::new(right),
96 },
97 Span::merge(start, self.prev_span()),
98 );
99 }
100 Ok(left)
101 }
102
103 pub(super) fn parse_logical_or(&mut self) -> Result<SNode, ParserError> {
104 let mut left = self.parse_logical_and()?;
105 while self.check_skip_newlines(&TokenKind::Or) {
106 let start = left.span;
107 self.advance();
108 self.skip_newlines();
109 let right = self.parse_logical_and()?;
110 left = spanned(
111 Node::BinaryOp {
112 op: "||".into(),
113 left: Box::new(left),
114 right: Box::new(right),
115 },
116 Span::merge(start, self.prev_span()),
117 );
118 }
119 Ok(left)
120 }
121
122 pub(super) fn parse_logical_and(&mut self) -> Result<SNode, ParserError> {
123 let mut left = self.parse_equality()?;
124 while self.check_skip_newlines(&TokenKind::And) {
125 let start = left.span;
126 self.advance();
127 self.skip_newlines();
128 let right = self.parse_equality()?;
129 left = spanned(
130 Node::BinaryOp {
131 op: "&&".into(),
132 left: Box::new(left),
133 right: Box::new(right),
134 },
135 Span::merge(start, self.prev_span()),
136 );
137 }
138 Ok(left)
139 }
140
141 pub(super) fn parse_equality(&mut self) -> Result<SNode, ParserError> {
142 let mut left = self.parse_comparison()?;
143 while self.check_skip_newlines(&TokenKind::Eq) || self.check_skip_newlines(&TokenKind::Neq)
144 {
145 let start = left.span;
146 let op = if self.check(&TokenKind::Eq) {
147 "=="
148 } else {
149 "!="
150 };
151 self.advance();
152 self.skip_newlines();
153 let right = self.parse_comparison()?;
154 left = spanned(
155 Node::BinaryOp {
156 op: op.into(),
157 left: Box::new(left),
158 right: Box::new(right),
159 },
160 Span::merge(start, self.prev_span()),
161 );
162 }
163 Ok(left)
164 }
165
166 pub(super) fn parse_comparison(&mut self) -> Result<SNode, ParserError> {
167 let mut left = self.parse_additive()?;
168 loop {
169 if self.check_skip_newlines(&TokenKind::Lt)
170 || self.check_skip_newlines(&TokenKind::Gt)
171 || self.check_skip_newlines(&TokenKind::Lte)
172 || self.check_skip_newlines(&TokenKind::Gte)
173 {
174 let start = left.span;
175 let op = match self.current().map(|t| &t.kind) {
176 Some(TokenKind::Lt) => "<",
177 Some(TokenKind::Gt) => ">",
178 Some(TokenKind::Lte) => "<=",
179 Some(TokenKind::Gte) => ">=",
180 _ => "<",
181 };
182 self.advance();
183 self.skip_newlines();
184 let right = self.parse_additive()?;
185 left = spanned(
186 Node::BinaryOp {
187 op: op.into(),
188 left: Box::new(left),
189 right: Box::new(right),
190 },
191 Span::merge(start, self.prev_span()),
192 );
193 } else if self.check(&TokenKind::In) {
194 let start = left.span;
195 self.advance();
196 self.skip_newlines();
197 let right = self.parse_additive()?;
198 left = spanned(
199 Node::BinaryOp {
200 op: "in".into(),
201 left: Box::new(left),
202 right: Box::new(right),
203 },
204 Span::merge(start, self.prev_span()),
205 );
206 } else if self.check_identifier("not") {
207 let saved = self.pos;
208 self.advance();
209 if self.check(&TokenKind::In) {
210 let start = left.span;
211 self.advance();
212 self.skip_newlines();
213 let right = self.parse_additive()?;
214 left = spanned(
215 Node::BinaryOp {
216 op: "not_in".into(),
217 left: Box::new(left),
218 right: Box::new(right),
219 },
220 Span::merge(start, self.prev_span()),
221 );
222 } else {
223 self.pos = saved;
224 break;
225 }
226 } else {
227 break;
228 }
229 }
230 Ok(left)
231 }
232
233 pub(super) fn parse_additive(&mut self) -> Result<SNode, ParserError> {
234 let mut left = self.parse_nil_coalescing()?;
235 while self.check_skip_newlines(&TokenKind::Plus) || self.check(&TokenKind::Minus) {
236 let start = left.span;
237 let op = if self.check(&TokenKind::Plus) {
238 "+"
239 } else {
240 "-"
241 };
242 self.advance();
243 self.skip_newlines();
244 let right = self.parse_nil_coalescing()?;
245 left = spanned(
246 Node::BinaryOp {
247 op: op.into(),
248 left: Box::new(left),
249 right: Box::new(right),
250 },
251 Span::merge(start, self.prev_span()),
252 );
253 }
254 Ok(left)
255 }
256
257 pub(super) fn parse_multiplicative(&mut self) -> Result<SNode, ParserError> {
258 let mut left = self.parse_exponent()?;
259 while self.check_skip_newlines(&TokenKind::Star)
260 || self.check_skip_newlines(&TokenKind::Slash)
261 || self.check_skip_newlines(&TokenKind::Percent)
262 {
263 let start = left.span;
264 let op = if self.check(&TokenKind::Star) {
265 "*"
266 } else if self.check(&TokenKind::Slash) {
267 "/"
268 } else {
269 "%"
270 };
271 self.advance();
272 self.skip_newlines();
273 let right = self.parse_exponent()?;
274 left = spanned(
275 Node::BinaryOp {
276 op: op.into(),
277 left: Box::new(left),
278 right: Box::new(right),
279 },
280 Span::merge(start, self.prev_span()),
281 );
282 }
283 Ok(left)
284 }
285
286 pub(super) fn parse_exponent(&mut self) -> Result<SNode, ParserError> {
287 let left = self.parse_unary()?;
288 if !self.check_skip_newlines(&TokenKind::Pow) {
289 return Ok(left);
290 }
291
292 let start = left.span;
293 self.advance();
294 self.skip_newlines();
295 let right = self.parse_exponent()?;
296 Ok(spanned(
297 Node::BinaryOp {
298 op: "**".into(),
299 left: Box::new(left),
300 right: Box::new(right),
301 },
302 Span::merge(start, self.prev_span()),
303 ))
304 }
305
306 pub(super) fn parse_unary(&mut self) -> Result<SNode, ParserError> {
307 if self.check(&TokenKind::Not) {
308 let start = self.current_span();
309 self.advance();
310 let operand = self.parse_unary()?;
311 return Ok(spanned(
312 Node::UnaryOp {
313 op: "!".into(),
314 operand: Box::new(operand),
315 },
316 Span::merge(start, self.prev_span()),
317 ));
318 }
319 if self.check(&TokenKind::Minus) {
320 let start = self.current_span();
321 self.advance();
322 let operand = self.parse_unary()?;
323 return Ok(spanned(
324 Node::UnaryOp {
325 op: "-".into(),
326 operand: Box::new(operand),
327 },
328 Span::merge(start, self.prev_span()),
329 ));
330 }
331 self.parse_postfix()
332 }
333
334 pub(super) fn parse_postfix(&mut self) -> Result<SNode, ParserError> {
335 let mut expr = self.parse_primary()?;
336
337 loop {
338 if self.check_skip_newlines(&TokenKind::Dot)
339 || self.check_skip_newlines(&TokenKind::QuestionDot)
340 {
341 let optional = self.check(&TokenKind::QuestionDot);
342 let start = expr.span;
343 self.advance();
344 let member = self.consume_identifier_or_keyword("member name")?;
345 if self.check(&TokenKind::LParen) {
346 self.advance();
347 let args = self.parse_arg_list()?;
348 self.consume(&TokenKind::RParen, ")")?;
349 if optional {
350 expr = spanned(
351 Node::OptionalMethodCall {
352 object: Box::new(expr),
353 method: member,
354 args,
355 },
356 Span::merge(start, self.prev_span()),
357 );
358 } else {
359 expr = spanned(
360 Node::MethodCall {
361 object: Box::new(expr),
362 method: member,
363 args,
364 },
365 Span::merge(start, self.prev_span()),
366 );
367 }
368 } else if optional {
369 expr = spanned(
370 Node::OptionalPropertyAccess {
371 object: Box::new(expr),
372 property: member,
373 },
374 Span::merge(start, self.prev_span()),
375 );
376 } else {
377 expr = spanned(
378 Node::PropertyAccess {
379 object: Box::new(expr),
380 property: member,
381 },
382 Span::merge(start, self.prev_span()),
383 );
384 }
385 } else if self.check(&TokenKind::LBracket) {
386 let start = expr.span;
387 self.advance();
388
389 if self.check(&TokenKind::Colon) {
392 self.advance();
393 let end_expr = if self.check(&TokenKind::RBracket) {
394 None
395 } else {
396 Some(Box::new(self.parse_expression()?))
397 };
398 self.consume(&TokenKind::RBracket, "]")?;
399 expr = spanned(
400 Node::SliceAccess {
401 object: Box::new(expr),
402 start: None,
403 end: end_expr,
404 },
405 Span::merge(start, self.prev_span()),
406 );
407 } else {
408 let index = self.parse_expression()?;
409 if self.check(&TokenKind::Colon) {
410 self.advance();
411 let end_expr = if self.check(&TokenKind::RBracket) {
412 None
413 } else {
414 Some(Box::new(self.parse_expression()?))
415 };
416 self.consume(&TokenKind::RBracket, "]")?;
417 expr = spanned(
418 Node::SliceAccess {
419 object: Box::new(expr),
420 start: Some(Box::new(index)),
421 end: end_expr,
422 },
423 Span::merge(start, self.prev_span()),
424 );
425 } else {
426 self.consume(&TokenKind::RBracket, "]")?;
427 expr = spanned(
428 Node::SubscriptAccess {
429 object: Box::new(expr),
430 index: Box::new(index),
431 },
432 Span::merge(start, self.prev_span()),
433 );
434 }
435 }
436 } else if self.check(&TokenKind::LBrace) {
437 let struct_name = match &expr.node {
438 Node::Identifier(name) if self.is_struct_construct_lookahead(name) => {
439 Some(name.clone())
440 }
441 _ => None,
442 };
443 let Some(struct_name) = struct_name else {
444 break;
445 };
446 let start = expr.span;
447 self.advance();
448 let dict = self.parse_dict_literal(start)?;
449 let fields = match dict.node {
450 Node::DictLiteral(fields) => fields,
451 _ => unreachable!("dict parser must return a dict literal"),
452 };
453 expr = spanned(
454 Node::StructConstruct {
455 struct_name,
456 fields,
457 },
458 dict.span,
459 );
460 } else if self.check(&TokenKind::Lt) && matches!(expr.node, Node::Identifier(_)) {
461 let saved_pos = self.pos;
462 let start = expr.span;
463 self.advance();
464 let parsed_type_args = self.parse_type_arg_list();
465 if let Ok(type_args) = parsed_type_args {
466 if self.check(&TokenKind::LParen) {
467 self.advance();
468 let args = self.parse_arg_list()?;
469 self.consume(&TokenKind::RParen, ")")?;
470 if let Node::Identifier(name) = expr.node {
471 expr = spanned(
472 Node::FunctionCall {
473 name,
474 type_args,
475 args,
476 },
477 Span::merge(start, self.prev_span()),
478 );
479 }
480 } else {
481 self.pos = saved_pos;
482 break;
483 }
484 } else {
485 self.pos = saved_pos;
486 break;
487 }
488 } else if self.check(&TokenKind::LParen) && matches!(expr.node, Node::Identifier(_)) {
489 let start = expr.span;
490 self.advance();
491 let args = self.parse_arg_list()?;
492 self.consume(&TokenKind::RParen, ")")?;
493 if let Node::Identifier(name) = expr.node {
494 expr = spanned(
495 Node::FunctionCall {
496 name,
497 type_args: Vec::new(),
498 args,
499 },
500 Span::merge(start, self.prev_span()),
501 );
502 }
503 } else if self.check(&TokenKind::Question) {
504 let next_pos = self.pos + 1;
512 let next_kind = self.tokens.get(next_pos).map(|t| &t.kind);
513 if matches!(next_kind, Some(TokenKind::LBracket)) {
514 let start = expr.span;
515 self.advance(); self.advance(); let index = self.parse_expression()?;
518 self.consume(&TokenKind::RBracket, "]")?;
519 expr = spanned(
520 Node::OptionalSubscriptAccess {
521 object: Box::new(expr),
522 index: Box::new(index),
523 },
524 Span::merge(start, self.prev_span()),
525 );
526 continue;
527 }
528 let is_ternary = next_kind.is_some_and(|kind| {
532 matches!(
533 kind,
534 TokenKind::Identifier(_)
535 | TokenKind::IntLiteral(_)
536 | TokenKind::FloatLiteral(_)
537 | TokenKind::StringLiteral(_)
538 | TokenKind::InterpolatedString(_)
539 | TokenKind::True
540 | TokenKind::False
541 | TokenKind::Nil
542 | TokenKind::LParen
543 | TokenKind::LBrace
544 | TokenKind::Not
545 | TokenKind::Minus
546 | TokenKind::Fn
547 )
548 });
549 if is_ternary {
550 break;
551 }
552 let start = expr.span;
553 self.advance();
554 expr = spanned(
555 Node::TryOperator {
556 operand: Box::new(expr),
557 },
558 Span::merge(start, self.prev_span()),
559 );
560 } else {
561 break;
562 }
563 }
564
565 Ok(expr)
566 }
567
568 pub(super) fn parse_primary(&mut self) -> Result<SNode, ParserError> {
569 let tok = self.current().ok_or_else(|| ParserError::UnexpectedEof {
570 expected: "expression".into(),
571 span: self.prev_span(),
572 })?;
573 let start = self.current_span();
574
575 match &tok.kind {
576 TokenKind::StringLiteral(s) => {
577 let s = s.clone();
578 self.advance();
579 Ok(spanned(
580 Node::StringLiteral(s),
581 Span::merge(start, self.prev_span()),
582 ))
583 }
584 TokenKind::RawStringLiteral(s) => {
585 let s = s.clone();
586 self.advance();
587 Ok(spanned(
588 Node::RawStringLiteral(s),
589 Span::merge(start, self.prev_span()),
590 ))
591 }
592 TokenKind::InterpolatedString(segments) => {
593 let segments = segments.clone();
594 self.advance();
595 Ok(spanned(
596 Node::InterpolatedString(segments),
597 Span::merge(start, self.prev_span()),
598 ))
599 }
600 TokenKind::IntLiteral(n) => {
601 let n = *n;
602 self.advance();
603 Ok(spanned(
604 Node::IntLiteral(n),
605 Span::merge(start, self.prev_span()),
606 ))
607 }
608 TokenKind::FloatLiteral(n) => {
609 let n = *n;
610 self.advance();
611 Ok(spanned(
612 Node::FloatLiteral(n),
613 Span::merge(start, self.prev_span()),
614 ))
615 }
616 TokenKind::True => {
617 self.advance();
618 Ok(spanned(
619 Node::BoolLiteral(true),
620 Span::merge(start, self.prev_span()),
621 ))
622 }
623 TokenKind::False => {
624 self.advance();
625 Ok(spanned(
626 Node::BoolLiteral(false),
627 Span::merge(start, self.prev_span()),
628 ))
629 }
630 TokenKind::Nil => {
631 self.advance();
632 Ok(spanned(
633 Node::NilLiteral,
634 Span::merge(start, self.prev_span()),
635 ))
636 }
637 TokenKind::Identifier(name)
638 if name == "cost_route" && self.peek_kind() == Some(&TokenKind::LBrace) =>
639 {
640 self.parse_cost_route()
641 }
642 TokenKind::Identifier(name) => {
643 let name = name.clone();
644 self.advance();
645 Ok(spanned(
646 Node::Identifier(name),
647 Span::merge(start, self.prev_span()),
648 ))
649 }
650 TokenKind::LParen => {
651 self.advance();
652 let expr = self.parse_expression()?;
653 self.consume(&TokenKind::RParen, ")")?;
654 Ok(expr)
655 }
656 TokenKind::LBracket => self.parse_list_literal(),
657 TokenKind::LBrace => self.parse_dict_or_closure(),
658 TokenKind::Parallel => self.parse_parallel(),
659 TokenKind::Retry => self.parse_retry(),
660 TokenKind::If => self.parse_if_else(),
661 TokenKind::Spawn => self.parse_spawn_expr(),
662 TokenKind::RequestApproval => self.parse_hitl_expr(HitlKind::RequestApproval),
663 TokenKind::DualControl => self.parse_hitl_expr(HitlKind::DualControl),
664 TokenKind::AskUser => self.parse_hitl_expr(HitlKind::AskUser),
665 TokenKind::EscalateTo => self.parse_hitl_expr(HitlKind::EscalateTo),
666 TokenKind::DurationLiteral(ms) => {
667 let ms = *ms;
668 self.advance();
669 Ok(spanned(
670 Node::DurationLiteral(ms),
671 Span::merge(start, self.prev_span()),
672 ))
673 }
674 TokenKind::Deadline => self.parse_deadline(),
675 TokenKind::Try => self.parse_try_catch(),
676 TokenKind::Match => self.parse_match(),
677 TokenKind::Fn => self.parse_fn_expr(),
678 TokenKind::Lt
681 if matches!(self.peek_kind(), Some(&TokenKind::Lt))
682 && matches!(self.peek_kind_at(2), Some(TokenKind::Identifier(_))) =>
683 {
684 Err(ParserError::Unexpected {
685 got: "`<<` heredoc-like syntax".to_string(),
686 expected: "an expression — heredocs are only valid \
687 inside LLM tool-call argument JSON; \
688 for multiline strings in source code use \
689 triple-quoted `\"\"\"...\"\"\"`"
690 .to_string(),
691 span: start,
692 })
693 }
694 _ => Err(self.error("expression")),
695 }
696 }
697
698 pub(super) fn parse_fn_expr(&mut self) -> Result<SNode, ParserError> {
701 let start = self.current_span();
702 self.consume(&TokenKind::Fn, "fn")?;
703 self.consume(&TokenKind::LParen, "(")?;
704 let params = self.parse_typed_param_list()?;
705 self.consume(&TokenKind::RParen, ")")?;
706 self.consume(&TokenKind::LBrace, "{")?;
707 let body = self.parse_block()?;
708 self.consume(&TokenKind::RBrace, "}")?;
709 Ok(spanned(
710 Node::Closure {
711 params,
712 body,
713 fn_syntax: true,
714 },
715 Span::merge(start, self.prev_span()),
716 ))
717 }
718
719 pub(super) fn parse_spawn_expr(&mut self) -> Result<SNode, ParserError> {
720 let start = self.current_span();
721 self.consume(&TokenKind::Spawn, "spawn")?;
722 self.consume(&TokenKind::LBrace, "{")?;
723 let body = self.parse_block()?;
724 self.consume(&TokenKind::RBrace, "}")?;
725 Ok(spanned(
726 Node::SpawnExpr { body },
727 Span::merge(start, self.prev_span()),
728 ))
729 }
730
731 pub(super) fn parse_hitl_expr(&mut self, kind: HitlKind) -> Result<SNode, ParserError> {
743 let start = self.current_span();
744 let kw_token = match kind {
745 HitlKind::RequestApproval => TokenKind::RequestApproval,
746 HitlKind::DualControl => TokenKind::DualControl,
747 HitlKind::AskUser => TokenKind::AskUser,
748 HitlKind::EscalateTo => TokenKind::EscalateTo,
749 };
750 self.consume(&kw_token, kind.as_keyword())?;
751 self.consume(&TokenKind::LParen, "(")?;
752 self.skip_newlines();
753
754 let mut args: Vec<HitlArg> = Vec::new();
755 while !self.is_at_end() && !self.check(&TokenKind::RParen) {
756 let arg_start = self.current_span();
757 let is_named = matches!(
764 (self.peek_kind_at(0), self.peek_kind_at(1)),
765 (Some(TokenKind::Identifier(_)), Some(TokenKind::Colon))
766 );
767 let (name, value) = if is_named {
768 let Some(TokenKind::Identifier(raw)) = self.peek_kind_at(0).cloned() else {
769 unreachable!("named arg dispatch already matched Identifier token")
770 };
771 self.advance();
772 self.consume(&TokenKind::Colon, ":")?;
773 self.skip_newlines();
774 let value = self.parse_expression()?;
775 (Some(raw), value)
776 } else {
777 (None, self.parse_expression()?)
778 };
779 let arg_span = Span::merge(arg_start, self.prev_span());
780 args.push(HitlArg {
781 name,
782 value,
783 span: arg_span,
784 });
785 self.skip_newlines();
786 if self.check(&TokenKind::Comma) {
787 self.advance();
788 self.skip_newlines();
789 } else {
790 break;
791 }
792 }
793
794 self.skip_newlines();
795 self.consume(&TokenKind::RParen, ")")?;
796 Ok(spanned(
797 Node::HitlExpr { kind, args },
798 Span::merge(start, self.prev_span()),
799 ))
800 }
801
802 pub(super) fn parse_list_literal(&mut self) -> Result<SNode, ParserError> {
803 let start = self.current_span();
804 self.consume(&TokenKind::LBracket, "[")?;
805 let mut elements = Vec::new();
806 self.skip_newlines();
807
808 while !self.is_at_end() && !self.check(&TokenKind::RBracket) {
809 if self.check(&TokenKind::Dot) {
810 let saved_pos = self.pos;
811 self.advance();
812 if self.check(&TokenKind::Dot) {
813 self.advance();
814 self.consume(&TokenKind::Dot, ".")?;
815 let spread_start = self.tokens[saved_pos].span;
816 let expr = self.parse_expression()?;
817 elements.push(spanned(
818 Node::Spread(Box::new(expr)),
819 Span::merge(spread_start, self.prev_span()),
820 ));
821 } else {
822 self.pos = saved_pos;
823 elements.push(self.parse_expression()?);
824 }
825 } else {
826 elements.push(self.parse_expression()?);
827 }
828 self.skip_newlines();
829 if self.check(&TokenKind::Comma) {
830 self.advance();
831 self.skip_newlines();
832 }
833 }
834
835 self.consume(&TokenKind::RBracket, "]")?;
836 Ok(spanned(
837 Node::ListLiteral(elements),
838 Span::merge(start, self.prev_span()),
839 ))
840 }
841
842 pub(super) fn parse_dict_or_closure(&mut self) -> Result<SNode, ParserError> {
843 let start = self.current_span();
844 self.consume(&TokenKind::LBrace, "{")?;
845 self.skip_newlines();
846
847 if self.check(&TokenKind::RBrace) {
848 self.advance();
849 return Ok(spanned(
850 Node::DictLiteral(Vec::new()),
851 Span::merge(start, self.prev_span()),
852 ));
853 }
854
855 let saved = self.pos;
857 if self.is_closure_lookahead() {
858 self.pos = saved;
859 return self.parse_closure_body(start);
860 }
861 self.pos = saved;
862 self.parse_dict_literal(start)
863 }
864
865 pub(super) fn is_struct_construct_lookahead(&self, struct_name: &str) -> bool {
869 if !struct_name
870 .chars()
871 .next()
872 .is_some_and(|ch| ch.is_uppercase())
873 {
874 return false;
875 }
876
877 let mut offset = 1;
878 while matches!(self.peek_kind_at(offset), Some(TokenKind::Newline)) {
879 offset += 1;
880 }
881
882 match self.peek_kind_at(offset) {
883 Some(TokenKind::RBrace) => true,
884 Some(TokenKind::Identifier(_)) | Some(TokenKind::StringLiteral(_)) => {
885 offset += 1;
886 while matches!(self.peek_kind_at(offset), Some(TokenKind::Newline)) {
887 offset += 1;
888 }
889 matches!(self.peek_kind_at(offset), Some(TokenKind::Colon))
890 }
891 _ => false,
892 }
893 }
894
895 pub(super) fn is_closure_lookahead(&mut self) -> bool {
897 let mut depth = 0;
898 while !self.is_at_end() {
899 if let Some(tok) = self.current() {
900 match &tok.kind {
901 TokenKind::Arrow if depth == 0 => return true,
902 TokenKind::LBrace | TokenKind::LParen | TokenKind::LBracket => depth += 1,
903 TokenKind::RBrace if depth == 0 => return false,
904 TokenKind::RBrace => depth -= 1,
905 TokenKind::RParen | TokenKind::RBracket if depth > 0 => depth -= 1,
906 _ => {}
907 }
908 self.advance();
909 } else {
910 return false;
911 }
912 }
913 false
914 }
915
916 pub(super) fn parse_closure_body(&mut self, start: Span) -> Result<SNode, ParserError> {
918 let params = self.parse_typed_param_list_until_arrow()?;
919 self.consume(&TokenKind::Arrow, "->")?;
920 let body = self.parse_block()?;
921 self.consume(&TokenKind::RBrace, "}")?;
922 Ok(spanned(
923 Node::Closure {
924 params,
925 body,
926 fn_syntax: false,
927 },
928 Span::merge(start, self.prev_span()),
929 ))
930 }
931
932 pub(super) fn parse_typed_param_list_until_arrow(
934 &mut self,
935 ) -> Result<Vec<TypedParam>, ParserError> {
936 self.parse_typed_params_until(|tok| tok == &TokenKind::Arrow)
937 }
938
939 pub(super) fn parse_dict_literal(&mut self, start: Span) -> Result<SNode, ParserError> {
940 let entries = self.parse_dict_entries()?;
941 Ok(spanned(
942 Node::DictLiteral(entries),
943 Span::merge(start, self.prev_span()),
944 ))
945 }
946
947 pub(super) fn parse_dict_entries(&mut self) -> Result<Vec<DictEntry>, ParserError> {
948 let mut entries = Vec::new();
949 self.skip_newlines();
950
951 while !self.is_at_end() && !self.check(&TokenKind::RBrace) {
952 if self.check(&TokenKind::Dot) {
953 let saved_pos = self.pos;
954 self.advance();
955 if self.check(&TokenKind::Dot) {
956 self.advance();
957 if self.check(&TokenKind::Dot) {
958 self.advance();
959 let spread_start = self.tokens[saved_pos].span;
960 let expr = self.parse_expression()?;
961 entries.push(DictEntry {
962 key: spanned(Node::NilLiteral, spread_start),
963 value: spanned(
964 Node::Spread(Box::new(expr)),
965 Span::merge(spread_start, self.prev_span()),
966 ),
967 });
968 self.skip_newlines();
969 if self.check(&TokenKind::Comma) {
970 self.advance();
971 self.skip_newlines();
972 }
973 continue;
974 }
975 self.pos = saved_pos;
976 } else {
977 self.pos = saved_pos;
978 }
979 }
980 let key = if self.check(&TokenKind::LBracket) {
981 self.advance();
982 let k = self.parse_expression()?;
983 self.consume(&TokenKind::RBracket, "]")?;
984 k
985 } else if matches!(
986 self.current().map(|t| &t.kind),
987 Some(TokenKind::StringLiteral(_))
988 ) {
989 let key_span = self.current_span();
990 let name =
991 if let Some(TokenKind::StringLiteral(s)) = self.current().map(|t| &t.kind) {
992 s.clone()
993 } else {
994 unreachable!()
995 };
996 self.advance();
997 spanned(Node::StringLiteral(name), key_span)
998 } else {
999 let key_span = self.current_span();
1000 let name = self.consume_identifier_or_keyword("dict key")?;
1001 spanned(Node::StringLiteral(name), key_span)
1002 };
1003 self.consume(&TokenKind::Colon, ":")?;
1004 let value = self.parse_expression()?;
1005 entries.push(DictEntry { key, value });
1006 self.skip_newlines();
1007 if self.check(&TokenKind::Comma) {
1008 self.advance();
1009 self.skip_newlines();
1010 }
1011 }
1012
1013 self.consume(&TokenKind::RBrace, "}")?;
1014 Ok(entries)
1015 }
1016
1017 pub(super) fn parse_param_list(&mut self) -> Result<Vec<String>, ParserError> {
1019 let mut params = Vec::new();
1020 self.skip_newlines();
1021
1022 while !self.is_at_end() && !self.check(&TokenKind::RParen) {
1023 params.push(self.consume_identifier("parameter name")?);
1024 if self.check(&TokenKind::Comma) {
1025 self.advance();
1026 self.skip_newlines();
1027 }
1028 }
1029 Ok(params)
1030 }
1031
1032 pub(super) fn parse_typed_param_list(&mut self) -> Result<Vec<TypedParam>, ParserError> {
1034 self.parse_typed_params_until(|tok| tok == &TokenKind::RParen)
1035 }
1036
1037 pub(super) fn parse_typed_params_until(
1040 &mut self,
1041 is_terminator: impl Fn(&TokenKind) -> bool,
1042 ) -> Result<Vec<TypedParam>, ParserError> {
1043 let mut params = Vec::new();
1044 let mut seen_default = false;
1045 self.skip_newlines();
1046
1047 while !self.is_at_end() {
1048 if let Some(tok) = self.current() {
1049 if is_terminator(&tok.kind) {
1050 break;
1051 }
1052 } else {
1053 break;
1054 }
1055 let is_rest = if self.check(&TokenKind::Dot) {
1056 let p1 = self.pos + 1;
1057 let p2 = self.pos + 2;
1058 let is_ellipsis = p1 < self.tokens.len()
1059 && p2 < self.tokens.len()
1060 && self.tokens[p1].kind == TokenKind::Dot
1061 && self.tokens[p2].kind == TokenKind::Dot;
1062 if is_ellipsis {
1063 self.advance();
1064 self.advance();
1065 self.advance();
1066 true
1067 } else {
1068 false
1069 }
1070 } else {
1071 false
1072 };
1073 let name = self.consume_identifier("parameter name")?;
1074 let type_expr = self.try_parse_type_annotation()?;
1075 let default_value = if self.check(&TokenKind::Assign) {
1076 self.advance();
1077 seen_default = true;
1078 Some(Box::new(self.parse_expression()?))
1079 } else {
1080 if seen_default && !is_rest {
1081 return Err(self.error(
1082 "Required parameter cannot follow a parameter with a default value",
1083 ));
1084 }
1085 None
1086 };
1087 if is_rest
1088 && !is_terminator(
1089 &self
1090 .current()
1091 .map(|t| t.kind.clone())
1092 .unwrap_or(TokenKind::Eof),
1093 )
1094 {
1095 return Err(self.error("Rest parameter must be the last parameter"));
1096 }
1097 params.push(TypedParam {
1098 name,
1099 type_expr,
1100 default_value,
1101 rest: is_rest,
1102 });
1103 if self.check(&TokenKind::Comma) {
1104 self.advance();
1105 self.skip_newlines();
1106 }
1107 }
1108 Ok(params)
1109 }
1110
1111 pub(super) fn parse_arg_list(&mut self) -> Result<Vec<SNode>, ParserError> {
1112 let mut args = Vec::new();
1113 self.skip_newlines();
1114
1115 while !self.is_at_end() && !self.check(&TokenKind::RParen) {
1116 if self.check(&TokenKind::Dot) {
1117 let saved_pos = self.pos;
1118 self.advance();
1119 if self.check(&TokenKind::Dot) {
1120 self.advance();
1121 self.consume(&TokenKind::Dot, ".")?;
1122 let spread_start = self.tokens[saved_pos].span;
1123 let expr = self.parse_expression()?;
1124 args.push(spanned(
1125 Node::Spread(Box::new(expr)),
1126 Span::merge(spread_start, self.prev_span()),
1127 ));
1128 } else {
1129 self.pos = saved_pos;
1130 args.push(self.parse_expression()?);
1131 }
1132 } else {
1133 args.push(self.parse_expression()?);
1134 }
1135 self.skip_newlines();
1136 if self.check(&TokenKind::Comma) {
1137 self.advance();
1138 self.skip_newlines();
1139 }
1140 }
1141 Ok(args)
1142 }
1143}