1use crate::ast::{
2 AssignPathStep, AssignTarget, AstString, BinaryOp, Declaration, Expr, ExpressionSourceSpan,
3 LabelMetadata, ListComprehensionClause, ProcessDecl, ProcessParam, ProcessSignalDecl,
4 ProcessStartExpr, Program, TypeDecl, TypeExpr, TypeField, UnaryOp,
5};
6use crate::lexer::{LexError, Span, Token, TokenKind, lex};
7use thiserror::Error;
8
9#[derive(Debug, Error, PartialEq)]
10pub enum ParseError {
11 #[error(transparent)]
12 Lex(#[from] LexError),
13 #[error("expected {expected}, found {found}")]
14 Expected {
15 expected: &'static str,
16 found: String,
17 span: Span,
18 },
19 #[error("unexpected {found}")]
20 Unexpected { found: String, span: Span },
21 #[error("`{keyword}` can only be used inside a loop")]
22 LoopControlOutsideLoop { keyword: &'static str, span: Span },
23 #[error("`{keyword}` can only be used inside a `process` body")]
24 SessionProcessAdminOutsideBlock { keyword: &'static str, span: Span },
25 #[error("`{keyword}` can't be used inside a `process` body")]
26 ForegroundControlInsideProcess { keyword: &'static str, span: Span },
27 #[error(
28 "declarative trigger syntax has been removed; construct a source value and call the trigger registry register operation"
29 )]
30 DeclarativeTriggerRemoved { span: Span },
31 #[error("invalid @label annotation: {message}")]
32 InvalidLabelAnnotation { message: String, span: Span },
33 #[error(
34 "@label can annotate statements or process declarations, but not other declarations or another @label"
35 )]
36 InvalidLabelTarget { span: Span },
37 #[error("expression nesting too deep (limit {limit}); flatten the program")]
38 NestingTooDeep { limit: usize, span: Span },
39}
40
41impl ParseError {
42 pub fn span(&self) -> Option<Span> {
43 match self {
44 Self::Lex(_) => None,
45 Self::Expected { span, .. }
46 | Self::Unexpected { span, .. }
47 | Self::LoopControlOutsideLoop { span, .. }
48 | Self::SessionProcessAdminOutsideBlock { span, .. }
49 | Self::ForegroundControlInsideProcess { span, .. }
50 | Self::DeclarativeTriggerRemoved { span }
51 | Self::InvalidLabelAnnotation { span, .. }
52 | Self::InvalidLabelTarget { span }
53 | Self::NestingTooDeep { span, .. } => Some(*span),
54 }
55 }
56
57 pub fn offset(&self) -> usize {
58 match self {
59 Self::Lex(err) => err.offset(),
60 Self::Expected { span, .. }
61 | Self::Unexpected { span, .. }
62 | Self::LoopControlOutsideLoop { span, .. }
63 | Self::SessionProcessAdminOutsideBlock { span, .. }
64 | Self::ForegroundControlInsideProcess { span, .. }
65 | Self::DeclarativeTriggerRemoved { span }
66 | Self::InvalidLabelAnnotation { span, .. }
67 | Self::InvalidLabelTarget { span }
68 | Self::NestingTooDeep { span, .. } => span.start,
69 }
70 }
71}
72
73pub fn parse(source: &str) -> Result<Program, ParseError> {
74 let tokens = lex(source)?;
75 Parser {
76 tokens,
77 index: 0,
78 loop_depth: 0,
79 process_depth: 0,
80 nesting_depth: 0,
81 }
82 .parse_program()
83}
84
85const MAX_NESTING_DEPTH: usize = 40;
104
105struct Parser {
106 tokens: Vec<Token>,
107 index: usize,
108 loop_depth: usize,
109 process_depth: usize,
110 nesting_depth: usize,
111}
112
113#[derive(Clone)]
114struct ParsedExpr {
115 expr: Expr,
116 span: Span,
117 source_spans: Vec<ExpressionSourceSpan>,
118}
119
120impl ParsedExpr {
121 fn leaf(expr: Expr, span: Span) -> Self {
122 Self {
123 expr,
124 span,
125 source_spans: vec![ExpressionSourceSpan {
126 path: Vec::new(),
127 span,
128 }],
129 }
130 }
131
132 fn node(expr: Expr, span: Span, children: impl IntoIterator<Item = (u32, ParsedExpr)>) -> Self {
133 let mut source_spans = vec![ExpressionSourceSpan {
134 path: Vec::new(),
135 span,
136 }];
137 for (child_index, child) in children {
138 source_spans.extend(child.source_spans.into_iter().map(|mut source_span| {
139 source_span.path.insert(0, child_index);
140 source_span
141 }));
142 }
143 Self {
144 expr,
145 span,
146 source_spans,
147 }
148 }
149
150 fn into_expr(self) -> Expr {
151 self.expr
152 }
153}
154
155struct ParsedAssignTarget {
156 target: AssignTarget,
157 index_spans: Vec<ParsedExpr>,
158}
159
160struct ParsedListComprehensionClause {
161 clause: ListComprehensionClause,
162 expr_span: ParsedExpr,
163}
164
165fn push_root_expression(
166 expressions: &mut Vec<Expr>,
167 source_spans: &mut Vec<ExpressionSourceSpan>,
168 parsed: ParsedExpr,
169) {
170 let root = expressions.len() as u32;
171 let ParsedExpr {
172 expr,
173 source_spans: parsed_source_spans,
174 ..
175 } = parsed;
176 source_spans.extend(parsed_source_spans.into_iter().map(|mut source_span| {
177 source_span.path.insert(0, root);
178 source_span
179 }));
180 expressions.push(expr);
181}
182
183impl Parser {
184 fn parse_program(&mut self) -> Result<Program, ParseError> {
185 let capacity = (self.tokens.len() / 20).max(1);
186 let mut declarations = Vec::new();
187 let mut declaration_spans = Vec::new();
188 let mut expressions = Vec::with_capacity(capacity);
189 let mut expression_spans = Vec::with_capacity(capacity);
190 let mut expression_source_spans = Vec::new();
191 while !self.at_eof() {
192 if matches!(self.peek_kind(), TokenKind::At) {
193 let start = self.peek().span.start;
194 let label = self.parse_label_annotation()?;
195 if self.peek_contextual("process") && !self.peek_assignment_target() {
196 declarations.push(Declaration::Process(self.parse_process_decl(Some(label))?));
197 declaration_spans.push(self.span_from(start));
198 continue;
199 }
200 if self.peek_contextual("type")
201 || self.peek_contextual("trigger")
202 || matches!(self.peek_kind(), TokenKind::At)
203 {
204 return Err(ParseError::InvalidLabelTarget {
205 span: self.peek().span,
206 });
207 }
208 let inner = self.parse_statement_expr()?;
209 let end = self
210 .tokens
211 .get(self.index.saturating_sub(1))
212 .map(|token| token.span.end)
213 .unwrap_or(start);
214 let span = Span { start, end };
215 let expr = ParsedExpr::node(
216 Expr::LabelAnnotated {
217 label,
218 expr: Box::new(inner.expr.clone()),
219 },
220 span,
221 [(0, inner)],
222 );
223 expression_spans.push(span);
224 push_root_expression(&mut expressions, &mut expression_source_spans, expr);
225 continue;
226 }
227 if self.peek_contextual("type") && !self.peek_assignment_target() {
228 let start = self.peek().span.start;
229 declarations.push(Declaration::Type(self.parse_type_decl()?));
230 declaration_spans.push(self.span_from(start));
231 continue;
232 }
233 if self.peek_contextual("process") && !self.peek_assignment_target() {
234 let start = self.peek().span.start;
235 declarations.push(Declaration::Process(self.parse_process_decl(None)?));
236 declaration_spans.push(self.span_from(start));
237 continue;
238 }
239 if self.peek_contextual("trigger") && !self.peek_assignment_target() {
240 return Err(ParseError::DeclarativeTriggerRemoved {
241 span: self.peek().span,
242 });
243 }
244 let start = self.peek().span.start;
245 let expr = self.parse_statement_expr()?;
246 let end = self
247 .tokens
248 .get(self.index.saturating_sub(1))
249 .map(|token| token.span.end)
250 .unwrap_or(start);
251 let span = Span { start, end };
252 expression_spans.push(span);
253 push_root_expression(&mut expressions, &mut expression_source_spans, expr);
254 }
255 Ok(Program::module_with_spans(
256 declarations,
257 declaration_spans,
258 expressions,
259 expression_spans,
260 expression_source_spans,
261 ))
262 }
263
264 fn span_from(&self, start: usize) -> Span {
265 let end = self
266 .tokens
267 .get(self.index.saturating_sub(1))
268 .map(|token| token.span.end)
269 .unwrap_or(start);
270 Span { start, end }
271 }
272
273 fn parse_type_decl(&mut self) -> Result<TypeDecl, ParseError> {
274 self.expect_contextual("type")?;
275 let name = self.expect_ident()?;
276 self.expect_exact(TokenKind::Equal, "`=`")?;
277 let ty = if matches!(self.peek_kind(), TokenKind::LBrace) {
278 self.parse_type_object_body()?
279 } else {
280 self.parse_type_expr()?
281 };
282 Ok(TypeDecl { name, ty })
283 }
284
285 fn parse_process_decl(
286 &mut self,
287 label: Option<LabelMetadata>,
288 ) -> Result<ProcessDecl, ParseError> {
289 self.expect_contextual("process")?;
290 let name = self.expect_ident()?;
291 self.expect_exact(TokenKind::LParen, "`(`")?;
292 let mut params = Vec::new();
293 while !matches!(self.peek_kind(), TokenKind::RParen | TokenKind::Eof) {
294 let param_name = self.expect_ident()?;
295 self.expect_exact(TokenKind::Colon, "`:`")?;
296 let ty = self.parse_type_expr()?;
297 params.push(ProcessParam {
298 name: param_name,
299 ty,
300 });
301 if matches!(self.peek_kind(), TokenKind::Comma) {
302 self.bump();
303 continue;
304 }
305 break;
306 }
307 self.expect_exact(TokenKind::RParen, "`)`")?;
308 let signals = if self.peek_contextual("signals") && !self.peek_assignment_target() {
309 self.parse_process_signal_decls()?
310 } else {
311 Vec::new()
312 };
313 let return_ty = if matches!(self.peek_kind(), TokenKind::Minus)
314 && self
315 .tokens
316 .get(self.index + 1)
317 .is_some_and(|token| matches!(token.kind, TokenKind::Greater))
318 {
319 self.bump();
320 self.bump();
321 Some(self.parse_type_expr()?)
322 } else {
323 None
324 };
325 self.process_depth += 1;
326 let body = self.parse_block()?;
327 self.process_depth -= 1;
328 Ok(ProcessDecl {
329 name,
330 params,
331 signals,
332 return_ty,
333 label,
334 body: body.into_expr(),
335 })
336 }
337
338 fn parse_process_signal_decls(&mut self) -> Result<Vec<ProcessSignalDecl>, ParseError> {
339 self.expect_contextual("signals")?;
340 self.expect_exact(TokenKind::LBrace, "`{`")?;
341 let mut signals = Vec::new();
342 while !matches!(self.peek_kind(), TokenKind::RBrace | TokenKind::Eof) {
343 let name = self.expect_ident()?;
344 self.expect_exact(TokenKind::Colon, "`:`")?;
345 let ty = self.parse_type_expr()?;
346 signals.push(ProcessSignalDecl { name, ty });
347 if matches!(self.peek_kind(), TokenKind::Comma) {
348 self.bump();
349 if matches!(self.peek_kind(), TokenKind::RBrace) {
350 break;
351 }
352 continue;
353 }
354 break;
355 }
356 self.expect_exact(TokenKind::RBrace, "`}`")?;
357 Ok(signals)
358 }
359
360 fn parse_statement_expr(&mut self) -> Result<ParsedExpr, ParseError> {
361 match self.peek_kind() {
362 TokenKind::If => self.parse_if(),
363 TokenKind::For => self.parse_for(),
364 TokenKind::Submit => self.parse_submit(),
365 TokenKind::Cancel => self.parse_cancel(),
366 TokenKind::Print => self.parse_print(),
367 TokenKind::Call => Err(ParseError::Unexpected {
368 found: "`call`".to_string(),
369 span: self.peek().span,
370 }),
371 TokenKind::Ident(name) if name == "let" && !self.peek_assignment_target() => {
372 self.parse_let_assign()
373 }
374 TokenKind::Ident(name)
375 if matches!(name.as_str(), "yield" | "wake" | "finish" | "fail")
376 && !self.peek_assignment_target() =>
377 {
378 self.parse_processes()
379 }
380 TokenKind::Ident(name) if name == "break" && !self.peek_assignment_target() => {
381 self.parse_loop_control("break")
382 }
383 TokenKind::Ident(name) if name == "continue" && !self.peek_assignment_target() => {
384 self.parse_loop_control("continue")
385 }
386 TokenKind::Ident(name) if name == "while" && !self.peek_assignment_target() => {
387 self.parse_while()
388 }
389 TokenKind::Ident(_) if self.peek_assignment_target() => self.parse_assign(),
390 _ => self.parse_expr(),
391 }
392 }
393
394 fn parse_let_assign(&mut self) -> Result<ParsedExpr, ParseError> {
395 self.bump();
396 self.parse_assign()
397 }
398
399 fn parse_assign(&mut self) -> Result<ParsedExpr, ParseError> {
400 let start = self.peek().span.start;
401 let target = self.parse_assignment_target()?;
402 self.expect_exact(TokenKind::Equal, "`=`")?;
403 let expr = self.parse_expr()?;
404 let value_child_index = target.index_spans.len() as u32;
405 let span = Span {
406 start,
407 end: expr.span.end,
408 };
409 let mut children = target
410 .index_spans
411 .into_iter()
412 .enumerate()
413 .map(|(index, expr)| (index as u32, expr))
414 .collect::<Vec<_>>();
415 children.push((value_child_index, expr));
416 let value_expr = children
417 .last()
418 .expect("assignment value child")
419 .1
420 .expr
421 .clone();
422 Ok(ParsedExpr::node(
423 Expr::Assign {
424 target: target.target,
425 expr: Box::new(value_expr),
426 },
427 span,
428 children,
429 ))
430 }
431
432 fn parse_assignment_target(&mut self) -> Result<ParsedAssignTarget, ParseError> {
433 let root = self.expect_ident()?;
434 let mut steps = Vec::new();
435 let mut index_spans = Vec::new();
436 loop {
437 match self.peek_kind() {
438 TokenKind::Dot => {
439 self.bump();
440 steps.push(AssignPathStep::Field(self.expect_key_name()?));
441 }
442 TokenKind::LBracket => {
443 self.bump();
444 let index = self.parse_expr()?;
445 self.expect_exact(TokenKind::RBracket, "`]`")?;
446 steps.push(AssignPathStep::Index(index.expr.clone()));
447 index_spans.push(index);
448 }
449 _ => break,
450 }
451 }
452 Ok(ParsedAssignTarget {
453 target: AssignTarget { root, steps },
454 index_spans,
455 })
456 }
457
458 fn parse_if(&mut self) -> Result<ParsedExpr, ParseError> {
459 let start = self.bump().span.start;
460 let condition = self.parse_expr()?;
461 let then_block = self.parse_block()?;
462 let else_block = if matches!(self.peek_kind(), TokenKind::Else) {
463 self.bump();
464 if matches!(self.peek_kind(), TokenKind::If) {
465 self.parse_if()?
466 } else {
467 self.parse_block()?
468 }
469 } else {
470 ParsedExpr::leaf(
471 Expr::Block(Vec::new()),
472 Span {
473 start: then_block.span.end,
474 end: then_block.span.end,
475 },
476 )
477 };
478 let span = Span {
479 start,
480 end: else_block.span.end,
481 };
482 Ok(ParsedExpr::node(
483 Expr::If {
484 condition: Box::new(condition.expr.clone()),
485 then_block: Box::new(then_block.expr.clone()),
486 else_block: Box::new(else_block.expr.clone()),
487 },
488 span,
489 [(0, condition), (1, then_block), (2, else_block)],
490 ))
491 }
492
493 fn parse_for(&mut self) -> Result<ParsedExpr, ParseError> {
494 let start = self.bump().span.start;
495 let binding = self.expect_ident()?;
496 self.expect_exact(TokenKind::In, "`in`")?;
497 let iterable = self.parse_expr()?;
498 self.loop_depth += 1;
499 let body = self.parse_block()?;
500 self.loop_depth -= 1;
501 let span = Span {
502 start,
503 end: body.span.end,
504 };
505 Ok(ParsedExpr::node(
506 Expr::For {
507 binding,
508 iterable: Box::new(iterable.expr.clone()),
509 body: Box::new(body.expr.clone()),
510 },
511 span,
512 [(0, iterable), (1, body)],
513 ))
514 }
515
516 fn parse_while(&mut self) -> Result<ParsedExpr, ParseError> {
517 let start = self.bump().span.start;
518 let condition = self.parse_expr()?;
519 self.loop_depth += 1;
520 let body = self.parse_block()?;
521 self.loop_depth -= 1;
522 let span = Span {
523 start,
524 end: body.span.end,
525 };
526 Ok(ParsedExpr::node(
527 Expr::While {
528 condition: Box::new(condition.expr.clone()),
529 body: Box::new(body.expr.clone()),
530 },
531 span,
532 [(0, condition), (1, body)],
533 ))
534 }
535
536 fn parse_loop_control(&mut self, keyword: &'static str) -> Result<ParsedExpr, ParseError> {
537 let span = self.bump().span;
538 if self.loop_depth == 0 {
539 return Err(ParseError::LoopControlOutsideLoop { keyword, span });
540 }
541 let expr = match keyword {
542 "break" => Expr::Break,
543 "continue" => Expr::Continue,
544 _ => unreachable!("unknown loop control keyword"),
545 };
546 Ok(ParsedExpr::leaf(expr, span))
547 }
548
549 fn parse_submit(&mut self) -> Result<ParsedExpr, ParseError> {
550 let span = self.bump().span;
551 if self.process_depth > 0 {
552 return Err(ParseError::ForegroundControlInsideProcess {
553 keyword: "submit",
554 span,
555 });
556 }
557 let expr = if matches!(self.peek_kind(), TokenKind::RBrace | TokenKind::Eof) {
558 None
559 } else {
560 Some(self.parse_expr()?)
561 };
562 let end = expr.as_ref().map(|expr| expr.span.end).unwrap_or(span.end);
563 let span = Span {
564 start: span.start,
565 end,
566 };
567 let value_expr = expr.as_ref().map(|expr| Box::new(expr.expr.clone()));
568 Ok(match expr {
569 Some(expr) => ParsedExpr::node(Expr::Submit(value_expr), span, [(0, expr)]),
570 None => ParsedExpr::leaf(Expr::Submit(None), span),
571 })
572 }
573
574 fn parse_print(&mut self) -> Result<ParsedExpr, ParseError> {
575 let span = self.bump().span;
576 if self.process_depth > 0 {
577 return Err(ParseError::ForegroundControlInsideProcess {
578 keyword: "print",
579 span,
580 });
581 }
582 let expr = self.parse_expr()?;
583 let span = Span {
584 start: span.start,
585 end: expr.span.end,
586 };
587 Ok(ParsedExpr::node(
588 Expr::Print(Box::new(expr.expr.clone())),
589 span,
590 [(0, expr)],
591 ))
592 }
593
594 fn parse_processes(&mut self) -> Result<ParsedExpr, ParseError> {
595 let token = self.bump().clone();
596 let TokenKind::Ident(keyword) = token.kind else {
597 unreachable!("process admins are contextual identifiers");
598 };
599 let keyword_static = match keyword.as_str() {
600 "yield" => "yield",
601 "wake" => "wake",
602 "finish" => "finish",
603 "fail" => "fail",
604 _ => unreachable!("unknown process admin keyword"),
605 };
606 if self.process_depth == 0 {
607 return Err(ParseError::SessionProcessAdminOutsideBlock {
608 keyword: keyword_static,
609 span: token.span,
610 });
611 }
612 match keyword_static {
613 "yield" => {
614 let expr = self.parse_expr()?;
615 let span = Span {
616 start: token.span.start,
617 end: expr.span.end,
618 };
619 Ok(ParsedExpr::node(
620 Expr::Yield(Box::new(expr.expr.clone())),
621 span,
622 [(0, expr)],
623 ))
624 }
625 "wake" => {
626 let expr = self.parse_expr()?;
627 let span = Span {
628 start: token.span.start,
629 end: expr.span.end,
630 };
631 Ok(ParsedExpr::node(
632 Expr::Wake(Box::new(expr.expr.clone())),
633 span,
634 [(0, expr)],
635 ))
636 }
637 "finish" => {
638 let expr = if matches!(self.peek_kind(), TokenKind::RBrace | TokenKind::Eof) {
639 None
640 } else {
641 Some(self.parse_expr()?)
642 };
643 let end = expr
644 .as_ref()
645 .map(|expr| expr.span.end)
646 .unwrap_or(token.span.end);
647 let span = Span {
648 start: token.span.start,
649 end,
650 };
651 let value_expr = expr.as_ref().map(|expr| Box::new(expr.expr.clone()));
652 Ok(match expr {
653 Some(expr) => ParsedExpr::node(Expr::Finish(value_expr), span, [(0, expr)]),
654 None => ParsedExpr::leaf(Expr::Finish(None), span),
655 })
656 }
657 "fail" => {
658 let expr = self.parse_expr()?;
659 let span = Span {
660 start: token.span.start,
661 end: expr.span.end,
662 };
663 Ok(ParsedExpr::node(
664 Expr::Fail(Box::new(expr.expr.clone())),
665 span,
666 [(0, expr)],
667 ))
668 }
669 _ => unreachable!("unknown process admin keyword"),
670 }
671 }
672
673 fn parse_cancel(&mut self) -> Result<ParsedExpr, ParseError> {
674 let start = self.bump().span.start;
675 let expr = self.parse_expr()?;
676 let span = Span {
677 start,
678 end: expr.span.end,
679 };
680 Ok(ParsedExpr::node(
681 Expr::Cancel(Box::new(expr.expr.clone())),
682 span,
683 [(0, expr)],
684 ))
685 }
686
687 fn enter_nesting(&mut self) -> Result<(), ParseError> {
691 if self.nesting_depth >= MAX_NESTING_DEPTH {
692 return Err(ParseError::NestingTooDeep {
693 limit: MAX_NESTING_DEPTH,
694 span: self.peek().span,
695 });
696 }
697 self.nesting_depth += 1;
698 Ok(())
699 }
700
701 fn leave_nesting(&mut self) {
702 self.nesting_depth -= 1;
703 }
704
705 fn parse_block(&mut self) -> Result<ParsedExpr, ParseError> {
706 self.enter_nesting()?;
709 let result = self.parse_block_inner();
710 self.leave_nesting();
711 result
712 }
713
714 fn parse_block_inner(&mut self) -> Result<ParsedExpr, ParseError> {
715 let start = self.peek().span.start;
716 self.expect_exact(TokenKind::LBrace, "`{`")?;
717 let mut expressions = Vec::new();
718 let mut children = Vec::new();
719 while !matches!(self.peek_kind(), TokenKind::RBrace | TokenKind::Eof) {
720 let expr = if matches!(self.peek_kind(), TokenKind::At) {
721 self.parse_annotated_statement()?
722 } else {
723 self.parse_statement_expr()?
724 };
725 let child_index = expressions.len() as u32;
726 expressions.push(expr.expr.clone());
727 children.push((child_index, expr));
728 }
729 self.expect_exact(TokenKind::RBrace, "`}`")?;
730 Ok(ParsedExpr::node(
731 Expr::Block(expressions),
732 self.span_from(start),
733 children,
734 ))
735 }
736
737 fn parse_annotated_statement(&mut self) -> Result<ParsedExpr, ParseError> {
738 let start = self.peek().span.start;
739 let label = self.parse_label_annotation()?;
740 if matches!(self.peek_kind(), TokenKind::At)
741 || self.peek_contextual("type")
742 || self.peek_contextual("process")
743 || self.peek_contextual("trigger")
744 {
745 return Err(ParseError::InvalidLabelTarget {
746 span: self.peek().span,
747 });
748 }
749 let expr = self.parse_statement_expr()?;
750 let span = Span {
751 start,
752 end: expr.span.end,
753 };
754 Ok(ParsedExpr::node(
755 Expr::LabelAnnotated {
756 label,
757 expr: Box::new(expr.expr.clone()),
758 },
759 span,
760 [(0, expr)],
761 ))
762 }
763
764 fn parse_label_annotation(&mut self) -> Result<LabelMetadata, ParseError> {
765 let span = self.peek().span;
766 self.expect_exact(TokenKind::At, "`@`")?;
767 self.expect_contextual("label")?;
768 self.expect_exact(TokenKind::LParen, "`(`")?;
769
770 let mut title = None;
771 let mut description = None;
772 while !matches!(self.peek_kind(), TokenKind::RParen | TokenKind::Eof) {
773 let key_span = self.peek().span;
774 let key = self.expect_ident()?;
775 self.expect_exact(TokenKind::Colon, "`:`")?;
776 let value = self.expect_string_literal()?;
777 match key.as_str() {
778 "title" => {
779 if title.replace(value).is_some() {
780 return Err(ParseError::InvalidLabelAnnotation {
781 message: "duplicate `title` field".to_string(),
782 span: key_span,
783 });
784 }
785 }
786 "description" => {
787 if description.replace(value).is_some() {
788 return Err(ParseError::InvalidLabelAnnotation {
789 message: "duplicate `description` field".to_string(),
790 span: key_span,
791 });
792 }
793 }
794 _ => {
795 return Err(ParseError::InvalidLabelAnnotation {
796 message: format!("unknown field `{key}`"),
797 span: key_span,
798 });
799 }
800 }
801 if matches!(self.peek_kind(), TokenKind::Comma) {
802 self.bump();
803 if matches!(self.peek_kind(), TokenKind::RParen) {
804 break;
805 }
806 continue;
807 }
808 break;
809 }
810 self.expect_exact(TokenKind::RParen, "`)`")?;
811 let Some(title) = title else {
812 return Err(ParseError::InvalidLabelAnnotation {
813 message: "`title` is required".to_string(),
814 span,
815 });
816 };
817 Ok(LabelMetadata { title, description })
818 }
819
820 fn parse_expr(&mut self) -> Result<ParsedExpr, ParseError> {
821 self.enter_nesting()?;
825 let result = self.parse_tuple_expr();
826 self.leave_nesting();
827 result
828 }
829
830 fn parse_expr_no_tuple(&mut self) -> Result<ParsedExpr, ParseError> {
831 self.enter_nesting()?;
832 let result = self.parse_ternary();
833 self.leave_nesting();
834 result
835 }
836
837 fn parse_tuple_expr(&mut self) -> Result<ParsedExpr, ParseError> {
838 let first = self.parse_ternary()?;
839 if !matches!(self.peek_kind(), TokenKind::Comma) {
840 return Ok(first);
841 }
842
843 let mut items = Vec::new();
844 let mut children = Vec::new();
845 children.push((0, first));
846 items.push(children.last().expect("tuple item").1.expr.clone());
847 let mut end = children.last().expect("tuple item").1.span.end;
848
849 while matches!(self.peek_kind(), TokenKind::Comma) {
850 end = self.bump().span.end;
851 if matches!(
852 self.peek_kind(),
853 TokenKind::RParen | TokenKind::RBracket | TokenKind::RBrace | TokenKind::Eof
854 ) {
855 break;
856 }
857 let item = self.parse_ternary()?;
858 end = item.span.end;
859 children.push((items.len() as u32, item));
860 items.push(children.last().expect("tuple item").1.expr.clone());
861 }
862
863 let span = Span {
864 start: children.first().expect("tuple first").1.span.start,
865 end,
866 };
867 Ok(ParsedExpr::node(Expr::Tuple(items), span, children))
868 }
869
870 fn parse_ternary(&mut self) -> Result<ParsedExpr, ParseError> {
871 let condition = self.parse_or()?;
872 if !matches!(self.peek_kind(), TokenKind::Question) {
873 return Ok(condition);
874 }
875 self.bump();
876 let then_expr = self.parse_expr_no_tuple()?;
877 self.expect_exact(TokenKind::Colon, "`:`")?;
878 let else_expr = self.parse_expr_no_tuple()?;
879 let span = Span {
880 start: condition.span.start,
881 end: else_expr.span.end,
882 };
883 Ok(ParsedExpr::node(
884 Expr::If {
885 condition: Box::new(condition.expr.clone()),
886 then_block: Box::new(then_expr.expr.clone()),
887 else_block: Box::new(else_expr.expr.clone()),
888 },
889 span,
890 [(0, condition), (1, then_expr), (2, else_expr)],
891 ))
892 }
893
894 fn parse_or(&mut self) -> Result<ParsedExpr, ParseError> {
895 let mut expr = self.parse_and()?;
896 while matches!(self.peek_kind(), TokenKind::Or | TokenKind::OrOr) {
897 self.bump();
898 let right = self.parse_and()?;
899 let span = Span {
900 start: expr.span.start,
901 end: right.span.end,
902 };
903 expr = ParsedExpr::node(
904 Expr::Binary {
905 left: Box::new(expr.expr.clone()),
906 op: BinaryOp::Or,
907 right: Box::new(right.expr.clone()),
908 },
909 span,
910 [(0, expr), (1, right)],
911 );
912 }
913 Ok(expr)
914 }
915
916 fn parse_and(&mut self) -> Result<ParsedExpr, ParseError> {
917 let mut expr = self.parse_compare()?;
918 while matches!(self.peek_kind(), TokenKind::And | TokenKind::AndAnd) {
919 self.bump();
920 let right = self.parse_compare()?;
921 let span = Span {
922 start: expr.span.start,
923 end: right.span.end,
924 };
925 expr = ParsedExpr::node(
926 Expr::Binary {
927 left: Box::new(expr.expr.clone()),
928 op: BinaryOp::And,
929 right: Box::new(right.expr.clone()),
930 },
931 span,
932 [(0, expr), (1, right)],
933 );
934 }
935 Ok(expr)
936 }
937
938 fn parse_compare(&mut self) -> Result<ParsedExpr, ParseError> {
939 let mut expr = self.parse_add()?;
940 loop {
941 let op = match self.peek_kind() {
942 TokenKind::DoubleEqual => BinaryOp::Equal,
943 TokenKind::BangEqual => BinaryOp::NotEqual,
944 TokenKind::Less => BinaryOp::Less,
945 TokenKind::LessEqual => BinaryOp::LessEqual,
946 TokenKind::Greater => BinaryOp::Greater,
947 TokenKind::GreaterEqual => BinaryOp::GreaterEqual,
948 _ => break,
949 };
950 self.bump();
951 let right = self.parse_add()?;
952 let span = Span {
953 start: expr.span.start,
954 end: right.span.end,
955 };
956 expr = ParsedExpr::node(
957 Expr::Binary {
958 left: Box::new(expr.expr.clone()),
959 op,
960 right: Box::new(right.expr.clone()),
961 },
962 span,
963 [(0, expr), (1, right)],
964 );
965 }
966 Ok(expr)
967 }
968
969 fn parse_add(&mut self) -> Result<ParsedExpr, ParseError> {
970 let mut expr = self.parse_mul()?;
971 loop {
972 let op = match self.peek_kind() {
973 TokenKind::Plus => BinaryOp::Add,
974 TokenKind::Minus => BinaryOp::Subtract,
975 _ => break,
976 };
977 self.bump();
978 let right = self.parse_mul()?;
979 let span = Span {
980 start: expr.span.start,
981 end: right.span.end,
982 };
983 expr = ParsedExpr::node(
984 Expr::Binary {
985 left: Box::new(expr.expr.clone()),
986 op,
987 right: Box::new(right.expr.clone()),
988 },
989 span,
990 [(0, expr), (1, right)],
991 );
992 }
993 Ok(expr)
994 }
995
996 fn parse_mul(&mut self) -> Result<ParsedExpr, ParseError> {
997 let mut expr = self.parse_unary()?;
998 loop {
999 let op = match self.peek_kind() {
1000 TokenKind::Star => BinaryOp::Multiply,
1001 TokenKind::Slash => BinaryOp::Divide,
1002 TokenKind::Percent => BinaryOp::Modulo,
1003 _ => break,
1004 };
1005 self.bump();
1006 let right = self.parse_unary()?;
1007 let span = Span {
1008 start: expr.span.start,
1009 end: right.span.end,
1010 };
1011 expr = ParsedExpr::node(
1012 Expr::Binary {
1013 left: Box::new(expr.expr.clone()),
1014 op,
1015 right: Box::new(right.expr.clone()),
1016 },
1017 span,
1018 [(0, expr), (1, right)],
1019 );
1020 }
1021 Ok(expr)
1022 }
1023
1024 fn parse_unary(&mut self) -> Result<ParsedExpr, ParseError> {
1025 match self.peek_kind() {
1026 TokenKind::Minus => {
1027 let start = self.bump().span.start;
1028 let expr = self.parse_unary()?;
1029 Ok(ParsedExpr::node(
1030 Expr::Unary {
1031 op: UnaryOp::Negate,
1032 expr: Box::new(expr.expr.clone()),
1033 },
1034 Span {
1035 start,
1036 end: expr.span.end,
1037 },
1038 [(0, expr)],
1039 ))
1040 }
1041 TokenKind::Not => {
1042 let start = self.bump().span.start;
1043 let expr = self.parse_unary()?;
1044 Ok(ParsedExpr::node(
1045 Expr::Unary {
1046 op: UnaryOp::Not,
1047 expr: Box::new(expr.expr.clone()),
1048 },
1049 Span {
1050 start,
1051 end: expr.span.end,
1052 },
1053 [(0, expr)],
1054 ))
1055 }
1056 TokenKind::Bang => {
1057 let start = self.bump().span.start;
1058 let expr = self.parse_unary()?;
1059 Ok(ParsedExpr::node(
1060 Expr::Unary {
1061 op: UnaryOp::Not,
1062 expr: Box::new(expr.expr.clone()),
1063 },
1064 Span {
1065 start,
1066 end: expr.span.end,
1067 },
1068 [(0, expr)],
1069 ))
1070 }
1071 TokenKind::Await => {
1072 let start = self.bump().span.start;
1073 let expr = self.parse_unary()?;
1074 Ok(ParsedExpr::node(
1075 Expr::Await(Box::new(expr.expr.clone())),
1076 Span {
1077 start,
1078 end: expr.span.end,
1079 },
1080 [(0, expr)],
1081 ))
1082 }
1083 _ => self.parse_postfix(),
1084 }
1085 }
1086
1087 fn parse_postfix(&mut self) -> Result<ParsedExpr, ParseError> {
1088 let mut expr = self.parse_primary()?;
1089 loop {
1090 match self.peek_kind() {
1091 TokenKind::Dot => {
1092 self.bump();
1093 let field = self.expect_key_name()?;
1094 if matches!(self.peek_kind(), TokenKind::LParen) {
1095 let args = self.parse_call_arguments()?;
1096 let span = self.span_from(expr.span.start);
1097 let mut children = Vec::with_capacity(args.len() + 1);
1098 children.push((0, expr));
1099 let arg_exprs = args.iter().map(|arg| arg.expr.clone()).collect();
1100 children.extend(
1101 args.into_iter()
1102 .enumerate()
1103 .map(|(index, arg)| ((index + 1) as u32, arg)),
1104 );
1105 let receiver = children[0].1.expr.clone();
1106 expr = ParsedExpr::node(
1107 Expr::ReceiverCall {
1108 receiver: Box::new(receiver),
1109 operation: field,
1110 args: arg_exprs,
1111 },
1112 span,
1113 children,
1114 );
1115 } else {
1116 let span = self.span_from(expr.span.start);
1117 expr = ParsedExpr::node(
1118 Expr::Field {
1119 target: Box::new(expr.expr.clone()),
1120 field,
1121 },
1122 span,
1123 [(0, expr)],
1124 );
1125 }
1126 }
1127 TokenKind::LBracket => {
1128 self.bump();
1129 let index = self.parse_expr()?;
1130 self.expect_exact(TokenKind::RBracket, "`]`")?;
1131 let span = self.span_from(expr.span.start);
1132 expr = ParsedExpr::node(
1133 Expr::Index {
1134 target: Box::new(expr.expr.clone()),
1135 index: Box::new(index.expr.clone()),
1136 },
1137 span,
1138 [(0, expr), (1, index)],
1139 );
1140 }
1141 TokenKind::Question if !self.question_starts_ternary() => {
1142 self.bump();
1143 let span = self.span_from(expr.span.start);
1144 expr = ParsedExpr::node(
1145 Expr::ResultUnwrap(Box::new(expr.expr.clone())),
1146 span,
1147 [(0, expr)],
1148 );
1149 }
1150 _ => break,
1151 }
1152 }
1153 Ok(expr)
1154 }
1155
1156 fn parse_primary(&mut self) -> Result<ParsedExpr, ParseError> {
1157 match self.peek_kind() {
1158 TokenKind::Null => {
1159 let span = self.bump().span;
1160 Ok(ParsedExpr::leaf(Expr::Null, span))
1161 }
1162 TokenKind::True => {
1163 let span = self.bump().span;
1164 Ok(ParsedExpr::leaf(Expr::Bool(true), span))
1165 }
1166 TokenKind::False => {
1167 let span = self.bump().span;
1168 Ok(ParsedExpr::leaf(Expr::Bool(false), span))
1169 }
1170 TokenKind::Number(value) => {
1171 let value = *value;
1172 let span = self.bump().span;
1173 Ok(ParsedExpr::leaf(Expr::Number(value), span))
1174 }
1175 TokenKind::String(value) => {
1176 let value = value.clone();
1177 let span = self.bump().span;
1178 Ok(ParsedExpr::leaf(Expr::String(value), span))
1179 }
1180 TokenKind::Ident(name) => {
1181 let token_span = self.peek().span;
1182 if name == "parallel"
1183 && self
1184 .tokens
1185 .get(self.index + 1)
1186 .is_some_and(|token| matches!(token.kind, TokenKind::LBrace))
1187 {
1188 return Err(ParseError::Unexpected {
1189 found: "`parallel`".to_string(),
1190 span: self.peek().span,
1191 });
1192 }
1193 let name = name.clone();
1194 self.bump();
1195 if name == "sleep" {
1196 return self.parse_sleep_expr(token_span.start);
1197 }
1198 if name == "start" && matches!(self.peek_kind(), TokenKind::Call) {
1199 return Err(ParseError::Unexpected {
1200 found: "`start call`".to_string(),
1201 span: self.tokens[self.index.saturating_sub(1)].span,
1202 });
1203 }
1204 if name == "start"
1205 && (matches!(self.peek_kind(), TokenKind::Ident(_))
1206 || matches!(self.peek_kind(), TokenKind::LBrace)
1207 || self.paren_group_followed_by_lbrace())
1208 {
1209 return self.parse_process_start_expr(token_span.start);
1210 }
1211 if name == "Type" && matches!(self.peek_kind(), TokenKind::LBrace) {
1212 let ty = self.parse_type_object()?;
1213 return Ok(ParsedExpr::leaf(
1214 Expr::TypeLiteral(Box::new(ty)),
1215 self.span_from(token_span.start),
1216 ));
1217 }
1218 if matches!(self.peek_kind(), TokenKind::LParen) {
1219 let args = self.parse_call_arguments()?;
1220 if name == "wait_signal" {
1221 if args.len() != 1 {
1222 return Err(ParseError::Expected {
1223 expected: "one signal name argument",
1224 found: format!("{} arguments", args.len()),
1225 span: self.tokens[self.index.saturating_sub(1)].span,
1226 });
1227 }
1228 return Ok(ParsedExpr::leaf(
1229 Expr::WaitSignal {
1230 name: static_signal_name_arg(&args[0].expr, "wait_signal")?,
1231 },
1232 self.span_from(token_span.start),
1233 ));
1234 }
1235 if name == "signal_run" {
1236 if args.len() != 3 {
1237 return Err(ParseError::Expected {
1238 expected: "run handle, signal name, and payload arguments",
1239 found: format!("{} arguments", args.len()),
1240 span: self.tokens[self.index.saturating_sub(1)].span,
1241 });
1242 }
1243 let run = args[0].expr.clone();
1244 let payload = args[2].expr.clone();
1245 return Ok(ParsedExpr::node(
1246 Expr::SignalRun {
1247 run: Box::new(run),
1248 name: static_signal_name_arg(&args[1].expr, "signal_run")?,
1249 payload: Box::new(payload),
1250 },
1251 self.span_from(token_span.start),
1252 [(0, args[0].clone()), (1, args[2].clone())],
1253 ));
1254 }
1255 let arg_exprs = args.iter().map(|arg| arg.expr.clone()).collect();
1256 Ok(ParsedExpr::node(
1257 Expr::BuiltinCall {
1258 name,
1259 args: arg_exprs,
1260 },
1261 self.span_from(token_span.start),
1262 args.into_iter()
1263 .enumerate()
1264 .map(|(index, arg)| (index as u32, arg)),
1265 ))
1266 } else {
1267 Ok(ParsedExpr::leaf(Expr::Variable(name), token_span))
1268 }
1269 }
1270 TokenKind::LParen => {
1271 let start = self.bump().span.start;
1272 if matches!(self.peek_kind(), TokenKind::RParen) {
1273 self.bump();
1274 return Ok(ParsedExpr::node(
1275 Expr::Tuple(Vec::new()),
1276 self.span_from(start),
1277 [],
1278 ));
1279 }
1280 let expr = self.parse_expr()?;
1281 self.expect_exact(TokenKind::RParen, "`)`")?;
1282 Ok(expr)
1283 }
1284 TokenKind::LBracket => self.parse_list(),
1285 TokenKind::LBrace => self.parse_record(),
1286 TokenKind::Call => Err(ParseError::Unexpected {
1287 found: "`call`".to_string(),
1288 span: self.peek().span,
1289 }),
1290 _ => Err(self.unexpected()),
1291 }
1292 }
1293
1294 fn parse_list(&mut self) -> Result<ParsedExpr, ParseError> {
1295 let start = self.peek().span.start;
1296 self.expect_exact(TokenKind::LBracket, "`[`")?;
1297 if matches!(self.peek_kind(), TokenKind::RBracket) {
1298 self.expect_exact(TokenKind::RBracket, "`]`")?;
1299 return Ok(ParsedExpr::node(
1300 Expr::List(Vec::new()),
1301 self.span_from(start),
1302 [],
1303 ));
1304 }
1305
1306 let first = self.parse_expr_no_tuple()?;
1307 if matches!(self.peek_kind(), TokenKind::For) {
1308 let parsed_clauses = self.parse_list_comprehension_clauses()?;
1309 self.expect_exact(TokenKind::RBracket, "`]`")?;
1310 let clauses = parsed_clauses
1311 .iter()
1312 .map(|parsed| parsed.clause.clone())
1313 .collect::<Vec<_>>();
1314 let mut children = parsed_clauses
1315 .into_iter()
1316 .enumerate()
1317 .map(|(index, parsed)| (index as u32, parsed.expr_span))
1318 .collect::<Vec<_>>();
1319 children.push((children.len() as u32, first.clone()));
1320 return Ok(ParsedExpr::node(
1321 Expr::ListComprehension {
1322 element: Box::new(first.expr.clone()),
1323 clauses,
1324 },
1325 self.span_from(start),
1326 children,
1327 ));
1328 }
1329
1330 let mut items = Vec::new();
1331 let mut children = Vec::new();
1332 children.push((0, first));
1333 items.push(children.last().expect("item").1.expr.clone());
1334 if matches!(self.peek_kind(), TokenKind::Comma) {
1335 self.bump();
1336 } else {
1337 self.expect_exact(TokenKind::RBracket, "`]`")?;
1338 return Ok(ParsedExpr::node(
1339 Expr::List(items),
1340 self.span_from(start),
1341 children,
1342 ));
1343 }
1344 while !matches!(self.peek_kind(), TokenKind::RBracket) {
1345 let item = self.parse_expr_no_tuple()?;
1346 children.push((items.len() as u32, item));
1347 items.push(children.last().expect("item").1.expr.clone());
1348 if matches!(self.peek_kind(), TokenKind::Comma) {
1349 self.bump();
1350 continue;
1351 }
1352 break;
1353 }
1354 self.expect_exact(TokenKind::RBracket, "`]`")?;
1355 Ok(ParsedExpr::node(
1356 Expr::List(items),
1357 self.span_from(start),
1358 children,
1359 ))
1360 }
1361
1362 fn parse_list_comprehension_clauses(
1363 &mut self,
1364 ) -> Result<Vec<ParsedListComprehensionClause>, ParseError> {
1365 let mut clauses = Vec::new();
1366 while matches!(self.peek_kind(), TokenKind::For) {
1367 self.bump();
1368 let binding = self.expect_ident()?;
1369 self.expect_exact(TokenKind::In, "`in`")?;
1370 let iterable = self.parse_expr()?;
1371 clauses.push(ParsedListComprehensionClause {
1372 clause: ListComprehensionClause::For {
1373 binding,
1374 iterable: iterable.expr.clone(),
1375 },
1376 expr_span: iterable,
1377 });
1378 while matches!(self.peek_kind(), TokenKind::If) {
1379 self.bump();
1380 let condition = self.parse_expr()?;
1381 clauses.push(ParsedListComprehensionClause {
1382 clause: ListComprehensionClause::If {
1383 condition: condition.expr.clone(),
1384 },
1385 expr_span: condition,
1386 });
1387 }
1388 }
1389 Ok(clauses)
1390 }
1391
1392 fn parse_record(&mut self) -> Result<ParsedExpr, ParseError> {
1393 let start = self.peek().span.start;
1394 self.expect_exact(TokenKind::LBrace, "`{`")?;
1395 let entries = self.parse_record_entries()?;
1396 self.expect_exact(TokenKind::RBrace, "`}`")?;
1397 let expr_entries = entries
1398 .iter()
1399 .map(|(key, value)| (key.clone(), value.expr.clone()))
1400 .collect();
1401 Ok(ParsedExpr::node(
1402 Expr::Record(expr_entries),
1403 self.span_from(start),
1404 entries
1405 .into_iter()
1406 .enumerate()
1407 .map(|(index, (_, value))| (index as u32, value)),
1408 ))
1409 }
1410
1411 fn parse_record_entries(&mut self) -> Result<Vec<(AstString, ParsedExpr)>, ParseError> {
1412 let mut entries = Vec::new();
1413 while !matches!(self.peek_kind(), TokenKind::RBrace) {
1414 let key = self.expect_key_name()?;
1415 self.expect_exact(TokenKind::Colon, "`:`")?;
1416 let value = self.parse_expr_no_tuple()?;
1417 entries.push((key, value));
1418 if matches!(self.peek_kind(), TokenKind::Comma) {
1419 self.bump();
1420 continue;
1421 }
1422 break;
1423 }
1424 Ok(entries)
1425 }
1426
1427 fn parse_call_arguments(&mut self) -> Result<Vec<ParsedExpr>, ParseError> {
1428 self.expect_exact(TokenKind::LParen, "`(`")?;
1429 let mut args = Vec::new();
1430 if !matches!(self.peek_kind(), TokenKind::RParen) {
1431 loop {
1432 args.push(self.parse_expr_no_tuple()?);
1433 if matches!(self.peek_kind(), TokenKind::Comma) {
1434 self.bump();
1435 if matches!(self.peek_kind(), TokenKind::RParen) {
1436 break;
1437 }
1438 continue;
1439 }
1440 break;
1441 }
1442 }
1443 self.expect_exact(TokenKind::RParen, "`)`")?;
1444 Ok(args)
1445 }
1446
1447 fn parse_named_arguments(&mut self) -> Result<Vec<(AstString, ParsedExpr)>, ParseError> {
1448 let mut entries = Vec::new();
1449 while !matches!(self.peek_kind(), TokenKind::RParen | TokenKind::Eof) {
1450 let key = self.expect_key_name()?;
1451 self.expect_exact(TokenKind::Colon, "`:`")?;
1452 let value = self.parse_expr_no_tuple()?;
1453 entries.push((key, value));
1454 if matches!(self.peek_kind(), TokenKind::Comma) {
1455 self.bump();
1456 continue;
1457 }
1458 break;
1459 }
1460 Ok(entries)
1461 }
1462
1463 fn parse_process_start_expr(&mut self, start: usize) -> Result<ParsedExpr, ParseError> {
1464 if matches!(self.peek_kind(), TokenKind::LBrace) || self.paren_group_followed_by_lbrace() {
1465 return Err(ParseError::Unexpected {
1466 found: "inline `start` process body".to_string(),
1467 span: self.peek().span,
1468 });
1469 }
1470 let process = self.expect_ident()?;
1471 self.expect_exact(TokenKind::LParen, "`(`")?;
1472 let args = self.parse_named_arguments()?;
1473 self.expect_exact(TokenKind::RParen, "`)`")?;
1474 let expr_args = args
1475 .iter()
1476 .map(|(name, value)| (name.clone(), value.expr.clone()))
1477 .collect();
1478 Ok(ParsedExpr::node(
1479 Expr::StartProcess(ProcessStartExpr {
1480 process,
1481 args: expr_args,
1482 }),
1483 self.span_from(start),
1484 args.into_iter()
1485 .enumerate()
1486 .map(|(index, (_, value))| (index as u32, value)),
1487 ))
1488 }
1489
1490 fn parse_sleep_expr(&mut self, start: usize) -> Result<ParsedExpr, ParseError> {
1491 if matches!(self.peek_kind(), TokenKind::For) {
1492 self.bump();
1493 let expr = self.parse_expr()?;
1494 return Ok(ParsedExpr::node(
1495 Expr::SleepFor(Box::new(expr.expr.clone())),
1496 Span {
1497 start,
1498 end: expr.span.end,
1499 },
1500 [(0, expr)],
1501 ));
1502 }
1503 if self.peek_contextual("until") {
1504 self.bump();
1505 let expr = self.parse_expr()?;
1506 return Ok(ParsedExpr::node(
1507 Expr::SleepUntil(Box::new(expr.expr.clone())),
1508 Span {
1509 start,
1510 end: expr.span.end,
1511 },
1512 [(0, expr)],
1513 ));
1514 }
1515 Err(ParseError::Expected {
1516 expected: "`for` or `until`",
1517 found: render_kind(self.peek_kind()),
1518 span: self.peek().span,
1519 })
1520 }
1521
1522 fn parse_type_object(&mut self) -> Result<TypeExpr, ParseError> {
1523 self.expect_exact(TokenKind::LBrace, "`{`")?;
1524 self.parse_type_object_body_after_lbrace()
1525 }
1526
1527 fn parse_type_object_body(&mut self) -> Result<TypeExpr, ParseError> {
1528 self.expect_exact(TokenKind::LBrace, "`{`")?;
1529 self.parse_type_object_body_after_lbrace()
1530 }
1531
1532 fn parse_type_object_body_after_lbrace(&mut self) -> Result<TypeExpr, ParseError> {
1533 let mut fields = Vec::new();
1534 let mut seen = std::collections::HashSet::new();
1535 while !matches!(self.peek_kind(), TokenKind::RBrace) {
1536 let name_token_span = self.peek().span;
1537 let name = self.expect_key_name()?;
1538 if !seen.insert(name.clone()) {
1539 return Err(ParseError::Expected {
1540 expected: "unique field name",
1541 found: format!("duplicate field `{name}`"),
1542 span: name_token_span,
1543 });
1544 }
1545 self.expect_exact(TokenKind::Colon, "`:`")?;
1546 let ty = self.parse_type_expr()?;
1547 let optional = if matches!(self.peek_kind(), TokenKind::Question) {
1548 self.bump();
1549 true
1550 } else {
1551 false
1552 };
1553 fields.push(TypeField { name, ty, optional });
1554 if matches!(self.peek_kind(), TokenKind::Comma) {
1555 self.bump();
1556 continue;
1557 }
1558 break;
1559 }
1560 self.expect_exact(TokenKind::RBrace, "`}`")?;
1561 Ok(TypeExpr::Object(fields))
1562 }
1563
1564 fn parse_type_expr(&mut self) -> Result<TypeExpr, ParseError> {
1565 let first = self.parse_type_term()?;
1566 if !matches!(self.peek_kind(), TokenKind::Pipe) {
1567 return Ok(first);
1568 }
1569 let mut variants = vec![first];
1573 while matches!(self.peek_kind(), TokenKind::Pipe) {
1574 self.bump();
1575 variants.push(self.parse_type_term()?);
1576 }
1577 Ok(TypeExpr::Union(variants))
1578 }
1579
1580 fn parse_type_term(&mut self) -> Result<TypeExpr, ParseError> {
1581 let token = self.peek().clone();
1582 match token.kind {
1583 TokenKind::Null => {
1584 self.bump();
1585 Ok(TypeExpr::Null)
1586 }
1587 TokenKind::String(value) => {
1588 self.bump();
1589 Ok(TypeExpr::Enum(vec![value]))
1590 }
1591 TokenKind::LBrace => self.parse_type_object_body(),
1596 TokenKind::Ident(_name) => {
1597 let name = self.parse_type_name()?;
1598 match name.as_str() {
1599 "str" | "string" => Ok(TypeExpr::Str),
1600 "int" | "integer" => Ok(TypeExpr::Int),
1601 "float" | "number" => Ok(TypeExpr::Float),
1602 "bool" | "boolean" => Ok(TypeExpr::Bool),
1603 "dict" | "object" => Ok(TypeExpr::Dict),
1604 "any" => Ok(TypeExpr::Any),
1605 "enum" => {
1606 self.expect_exact(TokenKind::LBracket, "`[`")?;
1607 let mut values = Vec::new();
1608 if !matches!(self.peek_kind(), TokenKind::RBracket) {
1609 loop {
1610 let value = self.expect_string_literal()?;
1611 values.push(value);
1612 if matches!(self.peek_kind(), TokenKind::Comma) {
1613 self.bump();
1614 continue;
1615 }
1616 break;
1617 }
1618 }
1619 if values.is_empty() {
1620 return Err(ParseError::Expected {
1621 expected: "at least one enum string literal",
1622 found: "empty enum".to_string(),
1623 span: token.span,
1624 });
1625 }
1626 self.expect_exact(TokenKind::RBracket, "`]`")?;
1627 Ok(TypeExpr::Enum(values))
1628 }
1629 "list" => {
1630 self.expect_exact(TokenKind::LBracket, "`[`")?;
1631 let inner = self.parse_type_expr()?;
1632 self.expect_exact(TokenKind::RBracket, "`]`")?;
1633 Ok(TypeExpr::List(Box::new(inner)))
1634 }
1635 "Process" => {
1636 self.expect_exact(TokenKind::Less, "`<`")?;
1637 let input = self.parse_type_expr()?;
1638 self.expect_exact(TokenKind::Comma, "`,`")?;
1639 let output = self.parse_type_expr()?;
1640 self.expect_exact(TokenKind::Greater, "`>`")?;
1641 Ok(TypeExpr::Process {
1642 input: Box::new(input),
1643 output: Box::new(output),
1644 input_count: 1,
1645 })
1646 }
1647 "TriggerHandle" => {
1648 self.expect_exact(TokenKind::Less, "`<`")?;
1649 let event = self.parse_type_expr()?;
1650 self.expect_exact(TokenKind::Greater, "`>`")?;
1651 Ok(TypeExpr::TriggerHandle(Box::new(event)))
1652 }
1653 "Type" => self.parse_type_object(),
1654 _ => Ok(TypeExpr::Ref(name)),
1655 }
1656 }
1657 _ => Err(ParseError::Expected {
1658 expected: "type expression",
1659 found: render_kind(&token.kind),
1660 span: token.span,
1661 }),
1662 }
1663 }
1664
1665 fn expect_string_literal(&mut self) -> Result<AstString, ParseError> {
1666 let token = self.bump().clone();
1667 match token.kind {
1668 TokenKind::String(value) => Ok(value),
1669 other => Err(ParseError::Expected {
1670 expected: "string literal",
1671 found: render_kind(&other),
1672 span: token.span,
1673 }),
1674 }
1675 }
1676
1677 fn expect_ident(&mut self) -> Result<AstString, ParseError> {
1678 let token = self.bump();
1679 match &token.kind {
1680 TokenKind::Ident(name) => Ok(name.clone()),
1681 other => Err(ParseError::Expected {
1682 expected: "identifier",
1683 found: render_kind(other),
1684 span: token.span,
1685 }),
1686 }
1687 }
1688
1689 fn parse_type_name(&mut self) -> Result<AstString, ParseError> {
1690 let mut path = vec![self.expect_ident()?];
1691 while matches!(self.peek_kind(), TokenKind::Dot) {
1692 self.bump();
1693 path.push(self.expect_ident()?);
1694 }
1695 Ok(path
1696 .iter()
1697 .map(AstString::as_str)
1698 .collect::<Vec<_>>()
1699 .join(".")
1700 .into())
1701 }
1702
1703 fn expect_key_name(&mut self) -> Result<AstString, ParseError> {
1704 let token = self.bump();
1705 match &token.kind {
1706 TokenKind::Ident(name) | TokenKind::String(name) => Ok(name.clone()),
1707 other => keyword_key_name(other)
1708 .map(Into::into)
1709 .ok_or_else(|| ParseError::Expected {
1710 expected: "identifier, string key, or keyword key",
1711 found: render_kind(other),
1712 span: token.span,
1713 }),
1714 }
1715 }
1716
1717 fn expect_exact(
1718 &mut self,
1719 expected_kind: TokenKind,
1720 expected: &'static str,
1721 ) -> Result<(), ParseError> {
1722 let token = self.bump();
1723 if std::mem::discriminant(&token.kind) == std::mem::discriminant(&expected_kind) {
1724 Ok(())
1725 } else {
1726 Err(ParseError::Expected {
1727 expected,
1728 found: render_kind(&token.kind),
1729 span: token.span,
1730 })
1731 }
1732 }
1733
1734 fn unexpected(&mut self) -> ParseError {
1735 let token = self.peek();
1736 ParseError::Unexpected {
1737 found: render_kind(&token.kind),
1738 span: token.span,
1739 }
1740 }
1741
1742 fn peek_assignment_target(&self) -> bool {
1743 if !matches!(self.peek_kind(), TokenKind::Ident(_)) {
1744 return false;
1745 }
1746
1747 let mut index = self.index + 1;
1748 loop {
1749 match self.tokens.get(index).map(|token| &token.kind) {
1750 Some(TokenKind::Dot) => {
1751 if !self
1752 .tokens
1753 .get(index + 1)
1754 .is_some_and(|token| token_can_be_key(&token.kind))
1755 {
1756 return false;
1757 }
1758 index += 2;
1759 }
1760 Some(TokenKind::LBracket) => {
1761 let Some(after_index) = self.skip_bracketed_index(index) else {
1762 return false;
1763 };
1764 index = after_index;
1765 }
1766 Some(TokenKind::Equal) => return true,
1767 _ => return false,
1768 }
1769 }
1770 }
1771
1772 fn skip_bracketed_index(&self, start: usize) -> Option<usize> {
1773 debug_assert!(matches!(
1774 self.tokens.get(start).map(|token| &token.kind),
1775 Some(TokenKind::LBracket)
1776 ));
1777 let mut parens = 0usize;
1778 let mut brackets = 1usize;
1779 let mut braces = 0usize;
1780 for (offset, token) in self.tokens.iter().enumerate().skip(start + 1) {
1781 match &token.kind {
1782 TokenKind::LParen => parens += 1,
1783 TokenKind::RParen => parens = parens.checked_sub(1)?,
1784 TokenKind::LBracket => brackets += 1,
1785 TokenKind::RBracket => {
1786 brackets = brackets.checked_sub(1)?;
1787 if brackets == 0 && parens == 0 && braces == 0 {
1788 return Some(offset + 1);
1789 }
1790 }
1791 TokenKind::LBrace => braces += 1,
1792 TokenKind::RBrace => braces = braces.checked_sub(1)?,
1793 TokenKind::Eof => return None,
1794 _ => {}
1795 }
1796 }
1797 None
1798 }
1799
1800 fn question_starts_ternary(&self) -> bool {
1801 debug_assert!(matches!(self.peek_kind(), TokenKind::Question));
1802 let Some(next) = self.tokens.get(self.index + 1) else {
1803 return false;
1804 };
1805 if !token_can_start_expr(&next.kind) {
1806 return false;
1807 }
1808
1809 let mut parens = 0usize;
1810 let mut brackets = 0usize;
1811 let mut braces = 0usize;
1812 for token in self.tokens.iter().skip(self.index + 1) {
1813 match &token.kind {
1814 TokenKind::Colon if parens == 0 && brackets == 0 && braces == 0 => return true,
1815 TokenKind::Equal if parens == 0 && brackets == 0 && braces == 0 => return false,
1816 TokenKind::Comma | TokenKind::RParen | TokenKind::RBracket | TokenKind::RBrace
1817 if parens == 0 && brackets == 0 && braces == 0 =>
1818 {
1819 return false;
1820 }
1821 TokenKind::Eof => return false,
1822 TokenKind::LParen => parens += 1,
1823 TokenKind::RParen => {
1824 if parens == 0 {
1825 return false;
1826 }
1827 parens -= 1;
1828 }
1829 TokenKind::LBracket => brackets += 1,
1830 TokenKind::RBracket => {
1831 if brackets == 0 {
1832 return false;
1833 }
1834 brackets -= 1;
1835 }
1836 TokenKind::LBrace => braces += 1,
1837 TokenKind::RBrace => {
1838 if braces == 0 {
1839 return false;
1840 }
1841 braces -= 1;
1842 }
1843 _ => {}
1844 }
1845 }
1846 false
1847 }
1848
1849 fn paren_group_followed_by_lbrace(&self) -> bool {
1850 if !matches!(self.peek_kind(), TokenKind::LParen) {
1851 return false;
1852 }
1853 let mut depth = 0usize;
1854 for (index, token) in self.tokens.iter().enumerate().skip(self.index) {
1855 match &token.kind {
1856 TokenKind::LParen => depth += 1,
1857 TokenKind::RParen => {
1858 depth = depth.saturating_sub(1);
1859 if depth == 0 {
1860 return self
1861 .tokens
1862 .get(index + 1)
1863 .is_some_and(|next| matches!(next.kind, TokenKind::LBrace));
1864 }
1865 }
1866 TokenKind::Eof => return false,
1867 _ => {}
1868 }
1869 }
1870 false
1871 }
1872
1873 fn peek_contextual(&self, keyword: &str) -> bool {
1874 matches!(self.peek_kind(), TokenKind::Ident(name) if name.as_str() == keyword)
1875 }
1876
1877 fn expect_contextual(&mut self, keyword: &'static str) -> Result<(), ParseError> {
1878 let token = self.bump();
1879 match &token.kind {
1880 TokenKind::Ident(name) if name.as_str() == keyword => Ok(()),
1881 other => Err(ParseError::Expected {
1882 expected: keyword,
1883 found: render_kind(other),
1884 span: token.span,
1885 }),
1886 }
1887 }
1888
1889 fn at_eof(&self) -> bool {
1890 matches!(self.peek_kind(), TokenKind::Eof)
1891 }
1892
1893 fn peek_kind(&self) -> &TokenKind {
1894 &self.tokens[self.index].kind
1895 }
1896
1897 fn peek(&self) -> &Token {
1898 &self.tokens[self.index]
1899 }
1900
1901 fn bump(&mut self) -> &Token {
1902 let token = &self.tokens[self.index];
1903 self.index += 1;
1904 token
1905 }
1906}
1907
1908fn static_signal_name_arg(expr: &Expr, call: &'static str) -> Result<AstString, ParseError> {
1909 if let Expr::String(name) = expr {
1910 return Ok(name.clone());
1911 }
1912 Err(ParseError::Unexpected {
1913 found: format!("non-literal signal name in `{call}`"),
1914 span: Span { start: 0, end: 0 },
1915 })
1916}
1917
1918fn token_can_be_key(kind: &TokenKind) -> bool {
1919 matches!(kind, TokenKind::Ident(_) | TokenKind::String(_)) || keyword_key_name(kind).is_some()
1920}
1921
1922fn keyword_key_name(kind: &TokenKind) -> Option<&'static str> {
1923 Some(match kind {
1924 TokenKind::If => "if",
1925 TokenKind::Else => "else",
1926 TokenKind::For => "for",
1927 TokenKind::In => "in",
1928 TokenKind::Await => "await",
1929 TokenKind::Cancel => "cancel",
1930 TokenKind::Submit => "submit",
1931 TokenKind::Print => "print",
1932 TokenKind::Call => "call",
1933 TokenKind::Ident(name) if matches!(name.as_str(), "yield" | "wake" | "finish" | "fail") => {
1934 return Some(match name.as_str() {
1935 "yield" => "yield",
1936 "wake" => "wake",
1937 "finish" => "finish",
1938 "fail" => "fail",
1939 _ => unreachable!(),
1940 });
1941 }
1942 TokenKind::And => "and",
1943 TokenKind::Or => "or",
1944 TokenKind::Not => "not",
1945 TokenKind::True => "true",
1946 TokenKind::False => "false",
1947 TokenKind::Null => "null",
1948 _ => return None,
1949 })
1950}
1951
1952fn token_can_start_expr(kind: &TokenKind) -> bool {
1953 matches!(
1954 kind,
1955 TokenKind::Null
1956 | TokenKind::True
1957 | TokenKind::False
1958 | TokenKind::Number(_)
1959 | TokenKind::String(_)
1960 | TokenKind::Ident(_)
1961 | TokenKind::LParen
1962 | TokenKind::LBracket
1963 | TokenKind::LBrace
1964 | TokenKind::Await
1965 | TokenKind::Minus
1966 | TokenKind::Bang
1967 | TokenKind::Not
1968 )
1969}
1970
1971fn render_kind(kind: &TokenKind) -> String {
1972 match kind {
1973 TokenKind::Ident(name) => format!("identifier `{name}`"),
1974 TokenKind::String(value) => format!("string {:?}", value),
1975 TokenKind::Number(value) => format!("number {value}"),
1976 TokenKind::LBrace => "`{`".to_string(),
1977 TokenKind::RBrace => "`}`".to_string(),
1978 TokenKind::LParen => "`(`".to_string(),
1979 TokenKind::RParen => "`)`".to_string(),
1980 TokenKind::LBracket => "`[`".to_string(),
1981 TokenKind::RBracket => "`]`".to_string(),
1982 TokenKind::Comma => "`,`".to_string(),
1983 TokenKind::Colon => "`:`".to_string(),
1984 TokenKind::At => "`@`".to_string(),
1985 TokenKind::Question => "`?`".to_string(),
1986 TokenKind::Dot => "`.`".to_string(),
1987 TokenKind::Bang => "`!`".to_string(),
1988 TokenKind::Equal => "`=`".to_string(),
1989 TokenKind::DoubleEqual => "`==`".to_string(),
1990 TokenKind::BangEqual => "`!=`".to_string(),
1991 TokenKind::AndAnd => "`&&`".to_string(),
1992 TokenKind::OrOr => "`||`".to_string(),
1993 TokenKind::Pipe => "`|`".to_string(),
1994 TokenKind::Less => "`<`".to_string(),
1995 TokenKind::LessEqual => "`<=`".to_string(),
1996 TokenKind::Greater => "`>`".to_string(),
1997 TokenKind::GreaterEqual => "`>=`".to_string(),
1998 TokenKind::Plus => "`+`".to_string(),
1999 TokenKind::Minus => "`-`".to_string(),
2000 TokenKind::Star => "`*`".to_string(),
2001 TokenKind::Slash => "`/`".to_string(),
2002 TokenKind::Percent => "`%`".to_string(),
2003 TokenKind::If => "`if`".to_string(),
2004 TokenKind::Else => "`else`".to_string(),
2005 TokenKind::For => "`for`".to_string(),
2006 TokenKind::In => "`in`".to_string(),
2007 TokenKind::Await => "`await`".to_string(),
2008 TokenKind::Cancel => "`cancel`".to_string(),
2009 TokenKind::Submit => "`submit`".to_string(),
2010 TokenKind::Print => "`print`".to_string(),
2011 TokenKind::Call => "`call`".to_string(),
2012 TokenKind::And => "`and`".to_string(),
2013 TokenKind::Or => "`or`".to_string(),
2014 TokenKind::Not => "`not`".to_string(),
2015 TokenKind::True => "`true`".to_string(),
2016 TokenKind::False => "`false`".to_string(),
2017 TokenKind::Null => "`null`".to_string(),
2018 TokenKind::Eof => "end of input".to_string(),
2019 }
2020}
2021
2022include!("parser/tests.rs");