1use crate::compiler::ast::*;
4use crate::compiler::tokens::{Span, Token, TokenKind};
5use thiserror::Error;
6
7#[derive(Debug, Error, Clone)]
8pub enum ParseError {
9 #[error("unexpected token {found} at line {line}, col {col}; expected {expected}")]
10 Unexpected {
11 found: String,
12 expected: String,
13 line: usize,
14 col: usize,
15 },
16 #[error("unexpected end of input")]
17 UnexpectedEof,
18 #[error("unclosed '{bracket}' opened at line {open_line}, col {open_col}")]
19 UnclosedBracket {
20 bracket: char,
21 open_line: usize,
22 open_col: usize,
23 current_line: usize,
24 current_col: usize,
25 },
26 #[error("expected 'end' to close '{construct}' at line {open_line}, col {open_col}")]
27 MissingEnd {
28 construct: String,
29 open_line: usize,
30 open_col: usize,
31 current_line: usize,
32 current_col: usize,
33 },
34 #[error("expected type after ':' at line {line}, col {col}")]
35 MissingType { line: usize, col: usize },
36 #[error("incomplete expression at line {line}, col {col}")]
37 IncompleteExpression {
38 line: usize,
39 col: usize,
40 context: String,
41 },
42 #[error("malformed {construct} at line {line}, col {col}: {reason}")]
43 MalformedConstruct {
44 construct: String,
45 reason: String,
46 line: usize,
47 col: usize,
48 },
49}
50
51pub struct Parser {
52 tokens: Vec<Token>,
53 pos: usize,
54 bracket_depth: usize,
55 errors: Vec<ParseError>,
56}
57
58impl Parser {
59 pub fn new(tokens: Vec<Token>) -> Self {
60 Self {
61 tokens,
62 pos: 0,
63 bracket_depth: 0,
64 errors: Vec::new(),
65 }
66 }
67
68 fn record_error(&mut self, error: ParseError) {
70 self.errors.push(error);
71 }
72
73 pub fn errors(&self) -> &[ParseError] {
74 &self.errors
75 }
76
77 fn synchronize(&mut self) {
80 let _start_pos = self.pos;
84 let mut last_pos = self.pos;
85 let mut iterations = 0;
86 const MAX_ITERATIONS: usize = 10000; while !self.at_end() && iterations < MAX_ITERATIONS {
89 if self.pos == last_pos && iterations > 0 {
91 self.advance();
93 }
94 last_pos = self.pos;
95 iterations += 1;
96
97 match self.peek_kind() {
98 TokenKind::Cell
99 | TokenKind::Record
100 | TokenKind::Enum
101 | TokenKind::Type
102 | TokenKind::Grant
103 | TokenKind::Import
104 | TokenKind::Use
105 | TokenKind::Pub
106 | TokenKind::Async
107 | TokenKind::At
108 | TokenKind::Schema
109 | TokenKind::Trait
110 | TokenKind::Impl
111 | TokenKind::Const
112 | TokenKind::Macro
113 | TokenKind::Extern
114 | TokenKind::Comptime
115 | TokenKind::Eof => break,
116 TokenKind::Ident(name) => {
117 if matches!(
118 name.as_str(),
119 "agent"
120 | "effect"
121 | "bind"
122 | "handler"
123 | "pipeline"
124 | "orchestration"
125 | "machine"
126 | "memory"
127 | "guardrail"
128 | "eval"
129 | "pattern"
130 ) {
131 break;
132 }
133 self.advance();
134 }
135 _ => {
136 self.advance();
137 }
138 }
139 }
140 }
141 fn synchronize_stmt(&mut self) {
144 let mut last_pos = self.pos;
145 let mut iterations = 0;
146 const MAX_ITERATIONS: usize = 10000;
147
148 while !self.at_end() && iterations < MAX_ITERATIONS {
149 if self.pos == last_pos && iterations > 0 {
151 self.advance();
152 }
153 last_pos = self.pos;
154 iterations += 1;
155
156 match self.peek_kind() {
157 TokenKind::Newline => {
158 self.advance();
159 if self.is_stmt_keyword() {
161 break;
162 }
163 }
164 TokenKind::End | TokenKind::Else | TokenKind::Dedent | TokenKind::Eof => break,
165 TokenKind::Let
167 | TokenKind::If
168 | TokenKind::For
169 | TokenKind::While
170 | TokenKind::Loop
171 | TokenKind::Match
172 | TokenKind::Return
173 | TokenKind::Halt
174 | TokenKind::Break
175 | TokenKind::Continue
176 | TokenKind::Emit => break,
177 TokenKind::Cell
179 | TokenKind::Record
180 | TokenKind::Enum
181 | TokenKind::Type
182 | TokenKind::Grant
183 | TokenKind::Import
184 | TokenKind::Use
185 | TokenKind::Pub
186 | TokenKind::Schema
187 | TokenKind::Fn
188 | TokenKind::Mod
189 | TokenKind::Trait
190 | TokenKind::Impl => break,
191 _ => {
192 self.advance();
193 }
194 }
195 }
196 }
197
198 fn is_stmt_keyword(&self) -> bool {
200 matches!(
201 self.peek_kind(),
202 TokenKind::Let
203 | TokenKind::If
204 | TokenKind::For
205 | TokenKind::While
206 | TokenKind::Loop
207 | TokenKind::Match
208 | TokenKind::Return
209 | TokenKind::Halt
210 | TokenKind::Break
211 | TokenKind::Continue
212 | TokenKind::Emit
213 )
214 }
215
216 fn current(&self) -> &Token {
217 self.tokens
218 .get(self.pos)
219 .unwrap_or_else(|| self.tokens.last().unwrap())
220 }
221
222 fn peek_kind(&self) -> &TokenKind {
223 &self.current().kind
224 }
225
226 fn advance(&mut self) -> &Token {
227 let tok = &self.tokens[self.pos.min(self.tokens.len() - 1)];
228 if self.pos < self.tokens.len() {
229 self.pos += 1;
230 }
231 tok
232 }
233
234 fn expect(&mut self, kind: &TokenKind) -> Result<Token, ParseError> {
235 let tok = self.current().clone();
236 if std::mem::discriminant(&tok.kind) == std::mem::discriminant(kind) {
237 self.advance();
238 Ok(tok)
239 } else {
240 Err(ParseError::Unexpected {
241 found: format!("{}", tok.kind),
242 expected: format!("{}", kind),
243 line: tok.span.line,
244 col: tok.span.col,
245 })
246 }
247 }
248
249 fn skip_newlines(&mut self) {
250 if self.bracket_depth > 0 {
251 self.skip_whitespace_tokens();
252 } else {
253 while matches!(self.peek_kind(), TokenKind::Newline) {
254 self.advance();
255 }
256 }
257 }
258
259 fn skip_whitespace_tokens(&mut self) {
261 while matches!(
262 self.peek_kind(),
263 TokenKind::Newline | TokenKind::Indent | TokenKind::Dedent
264 ) {
265 self.advance();
266 }
267 }
268
269 fn at_end(&self) -> bool {
270 matches!(self.peek_kind(), TokenKind::Eof)
271 }
272
273 fn peek_n_kind(&self, n: usize) -> Option<&TokenKind> {
274 self.tokens.get(self.pos + n).map(|t| &t.kind)
275 }
276
277 fn looks_like_named_field(&self) -> bool {
279 matches!(self.peek_kind(), TokenKind::Ident(_))
280 && matches!(self.peek_n_kind(1), Some(TokenKind::Colon))
281 }
282
283 fn token_can_be_named_arg_key(&self) -> bool {
284 matches!(
285 self.peek_kind(),
286 TokenKind::Ident(_)
287 | TokenKind::Role
288 | TokenKind::Schema
289 | TokenKind::Tool
290 | TokenKind::Type
291 | TokenKind::From
292 | TokenKind::With
293 | TokenKind::Result
294 | TokenKind::List
295 | TokenKind::Map
296 | TokenKind::Set
297 | TokenKind::Tuple
298 )
299 }
300
301 fn is_identifier_like(kind: &TokenKind) -> bool {
302 matches!(
303 kind,
304 TokenKind::Ident(_)
305 | TokenKind::SelfKw
306 | TokenKind::Result
307 | TokenKind::Cell
308 | TokenKind::String_
309 | TokenKind::Int_
310 | TokenKind::Float_
311 | TokenKind::Bool
312 | TokenKind::Bytes
313 | TokenKind::Json
314 | TokenKind::Type
315 | TokenKind::List
316 | TokenKind::Map
317 | TokenKind::Set
318 | TokenKind::Tuple
319 | TokenKind::Schema
320 | TokenKind::Ok_
321 | TokenKind::Err_
322 | TokenKind::Tool
323 | TokenKind::Role
324 | TokenKind::Union
325 | TokenKind::From
326 | TokenKind::With
327 | TokenKind::Where
328 | TokenKind::When
329 | TokenKind::Try
330 | TokenKind::Step
331 | TokenKind::Comptime
332 | TokenKind::Macro
333 | TokenKind::Extern
334 | TokenKind::Async
335 | TokenKind::Loop
336 | TokenKind::If
337 | TokenKind::Match
338 | TokenKind::End
339 )
340 }
341
342 fn consumes_section_colon_block(&self) -> bool {
343 let mut i = self.pos;
344 if !matches!(
345 self.tokens.get(i).map(|t| &t.kind),
346 Some(TokenKind::Ident(_))
347 | Some(TokenKind::Role)
348 | Some(TokenKind::Tool)
349 | Some(TokenKind::With)
350 | Some(TokenKind::From)
351 | Some(TokenKind::Type)
352 | Some(TokenKind::Result)
353 | Some(TokenKind::List)
354 | Some(TokenKind::Map)
355 | Some(TokenKind::Set)
356 | Some(TokenKind::Tuple)
357 ) {
358 return false;
359 }
360 i += 1;
361
362 if matches!(self.tokens.get(i).map(|t| &t.kind), Some(TokenKind::LParen)) {
363 let mut depth = 0usize;
364 while let Some(kind) = self.tokens.get(i).map(|t| &t.kind) {
365 match kind {
366 TokenKind::LParen => depth += 1,
367 TokenKind::RParen => {
368 depth -= 1;
369 if depth == 0 {
370 i += 1;
371 break;
372 }
373 }
374 TokenKind::Eof => return false,
375 _ => {}
376 }
377 i += 1;
378 }
379 }
380
381 if !matches!(self.tokens.get(i).map(|t| &t.kind), Some(TokenKind::Colon)) {
382 return false;
383 }
384 i += 1;
385 while matches!(
386 self.tokens.get(i).map(|t| &t.kind),
387 Some(TokenKind::Newline)
388 ) {
389 i += 1;
390 }
391 matches!(self.tokens.get(i).map(|t| &t.kind), Some(TokenKind::Indent))
392 }
393
394 pub fn parse_program(&mut self, directives: Vec<Directive>) -> Result<Program, ParseError> {
397 let span_start = self.current().span;
398 let mut items = Vec::new();
399 let mut top_level_stmts = Vec::new();
400 self.skip_newlines();
401 while !self.at_end() {
402 self.skip_newlines();
403 if self.at_end() {
404 break;
405 }
406 if matches!(self.peek_kind(), TokenKind::Indent | TokenKind::Dedent) {
407 self.advance();
408 continue;
409 }
410 if matches!(self.peek_kind(), TokenKind::End) {
411 self.advance();
412 continue;
413 }
414 if self.is_top_level_stmt_start() {
415 match self.parse_stmt() {
416 Ok(stmt) => top_level_stmts.push(stmt),
417 Err(err) => {
418 self.record_error(err);
419 self.synchronize();
420 }
421 }
422 } else {
423 match self.parse_item() {
424 Ok(item) => items.push(item),
425 Err(err) => {
426 self.record_error(err);
427 self.synchronize();
428 }
429 }
430 }
431 self.skip_newlines();
432 }
433 if !top_level_stmts.is_empty() {
434 let has_main = items
435 .iter()
436 .any(|item| matches!(item, Item::Cell(c) if c.name == "main"));
437 let synthetic_name = if has_main {
438 "__script_main".to_string()
439 } else {
440 "main".to_string()
441 };
442 let end_span = top_level_stmts
443 .last()
444 .map(|s| s.span())
445 .unwrap_or(span_start);
446 items.push(Item::Cell(CellDef {
447 name: synthetic_name,
448 generic_params: vec![],
449 params: vec![],
450 return_type: None,
451 effects: vec![],
452 body: top_level_stmts,
453 is_pub: false,
454 is_async: false,
455 where_clauses: vec![],
456 span: span_start.merge(end_span),
457 }));
458 }
459 let span = if items.is_empty() {
460 span_start
461 } else {
462 span_start.merge(items.last().unwrap().span())
463 };
464 Ok(Program {
465 directives,
466 items,
467 span,
468 })
469 }
470
471 fn is_top_level_stmt_start(&self) -> bool {
472 match self.peek_kind() {
473 TokenKind::Let
474 | TokenKind::If
475 | TokenKind::For
476 | TokenKind::Match
477 | TokenKind::Return
478 | TokenKind::Halt
479 | TokenKind::While
480 | TokenKind::Loop
481 | TokenKind::Break
482 | TokenKind::Continue
483 | TokenKind::Emit
484 | TokenKind::Role
485 | TokenKind::LParen
486 | TokenKind::LBracket
487 | TokenKind::LBrace
488 | TokenKind::IntLit(_)
489 | TokenKind::FloatLit(_)
490 | TokenKind::StringLit(_)
491 | TokenKind::StringInterpLit(_)
492 | TokenKind::RawStringLit(_)
493 | TokenKind::BytesLit(_)
494 | TokenKind::BoolLit(_)
495 | TokenKind::Null
496 | TokenKind::NullLit
497 | TokenKind::Minus
498 | TokenKind::Not
499 | TokenKind::Tilde
500 | TokenKind::Fn
501 | TokenKind::With
502 | TokenKind::SelfKw => true,
503 TokenKind::Ident(name) => !matches!(
504 name.as_str(),
505 "agent"
506 | "effect"
507 | "bind"
508 | "handler"
509 | "pipeline"
510 | "orchestration"
511 | "machine"
512 | "memory"
513 | "guardrail"
514 | "eval"
515 | "pattern"
516 ),
517 _ => false,
518 }
519 }
520
521 fn parse_item(&mut self) -> Result<Item, ParseError> {
522 let is_pub = matches!(self.peek_kind(), TokenKind::Pub);
524 if is_pub {
525 self.advance();
526 self.skip_newlines();
527 }
528
529 let is_async = matches!(self.peek_kind(), TokenKind::Async);
531 if is_async {
532 self.advance();
533 self.skip_newlines();
534 }
535
536 match self.peek_kind() {
537 TokenKind::Record => {
538 let mut r = self.parse_record()?;
539 r.is_pub = is_pub;
540 Ok(Item::Record(r))
541 }
542 TokenKind::Enum => {
543 let mut e = self.parse_enum()?;
544 e.is_pub = is_pub;
545 Ok(Item::Enum(e))
546 }
547 TokenKind::Cell => {
548 let mut c = self.parse_cell(true)?;
549 c.is_pub = is_pub;
550 c.is_async = is_async;
551 Ok(Item::Cell(c))
552 }
553 TokenKind::At => Ok(Item::Addon(self.parse_attribute_decl()?)),
554 TokenKind::Use => Ok(Item::UseTool(self.parse_use_tool()?)),
555 TokenKind::Grant => Ok(Item::Grant(self.parse_grant()?)),
556 TokenKind::Type => Ok(Item::TypeAlias(self.parse_type_alias(is_pub)?)),
557 TokenKind::Trait => Ok(Item::Trait(self.parse_trait_def(is_pub)?)),
558 TokenKind::Impl => Ok(Item::Impl(self.parse_impl_def()?)),
559 TokenKind::Import => Ok(Item::Import(self.parse_import(is_pub)?)),
560 TokenKind::Const => Ok(Item::ConstDecl(self.parse_const_decl()?)),
561 TokenKind::Macro => Ok(Item::MacroDecl(self.parse_macro_decl()?)),
562 TokenKind::Schema => {
563 let start = self.current().span;
564 self.advance();
565 self.consume_block_until_end();
566 Ok(Item::Addon(AddonDecl {
567 kind: "schema".into(),
568 name: None,
569 span: start.merge(self.current().span),
570 }))
571 }
572 TokenKind::Extern | TokenKind::Comptime => {
573 let start = self.current().span;
574 let kind = format!("{}", self.peek_kind());
575 self.advance();
576 self.consume_rest_of_line();
577 Ok(Item::Addon(AddonDecl {
578 kind,
579 name: None,
580 span: start.merge(self.current().span),
581 }))
582 }
583 TokenKind::Ident(name) => match name.as_str() {
584 "agent" => Ok(Item::Agent(self.parse_agent_decl()?)),
585 "effect" => Ok(Item::Effect(self.parse_effect_decl()?)),
586 "handler" => Ok(Item::Handler(self.parse_handler_decl()?)),
587 "bind" => {
588 if matches!(self.peek_n_kind(1), Some(TokenKind::Ident(s)) if s == "effect") {
589 Ok(Item::EffectBind(self.parse_effect_bind_decl()?))
590 } else {
591 Ok(Item::Addon(self.parse_addon_decl()?))
592 }
593 }
594 "pipeline" | "orchestration" | "machine" | "memory" | "guardrail" | "eval"
595 | "pattern" => Ok(Item::Process(self.parse_process_decl()?)),
596 _ => {
597 eprintln!("DEBUG: Ident fallback for {}", name);
598 let tok = self.current().clone();
599 Err(ParseError::Unexpected {
600 found: name.clone(),
601 expected: "top-level declaration".into(),
602 line: tok.span.line,
603 col: tok.span.col,
604 })
605 }
606 },
607 _ => {
608 let kind = format!("{}", self.peek_kind());
609 eprintln!("DEBUG: General fallback for {}", kind);
610 let tok = self.current().clone();
611 Err(ParseError::Unexpected {
612 found: kind,
613 expected: "top-level declaration".into(),
614 line: tok.span.line,
615 col: tok.span.col,
616 })
617 }
618 }
619 }
620
621 fn parse_record(&mut self) -> Result<RecordDef, ParseError> {
624 let start = self.expect(&TokenKind::Record)?.span;
625 let name = self.expect_ident()?;
626 let generic_params = self.parse_optional_generic_params()?;
627 self.skip_newlines();
628 let mut fields = Vec::new();
629 let has_indent = matches!(self.peek_kind(), TokenKind::Indent);
631 if has_indent {
632 self.advance();
633 }
634 self.skip_newlines();
635 while !matches!(self.peek_kind(), TokenKind::End | TokenKind::Eof) {
636 self.skip_newlines();
637 if matches!(self.peek_kind(), TokenKind::End | TokenKind::Eof) {
638 break;
639 }
640 if matches!(self.peek_kind(), TokenKind::Indent | TokenKind::Dedent) {
641 self.advance();
642 continue;
643 }
644 if matches!(self.peek_kind(), TokenKind::At) {
645 let _ = self.parse_attribute_decl()?;
646 } else if self.looks_like_named_field() {
647 fields.push(self.parse_field()?);
648 } else if matches!(self.peek_kind(), TokenKind::Ident(s) if s == "migrate") {
649 self.advance();
650 self.consume_block_until_end();
651 } else {
652 self.consume_rest_of_line();
653 }
654 self.skip_newlines();
655 }
656 if has_indent && matches!(self.peek_kind(), TokenKind::Dedent) {
657 self.advance();
658 }
659 while matches!(
660 self.peek_kind(),
661 TokenKind::Newline | TokenKind::Indent | TokenKind::Dedent
662 ) {
663 self.advance();
664 }
665 let end_span = self.expect(&TokenKind::End)?.span;
666 Ok(RecordDef {
667 name,
668 generic_params,
669 fields,
670 is_pub: false,
671 span: start.merge(end_span),
672 })
673 }
674
675 fn parse_field(&mut self) -> Result<FieldDef, ParseError> {
676 let start = self.current().span;
677 let name = self.expect_ident()?;
678 self.expect(&TokenKind::Colon)?;
679 let ty = self.parse_type()?;
680 let default_value = if matches!(self.peek_kind(), TokenKind::Assign) {
681 self.advance();
682 Some(self.parse_expr(0)?)
683 } else {
684 None
685 };
686 let constraint = if matches!(self.peek_kind(), TokenKind::Where) {
687 self.advance();
688 Some(self.parse_expr(0)?)
689 } else {
690 None
691 };
692 let span = start.merge(
693 constraint
694 .as_ref()
695 .map(|c| c.span())
696 .or(default_value.as_ref().map(|d| d.span()))
697 .unwrap_or(ty.span()),
698 );
699 Ok(FieldDef {
700 name,
701 ty,
702 default_value,
703 constraint,
704 span,
705 })
706 }
707
708 fn parse_enum(&mut self) -> Result<EnumDef, ParseError> {
711 let start = self.expect(&TokenKind::Enum)?.span;
712 let name = self.expect_ident()?;
713 let generic_params = self.parse_optional_generic_params()?;
714 self.skip_newlines();
715 let mut variants = Vec::new();
716 let mut methods = Vec::new();
717 let has_indent = matches!(self.peek_kind(), TokenKind::Indent);
718 if has_indent {
719 self.advance();
720 }
721 self.skip_newlines();
722 while !matches!(self.peek_kind(), TokenKind::End | TokenKind::Eof) {
723 self.skip_newlines();
724 if matches!(self.peek_kind(), TokenKind::Dedent) {
725 let mut i = self.pos;
726 while matches!(
727 self.tokens.get(i).map(|t| &t.kind),
728 Some(TokenKind::Dedent | TokenKind::Newline)
729 ) {
730 i += 1;
731 }
732 let mut j = i;
733 let mut saw_arrow = false;
734 while let Some(tok) = self.tokens.get(j) {
735 match tok.kind {
736 TokenKind::Arrow => {
737 saw_arrow = true;
738 break;
739 }
740 TokenKind::Newline
741 | TokenKind::Eof
742 | TokenKind::End
743 | TokenKind::Dedent => break,
744 _ => j += 1,
745 }
746 }
747 if saw_arrow {
748 while matches!(self.peek_kind(), TokenKind::Dedent | TokenKind::Newline) {
749 self.advance();
750 }
751 continue;
752 }
753 break;
754 }
755 if matches!(self.peek_kind(), TokenKind::End | TokenKind::Eof) {
756 break;
757 }
758 if matches!(self.peek_kind(), TokenKind::Cell) {
759 methods.push(self.parse_cell(true)?);
760 self.skip_newlines();
761 continue;
762 }
763 let vs = self.current().span;
764 let vname = self.expect_ident()?;
765 let payload = if matches!(self.peek_kind(), TokenKind::LParen) {
766 self.advance();
767 if matches!(self.peek_kind(), TokenKind::RParen) {
768 self.advance();
769 None
770 } else {
771 let start_span = self.current().span;
772 let mut types = Vec::new();
773
774 loop {
775 let is_named_field = self
779 .tokens
780 .get(self.pos + 1)
781 .is_some_and(|tok| matches!(tok.kind, TokenKind::Colon));
782
783 if is_named_field {
784 self.advance();
786 self.advance();
787 match self.parse_type() {
788 Ok(ty) => types.push(ty),
789 Err(_) => {
790 self.consume_variant_arg_tokens();
791 }
792 }
793 } else {
794 match self.parse_type() {
795 Ok(ty) => types.push(ty),
796 Err(_) => {
797 types.push(TypeExpr::Named("Any".into(), start_span));
798 }
799 }
800 }
801
802 if matches!(self.peek_kind(), TokenKind::Comma) {
803 self.advance();
804 } else {
805 break;
806 }
807 }
808
809 if matches!(self.peek_kind(), TokenKind::RParen) {
810 self.advance();
811 }
812
813 if types.is_empty() {
814 None
815 } else if types.len() == 1 {
816 Some(types.remove(0))
817 } else {
818 Some(TypeExpr::Tuple(types, start_span))
819 }
820 }
821 } else {
822 None
823 };
824 variants.push(EnumVariant {
825 name: vname,
826 payload,
827 span: vs,
828 });
829 self.skip_newlines();
830 }
831 if has_indent && matches!(self.peek_kind(), TokenKind::Dedent) {
832 self.advance();
833 }
834 self.skip_newlines();
835 let end_span = self.expect(&TokenKind::End)?.span;
836 Ok(EnumDef {
837 name,
838 generic_params,
839 variants,
840 methods,
841 is_pub: false,
842 span: start.merge(end_span),
843 })
844 }
845
846 fn parse_cell(&mut self, require_body: bool) -> Result<CellDef, ParseError> {
849 let start = self.expect(&TokenKind::Cell)?.span;
850 let name = self.expect_ident()?;
851 let generic_params = self.parse_optional_generic_params()?;
852 self.expect(&TokenKind::LParen)?;
853 self.bracket_depth += 1;
854 let mut params = Vec::new();
855 self.skip_whitespace_tokens();
856 while !matches!(self.peek_kind(), TokenKind::RParen) {
857 if !params.is_empty() {
858 self.expect(&TokenKind::Comma)?;
859 self.skip_whitespace_tokens();
860 }
861 let variadic = if matches!(self.peek_kind(), TokenKind::DotDot | TokenKind::DotDotDot) {
862 self.advance();
863 true
864 } else {
865 false
866 };
867 let ps = self.current().span;
868 let pname = self.expect_ident()?;
869 let pty = if matches!(self.peek_kind(), TokenKind::Colon) {
870 self.advance();
871 self.parse_type()?
872 } else {
873 TypeExpr::Named("Any".into(), ps)
874 };
875 let default_value = if matches!(self.peek_kind(), TokenKind::Assign) {
876 self.advance();
877 Some(self.parse_expr(0)?)
878 } else {
879 None
880 };
881 params.push(Param {
882 name: pname,
883 ty: pty,
884 default_value,
885 variadic,
886 span: ps,
887 });
888 self.skip_whitespace_tokens();
889 }
890 self.bracket_depth -= 1;
891 self.expect(&TokenKind::RParen)?;
892 let ret = if matches!(self.peek_kind(), TokenKind::Arrow) {
893 self.advance();
894 Some(self.parse_type()?)
895 } else {
896 None
897 };
898 let effects = self.parse_optional_effect_row()?;
899
900 if matches!(self.peek_kind(), TokenKind::Assign) {
901 self.advance();
902 let expr = self.parse_expr(0)?;
903 let span = start.merge(expr.span());
904 return Ok(CellDef {
905 name,
906 generic_params,
907 params,
908 return_type: ret,
909 effects,
910 body: vec![Stmt::Return(ReturnStmt { value: expr, span })],
911 is_pub: false,
912 is_async: false,
913 where_clauses: vec![],
914 span,
915 });
916 }
917
918 if !require_body
921 && matches!(
922 self.peek_kind(),
923 TokenKind::Newline | TokenKind::Eof | TokenKind::Dedent
924 )
925 {
926 let mut look = self.pos;
927 while matches!(
928 self.tokens.get(look).map(|t| &t.kind),
929 Some(TokenKind::Newline)
930 ) {
931 look += 1;
932 }
933 if !matches!(
934 self.tokens.get(look).map(|t| &t.kind),
935 Some(TokenKind::Indent)
936 ) {
937 let end_span = self.current().span;
938 return Ok(CellDef {
939 name,
940 generic_params,
941 params,
942 return_type: ret,
943 effects,
944 body: vec![],
945 is_pub: false,
946 is_async: false,
947 where_clauses: vec![],
948 span: start.merge(end_span),
949 });
950 }
951 }
952
953 self.skip_newlines();
954 let body = self.parse_block()?;
955 let end_span = self.expect(&TokenKind::End)?.span;
956 Ok(CellDef {
957 name,
958 generic_params,
959 params,
960 return_type: ret,
961 effects,
962 body,
963 is_pub: false,
964 is_async: false,
965 where_clauses: vec![],
966 span: start.merge(end_span),
967 })
968 }
969
970 fn parse_block(&mut self) -> Result<Vec<Stmt>, ParseError> {
971 let mut stmts = Vec::new();
972 let has_indent = matches!(self.peek_kind(), TokenKind::Indent);
973 if has_indent {
974 self.advance();
975 }
976 self.skip_newlines();
977 while !matches!(
978 self.peek_kind(),
979 TokenKind::End
980 | TokenKind::Eof
981 | TokenKind::Else
982 | TokenKind::Cell
983 | TokenKind::Record
984 | TokenKind::Enum
985 | TokenKind::Type
986 | TokenKind::Grant
987 | TokenKind::Import
988 | TokenKind::Use
989 | TokenKind::Pub
990 | TokenKind::Schema
991 | TokenKind::Fn
992 | TokenKind::Mod
993 | TokenKind::Trait
994 | TokenKind::Impl
995 ) {
996 self.skip_newlines();
997 if matches!(
998 self.peek_kind(),
999 TokenKind::End
1000 | TokenKind::Eof
1001 | TokenKind::Else
1002 | TokenKind::Cell
1003 | TokenKind::Record
1004 | TokenKind::Enum
1005 | TokenKind::Type
1006 | TokenKind::Grant
1007 | TokenKind::Import
1008 | TokenKind::Use
1009 | TokenKind::Pub
1010 | TokenKind::Schema
1011 | TokenKind::Fn
1012 | TokenKind::Mod
1013 | TokenKind::Trait
1014 | TokenKind::Impl
1015 ) {
1016 break;
1017 }
1018 if matches!(self.peek_kind(), TokenKind::Dedent) {
1019 let mut i = self.pos;
1020 while matches!(
1021 self.tokens.get(i).map(|t| &t.kind),
1022 Some(TokenKind::Dedent | TokenKind::Newline)
1023 ) {
1024 i += 1;
1025 }
1026 if matches!(
1027 self.tokens.get(i).map(|t| &t.kind),
1028 Some(
1029 TokenKind::End
1030 | TokenKind::Else
1031 | TokenKind::Eof
1032 | TokenKind::Cell
1033 | TokenKind::Record
1034 | TokenKind::Enum
1035 | TokenKind::Type
1036 | TokenKind::Grant
1037 | TokenKind::Import
1038 | TokenKind::Use
1039 | TokenKind::Pub
1040 | TokenKind::Schema
1041 | TokenKind::Fn
1042 | TokenKind::Mod
1043 | TokenKind::Trait
1044 | TokenKind::Impl
1045 )
1046 ) {
1047 break;
1048 }
1049 self.advance();
1050 continue;
1051 }
1052 match self.parse_stmt() {
1053 Ok(stmt) => stmts.push(stmt),
1054 Err(err) => {
1055 self.record_error(err);
1056 self.synchronize_stmt();
1057 }
1058 }
1059 self.skip_newlines();
1060 }
1061 if has_indent && matches!(self.peek_kind(), TokenKind::Dedent) {
1062 self.advance();
1063 }
1064 while matches!(self.peek_kind(), TokenKind::Dedent) {
1065 let mut i = self.pos + 1;
1066 while matches!(
1067 self.tokens.get(i).map(|t| &t.kind),
1068 Some(TokenKind::Newline | TokenKind::Dedent)
1069 ) {
1070 i += 1;
1071 }
1072 if matches!(
1073 self.tokens.get(i).map(|t| &t.kind),
1074 Some(
1075 TokenKind::End
1076 | TokenKind::Else
1077 | TokenKind::Eof
1078 | TokenKind::Cell
1079 | TokenKind::Record
1080 | TokenKind::Enum
1081 | TokenKind::Type
1082 | TokenKind::Grant
1083 | TokenKind::Import
1084 | TokenKind::Use
1085 | TokenKind::Pub
1086 | TokenKind::Schema
1087 | TokenKind::Fn
1088 | TokenKind::Mod
1089 | TokenKind::Trait
1090 | TokenKind::Impl
1091 )
1092 ) {
1093 self.advance();
1094 } else {
1095 break;
1096 }
1097 }
1098 self.skip_newlines();
1099 Ok(stmts)
1100 }
1101
1102 fn parse_block_strict_dedent(&mut self) -> Result<Vec<Stmt>, ParseError> {
1103 let mut stmts = Vec::new();
1104 if matches!(self.peek_kind(), TokenKind::Indent) {
1105 self.advance();
1106 }
1107 self.skip_newlines();
1108 while !matches!(self.peek_kind(), TokenKind::Dedent | TokenKind::Eof) {
1109 self.skip_newlines();
1110 if matches!(self.peek_kind(), TokenKind::Dedent | TokenKind::Eof) {
1111 break;
1112 }
1113 stmts.push(self.parse_stmt()?);
1114 self.skip_newlines();
1115 }
1116 if matches!(self.peek_kind(), TokenKind::Dedent) {
1117 self.advance();
1118 }
1119 Ok(stmts)
1120 }
1121
1122 fn parse_stmt(&mut self) -> Result<Stmt, ParseError> {
1125 match self.peek_kind() {
1126 TokenKind::Let => self.parse_let(),
1127 TokenKind::If => self.parse_if(),
1128 TokenKind::For => self.parse_for(),
1129 TokenKind::Match => self.parse_match(),
1130 TokenKind::Return => self.parse_return(),
1131 TokenKind::Halt => self.parse_halt(),
1132 TokenKind::While => self.parse_while(),
1133 TokenKind::Loop => self.parse_loop(),
1134 TokenKind::Break => self.parse_break(),
1135 TokenKind::Continue => self.parse_continue(),
1136 TokenKind::Emit => self.parse_emit(),
1137 TokenKind::Defer => self.parse_defer(),
1138 TokenKind::Where => {
1139 let s = self.current().span;
1140 self.advance();
1141 self.consume_rest_of_line();
1142 Ok(Stmt::Emit(EmitStmt {
1143 value: Expr::StringLit("where".into(), s),
1144 span: s,
1145 }))
1146 }
1147 TokenKind::At => {
1148 let save = self.pos;
1149 self.advance();
1150 if matches!(self.peek_kind(), TokenKind::Ident(_)) {
1151 self.advance();
1152 }
1153 if matches!(
1154 self.peek_kind(),
1155 TokenKind::For | TokenKind::While | TokenKind::Loop
1156 ) {
1157 return self.parse_stmt();
1158 }
1159 self.pos = save;
1160 let start = self.current().span;
1161 let decl = self.parse_attribute_decl()?;
1162 let label = decl.name.unwrap_or_else(|| "attribute".to_string());
1163 let value = Expr::StringLit(label, start);
1164 let span = start.merge(value.span());
1165 Ok(Stmt::Emit(EmitStmt { value, span }))
1166 }
1167 TokenKind::With => self.parse_addon_stmt(),
1168 TokenKind::Ident(_)
1169 | TokenKind::SelfKw
1170 | TokenKind::Result
1171 | TokenKind::Cell
1172 | TokenKind::String_
1173 | TokenKind::Int_
1174 | TokenKind::Float_
1175 | TokenKind::Bool
1176 | TokenKind::Bytes
1177 | TokenKind::Json
1178 | TokenKind::Type
1179 | TokenKind::List
1180 | TokenKind::Map
1181 | TokenKind::Set
1182 | TokenKind::Tuple
1183 | TokenKind::Schema
1184 | TokenKind::Ok_
1185 | TokenKind::Err_
1186 | TokenKind::Tool
1187 | TokenKind::Union
1188 | TokenKind::From
1189 | TokenKind::When
1190 | TokenKind::Try
1191 | TokenKind::Step
1192 | TokenKind::Comptime
1193 | TokenKind::Macro
1194 | TokenKind::Extern
1195 | TokenKind::Async
1196 | TokenKind::End => {
1197 if self.is_addon_stmt_keyword() {
1198 return self.parse_addon_stmt();
1199 }
1200 if self.is_compound_assignment() {
1202 self.parse_compound_assign()
1203 } else if self.is_assignment() {
1204 self.parse_assign()
1205 } else {
1206 self.parse_expr_stmt()
1207 }
1208 }
1209 TokenKind::Role => {
1210 let expr = self.parse_role_block_stmt()?;
1211 Ok(Stmt::Expr(ExprStmt {
1212 expr: expr.clone(),
1213 span: expr.span(),
1214 }))
1215 }
1216 _ => self.parse_expr_stmt(),
1217 }
1218 }
1219
1220 fn is_addon_stmt_keyword(&self) -> bool {
1221 matches!(
1222 self.peek_kind(),
1223 TokenKind::Ident(name)
1224 if matches!(name.as_str(), "approve" | "checkpoint" | "escalate" | "observe" | "with" | "with_tool")
1225 )
1226 }
1227
1228 fn parse_addon_stmt(&mut self) -> Result<Stmt, ParseError> {
1229 let start = self.current().span;
1230 let kind = match self.peek_kind().clone() {
1231 TokenKind::Ident(_) => self.expect_ident()?,
1232 TokenKind::With => {
1233 self.advance();
1234 "with".to_string()
1235 }
1236 _ => {
1237 let tok = self.current().clone();
1238 return Err(ParseError::Unexpected {
1239 found: format!("{}", tok.kind),
1240 expected: "addon statement".into(),
1241 line: tok.span.line,
1242 col: tok.span.col,
1243 });
1244 }
1245 };
1246 self.consume_rest_of_line();
1247
1248 if matches!(self.peek_kind(), TokenKind::Newline) {
1251 self.skip_newlines();
1252 if matches!(self.peek_kind(), TokenKind::Indent) {
1253 self.consume_indented_payload();
1254 self.skip_newlines();
1255 if matches!(self.peek_kind(), TokenKind::End) {
1256 self.advance();
1257 }
1258 } else if matches!(self.peek_kind(), TokenKind::In) {
1259 self.consume_block_until_end();
1260 }
1261 }
1262
1263 let mut in_block_end = None;
1264 let mut in_block = None;
1265 self.skip_newlines();
1266 if matches!(self.peek_kind(), TokenKind::In) {
1267 self.advance();
1268 self.skip_newlines();
1269 let body = self.parse_block()?;
1270 let end = self.expect(&TokenKind::End)?.span;
1271 in_block_end = Some(end);
1272 in_block = Some(body);
1273 }
1274
1275 if let Some(body) = in_block {
1276 let end = in_block_end.unwrap_or(start);
1277 return Ok(Stmt::If(IfStmt {
1278 condition: Expr::BoolLit(true, start),
1279 then_body: body,
1280 else_body: None,
1281 span: start.merge(end),
1282 }));
1283 }
1284
1285 let value = Expr::StringLit(kind, start);
1286 let span = start.merge(value.span());
1287 Ok(Stmt::Emit(EmitStmt { value, span }))
1288 }
1289
1290 fn parse_let(&mut self) -> Result<Stmt, ParseError> {
1291 let start = self.expect(&TokenKind::Let)?.span;
1292 let mutable = if matches!(self.peek_kind(), TokenKind::Mut) {
1293 self.advance();
1294 true
1295 } else {
1296 false
1297 };
1298 let (name, pattern) = if matches!(self.peek_kind(), TokenKind::LParen | TokenKind::LBracket)
1299 {
1300 let pat = self.parse_pattern()?;
1302 let pat_name = match &pat {
1303 Pattern::TupleDestructure { elements, .. } => {
1304 elements
1306 .first()
1307 .and_then(|p| match p {
1308 Pattern::Ident(n, _) => Some(n.clone()),
1309 _ => None,
1310 })
1311 .unwrap_or_else(|| "__tuple".to_string())
1312 }
1313 Pattern::ListDestructure { elements, .. } => elements
1314 .first()
1315 .and_then(|p| match p {
1316 Pattern::Ident(n, _) => Some(n.clone()),
1317 _ => None,
1318 })
1319 .unwrap_or_else(|| "__pattern".to_string()),
1320 _ => "__pattern".to_string(),
1321 };
1322 (pat_name, Some(pat))
1323 } else if matches!(self.peek_kind(), TokenKind::LBrace) {
1324 let brace_span = self.advance().span; let mut fields = Vec::new();
1327 while !matches!(self.peek_kind(), TokenKind::RBrace | TokenKind::Eof) {
1328 if matches!(self.peek_kind(), TokenKind::Comma) {
1329 self.advance();
1330 continue;
1331 }
1332 let field_name = self.expect_ident()?;
1333 fields.push((field_name, None));
1334 }
1335 if matches!(self.peek_kind(), TokenKind::RBrace) {
1336 self.advance();
1337 }
1338 let first_name = fields
1339 .first()
1340 .map(|(n, _)| n.clone())
1341 .unwrap_or_else(|| "__pattern".to_string());
1342 let pat = Pattern::RecordDestructure {
1343 type_name: String::new(), fields,
1345 open: false,
1346 span: brace_span,
1347 };
1348 (first_name, Some(pat))
1349 } else {
1350 let first = self.expect_ident()?;
1351 if matches!(self.peek_kind(), TokenKind::LParen) {
1352 self.pos -= 1;
1355 let pat = self.parse_pattern()?;
1356 let pat_name = match &pat {
1357 Pattern::Variant(_, Some(binding), _) => Self::pattern_binding_name(binding)
1358 .unwrap_or_else(|| "__pattern".to_string()),
1359 Pattern::RecordDestructure { fields, .. } => fields
1360 .first()
1361 .map(|(n, _)| n.clone())
1362 .unwrap_or_else(|| "__pattern".to_string()),
1363 _ => first.clone(),
1364 };
1365 (pat_name, Some(pat))
1366 } else {
1367 (first, None)
1368 }
1369 };
1370 let ty = if matches!(self.peek_kind(), TokenKind::Colon) {
1371 self.advance();
1372 Some(self.parse_type()?)
1373 } else {
1374 None
1375 };
1376 self.expect(&TokenKind::Assign)?;
1377 let value = self.parse_expr(0)?;
1378 let span = start.merge(value.span());
1379 Ok(Stmt::Let(LetStmt {
1380 name,
1381 mutable,
1382 pattern,
1383 ty,
1384 value,
1385 span,
1386 }))
1387 }
1388
1389 fn parse_if(&mut self) -> Result<Stmt, ParseError> {
1390 let start = self.expect(&TokenKind::If)?.span;
1391
1392 if matches!(self.peek_kind(), TokenKind::Let) {
1394 self.advance();
1395 let pattern = self.parse_pattern()?;
1396 let subject = if matches!(self.peek_kind(), TokenKind::Assign) {
1397 self.advance();
1398 self.parse_expr(0)?
1399 } else {
1400 Expr::BoolLit(true, start)
1402 };
1403
1404 self.skip_newlines();
1406 let then_body = self.parse_block()?;
1407
1408 let else_body = if matches!(self.peek_kind(), TokenKind::Else) {
1410 self.advance();
1411 self.skip_newlines();
1412 if matches!(self.peek_kind(), TokenKind::If) {
1413 let elif = self.parse_if()?;
1414 Some(vec![elif])
1415 } else {
1416 Some(self.parse_block()?)
1417 }
1418 } else {
1419 None
1420 };
1421
1422 let end_span = if matches!(self.peek_kind(), TokenKind::End) {
1423 self.expect(&TokenKind::End)?.span
1424 } else if let Some(ref eb) = else_body {
1425 eb.last().map(|s| s.span()).unwrap_or(start)
1426 } else {
1427 start
1428 };
1429
1430 let mut arms = vec![MatchArm {
1432 pattern,
1433 body: then_body,
1434 span: start,
1435 }];
1436 if let Some(eb) = else_body {
1437 arms.push(MatchArm {
1438 pattern: Pattern::Wildcard(start),
1439 body: eb,
1440 span: start,
1441 });
1442 }
1443
1444 return Ok(Stmt::Match(MatchStmt {
1445 subject,
1446 arms,
1447 span: start.merge(end_span),
1448 }));
1449 }
1450
1451 let cond = self.parse_expr(0)?;
1452 if matches!(self.peek_kind(), TokenKind::Then) {
1453 self.advance();
1454 let then_expr = self.parse_expr(0)?;
1455 let then_stmt = Stmt::Expr(ExprStmt {
1456 expr: then_expr.clone(),
1457 span: then_expr.span(),
1458 });
1459 let else_body = if matches!(self.peek_kind(), TokenKind::Else) {
1460 self.advance();
1461 if matches!(self.peek_kind(), TokenKind::If) {
1462 let elif = self.parse_if()?;
1463 Some(vec![elif])
1464 } else {
1465 let expr = self.parse_expr(0)?;
1466 Some(vec![Stmt::Expr(ExprStmt {
1467 span: expr.span(),
1468 expr,
1469 })])
1470 }
1471 } else {
1472 None
1473 };
1474 let end_span = else_body
1475 .as_ref()
1476 .and_then(|b| b.last().map(|s| s.span()))
1477 .unwrap_or(then_stmt.span());
1478 return Ok(Stmt::If(IfStmt {
1479 condition: cond,
1480 then_body: vec![then_stmt],
1481 else_body,
1482 span: start.merge(end_span),
1483 }));
1484 }
1485 self.skip_newlines();
1486 let then_body = self.parse_block()?;
1487 let else_body = if matches!(self.peek_kind(), TokenKind::Else) {
1488 self.advance();
1489 self.skip_newlines();
1490 if matches!(self.peek_kind(), TokenKind::If) {
1491 let elif = self.parse_if()?;
1493 Some(vec![elif])
1494 } else {
1495 Some(self.parse_block()?)
1496 }
1497 } else {
1498 None
1499 };
1500 let end_span = if matches!(self.peek_kind(), TokenKind::End) {
1501 self.expect(&TokenKind::End)?.span
1502 } else if let Some(ref eb) = else_body {
1503 eb.last().map(|s| s.span()).unwrap_or(start)
1504 } else {
1505 start
1506 };
1507 Ok(Stmt::If(IfStmt {
1508 condition: cond,
1509 then_body,
1510 else_body,
1511 span: start.merge(end_span),
1512 }))
1513 }
1514
1515 fn parse_for(&mut self) -> Result<Stmt, ParseError> {
1516 let start = self.expect(&TokenKind::For)?.span;
1517 let label = if matches!(self.peek_kind(), TokenKind::At) {
1518 self.advance();
1519 Some(self.expect_ident()?)
1520 } else {
1521 None
1522 };
1523 let (var, pattern) = if matches!(self.peek_kind(), TokenKind::LParen) {
1524 let pat = self.parse_pattern()?;
1526 let first_name = match &pat {
1527 Pattern::TupleDestructure { elements, .. } => elements
1528 .first()
1529 .and_then(|p| match p {
1530 Pattern::Ident(n, _) => Some(n.clone()),
1531 _ => None,
1532 })
1533 .unwrap_or_else(|| "__tuple".to_string()),
1534 Pattern::Ident(n, _) => n.clone(),
1535 _ => "__pattern".to_string(),
1536 };
1537 (first_name, Some(pat))
1538 } else {
1539 (self.expect_ident()?, None)
1540 };
1541 self.expect(&TokenKind::In)?;
1542 let iter = self.parse_expr(0)?;
1543 let filter = if matches!(self.peek_kind(), TokenKind::If) {
1544 self.advance();
1545 Some(self.parse_expr(0)?)
1546 } else {
1547 None
1548 };
1549 self.skip_newlines();
1550 let body = self.parse_block()?;
1551 let end_span = self.expect(&TokenKind::End)?.span;
1552 Ok(Stmt::For(ForStmt {
1553 label,
1554 var,
1555 pattern,
1556 iter,
1557 filter,
1558 body,
1559 span: start.merge(end_span),
1560 }))
1561 }
1562
1563 fn parse_match(&mut self) -> Result<Stmt, ParseError> {
1564 let start = self.expect(&TokenKind::Match)?.span;
1565 let subject = self.parse_expr(0)?;
1566 self.skip_newlines();
1567 let mut arms = Vec::new();
1568 let has_indent = matches!(self.peek_kind(), TokenKind::Indent);
1569 if has_indent {
1570 self.advance();
1571 }
1572 self.skip_newlines();
1573 while !matches!(self.peek_kind(), TokenKind::End | TokenKind::Eof) {
1574 self.skip_newlines();
1575 if matches!(self.peek_kind(), TokenKind::Dedent) {
1576 self.advance();
1577 continue;
1578 }
1579 if matches!(self.peek_kind(), TokenKind::End | TokenKind::Eof) {
1580 break;
1581 }
1582 let arm_start = self.current().span;
1583 let first_pattern = self.parse_pattern()?;
1584 let mut pattern = if matches!(self.peek_kind(), TokenKind::Pipe) {
1585 let mut patterns = vec![first_pattern];
1586 while matches!(self.peek_kind(), TokenKind::Pipe) {
1587 self.advance();
1588 patterns.push(self.parse_pattern()?);
1589 }
1590 Pattern::Or {
1591 patterns,
1592 span: arm_start,
1593 }
1594 } else {
1595 first_pattern
1596 };
1597 if matches!(self.peek_kind(), TokenKind::If) {
1598 self.advance();
1599 let guard = self.parse_expr(0)?;
1600 pattern = Pattern::Guard {
1601 inner: Box::new(pattern),
1602 condition: Box::new(guard),
1603 span: arm_start,
1604 };
1605 }
1606 self.expect(&TokenKind::Arrow)?;
1607 let body = if matches!(self.peek_kind(), TokenKind::Newline) {
1609 self.skip_newlines();
1611 if matches!(self.peek_kind(), TokenKind::Indent) {
1612 self.parse_block_strict_dedent()?
1613 } else {
1614 vec![self.parse_stmt()?]
1616 }
1617 } else {
1618 vec![self.parse_stmt()?]
1620 };
1621 let arm_span = arm_start.merge(body.last().map(|s| s.span()).unwrap_or(arm_start));
1622 arms.push(MatchArm {
1623 pattern,
1624 body,
1625 span: arm_span,
1626 });
1627 self.skip_newlines();
1628 }
1629 if has_indent && matches!(self.peek_kind(), TokenKind::Dedent) {
1630 self.advance();
1631 }
1632 self.skip_newlines();
1633 let end_span = self.expect(&TokenKind::End)?.span;
1634 Ok(Stmt::Match(MatchStmt {
1635 subject,
1636 arms,
1637 span: start.merge(end_span),
1638 }))
1639 }
1640
1641 fn parse_pattern(&mut self) -> Result<Pattern, ParseError> {
1642 if matches!(self.peek_kind(), TokenKind::LParen) {
1643 let s = self.advance().span;
1644 if self.paren_contains_top_level_arrow() {
1645 let mut depth = 1usize;
1646 while !self.at_end() {
1647 match self.peek_kind() {
1648 TokenKind::LParen => {
1649 depth += 1;
1650 self.advance();
1651 }
1652 TokenKind::RParen => {
1653 depth -= 1;
1654 self.advance();
1655 if depth == 0 {
1656 break;
1657 }
1658 }
1659 _ => {
1660 self.advance();
1661 }
1662 }
1663 }
1664 return Ok(Pattern::Wildcard(s));
1665 }
1666 if matches!(self.peek_kind(), TokenKind::RParen) {
1667 self.advance();
1668 return Ok(Pattern::TupleDestructure {
1669 elements: vec![],
1670 span: s,
1671 });
1672 }
1673 let first = self.parse_pattern()?;
1674 if matches!(self.peek_kind(), TokenKind::Comma) {
1675 let mut elements = vec![first];
1676 while matches!(self.peek_kind(), TokenKind::Comma) {
1677 self.advance();
1678 if matches!(self.peek_kind(), TokenKind::RParen | TokenKind::Eof) {
1679 break;
1680 }
1681 elements.push(self.parse_pattern()?);
1682 }
1683 self.expect(&TokenKind::RParen)?;
1684 return Ok(Pattern::TupleDestructure { elements, span: s });
1685 }
1686 self.expect(&TokenKind::RParen)?;
1687 return Ok(first);
1688 }
1689 if matches!(self.peek_kind(), TokenKind::LBracket) {
1690 let s = self.advance().span;
1691 let mut elements = Vec::new();
1692 let mut rest = None;
1693 while !matches!(self.peek_kind(), TokenKind::RBracket | TokenKind::Eof) {
1694 if matches!(self.peek_kind(), TokenKind::Comma) {
1695 self.advance();
1696 continue;
1697 }
1698 if matches!(self.peek_kind(), TokenKind::DotDot | TokenKind::DotDotDot) {
1699 self.advance();
1700 if matches!(self.peek_kind(), TokenKind::Ident(_)) {
1701 rest = Some(self.expect_ident()?);
1702 }
1703 while !matches!(self.peek_kind(), TokenKind::RBracket | TokenKind::Eof) {
1704 if matches!(self.peek_kind(), TokenKind::Comma) {
1705 self.advance();
1706 break;
1707 }
1708 self.advance();
1709 }
1710 continue;
1711 }
1712 elements.push(self.parse_pattern()?);
1713 }
1714 self.expect(&TokenKind::RBracket)?;
1715 return Ok(Pattern::ListDestructure {
1716 elements,
1717 rest,
1718 span: s,
1719 });
1720 }
1721
1722 match self.peek_kind().clone() {
1723 TokenKind::IntLit(n) => {
1724 let s = self.advance().span;
1725 Ok(Pattern::Literal(Expr::IntLit(n, s)))
1726 }
1727 TokenKind::FloatLit(n) => {
1728 let s = self.advance().span;
1729 Ok(Pattern::Literal(Expr::FloatLit(n, s)))
1730 }
1731 TokenKind::StringLit(ref sv) => {
1732 let sv = sv.clone();
1733 let s = self.advance().span;
1734 Ok(Pattern::Literal(Expr::StringLit(sv, s)))
1735 }
1736 TokenKind::BoolLit(b) => {
1737 let s = self.advance().span;
1738 Ok(Pattern::Literal(Expr::BoolLit(b, s)))
1739 }
1740 TokenKind::Ident(ref name) if name == "_" => {
1741 let s = self.advance().span;
1742 Ok(Pattern::Wildcard(s))
1743 }
1744 TokenKind::Ok_ | TokenKind::Err_ => {
1745 let vname = format!("{}", self.peek_kind());
1746 let s = self.advance().span;
1747 if matches!(self.peek_kind(), TokenKind::LParen) {
1748 self.advance();
1749 let inner = if matches!(self.peek_kind(), TokenKind::RParen) {
1750 None
1751 } else {
1752 Some(Box::new(self.parse_pattern()?))
1753 };
1754 self.expect(&TokenKind::RParen)?;
1755 Ok(Pattern::Variant(vname, inner, s))
1756 } else {
1757 Ok(Pattern::Variant(vname, None, s))
1758 }
1759 }
1760 TokenKind::Ident(ref name) => {
1761 let mut name = name.clone();
1762 let s = self.advance().span;
1763 while matches!(self.peek_kind(), TokenKind::Dot) {
1764 self.advance();
1765 name.push('.');
1766 name.push_str(&self.expect_ident()?);
1767 }
1768 if matches!(self.peek_kind(), TokenKind::Colon) {
1769 self.advance();
1770 let ty = self.parse_type()?;
1771 return Ok(Pattern::TypeCheck {
1772 name,
1773 type_expr: Box::new(ty),
1774 span: s,
1775 });
1776 }
1777 if matches!(self.peek_kind(), TokenKind::LParen) {
1778 if self.paren_looks_like_record_destructure() {
1779 self.advance(); let mut fields = Vec::new();
1781 let mut open = false;
1782 while !matches!(self.peek_kind(), TokenKind::RParen | TokenKind::Eof) {
1783 if matches!(self.peek_kind(), TokenKind::Comma) {
1784 self.advance();
1785 continue;
1786 }
1787 if matches!(self.peek_kind(), TokenKind::DotDot | TokenKind::DotDotDot)
1788 {
1789 open = true;
1790 self.advance();
1791 if matches!(self.peek_kind(), TokenKind::Ident(_)) {
1792 self.advance();
1793 }
1794 continue;
1795 }
1796 let field_name = self.expect_ident()?;
1797 let field_pat = if matches!(self.peek_kind(), TokenKind::Colon) {
1798 self.advance();
1799 if matches!(self.peek_kind(), TokenKind::Comma | TokenKind::RParen)
1800 {
1801 None
1802 } else {
1803 Some(self.parse_pattern()?)
1804 }
1805 } else {
1806 None
1807 };
1808 fields.push((field_name, field_pat));
1809 if matches!(self.peek_kind(), TokenKind::Comma) {
1810 self.advance();
1811 }
1812 }
1813 self.expect(&TokenKind::RParen)?;
1814 Ok(Pattern::RecordDestructure {
1815 type_name: name,
1816 fields,
1817 open,
1818 span: s,
1819 })
1820 } else {
1821 self.advance();
1822 let binding = self.parse_variant_binding_candidate()?;
1823 self.expect(&TokenKind::RParen)?;
1824 Ok(Pattern::Variant(name, binding, s))
1825 }
1826 } else {
1827 Ok(Pattern::Ident(name, s))
1828 }
1829 }
1830 _ => {
1831 let tok = self.current().clone();
1832 Err(ParseError::Unexpected {
1833 found: format!("{}", tok.kind),
1834 expected: "pattern".into(),
1835 line: tok.span.line,
1836 col: tok.span.col,
1837 })
1838 }
1839 }
1840 }
1841
1842 fn parse_return(&mut self) -> Result<Stmt, ParseError> {
1843 let start = self.expect(&TokenKind::Return)?.span;
1844 let value = self.parse_expr(0)?;
1845 Ok(Stmt::Return(ReturnStmt {
1846 value: value.clone(),
1847 span: start.merge(value.span()),
1848 }))
1849 }
1850
1851 fn parse_halt(&mut self) -> Result<Stmt, ParseError> {
1852 let start = self.expect(&TokenKind::Halt)?.span;
1853 self.expect(&TokenKind::LParen)?;
1854 let msg = self.parse_expr(0)?;
1855 self.expect(&TokenKind::RParen)?;
1856 Ok(Stmt::Halt(HaltStmt {
1857 message: msg.clone(),
1858 span: start.merge(msg.span()),
1859 }))
1860 }
1861
1862 fn parse_while(&mut self) -> Result<Stmt, ParseError> {
1863 let start = self.expect(&TokenKind::While)?.span;
1864 let label = if matches!(self.peek_kind(), TokenKind::At) {
1865 self.advance();
1866 Some(self.expect_ident()?)
1867 } else {
1868 None
1869 };
1870
1871 if matches!(self.peek_kind(), TokenKind::Let) {
1873 self.advance();
1874 let pattern = self.parse_pattern()?;
1875 let subject = if matches!(self.peek_kind(), TokenKind::Assign) {
1876 self.advance();
1877 self.parse_expr(0)?
1878 } else {
1879 Expr::BoolLit(true, start)
1880 };
1881 self.skip_newlines();
1882 let body = self.parse_block()?;
1883 let end_span = self.expect(&TokenKind::End)?.span;
1884
1885 let match_stmt = Stmt::Match(MatchStmt {
1893 subject,
1894 arms: vec![
1895 MatchArm {
1896 pattern,
1897 body,
1898 span: start,
1899 },
1900 MatchArm {
1901 pattern: Pattern::Wildcard(start),
1902 body: vec![Stmt::Break(BreakStmt {
1903 label: None,
1904 value: None,
1905 span: start,
1906 })],
1907 span: start,
1908 },
1909 ],
1910 span: start,
1911 });
1912
1913 return Ok(Stmt::Loop(LoopStmt {
1914 label,
1915 body: vec![match_stmt],
1916 span: start.merge(end_span),
1917 }));
1918 }
1919
1920 let cond = self.parse_expr(0)?;
1921 self.skip_newlines();
1922 let body = self.parse_block()?;
1923 let end_span = self.expect(&TokenKind::End)?.span;
1924 Ok(Stmt::While(WhileStmt {
1925 label,
1926 condition: cond,
1927 body,
1928 span: start.merge(end_span),
1929 }))
1930 }
1931
1932 fn parse_loop(&mut self) -> Result<Stmt, ParseError> {
1933 let start = self.expect(&TokenKind::Loop)?.span;
1934 let label = if matches!(self.peek_kind(), TokenKind::At) {
1935 self.advance();
1936 Some(self.expect_ident()?)
1937 } else {
1938 None
1939 };
1940 self.skip_newlines();
1941 let body = self.parse_block()?;
1942 let end_span = self.expect(&TokenKind::End)?.span;
1943 Ok(Stmt::Loop(LoopStmt {
1944 label,
1945 body,
1946 span: start.merge(end_span),
1947 }))
1948 }
1949
1950 fn parse_defer(&mut self) -> Result<Stmt, ParseError> {
1951 let start = self.expect(&TokenKind::Defer)?.span;
1952 self.skip_newlines();
1953 let body = self.parse_block()?;
1954 let end_span = self.expect(&TokenKind::End)?.span;
1955 Ok(Stmt::Defer(DeferStmt {
1956 body,
1957 span: start.merge(end_span),
1958 }))
1959 }
1960
1961 fn parse_break(&mut self) -> Result<Stmt, ParseError> {
1962 let start = self.expect(&TokenKind::Break)?.span;
1963 let label = if matches!(self.peek_kind(), TokenKind::At) {
1964 self.advance();
1965 Some(self.expect_ident()?)
1966 } else {
1967 None
1968 };
1969 let value = if label.is_none()
1970 && !matches!(
1971 self.peek_kind(),
1972 TokenKind::Newline | TokenKind::Eof | TokenKind::End | TokenKind::Dedent
1973 ) {
1974 Some(self.parse_expr(0)?)
1975 } else {
1976 None
1977 };
1978 let span = value
1979 .as_ref()
1980 .map(|v| start.merge(v.span()))
1981 .unwrap_or(start);
1982 Ok(Stmt::Break(BreakStmt { label, value, span }))
1983 }
1984
1985 fn parse_continue(&mut self) -> Result<Stmt, ParseError> {
1986 let start = self.expect(&TokenKind::Continue)?.span;
1987 let label = if matches!(self.peek_kind(), TokenKind::At) {
1988 self.advance();
1989 Some(self.expect_ident()?)
1990 } else {
1991 None
1992 };
1993 Ok(Stmt::Continue(ContinueStmt { label, span: start }))
1994 }
1995
1996 fn parse_emit(&mut self) -> Result<Stmt, ParseError> {
1997 let start = self.expect(&TokenKind::Emit)?.span;
1998 let value = self.parse_expr(0)?;
1999 let span = start.merge(value.span());
2000 Ok(Stmt::Emit(EmitStmt { value, span }))
2001 }
2002
2003 fn is_compound_assignment(&self) -> bool {
2004 let mut i = self.pos;
2005 if !matches!(self.tokens.get(i).map(|t| &t.kind), Some(k) if Self::is_identifier_like(k)) {
2006 return false;
2007 }
2008 i += 1;
2009 while matches!(self.tokens.get(i).map(|t| &t.kind), Some(TokenKind::Dot))
2010 && matches!(
2011 self.tokens.get(i + 1).map(|t| &t.kind),
2012 Some(TokenKind::Ident(_))
2013 )
2014 {
2015 i += 2;
2016 }
2017 matches!(
2018 self.tokens.get(i).map(|t| &t.kind),
2019 Some(
2020 TokenKind::PlusAssign
2021 | TokenKind::MinusAssign
2022 | TokenKind::StarAssign
2023 | TokenKind::SlashAssign
2024 | TokenKind::FloorDivAssign
2025 | TokenKind::PercentAssign
2026 | TokenKind::StarStarAssign
2027 | TokenKind::AmpAssign
2028 | TokenKind::PipeAssign
2029 | TokenKind::CaretAssign
2030 )
2031 )
2032 }
2033
2034 fn parse_compound_assign(&mut self) -> Result<Stmt, ParseError> {
2035 let start = self.tokens[self.pos].span;
2036 let name = self.parse_assignment_target()?;
2037 let op = match self.peek_kind() {
2038 TokenKind::PlusAssign => {
2039 self.advance();
2040 CompoundOp::AddAssign
2041 }
2042 TokenKind::MinusAssign => {
2043 self.advance();
2044 CompoundOp::SubAssign
2045 }
2046 TokenKind::StarAssign => {
2047 self.advance();
2048 CompoundOp::MulAssign
2049 }
2050 TokenKind::SlashAssign => {
2051 self.advance();
2052 CompoundOp::DivAssign
2053 }
2054 TokenKind::FloorDivAssign => {
2055 self.advance();
2056 CompoundOp::FloorDivAssign
2057 }
2058 TokenKind::PercentAssign => {
2059 self.advance();
2060 CompoundOp::ModAssign
2061 }
2062 TokenKind::StarStarAssign => {
2063 self.advance();
2064 CompoundOp::PowAssign
2065 }
2066 TokenKind::AmpAssign => {
2067 self.advance();
2068 CompoundOp::BitAndAssign
2069 }
2070 TokenKind::PipeAssign => {
2071 self.advance();
2072 CompoundOp::BitOrAssign
2073 }
2074 TokenKind::CaretAssign => {
2075 self.advance();
2076 CompoundOp::BitXorAssign
2077 }
2078 _ => unreachable!(),
2079 };
2080 let value = self.parse_expr(0)?;
2081 let span = start.merge(value.span());
2082 Ok(Stmt::CompoundAssign(CompoundAssignStmt {
2083 target: name,
2084 op,
2085 value,
2086 span,
2087 }))
2088 }
2089
2090 fn parse_type_alias(&mut self, is_pub: bool) -> Result<TypeAliasDef, ParseError> {
2093 let start = self.expect(&TokenKind::Type)?.span;
2094 let name = self.expect_ident()?;
2095 let generic_params = self.parse_optional_generic_params()?;
2096 self.expect(&TokenKind::Assign)?;
2097 let type_expr = self.parse_type()?;
2098 if matches!(self.peek_kind(), TokenKind::Where) {
2099 self.advance();
2100 let _ = self.parse_expr(0)?;
2101 }
2102 let span = start.merge(type_expr.span());
2103 Ok(TypeAliasDef {
2104 name,
2105 generic_params,
2106 type_expr,
2107 is_pub,
2108 span,
2109 })
2110 }
2111
2112 fn parse_trait_def(&mut self, is_pub: bool) -> Result<TraitDef, ParseError> {
2113 let start = self.expect(&TokenKind::Trait)?.span;
2114 let name = self.expect_ident()?;
2115 let parent_traits = if matches!(self.peek_kind(), TokenKind::Colon) {
2116 self.advance();
2117 let mut traits = vec![self.expect_ident()?];
2118 while matches!(self.peek_kind(), TokenKind::Comma | TokenKind::Plus) {
2119 self.advance();
2120 traits.push(self.expect_ident()?);
2121 }
2122 traits
2123 } else {
2124 vec![]
2125 };
2126 self.skip_newlines();
2127 let mut methods = Vec::new();
2128 let has_indent = matches!(self.peek_kind(), TokenKind::Indent);
2129 if has_indent {
2130 self.advance();
2131 }
2132 self.skip_newlines();
2133 while !matches!(self.peek_kind(), TokenKind::End | TokenKind::Eof) {
2134 self.skip_newlines();
2135 if matches!(self.peek_kind(), TokenKind::Dedent) {
2136 self.advance();
2137 continue;
2138 }
2139 if matches!(self.peek_kind(), TokenKind::End | TokenKind::Eof) {
2140 break;
2141 }
2142 methods.push(self.parse_cell(false)?);
2143 self.skip_newlines();
2144 }
2145 if has_indent && matches!(self.peek_kind(), TokenKind::Dedent) {
2146 self.advance();
2147 }
2148 self.skip_newlines();
2149 let end_span = self.expect(&TokenKind::End)?.span;
2150 Ok(TraitDef {
2151 name,
2152 parent_traits,
2153 methods,
2154 is_pub,
2155 span: start.merge(end_span),
2156 })
2157 }
2158
2159 fn parse_impl_def(&mut self) -> Result<ImplDef, ParseError> {
2160 let start = self.expect(&TokenKind::Impl)?.span;
2161 let generic_params = self.parse_optional_generic_params()?;
2162 let trait_name = self.expect_ident()?;
2163 self.expect(&TokenKind::For)?;
2164 let mut target_type = self.parse_dotted_ident()?;
2165 if matches!(self.peek_kind(), TokenKind::LBracket) {
2166 let mut depth = 0usize;
2167 let mut suffix = String::new();
2168 while !self.at_end() {
2169 match self.peek_kind() {
2170 TokenKind::LBracket => {
2171 depth += 1;
2172 suffix.push('[');
2173 self.advance();
2174 }
2175 TokenKind::RBracket => {
2176 suffix.push(']');
2177 self.advance();
2178 depth -= 1;
2179 if depth == 0 {
2180 break;
2181 }
2182 }
2183 _ => {
2184 suffix.push_str(&format!("{}", self.current().kind));
2185 self.advance();
2186 }
2187 }
2188 }
2189 target_type.push_str(&suffix);
2190 }
2191 self.skip_newlines();
2192 let mut cells = Vec::new();
2193 let has_indent = matches!(self.peek_kind(), TokenKind::Indent);
2194 if has_indent {
2195 self.advance();
2196 }
2197 self.skip_newlines();
2198 while !matches!(self.peek_kind(), TokenKind::End | TokenKind::Eof) {
2199 self.skip_newlines();
2200 if matches!(self.peek_kind(), TokenKind::Dedent) {
2201 self.advance();
2202 continue;
2203 }
2204 if matches!(self.peek_kind(), TokenKind::End | TokenKind::Eof) {
2205 break;
2206 }
2207 cells.push(self.parse_cell(true)?);
2208 self.skip_newlines();
2209 }
2210 if has_indent && matches!(self.peek_kind(), TokenKind::Dedent) {
2211 self.advance();
2212 }
2213 self.skip_newlines();
2214 let end_span = self.expect(&TokenKind::End)?.span;
2215 Ok(ImplDef {
2216 trait_name,
2217 generic_params,
2218 target_type,
2219 cells,
2220 span: start.merge(end_span),
2221 })
2222 }
2223
2224 fn parse_import(&mut self, is_pub: bool) -> Result<ImportDecl, ParseError> {
2225 let start = self.expect(&TokenKind::Import)?.span;
2226 let mut path = vec![self.expect_ident()?];
2227 while matches!(self.peek_kind(), TokenKind::Dot) {
2228 self.advance();
2229 path.push(self.expect_ident()?);
2230 }
2231 self.expect(&TokenKind::Colon)?;
2232 let names = if matches!(self.peek_kind(), TokenKind::Star) {
2233 self.advance();
2234 ImportList::Wildcard
2235 } else {
2236 let mut names = Vec::new();
2237 loop {
2238 let ns = self.current().span;
2239 let n = self.expect_ident()?;
2240 let alias = if matches!(self.peek_kind(), TokenKind::As) {
2241 self.advance();
2242 Some(self.expect_ident()?)
2243 } else {
2244 None
2245 };
2246 names.push(ImportName {
2247 name: n,
2248 alias,
2249 span: ns,
2250 });
2251 if !matches!(self.peek_kind(), TokenKind::Comma) {
2252 break;
2253 }
2254 self.advance();
2255 }
2256 ImportList::Names(names)
2257 };
2258 let span = start.merge(self.current().span);
2259 Ok(ImportDecl {
2260 path,
2261 names,
2262 is_pub,
2263 span,
2264 })
2265 }
2266
2267 fn parse_const_decl(&mut self) -> Result<ConstDeclDef, ParseError> {
2268 let start = self.expect(&TokenKind::Const)?.span;
2269 let name = self.expect_ident()?;
2270 let type_ann = if matches!(self.peek_kind(), TokenKind::Colon) {
2271 self.advance();
2272 Some(self.parse_type()?)
2273 } else {
2274 None
2275 };
2276 self.expect(&TokenKind::Assign)?;
2277 let value = self.parse_expr(0)?;
2278 let span = start.merge(value.span());
2279 Ok(ConstDeclDef {
2280 name,
2281 type_ann,
2282 value,
2283 span,
2284 })
2285 }
2286
2287 fn parse_macro_decl(&mut self) -> Result<MacroDeclDef, ParseError> {
2288 let start = self.expect(&TokenKind::Macro)?.span;
2289 let mut name = if matches!(self.peek_kind(), TokenKind::Ident(_)) {
2290 self.expect_ident()?
2291 } else {
2292 "__macro".to_string()
2293 };
2294 if matches!(self.peek_kind(), TokenKind::Bang) {
2295 self.advance();
2296 name.push('!');
2297 }
2298
2299 let mut params = Vec::new();
2300 if matches!(self.peek_kind(), TokenKind::LParen) {
2301 self.advance();
2302 while !matches!(self.peek_kind(), TokenKind::RParen | TokenKind::Eof) {
2303 if matches!(self.peek_kind(), TokenKind::Comma) {
2304 self.advance();
2305 continue;
2306 }
2307 if Self::is_identifier_like(self.peek_kind()) {
2308 params.push(self.expect_ident()?);
2309 } else {
2310 self.advance();
2311 }
2312 }
2313 if matches!(self.peek_kind(), TokenKind::RParen) {
2314 self.advance();
2315 }
2316 }
2317
2318 self.consume_block_until_end();
2319 let span = start.merge(self.current().span);
2320 Ok(MacroDeclDef {
2321 name,
2322 params,
2323 body: vec![],
2324 span,
2325 })
2326 }
2327
2328 fn parse_optional_generic_params(&mut self) -> Result<Vec<GenericParam>, ParseError> {
2329 if !matches!(self.peek_kind(), TokenKind::LBracket) {
2330 return Ok(vec![]);
2331 }
2332 self.advance();
2333 let mut params = Vec::new();
2334 while !matches!(self.peek_kind(), TokenKind::RBracket) {
2335 if !params.is_empty() {
2336 self.expect(&TokenKind::Comma)?;
2337 }
2338 let ps = self.current().span;
2339 let name = self.expect_ident()?;
2340 let bounds = if matches!(self.peek_kind(), TokenKind::Colon) {
2341 self.advance();
2342 let mut b = vec![self.expect_ident()?];
2343 while matches!(self.peek_kind(), TokenKind::Plus) {
2344 self.advance();
2345 b.push(self.expect_ident()?);
2346 }
2347 b
2348 } else {
2349 vec![]
2350 };
2351 params.push(GenericParam {
2352 name,
2353 bounds,
2354 span: ps,
2355 });
2356 }
2357 self.expect(&TokenKind::RBracket)?;
2358 Ok(params)
2359 }
2360
2361 fn parse_optional_effect_row(&mut self) -> Result<Vec<String>, ParseError> {
2362 if !matches!(self.peek_kind(), TokenKind::Slash) {
2363 return Ok(vec![]);
2364 }
2365 self.advance();
2366 self.skip_newlines();
2367 if matches!(self.peek_kind(), TokenKind::LBrace) {
2368 self.advance();
2369 let mut effects = Vec::new();
2370 while !matches!(self.peek_kind(), TokenKind::RBrace | TokenKind::Eof) {
2371 if matches!(self.peek_kind(), TokenKind::Comma) {
2372 self.advance();
2373 continue;
2374 }
2375 effects.push(self.parse_effect_name()?);
2376 if matches!(self.peek_kind(), TokenKind::Comma) {
2377 self.advance();
2378 }
2379 }
2380 self.expect(&TokenKind::RBrace)?;
2381 Ok(effects)
2382 } else if matches!(
2383 self.peek_kind(),
2384 TokenKind::Ident(_)
2385 | TokenKind::Emit
2386 | TokenKind::Role
2387 | TokenKind::Use
2388 | TokenKind::Tool
2389 | TokenKind::Grant
2390 | TokenKind::Await
2391 | TokenKind::Async
2392 | TokenKind::Parallel
2393 ) {
2394 Ok(vec![self.parse_effect_name()?])
2395 } else {
2396 Ok(vec![])
2397 }
2398 }
2399
2400 fn parse_effect_name(&mut self) -> Result<String, ParseError> {
2401 match self.peek_kind().clone() {
2402 TokenKind::Ident(_) => self.expect_ident(),
2403 TokenKind::Emit => {
2404 self.advance();
2405 Ok("emit".into())
2406 }
2407 TokenKind::Role => {
2408 self.advance();
2409 Ok("role".into())
2410 }
2411 TokenKind::Use => {
2412 self.advance();
2413 Ok("use".into())
2414 }
2415 TokenKind::Tool => {
2416 self.advance();
2417 Ok("tool".into())
2418 }
2419 TokenKind::Grant => {
2420 self.advance();
2421 Ok("grant".into())
2422 }
2423 TokenKind::Await => {
2424 self.advance();
2425 Ok("await".into())
2426 }
2427 TokenKind::Async => {
2428 self.advance();
2429 Ok("async".into())
2430 }
2431 TokenKind::Parallel => {
2432 self.advance();
2433 Ok("parallel".into())
2434 }
2435 _ => {
2436 let tok = self.current().clone();
2437 Err(ParseError::Unexpected {
2438 found: format!("{}", tok.kind),
2439 expected: "effect name".into(),
2440 line: tok.span.line,
2441 col: tok.span.col,
2442 })
2443 }
2444 }
2445 }
2446
2447 fn parse_attribute_decl(&mut self) -> Result<AddonDecl, ParseError> {
2448 let start = self.expect(&TokenKind::At)?.span;
2449 let name = match self.peek_kind() {
2450 TokenKind::Ident(_) => Some(self.expect_ident()?),
2451 _ => None,
2452 };
2453
2454 if matches!(self.peek_kind(), TokenKind::LParen) {
2455 self.consume_parenthesized();
2456 }
2457
2458 if matches!(self.peek_kind(), TokenKind::Newline) {
2459 self.skip_newlines();
2462 if matches!(self.peek_kind(), TokenKind::Indent) {
2463 self.consume_indented_payload();
2464 self.skip_newlines();
2465 if matches!(self.peek_kind(), TokenKind::End) {
2466 self.advance();
2467 }
2468 }
2469 } else {
2470 self.consume_rest_of_line();
2471 }
2472
2473 let end = self.current().span;
2474 Ok(AddonDecl {
2475 kind: "attribute".into(),
2476 name,
2477 span: start.merge(end),
2478 })
2479 }
2480
2481 fn parse_addon_decl(&mut self) -> Result<AddonDecl, ParseError> {
2482 let start = self.current().span;
2483 let kind = self.expect_ident()?;
2484 let name = self.parse_optional_decl_name()?;
2485
2486 let is_line_decl = matches!(kind.as_str(), "bind" | "pattern");
2487 if is_line_decl {
2488 self.consume_rest_of_line();
2489 } else {
2490 self.consume_block_until_end();
2491 }
2492
2493 let end = self.current().span;
2494 Ok(AddonDecl {
2495 kind,
2496 name,
2497 span: start.merge(end),
2498 })
2499 }
2500
2501 fn parse_agent_decl(&mut self) -> Result<AgentDecl, ParseError> {
2502 let start = self.current().span;
2503 let _kw = self.expect_ident()?;
2504 let name = self
2505 .parse_optional_decl_name()?
2506 .unwrap_or_else(|| "Agent".to_string());
2507
2508 let mut cells = Vec::new();
2509 let mut grants = Vec::new();
2510
2511 self.skip_newlines();
2512 let has_indent = matches!(self.peek_kind(), TokenKind::Indent);
2513 if has_indent {
2514 self.advance();
2515 }
2516 self.skip_newlines();
2517
2518 while !matches!(
2519 self.peek_kind(),
2520 TokenKind::End | TokenKind::Dedent | TokenKind::Eof
2521 ) {
2522 self.skip_newlines();
2523 if matches!(
2524 self.peek_kind(),
2525 TokenKind::End | TokenKind::Dedent | TokenKind::Eof
2526 ) {
2527 break;
2528 }
2529
2530 let is_async = matches!(self.peek_kind(), TokenKind::Async);
2531 if is_async {
2532 self.advance();
2533 self.skip_newlines();
2534 }
2535
2536 match self.peek_kind() {
2537 TokenKind::Cell => {
2538 let mut cell = self.parse_cell(true)?;
2539 cell.is_async = is_async;
2540 if cell.params.first().map(|p| p.name.as_str()) != Some("self") {
2541 let self_span = cell.span;
2542 cell.params.insert(
2543 0,
2544 Param {
2545 name: "self".into(),
2546 ty: TypeExpr::Named("Json".into(), self_span),
2547 default_value: None,
2548 variadic: false,
2549 span: self_span,
2550 },
2551 );
2552 }
2553 cells.push(cell);
2554 }
2555 TokenKind::Grant => grants.push(self.parse_grant()?),
2556 TokenKind::At => {
2557 let _ = self.parse_attribute_decl()?;
2558 }
2559 TokenKind::Role | TokenKind::Tool => {
2560 self.advance();
2561 self.consume_section_or_line_after_name();
2562 }
2563 TokenKind::Impl => {
2564 self.advance();
2565 self.consume_block_until_end();
2566 }
2567 TokenKind::Ident(_) => {
2568 self.consume_named_section_or_line();
2569 }
2570 _ => {
2571 self.consume_rest_of_line();
2572 }
2573 }
2574 self.skip_newlines();
2575 }
2576
2577 if has_indent && matches!(self.peek_kind(), TokenKind::Dedent) {
2578 self.advance();
2579 }
2580 while matches!(
2581 self.peek_kind(),
2582 TokenKind::Newline | TokenKind::Indent | TokenKind::Dedent
2583 ) {
2584 self.advance();
2585 }
2586 let end_span = if matches!(self.peek_kind(), TokenKind::End) {
2587 self.advance().span
2588 } else {
2589 self.current().span
2590 };
2591 Ok(AgentDecl {
2592 name,
2593 cells,
2594 grants,
2595 span: start.merge(end_span),
2596 })
2597 }
2598
2599 fn parse_effect_decl(&mut self) -> Result<EffectDecl, ParseError> {
2600 let start = self.current().span;
2601 let kw = self.expect_ident()?;
2602 if kw != "effect" {
2603 let tok = self.current().clone();
2604 return Err(ParseError::Unexpected {
2605 found: kw,
2606 expected: "effect".into(),
2607 line: tok.span.line,
2608 col: tok.span.col,
2609 });
2610 }
2611 let name = self
2612 .parse_optional_decl_name()?
2613 .unwrap_or_else(|| "Effect".to_string());
2614 self.skip_newlines();
2615 let mut operations = Vec::new();
2616 let has_indent = matches!(self.peek_kind(), TokenKind::Indent);
2617 if has_indent {
2618 self.advance();
2619 }
2620 self.skip_newlines();
2621 while !matches!(
2622 self.peek_kind(),
2623 TokenKind::End | TokenKind::Dedent | TokenKind::Eof
2624 ) {
2625 self.skip_newlines();
2626 if matches!(
2627 self.peek_kind(),
2628 TokenKind::End | TokenKind::Dedent | TokenKind::Eof
2629 ) {
2630 break;
2631 }
2632 if matches!(self.peek_kind(), TokenKind::Cell) {
2633 operations.push(self.parse_cell(false)?);
2634 } else {
2635 self.consume_rest_of_line();
2636 }
2637 self.skip_newlines();
2638 }
2639 if has_indent && matches!(self.peek_kind(), TokenKind::Dedent) {
2640 self.advance();
2641 }
2642 while matches!(
2643 self.peek_kind(),
2644 TokenKind::Newline | TokenKind::Indent | TokenKind::Dedent
2645 ) {
2646 self.advance();
2647 }
2648 let end_span = if matches!(self.peek_kind(), TokenKind::End) {
2649 self.advance().span
2650 } else {
2651 self.current().span
2652 };
2653 Ok(EffectDecl {
2654 name,
2655 operations,
2656 span: start.merge(end_span),
2657 })
2658 }
2659
2660 fn parse_process_decl(&mut self) -> Result<ProcessDecl, ParseError> {
2661 let start = self.current().span;
2662 let kind = self.expect_ident()?;
2663 let name = self
2664 .parse_optional_decl_name()?
2665 .unwrap_or_else(|| "Process".to_string());
2666 let mut cells = Vec::new();
2667 let mut grants = Vec::new();
2668 let mut pipeline_stages = Vec::new();
2669 let mut machine_initial = None;
2670 let mut machine_states = Vec::new();
2671
2672 self.skip_newlines();
2673 let has_indent = matches!(self.peek_kind(), TokenKind::Indent);
2674 if has_indent {
2675 self.advance();
2676 }
2677 self.skip_newlines();
2678
2679 while !matches!(self.peek_kind(), TokenKind::End | TokenKind::Eof) {
2680 self.skip_newlines();
2681 if matches!(self.peek_kind(), TokenKind::Dedent) {
2682 self.advance();
2683 continue;
2684 }
2685 if matches!(self.peek_kind(), TokenKind::End | TokenKind::Eof) {
2686 break;
2687 }
2688
2689 let is_async = matches!(self.peek_kind(), TokenKind::Async);
2690 if is_async {
2691 self.advance();
2692 self.skip_newlines();
2693 }
2694
2695 match self.peek_kind() {
2696 TokenKind::Cell => {
2697 let mut cell = self.parse_cell(true)?;
2698 cell.is_async = is_async;
2699 if cell.params.first().map(|p| p.name.as_str()) != Some("self") {
2700 let self_span = cell.span;
2701 cell.params.insert(
2702 0,
2703 Param {
2704 name: "self".into(),
2705 ty: TypeExpr::Named("Json".into(), self_span),
2706 default_value: None,
2707 variadic: false,
2708 span: self_span,
2709 },
2710 );
2711 }
2712 cells.push(cell);
2713 }
2714 TokenKind::Grant => grants.push(self.parse_grant()?),
2715 TokenKind::Ident(name) if kind == "pipeline" && name == "stages" => {
2716 pipeline_stages = self.parse_pipeline_stages_decl()?;
2717 }
2718 TokenKind::Ident(name) if kind == "machine" && name == "initial" => {
2719 machine_initial = Some(self.parse_machine_initial_decl()?);
2720 }
2721 TokenKind::Ident(name) if kind == "machine" && name == "state" => {
2722 machine_states.push(self.parse_machine_state_decl()?);
2723 }
2724 TokenKind::At => {
2725 let _ = self.parse_attribute_decl()?;
2726 }
2727 TokenKind::Role | TokenKind::Tool => {
2728 self.advance();
2729 self.consume_section_or_line_after_name();
2730 }
2731 TokenKind::Record | TokenKind::Enum | TokenKind::Trait | TokenKind::Impl => {
2732 self.advance();
2733 self.consume_block_until_end();
2734 }
2735 TokenKind::Ident(name)
2736 if matches!(
2737 name.as_str(),
2738 "state"
2739 | "on_enter"
2740 | "on_event"
2741 | "on_error"
2742 | "on_input"
2743 | "on_output"
2744 | "on_violation"
2745 | "on_timeout"
2746 | "migrate"
2747 ) =>
2748 {
2749 self.advance();
2750 self.consume_block_until_end();
2751 }
2752 TokenKind::Ident(_) => {
2753 self.consume_named_section_or_line();
2754 }
2755 _ => {
2756 self.consume_rest_of_line();
2757 }
2758 }
2759 self.skip_newlines();
2760 }
2761
2762 if has_indent && matches!(self.peek_kind(), TokenKind::Dedent) {
2763 self.advance();
2764 }
2765 while matches!(
2766 self.peek_kind(),
2767 TokenKind::Newline | TokenKind::Indent | TokenKind::Dedent
2768 ) {
2769 self.advance();
2770 }
2771 let end_span = if matches!(self.peek_kind(), TokenKind::End) {
2772 self.advance().span
2773 } else {
2774 self.current().span
2775 };
2776
2777 Ok(ProcessDecl {
2778 kind,
2779 name,
2780 cells,
2781 grants,
2782 pipeline_stages,
2783 machine_initial,
2784 machine_states,
2785 span: start.merge(end_span),
2786 })
2787 }
2788
2789 fn parse_pipeline_stages_decl(&mut self) -> Result<Vec<String>, ParseError> {
2790 let kw = self.expect_ident()?;
2791 if kw != "stages" {
2792 let tok = self.current().clone();
2793 return Err(ParseError::Unexpected {
2794 found: kw,
2795 expected: "stages".into(),
2796 line: tok.span.line,
2797 col: tok.span.col,
2798 });
2799 }
2800 if matches!(self.peek_kind(), TokenKind::Colon) {
2801 self.advance();
2802 }
2803 self.skip_newlines();
2804 let has_indent = matches!(self.peek_kind(), TokenKind::Indent);
2805 if has_indent {
2806 self.advance();
2807 }
2808 self.skip_newlines();
2809 let mut stages = Vec::new();
2810 while !matches!(self.peek_kind(), TokenKind::End | TokenKind::Eof) {
2811 self.skip_newlines();
2812 if matches!(self.peek_kind(), TokenKind::Dedent) {
2813 self.advance();
2814 continue;
2815 }
2816 if matches!(self.peek_kind(), TokenKind::Indent) {
2817 self.advance();
2818 continue;
2819 }
2820 if matches!(self.peek_kind(), TokenKind::Arrow) {
2821 self.advance();
2822 self.skip_whitespace_tokens();
2823 }
2824 if matches!(self.peek_kind(), TokenKind::End | TokenKind::Eof) {
2825 break;
2826 }
2827 stages.push(self.parse_dotted_ident()?);
2828 self.consume_rest_of_line();
2829 self.skip_newlines();
2830 }
2831 if has_indent && matches!(self.peek_kind(), TokenKind::Dedent) {
2832 self.advance();
2833 }
2834 if matches!(self.peek_kind(), TokenKind::End) {
2835 self.advance();
2836 }
2837 Ok(stages)
2838 }
2839
2840 fn parse_machine_initial_decl(&mut self) -> Result<String, ParseError> {
2841 let kw = self.expect_ident()?;
2842 if kw != "initial" {
2843 let tok = self.current().clone();
2844 return Err(ParseError::Unexpected {
2845 found: kw,
2846 expected: "initial".into(),
2847 line: tok.span.line,
2848 col: tok.span.col,
2849 });
2850 }
2851 if matches!(self.peek_kind(), TokenKind::Colon) {
2852 self.advance();
2853 }
2854 let state = self.expect_ident()?;
2855 self.consume_rest_of_line();
2856 Ok(state)
2857 }
2858
2859 fn parse_machine_state_decl(&mut self) -> Result<MachineStateDecl, ParseError> {
2860 let start = self.current().span;
2861 let kw = self.expect_ident()?;
2862 if kw != "state" {
2863 let tok = self.current().clone();
2864 return Err(ParseError::Unexpected {
2865 found: kw,
2866 expected: "state".into(),
2867 line: tok.span.line,
2868 col: tok.span.col,
2869 });
2870 }
2871 let name = self.expect_ident()?;
2872 let params = if matches!(self.peek_kind(), TokenKind::LParen) {
2873 self.parse_machine_state_params()?
2874 } else {
2875 vec![]
2876 };
2877 let mut terminal = false;
2878 let mut guard = None;
2879 let mut transition_to = None;
2880 let mut transition_args = Vec::new();
2881
2882 self.skip_newlines();
2883 let has_indent = matches!(self.peek_kind(), TokenKind::Indent);
2884 if has_indent {
2885 self.advance();
2886 }
2887 self.skip_newlines();
2888
2889 while !matches!(self.peek_kind(), TokenKind::End | TokenKind::Eof) {
2890 self.skip_newlines();
2891 if matches!(self.peek_kind(), TokenKind::Dedent) {
2892 self.advance();
2893 continue;
2894 }
2895 match self.peek_kind() {
2896 TokenKind::Ident(id) if id == "terminal" => {
2897 self.advance();
2898 if matches!(self.peek_kind(), TokenKind::Colon) {
2899 self.advance();
2900 }
2901 terminal = match self.peek_kind().clone() {
2902 TokenKind::BoolLit(v) => {
2903 self.advance();
2904 v
2905 }
2906 TokenKind::Ident(text) if text == "true" => {
2907 self.advance();
2908 true
2909 }
2910 TokenKind::Ident(text) if text == "false" => {
2911 self.advance();
2912 false
2913 }
2914 _ => false,
2915 };
2916 self.consume_rest_of_line();
2917 }
2918 TokenKind::Ident(id) if id == "guard" => {
2919 self.advance();
2920 if matches!(self.peek_kind(), TokenKind::Colon) {
2921 self.advance();
2922 }
2923 guard = Some(self.parse_expr(0)?);
2924 self.consume_rest_of_line();
2925 }
2926 TokenKind::Ident(id) if id == "transition" => {
2927 self.advance();
2928 let (target, args) = self.parse_machine_transition_decl()?;
2929 transition_to = Some(target);
2930 transition_args = args;
2931 self.consume_rest_of_line();
2932 }
2933 TokenKind::Ident(id)
2934 if matches!(id.as_str(), "on_enter" | "on_event" | "on_timeout") =>
2935 {
2936 self.advance();
2937 self.consume_rest_of_line();
2938 self.skip_newlines();
2939 let nested_indent = matches!(self.peek_kind(), TokenKind::Indent);
2940 if nested_indent {
2941 self.advance();
2942 }
2943 self.skip_newlines();
2944 while !matches!(self.peek_kind(), TokenKind::End | TokenKind::Eof) {
2945 self.skip_newlines();
2946 if matches!(self.peek_kind(), TokenKind::Dedent) {
2947 self.advance();
2948 continue;
2949 }
2950 if let TokenKind::Ident(id2) = self.peek_kind() {
2951 if id2 == "transition" {
2952 self.advance();
2953 let (target, args) = self.parse_machine_transition_decl()?;
2954 transition_to = Some(target);
2955 transition_args = args;
2956 self.consume_rest_of_line();
2957 continue;
2958 }
2959 }
2960 self.consume_rest_of_line();
2961 }
2962 if nested_indent && matches!(self.peek_kind(), TokenKind::Dedent) {
2963 self.advance();
2964 }
2965 if matches!(self.peek_kind(), TokenKind::End) {
2966 self.advance();
2967 }
2968 }
2969 _ => {
2970 self.consume_rest_of_line();
2971 }
2972 }
2973 self.skip_newlines();
2974 }
2975
2976 if has_indent && matches!(self.peek_kind(), TokenKind::Dedent) {
2977 self.advance();
2978 }
2979 let end_span = if matches!(self.peek_kind(), TokenKind::End) {
2980 self.advance().span
2981 } else {
2982 self.current().span
2983 };
2984
2985 Ok(MachineStateDecl {
2986 name,
2987 params,
2988 terminal,
2989 guard,
2990 transition_to,
2991 transition_args,
2992 span: start.merge(end_span),
2993 })
2994 }
2995
2996 fn parse_machine_state_params(&mut self) -> Result<Vec<Param>, ParseError> {
2997 let mut params = Vec::new();
2998 self.expect(&TokenKind::LParen)?;
2999 self.bracket_depth += 1;
3000 self.skip_whitespace_tokens();
3001 while !matches!(self.peek_kind(), TokenKind::RParen | TokenKind::Eof) {
3002 if !params.is_empty() {
3003 self.expect(&TokenKind::Comma)?;
3004 self.skip_whitespace_tokens();
3005 }
3006 let ps = self.current().span;
3007 let pname = self.expect_ident()?;
3008 let pty = if matches!(self.peek_kind(), TokenKind::Colon) {
3009 self.advance();
3010 self.parse_type()?
3011 } else {
3012 TypeExpr::Named("Any".into(), ps)
3013 };
3014 params.push(Param {
3015 name: pname,
3016 ty: pty,
3017 default_value: None,
3018 variadic: false,
3019 span: ps,
3020 });
3021 self.skip_whitespace_tokens();
3022 }
3023 self.bracket_depth -= 1;
3024 self.expect(&TokenKind::RParen)?;
3025 Ok(params)
3026 }
3027
3028 fn parse_machine_transition_decl(&mut self) -> Result<(String, Vec<Expr>), ParseError> {
3029 let target = self.expect_ident()?;
3030 let mut args = Vec::new();
3031 if matches!(self.peek_kind(), TokenKind::LParen) {
3032 self.expect(&TokenKind::LParen)?;
3033 self.bracket_depth += 1;
3034 self.skip_whitespace_tokens();
3035 while !matches!(self.peek_kind(), TokenKind::RParen | TokenKind::Eof) {
3036 if !args.is_empty() {
3037 self.expect(&TokenKind::Comma)?;
3038 self.skip_whitespace_tokens();
3039 }
3040 args.push(self.parse_expr(0)?);
3041 self.skip_whitespace_tokens();
3042 }
3043 self.bracket_depth -= 1;
3044 self.expect(&TokenKind::RParen)?;
3045 }
3046 Ok((target, args))
3047 }
3048
3049 fn parse_effect_bind_decl(&mut self) -> Result<EffectBindDecl, ParseError> {
3050 let start = self.current().span;
3051 let bind_kw = self.expect_ident()?;
3052 if bind_kw != "bind" {
3053 let tok = self.current().clone();
3054 return Err(ParseError::Unexpected {
3055 found: bind_kw,
3056 expected: "bind".into(),
3057 line: tok.span.line,
3058 col: tok.span.col,
3059 });
3060 }
3061 let effect_kw = self.expect_ident()?;
3062 if effect_kw != "effect" {
3063 let tok = self.current().clone();
3064 return Err(ParseError::Unexpected {
3065 found: effect_kw,
3066 expected: "effect".into(),
3067 line: tok.span.line,
3068 col: tok.span.col,
3069 });
3070 }
3071 let effect_path = self.parse_dotted_ident()?;
3072 let to_kw = self.expect_ident()?;
3073 if to_kw != "to" {
3074 let tok = self.current().clone();
3075 return Err(ParseError::Unexpected {
3076 found: to_kw,
3077 expected: "to".into(),
3078 line: tok.span.line,
3079 col: tok.span.col,
3080 });
3081 }
3082 let tool_alias = self.parse_dotted_ident()?;
3083 self.consume_rest_of_line();
3084 Ok(EffectBindDecl {
3085 effect_path,
3086 tool_alias,
3087 span: start.merge(self.current().span),
3088 })
3089 }
3090
3091 fn parse_handler_decl(&mut self) -> Result<HandlerDecl, ParseError> {
3092 let start = self.current().span;
3093 let kw = self.expect_ident()?;
3094 if kw != "handler" {
3095 let tok = self.current().clone();
3096 return Err(ParseError::Unexpected {
3097 found: kw,
3098 expected: "handler".into(),
3099 line: tok.span.line,
3100 col: tok.span.col,
3101 });
3102 }
3103 let name = self
3104 .parse_optional_decl_name()?
3105 .unwrap_or_else(|| "Handler".to_string());
3106 self.skip_newlines();
3107 let mut handles = Vec::new();
3108 let has_indent = matches!(self.peek_kind(), TokenKind::Indent);
3109 if has_indent {
3110 self.advance();
3111 }
3112 self.skip_newlines();
3113 while !matches!(
3114 self.peek_kind(),
3115 TokenKind::End | TokenKind::Dedent | TokenKind::Eof
3116 ) {
3117 self.skip_newlines();
3118 if matches!(
3119 self.peek_kind(),
3120 TokenKind::End | TokenKind::Dedent | TokenKind::Eof
3121 ) {
3122 break;
3123 }
3124 if matches!(self.peek_kind(), TokenKind::Ident(s) if s == "handle") {
3125 handles.push(self.parse_handle_cell()?);
3126 } else if matches!(self.peek_kind(), TokenKind::Cell) {
3127 handles.push(self.parse_cell(true)?);
3128 } else {
3129 self.consume_rest_of_line();
3130 }
3131 self.skip_newlines();
3132 }
3133 if has_indent && matches!(self.peek_kind(), TokenKind::Dedent) {
3134 self.advance();
3135 }
3136 while matches!(
3137 self.peek_kind(),
3138 TokenKind::Newline | TokenKind::Indent | TokenKind::Dedent
3139 ) {
3140 self.advance();
3141 }
3142 let end_span = if matches!(self.peek_kind(), TokenKind::End) {
3143 self.advance().span
3144 } else {
3145 self.current().span
3146 };
3147 Ok(HandlerDecl {
3148 name,
3149 handles,
3150 span: start.merge(end_span),
3151 })
3152 }
3153
3154 fn parse_handle_cell(&mut self) -> Result<CellDef, ParseError> {
3155 let start = self.current().span;
3156 let kw = self.expect_ident()?;
3157 if kw != "handle" {
3158 let tok = self.current().clone();
3159 return Err(ParseError::Unexpected {
3160 found: kw,
3161 expected: "handle".into(),
3162 line: tok.span.line,
3163 col: tok.span.col,
3164 });
3165 }
3166 let name = self.parse_dotted_ident()?;
3167 self.expect(&TokenKind::LParen)?;
3168 self.bracket_depth += 1;
3169 let mut params = Vec::new();
3170 self.skip_whitespace_tokens();
3171 while !matches!(self.peek_kind(), TokenKind::RParen) {
3172 if !params.is_empty() {
3173 self.expect(&TokenKind::Comma)?;
3174 self.skip_whitespace_tokens();
3175 }
3176 let variadic = if matches!(self.peek_kind(), TokenKind::DotDot | TokenKind::DotDotDot) {
3177 self.advance();
3178 true
3179 } else {
3180 false
3181 };
3182 let ps = self.current().span;
3183 let pname = self.expect_ident()?;
3184 let pty = if matches!(self.peek_kind(), TokenKind::Colon) {
3185 self.advance();
3186 self.parse_type()?
3187 } else {
3188 TypeExpr::Named("Any".into(), ps)
3189 };
3190 let default_value = if matches!(self.peek_kind(), TokenKind::Assign) {
3191 self.advance();
3192 Some(self.parse_expr(0)?)
3193 } else {
3194 None
3195 };
3196 params.push(Param {
3197 name: pname,
3198 ty: pty,
3199 default_value,
3200 variadic,
3201 span: ps,
3202 });
3203 self.skip_whitespace_tokens();
3204 }
3205 self.bracket_depth -= 1;
3206 self.expect(&TokenKind::RParen)?;
3207 let ret = if matches!(self.peek_kind(), TokenKind::Arrow) {
3208 self.advance();
3209 Some(self.parse_type()?)
3210 } else {
3211 None
3212 };
3213 let effects = self.parse_optional_effect_row()?;
3214
3215 if matches!(self.peek_kind(), TokenKind::Assign) {
3216 self.advance();
3217 let expr = self.parse_expr(0)?;
3218 let span = start.merge(expr.span());
3219 return Ok(CellDef {
3220 name,
3221 generic_params: vec![],
3222 params,
3223 return_type: ret,
3224 effects,
3225 body: vec![Stmt::Return(ReturnStmt { value: expr, span })],
3226 is_pub: false,
3227 is_async: false,
3228 where_clauses: vec![],
3229 span,
3230 });
3231 }
3232
3233 if matches!(
3234 self.peek_kind(),
3235 TokenKind::Newline | TokenKind::Eof | TokenKind::Dedent
3236 ) {
3237 let mut look = self.pos;
3238 while matches!(
3239 self.tokens.get(look).map(|t| &t.kind),
3240 Some(TokenKind::Newline)
3241 ) {
3242 look += 1;
3243 }
3244 if !matches!(
3245 self.tokens.get(look).map(|t| &t.kind),
3246 Some(TokenKind::Indent)
3247 ) {
3248 let end_span = self.current().span;
3249 return Ok(CellDef {
3250 name,
3251 generic_params: vec![],
3252 params,
3253 return_type: ret,
3254 effects,
3255 body: vec![],
3256 is_pub: false,
3257 is_async: false,
3258 where_clauses: vec![],
3259 span: start.merge(end_span),
3260 });
3261 }
3262 }
3263
3264 self.skip_newlines();
3265 let body = self.parse_block()?;
3266 let end_span = self.expect(&TokenKind::End)?.span;
3267 Ok(CellDef {
3268 name,
3269 generic_params: vec![],
3270 params,
3271 return_type: ret,
3272 effects,
3273 body,
3274 is_pub: false,
3275 is_async: false,
3276 where_clauses: vec![],
3277 span: start.merge(end_span),
3278 })
3279 }
3280
3281 fn consume_parenthesized(&mut self) {
3282 if !matches!(self.peek_kind(), TokenKind::LParen) {
3283 return;
3284 }
3285 let mut depth = 0usize;
3286 while !self.at_end() {
3287 match self.peek_kind() {
3288 TokenKind::LParen => {
3289 depth += 1;
3290 self.advance();
3291 }
3292 TokenKind::RParen => {
3293 self.advance();
3294 if depth == 0 {
3295 break;
3296 }
3297 depth -= 1;
3298 if depth == 0 {
3299 break;
3300 }
3301 }
3302 _ => {
3303 self.advance();
3304 }
3305 }
3306 if depth == 0 && !matches!(self.peek_kind(), TokenKind::RParen) {
3307 break;
3308 }
3309 }
3310 }
3311
3312 fn consume_rest_of_line(&mut self) {
3313 while !matches!(self.peek_kind(), TokenKind::Newline | TokenKind::Eof) {
3314 self.advance();
3315 }
3316 }
3317
3318 fn consume_indented_payload(&mut self) {
3319 if !matches!(self.peek_kind(), TokenKind::Indent) {
3320 return;
3321 }
3322 self.advance();
3323 let mut depth = 0usize;
3324 while !self.at_end() {
3325 match self.peek_kind() {
3326 TokenKind::Indent => {
3327 depth += 1;
3328 self.advance();
3329 }
3330 TokenKind::Dedent => {
3331 if depth == 0 {
3332 self.advance();
3333 break;
3334 }
3335 depth -= 1;
3336 self.advance();
3337 }
3338 _ => {
3339 self.advance();
3340 }
3341 }
3342 }
3343 }
3344
3345 fn consume_block_until_end(&mut self) {
3346 let mut depth = 0usize;
3347 while !self.at_end() {
3348 match self.peek_kind() {
3349 TokenKind::End => {
3350 if depth == 0 {
3351 self.advance();
3352 break;
3353 }
3354 depth -= 1;
3355 self.advance();
3356 }
3357 TokenKind::Record
3358 | TokenKind::Enum
3359 | TokenKind::Cell
3360 | TokenKind::Trait
3361 | TokenKind::Impl
3362 | TokenKind::If
3363 | TokenKind::For
3364 | TokenKind::Match
3365 | TokenKind::While
3366 | TokenKind::Loop => {
3367 depth += 1;
3368 self.advance();
3369 }
3370 TokenKind::Role | TokenKind::Tool if self.consumes_section_colon_block() => {
3371 depth += 1;
3372 self.advance();
3373 }
3374 TokenKind::Ident(name)
3375 if matches!(
3376 name.as_str(),
3377 "effect"
3378 | "handler"
3379 | "agent"
3380 | "pipeline"
3381 | "orchestration"
3382 | "machine"
3383 | "memory"
3384 | "guardrail"
3385 | "eval"
3386 | "handle"
3387 | "state"
3388 | "on_enter"
3389 | "on_event"
3390 | "on_error"
3391 | "on_input"
3392 | "on_output"
3393 | "on_violation"
3394 | "on_timeout"
3395 | "migrate"
3396 | "approve"
3397 | "checkpoint"
3398 | "escalate"
3399 | "observe"
3400 | "with"
3401 | "stages"
3402 | "thresholds"
3403 ) =>
3404 {
3405 depth += 1;
3406 self.advance();
3407 }
3408 TokenKind::Ident(_) if self.consumes_section_colon_block() => {
3409 depth += 1;
3410 self.advance();
3411 }
3412 _ => {
3413 self.advance();
3414 }
3415 }
3416 }
3417 }
3418
3419 fn consume_named_section_or_line(&mut self) {
3420 self.advance(); self.consume_section_or_line_after_name();
3422 }
3423
3424 fn consume_section_or_line_after_name(&mut self) {
3425 if matches!(self.peek_kind(), TokenKind::Colon) {
3426 self.advance();
3427 if matches!(self.peek_kind(), TokenKind::Newline) {
3428 self.skip_newlines();
3429 if matches!(self.peek_kind(), TokenKind::Indent) {
3430 self.consume_indented_payload();
3431 self.skip_newlines();
3432 if matches!(self.peek_kind(), TokenKind::End) {
3433 self.advance();
3434 }
3435 return;
3436 }
3437 }
3438 if matches!(
3439 self.peek_kind(),
3440 TokenKind::LBracket | TokenKind::LBrace | TokenKind::LParen
3441 ) {
3442 self.consume_balanced_group();
3443 self.consume_rest_of_line();
3444 return;
3445 }
3446 self.consume_rest_of_line();
3447 return;
3448 }
3449 self.consume_rest_of_line();
3450 if matches!(self.peek_kind(), TokenKind::Newline) {
3451 self.skip_newlines();
3452 if matches!(self.peek_kind(), TokenKind::Indent) {
3453 self.consume_indented_payload();
3454 self.skip_newlines();
3455 if matches!(self.peek_kind(), TokenKind::End) {
3456 self.advance();
3457 }
3458 }
3459 }
3460 }
3461
3462 fn consume_balanced_group(&mut self) {
3463 let (open, close) = match self.peek_kind() {
3464 TokenKind::LBracket => (TokenKind::LBracket, TokenKind::RBracket),
3465 TokenKind::LBrace => (TokenKind::LBrace, TokenKind::RBrace),
3466 TokenKind::LParen => (TokenKind::LParen, TokenKind::RParen),
3467 _ => return,
3468 };
3469 let mut depth = 0usize;
3470 while !self.at_end() {
3471 if std::mem::discriminant(self.peek_kind()) == std::mem::discriminant(&open) {
3472 depth += 1;
3473 self.advance();
3474 continue;
3475 }
3476 if std::mem::discriminant(self.peek_kind()) == std::mem::discriminant(&close) {
3477 self.advance();
3478 depth -= 1;
3479 if depth == 0 {
3480 break;
3481 }
3482 continue;
3483 }
3484 self.advance();
3485 }
3486 }
3487
3488 fn pattern_binding_name(pattern: &Pattern) -> Option<String> {
3489 match pattern {
3490 Pattern::Ident(name, _) => Some(name.clone()),
3491 Pattern::TypeCheck { name, .. } => Some(name.clone()),
3492 Pattern::Variant(_, Some(inner), _) => Self::pattern_binding_name(inner),
3493 Pattern::TupleDestructure { elements, .. }
3494 | Pattern::ListDestructure { elements, .. } => {
3495 elements.iter().find_map(Self::pattern_binding_name)
3496 }
3497 Pattern::RecordDestructure { fields, .. } => fields.iter().find_map(|(name, pat)| {
3498 pat.as_ref()
3499 .and_then(Self::pattern_binding_name)
3500 .or_else(|| Some(name.clone()))
3501 }),
3502 Pattern::Guard { inner, .. } => Self::pattern_binding_name(inner),
3503 Pattern::Or { patterns, .. } => patterns.iter().find_map(Self::pattern_binding_name),
3504 _ => None,
3505 }
3506 }
3507
3508 fn parse_variant_binding_candidate(&mut self) -> Result<Option<Box<Pattern>>, ParseError> {
3509 let mut binding = None;
3510 if !matches!(self.peek_kind(), TokenKind::RParen) {
3511 let save = self.pos;
3512 match self.parse_pattern() {
3513 Ok(pattern) => binding = Some(Box::new(pattern)),
3514 Err(_) => {
3515 self.pos = save;
3516 self.consume_variant_arg_tokens();
3517 }
3518 }
3519 while !matches!(self.peek_kind(), TokenKind::RParen | TokenKind::Eof) {
3520 if matches!(self.peek_kind(), TokenKind::Comma) {
3521 self.advance();
3522 if matches!(self.peek_kind(), TokenKind::RParen) {
3523 break;
3524 }
3525 }
3526 self.consume_variant_arg_tokens();
3527 }
3528 }
3529 Ok(binding)
3530 }
3531
3532 fn paren_looks_like_record_destructure(&self) -> bool {
3533 if !matches!(self.peek_kind(), TokenKind::LParen) {
3534 return false;
3535 }
3536 let mut i = self.pos + 1;
3537 let mut depth = 0usize;
3538 while let Some(tok) = self.tokens.get(i) {
3539 match tok.kind {
3540 TokenKind::LParen => depth += 1,
3541 TokenKind::RParen => {
3542 if depth == 0 {
3543 break;
3544 }
3545 depth -= 1;
3546 }
3547 TokenKind::Colon | TokenKind::DotDot | TokenKind::DotDotDot if depth == 0 => {
3548 return true;
3549 }
3550 _ => {}
3551 }
3552 i += 1;
3553 }
3554 false
3555 }
3556
3557 fn paren_contains_top_level_arrow(&self) -> bool {
3558 let mut i = self.pos;
3559 let mut depth = 1usize;
3561 while let Some(tok) = self.tokens.get(i) {
3562 match tok.kind {
3563 TokenKind::LParen => depth += 1,
3564 TokenKind::RParen => {
3565 depth -= 1;
3566 if depth == 0 {
3567 break;
3568 }
3569 }
3570 TokenKind::Arrow if depth == 1 => return true,
3571 _ => {}
3572 }
3573 i += 1;
3574 }
3575 false
3576 }
3577
3578 fn consume_variant_arg_tokens(&mut self) {
3579 let mut depth = 0usize;
3580 loop {
3581 match self.peek_kind() {
3582 TokenKind::LParen | TokenKind::LBracket | TokenKind::LBrace => {
3583 depth += 1;
3584 self.advance();
3585 }
3586 TokenKind::RParen | TokenKind::RBracket | TokenKind::RBrace => {
3587 if depth == 0 {
3588 break;
3589 }
3590 depth -= 1;
3591 self.advance();
3592 }
3593 TokenKind::Comma if depth == 0 => break,
3594 TokenKind::Eof => break,
3595 _ => {
3596 self.advance();
3597 }
3598 }
3599 }
3600 }
3601
3602 fn parse_optional_decl_name(&mut self) -> Result<Option<String>, ParseError> {
3603 if matches!(self.peek_kind(), TokenKind::Ident(_)) {
3604 return Ok(Some(self.expect_ident()?));
3605 }
3606 if matches!(self.peek_kind(), TokenKind::Lt) {
3607 self.advance(); let mut buf = String::new();
3610 while !matches!(self.peek_kind(), TokenKind::Gt | TokenKind::Eof) {
3611 buf.push_str(&format!("{}", self.current().kind));
3612 self.advance();
3613 }
3614 if matches!(self.peek_kind(), TokenKind::Gt) {
3615 self.advance();
3616 }
3617 if !buf.trim().is_empty() {
3618 return Ok(Some(buf.trim().to_string()));
3619 }
3620 }
3621 Ok(None)
3622 }
3623
3624 fn parse_assignment_target(&mut self) -> Result<String, ParseError> {
3625 let mut parts = Vec::new();
3626 match self.peek_kind().clone() {
3627 TokenKind::SelfKw => {
3628 self.advance();
3629 parts.push("self".to_string());
3630 }
3631 _ if Self::is_identifier_like(self.peek_kind()) => {
3632 parts.push(self.expect_ident()?);
3633 }
3634 _ => {
3635 let tok = self.current().clone();
3636 return Err(ParseError::Unexpected {
3637 found: format!("{}", tok.kind),
3638 expected: "assignment target".into(),
3639 line: tok.span.line,
3640 col: tok.span.col,
3641 });
3642 }
3643 }
3644
3645 while matches!(self.peek_kind(), TokenKind::Dot) {
3646 self.advance();
3647 parts.push(self.expect_ident()?);
3648 }
3649
3650 Ok(parts.join("."))
3651 }
3652
3653 fn parse_expr_stmt(&mut self) -> Result<Stmt, ParseError> {
3654 let expr = self.parse_expr(0)?;
3655 let mut span = expr.span();
3656 if matches!(self.peek_kind(), TokenKind::In) {
3657 self.advance();
3658 self.skip_newlines();
3659 if matches!(self.peek_kind(), TokenKind::Indent) {
3660 self.consume_indented_payload();
3661 self.skip_newlines();
3662 if matches!(self.peek_kind(), TokenKind::End) {
3663 span = span.merge(self.advance().span);
3664 }
3665 } else {
3666 self.consume_block_until_end();
3667 span = span.merge(self.current().span);
3668 }
3669 }
3670 Ok(Stmt::Expr(ExprStmt { expr, span }))
3671 }
3672
3673 fn is_assignment(&self) -> bool {
3675 let mut i = self.pos;
3676 if !matches!(self.tokens.get(i).map(|t| &t.kind), Some(k) if Self::is_identifier_like(k)) {
3677 return false;
3678 }
3679 i += 1;
3680 while matches!(self.tokens.get(i).map(|t| &t.kind), Some(TokenKind::Dot))
3681 && matches!(
3682 self.tokens.get(i + 1).map(|t| &t.kind),
3683 Some(TokenKind::Ident(_))
3684 )
3685 {
3686 i += 2;
3687 }
3688 matches!(self.tokens.get(i).map(|t| &t.kind), Some(TokenKind::Assign))
3689 }
3690
3691 fn parse_assign(&mut self) -> Result<Stmt, ParseError> {
3693 let start = self.tokens[self.pos].span;
3694 let name = self.parse_assignment_target()?;
3695 self.expect(&TokenKind::Assign)?;
3696 let value = self.parse_expr(0)?;
3697 let span = start.merge(value.span());
3698 Ok(Stmt::Assign(AssignStmt {
3699 target: name,
3700 value,
3701 span,
3702 }))
3703 }
3704
3705 fn parse_use_tool(&mut self) -> Result<UseToolDecl, ParseError> {
3708 let start = self.expect(&TokenKind::Use)?.span;
3709 self.expect(&TokenKind::Tool)?;
3710 let mcp_url = if matches!(self.peek_kind(), TokenKind::Ident(ref s) if s == "mcp") {
3712 self.advance();
3713 let url = self.expect_string()?;
3714 Some(url)
3715 } else {
3716 None
3717 };
3718 let tool_path = if mcp_url.is_none() {
3719 let mut path = self.parse_dotted_ident()?;
3720 if matches!(self.peek_kind(), TokenKind::At) {
3721 self.advance();
3722 let mut ver = String::new();
3723 while !matches!(
3724 self.peek_kind(),
3725 TokenKind::As | TokenKind::Newline | TokenKind::Eof
3726 ) {
3727 ver.push_str(&format!("{}", self.current().kind));
3728 self.advance();
3729 }
3730 if !ver.is_empty() {
3731 path = format!("{path}@{ver}");
3732 }
3733 }
3734 path
3735 } else {
3736 String::new()
3737 };
3738 self.expect(&TokenKind::As)?;
3739 let alias = if matches!(self.peek_kind(), TokenKind::Star) {
3740 self.advance();
3741 "__all__".to_string()
3742 } else {
3743 self.expect_ident()?
3744 };
3745 Ok(UseToolDecl {
3746 tool_path,
3747 alias,
3748 mcp_url,
3749 span: start,
3750 })
3751 }
3752
3753 fn parse_grant(&mut self) -> Result<GrantDecl, ParseError> {
3754 let start = self.expect(&TokenKind::Grant)?.span;
3755 let alias = self.parse_dotted_ident()?;
3756 let mut constraints = Vec::new();
3757 self.skip_newlines();
3758 let has_indent = matches!(self.peek_kind(), TokenKind::Indent);
3760 if has_indent {
3761 self.advance();
3762 self.skip_newlines();
3763 }
3764 while matches!(self.peek_kind(), TokenKind::Ident(_)) {
3765 let cs = self.current().span;
3766 let key = self.expect_ident()?;
3767 let value = self.parse_expr(0)?;
3768 constraints.push(GrantConstraint {
3769 key,
3770 value,
3771 span: cs,
3772 });
3773 self.consume_rest_of_line();
3774 self.skip_newlines();
3775 if !has_indent {
3776 break;
3777 } }
3779 if has_indent && matches!(self.peek_kind(), TokenKind::Dedent) {
3780 self.advance();
3781 }
3782 Ok(GrantDecl {
3783 tool_alias: alias,
3784 constraints,
3785 span: start,
3786 })
3787 }
3788
3789 fn parse_type(&mut self) -> Result<TypeExpr, ParseError> {
3792 let base = self.parse_base_type()?;
3793 if matches!(self.peek_kind(), TokenKind::Pipe | TokenKind::Ampersand) {
3795 let mut types = vec![base];
3796 while matches!(self.peek_kind(), TokenKind::Pipe | TokenKind::Ampersand) {
3797 self.advance();
3798 types.push(self.parse_base_type()?);
3799 }
3800 let span = types
3801 .first()
3802 .unwrap()
3803 .span()
3804 .merge(types.last().unwrap().span());
3805 Ok(TypeExpr::Union(types, span))
3806 } else {
3807 Ok(base)
3808 }
3809 }
3810
3811 fn parse_base_type(&mut self) -> Result<TypeExpr, ParseError> {
3812 let base = match self.peek_kind().clone() {
3813 TokenKind::Null => {
3814 let s = self.advance().span;
3815 Ok(TypeExpr::Null(s))
3816 }
3817 TokenKind::List => {
3818 let s = self.advance().span;
3819 self.expect(&TokenKind::LBracket)?;
3820 let inner = self.parse_type()?;
3821 self.expect(&TokenKind::RBracket)?;
3822 Ok(TypeExpr::List(Box::new(inner), s))
3823 }
3824 TokenKind::Map => {
3825 let s = self.advance().span;
3826 self.expect(&TokenKind::LBracket)?;
3827 let k = self.parse_type()?;
3828 self.expect(&TokenKind::Comma)?;
3829 let v = self.parse_type()?;
3830 self.expect(&TokenKind::RBracket)?;
3831 Ok(TypeExpr::Map(Box::new(k), Box::new(v), s))
3832 }
3833 TokenKind::Result => {
3834 let s = self.advance().span;
3835 self.expect(&TokenKind::LBracket)?;
3836 let ok = self.parse_type()?;
3837 self.expect(&TokenKind::Comma)?;
3838 let err = self.parse_type()?;
3839 self.expect(&TokenKind::RBracket)?;
3840 Ok(TypeExpr::Result(Box::new(ok), Box::new(err), s))
3841 }
3842 TokenKind::Set => {
3843 let s = self.advance().span;
3844 self.expect(&TokenKind::LBracket)?;
3845 let inner = self.parse_type()?;
3846 self.expect(&TokenKind::RBracket)?;
3847 Ok(TypeExpr::Set(Box::new(inner), s))
3848 }
3849 TokenKind::Tuple => {
3850 let s = self.advance().span;
3851 self.expect(&TokenKind::LBracket)?;
3852 let mut types = vec![self.parse_type()?];
3853 while matches!(self.peek_kind(), TokenKind::Comma) {
3854 self.advance();
3855 types.push(self.parse_type()?);
3856 }
3857 self.expect(&TokenKind::RBracket)?;
3858 Ok(TypeExpr::Tuple(types, s))
3859 }
3860 TokenKind::Fn => {
3861 let s = self.advance().span;
3862 self.expect(&TokenKind::LParen)?;
3863 let mut params = Vec::new();
3864 if !matches!(self.peek_kind(), TokenKind::RParen) {
3865 params.push(self.parse_type()?);
3866 while matches!(self.peek_kind(), TokenKind::Comma) {
3867 self.advance();
3868 params.push(self.parse_type()?);
3869 }
3870 }
3871 self.expect(&TokenKind::RParen)?;
3872 self.expect(&TokenKind::Arrow)?;
3873 let ret = self.parse_type()?;
3874 let effects = self.parse_optional_effect_row()?;
3875 Ok(TypeExpr::Fn(params, Box::new(ret), effects, s))
3876 }
3877 TokenKind::LParen => {
3878 let s = self.advance().span;
3880 let mut types = vec![self.parse_type()?];
3881 while matches!(self.peek_kind(), TokenKind::Comma) {
3882 self.advance();
3883 types.push(self.parse_type()?);
3884 }
3885 self.expect(&TokenKind::RParen)?;
3886 Ok(TypeExpr::Tuple(types, s))
3887 }
3888 TokenKind::Ident(_) => {
3889 let name = self.expect_ident()?;
3890 let span = self.current().span;
3891 if matches!(self.peek_kind(), TokenKind::LBracket) {
3893 self.advance(); let mut args = vec![self.parse_type()?];
3895 while matches!(self.peek_kind(), TokenKind::Comma) {
3896 self.advance();
3897 args.push(self.parse_type()?);
3898 }
3899 self.expect(&TokenKind::RBracket)?;
3900 Ok(TypeExpr::Generic(name, args, span))
3901 } else {
3902 Ok(TypeExpr::Named(name, span))
3903 }
3904 }
3905 TokenKind::String_ => {
3907 let s = self.advance().span;
3908 Ok(TypeExpr::Named("String".to_string(), s))
3909 }
3910 TokenKind::Int_ => {
3911 let s = self.advance().span;
3912 Ok(TypeExpr::Named("Int".to_string(), s))
3913 }
3914 TokenKind::Float_ => {
3915 let s = self.advance().span;
3916 Ok(TypeExpr::Named("Float".to_string(), s))
3917 }
3918 TokenKind::Bool => {
3919 let s = self.advance().span;
3920 Ok(TypeExpr::Named("Bool".to_string(), s))
3921 }
3922 TokenKind::Bytes => {
3923 let s = self.advance().span;
3924 Ok(TypeExpr::Named("Bytes".to_string(), s))
3925 }
3926 TokenKind::Json => {
3927 let s = self.advance().span;
3928 Ok(TypeExpr::Named("Json".to_string(), s))
3929 }
3930 TokenKind::Type => {
3931 let s = self.advance().span;
3932 if matches!(self.peek_kind(), TokenKind::LBracket) {
3933 self.advance();
3934 let mut args = vec![self.parse_type()?];
3935 while matches!(self.peek_kind(), TokenKind::Comma) {
3936 self.advance();
3937 args.push(self.parse_type()?);
3938 }
3939 self.expect(&TokenKind::RBracket)?;
3940 Ok(TypeExpr::Generic("type".into(), args, s))
3941 } else {
3942 Ok(TypeExpr::Named("type".to_string(), s))
3943 }
3944 }
3945 TokenKind::Comptime => {
3946 let s = self.advance().span;
3947 if matches!(self.peek_kind(), TokenKind::LBrace) {
3948 self.consume_balanced_group();
3949 }
3950 Ok(TypeExpr::Named("Any".to_string(), s))
3951 }
3952 _ => {
3953 let tok = self.current().clone();
3954 Err(ParseError::Unexpected {
3955 found: format!("{}", tok.kind),
3956 expected: "type".into(),
3957 line: tok.span.line,
3958 col: tok.span.col,
3959 })
3960 }
3961 }?;
3962
3963 if matches!(self.peek_kind(), TokenKind::Question) {
3965 let q_span = self.advance().span;
3966 let span = base.span().merge(q_span);
3967 Ok(TypeExpr::Union(vec![base, TypeExpr::Null(q_span)], span))
3968 } else {
3969 Ok(base)
3970 }
3971 }
3972
3973 fn parse_expr(&mut self, min_bp: u8) -> Result<Expr, ParseError> {
3976 let mut lhs = self.parse_prefix()?;
3977 let mut pending_continuation_dedents: usize = 0;
3978 loop {
3979 while pending_continuation_dedents > 0
3980 && matches!(self.peek_kind(), TokenKind::Newline | TokenKind::Dedent)
3981 {
3982 if matches!(self.peek_kind(), TokenKind::Dedent) {
3983 pending_continuation_dedents -= 1;
3984 }
3985 self.advance();
3986 }
3987 if matches!(
3988 self.peek_kind(),
3989 TokenKind::Newline | TokenKind::Indent | TokenKind::Dedent
3990 ) {
3991 let ws_start = self.pos;
3992 let mut i = self.pos;
3993 while matches!(
3994 self.tokens.get(i).map(|t| &t.kind),
3995 Some(TokenKind::Newline | TokenKind::Indent | TokenKind::Dedent)
3996 ) {
3997 i += 1;
3998 }
3999 if matches!(
4000 self.tokens.get(i).map(|t| &t.kind),
4001 Some(
4002 TokenKind::PipeForward
4003 | TokenKind::TildeArrow
4004 | TokenKind::Compose
4005 | TokenKind::RightShift
4006 | TokenKind::LeftShift
4007 | TokenKind::Dot
4008 | TokenKind::QuestionQuestion
4009 | TokenKind::Plus
4010 | TokenKind::Minus
4011 | TokenKind::Star
4012 | TokenKind::Slash
4013 | TokenKind::FloorDiv
4014 | TokenKind::Percent
4015 | TokenKind::Eq
4016 | TokenKind::NotEq
4017 | TokenKind::Lt
4018 | TokenKind::LtEq
4019 | TokenKind::Gt
4020 | TokenKind::GtEq
4021 | TokenKind::And
4022 | TokenKind::Or
4023 | TokenKind::In
4024 )
4025 ) {
4026 while self.pos < i {
4027 self.advance();
4028 }
4029 for tok in &self.tokens[ws_start..i] {
4030 match tok.kind {
4031 TokenKind::Indent => pending_continuation_dedents += 1,
4032 TokenKind::Dedent => {
4033 pending_continuation_dedents =
4034 pending_continuation_dedents.saturating_sub(1);
4035 }
4036 _ => {}
4037 }
4038 }
4039 }
4040 }
4041 let kind = self.peek_kind();
4042 let (op, bp) = match kind {
4043 TokenKind::Plus => (BinOp::Add, (22, 23)),
4044 TokenKind::Minus => (BinOp::Sub, (22, 23)),
4045 TokenKind::Star => (BinOp::Mul, (24, 25)),
4046 TokenKind::Slash => (BinOp::Div, (24, 25)),
4047 TokenKind::FloorDiv => (BinOp::FloorDiv, (24, 25)),
4048 TokenKind::Percent => (BinOp::Mod, (24, 25)),
4049 TokenKind::StarStar => (BinOp::Pow, (27, 26)), TokenKind::Eq => (BinOp::Eq, (14, 15)),
4051 TokenKind::NotEq => (BinOp::NotEq, (14, 15)),
4052 TokenKind::Lt => (BinOp::Lt, (14, 15)),
4053 TokenKind::LtEq => (BinOp::LtEq, (14, 15)),
4054 TokenKind::Gt => (BinOp::Gt, (14, 15)),
4055 TokenKind::GtEq => (BinOp::GtEq, (14, 15)),
4056 TokenKind::In => {
4057 if matches!(
4058 self.peek_n_kind(1),
4059 Some(TokenKind::Newline | TokenKind::Eof | TokenKind::Dedent)
4060 ) {
4061 break;
4062 }
4063 (BinOp::In, (14, 15))
4064 }
4065 TokenKind::Is => {
4067 if min_bp > 14 {
4068 break;
4069 }
4070 self.advance();
4071 let type_name = self.expect_type_name_for_is()?;
4072 let span = lhs.span().merge(self.current().span);
4073 lhs = Expr::IsType {
4074 expr: Box::new(lhs),
4075 type_name,
4076 span,
4077 };
4078 continue;
4079 }
4080 TokenKind::As => {
4082 if min_bp > 14 {
4083 break;
4084 }
4085 self.advance();
4086 let target_type = self.expect_type_name_for_is()?;
4087 let span = lhs.span().merge(self.current().span);
4088 lhs = Expr::TypeCast {
4089 expr: Box::new(lhs),
4090 target_type,
4091 span,
4092 };
4093 continue;
4094 }
4095 TokenKind::And => (BinOp::And, (12, 13)),
4096 TokenKind::Or => (BinOp::Or, (10, 11)),
4097 TokenKind::PlusPlus => (BinOp::Concat, (18, 19)),
4098 TokenKind::PipeForward | TokenKind::Compose | TokenKind::Step => {
4100 if min_bp > 16 {
4103 break;
4104 }
4105 self.advance();
4106 let rhs = self.parse_expr(17)?;
4107 let span = lhs.span().merge(rhs.span());
4108 lhs = Expr::Pipe {
4109 left: Box::new(lhs),
4110 right: Box::new(rhs),
4111 span,
4112 };
4113 continue;
4114 }
4115 TokenKind::TildeArrow => {
4117 if min_bp > 16 {
4118 break;
4119 }
4120 self.advance();
4121 let rhs = self.parse_expr(17)?;
4122 let span = lhs.span().merge(rhs.span());
4123 lhs = Expr::Illuminate {
4124 input: Box::new(lhs),
4125 transform: Box::new(rhs),
4126 span,
4127 };
4128 continue;
4129 }
4130 TokenKind::Ampersand => (BinOp::BitAnd, (14, 15)),
4131 TokenKind::Caret => (BinOp::BitXor, (14, 15)),
4132 TokenKind::LeftShift => (BinOp::Shl, (14, 15)),
4133 TokenKind::RightShift => (BinOp::Shr, (14, 15)),
4134 TokenKind::PlusAssign => (BinOp::Add, (2, 3)),
4135 TokenKind::MinusAssign => (BinOp::Sub, (2, 3)),
4136 TokenKind::StarAssign => (BinOp::Mul, (2, 3)),
4137 TokenKind::SlashAssign => (BinOp::Div, (2, 3)),
4138 TokenKind::FloorDivAssign => (BinOp::FloorDiv, (2, 3)),
4139 TokenKind::PercentAssign => (BinOp::Mod, (2, 3)),
4140 TokenKind::StarStarAssign => (BinOp::Pow, (2, 3)),
4141 TokenKind::AmpAssign => (BinOp::BitAnd, (2, 3)),
4142 TokenKind::PipeAssign => (BinOp::BitOr, (2, 3)),
4143 TokenKind::CaretAssign => (BinOp::BitXor, (2, 3)),
4144 TokenKind::QuestionQuestion => {
4146 if min_bp > 8 {
4147 break;
4148 }
4149 self.advance();
4150 let rhs = self.parse_expr(9)?;
4151 let span = lhs.span().merge(rhs.span());
4152 lhs = Expr::NullCoalesce(Box::new(lhs), Box::new(rhs), span);
4153 continue;
4154 }
4155 TokenKind::DotDot => {
4157 if min_bp > 20 {
4158 break;
4159 }
4160 self.advance();
4161 let rhs = if matches!(
4162 self.peek_kind(),
4163 TokenKind::Newline
4164 | TokenKind::Eof
4165 | TokenKind::RBracket
4166 | TokenKind::RParen
4167 | TokenKind::Comma
4168 ) {
4169 None
4170 } else {
4171 Some(Box::new(self.parse_expr(21)?))
4172 };
4173 let span = lhs
4174 .span()
4175 .merge(rhs.as_ref().map(|r| r.span()).unwrap_or(lhs.span()));
4176 lhs = Expr::RangeExpr {
4177 start: Some(Box::new(lhs)),
4178 end: rhs,
4179 inclusive: false,
4180 step: None,
4181 span,
4182 };
4183 continue;
4184 }
4185 TokenKind::DotDotEq => {
4186 if min_bp > 20 {
4187 break;
4188 }
4189 self.advance();
4190 let rhs = self.parse_expr(21)?;
4191 let span = lhs.span().merge(rhs.span());
4192 lhs = Expr::RangeExpr {
4193 start: Some(Box::new(lhs)),
4194 end: Some(Box::new(rhs)),
4195 inclusive: true,
4196 step: None,
4197 span,
4198 };
4199 continue;
4200 }
4201 TokenKind::Dot => {
4203 if min_bp > 32 {
4204 break;
4205 }
4206 self.advance();
4207 let field = match self.peek_kind().clone() {
4208 TokenKind::IntLit(n) => {
4209 self.advance();
4210 n.to_string()
4211 }
4212 _ => self.expect_ident()?,
4213 };
4214 let span = lhs.span().merge(self.current().span);
4215 lhs = Expr::DotAccess(Box::new(lhs), field, span);
4216 continue;
4217 }
4218 TokenKind::QuestionDot => {
4219 if min_bp > 32 {
4220 break;
4221 }
4222 self.advance();
4223 let field = self.expect_ident()?;
4224 let span = lhs.span().merge(self.current().span);
4225 lhs = Expr::NullSafeAccess(Box::new(lhs), field, span);
4226 continue;
4227 }
4228 TokenKind::QuestionBracket => {
4229 if min_bp > 32 {
4230 break;
4231 }
4232 self.advance(); let idx = self.parse_expr(0)?;
4234 self.expect(&TokenKind::RBracket)?;
4235 let span = lhs.span().merge(self.current().span);
4236 lhs = Expr::NullSafeIndex(Box::new(lhs), Box::new(idx), span);
4237 continue;
4238 }
4239 TokenKind::LBracket => {
4240 if min_bp > 32 {
4241 break;
4242 }
4243 self.advance();
4244 if matches!(self.peek_kind(), TokenKind::RBracket) {
4245 self.expect(&TokenKind::RBracket)?;
4246 let span = lhs.span().merge(self.current().span);
4247 lhs =
4248 Expr::IndexAccess(Box::new(lhs), Box::new(Expr::IntLit(0, span)), span);
4249 continue;
4250 }
4251 let idx = self.parse_expr(0)?;
4252 if matches!(self.peek_kind(), TokenKind::Comma) {
4253 let mut args = vec![CallArg::Positional(idx)];
4254 while matches!(self.peek_kind(), TokenKind::Comma) {
4255 self.advance();
4256 if matches!(self.peek_kind(), TokenKind::RBracket) {
4257 break;
4258 }
4259 args.push(CallArg::Positional(self.parse_expr(0)?));
4260 }
4261 self.expect(&TokenKind::RBracket)?;
4262 let span = lhs.span().merge(self.current().span);
4263 lhs = Expr::Call(Box::new(lhs), args, span);
4264 continue;
4265 }
4266 self.expect(&TokenKind::RBracket)?;
4267 let span = lhs.span().merge(self.current().span);
4268 lhs = Expr::IndexAccess(Box::new(lhs), Box::new(idx), span);
4269 continue;
4270 }
4271 TokenKind::LParen => {
4272 if min_bp > 32 {
4273 break;
4274 }
4275 lhs = self.parse_call(lhs)?;
4276 continue;
4277 }
4278 TokenKind::Question => {
4279 if min_bp > 32 {
4280 break;
4281 }
4282 let span = lhs.span().merge(self.advance().span);
4283 lhs = Expr::TryExpr(Box::new(lhs), span);
4284 continue;
4285 }
4286 TokenKind::Bang => {
4287 if min_bp > 32 {
4288 break;
4289 }
4290 let span = lhs.span().merge(self.advance().span);
4291 lhs = Expr::NullAssert(Box::new(lhs), span);
4292 continue;
4293 }
4294 TokenKind::Expect => {
4295 if min_bp > 1 {
4296 break;
4297 }
4298 self.advance();
4299 self.expect(&TokenKind::Schema)?;
4300 let schema_name = self.expect_ident()?;
4301 let span = lhs.span().merge(self.current().span);
4302 lhs = Expr::ExpectSchema(Box::new(lhs), schema_name, span);
4303 continue;
4304 }
4305 TokenKind::At => {
4306 if min_bp > 32 {
4307 break;
4308 }
4309 self.advance();
4310 let _ = self.expect_ident();
4311 if matches!(self.peek_kind(), TokenKind::LParen) {
4312 self.consume_parenthesized();
4313 }
4314 continue;
4315 }
4316 _ => break,
4317 };
4318 let (l_bp, r_bp) = bp;
4319 if l_bp < min_bp {
4320 break;
4321 }
4322 self.advance();
4323 let rhs = self.parse_expr(r_bp)?;
4324 let span = lhs.span().merge(rhs.span());
4325 lhs = Expr::BinOp(Box::new(lhs), op, Box::new(rhs), span);
4326 }
4327 Ok(lhs)
4328 }
4329
4330 fn parse_prefix(&mut self) -> Result<Expr, ParseError> {
4331 match self.peek_kind().clone() {
4332 TokenKind::IntLit(n) => {
4333 let s = self.advance().span;
4334 Ok(Expr::IntLit(n, s))
4335 }
4336 TokenKind::FloatLit(n) => {
4337 let s = self.advance().span;
4338 Ok(Expr::FloatLit(n, s))
4339 }
4340 TokenKind::StringLit(ref sv) => {
4341 let sv = sv.clone();
4342 let s = self.advance().span;
4343 Ok(Expr::StringLit(sv, s))
4344 }
4345 TokenKind::Symbol('\'') => {
4346 let s = self.advance().span;
4347 let mut buf = String::new();
4348 while !matches!(self.peek_kind(), TokenKind::Symbol('\'') | TokenKind::Eof) {
4349 if !buf.is_empty() {
4350 buf.push(' ');
4351 }
4352 buf.push_str(&format!("{}", self.current().kind));
4353 self.advance();
4354 }
4355 let end = if matches!(self.peek_kind(), TokenKind::Symbol('\'')) {
4356 self.advance().span
4357 } else {
4358 s
4359 };
4360 Ok(Expr::StringLit(buf, s.merge(end)))
4361 }
4362 TokenKind::RawStringLit(ref sv) => {
4363 let sv = sv.clone();
4364 let s = self.advance().span;
4365 Ok(Expr::RawStringLit(sv, s))
4366 }
4367 TokenKind::BytesLit(ref bv) => {
4368 let bv = bv.clone();
4369 let s = self.advance().span;
4370 Ok(Expr::BytesLit(bv, s))
4371 }
4372 TokenKind::NullLit => {
4373 let s = self.advance().span;
4374 Ok(Expr::NullLit(s))
4375 }
4376 TokenKind::StringInterpLit(ref segments) => {
4377 let segments = segments.clone();
4378 let span = self.advance().span;
4379 let mut ast_segments = Vec::new();
4380 for (is_expr, text) in segments {
4381 if is_expr {
4382 let mut lexer =
4390 crate::compiler::lexer::Lexer::new(&text, span.line, span.col);
4391 let tokens = lexer.tokenize().map_err(|e| ParseError::Unexpected {
4392 found: format!("lexer error: {}", e),
4393 expected: "expression".into(),
4394 line: span.line,
4395 col: span.col,
4396 })?;
4397 let mut parser = Parser::new(tokens);
4398 let expr = parser.parse_expr(0)?;
4399 ast_segments.push(StringSegment::Interpolation(Box::new(expr)));
4400 } else {
4401 ast_segments.push(StringSegment::Literal(text));
4402 }
4403 }
4404 Ok(Expr::StringInterp(ast_segments, span))
4405 }
4406 TokenKind::BoolLit(b) => {
4407 let s = self.advance().span;
4408 Ok(Expr::BoolLit(b, s))
4409 }
4410 TokenKind::Null => {
4411 let s = self.advance().span;
4412 Ok(Expr::NullLit(s))
4413 }
4414 TokenKind::Minus => {
4415 let s = self.advance().span;
4416 let expr = self.parse_expr(28)?; let span = s.merge(expr.span());
4418 Ok(Expr::UnaryOp(UnaryOp::Neg, Box::new(expr), span))
4419 }
4420 TokenKind::Not => {
4421 let s = self.advance().span;
4422 let expr = self.parse_expr(28)?;
4423 let span = s.merge(expr.span());
4424 Ok(Expr::UnaryOp(UnaryOp::Not, Box::new(expr), span))
4425 }
4426 TokenKind::Tilde => {
4427 let s = self.advance().span;
4428 let expr = self.parse_expr(28)?;
4429 let span = s.merge(expr.span());
4430 Ok(Expr::UnaryOp(UnaryOp::BitNot, Box::new(expr), span))
4431 }
4432 TokenKind::DotDotDot => {
4433 let s = self.advance().span;
4434 if matches!(
4435 self.peek_kind(),
4436 TokenKind::RBracket | TokenKind::RParen | TokenKind::RBrace | TokenKind::Comma
4437 ) {
4438 return Ok(Expr::Ident("...".into(), s));
4439 }
4440 let expr = self.parse_expr(0)?;
4441 let span = s.merge(expr.span());
4442 Ok(Expr::SpreadExpr(Box::new(expr), span))
4443 }
4444 TokenKind::DotDot => {
4445 let s = self.advance().span;
4446 if matches!(
4447 self.peek_kind(),
4448 TokenKind::RBracket | TokenKind::RParen | TokenKind::RBrace | TokenKind::Comma
4449 ) {
4450 return Ok(Expr::Ident("..".into(), s));
4451 }
4452 let expr = self.parse_expr(28)?;
4453 let span = s.merge(expr.span());
4454 Ok(Expr::SpreadExpr(Box::new(expr), span))
4455 }
4456 TokenKind::Await => {
4457 let s = self.advance().span;
4458 let expr = self.parse_expr(0)?;
4459 let expr = self.rewrite_await_orchestration(expr)?;
4460 let span = s.merge(expr.span());
4461 Ok(Expr::AwaitExpr(Box::new(expr), span))
4462 }
4463 TokenKind::Fn => self.parse_lambda(),
4464 TokenKind::Parallel => {
4465 let s = self.advance().span;
4466 Ok(Expr::Ident("parallel".into(), s))
4467 }
4468 TokenKind::Match => {
4469 let stmt = self.parse_match()?;
4471 if let Stmt::Match(ms) = stmt {
4472 let span = ms.span;
4473 Ok(Expr::MatchExpr {
4474 subject: Box::new(ms.subject),
4475 arms: ms.arms,
4476 span,
4477 })
4478 } else {
4479 let span = stmt.span();
4480 Ok(Expr::BlockExpr(vec![stmt], span))
4481 }
4482 }
4483 TokenKind::If => {
4484 let stmt = self.parse_if()?;
4486 let span = stmt.span();
4487 Ok(Expr::BlockExpr(vec![stmt], span))
4488 }
4489 TokenKind::When => {
4490 let s = self.advance().span;
4491 self.skip_newlines();
4492 self.consume_block_until_end();
4493 Ok(Expr::Ident("when_expr".into(), s))
4494 }
4495 TokenKind::Loop => {
4496 let stmt = self.parse_loop()?;
4498 let span = stmt.span();
4499 Ok(Expr::BlockExpr(vec![stmt], span))
4500 }
4501 TokenKind::Let => {
4502 let stmt = self.parse_let()?;
4504 let span = stmt.span();
4505 Ok(Expr::BlockExpr(vec![stmt], span))
4506 }
4507 TokenKind::Try => {
4508 let s = self.advance().span;
4509 let inner = self.parse_expr(0)?;
4510 let span = s.merge(inner.span());
4511 Ok(Expr::TryExpr(Box::new(inner), span))
4512 }
4513 TokenKind::Async => {
4514 let s = self.advance().span;
4515 if matches!(self.peek_kind(), TokenKind::Newline | TokenKind::Indent) {
4517 self.skip_newlines();
4518 let block = self.parse_block()?;
4519 let end_span = if matches!(self.peek_kind(), TokenKind::End) {
4520 self.advance().span
4521 } else {
4522 s
4523 };
4524 Ok(Expr::BlockExpr(block, s.merge(end_span)))
4525 } else if !matches!(
4526 self.peek_kind(),
4527 TokenKind::RParen
4528 | TokenKind::RBracket
4529 | TokenKind::RBrace
4530 | TokenKind::Comma
4531 | TokenKind::Eof
4532 ) {
4533 let inner = self.parse_expr(0)?;
4534 let span = s.merge(inner.span());
4535 Ok(Expr::AwaitExpr(Box::new(inner), span))
4536 } else {
4537 Ok(Expr::BlockExpr(vec![], s))
4538 }
4539 }
4540 TokenKind::Comptime => {
4541 let s = self.advance().span;
4542 if matches!(self.peek_kind(), TokenKind::LBrace) {
4543 self.consume_balanced_group();
4544 } else {
4545 self.consume_rest_of_line();
4546 }
4547 Ok(Expr::Ident("comptime".into(), s))
4548 }
4549 TokenKind::Use => {
4550 let s = self.advance().span;
4551 Ok(Expr::Ident("use".into(), s))
4552 }
4553 TokenKind::Halt => {
4554 let s = self.advance().span;
4555 Ok(Expr::Ident("halt".into(), s))
4556 }
4557 TokenKind::Cell => {
4558 let s = self.advance().span;
4559 Ok(Expr::Ident("cell".into(), s))
4560 }
4561 TokenKind::End => {
4562 let s = self.advance().span;
4563 Ok(Expr::Ident("end".into(), s))
4564 }
4565 TokenKind::Dot => {
4566 let s = self.advance().span;
4567 let name = self.expect_ident()?;
4568 let mut expr = Expr::Ident(format!(".{name}"), s);
4569 if matches!(self.peek_kind(), TokenKind::LParen) {
4570 expr = self.parse_call(expr)?;
4571 }
4572 Ok(expr)
4573 }
4574 TokenKind::Set => {
4575 let s = self.advance().span;
4576 self.expect(&TokenKind::LBracket)?;
4577 self.bracket_depth += 1;
4578 self.skip_whitespace_tokens();
4579 if matches!(self.peek_kind(), TokenKind::RBracket) {
4580 self.bracket_depth -= 1;
4581 let end = self.expect(&TokenKind::RBracket)?.span;
4582 return Ok(Expr::SetLit(vec![], s.merge(end)));
4583 }
4584 let first = self.parse_expr(0)?;
4585 self.skip_whitespace_tokens();
4586 if matches!(self.peek_kind(), TokenKind::For) {
4587 self.advance();
4588 let var = self.expect_ident()?;
4589 self.expect(&TokenKind::In)?;
4590 let iter = self.parse_expr(0)?;
4591 while matches!(self.peek_kind(), TokenKind::For) {
4592 self.advance();
4593 let _ = self.expect_ident()?;
4594 self.expect(&TokenKind::In)?;
4595 let _ = self.parse_expr(0)?;
4596 }
4597 let condition = if matches!(self.peek_kind(), TokenKind::If) {
4598 self.advance();
4599 Some(Box::new(self.parse_expr(0)?))
4600 } else {
4601 None
4602 };
4603 self.skip_whitespace_tokens();
4604 self.bracket_depth -= 1;
4605 let end = self.expect(&TokenKind::RBrace)?.span;
4606 return Ok(Expr::Comprehension {
4607 body: Box::new(first),
4608 var,
4609 iter: Box::new(iter),
4610 condition,
4611 kind: ComprehensionKind::Set,
4612 span: s.merge(end),
4613 });
4614 }
4615 let mut elems = vec![first];
4616 while matches!(self.peek_kind(), TokenKind::Comma) {
4617 self.advance();
4618 self.skip_whitespace_tokens();
4619 if matches!(self.peek_kind(), TokenKind::RBrace) {
4620 break;
4621 }
4622 elems.push(self.parse_expr(0)?);
4623 self.skip_whitespace_tokens();
4624 }
4625 self.bracket_depth -= 1;
4626 let end = self.expect(&TokenKind::RBrace)?.span;
4627 Ok(Expr::SetLit(elems, s.merge(end)))
4628 }
4629 TokenKind::LParen => {
4630 let s = self.advance().span;
4631 if matches!(self.peek_kind(), TokenKind::RParen) {
4633 let end = self.advance().span;
4635 return Ok(Expr::TupleLit(vec![], s.merge(end)));
4636 }
4637 let first = self.parse_expr(0)?;
4638 if matches!(self.peek_kind(), TokenKind::Comma) {
4639 let mut elems = vec![first];
4641 while matches!(self.peek_kind(), TokenKind::Comma) {
4642 self.advance();
4643 if matches!(self.peek_kind(), TokenKind::RParen) {
4644 break;
4645 }
4646 elems.push(self.parse_expr(0)?);
4647 }
4648 let end = self.expect(&TokenKind::RParen)?.span;
4649 Ok(Expr::TupleLit(elems, s.merge(end)))
4650 } else {
4651 self.expect(&TokenKind::RParen)?;
4653 Ok(first)
4654 }
4655 }
4656 TokenKind::LBracket => self.parse_list_or_comprehension(),
4657 TokenKind::LBrace => self.parse_map_lit(),
4658 TokenKind::Role => self.parse_role_block_expr(),
4659 TokenKind::Ok_ => {
4660 let s = self.advance().span;
4661 Ok(Expr::Ident("ok".into(), s))
4662 }
4663 TokenKind::Err_ => {
4664 let s = self.advance().span;
4665 Ok(Expr::Ident("err".into(), s))
4666 }
4667 TokenKind::SelfKw => {
4668 let s = self.advance().span;
4669 Ok(Expr::Ident("self".into(), s))
4670 }
4671 TokenKind::Ident(_) => {
4672 let start = self.current().span;
4673 let name = self.expect_ident()?;
4674 if name == "agent" {
4675 return self.parse_expr(28);
4676 }
4677 if name == "confirm" {
4678 let arg = self.parse_expr(28)?;
4679 let span = start.merge(arg.span());
4680 return Ok(Expr::Call(
4681 Box::new(Expr::Ident(name, start)),
4682 vec![CallArg::Positional(arg)],
4683 span,
4684 ));
4685 }
4686 let span = self.current().span;
4687 Ok(Expr::Ident(name, span))
4688 }
4689 TokenKind::String_ => {
4691 let s = self.advance().span;
4692 Ok(Expr::Ident("string".into(), s))
4693 }
4694 TokenKind::Int_ => {
4695 let s = self.advance().span;
4696 Ok(Expr::Ident("int".into(), s))
4697 }
4698 TokenKind::Float_ => {
4699 let s = self.advance().span;
4700 Ok(Expr::Ident("float".into(), s))
4701 }
4702 TokenKind::Bool => {
4703 let s = self.advance().span;
4704 Ok(Expr::Ident("bool".into(), s))
4705 }
4706 TokenKind::Bytes => {
4707 let s = self.advance().span;
4708 Ok(Expr::Ident("bytes".into(), s))
4709 }
4710 TokenKind::Json => {
4711 let s = self.advance().span;
4712 Ok(Expr::Ident("json".into(), s))
4713 }
4714 TokenKind::List => {
4715 let s = self.advance().span;
4716 Ok(Expr::Ident("list".into(), s))
4717 }
4718 TokenKind::Map => {
4719 let s = self.advance().span;
4720 Ok(Expr::Ident("map".into(), s))
4721 }
4722 TokenKind::Type => {
4723 let s = self.advance().span;
4724 Ok(Expr::Ident("type".into(), s))
4725 }
4726 TokenKind::Result => {
4727 let s = self.advance().span;
4728 Ok(Expr::Ident("result".into(), s))
4729 }
4730 TokenKind::Tool => {
4731 let s = self.advance().span;
4732 Ok(Expr::Ident("tool".into(), s))
4733 }
4734 TokenKind::Schema => {
4735 let s = self.advance().span;
4736 Ok(Expr::Ident("schema".into(), s))
4737 }
4738 _ => {
4739 let tok = self.current().clone();
4740 Err(ParseError::Unexpected {
4741 found: format!("{}", tok.kind),
4742 expected: "expression".into(),
4743 line: tok.span.line,
4744 col: tok.span.col,
4745 })
4746 }
4747 }
4748 }
4749
4750 fn parse_lambda(&mut self) -> Result<Expr, ParseError> {
4751 let start = self.expect(&TokenKind::Fn)?.span;
4752 self.expect(&TokenKind::LParen)?;
4753 let mut params = Vec::new();
4754 while !matches!(self.peek_kind(), TokenKind::RParen) {
4755 if !params.is_empty() {
4756 self.expect(&TokenKind::Comma)?;
4757 }
4758 let ps = self.current().span;
4759 let pname = if matches!(self.peek_kind(), TokenKind::LParen) {
4760 self.consume_balanced_group();
4761 format!("__arg{}", params.len())
4762 } else {
4763 self.expect_ident()?
4764 };
4765 let pty = if matches!(self.peek_kind(), TokenKind::Colon) {
4766 self.advance();
4767 self.parse_type()?
4768 } else {
4769 TypeExpr::Named("Any".into(), ps)
4770 };
4771 params.push(Param {
4772 name: pname,
4773 ty: pty,
4774 default_value: None,
4775 variadic: false,
4776 span: ps,
4777 });
4778 }
4779 self.expect(&TokenKind::RParen)?;
4780 let return_type = if matches!(self.peek_kind(), TokenKind::Arrow) {
4781 self.advance();
4782 Some(Box::new(self.parse_type()?))
4783 } else {
4784 None
4785 };
4786 let body = if matches!(self.peek_kind(), TokenKind::FatArrow) {
4787 self.advance();
4788 self.skip_whitespace_tokens();
4789 let expr = self.parse_expr(0)?;
4790 LambdaBody::Expr(Box::new(expr))
4791 } else {
4792 self.skip_newlines();
4793 let stmts = self.parse_block()?;
4794 self.expect(&TokenKind::End)?;
4795 LambdaBody::Block(stmts)
4796 };
4797 let end_span = match &body {
4798 LambdaBody::Expr(e) => e.span(),
4799 LambdaBody::Block(stmts) => stmts.last().map(|s| s.span()).unwrap_or(start),
4800 };
4801 Ok(Expr::Lambda {
4802 params,
4803 return_type,
4804 body,
4805 span: start.merge(end_span),
4806 })
4807 }
4808
4809 fn parse_list_or_comprehension(&mut self) -> Result<Expr, ParseError> {
4810 let start = self.expect(&TokenKind::LBracket)?.span;
4811 self.bracket_depth += 1;
4812 self.skip_whitespace_tokens();
4813 if matches!(self.peek_kind(), TokenKind::RBracket) {
4814 self.bracket_depth -= 1;
4815 let end = self.expect(&TokenKind::RBracket)?.span;
4816 return Ok(Expr::ListLit(vec![], start.merge(end)));
4817 }
4818 let first = self.parse_expr(0)?;
4820 self.skip_whitespace_tokens();
4821 if matches!(self.peek_kind(), TokenKind::For) {
4823 self.advance();
4824 let var = if matches!(self.peek_kind(), TokenKind::LParen) {
4825 self.advance();
4826 let first = self.expect_ident()?;
4827 while !matches!(self.peek_kind(), TokenKind::RParen | TokenKind::Eof) {
4828 self.advance();
4829 }
4830 if matches!(self.peek_kind(), TokenKind::RParen) {
4831 self.advance();
4832 }
4833 first
4834 } else {
4835 self.expect_ident()?
4836 };
4837 self.expect(&TokenKind::In)?;
4838 let iter = self.parse_expr(0)?;
4839 self.skip_whitespace_tokens();
4840 while matches!(self.peek_kind(), TokenKind::For) {
4841 self.advance();
4842 if matches!(self.peek_kind(), TokenKind::LParen) {
4843 self.advance();
4844 while !matches!(self.peek_kind(), TokenKind::RParen | TokenKind::Eof) {
4845 self.advance();
4846 }
4847 if matches!(self.peek_kind(), TokenKind::RParen) {
4848 self.advance();
4849 }
4850 } else {
4851 let _ = self.expect_ident()?;
4852 }
4853 self.expect(&TokenKind::In)?;
4854 let _ = self.parse_expr(0)?;
4855 self.skip_whitespace_tokens();
4856 }
4857 let condition = if matches!(self.peek_kind(), TokenKind::If) {
4858 self.advance();
4859 Some(Box::new(self.parse_expr(0)?))
4860 } else {
4861 None
4862 };
4863 self.skip_whitespace_tokens();
4864 self.bracket_depth -= 1;
4865 let end = self.expect(&TokenKind::RBracket)?.span;
4866 return Ok(Expr::Comprehension {
4867 body: Box::new(first),
4868 var,
4869 iter: Box::new(iter),
4870 condition,
4871 kind: ComprehensionKind::List,
4872 span: start.merge(end),
4873 });
4874 }
4875 let mut elems = vec![first];
4877 while matches!(self.peek_kind(), TokenKind::Comma) {
4878 self.advance();
4879 self.skip_whitespace_tokens();
4880 if matches!(self.peek_kind(), TokenKind::RBracket) {
4881 break;
4882 }
4883 elems.push(self.parse_expr(0)?);
4884 self.skip_whitespace_tokens();
4885 }
4886 self.bracket_depth -= 1;
4887 let end = self.expect(&TokenKind::RBracket)?.span;
4888 Ok(Expr::ListLit(elems, start.merge(end)))
4889 }
4890
4891 fn parse_call(&mut self, callee: Expr) -> Result<Expr, ParseError> {
4892 let start = callee.span();
4893 self.expect(&TokenKind::LParen)?;
4894 self.bracket_depth += 1;
4895 let mut args = Vec::new();
4896 while !matches!(self.peek_kind(), TokenKind::RParen) {
4897 self.skip_whitespace_tokens();
4898 if matches!(self.peek_kind(), TokenKind::RParen) {
4899 break;
4900 }
4901 if !args.is_empty() {
4902 self.expect(&TokenKind::Comma)?;
4903 self.skip_whitespace_tokens();
4904 }
4905 if matches!(self.peek_kind(), TokenKind::Schema) {
4906 let ks = self.advance().span;
4907 self.skip_whitespace_tokens();
4908 if matches!(self.peek_kind(), TokenKind::Colon) {
4909 self.advance();
4910 self.skip_whitespace_tokens();
4911 }
4912 let val = self.parse_expr(28)?;
4913 let span = ks.merge(val.span());
4914 args.push(CallArg::Named("schema".into(), val, span));
4915 self.skip_whitespace_tokens();
4916 continue;
4917 }
4918 if matches!(self.peek_kind(), TokenKind::Role)
4920 && !matches!(self.peek_n_kind(1), Some(TokenKind::Colon))
4921 {
4922 self.advance();
4923 let role_span = self.current().span;
4924 let role_name = self.expect_ident()?;
4925 self.expect(&TokenKind::Colon)?;
4926
4927 if matches!(self.peek_kind(), TokenKind::Newline) {
4928 while matches!(self.peek_kind(), TokenKind::Newline) {
4929 self.advance();
4930 }
4931 }
4932 let has_indent = matches!(self.peek_kind(), TokenKind::Indent);
4933 let role_terminators: &[TokenKind] = if has_indent {
4934 &[TokenKind::RParen]
4935 } else {
4936 &[TokenKind::Comma, TokenKind::RParen]
4937 };
4938 let content_expr = self.parse_role_content(role_terminators, has_indent)?;
4939 if has_indent && matches!(self.peek_kind(), TokenKind::End) {
4940 self.advance();
4941 }
4942
4943 let span = role_span.merge(content_expr.span());
4944 args.push(CallArg::Role(role_name, content_expr, span));
4945 continue;
4946 }
4947 if self.token_can_be_named_arg_key() {
4948 let save = self.pos;
4950 let name_clone = self.expect_ident()?;
4951 if matches!(self.peek_kind(), TokenKind::Colon) {
4952 self.advance();
4953 self.skip_whitespace_tokens();
4954 let val = self.parse_expr(0)?;
4955 let span = val.span();
4956 args.push(CallArg::Named(name_clone, val, span));
4957 } else {
4958 let is_record_ctor =
4962 matches!(&callee, Expr::Ident(n, _) if n.starts_with(char::is_uppercase));
4963 if is_record_ctor
4964 && matches!(
4965 self.peek_kind(),
4966 TokenKind::Comma | TokenKind::RParen | TokenKind::Newline
4967 )
4968 {
4969 let span = self.tokens[save].span;
4970 args.push(CallArg::Named(
4971 name_clone.clone(),
4972 Expr::Ident(name_clone, span),
4973 span,
4974 ));
4975 } else {
4976 self.pos = save;
4977 let expr = self.parse_expr(0)?;
4978 args.push(CallArg::Positional(expr));
4979 }
4980 }
4981 } else {
4982 let expr = self.parse_expr(0)?;
4983 args.push(CallArg::Positional(expr));
4984 }
4985 self.skip_whitespace_tokens();
4986 }
4987 self.bracket_depth -= 1;
4988 let end = self.expect(&TokenKind::RParen)?.span;
4989
4990 Ok(Expr::Call(Box::new(callee), args, start.merge(end)))
4991 }
4992
4993 fn parse_map_lit(&mut self) -> Result<Expr, ParseError> {
4994 let start = self.expect(&TokenKind::LBrace)?.span;
4995 self.bracket_depth += 1;
4996 self.skip_whitespace_tokens();
4997
4998 if matches!(self.peek_kind(), TokenKind::RBrace) {
5000 self.bracket_depth -= 1;
5001 let end = self.expect(&TokenKind::RBrace)?.span;
5002 return Ok(Expr::MapLit(vec![], start.merge(end)));
5003 }
5004
5005 if matches!(self.peek_kind(), TokenKind::DotDot | TokenKind::DotDotDot) {
5007 let spread_span = self.advance().span;
5008 let spread_expr = self.parse_expr(0)?;
5009 let mut pairs = vec![(Expr::StringLit("__spread".into(), spread_span), spread_expr)];
5010 self.skip_whitespace_tokens();
5011
5012 while matches!(self.peek_kind(), TokenKind::Comma) {
5013 self.advance();
5014 self.skip_whitespace_tokens();
5015 if matches!(self.peek_kind(), TokenKind::RBrace) {
5016 break;
5017 }
5018 if matches!(self.peek_kind(), TokenKind::DotDot | TokenKind::DotDotDot) {
5019 let spread_span = self.advance().span;
5020 let spread_expr = self.parse_expr(0)?;
5021 pairs.push((Expr::StringLit("__spread".into(), spread_span), spread_expr));
5022 } else {
5023 let key = if let TokenKind::Ident(name) = self.peek_kind().clone() {
5024 if matches!(
5025 self.tokens.get(self.pos + 1).map(|t| &t.kind),
5026 Some(TokenKind::Colon)
5027 ) {
5028 let span = self.current().span;
5029 self.advance();
5030 Expr::StringLit(name, span)
5031 } else {
5032 self.parse_expr(0)?
5033 }
5034 } else {
5035 self.parse_expr(0)?
5036 };
5037 self.expect(&TokenKind::Colon)?;
5038 self.skip_whitespace_tokens();
5039 let val = self.parse_expr(0)?;
5040 pairs.push((key, val));
5041 }
5042 self.skip_whitespace_tokens();
5043 }
5044
5045 self.bracket_depth -= 1;
5046 let end = self.expect(&TokenKind::RBrace)?.span;
5047 return Ok(Expr::MapLit(pairs, start.merge(end)));
5048 }
5049
5050 let first = self.parse_expr(0)?;
5052 self.skip_whitespace_tokens();
5053
5054 match self.peek_kind() {
5056 TokenKind::For => {
5057 self.advance();
5059 let var = self.expect_ident()?;
5060 self.expect(&TokenKind::In)?;
5061 let iter = self.parse_expr(0)?;
5062 while matches!(self.peek_kind(), TokenKind::For) {
5063 self.advance();
5064 let _ = self.expect_ident()?;
5065 self.expect(&TokenKind::In)?;
5066 let _ = self.parse_expr(0)?;
5067 }
5068 let condition = if matches!(self.peek_kind(), TokenKind::If) {
5069 self.advance();
5070 Some(Box::new(self.parse_expr(0)?))
5071 } else {
5072 None
5073 };
5074 self.skip_whitespace_tokens();
5075 self.bracket_depth -= 1;
5076 let end = self.expect(&TokenKind::RBrace)?.span;
5077
5078 let kind = if matches!(first, Expr::TupleLit(..)) {
5081 ComprehensionKind::Map
5082 } else {
5083 ComprehensionKind::Set
5084 };
5085
5086 Ok(Expr::Comprehension {
5087 body: Box::new(first),
5088 var,
5089 iter: Box::new(iter),
5090 condition,
5091 kind,
5092 span: start.merge(end),
5093 })
5094 }
5095 TokenKind::Colon | TokenKind::Assign => {
5096 self.advance();
5098 self.skip_whitespace_tokens();
5099 let val = self.parse_expr(0)?;
5100 self.skip_whitespace_tokens();
5101
5102 let mut pairs = vec![(first, val)];
5103 while matches!(self.peek_kind(), TokenKind::Comma) {
5104 self.advance();
5105 self.skip_whitespace_tokens();
5106 if matches!(self.peek_kind(), TokenKind::RBrace) {
5107 break;
5108 }
5109 if matches!(self.peek_kind(), TokenKind::DotDot | TokenKind::DotDotDot) {
5110 let spread_span = self.advance().span;
5111 let spread_expr = self.parse_expr(0)?;
5112 pairs.push((Expr::StringLit("__spread".into(), spread_span), spread_expr));
5113 self.skip_whitespace_tokens();
5114 continue;
5115 }
5116 let key = if let TokenKind::Ident(name) = self.peek_kind().clone() {
5117 if matches!(
5118 self.tokens.get(self.pos + 1).map(|t| &t.kind),
5119 Some(TokenKind::Colon)
5120 ) {
5121 let span = self.current().span;
5122 self.advance();
5123 Expr::StringLit(name, span)
5124 } else {
5125 self.parse_expr(0)?
5126 }
5127 } else {
5128 self.parse_expr(0)?
5129 };
5130 self.expect(&TokenKind::Colon)?;
5131 self.skip_whitespace_tokens();
5132 let val = self.parse_expr(0)?;
5133 pairs.push((key, val));
5134 self.skip_whitespace_tokens();
5135 }
5136 self.bracket_depth -= 1;
5137 let end = self.expect(&TokenKind::RBrace)?.span;
5138 Ok(Expr::MapLit(pairs, start.merge(end)))
5139 }
5140 TokenKind::Comma | TokenKind::RBrace => {
5141 let mut elems = vec![first];
5143 while matches!(self.peek_kind(), TokenKind::Comma) {
5144 self.advance();
5145 self.skip_whitespace_tokens();
5146 if matches!(self.peek_kind(), TokenKind::RBrace) {
5147 break;
5148 }
5149 elems.push(self.parse_expr(0)?);
5150 self.skip_whitespace_tokens();
5151 }
5152 self.bracket_depth -= 1;
5153 let end = self.expect(&TokenKind::RBrace)?.span;
5154 Ok(Expr::SetLit(elems, start.merge(end)))
5155 }
5156 _ => {
5157 let tok = self.current().clone();
5158 Err(ParseError::Unexpected {
5159 found: format!("{}", tok.kind),
5160 expected: "',', ':', or 'for'".into(),
5161 line: tok.span.line,
5162 col: tok.span.col,
5163 })
5164 }
5165 }
5166 }
5167
5168 fn parse_role_block_expr(&mut self) -> Result<Expr, ParseError> {
5169 self.parse_role_block_general(&[
5171 TokenKind::End,
5172 TokenKind::Role,
5173 TokenKind::Eof,
5174 TokenKind::RParen,
5175 ])
5176 }
5177
5178 fn parse_role_block_stmt(&mut self) -> Result<Expr, ParseError> {
5180 self.parse_role_block_general(&[TokenKind::End, TokenKind::Role, TokenKind::Eof])
5181 }
5182
5183 fn parse_role_block_general(&mut self, terminators: &[TokenKind]) -> Result<Expr, ParseError> {
5184 let start = self.expect(&TokenKind::Role)?.span;
5185 let name = self.expect_ident()?;
5186 self.expect(&TokenKind::Colon)?;
5187
5188 let has_indent = matches!(self.peek_kind(), TokenKind::Indent);
5201 let content_expr = self.parse_role_content(terminators, has_indent)?;
5202
5203 let end_span = if has_indent || matches!(self.peek_kind(), TokenKind::End) {
5204 self.expect(&TokenKind::End)?.span
5205 } else {
5206 content_expr.span()
5210 };
5211
5212 Ok(Expr::RoleBlock(
5213 name,
5214 Box::new(content_expr),
5215 start.merge(end_span),
5216 ))
5217 }
5218
5219 fn parse_role_content(
5223 &mut self,
5224 terminators: &[TokenKind],
5225 has_indent: bool,
5226 ) -> Result<Expr, ParseError> {
5227 let start = self.current().span;
5228 let mut segments = Vec::new();
5229 let mut text_buf = String::new();
5230 if has_indent {
5231 self.advance();
5232 }
5233 self.skip_newlines();
5234
5235 loop {
5236 let peek = self.peek_kind();
5237 if terminators.contains(peek) {
5238 break;
5239 }
5240 if matches!(peek, TokenKind::Newline) && !has_indent {
5241 break;
5242 }
5243 if matches!(peek, TokenKind::Dedent) && has_indent {
5244 break;
5245 }
5246
5247 match peek {
5248 TokenKind::LBrace => {
5249 let saved_pos = self.pos;
5251 let saved_bracket_depth = self.bracket_depth;
5252 self.advance(); let parsed_interp = (|| {
5254 let expr = self.parse_expr(0).ok()?;
5255 self.expect(&TokenKind::RBrace).ok()?;
5256 Some(expr)
5257 })();
5258
5259 if let Some(expr) = parsed_interp {
5260 if !text_buf.is_empty() {
5261 segments.push(StringSegment::Literal(text_buf.clone()));
5262 text_buf.clear();
5263 }
5264 segments.push(StringSegment::Interpolation(Box::new(expr)));
5265 } else {
5266 self.pos = saved_pos;
5267 self.bracket_depth = saved_bracket_depth;
5268 text_buf.push('{');
5269 self.advance();
5270 }
5271 }
5272 TokenKind::Newline => {
5273 text_buf.push('\n');
5275 self.advance();
5276 }
5277 TokenKind::Indent | TokenKind::Dedent => {
5278 self.advance();
5283 }
5284 _ => {
5285 let tok = self.advance();
5287 let text = format!("{}", tok.kind);
5288 if !text_buf.is_empty() && !text_buf.ends_with('\n') {
5289 text_buf.push(' ');
5290 }
5291 text_buf.push_str(&text);
5292 }
5293 }
5294 }
5295
5296 if !text_buf.is_empty() {
5297 segments.push(StringSegment::Literal(text_buf));
5298 }
5299
5300 if has_indent && matches!(self.peek_kind(), TokenKind::Dedent) {
5301 self.advance();
5302 }
5303
5304 let span = if segments.is_empty() {
5310 start
5311 } else {
5312 start.merge(self.current().span)
5313 };
5314
5315 if segments.len() == 1 {
5316 if let StringSegment::Literal(ref s) = segments[0] {
5317 return Ok(Expr::StringLit(s.clone(), span));
5318 }
5319 }
5320
5321 Ok(Expr::StringInterp(segments, span))
5322 }
5323
5324 fn expect_ident(&mut self) -> Result<String, ParseError> {
5327 let tok = self.current().clone();
5328 match &tok.kind {
5329 TokenKind::Ident(name) => {
5330 let n = name.clone();
5331 self.advance();
5332 Ok(n)
5333 }
5334 TokenKind::Result => {
5335 self.advance();
5336 Ok("result".into())
5337 }
5338 TokenKind::Ok_ => {
5339 self.advance();
5340 Ok("ok".into())
5341 }
5342 TokenKind::Err_ => {
5343 self.advance();
5344 Ok("err".into())
5345 }
5346 TokenKind::List => {
5347 self.advance();
5348 Ok("list".into())
5349 }
5350 TokenKind::Map => {
5351 self.advance();
5352 Ok("map".into())
5353 }
5354 TokenKind::Json => {
5355 self.advance();
5356 Ok("json".into())
5357 }
5358 TokenKind::Bytes => {
5359 self.advance();
5360 Ok("bytes".into())
5361 }
5362 TokenKind::Bool => {
5363 self.advance();
5364 Ok("bool".into())
5365 }
5366 TokenKind::Int_ => {
5367 self.advance();
5368 Ok("int".into())
5369 }
5370 TokenKind::Float_ => {
5371 self.advance();
5372 Ok("float".into())
5373 }
5374 TokenKind::Set => {
5375 self.advance();
5376 Ok("set".into())
5377 }
5378 TokenKind::Tuple => {
5379 self.advance();
5380 Ok("tuple".into())
5381 }
5382 TokenKind::Type => {
5383 self.advance();
5384 Ok("type".into())
5385 }
5386 TokenKind::String_ => {
5387 self.advance();
5388 Ok("string".into())
5389 }
5390 TokenKind::Cell => {
5391 self.advance();
5392 Ok("cell".into())
5393 }
5394 TokenKind::Record => {
5395 self.advance();
5396 Ok("record".into())
5397 }
5398 TokenKind::SelfKw => {
5399 self.advance();
5400 Ok("self".into())
5401 }
5402 TokenKind::Schema => {
5403 self.advance();
5404 Ok("schema".into())
5405 }
5406 TokenKind::Try => {
5407 self.advance();
5408 Ok("try".into())
5409 }
5410 TokenKind::When => {
5411 self.advance();
5412 Ok("when".into())
5413 }
5414 TokenKind::Step => {
5415 self.advance();
5416 Ok("step".into())
5417 }
5418 TokenKind::Comptime => {
5419 self.advance();
5420 Ok("comptime".into())
5421 }
5422 TokenKind::Macro => {
5423 self.advance();
5424 Ok("macro".into())
5425 }
5426 TokenKind::Extern => {
5427 self.advance();
5428 Ok("extern".into())
5429 }
5430 TokenKind::Union => {
5431 self.advance();
5432 Ok("union".into())
5433 }
5434 TokenKind::If => {
5435 self.advance();
5436 Ok("if".into())
5437 }
5438 TokenKind::Match => {
5439 self.advance();
5440 Ok("match".into())
5441 }
5442 TokenKind::Loop => {
5443 self.advance();
5444 Ok("loop".into())
5445 }
5446 TokenKind::Async => {
5447 self.advance();
5448 Ok("async".into())
5449 }
5450 TokenKind::With => {
5451 self.advance();
5452 Ok("with".into())
5453 }
5454 TokenKind::Tool => {
5455 self.advance();
5456 Ok("tool".into())
5457 }
5458 TokenKind::Role => {
5459 self.advance();
5460 Ok("role".into())
5461 }
5462 TokenKind::Parallel => {
5463 self.advance();
5464 Ok("parallel".into())
5465 }
5466 TokenKind::From => {
5467 self.advance();
5468 Ok("from".into())
5469 }
5470 TokenKind::Where => {
5471 self.advance();
5472 Ok("where".into())
5473 }
5474 _ => Err(ParseError::Unexpected {
5475 found: format!("{}", tok.kind),
5476 expected: "identifier".into(),
5477 line: tok.span.line,
5478 col: tok.span.col,
5479 }),
5480 }
5481 }
5482
5483 fn expect_type_name_for_is(&mut self) -> Result<String, ParseError> {
5486 let tok = self.current().clone();
5487 match &tok.kind {
5488 TokenKind::Ident(name) => {
5489 let n = name.clone();
5490 self.advance();
5491 Ok(n)
5492 }
5493 TokenKind::Int_ => {
5494 self.advance();
5495 Ok("Int".into())
5496 }
5497 TokenKind::Float_ => {
5498 self.advance();
5499 Ok("Float".into())
5500 }
5501 TokenKind::String_ => {
5502 self.advance();
5503 Ok("String".into())
5504 }
5505 TokenKind::Bool => {
5506 self.advance();
5507 Ok("Bool".into())
5508 }
5509 TokenKind::Null => {
5510 self.advance();
5511 Ok("Null".into())
5512 }
5513 TokenKind::List => {
5514 self.advance();
5515 Ok("List".into())
5516 }
5517 TokenKind::Map => {
5518 self.advance();
5519 Ok("Map".into())
5520 }
5521 TokenKind::Set => {
5522 self.advance();
5523 Ok("Set".into())
5524 }
5525 TokenKind::Tuple => {
5526 self.advance();
5527 Ok("Tuple".into())
5528 }
5529 TokenKind::Bytes => {
5530 self.advance();
5531 Ok("Bytes".into())
5532 }
5533 TokenKind::Json => {
5534 self.advance();
5535 Ok("Json".into())
5536 }
5537 TokenKind::Result => {
5538 self.advance();
5539 Ok("Result".into())
5540 }
5541 _ => Err(ParseError::Unexpected {
5542 found: format!("{}", tok.kind),
5543 expected: "type name".into(),
5544 line: tok.span.line,
5545 col: tok.span.col,
5546 }),
5547 }
5548 }
5549
5550 fn expect_string(&mut self) -> Result<String, ParseError> {
5551 let tok = self.current().clone();
5552 match &tok.kind {
5553 TokenKind::StringLit(s) => {
5554 let s = s.clone();
5555 self.advance();
5556 Ok(s)
5557 }
5558 _ => Err(ParseError::Unexpected {
5559 found: format!("{}", tok.kind),
5560 expected: "string literal".into(),
5561 line: tok.span.line,
5562 col: tok.span.col,
5563 }),
5564 }
5565 }
5566
5567 fn rewrite_await_orchestration(&mut self, expr: Expr) -> Result<Expr, ParseError> {
5568 if let Some((name, base_args, span)) = self.orchestration_call_parts(&expr) {
5569 if name == "parallel" && matches!(self.peek_kind(), TokenKind::For) {
5570 return self.rewrite_await_parallel_for(base_args, span);
5571 }
5572 if self.await_block_follows() {
5573 return self.rewrite_await_orchestration_block(name, base_args, span);
5574 }
5575 }
5576 Ok(expr)
5577 }
5578
5579 fn rewrite_await_parallel_for(
5580 &mut self,
5581 mut base_args: Vec<CallArg>,
5582 call_span: Span,
5583 ) -> Result<Expr, ParseError> {
5584 self.expect(&TokenKind::For)?;
5585 let var = self.expect_ident()?;
5586 self.expect(&TokenKind::In)?;
5587 let iter = self.parse_expr(0)?;
5588 self.skip_newlines();
5589
5590 if matches!(self.peek_kind(), TokenKind::Indent) {
5591 self.advance();
5592 self.skip_newlines();
5593 }
5594 let body_expr = self.parse_expr(0)?;
5595 self.skip_newlines();
5596 if matches!(self.peek_kind(), TokenKind::Dedent) {
5597 self.advance();
5598 }
5599 let end_span = self.expect(&TokenKind::End)?.span;
5600
5601 let body_span = body_expr.span();
5602 let lambda = Expr::Lambda {
5603 params: vec![Param {
5604 name: var.clone(),
5605 ty: TypeExpr::Named("Any".into(), body_span),
5606 default_value: None,
5607 variadic: false,
5608 span: body_span,
5609 }],
5610 return_type: None,
5611 body: LambdaBody::Expr(Box::new(body_expr)),
5612 span: body_span,
5613 };
5614 let spawn_body = Expr::Call(
5615 Box::new(Expr::Ident("spawn".into(), body_span)),
5616 vec![
5617 CallArg::Positional(lambda),
5618 CallArg::Positional(Expr::Ident(var.clone(), body_span)),
5619 ],
5620 body_span,
5621 );
5622 let comp = Expr::Comprehension {
5623 body: Box::new(spawn_body),
5624 var,
5625 iter: Box::new(iter),
5626 condition: None,
5627 kind: ComprehensionKind::List,
5628 span: call_span.merge(end_span),
5629 };
5630 base_args.push(CallArg::Positional(comp));
5631 Ok(Expr::Call(
5632 Box::new(Expr::Ident("parallel".into(), call_span)),
5633 base_args,
5634 call_span.merge(end_span),
5635 ))
5636 }
5637
5638 fn rewrite_await_orchestration_block(
5639 &mut self,
5640 name: String,
5641 mut base_args: Vec<CallArg>,
5642 call_span: Span,
5643 ) -> Result<Expr, ParseError> {
5644 self.skip_newlines();
5645 let has_indent = matches!(self.peek_kind(), TokenKind::Indent);
5646 if has_indent {
5647 self.advance();
5648 }
5649 self.skip_newlines();
5650
5651 while !matches!(
5652 self.peek_kind(),
5653 TokenKind::End | TokenKind::Dedent | TokenKind::Eof
5654 ) {
5655 let branch_expr = self.parse_expr(0)?;
5656 base_args.push(CallArg::Positional(self.make_spawn_lambda(branch_expr)));
5657 self.skip_newlines();
5658 }
5659 if has_indent && matches!(self.peek_kind(), TokenKind::Dedent) {
5660 self.advance();
5661 }
5662 let end_span = self.expect(&TokenKind::End)?.span;
5663 Ok(Expr::Call(
5664 Box::new(Expr::Ident(name, call_span)),
5665 base_args,
5666 call_span.merge(end_span),
5667 ))
5668 }
5669
5670 fn make_spawn_lambda(&self, body_expr: Expr) -> Expr {
5671 let body_span = body_expr.span();
5672 let lambda = Expr::Lambda {
5673 params: vec![],
5674 return_type: None,
5675 body: LambdaBody::Expr(Box::new(body_expr)),
5676 span: body_span,
5677 };
5678 Expr::Call(
5679 Box::new(Expr::Ident("spawn".into(), body_span)),
5680 vec![CallArg::Positional(lambda)],
5681 body_span,
5682 )
5683 }
5684
5685 fn orchestration_call_parts(&self, expr: &Expr) -> Option<(String, Vec<CallArg>, Span)> {
5686 match expr {
5687 Expr::Ident(name, span)
5688 if matches!(name.as_str(), "parallel" | "race" | "vote" | "select") =>
5689 {
5690 Some((name.clone(), vec![], *span))
5691 }
5692 Expr::Call(callee, args, span) => {
5693 if let Expr::Ident(name, _) = callee.as_ref() {
5694 if matches!(name.as_str(), "parallel" | "race" | "vote" | "select") {
5695 return Some((name.clone(), args.clone(), *span));
5696 }
5697 }
5698 None
5699 }
5700 _ => None,
5701 }
5702 }
5703
5704 fn await_block_follows(&self) -> bool {
5705 let mut i = self.pos;
5706 if !matches!(
5707 self.tokens.get(i).map(|t| &t.kind),
5708 Some(TokenKind::Newline)
5709 ) {
5710 return false;
5711 }
5712 while matches!(
5713 self.tokens.get(i).map(|t| &t.kind),
5714 Some(TokenKind::Newline)
5715 ) {
5716 i += 1;
5717 }
5718 matches!(self.tokens.get(i).map(|t| &t.kind), Some(TokenKind::Indent))
5719 }
5720
5721 fn parse_dotted_ident(&mut self) -> Result<String, ParseError> {
5722 let mut parts = vec![self.expect_ident()?];
5723 while matches!(self.peek_kind(), TokenKind::Dot) {
5724 self.advance();
5725 parts.push(self.expect_ident()?);
5726 }
5727 Ok(parts.join("."))
5728 }
5729
5730 pub fn parse_program_with_recovery(
5734 &mut self,
5735 directives: Vec<Directive>,
5736 ) -> (Program, Vec<ParseError>) {
5737 let result = self.parse_program(directives);
5738 let program = match result {
5739 Ok(program) => program,
5740 Err(err) => {
5741 self.record_error(err);
5743 Program {
5744 directives: vec![],
5745 items: vec![],
5746 span: Span {
5747 start: 0,
5748 end: 0,
5749 line: 1,
5750 col: 1,
5751 },
5752 }
5753 }
5754 };
5755 let errors = std::mem::take(&mut self.errors);
5756 (program, errors)
5757 }
5758}
5759
5760pub fn parse_with_recovery(
5763 tokens: Vec<Token>,
5764 directives: Vec<Directive>,
5765) -> (Program, Vec<ParseError>) {
5766 let mut parser = Parser::new(tokens);
5767 parser.parse_program_with_recovery(directives)
5768}
5769
5770#[cfg(test)]
5771mod tests {
5772 use super::*;
5773 use crate::compiler::lexer::Lexer;
5774
5775 fn parse_src(src: &str) -> Result<Program, ParseError> {
5776 let mut lexer = Lexer::new(src, 1, 0);
5777 let tokens = lexer.tokenize().unwrap();
5778 let mut parser = Parser::new(tokens);
5779 parser.parse_program(vec![])
5780 }
5781
5782 #[test]
5783 fn test_parse_record() {
5784 let prog = parse_src("record Foo\n x: Int\n y: String\nend").unwrap();
5785 assert_eq!(prog.items.len(), 1);
5786 if let Item::Record(r) = &prog.items[0] {
5787 assert_eq!(r.name, "Foo");
5788 assert_eq!(r.fields.len(), 2);
5789 } else {
5790 panic!("expected record");
5791 }
5792 }
5793
5794 #[test]
5795 fn test_parse_cell() {
5796 let prog = parse_src("cell add(a: Int, b: Int) -> Int\n return a + b\nend").unwrap();
5797 assert_eq!(prog.items.len(), 1);
5798 if let Item::Cell(c) = &prog.items[0] {
5799 assert_eq!(c.name, "add");
5800 assert_eq!(c.params.len(), 2);
5801 } else {
5802 panic!("expected cell");
5803 }
5804 }
5805
5806 #[test]
5807 fn test_parse_cell_effect_row_preserved_after_return_type() {
5808 let prog = parse_src("cell main() -> Int / {http, emit}\n return 1\nend").unwrap();
5809 assert_eq!(prog.items.len(), 1);
5810 if let Item::Cell(c) = &prog.items[0] {
5811 assert_eq!(c.effects, vec!["http".to_string(), "emit".to_string()]);
5812 } else {
5813 panic!("expected cell");
5814 }
5815 }
5816
5817 #[test]
5818 fn test_parse_enum() {
5819 let prog = parse_src("enum Color\n Red\n Green\n Blue\nend").unwrap();
5820 if let Item::Enum(e) = &prog.items[0] {
5821 assert_eq!(e.name, "Color");
5822 assert_eq!(e.variants.len(), 3);
5823 } else {
5824 panic!("expected enum");
5825 }
5826 }
5827
5828 #[test]
5829 fn test_parse_match() {
5830 let src = "cell test(x: Int) -> String\n match x\n 1 -> return \"one\"\n _ -> return \"other\"\n end\nend";
5831 let prog = parse_src(src).unwrap();
5832 assert_eq!(prog.items.len(), 1);
5833 }
5834
5835 #[test]
5836 fn test_parse_addon_stmt_in_block_preserved() {
5837 let src = r#"cell main() -> Int
5838 observe "batch"
5839 metrics:
5840 counter items_processed
5841 end
5842 in
5843 return 1
5844 end
5845end"#;
5846 let prog = parse_src(src).unwrap();
5847 if let Item::Cell(c) = &prog.items[0] {
5848 assert_eq!(c.body.len(), 1);
5849 match &c.body[0] {
5850 Stmt::If(ifs) => {
5851 assert_eq!(ifs.then_body.len(), 1);
5852 assert!(matches!(ifs.then_body[0], Stmt::Return(_)));
5853 }
5854 _ => panic!("expected addon in-body to lower to executable block"),
5855 }
5856 } else {
5857 panic!("expected cell");
5858 }
5859 }
5860
5861 #[test]
5862 fn test_parse_machine_state_block() {
5863 let src = r#"machine TicketFlow
5864 initial: Start
5865 state Start(ticket: Int)
5866 guard: ticket > 0
5867 on_enter() / {trace}
5868 transition Done(ticket)
5869 end
5870 end
5871 state Done(value: Int)
5872 terminal: true
5873 end
5874end"#;
5875 let prog = parse_src(src).unwrap();
5876 assert_eq!(prog.items.len(), 1);
5877 if let Item::Process(p) = &prog.items[0] {
5878 assert_eq!(p.kind, "machine");
5879 assert_eq!(p.name, "TicketFlow");
5880 assert_eq!(p.machine_initial.as_deref(), Some("Start"));
5881 assert_eq!(p.machine_states.len(), 2);
5882 let start_state = p
5883 .machine_states
5884 .iter()
5885 .find(|s| s.name == "Start")
5886 .expect("Start state should be parsed");
5887 assert_eq!(start_state.params.len(), 1);
5888 assert_eq!(start_state.params[0].name, "ticket");
5889 assert!(start_state.guard.is_some());
5890 assert_eq!(start_state.transition_to.as_deref(), Some("Done"));
5891 assert_eq!(start_state.transition_args.len(), 1);
5892 let done_state = p
5893 .machine_states
5894 .iter()
5895 .find(|s| s.name == "Done")
5896 .expect("Done state should be parsed");
5897 assert_eq!(done_state.params.len(), 1);
5898 assert_eq!(done_state.params[0].name, "value");
5899 assert!(done_state.terminal);
5900 } else {
5901 panic!("expected process");
5902 }
5903 }
5904
5905 #[test]
5906 fn test_parse_match_arm_line_continuation_with_null_coalesce() {
5907 let src = r#"cell main() -> String
5908 loop
5909 let result = foo()
5910 match result
5911 Response.Handoff(target, reason) ->
5912 let current_agent = self.agents.find(fn(a) => a.name == target)
5913 ?? halt("Unknown agent: {target}")
5914 Response.Escalate(reason) ->
5915 return "ok"
5916 end
5917 end
5918end"#;
5919 let prog = parse_src(src).unwrap();
5920 assert_eq!(prog.items.len(), 1);
5921 }
5922
5923 #[test]
5924 fn test_parse_machine_states_with_empty_bodies() {
5925 let src = r#"machine DistributedOrder
5926 @replicated(factor: 3)
5927
5928 state Pending
5929 # ...
5930 end
5931
5932 state Processing
5933 @location("warehouse-{region}")
5934 # ...
5935 end
5936
5937 state Shipped
5938 # ...
5939 end
5940end"#;
5941 let prog = parse_src(src).unwrap();
5942 assert_eq!(prog.items.len(), 1);
5943 assert!(matches!(prog.items[0], Item::Process(_)));
5944 }
5945
5946 #[test]
5947 fn test_parse_pipeline_stages_chain() {
5948 let src = r#"pipeline InvoicePipeline
5949 stages:
5950 Extractor.extract
5951 -> Validator.validate
5952 -> Writer.store
5953 end
5954end"#;
5955 let prog = parse_src(src).unwrap();
5956 let Item::Process(p) = &prog.items[0] else {
5957 panic!("expected process");
5958 };
5959 assert_eq!(p.kind, "pipeline");
5960 assert_eq!(
5961 p.pipeline_stages,
5962 vec![
5963 "Extractor.extract".to_string(),
5964 "Validator.validate".to_string(),
5965 "Writer.store".to_string()
5966 ]
5967 );
5968 }
5969
5970 #[test]
5971 fn test_parse_await_parallel_for_desugars_to_spawn_comprehension() {
5972 let src = r#"cell main() -> Int / {async}
5973 let values = await parallel for i in 0..3
5974 i * 2
5975 end
5976 return length(values)
5977end"#;
5978 let prog = parse_src(src).unwrap();
5979 let Item::Cell(cell) = &prog.items[0] else {
5980 panic!("expected cell");
5981 };
5982 let Stmt::Let(let_stmt) = &cell.body[0] else {
5983 panic!("expected let");
5984 };
5985 let Expr::AwaitExpr(inner, _) = &let_stmt.value else {
5986 panic!("expected await expression");
5987 };
5988 let Expr::Call(callee, args, _) = inner.as_ref() else {
5989 panic!("expected orchestration call");
5990 };
5991 assert!(matches!(callee.as_ref(), Expr::Ident(name, _) if name == "parallel"));
5992 assert_eq!(args.len(), 1);
5993 let CallArg::Positional(Expr::Comprehension { body, var, .. }) = &args[0] else {
5994 panic!("expected list comprehension argument");
5995 };
5996 assert_eq!(var, "i");
5997 assert!(matches!(body.as_ref(), Expr::Call(_, _, _)));
5998 }
5999
6000 #[test]
6001 fn test_parse_await_race_block_desugars_to_spawn_calls() {
6002 let src = r#"cell main() -> Int / {async}
6003 let fastest = await race
6004 10
6005 20
6006 end
6007 return fastest
6008end"#;
6009 let prog = parse_src(src).unwrap();
6010 let Item::Cell(cell) = &prog.items[0] else {
6011 panic!("expected cell");
6012 };
6013 let Stmt::Let(let_stmt) = &cell.body[0] else {
6014 panic!("expected let");
6015 };
6016 let Expr::AwaitExpr(inner, _) = &let_stmt.value else {
6017 panic!("expected await expression");
6018 };
6019 let Expr::Call(callee, args, _) = inner.as_ref() else {
6020 panic!("expected orchestration call");
6021 };
6022 assert!(matches!(callee.as_ref(), Expr::Ident(name, _) if name == "race"));
6023 assert_eq!(args.len(), 2);
6024 for arg in args {
6025 assert!(matches!(arg, CallArg::Positional(Expr::Call(_, _, _))));
6026 }
6027 }
6028
6029 #[test]
6030 fn test_if_let_desugars_to_match() {
6031 let src = r#"cell test(x: Int) -> Int
6032 if let ok(val) = get_result()
6033 return val
6034 else
6035 return 0
6036 end
6037end"#;
6038 let prog = parse_src(src).unwrap();
6039 let Item::Cell(c) = &prog.items[0] else {
6040 panic!("expected cell");
6041 };
6042 let Stmt::Match(ms) = &c.body[0] else {
6044 panic!("expected match from if-let desugar, got {:?}", c.body[0]);
6045 };
6046 assert_eq!(ms.arms.len(), 2);
6047 assert!(
6049 matches!(&ms.arms[0].pattern, Pattern::Variant(name, Some(binding), _)
6050 if name == "ok" && matches!(binding.as_ref(), Pattern::Ident(bind_name, _) if bind_name == "val"))
6051 );
6052 assert!(matches!(&ms.arms[1].pattern, Pattern::Wildcard(_)));
6054 }
6055
6056 #[test]
6057 fn test_if_let_no_else() {
6058 let src = r#"cell test(x: Int) -> Int
6059 if let ok(val) = get_result()
6060 print(val)
6061 end
6062 return 0
6063end"#;
6064 let prog = parse_src(src).unwrap();
6065 let Item::Cell(c) = &prog.items[0] else {
6066 panic!("expected cell");
6067 };
6068 let Stmt::Match(ms) = &c.body[0] else {
6069 panic!("expected match from if-let desugar");
6070 };
6071 assert_eq!(ms.arms.len(), 1);
6073 assert!(matches!(&ms.arms[0].pattern, Pattern::Variant(name, _, _)
6074 if name == "ok"));
6075 }
6076
6077 #[test]
6078 fn test_while_let_desugars_to_loop_match() {
6079 let src = r#"cell test(items: list[Int]) -> Int
6080 while let ok(item) = next(items)
6081 print(item)
6082 end
6083 return 0
6084end"#;
6085 let prog = parse_src(src).unwrap();
6086 let Item::Cell(c) = &prog.items[0] else {
6087 panic!("expected cell");
6088 };
6089 let Stmt::Loop(ls) = &c.body[0] else {
6091 panic!("expected loop from while-let desugar, got {:?}", c.body[0]);
6092 };
6093 assert_eq!(ls.body.len(), 1);
6095 let Stmt::Match(ms) = &ls.body[0] else {
6096 panic!("expected match inside loop");
6097 };
6098 assert_eq!(ms.arms.len(), 2);
6099 assert!(matches!(&ms.arms[0].pattern, Pattern::Variant(name, _, _)
6101 if name == "ok"));
6102 assert!(matches!(&ms.arms[1].pattern, Pattern::Wildcard(_)));
6104 assert!(matches!(&ms.arms[1].body[0], Stmt::Break(_)));
6105 }
6106
6107 #[test]
6108 fn test_expr_position_match_produces_match_expr() {
6109 let src = r#"cell test(x: Int) -> String
6110 let y = match x
6111 1 -> "one"
6112 _ -> "other"
6113 end
6114 return y
6115end"#;
6116 let prog = parse_src(src).unwrap();
6117 let Item::Cell(c) = &prog.items[0] else {
6118 panic!("expected cell");
6119 };
6120 let Stmt::Let(ls) = &c.body[0] else {
6121 panic!("expected let");
6122 };
6123 assert!(
6125 matches!(&ls.value, Expr::MatchExpr { arms, .. } if arms.len() == 2),
6126 "expected MatchExpr with 2 arms, got {:?}",
6127 ls.value
6128 );
6129 }
6130
6131 #[test]
6132 fn test_expr_position_if_produces_block_expr() {
6133 let src = r#"cell test(x: Int) -> Int
6134 let y = if x > 0
6135 return 1
6136 else
6137 return 0
6138 end
6139 return y
6140end"#;
6141 let prog = parse_src(src).unwrap();
6142 let Item::Cell(c) = &prog.items[0] else {
6143 panic!("expected cell");
6144 };
6145 let Stmt::Let(ls) = &c.body[0] else {
6146 panic!("expected let");
6147 };
6148 assert!(
6150 matches!(&ls.value, Expr::BlockExpr(stmts, _) if matches!(&stmts[0], Stmt::If(_))),
6151 "expected BlockExpr with If, got {:?}",
6152 ls.value
6153 );
6154 }
6155
6156 #[test]
6157 fn test_expr_position_loop_produces_block_expr() {
6158 let src = r#"cell test() -> Int
6159 let y = loop
6160 break 42
6161 end
6162 return y
6163end"#;
6164 let prog = parse_src(src).unwrap();
6165 let Item::Cell(c) = &prog.items[0] else {
6166 panic!("expected cell");
6167 };
6168 let Stmt::Let(ls) = &c.body[0] else {
6169 panic!("expected let");
6170 };
6171 assert!(
6172 matches!(&ls.value, Expr::BlockExpr(stmts, _) if matches!(&stmts[0], Stmt::Loop(_))),
6173 "expected BlockExpr with Loop, got {:?}",
6174 ls.value
6175 );
6176 }
6177
6178 #[test]
6179 fn test_for_loop_tuple_destructuring() {
6180 let src = r#"cell test(m: map[String, Int]) -> Int
6181 for (k, v) in m
6182 print(k)
6183 end
6184 return 0
6185end"#;
6186 let prog = parse_src(src).unwrap();
6187 let Item::Cell(c) = &prog.items[0] else {
6188 panic!("expected cell");
6189 };
6190 let Stmt::For(fs) = &c.body[0] else {
6191 panic!("expected for, got {:?}", c.body[0]);
6192 };
6193 assert_eq!(fs.var, "k");
6195 let Some(Pattern::TupleDestructure { elements, .. }) = &fs.pattern else {
6197 panic!("expected tuple destructure pattern, got {:?}", fs.pattern);
6198 };
6199 assert_eq!(elements.len(), 2);
6200 assert!(matches!(&elements[0], Pattern::Ident(n, _) if n == "k"));
6201 assert!(matches!(&elements[1], Pattern::Ident(n, _) if n == "v"));
6202 }
6203
6204 #[test]
6205 fn test_let_variant_destructuring() {
6206 let src = r#"cell test() -> Int
6207 let ok(val) = get_result()
6208 return val
6209end"#;
6210 let prog = parse_src(src).unwrap();
6211 let Item::Cell(c) = &prog.items[0] else {
6212 panic!("expected cell");
6213 };
6214 let Stmt::Let(ls) = &c.body[0] else {
6215 panic!("expected let");
6216 };
6217 assert_eq!(ls.name, "val");
6218 let Some(Pattern::Variant(name, binding, _)) = &ls.pattern else {
6219 panic!("expected variant pattern, got {:?}", ls.pattern);
6220 };
6221 assert_eq!(name, "ok");
6222 assert!(matches!(
6223 binding.as_deref(),
6224 Some(Pattern::Ident(bind_name, _)) if bind_name == "val"
6225 ));
6226 }
6227
6228 #[test]
6229 fn test_let_brace_destructuring() {
6230 let src = r#"cell test() -> Int
6231 let { x, y } = get_point()
6232 return x
6233end"#;
6234 let prog = parse_src(src).unwrap();
6235 let Item::Cell(c) = &prog.items[0] else {
6236 panic!("expected cell");
6237 };
6238 let Stmt::Let(ls) = &c.body[0] else {
6239 panic!("expected let");
6240 };
6241 assert_eq!(ls.name, "x");
6242 let Some(Pattern::RecordDestructure { fields, .. }) = &ls.pattern else {
6243 panic!("expected record destructure pattern, got {:?}", ls.pattern);
6244 };
6245 assert_eq!(fields.len(), 2);
6246 assert_eq!(fields[0].0, "x");
6247 assert_eq!(fields[1].0, "y");
6248 }
6249
6250 #[test]
6251 fn test_for_loop_simple_var_no_pattern() {
6252 let src = r#"cell test(items: list[Int]) -> Int
6253 for item in items
6254 print(item)
6255 end
6256 return 0
6257end"#;
6258 let prog = parse_src(src).unwrap();
6259 let Item::Cell(c) = &prog.items[0] else {
6260 panic!("expected cell");
6261 };
6262 let Stmt::For(fs) = &c.body[0] else {
6263 panic!("expected for");
6264 };
6265 assert_eq!(fs.var, "item");
6266 assert!(fs.pattern.is_none());
6267 }
6268
6269 #[test]
6272 fn test_error_recovery_multiple_errors() {
6273 let src = r#"
6275cell bad1() -> Int
6276 let x =
6277
6278cell good() -> Int
6279 return 42
6280end
6281
6282cell bad2() -> String
6283 return
6284
6285enum GoodEnum
6286 A
6287 B
6288end
6289"#;
6290 let mut lexer = Lexer::new(src, 1, 0);
6291 let tokens = lexer.tokenize().unwrap();
6292 let (program, errors) = parse_with_recovery(tokens, vec![]);
6293
6294 assert!(!errors.is_empty(), "Expected at least 1 parse error");
6296
6297 let has_good_cell = program
6299 .items
6300 .iter()
6301 .any(|item| matches!(item, Item::Cell(c) if c.name == "good"));
6302 let has_good_enum = program
6303 .items
6304 .iter()
6305 .any(|item| matches!(item, Item::Enum(e) if e.name == "GoodEnum"));
6306
6307 assert!(
6308 has_good_cell || has_good_enum,
6309 "Should parse at least one valid declaration after errors"
6310 );
6311 }
6312
6313 #[test]
6314 fn test_error_recovery_continues_after_bad_declaration() {
6315 let src = r#"
6316record Point
6317 x: Int
6318 invalid: something wrong
6319
6320cell get_x() -> Int
6321 return 1
6322end
6323
6324record Color
6325 r: Int
6326 g: Int
6327 b: Int
6328end
6329"#;
6330 let mut lexer = Lexer::new(src, 1, 0);
6331 let tokens = lexer.tokenize().unwrap();
6332 let (program, _errors) = parse_with_recovery(tokens, vec![]);
6333
6334 let has_cell = program
6337 .items
6338 .iter()
6339 .any(|item| matches!(item, Item::Cell(c) if c.name == "get_x"));
6340 let has_color = program
6341 .items
6342 .iter()
6343 .any(|item| matches!(item, Item::Record(r) if r.name == "Color"));
6344
6345 assert!(
6346 has_cell || has_color,
6347 "Should parse declarations after error in Point"
6348 );
6349 }
6350
6351 #[test]
6352 fn test_error_recovery_valid_declarations_after_errors() {
6353 let src = r#"
6354cell bad_one() -> Int
6355 let x =
6356 // Incomplete statement
6357
6358cell good_one() -> Int
6359 return 42
6360end
6361
6362cell bad_two() -> String
6363 return
6364
6365cell good_two() -> Bool
6366 return false
6367end
6368"#;
6369 let mut lexer = Lexer::new(src, 1, 0);
6370 let tokens = lexer.tokenize().unwrap();
6371 let (program, errors) = parse_with_recovery(tokens, vec![]);
6372
6373 assert!(!errors.is_empty(), "Expected parse errors");
6375
6376 let good_cells: Vec<_> = program
6378 .items
6379 .iter()
6380 .filter_map(|item| {
6381 if let Item::Cell(c) = item {
6382 Some(c.name.as_str())
6383 } else {
6384 None
6385 }
6386 })
6387 .collect();
6388
6389 assert!(
6390 good_cells.contains(&"good_one") || good_cells.contains(&"good_two"),
6391 "Should parse at least one valid cell after errors"
6392 );
6393 }
6394
6395 #[test]
6396 fn test_error_recovery_single_error() {
6397 let src = r#"
6399cell test() -> Int
6400 return 1
6401 // Missing 'end'
6402"#;
6403 let mut lexer = Lexer::new(src, 1, 0);
6404 let tokens = lexer.tokenize().unwrap();
6405 let (_, errors) = parse_with_recovery(tokens, vec![]);
6406
6407 assert!(!errors.is_empty(), "Should report at least 1 error");
6408 }
6409
6410 #[test]
6411 fn test_error_recovery_empty_file() {
6412 let src = "";
6413 let mut lexer = Lexer::new(src, 1, 0);
6414 let tokens = lexer.tokenize().unwrap();
6415 let (program, errors) = parse_with_recovery(tokens, vec![]);
6416
6417 assert!(errors.is_empty(), "Empty file should have no errors");
6418 assert!(program.items.is_empty(), "Empty file should have no items");
6419 }
6420
6421 #[test]
6422 fn test_error_recovery_synchronizes_on_keywords() {
6423 let src = r#"
6424cell bad() -> Int
6425 return
6426
6427enum Color
6428 Red
6429 Green
6430 Blue
6431end
6432
6433cell process() -> Int
6434 return 1
6435end
6436"#;
6437 let mut lexer = Lexer::new(src, 1, 0);
6438 let tokens = lexer.tokenize().unwrap();
6439 let (program, _errors) = parse_with_recovery(tokens, vec![]);
6440
6441 let has_enum = program
6444 .items
6445 .iter()
6446 .any(|item| matches!(item, Item::Enum(e) if e.name == "Color"));
6447 let has_cell = program
6448 .items
6449 .iter()
6450 .any(|item| matches!(item, Item::Cell(c) if c.name == "process"));
6451
6452 assert!(
6453 has_enum || has_cell,
6454 "Should parse at least one declaration after synchronization"
6455 );
6456 }
6457
6458 #[test]
6459 fn test_error_recovery_mixed_process_types() {
6460 let src = r#"
6461cell bad() -> Int
6462 let x =
6463 return 1
6464end
6465
6466record GoodRecord
6467 count: Int
6468end
6469"#;
6470 let mut lexer = Lexer::new(src, 1, 0);
6471 let tokens = lexer.tokenize().unwrap();
6472 let (program, _errors) = parse_with_recovery(tokens, vec![]);
6473
6474 let has_record = program
6476 .items
6477 .iter()
6478 .any(|item| matches!(item, Item::Record(r) if r.name == "GoodRecord"));
6479
6480 assert!(has_record, "Should parse record after error in cell");
6481 }
6482
6483 #[test]
6486 fn test_recovery_missing_type_annotation() {
6487 let src = r#"
6488cell test() -> Int
6489 let x: = 5
6490 return x
6491end
6492
6493cell good() -> Int
6494 return 42
6495end
6496"#;
6497 let mut lexer = Lexer::new(src, 1, 0);
6498 let tokens = lexer.tokenize().unwrap();
6499 let (program, errors) = parse_with_recovery(tokens, vec![]);
6500
6501 assert!(!errors.is_empty(), "Should report missing type error");
6503
6504 let has_good = program
6506 .items
6507 .iter()
6508 .any(|item| matches!(item, Item::Cell(c) if c.name == "good"));
6509 assert!(has_good, "Should parse valid cell after error");
6510 }
6511
6512 #[test]
6513 fn test_recovery_multiple_independent_errors() {
6514 let src = r#"
6515cell bad1() -> Int
6516 let x =
6517 return 1
6518end
6519
6520cell bad2() -> String
6521 return
6522end
6523
6524cell good() -> Bool
6525 return true
6526end
6527
6528record Bad
6529 x:
6530 y: Int
6531end
6532
6533record Good
6534 a: Int
6535 b: String
6536end
6537"#;
6538 let mut lexer = Lexer::new(src, 1, 0);
6539 let tokens = lexer.tokenize().unwrap();
6540 let (program, errors) = parse_with_recovery(tokens, vec![]);
6541
6542 assert!(
6544 errors.len() >= 2,
6545 "Should report multiple independent errors"
6546 );
6547
6548 let has_good_cell = program
6550 .items
6551 .iter()
6552 .any(|item| matches!(item, Item::Cell(c) if c.name == "good"));
6553 let has_good_record = program
6554 .items
6555 .iter()
6556 .any(|item| matches!(item, Item::Record(r) if r.name == "Good"));
6557
6558 assert!(has_good_cell, "Should parse good cell");
6559 assert!(has_good_record, "Should parse good record");
6560 }
6561
6562 #[test]
6563 fn test_recovery_unclosed_paren() {
6564 let src = r#"
6565cell bad() -> Int
6566 let x = (1 + 2
6567 return x
6568end
6569
6570cell good() -> Int
6571 return 10
6572end
6573"#;
6574 let mut lexer = Lexer::new(src, 1, 0);
6575 let tokens = lexer.tokenize().unwrap();
6576 let (program, errors) = parse_with_recovery(tokens, vec![]);
6577
6578 assert!(!errors.is_empty(), "Should report unclosed paren error");
6579
6580 let cell_count = program
6582 .items
6583 .iter()
6584 .filter(|item| matches!(item, Item::Cell(_)))
6585 .count();
6586 assert!(cell_count >= 1, "Should parse at least one cell");
6587 }
6588
6589 #[test]
6590 fn test_recovery_malformed_if_stmt() {
6591 let src = r#"
6592cell test() -> Int
6593 if
6594 return 1
6595 end
6596 return 0
6597end
6598
6599cell good() -> Int
6600 if true
6601 return 5
6602 end
6603 return 0
6604end
6605"#;
6606 let mut lexer = Lexer::new(src, 1, 0);
6607 let tokens = lexer.tokenize().unwrap();
6608 let (program, errors) = parse_with_recovery(tokens, vec![]);
6609
6610 assert!(!errors.is_empty(), "Should report malformed if error");
6611
6612 let has_good = program
6613 .items
6614 .iter()
6615 .any(|item| matches!(item, Item::Cell(c) if c.name == "good"));
6616 assert!(has_good, "Should parse valid cell after error");
6617 }
6618
6619 #[test]
6620 fn test_recovery_exact_error_locations() {
6621 let src = r#"
6622cell test() -> Int
6623 let x: = 5
6624 return x
6625end
6626"#;
6627 let mut lexer = Lexer::new(src, 1, 0);
6628 let tokens = lexer.tokenize().unwrap();
6629 let (_program, errors) = parse_with_recovery(tokens, vec![]);
6630
6631 assert!(!errors.is_empty(), "Should have at least one error");
6632
6633 for err in &errors {
6635 match err {
6636 ParseError::Unexpected { line, col, .. } => {
6637 assert!(*line > 0, "Error should have valid line number");
6638 assert!(*col > 0, "Error should have valid column number");
6639 }
6640 ParseError::MissingType { line, col } => {
6641 assert!(*line > 0, "Error should have valid line number");
6642 assert!(*col > 0, "Error should have valid column number");
6643 }
6644 ParseError::IncompleteExpression { line, col, .. } => {
6645 assert!(*line > 0, "Error should have valid line number");
6646 assert!(*col > 0, "Error should have valid column number");
6647 }
6648 ParseError::MalformedConstruct { line, col, .. } => {
6649 assert!(*line > 0, "Error should have valid line number");
6650 assert!(*col > 0, "Error should have valid column number");
6651 }
6652 ParseError::UnclosedBracket {
6653 open_line,
6654 open_col,
6655 current_line,
6656 current_col,
6657 ..
6658 } => {
6659 assert!(
6660 *open_line > 0 && *current_line > 0,
6661 "Should have valid line numbers"
6662 );
6663 assert!(
6664 *open_col > 0 && *current_col > 0,
6665 "Should have valid column numbers"
6666 );
6667 }
6668 ParseError::MissingEnd {
6669 open_line,
6670 open_col,
6671 current_line,
6672 current_col,
6673 ..
6674 } => {
6675 assert!(
6676 *open_line > 0 && *current_line > 0,
6677 "Should have valid line numbers"
6678 );
6679 assert!(
6680 *open_col > 0 && *current_col > 0,
6681 "Should have valid column numbers"
6682 );
6683 }
6684 _ => {}
6685 }
6686 }
6687 }
6688
6689 #[test]
6690 fn test_recovery_all_errors_collected() {
6691 let src = r#"
6692cell bad1() -> Int
6693 let x =
6694 return 1
6695end
6696
6697cell bad2() -> Int
6698 return
6699end
6700
6701cell good() -> Int
6702 return 1
6703end
6704"#;
6705 let mut lexer = Lexer::new(src, 1, 0);
6706 let tokens = lexer.tokenize().unwrap();
6707 let (program, errors) = parse_with_recovery(tokens, vec![]);
6708
6709 assert!(
6711 errors.len() >= 2,
6712 "Should collect multiple errors: got {}",
6713 errors.len()
6714 );
6715
6716 let has_cell = program
6718 .items
6719 .iter()
6720 .any(|item| matches!(item, Item::Cell(c) if c.name == "good"));
6721 assert!(has_cell, "Should parse valid declaration after errors");
6722 }
6723
6724 #[test]
6725 fn test_recovery_no_cascading_undefined_var() {
6726 let src = r#"
6729cell test() -> Int
6730 let x = (1 + unclosed
6731 let y = x + 1
6732 return x + y
6733end
6734"#;
6735 let mut lexer = Lexer::new(src, 1, 0);
6736 let tokens = lexer.tokenize().unwrap();
6737 let (program, _errors) = parse_with_recovery(tokens, vec![]);
6738
6739 let has_cell = program
6741 .items
6742 .iter()
6743 .any(|item| matches!(item, Item::Cell(_)));
6744 assert!(has_cell, "Should parse cell structure despite parse errors");
6745 }
6746
6747 #[test]
6748 fn test_recovery_synchronize_on_newline_stmt() {
6749 let src = r#"
6750cell test() -> Int
6751 let x = 1 +
6752 let y = 2
6753 return y
6754end
6755"#;
6756 let mut lexer = Lexer::new(src, 1, 0);
6757 let tokens = lexer.tokenize().unwrap();
6758 let (program, errors) = parse_with_recovery(tokens, vec![]);
6759
6760 assert!(!errors.is_empty(), "Should report incomplete expression");
6761
6762 let has_cell = program
6763 .items
6764 .iter()
6765 .any(|item| matches!(item, Item::Cell(c) if c.name == "test"));
6766 assert!(has_cell, "Should parse cell with recovery");
6767 }
6768
6769 #[test]
6770 fn test_recovery_nested_errors() {
6771 let src = r#"
6772cell outer() -> Int
6773 if true
6774 let x =
6775 return 1
6776 end
6777 return 0
6778end
6779
6780cell good() -> Bool
6781 return false
6782end
6783"#;
6784 let mut lexer = Lexer::new(src, 1, 0);
6785 let tokens = lexer.tokenize().unwrap();
6786 let (program, errors) = parse_with_recovery(tokens, vec![]);
6787
6788 assert!(!errors.is_empty(), "Should report nested error");
6789
6790 let has_good = program
6791 .items
6792 .iter()
6793 .any(|item| matches!(item, Item::Cell(c) if c.name == "good"));
6794 assert!(has_good, "Should parse cell after nested error");
6795 }
6796
6797 #[test]
6798 fn test_recovery_actionable_error_messages() {
6799 let src = r#"
6800cell test() -> Int
6801 let x: = 5
6802 return x
6803end
6804"#;
6805 let mut lexer = Lexer::new(src, 1, 0);
6806 let tokens = lexer.tokenize().unwrap();
6807 let (_program, errors) = parse_with_recovery(tokens, vec![]);
6808
6809 assert!(!errors.is_empty(), "Should have errors");
6810
6811 for err in &errors {
6813 let msg = format!("{}", err);
6814 assert!(
6816 msg.contains("line") || msg.contains("col"),
6817 "Error message should mention line/col: {}",
6818 msg
6819 );
6820 }
6821 }
6822}