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