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> {
17 self.check_token_nesting_limit()?;
18 self.skip_newlines();
19 let expr = self.parse_expression()?;
20 self.skip_newlines();
21 if !self.is_at_end() {
22 return Err(self.error("end of interpolated expression"));
23 }
24 Ok(expr)
25 }
26
27 pub(super) fn parse_nested_expression(
28 &mut self,
29 context: &'static str,
30 ) -> Result<SNode, ParserError> {
31 self.with_nesting(context, |parser| parser.parse_expression())
32 }
33
34 pub(super) fn parse_expression(&mut self) -> Result<SNode, ParserError> {
35 self.skip_newlines();
36 self.parse_pipe()
37 }
38
39 pub(super) fn parse_pipe(&mut self) -> Result<SNode, ParserError> {
40 let mut left = self.parse_range()?;
41 while self.check_skip_newlines(&TokenKind::Pipe) {
42 let start = left.span;
43 self.advance();
44 self.skip_newlines();
45 let right = self.parse_range()?;
46 left = spanned(
47 Node::BinaryOp {
48 op: "|>".into(),
49 left: Box::new(left),
50 right: Box::new(right),
51 },
52 Span::merge(start, self.prev_span()),
53 );
54 }
55 Ok(left)
56 }
57
58 pub(super) fn parse_range(&mut self) -> Result<SNode, ParserError> {
59 let left = self.parse_ternary()?;
60 if self.check(&TokenKind::To) {
61 let start = left.span;
62 self.advance();
63 let right = self.parse_ternary()?;
64 let inclusive = if self.check(&TokenKind::Exclusive) {
65 self.advance();
66 false
67 } else {
68 true
69 };
70 return Ok(spanned(
71 Node::RangeExpr {
72 start: Box::new(left),
73 end: Box::new(right),
74 inclusive,
75 },
76 Span::merge(start, self.prev_span()),
77 ));
78 }
79 Ok(left)
80 }
81
82 pub(super) fn parse_ternary(&mut self) -> Result<SNode, ParserError> {
83 let condition = self.parse_logical_or()?;
84 if !self.check_skip_newlines(&TokenKind::Question) {
89 return Ok(condition);
90 }
91 let start = condition.span;
92 self.advance(); self.skip_newlines();
94 let true_val = self.with_nesting("ternary expression", |parser| parser.parse_ternary())?;
95 self.consume(&TokenKind::Colon, ":")?;
97 self.skip_newlines();
98 let false_val = self.with_nesting("ternary expression", |parser| parser.parse_ternary())?;
99 Ok(spanned(
100 Node::Ternary {
101 condition: Box::new(condition),
102 true_expr: Box::new(true_val),
103 false_expr: Box::new(false_val),
104 },
105 Span::merge(start, self.prev_span()),
106 ))
107 }
108
109 pub(super) fn parse_nil_coalescing(&mut self) -> Result<SNode, ParserError> {
112 let mut left = self.parse_multiplicative()?;
113 while self.check_skip_newlines(&TokenKind::NilCoal) {
114 let start = left.span;
115 self.advance();
116 self.skip_newlines();
117 let right = self.parse_multiplicative()?;
118 left = spanned(
119 Node::BinaryOp {
120 op: "??".into(),
121 left: Box::new(left),
122 right: Box::new(right),
123 },
124 Span::merge(start, self.prev_span()),
125 );
126 }
127 Ok(left)
128 }
129
130 pub(super) fn parse_logical_or(&mut self) -> Result<SNode, ParserError> {
131 let mut left = self.parse_logical_and()?;
132 while self.check_skip_newlines(&TokenKind::Or) {
133 let start = left.span;
134 self.advance();
135 self.skip_newlines();
136 let right = self.parse_logical_and()?;
137 left = spanned(
138 Node::BinaryOp {
139 op: "||".into(),
140 left: Box::new(left),
141 right: Box::new(right),
142 },
143 Span::merge(start, self.prev_span()),
144 );
145 }
146 Ok(left)
147 }
148
149 pub(super) fn parse_logical_and(&mut self) -> Result<SNode, ParserError> {
150 let mut left = self.parse_equality()?;
151 while self.check_skip_newlines(&TokenKind::And) {
152 let start = left.span;
153 self.advance();
154 self.skip_newlines();
155 let right = self.parse_equality()?;
156 left = spanned(
157 Node::BinaryOp {
158 op: "&&".into(),
159 left: Box::new(left),
160 right: Box::new(right),
161 },
162 Span::merge(start, self.prev_span()),
163 );
164 }
165 Ok(left)
166 }
167
168 pub(super) fn parse_equality(&mut self) -> Result<SNode, ParserError> {
169 let mut left = self.parse_comparison()?;
170 while self.check_skip_newlines(&TokenKind::Eq) || self.check_skip_newlines(&TokenKind::Neq)
171 {
172 let start = left.span;
173 let op = if self.check(&TokenKind::Eq) {
174 "=="
175 } else {
176 "!="
177 };
178 self.advance();
179 self.skip_newlines();
180 let right = self.parse_comparison()?;
181 left = spanned(
182 Node::BinaryOp {
183 op: op.into(),
184 left: Box::new(left),
185 right: Box::new(right),
186 },
187 Span::merge(start, self.prev_span()),
188 );
189 }
190 Ok(left)
191 }
192
193 pub(super) fn parse_comparison(&mut self) -> Result<SNode, ParserError> {
194 let mut left = self.parse_additive()?;
195 loop {
196 if self.check_skip_newlines(&TokenKind::Lt)
197 || self.check_skip_newlines(&TokenKind::Gt)
198 || self.check_skip_newlines(&TokenKind::Lte)
199 || self.check_skip_newlines(&TokenKind::Gte)
200 {
201 let start = left.span;
202 let op = match self.current().map(|t| &t.kind) {
203 Some(TokenKind::Lt) => "<",
204 Some(TokenKind::Gt) => ">",
205 Some(TokenKind::Lte) => "<=",
206 Some(TokenKind::Gte) => ">=",
207 _ => "<",
208 };
209 self.advance();
210 self.skip_newlines();
211 let right = self.parse_additive()?;
212 left = spanned(
213 Node::BinaryOp {
214 op: op.into(),
215 left: Box::new(left),
216 right: Box::new(right),
217 },
218 Span::merge(start, self.prev_span()),
219 );
220 } else if self.check(&TokenKind::In) {
221 let start = left.span;
222 self.advance();
223 self.skip_newlines();
224 let right = self.parse_additive()?;
225 left = spanned(
226 Node::BinaryOp {
227 op: "in".into(),
228 left: Box::new(left),
229 right: Box::new(right),
230 },
231 Span::merge(start, self.prev_span()),
232 );
233 } else if self.check_identifier("not") {
234 let saved = self.pos;
235 self.advance();
236 if self.check(&TokenKind::In) {
237 let start = left.span;
238 self.advance();
239 self.skip_newlines();
240 let right = self.parse_additive()?;
241 left = spanned(
242 Node::BinaryOp {
243 op: "not_in".into(),
244 left: Box::new(left),
245 right: Box::new(right),
246 },
247 Span::merge(start, self.prev_span()),
248 );
249 } else {
250 self.pos = saved;
251 break;
252 }
253 } else {
254 break;
255 }
256 }
257 Ok(left)
258 }
259
260 pub(super) fn parse_additive(&mut self) -> Result<SNode, ParserError> {
261 let mut left = self.parse_nil_coalescing()?;
262 while self.check_skip_newlines(&TokenKind::Plus) || self.check(&TokenKind::Minus) {
263 let start = left.span;
264 let op = if self.check(&TokenKind::Plus) {
265 "+"
266 } else {
267 "-"
268 };
269 self.advance();
270 self.skip_newlines();
271 let right = self.parse_nil_coalescing()?;
272 left = spanned(
273 Node::BinaryOp {
274 op: op.into(),
275 left: Box::new(left),
276 right: Box::new(right),
277 },
278 Span::merge(start, self.prev_span()),
279 );
280 }
281 Ok(left)
282 }
283
284 pub(super) fn parse_multiplicative(&mut self) -> Result<SNode, ParserError> {
285 let mut left = self.parse_unary()?;
286 while self.check_skip_newlines(&TokenKind::Star)
287 || self.check_skip_newlines(&TokenKind::Slash)
288 || self.check_skip_newlines(&TokenKind::Percent)
289 {
290 let start = left.span;
291 let op = if self.check(&TokenKind::Star) {
292 "*"
293 } else if self.check(&TokenKind::Slash) {
294 "/"
295 } else {
296 "%"
297 };
298 self.advance();
299 self.skip_newlines();
300 let right = self.parse_unary()?;
301 left = spanned(
302 Node::BinaryOp {
303 op: op.into(),
304 left: Box::new(left),
305 right: Box::new(right),
306 },
307 Span::merge(start, self.prev_span()),
308 );
309 }
310 Ok(left)
311 }
312
313 pub(super) fn parse_exponent(&mut self) -> Result<SNode, ParserError> {
320 let left = self.parse_postfix()?;
321 if !self.check_skip_newlines(&TokenKind::Pow) {
322 return Ok(left);
323 }
324
325 let start = left.span;
326 self.advance();
327 self.skip_newlines();
328 let right = self.with_nesting("exponent expression", |parser| parser.parse_unary())?;
329 Ok(spanned(
330 Node::BinaryOp {
331 op: "**".into(),
332 left: Box::new(left),
333 right: Box::new(right),
334 },
335 Span::merge(start, self.prev_span()),
336 ))
337 }
338
339 pub(super) fn parse_unary(&mut self) -> Result<SNode, ParserError> {
340 if self.check(&TokenKind::Not) {
341 let start = self.current_span();
342 self.advance();
343 let operand = self.with_nesting("unary expression", |parser| parser.parse_unary())?;
344 return Ok(spanned(
345 Node::UnaryOp {
346 op: "!".into(),
347 operand: Box::new(operand),
348 },
349 Span::merge(start, self.prev_span()),
350 ));
351 }
352 if self.check(&TokenKind::Minus) {
353 let start = self.current_span();
354 self.advance();
355 let operand = self.with_nesting("unary expression", |parser| parser.parse_unary())?;
356 return Ok(spanned(
357 Node::UnaryOp {
358 op: "-".into(),
359 operand: Box::new(operand),
360 },
361 Span::merge(start, self.prev_span()),
362 ));
363 }
364 self.parse_exponent()
365 }
366
367 pub(super) fn parse_postfix(&mut self) -> Result<SNode, ParserError> {
368 let mut expr = self.parse_primary()?;
369
370 loop {
371 if self.check_skip_newlines(&TokenKind::Dot)
372 || self.check_skip_newlines(&TokenKind::QuestionDot)
373 {
374 let optional = self.check(&TokenKind::QuestionDot);
375 let start = expr.span;
376 self.advance();
377 if optional && self.check(&TokenKind::LBracket) {
378 self.advance();
379 let index = self.parse_nested_expression("optional subscript index")?;
380 self.consume(&TokenKind::RBracket, "]")?;
381 expr = spanned(
382 Node::OptionalSubscriptAccess {
383 object: Box::new(expr),
384 index: Box::new(index),
385 },
386 Span::merge(start, self.prev_span()),
387 );
388 continue;
389 }
390 let member = self.consume_identifier_or_keyword("member name")?;
391 if self.check(&TokenKind::LParen) {
392 self.advance();
393 let args = self.parse_arg_list()?;
394 self.consume(&TokenKind::RParen, ")")?;
395 if optional {
396 expr = spanned(
397 Node::OptionalMethodCall {
398 object: Box::new(expr),
399 method: member,
400 args,
401 },
402 Span::merge(start, self.prev_span()),
403 );
404 } else {
405 expr = spanned(
406 Node::MethodCall {
407 object: Box::new(expr),
408 method: member,
409 args,
410 },
411 Span::merge(start, self.prev_span()),
412 );
413 }
414 } else if optional {
415 expr = spanned(
416 Node::OptionalPropertyAccess {
417 object: Box::new(expr),
418 property: member,
419 },
420 Span::merge(start, self.prev_span()),
421 );
422 } else {
423 expr = spanned(
424 Node::PropertyAccess {
425 object: Box::new(expr),
426 property: member,
427 },
428 Span::merge(start, self.prev_span()),
429 );
430 }
431 } else if self.check(&TokenKind::LBracket) {
432 let start = expr.span;
433 self.advance();
434
435 if self.check(&TokenKind::Colon) {
438 self.advance();
439 let end_expr = if self.check(&TokenKind::RBracket) {
440 None
441 } else {
442 Some(Box::new(self.parse_nested_expression("slice bound")?))
443 };
444 self.consume(&TokenKind::RBracket, "]")?;
445 expr = spanned(
446 Node::SliceAccess {
447 object: Box::new(expr),
448 start: None,
449 end: end_expr,
450 },
451 Span::merge(start, self.prev_span()),
452 );
453 } else {
454 let index = self.parse_nested_expression("subscript index")?;
455 if self.check(&TokenKind::Colon) {
456 self.advance();
457 let end_expr = if self.check(&TokenKind::RBracket) {
458 None
459 } else {
460 Some(Box::new(self.parse_nested_expression("slice bound")?))
461 };
462 self.consume(&TokenKind::RBracket, "]")?;
463 expr = spanned(
464 Node::SliceAccess {
465 object: Box::new(expr),
466 start: Some(Box::new(index)),
467 end: end_expr,
468 },
469 Span::merge(start, self.prev_span()),
470 );
471 } else {
472 self.consume(&TokenKind::RBracket, "]")?;
473 expr = spanned(
474 Node::SubscriptAccess {
475 object: Box::new(expr),
476 index: Box::new(index),
477 },
478 Span::merge(start, self.prev_span()),
479 );
480 }
481 }
482 } else if self.check(&TokenKind::LBrace) {
483 let struct_name = match &expr.node {
484 Node::Identifier(name) if self.is_struct_construct_lookahead(name) => {
485 Some(name.clone())
486 }
487 _ => None,
488 };
489 let Some(struct_name) = struct_name else {
490 break;
491 };
492 let start = expr.span;
493 self.advance();
494 let dict = self.parse_dict_literal(start)?;
495 let fields = match dict.node {
496 Node::DictLiteral(fields) => fields,
497 _ => unreachable!("dict parser must return a dict literal"),
498 };
499 expr = spanned(
500 Node::StructConstruct {
501 struct_name,
502 fields,
503 },
504 dict.span,
505 );
506 } else if self.check(&TokenKind::Lt) && matches!(expr.node, Node::Identifier(_)) {
507 let saved_pos = self.pos;
508 let start = expr.span;
509 self.advance();
510 let parsed_type_args = self.parse_type_arg_list();
511 if let Ok(type_args) = parsed_type_args {
512 if self.check(&TokenKind::LParen) {
513 self.advance();
514 let args = self.parse_arg_list()?;
515 self.consume(&TokenKind::RParen, ")")?;
516 if let Node::Identifier(name) = expr.node {
517 expr = spanned(
518 Node::FunctionCall {
519 name,
520 type_args,
521 args,
522 },
523 Span::merge(start, self.prev_span()),
524 );
525 }
526 } else {
527 self.pos = saved_pos;
528 break;
529 }
530 } else {
531 self.pos = saved_pos;
532 break;
533 }
534 } else if self.check(&TokenKind::LParen) && matches!(expr.node, Node::Identifier(_)) {
535 let start = expr.span;
536 self.advance();
537 let args = self.parse_arg_list()?;
538 self.consume(&TokenKind::RParen, ")")?;
539 if let Node::Identifier(name) = expr.node {
540 expr = spanned(
541 Node::FunctionCall {
542 name,
543 type_args: Vec::new(),
544 args,
545 },
546 Span::merge(start, self.prev_span()),
547 );
548 }
549 } else if self.check(&TokenKind::Question) {
550 if self.question_starts_ternary_branch() {
553 break;
554 }
555 if matches!(self.peek_kind_at(1), Some(TokenKind::LBracket)) {
556 let start = expr.span;
557 self.advance(); self.advance(); let index = self.parse_nested_expression("optional subscript index")?;
560 self.consume(&TokenKind::RBracket, "]")?;
561 expr = spanned(
562 Node::OptionalSubscriptAccess {
563 object: Box::new(expr),
564 index: Box::new(index),
565 },
566 Span::merge(start, self.prev_span()),
567 );
568 continue;
569 }
570 let start = expr.span;
571 self.advance();
572 expr = spanned(
573 Node::TryOperator {
574 operand: Box::new(expr),
575 },
576 Span::merge(start, self.prev_span()),
577 );
578 } else if self.check(&TokenKind::Not) {
579 let start = expr.span;
584 self.advance();
585 expr = spanned(
586 Node::NonNullAssert {
587 operand: Box::new(expr),
588 },
589 Span::merge(start, self.prev_span()),
590 );
591 } else {
592 break;
593 }
594 }
595
596 Ok(expr)
597 }
598
599 fn question_starts_ternary_branch(&self) -> bool {
600 let next = self
605 .tokens
606 .iter()
607 .skip(self.pos + 1)
608 .find(|t| t.kind != TokenKind::Newline)
609 .map(|t| &t.kind);
610 next.is_some_and(Self::token_starts_ternary_branch)
611 && self.question_has_top_level_ternary_colon()
612 }
613
614 fn token_starts_ternary_branch(kind: &TokenKind) -> bool {
615 matches!(
616 kind,
617 TokenKind::Identifier(_)
618 | TokenKind::IntLiteral(_)
619 | TokenKind::FloatLiteral(_)
620 | TokenKind::StringLiteral(_)
621 | TokenKind::RawStringLiteral(_)
622 | TokenKind::InterpolatedString(_)
623 | TokenKind::True
624 | TokenKind::False
625 | TokenKind::Nil
626 | TokenKind::LParen
627 | TokenKind::LBracket
628 | TokenKind::LBrace
629 | TokenKind::Not
630 | TokenKind::Minus
631 | TokenKind::Fn
632 | TokenKind::If
633 | TokenKind::Match
634 | TokenKind::Try
635 | TokenKind::Spawn
636 | TokenKind::Parallel
637 | TokenKind::Retry
638 | TokenKind::Deadline
639 | TokenKind::RequestApproval
640 | TokenKind::DualControl
641 | TokenKind::AskUser
642 | TokenKind::EscalateTo
643 | TokenKind::DurationLiteral(_)
644 )
645 }
646
647 fn question_has_top_level_ternary_colon(&self) -> bool {
648 let mut delimiter_depth = 0usize;
649 let mut at_branch_start = true;
653 for (pos, token) in self.tokens.iter().enumerate().skip(self.pos + 1) {
654 if delimiter_depth == 0 {
655 match token.kind {
656 TokenKind::Colon => return true,
657 TokenKind::Newline => {
658 if at_branch_start {
659 continue;
662 }
663 if self.next_non_newline_continues_ternary_branch(pos + 1) {
664 continue;
665 }
666 return false;
667 }
668 TokenKind::RParen
669 | TokenKind::RBracket
670 | TokenKind::RBrace
671 | TokenKind::Eof => {
672 return false;
673 }
674 _ => {
675 at_branch_start = false;
676 }
677 }
678 }
679
680 match token.kind {
681 TokenKind::LParen | TokenKind::LBracket | TokenKind::LBrace => {
682 delimiter_depth += 1;
683 }
684 TokenKind::RParen | TokenKind::RBracket | TokenKind::RBrace => {
685 delimiter_depth = delimiter_depth.saturating_sub(1);
686 }
687 TokenKind::Eof => return false,
688 _ => {}
689 }
690 }
691 false
692 }
693
694 fn next_non_newline_continues_ternary_branch(&self, start_pos: usize) -> bool {
695 let Some(kind) = self
696 .tokens
697 .iter()
698 .skip(start_pos)
699 .find(|token| token.kind != TokenKind::Newline)
700 .map(|token| &token.kind)
701 else {
702 return false;
703 };
704 matches!(
705 kind,
706 TokenKind::Colon
707 | TokenKind::Plus
708 | TokenKind::Star
709 | TokenKind::Slash
710 | TokenKind::Percent
711 | TokenKind::Pow
712 | TokenKind::And
713 | TokenKind::Or
714 | TokenKind::Eq
715 | TokenKind::Neq
716 | TokenKind::Lt
717 | TokenKind::Gt
718 | TokenKind::Lte
719 | TokenKind::Gte
720 | TokenKind::NilCoal
721 | TokenKind::Pipe
722 | TokenKind::Dot
723 | TokenKind::QuestionDot
724 )
725 }
726
727 pub(super) fn parse_primary(&mut self) -> Result<SNode, ParserError> {
728 let tok = self.current().ok_or_else(|| ParserError::UnexpectedEof {
729 expected: "expression".into(),
730 span: self.prev_span(),
731 })?;
732 let start = self.current_span();
733
734 match &tok.kind {
735 TokenKind::StringLiteral(s) => {
736 let s = s.clone();
737 self.advance();
738 Ok(spanned(
739 Node::StringLiteral(s),
740 Span::merge(start, self.prev_span()),
741 ))
742 }
743 TokenKind::RawStringLiteral(s) => {
744 let s = s.clone();
745 self.advance();
746 Ok(spanned(
747 Node::RawStringLiteral(s),
748 Span::merge(start, self.prev_span()),
749 ))
750 }
751 TokenKind::InterpolatedString(segments) => {
752 let segments = segments.clone();
753 self.advance();
754 Ok(spanned(
755 Node::InterpolatedString(segments),
756 Span::merge(start, self.prev_span()),
757 ))
758 }
759 TokenKind::IntLiteral(n) => {
760 let n = *n;
761 self.advance();
762 Ok(spanned(
763 Node::IntLiteral(n),
764 Span::merge(start, self.prev_span()),
765 ))
766 }
767 TokenKind::FloatLiteral(n) => {
768 let n = *n;
769 self.advance();
770 Ok(spanned(
771 Node::FloatLiteral(n),
772 Span::merge(start, self.prev_span()),
773 ))
774 }
775 TokenKind::True => {
776 self.advance();
777 Ok(spanned(
778 Node::BoolLiteral(true),
779 Span::merge(start, self.prev_span()),
780 ))
781 }
782 TokenKind::False => {
783 self.advance();
784 Ok(spanned(
785 Node::BoolLiteral(false),
786 Span::merge(start, self.prev_span()),
787 ))
788 }
789 TokenKind::Nil => {
790 self.advance();
791 Ok(spanned(
792 Node::NilLiteral,
793 Span::merge(start, self.prev_span()),
794 ))
795 }
796 TokenKind::Identifier(name)
797 if name == "cost_route" && self.peek_kind() == Some(&TokenKind::LBrace) =>
798 {
799 self.parse_cost_route()
800 }
801 TokenKind::Identifier(name) => {
802 let name = name.clone();
803 self.advance();
804 Ok(spanned(
805 Node::Identifier(name),
806 Span::merge(start, self.prev_span()),
807 ))
808 }
809 TokenKind::LParen => {
810 self.advance();
811 let expr = self.with_nesting("parenthesized expression", |parser| {
812 let expr = parser.parse_expression()?;
813 parser.consume(&TokenKind::RParen, ")")?;
814 Ok(expr)
815 })?;
816 Ok(expr)
817 }
818 TokenKind::LBracket => self.parse_list_literal(),
819 TokenKind::LBrace => self.parse_dict_or_closure(),
820 TokenKind::Parallel => self.parse_parallel(),
821 TokenKind::Retry => self.parse_retry(),
822 TokenKind::If => self.parse_if_else(),
823 TokenKind::Spawn => self.parse_spawn_expr(),
824 TokenKind::RequestApproval => self.parse_hitl_expr(HitlKind::RequestApproval),
825 TokenKind::DualControl => self.parse_hitl_expr(HitlKind::DualControl),
826 TokenKind::AskUser => self.parse_hitl_expr(HitlKind::AskUser),
827 TokenKind::EscalateTo => self.parse_hitl_expr(HitlKind::EscalateTo),
828 TokenKind::DurationLiteral(ms) => {
829 let ms = *ms;
830 self.advance();
831 Ok(spanned(
832 Node::DurationLiteral(ms),
833 Span::merge(start, self.prev_span()),
834 ))
835 }
836 TokenKind::Deadline => self.parse_deadline(),
837 TokenKind::Try => self.parse_try_catch(),
838 TokenKind::Match => self.parse_match(),
839 TokenKind::Fn => self.parse_fn_expr(),
840 TokenKind::Lt
843 if matches!(self.peek_kind(), Some(&TokenKind::Lt))
844 && matches!(self.peek_kind_at(2), Some(TokenKind::Identifier(_))) =>
845 {
846 Err(ParserError::Unexpected {
847 got: "`<<` heredoc-like syntax".to_string(),
848 expected: "an expression — heredocs are only valid \
849 inside LLM tool-call argument JSON; \
850 for multiline strings in source code use \
851 triple-quoted `\"\"\"...\"\"\"`"
852 .to_string(),
853 span: start,
854 })
855 }
856 _ => Err(self.error("expression")),
857 }
858 }
859
860 pub(super) fn parse_fn_expr(&mut self) -> Result<SNode, ParserError> {
863 let start = self.current_span();
864 self.consume(&TokenKind::Fn, "fn")?;
865 self.consume(&TokenKind::LParen, "(")?;
866 let params = self.parse_typed_param_list()?;
867 self.consume(&TokenKind::RParen, ")")?;
868 let return_type = if self.check(&TokenKind::Arrow) {
869 self.advance();
870 Some(self.parse_nested_type_expr("closure return type")?)
871 } else {
872 None
873 };
874 let throws = if self.check(&TokenKind::Throws) {
877 self.advance();
878 Some(self.parse_nested_type_expr("closure throws type")?)
879 } else {
880 None
881 };
882 self.consume(&TokenKind::LBrace, "{")?;
883 let body = self.parse_block()?;
884 self.consume(&TokenKind::RBrace, "}")?;
885 Ok(spanned(
886 Node::Closure {
887 params,
888 return_type,
889 throws,
890 body,
891 fn_syntax: true,
892 },
893 Span::merge(start, self.prev_span()),
894 ))
895 }
896
897 pub(super) fn parse_spawn_expr(&mut self) -> Result<SNode, ParserError> {
898 let start = self.current_span();
899 self.consume(&TokenKind::Spawn, "spawn")?;
900 self.consume(&TokenKind::LBrace, "{")?;
901 let body = self.parse_block()?;
902 self.consume(&TokenKind::RBrace, "}")?;
903 Ok(spanned(
904 Node::SpawnExpr { body },
905 Span::merge(start, self.prev_span()),
906 ))
907 }
908
909 pub(super) fn parse_hitl_expr(&mut self, kind: HitlKind) -> Result<SNode, ParserError> {
921 let start = self.current_span();
922 let kw_token = match kind {
923 HitlKind::RequestApproval => TokenKind::RequestApproval,
924 HitlKind::DualControl => TokenKind::DualControl,
925 HitlKind::AskUser => TokenKind::AskUser,
926 HitlKind::EscalateTo => TokenKind::EscalateTo,
927 };
928 self.consume(&kw_token, kind.as_keyword())?;
929 self.consume(&TokenKind::LParen, "(")?;
930 self.skip_newlines();
931
932 let mut args: Vec<HitlArg> = Vec::new();
933 while !self.is_at_end() && !self.check(&TokenKind::RParen) {
934 let arg_start = self.current_span();
935 let is_named = matches!(
942 (self.peek_kind_at(0), self.peek_kind_at(1)),
943 (Some(TokenKind::Identifier(_)), Some(TokenKind::Colon))
944 );
945 let (name, value) = if is_named {
946 let Some(TokenKind::Identifier(raw)) = self.peek_kind_at(0).cloned() else {
947 unreachable!("named arg dispatch already matched Identifier token")
948 };
949 self.advance();
950 self.consume(&TokenKind::Colon, ":")?;
951 self.skip_newlines();
952 let value = self.parse_nested_expression("HITL argument")?;
953 (Some(raw), value)
954 } else {
955 (None, self.parse_nested_expression("HITL argument")?)
956 };
957 let arg_span = Span::merge(arg_start, self.prev_span());
958 args.push(HitlArg {
959 name,
960 value,
961 span: arg_span,
962 });
963 self.skip_newlines();
964 if self.check(&TokenKind::Comma) {
965 self.advance();
966 self.skip_newlines();
967 } else {
968 break;
969 }
970 }
971
972 self.skip_newlines();
973 self.consume(&TokenKind::RParen, ")")?;
974 Ok(spanned(
975 Node::HitlExpr { kind, args },
976 Span::merge(start, self.prev_span()),
977 ))
978 }
979
980 pub(super) fn parse_list_literal(&mut self) -> Result<SNode, ParserError> {
981 let start = self.current_span();
982 self.consume(&TokenKind::LBracket, "[")?;
983 let mut elements = Vec::new();
984 self.skip_newlines();
985
986 while !self.is_at_end() && !self.check(&TokenKind::RBracket) {
987 if self.check(&TokenKind::Dot) {
988 let saved_pos = self.pos;
989 self.advance();
990 if self.check(&TokenKind::Dot) {
991 self.advance();
992 self.consume(&TokenKind::Dot, ".")?;
993 let spread_start = self.tokens[saved_pos].span;
994 let expr = self.parse_nested_expression("list spread")?;
995 elements.push(spanned(
996 Node::Spread(Box::new(expr)),
997 Span::merge(spread_start, self.prev_span()),
998 ));
999 } else {
1000 self.pos = saved_pos;
1001 elements.push(self.parse_nested_expression("list element")?);
1002 }
1003 } else {
1004 elements.push(self.parse_nested_expression("list element")?);
1005 }
1006 self.skip_newlines();
1007 if self.check(&TokenKind::Comma) {
1008 self.advance();
1009 self.skip_newlines();
1010 }
1011 }
1012
1013 self.consume(&TokenKind::RBracket, "]")?;
1014 Ok(spanned(
1015 Node::ListLiteral(elements),
1016 Span::merge(start, self.prev_span()),
1017 ))
1018 }
1019
1020 pub(super) fn parse_dict_or_closure(&mut self) -> Result<SNode, ParserError> {
1021 let start = self.current_span();
1022 self.consume(&TokenKind::LBrace, "{")?;
1023 self.skip_newlines();
1024
1025 if self.check(&TokenKind::RBrace) {
1026 self.advance();
1027 return Ok(spanned(
1028 Node::DictLiteral(Vec::new()),
1029 Span::merge(start, self.prev_span()),
1030 ));
1031 }
1032
1033 let saved = self.pos;
1035 if self.is_closure_lookahead() {
1036 self.pos = saved;
1037 return self.parse_closure_body(start);
1038 }
1039 self.pos = saved;
1040 self.parse_dict_literal(start)
1041 }
1042
1043 pub(super) fn is_struct_construct_lookahead(&self, struct_name: &str) -> bool {
1047 if !struct_name
1048 .chars()
1049 .next()
1050 .is_some_and(|ch| ch.is_uppercase())
1051 {
1052 return false;
1053 }
1054
1055 let mut offset = 1;
1056 while matches!(self.peek_kind_at(offset), Some(TokenKind::Newline)) {
1057 offset += 1;
1058 }
1059
1060 match self.peek_kind_at(offset) {
1061 Some(TokenKind::RBrace) => true,
1062 Some(TokenKind::Identifier(_)) | Some(TokenKind::StringLiteral(_)) => {
1063 offset += 1;
1064 while matches!(self.peek_kind_at(offset), Some(TokenKind::Newline)) {
1065 offset += 1;
1066 }
1067 matches!(self.peek_kind_at(offset), Some(TokenKind::Colon))
1068 }
1069 _ => false,
1070 }
1071 }
1072
1073 pub(super) fn is_closure_lookahead(&mut self) -> bool {
1075 let mut depth = 0;
1076 while !self.is_at_end() {
1077 if let Some(tok) = self.current() {
1078 match &tok.kind {
1079 TokenKind::Arrow if depth == 0 => return true,
1080 TokenKind::LBrace | TokenKind::LParen | TokenKind::LBracket => depth += 1,
1081 TokenKind::RBrace if depth == 0 => return false,
1082 TokenKind::RBrace => depth -= 1,
1083 TokenKind::RParen | TokenKind::RBracket if depth > 0 => depth -= 1,
1084 _ => {}
1085 }
1086 self.advance();
1087 } else {
1088 return false;
1089 }
1090 }
1091 false
1092 }
1093
1094 pub(super) fn parse_closure_body(&mut self, start: Span) -> Result<SNode, ParserError> {
1096 let params = self.parse_typed_param_list_until_arrow()?;
1097 self.consume(&TokenKind::Arrow, "->")?;
1098 let body = self.parse_block()?;
1099 self.consume(&TokenKind::RBrace, "}")?;
1100 Ok(spanned(
1101 Node::Closure {
1102 params,
1103 return_type: None,
1104 throws: None,
1107 body,
1108 fn_syntax: false,
1109 },
1110 Span::merge(start, self.prev_span()),
1111 ))
1112 }
1113
1114 pub(super) fn parse_typed_param_list_until_arrow(
1116 &mut self,
1117 ) -> Result<Vec<TypedParam>, ParserError> {
1118 self.parse_typed_params_until(|tok| tok == &TokenKind::Arrow)
1119 }
1120
1121 pub(super) fn parse_dict_literal(&mut self, start: Span) -> Result<SNode, ParserError> {
1122 let entries = self.parse_dict_entries()?;
1123 Ok(spanned(
1124 Node::DictLiteral(entries),
1125 Span::merge(start, self.prev_span()),
1126 ))
1127 }
1128
1129 pub(super) fn parse_dict_entries(&mut self) -> Result<Vec<DictEntry>, ParserError> {
1130 let mut entries = Vec::new();
1131 self.skip_newlines();
1132
1133 while !self.is_at_end() && !self.check(&TokenKind::RBrace) {
1134 if self.check(&TokenKind::Dot) {
1135 let saved_pos = self.pos;
1136 self.advance();
1137 if self.check(&TokenKind::Dot) {
1138 self.advance();
1139 if self.check(&TokenKind::Dot) {
1140 self.advance();
1141 let spread_start = self.tokens[saved_pos].span;
1142 let expr = self.parse_nested_expression("dict spread")?;
1143 entries.push(DictEntry {
1144 key: spanned(Node::NilLiteral, spread_start),
1145 value: spanned(
1146 Node::Spread(Box::new(expr)),
1147 Span::merge(spread_start, self.prev_span()),
1148 ),
1149 });
1150 self.skip_newlines();
1151 if self.check(&TokenKind::Comma) {
1152 self.advance();
1153 self.skip_newlines();
1154 }
1155 continue;
1156 }
1157 self.pos = saved_pos;
1158 } else {
1159 self.pos = saved_pos;
1160 }
1161 }
1162 let key = if self.check(&TokenKind::LBracket) {
1163 self.advance();
1164 let k = self.parse_nested_expression("computed dict key")?;
1165 self.consume(&TokenKind::RBracket, "]")?;
1166 k
1167 } else if matches!(
1168 self.current().map(|t| &t.kind),
1169 Some(TokenKind::StringLiteral(_))
1170 ) {
1171 let key_span = self.current_span();
1172 let name =
1173 if let Some(TokenKind::StringLiteral(s)) = self.current().map(|t| &t.kind) {
1174 s.clone()
1175 } else {
1176 unreachable!()
1177 };
1178 self.advance();
1179 spanned(Node::StringLiteral(name), key_span)
1180 } else {
1181 let key_span = self.current_span();
1182 let name = self.consume_identifier_or_keyword("dict key")?;
1183 spanned(Node::StringLiteral(name), key_span)
1184 };
1185 self.consume(&TokenKind::Colon, ":")?;
1186 let value = self.parse_nested_expression("dict value")?;
1187 entries.push(DictEntry { key, value });
1188 self.skip_newlines();
1189 if self.check(&TokenKind::Comma) {
1190 self.advance();
1191 self.skip_newlines();
1192 }
1193 }
1194
1195 self.consume(&TokenKind::RBrace, "}")?;
1196 Ok(entries)
1197 }
1198
1199 pub(super) fn parse_param_list(&mut self) -> Result<Vec<String>, ParserError> {
1201 let mut params = Vec::new();
1202 self.skip_newlines();
1203
1204 while !self.is_at_end() && !self.check(&TokenKind::RParen) {
1205 params.push(self.consume_identifier("parameter name")?);
1206 if self.check(&TokenKind::Comma) {
1207 self.advance();
1208 self.skip_newlines();
1209 }
1210 }
1211 Ok(params)
1212 }
1213
1214 pub(super) fn parse_typed_param_list(&mut self) -> Result<Vec<TypedParam>, ParserError> {
1216 self.parse_typed_params_until(|tok| tok == &TokenKind::RParen)
1217 }
1218
1219 pub(super) fn parse_typed_params_until(
1222 &mut self,
1223 is_terminator: impl Fn(&TokenKind) -> bool,
1224 ) -> Result<Vec<TypedParam>, ParserError> {
1225 let mut params = Vec::new();
1226 let mut seen_default = false;
1227 self.skip_newlines();
1228
1229 while !self.is_at_end() {
1230 if let Some(tok) = self.current() {
1231 if is_terminator(&tok.kind) {
1232 break;
1233 }
1234 } else {
1235 break;
1236 }
1237 let is_rest = if self.check(&TokenKind::Dot) {
1238 let p1 = self.pos + 1;
1239 let p2 = self.pos + 2;
1240 let is_ellipsis = p1 < self.tokens.len()
1241 && p2 < self.tokens.len()
1242 && self.tokens[p1].kind == TokenKind::Dot
1243 && self.tokens[p2].kind == TokenKind::Dot;
1244 if is_ellipsis {
1245 self.advance();
1246 self.advance();
1247 self.advance();
1248 true
1249 } else {
1250 false
1251 }
1252 } else {
1253 false
1254 };
1255 let name = self.consume_identifier("parameter name")?;
1256 let type_expr = self.try_parse_type_annotation()?;
1257 let default_value = if self.check(&TokenKind::Assign) {
1258 self.advance();
1259 seen_default = true;
1260 Some(Box::new(self.parse_nested_expression("parameter default")?))
1261 } else {
1262 if seen_default && !is_rest {
1263 return Err(self.error(
1264 "Required parameter cannot follow a parameter with a default value",
1265 ));
1266 }
1267 None
1268 };
1269 if is_rest
1270 && !is_terminator(
1271 &self
1272 .current()
1273 .map(|t| t.kind.clone())
1274 .unwrap_or(TokenKind::Eof),
1275 )
1276 {
1277 return Err(self.error("Rest parameter must be the last parameter"));
1278 }
1279 params.push(TypedParam {
1280 name,
1281 type_expr,
1282 default_value,
1283 rest: is_rest,
1284 });
1285 if self.check(&TokenKind::Comma) {
1286 self.advance();
1287 self.skip_newlines();
1288 }
1289 }
1290 Ok(params)
1291 }
1292
1293 pub(super) fn parse_arg_list(&mut self) -> Result<Vec<SNode>, ParserError> {
1294 let mut args = Vec::new();
1295 self.skip_newlines();
1296
1297 while !self.is_at_end() && !self.check(&TokenKind::RParen) {
1298 if self.check(&TokenKind::Dot) {
1299 let saved_pos = self.pos;
1300 self.advance();
1301 if self.check(&TokenKind::Dot) {
1302 self.advance();
1303 self.consume(&TokenKind::Dot, ".")?;
1304 let spread_start = self.tokens[saved_pos].span;
1305 let expr = self.parse_nested_expression("spread argument")?;
1306 args.push(spanned(
1307 Node::Spread(Box::new(expr)),
1308 Span::merge(spread_start, self.prev_span()),
1309 ));
1310 } else {
1311 self.pos = saved_pos;
1312 args.push(self.parse_nested_expression("argument")?);
1313 }
1314 } else {
1315 args.push(self.parse_nested_expression("argument")?);
1316 }
1317 self.skip_newlines();
1318 if self.check(&TokenKind::Comma) {
1319 self.advance();
1320 self.skip_newlines();
1321 }
1322 }
1323 Ok(args)
1324 }
1325}