1use crate::ast::{
6 AgentDecl, BeliefDecl, BinOp, Block, ClosureParam, ConstDecl, ElseBranch, EnumDecl, EventKind,
7 Expr, FieldInit, FnDecl, HandlerDecl, InterpExpr, Literal, MapEntry, MatchArm, MockValue,
8 ModDecl, Param, Pattern, Program, RecordDecl, RecordField, Stmt, StringPart, StringTemplate,
9 TestDecl, ToolDecl, ToolFnDecl, UnaryOp, UseDecl, UseKind,
10};
11use chumsky::prelude::*;
12use chumsky::BoxedParser;
13use crate::{Spanned, Token};
14use crate::{Ident, Span, TypeExpr};
15use std::ops::Range;
16use std::sync::Arc;
17
18pub type ParseError = Simple<Token>;
20
21#[must_use]
27#[allow(clippy::needless_pass_by_value)] pub fn parse(tokens: &[Spanned], source: Arc<str>) -> (Option<Program>, Vec<ParseError>) {
29 let len = source.len();
30
31 let token_spans: Vec<(Token, Range<usize>)> = tokens
33 .iter()
34 .map(|s| (s.token.clone(), s.start..s.end))
35 .collect();
36
37 let stream = chumsky::Stream::from_iter(len..len, token_spans.into_iter());
38
39 let (ast, errors) = program_parser(Arc::clone(&source)).parse_recovery(stream);
40
41 (ast, errors)
42}
43
44#[allow(clippy::needless_pass_by_value)]
50fn program_parser(source: Arc<str>) -> impl Parser<Token, Program, Error = ParseError> {
51 let src = source.clone();
52 let src2 = source.clone();
53
54 let top_level = mod_parser(source.clone())
56 .or(use_parser(source.clone()))
57 .or(record_parser(source.clone()))
58 .or(enum_parser(source.clone()))
59 .or(const_parser(source.clone()))
60 .or(tool_parser(source.clone()))
61 .or(agent_parser(source.clone()))
62 .or(fn_parser(source.clone()))
63 .or(test_parser(source.clone()))
64 .recover_with(skip_then_retry_until([
65 Token::KwMod,
66 Token::KwUse,
67 Token::KwPub,
68 Token::KwRecord,
69 Token::KwEnum,
70 Token::KwConst,
71 Token::KwTool,
72 Token::KwAgent,
73 Token::KwFn,
74 Token::KwRun,
75 Token::KwTest,
76 ]));
77
78 let run_stmt = just(Token::KwRun)
79 .ignore_then(ident_token_parser(src.clone()))
80 .then_ignore(just(Token::Semicolon))
81 .or_not();
82
83 top_level.repeated().then(run_stmt).map_with_span(
84 move |(items, run_agent), span: Range<usize>| {
85 let mut mod_decls = Vec::new();
86 let mut use_decls = Vec::new();
87 let mut records = Vec::new();
88 let mut enums = Vec::new();
89 let mut consts = Vec::new();
90 let mut tools = Vec::new();
91 let mut agents = Vec::new();
92 let mut functions = Vec::new();
93 let mut tests = Vec::new();
94
95 for item in items {
96 match item {
97 TopLevel::Mod(m) => mod_decls.push(m),
98 TopLevel::Use(u) => use_decls.push(u),
99 TopLevel::Record(r) => records.push(r),
100 TopLevel::Enum(e) => enums.push(e),
101 TopLevel::Const(c) => consts.push(c),
102 TopLevel::Tool(t) => tools.push(t),
103 TopLevel::Agent(a) => agents.push(a),
104 TopLevel::Function(f) => functions.push(f),
105 TopLevel::Test(t) => tests.push(t),
106 }
107 }
108
109 Program {
110 mod_decls,
111 use_decls,
112 records,
113 enums,
114 consts,
115 tools,
116 agents,
117 functions,
118 tests,
119 run_agent,
120 span: make_span(&src2, span),
121 }
122 },
123 )
124}
125
126enum TopLevel {
128 Mod(ModDecl),
129 Use(UseDecl),
130 Record(RecordDecl),
131 Enum(EnumDecl),
132 Const(ConstDecl),
133 Tool(ToolDecl),
134 Agent(AgentDecl),
135 Function(FnDecl),
136 Test(TestDecl),
137}
138
139#[allow(clippy::needless_pass_by_value)]
145fn mod_parser(source: Arc<str>) -> impl Parser<Token, TopLevel, Error = ParseError> {
146 let src = source.clone();
147
148 just(Token::KwPub)
149 .or_not()
150 .then_ignore(just(Token::KwMod))
151 .then(ident_token_parser(src.clone()))
152 .then_ignore(just(Token::Semicolon))
153 .map_with_span(move |(is_pub, name), span: Range<usize>| {
154 TopLevel::Mod(ModDecl {
155 is_pub: is_pub.is_some(),
156 name,
157 span: make_span(&src, span),
158 })
159 })
160}
161
162#[allow(clippy::needless_pass_by_value)]
164fn use_parser(source: Arc<str>) -> impl Parser<Token, TopLevel, Error = ParseError> {
165 let src = source.clone();
166 let src2 = source.clone();
167 let src3 = source.clone();
168 let src4 = source.clone();
169
170 let simple_use = just(Token::KwPub)
172 .or_not()
173 .then_ignore(just(Token::KwUse))
174 .then(
175 ident_token_parser(src.clone())
176 .separated_by(just(Token::ColonColon))
177 .at_least(1),
178 )
179 .then(
180 just(Token::KwAs)
181 .ignore_then(ident_token_parser(src.clone()))
182 .or_not(),
183 )
184 .then_ignore(just(Token::Semicolon))
185 .map_with_span(move |((is_pub, path), alias), span: Range<usize>| {
186 TopLevel::Use(UseDecl {
187 is_pub: is_pub.is_some(),
188 path,
189 kind: UseKind::Simple(alias),
190 span: make_span(&src, span),
191 })
192 });
193
194 let group_item = ident_token_parser(src2.clone()).then(
196 just(Token::KwAs)
197 .ignore_then(ident_token_parser(src2.clone()))
198 .or_not(),
199 );
200
201 let group_use = just(Token::KwPub)
203 .or_not()
204 .then_ignore(just(Token::KwUse))
205 .then(
206 ident_token_parser(src3.clone())
207 .then_ignore(just(Token::ColonColon))
208 .repeated()
209 .at_least(1),
210 )
211 .then(
212 group_item
213 .separated_by(just(Token::Comma))
214 .allow_trailing()
215 .delimited_by(just(Token::LBrace), just(Token::RBrace)),
216 )
217 .then_ignore(just(Token::Semicolon))
218 .map_with_span(move |((is_pub, path), items), span: Range<usize>| {
219 TopLevel::Use(UseDecl {
220 is_pub: is_pub.is_some(),
221 path,
222 kind: UseKind::Group(items),
223 span: make_span(&src3, span),
224 })
225 });
226
227 let glob_use = just(Token::KwPub)
229 .or_not()
230 .then_ignore(just(Token::KwUse))
231 .then(
232 ident_token_parser(src4.clone())
233 .then_ignore(just(Token::ColonColon))
234 .repeated()
235 .at_least(1),
236 )
237 .then_ignore(just(Token::Star))
238 .then_ignore(just(Token::Semicolon))
239 .map_with_span(move |(is_pub, path), span: Range<usize>| {
240 TopLevel::Use(UseDecl {
241 is_pub: is_pub.is_some(),
242 path,
243 kind: UseKind::Glob,
244 span: make_span(&src4, span),
245 })
246 });
247
248 group_use.or(glob_use).or(simple_use)
250}
251
252#[allow(clippy::needless_pass_by_value)]
258fn record_parser(source: Arc<str>) -> impl Parser<Token, TopLevel, Error = ParseError> {
259 let src = source.clone();
260 let src2 = source.clone();
261
262 let field = ident_token_parser(src.clone())
264 .then_ignore(just(Token::Colon))
265 .then(type_parser(src.clone()))
266 .map_with_span(move |(name, ty), span: Range<usize>| RecordField {
267 name,
268 ty,
269 span: make_span(&src, span),
270 });
271
272 just(Token::KwPub)
273 .or_not()
274 .then_ignore(just(Token::KwRecord))
275 .then(ident_token_parser(src2.clone()))
276 .then(
277 field
278 .separated_by(just(Token::Comma))
279 .allow_trailing()
280 .delimited_by(just(Token::LBrace), just(Token::RBrace)),
281 )
282 .map_with_span(move |((is_pub, name), fields), span: Range<usize>| {
283 TopLevel::Record(RecordDecl {
284 is_pub: is_pub.is_some(),
285 name,
286 fields,
287 span: make_span(&src2, span),
288 })
289 })
290}
291
292#[allow(clippy::needless_pass_by_value)]
294fn enum_parser(source: Arc<str>) -> impl Parser<Token, TopLevel, Error = ParseError> {
295 let src = source.clone();
296 let src2 = source.clone();
297 let src3 = source.clone();
298
299 let variant = ident_token_parser(src.clone())
301 .then(
302 type_parser(src.clone())
303 .delimited_by(just(Token::LParen), just(Token::RParen))
304 .or_not(),
305 )
306 .map_with_span({
307 let src = src.clone();
308 move |(name, payload), span: Range<usize>| crate::ast::EnumVariant {
309 name,
310 payload,
311 span: make_span(&src, span),
312 }
313 });
314
315 just(Token::KwPub)
316 .or_not()
317 .then_ignore(just(Token::KwEnum))
318 .then(ident_token_parser(src3.clone()))
319 .then(
320 variant
321 .separated_by(just(Token::Comma))
322 .allow_trailing()
323 .delimited_by(just(Token::LBrace), just(Token::RBrace)),
324 )
325 .map_with_span(move |((is_pub, name), variants), span: Range<usize>| {
326 TopLevel::Enum(EnumDecl {
327 is_pub: is_pub.is_some(),
328 name,
329 variants,
330 span: make_span(&src2, span),
331 })
332 })
333}
334
335#[allow(clippy::needless_pass_by_value)]
337fn const_parser(source: Arc<str>) -> impl Parser<Token, TopLevel, Error = ParseError> {
338 let src = source.clone();
339 let src2 = source.clone();
340
341 just(Token::KwPub)
342 .or_not()
343 .then_ignore(just(Token::KwConst))
344 .then(ident_token_parser(src.clone()))
345 .then_ignore(just(Token::Colon))
346 .then(type_parser(src.clone()))
347 .then_ignore(just(Token::Eq))
348 .then(expr_parser(src.clone()))
349 .then_ignore(just(Token::Semicolon))
350 .map_with_span(move |(((is_pub, name), ty), value), span: Range<usize>| {
351 TopLevel::Const(ConstDecl {
352 is_pub: is_pub.is_some(),
353 name,
354 ty,
355 value,
356 span: make_span(&src2, span),
357 })
358 })
359}
360
361#[allow(clippy::needless_pass_by_value)]
367fn tool_parser(source: Arc<str>) -> impl Parser<Token, TopLevel, Error = ParseError> {
368 let src = source.clone();
369 let src2 = source.clone();
370 let src3 = source.clone();
371
372 let param = ident_token_parser(src.clone())
374 .then_ignore(just(Token::Colon))
375 .then(type_parser(src.clone()))
376 .map_with_span(move |(name, ty), span: Range<usize>| Param {
377 name,
378 ty,
379 span: make_span(&src, span),
380 });
381
382 let params = param
383 .separated_by(just(Token::Comma))
384 .allow_trailing()
385 .delimited_by(just(Token::LParen), just(Token::RParen));
386
387 let tool_fn = just(Token::KwFn)
389 .ignore_then(ident_token_parser(src2.clone()))
390 .then(params)
391 .then_ignore(just(Token::Arrow))
392 .then(type_parser(src2.clone()))
393 .map_with_span(move |((name, params), return_ty), span: Range<usize>| ToolFnDecl {
394 name,
395 params,
396 return_ty,
397 span: make_span(&src2, span),
398 });
399
400 just(Token::KwPub)
401 .or_not()
402 .then_ignore(just(Token::KwTool))
403 .then(ident_token_parser(src3.clone()))
404 .then(
405 tool_fn
406 .repeated()
407 .delimited_by(just(Token::LBrace), just(Token::RBrace)),
408 )
409 .map_with_span(move |((is_pub, name), functions), span: Range<usize>| {
410 TopLevel::Tool(ToolDecl {
411 is_pub: is_pub.is_some(),
412 name,
413 functions,
414 span: make_span(&src3, span),
415 })
416 })
417}
418
419#[allow(clippy::needless_pass_by_value)]
425fn test_parser(source: Arc<str>) -> impl Parser<Token, TopLevel, Error = ParseError> {
426 let src = source.clone();
427 let src2 = source.clone();
428
429 let serial_annotation = just(Token::At)
432 .then(filter(|t: &Token| matches!(t, Token::Ident)))
433 .or_not()
434 .map(|opt| opt.is_some());
435
436 let test_name = filter_map(|span: Range<usize>, tok: Token| match tok {
438 Token::StringLit => Ok(()),
439 _ => Err(Simple::expected_input_found(span, [], Some(tok))),
440 })
441 .map_with_span(move |_, span: Range<usize>| {
442 let s = &src[span.clone()];
444 s.trim_matches('"').to_string()
445 });
446
447 let body = block_parser(src2.clone());
449
450 serial_annotation
451 .then_ignore(just(Token::KwTest))
452 .then(test_name)
453 .then(body)
454 .map_with_span(move |((is_serial, name), body), span: Range<usize>| {
455 TopLevel::Test(TestDecl {
456 name,
457 is_serial,
458 body,
459 span: make_span(&src2, span),
460 })
461 })
462}
463
464#[allow(clippy::needless_pass_by_value)]
470fn agent_parser(source: Arc<str>) -> impl Parser<Token, TopLevel, Error = ParseError> {
471 let src = source.clone();
472 let src2 = source.clone();
473 let src3 = source.clone();
474 let src4 = source.clone();
475 let src5 = source.clone();
476
477 let tool_use = just(Token::KwUse)
479 .ignore_then(
480 ident_token_parser(src5.clone())
481 .separated_by(just(Token::Comma))
482 .at_least(1),
483 )
484 .or_not()
485 .map(|tools| tools.unwrap_or_default());
486
487 let belief = ident_token_parser(src.clone())
490 .then_ignore(just(Token::Colon))
491 .then(type_parser(src.clone()))
492 .map_with_span(move |(name, ty), span: Range<usize>| BeliefDecl {
493 name,
494 ty,
495 span: make_span(&src, span),
496 });
497
498 let handler = just(Token::KwOn)
499 .ignore_then(event_kind_parser(src2.clone()))
500 .then(block_parser(src2.clone()))
501 .map_with_span(move |(event, body), span: Range<usize>| HandlerDecl {
502 event,
503 body,
504 span: make_span(&src2, span),
505 });
506
507 let receives_clause = just(Token::KwReceives)
509 .ignore_then(type_parser(src3.clone()))
510 .or_not();
511
512 just(Token::KwPub)
513 .or_not()
514 .then_ignore(just(Token::KwAgent))
515 .then(ident_token_parser(src3.clone()))
516 .then(receives_clause)
517 .then_ignore(just(Token::LBrace))
518 .then(tool_use)
519 .then(belief.repeated())
520 .then(handler.repeated())
521 .then_ignore(just(Token::RBrace))
522 .map_with_span(
523 move |(((((is_pub, name), receives), tool_uses), beliefs), handlers),
524 span: Range<usize>| {
525 TopLevel::Agent(AgentDecl {
526 is_pub: is_pub.is_some(),
527 name,
528 receives,
529 tool_uses,
530 beliefs,
531 handlers,
532 span: make_span(&src4, span),
533 })
534 },
535 )
536}
537
538#[allow(clippy::needless_pass_by_value)]
540fn event_kind_parser(source: Arc<str>) -> impl Parser<Token, EventKind, Error = ParseError> {
541 let src = source.clone();
542
543 let start = just(Token::KwStart).to(EventKind::Start);
544 let stop = just(Token::KwStop).to(EventKind::Stop);
545
546 let message = just(Token::KwMessage)
547 .ignore_then(just(Token::LParen))
548 .ignore_then(ident_token_parser(src.clone()))
549 .then_ignore(just(Token::Colon))
550 .then(type_parser(src.clone()))
551 .then_ignore(just(Token::RParen))
552 .map(|(param_name, param_ty)| EventKind::Message {
553 param_name,
554 param_ty,
555 });
556
557 let error = just(Token::KwError)
559 .ignore_then(just(Token::LParen))
560 .ignore_then(ident_token_parser(src))
561 .then_ignore(just(Token::RParen))
562 .map(|param_name| EventKind::Error { param_name });
563
564 start.or(stop).or(message).or(error)
565}
566
567#[allow(clippy::needless_pass_by_value)]
573fn fn_parser(source: Arc<str>) -> impl Parser<Token, TopLevel, Error = ParseError> {
574 let src = source.clone();
575 let src2 = source.clone();
576 let src3 = source.clone();
577
578 let param = ident_token_parser(src.clone())
579 .then_ignore(just(Token::Colon))
580 .then(type_parser(src.clone()))
581 .map_with_span(move |(name, ty), span: Range<usize>| Param {
582 name,
583 ty,
584 span: make_span(&src, span),
585 });
586
587 let params = param
588 .separated_by(just(Token::Comma))
589 .allow_trailing()
590 .delimited_by(just(Token::LParen), just(Token::RParen));
591
592 just(Token::KwPub)
593 .or_not()
594 .then_ignore(just(Token::KwFn))
595 .then(ident_token_parser(src2.clone()))
596 .then(params)
597 .then_ignore(just(Token::Arrow))
598 .then(type_parser(src2.clone()))
599 .then(just(Token::KwFails).or_not())
600 .then(block_parser(src2))
601 .map_with_span(
602 move |(((((is_pub, name), params), return_ty), is_fallible), body),
603 span: Range<usize>| {
604 TopLevel::Function(FnDecl {
605 is_pub: is_pub.is_some(),
606 name,
607 params,
608 return_ty,
609 is_fallible: is_fallible.is_some(),
610 body,
611 span: make_span(&src3, span),
612 })
613 },
614 )
615}
616
617#[allow(clippy::needless_pass_by_value)]
624fn block_parser(source: Arc<str>) -> BoxedParser<'static, Token, Block, ParseError> {
625 let src = source.clone();
626
627 recursive(move |block: Recursive<Token, Block, ParseError>| {
628 let src_inner = src.clone();
629 stmt_parser(src.clone(), block)
630 .repeated()
631 .delimited_by(just(Token::LBrace), just(Token::RBrace))
632 .recover_with(nested_delimiters(
633 Token::LBrace,
634 Token::RBrace,
635 [
636 (Token::LParen, Token::RParen),
637 (Token::LBracket, Token::RBracket),
638 ],
639 |_span: Range<usize>| vec![],
640 ))
641 .map_with_span(move |stmts, span: Range<usize>| Block {
642 stmts,
643 span: make_span(&src_inner, span),
644 })
645 })
646 .boxed()
647}
648
649#[allow(clippy::needless_pass_by_value)]
651fn stmt_parser(
652 source: Arc<str>,
653 block: impl Parser<Token, Block, Error = ParseError> + Clone + 'static,
654) -> impl Parser<Token, Stmt, Error = ParseError> + Clone {
655 let src = source.clone();
656 let src2 = source.clone();
657 let src3 = source.clone();
658 let src4 = source.clone();
659 let src5 = source.clone();
660 let src6 = source.clone();
661 let src7 = source.clone();
662
663 let src10 = source.clone();
665 let let_tuple_stmt = just(Token::KwLet)
666 .ignore_then(
667 ident_token_parser(src10.clone())
668 .separated_by(just(Token::Comma))
669 .at_least(2)
670 .allow_trailing()
671 .delimited_by(just(Token::LParen), just(Token::RParen)),
672 )
673 .then(
674 just(Token::Colon)
675 .ignore_then(type_parser(src10.clone()))
676 .or_not(),
677 )
678 .then_ignore(just(Token::Eq))
679 .then(expr_parser(src10.clone()))
680 .then_ignore(just(Token::Semicolon))
681 .map_with_span(move |((names, ty), value), span: Range<usize>| Stmt::LetTuple {
682 names,
683 ty,
684 value,
685 span: make_span(&src10, span),
686 });
687
688 let let_stmt = just(Token::KwLet)
689 .ignore_then(ident_token_parser(src.clone()))
690 .then(
691 just(Token::Colon)
692 .ignore_then(type_parser(src.clone()))
693 .or_not(),
694 )
695 .then_ignore(just(Token::Eq))
696 .then(expr_parser(src.clone()))
697 .then_ignore(just(Token::Semicolon))
698 .map_with_span(move |((name, ty), value), span: Range<usize>| Stmt::Let {
699 name,
700 ty,
701 value,
702 span: make_span(&src, span),
703 });
704
705 let return_stmt = just(Token::KwReturn)
706 .ignore_then(expr_parser(src2.clone()).or_not())
707 .then_ignore(just(Token::Semicolon))
708 .map_with_span(move |value, span: Range<usize>| Stmt::Return {
709 value,
710 span: make_span(&src2, span),
711 });
712
713 let if_stmt = recursive(|if_stmt| {
714 let src_if = src3.clone();
715 let block_clone = block.clone();
716
717 just(Token::KwIf)
718 .ignore_then(expr_parser(src3.clone()))
719 .then(block_clone.clone())
720 .then(
721 just(Token::KwElse)
722 .ignore_then(
723 if_stmt
724 .map(|s| ElseBranch::ElseIf(Box::new(s)))
725 .or(block_clone.map(ElseBranch::Block)),
726 )
727 .or_not(),
728 )
729 .map_with_span(
730 move |((condition, then_block), else_block), span: Range<usize>| Stmt::If {
731 condition,
732 then_block,
733 else_block,
734 span: make_span(&src_if, span),
735 },
736 )
737 });
738
739 let for_stmt = just(Token::KwFor)
740 .ignore_then(for_pattern_parser(src4.clone()))
741 .then_ignore(just(Token::KwIn))
742 .then(expr_parser(src4.clone()))
743 .then(block.clone())
744 .map_with_span(move |((pattern, iter), body), span: Range<usize>| Stmt::For {
745 pattern,
746 iter,
747 body,
748 span: make_span(&src4, span),
749 });
750
751 let while_stmt = just(Token::KwWhile)
752 .ignore_then(expr_parser(src7.clone()))
753 .then(block.clone())
754 .map_with_span(move |(condition, body), span: Range<usize>| Stmt::While {
755 condition,
756 body,
757 span: make_span(&src7, span),
758 });
759
760 let src8 = source.clone();
761 let loop_stmt = just(Token::KwLoop)
762 .ignore_then(block.clone())
763 .map_with_span(move |body, span: Range<usize>| Stmt::Loop {
764 body,
765 span: make_span(&src8, span),
766 });
767
768 let src9 = source.clone();
769 let break_stmt = just(Token::KwBreak)
770 .then_ignore(just(Token::Semicolon))
771 .map_with_span(move |_, span: Range<usize>| Stmt::Break {
772 span: make_span(&src9, span),
773 });
774
775 let src11 = source.clone();
777 let src12 = source.clone();
778 let mock_infer_stmt = just(Token::KwMock)
779 .ignore_then(just(Token::KwInfer))
780 .ignore_then(just(Token::Arrow))
781 .ignore_then(
782 filter(|t: &Token| matches!(t, Token::Ident))
784 .then(
785 expr_parser(src11.clone())
786 .delimited_by(just(Token::LParen), just(Token::RParen)),
787 )
788 .try_map(move |(_, arg), span: Range<usize>| {
789 let ident_text = &src11[span.clone()];
791 if ident_text.starts_with("fail") {
792 Ok(MockValue::Fail(arg))
793 } else {
794 Err(Simple::custom(span, "expected 'fail' or a value"))
795 }
796 })
797 .or(expr_parser(src12.clone()).map(MockValue::Value)),
798 )
799 .then_ignore(just(Token::Semicolon))
800 .map_with_span(move |value, span: Range<usize>| Stmt::MockInfer {
801 value,
802 span: make_span(&src12, span),
803 });
804
805 let assign_stmt = ident_token_parser(src5.clone())
806 .then_ignore(just(Token::Eq))
807 .then(expr_parser(src5.clone()))
808 .then_ignore(just(Token::Semicolon))
809 .map_with_span(move |(name, value), span: Range<usize>| Stmt::Assign {
810 name,
811 value,
812 span: make_span(&src5, span),
813 });
814
815 let expr_stmt = expr_parser(src6.clone())
816 .then_ignore(just(Token::Semicolon))
817 .map_with_span(move |expr, span: Range<usize>| Stmt::Expr {
818 expr,
819 span: make_span(&src6, span),
820 });
821
822 let_tuple_stmt
823 .or(let_stmt)
824 .or(return_stmt)
825 .or(if_stmt)
826 .or(for_stmt)
827 .or(while_stmt)
828 .or(loop_stmt)
829 .or(break_stmt)
830 .or(mock_infer_stmt)
831 .or(assign_stmt)
832 .or(expr_stmt)
833}
834
835#[allow(clippy::needless_pass_by_value, clippy::too_many_lines)]
842fn expr_parser(source: Arc<str>) -> BoxedParser<'static, Token, Expr, ParseError> {
843 recursive(move |expr: Recursive<Token, Expr, ParseError>| {
844 let src = source.clone();
845
846 let literal = literal_parser(src.clone());
847 let var = var_parser(src.clone());
848
849 let paren_or_tuple = just(Token::LParen)
852 .ignore_then(
853 expr.clone()
854 .separated_by(just(Token::Comma))
855 .allow_trailing(),
856 )
857 .then_ignore(just(Token::RParen))
858 .map_with_span({
859 let src = src.clone();
860 move |elements, span: Range<usize>| {
861 if elements.len() == 1 {
862 Expr::Paren {
864 inner: Box::new(elements.into_iter().next().unwrap()),
865 span: make_span(&src, span),
866 }
867 } else {
868 Expr::Tuple {
870 elements,
871 span: make_span(&src, span),
872 }
873 }
874 }
875 });
876
877 let list = expr
878 .clone()
879 .separated_by(just(Token::Comma))
880 .allow_trailing()
881 .delimited_by(just(Token::LBracket), just(Token::RBracket))
882 .map_with_span({
883 let src = src.clone();
884 move |elements, span: Range<usize>| Expr::List {
885 elements,
886 span: make_span(&src, span),
887 }
888 });
889
890 let self_access = just(Token::KwSelf)
892 .ignore_then(just(Token::Dot))
893 .ignore_then(ident_token_parser(src.clone()))
894 .then(
895 expr.clone()
896 .separated_by(just(Token::Comma))
897 .allow_trailing()
898 .delimited_by(just(Token::LParen), just(Token::RParen))
899 .or_not(),
900 )
901 .map_with_span({
902 let src = src.clone();
903 move |(field, args), span: Range<usize>| match args {
904 Some(args) => Expr::SelfMethodCall {
905 method: field,
906 args,
907 span: make_span(&src, span),
908 },
909 None => Expr::SelfField {
910 field,
911 span: make_span(&src, span),
912 },
913 }
914 });
915
916 let infer_expr = just(Token::KwInfer)
918 .ignore_then(just(Token::LParen))
919 .ignore_then(string_template_parser(src.clone()))
920 .then(
921 just(Token::Arrow)
922 .ignore_then(type_parser(src.clone()))
923 .or_not(),
924 )
925 .then_ignore(just(Token::RParen))
926 .map_with_span({
927 let src = src.clone();
928 move |(template, result_ty), span: Range<usize>| Expr::Infer {
929 template,
930 result_ty,
931 span: make_span(&src, span),
932 }
933 });
934
935 let spawn_field_init = ident_token_parser(src.clone())
937 .then_ignore(just(Token::Colon))
938 .then(expr.clone())
939 .map_with_span({
940 let src = src.clone();
941 move |(name, value), span: Range<usize>| FieldInit {
942 name,
943 value,
944 span: make_span(&src, span),
945 }
946 });
947
948 let spawn_expr = just(Token::KwSpawn)
949 .ignore_then(ident_token_parser(src.clone()))
950 .then_ignore(just(Token::LBrace))
951 .then(
952 spawn_field_init
953 .separated_by(just(Token::Comma))
954 .allow_trailing(),
955 )
956 .then_ignore(just(Token::RBrace))
957 .map_with_span({
958 let src = src.clone();
959 move |(agent, fields), span: Range<usize>| Expr::Spawn {
960 agent,
961 fields,
962 span: make_span(&src, span),
963 }
964 });
965
966 let timeout_clause = just(Token::KwTimeout)
969 .ignore_then(just(Token::LParen))
970 .ignore_then(expr.clone())
971 .then_ignore(just(Token::RParen));
972
973 let await_expr = just(Token::KwAwait)
974 .ignore_then(ident_token_parser(src.clone()).map_with_span({
975 let src = src.clone();
976 move |name, span: Range<usize>| Expr::Var {
977 name,
978 span: make_span(&src, span),
979 }
980 }))
981 .then(timeout_clause.or_not())
982 .map_with_span({
983 let src = src.clone();
984 move |(handle, timeout), span: Range<usize>| Expr::Await {
985 handle: Box::new(handle),
986 timeout: timeout.map(Box::new),
987 span: make_span(&src, span),
988 }
989 });
990
991 let send_expr = just(Token::KwSend)
993 .ignore_then(just(Token::LParen))
994 .ignore_then(expr.clone())
995 .then_ignore(just(Token::Comma))
996 .then(expr.clone())
997 .then_ignore(just(Token::RParen))
998 .map_with_span({
999 let src = src.clone();
1000 move |(handle, message), span: Range<usize>| Expr::Send {
1001 handle: Box::new(handle),
1002 message: Box::new(message),
1003 span: make_span(&src, span),
1004 }
1005 });
1006
1007 let emit_expr = just(Token::KwEmit)
1009 .ignore_then(just(Token::LParen))
1010 .ignore_then(expr.clone())
1011 .then_ignore(just(Token::RParen))
1012 .map_with_span({
1013 let src = src.clone();
1014 move |value, span: Range<usize>| Expr::Emit {
1015 value: Box::new(value),
1016 span: make_span(&src, span),
1017 }
1018 });
1019
1020 let call_expr = ident_token_parser(src.clone())
1022 .then(
1023 expr.clone()
1024 .separated_by(just(Token::Comma))
1025 .allow_trailing()
1026 .delimited_by(just(Token::LParen), just(Token::RParen)),
1027 )
1028 .map_with_span({
1029 let src = src.clone();
1030 move |(name, args), span: Range<usize>| Expr::Call {
1031 name,
1032 args,
1033 span: make_span(&src, span),
1034 }
1035 });
1036
1037 let pattern = pattern_parser(src.clone());
1039
1040 let match_arm = pattern
1042 .then_ignore(just(Token::FatArrow))
1043 .then(expr.clone())
1044 .map_with_span({
1045 let src = src.clone();
1046 move |(pattern, body), span: Range<usize>| MatchArm {
1047 pattern,
1048 body,
1049 span: make_span(&src, span),
1050 }
1051 });
1052
1053 let match_expr = just(Token::KwMatch)
1054 .ignore_then(expr.clone())
1055 .then(
1056 match_arm
1057 .separated_by(just(Token::Comma))
1058 .allow_trailing()
1059 .delimited_by(just(Token::LBrace), just(Token::RBrace)),
1060 )
1061 .map_with_span({
1062 let src = src.clone();
1063 move |(scrutinee, arms), span: Range<usize>| Expr::Match {
1064 scrutinee: Box::new(scrutinee),
1065 arms,
1066 span: make_span(&src, span),
1067 }
1068 });
1069
1070 let receive_expr = just(Token::KwReceive)
1072 .ignore_then(just(Token::LParen))
1073 .ignore_then(just(Token::RParen))
1074 .map_with_span({
1075 let src = src.clone();
1076 move |_, span: Range<usize>| Expr::Receive {
1077 span: make_span(&src, span),
1078 }
1079 });
1080
1081 let trace_expr = just(Token::KwTrace)
1083 .ignore_then(just(Token::LParen))
1084 .ignore_then(expr.clone())
1085 .then_ignore(just(Token::RParen))
1086 .map_with_span({
1087 let src = src.clone();
1088 move |message, span: Range<usize>| Expr::Trace {
1089 message: Box::new(message),
1090 span: make_span(&src, span),
1091 }
1092 });
1093
1094 let record_field_init = ident_token_parser(src.clone())
1098 .then_ignore(just(Token::Colon))
1099 .then(expr.clone())
1100 .map_with_span({
1101 let src = src.clone();
1102 move |(name, value), span: Range<usize>| FieldInit {
1103 name,
1104 value,
1105 span: make_span(&src, span),
1106 }
1107 });
1108
1109 let record_construct = ident_token_parser(src.clone())
1110 .then_ignore(just(Token::LBrace))
1111 .then(
1112 record_field_init
1113 .separated_by(just(Token::Comma))
1114 .allow_trailing(),
1115 )
1116 .then_ignore(just(Token::RBrace))
1117 .map_with_span({
1118 let src = src.clone();
1119 move |(name, fields), span: Range<usize>| Expr::RecordConstruct {
1120 name,
1121 fields,
1122 span: make_span(&src, span),
1123 }
1124 });
1125
1126 let closure_param = ident_token_parser(src.clone())
1128 .then(just(Token::Colon).ignore_then(type_parser(src.clone())).or_not())
1129 .map_with_span({
1130 let src = src.clone();
1131 move |(name, ty), span: Range<usize>| ClosureParam {
1132 name,
1133 ty,
1134 span: make_span(&src, span),
1135 }
1136 });
1137
1138 let closure_empty = just(Token::Or)
1141 .ignore_then(expr.clone())
1142 .map_with_span({
1143 let src = src.clone();
1144 move |body, span: Range<usize>| Expr::Closure {
1145 params: vec![],
1146 body: Box::new(body),
1147 span: make_span(&src, span),
1148 }
1149 });
1150
1151 let closure_with_params = just(Token::Pipe)
1152 .ignore_then(
1153 closure_param
1154 .separated_by(just(Token::Comma))
1155 .allow_trailing(),
1156 )
1157 .then_ignore(just(Token::Pipe))
1158 .then(expr.clone())
1159 .map_with_span({
1160 let src = src.clone();
1161 move |(params, body), span: Range<usize>| Expr::Closure {
1162 params,
1163 body: Box::new(body),
1164 span: make_span(&src, span),
1165 }
1166 });
1167
1168 let closure = closure_with_params.or(closure_empty);
1169
1170 let map_entry = expr
1173 .clone()
1174 .then_ignore(just(Token::Colon))
1175 .then(expr.clone())
1176 .map_with_span({
1177 let src = src.clone();
1178 move |(key, value), span: Range<usize>| MapEntry {
1179 key,
1180 value,
1181 span: make_span(&src, span),
1182 }
1183 });
1184
1185 let map_literal = map_entry
1186 .separated_by(just(Token::Comma))
1187 .allow_trailing()
1188 .delimited_by(just(Token::LBrace), just(Token::RBrace))
1189 .map_with_span({
1190 let src = src.clone();
1191 move |entries, span: Range<usize>| Expr::Map {
1192 entries,
1193 span: make_span(&src, span),
1194 }
1195 });
1196
1197 let variant_construct = ident_token_parser(src.clone())
1199 .then_ignore(just(Token::ColonColon))
1200 .then(ident_token_parser(src.clone()))
1201 .then(
1202 expr.clone()
1203 .delimited_by(just(Token::LParen), just(Token::RParen))
1204 .or_not(),
1205 )
1206 .map_with_span({
1207 let src = src.clone();
1208 move |((enum_name, variant), payload), span: Range<usize>| Expr::VariantConstruct {
1209 enum_name,
1210 variant,
1211 payload: payload.map(Box::new),
1212 span: make_span(&src, span),
1213 }
1214 });
1215
1216 let atom = closure
1224 .or(infer_expr)
1225 .or(spawn_expr)
1226 .or(await_expr)
1227 .or(send_expr)
1228 .or(emit_expr)
1229 .or(receive_expr)
1230 .or(trace_expr)
1231 .or(match_expr)
1232 .or(self_access)
1233 .or(record_construct)
1234 .or(variant_construct)
1235 .or(call_expr)
1236 .or(map_literal)
1237 .or(list)
1238 .or(paren_or_tuple)
1239 .or(literal)
1240 .or(var)
1241 .boxed();
1242
1243 enum PostfixOp {
1246 Field(Ident),
1247 TupleIndex(usize, Range<usize>),
1248 MethodCall(Ident, Vec<Expr>, Range<usize>), }
1250
1251 let method_call = ident_token_parser(src.clone())
1253 .then(
1254 expr.clone()
1255 .separated_by(just(Token::Comma))
1256 .allow_trailing()
1257 .delimited_by(just(Token::LParen), just(Token::RParen)),
1258 )
1259 .map_with_span(|(name, args), span: Range<usize>| {
1260 PostfixOp::MethodCall(name, args, span)
1261 });
1262
1263 let postfix_op = just(Token::Dot).ignore_then(
1264 filter_map({
1266 let src = src.clone();
1267 move |span: Range<usize>, token| match token {
1268 Token::IntLit => {
1269 let text = &src[span.start..span.end];
1270 text.parse::<usize>()
1271 .map(|idx| PostfixOp::TupleIndex(idx, span.clone()))
1272 .map_err(|_| Simple::custom(span, "invalid tuple index"))
1273 }
1274 _ => Err(Simple::expected_input_found(
1275 span,
1276 vec![Some(Token::IntLit)],
1277 Some(token),
1278 )),
1279 }
1280 })
1281 .or(method_call)
1283 .or(ident_token_parser(src.clone()).map(PostfixOp::Field)),
1284 );
1285
1286 let postfix = atom
1287 .then(postfix_op.repeated())
1288 .foldl({
1289 let src = src.clone();
1290 move |object, op| match op {
1291 PostfixOp::Field(field) => {
1292 let span = make_span(&src, object.span().start..field.span.end);
1293 Expr::FieldAccess {
1294 object: Box::new(object),
1295 field,
1296 span,
1297 }
1298 }
1299 PostfixOp::TupleIndex(index, idx_span) => {
1300 let span = make_span(&src, object.span().start..idx_span.end);
1301 Expr::TupleIndex {
1302 tuple: Box::new(object),
1303 index,
1304 span,
1305 }
1306 }
1307 PostfixOp::MethodCall(method, args, call_span) => {
1308 if let Expr::Var { name: tool, .. } = &object {
1311 let span = make_span(&src, object.span().start..call_span.end);
1312 Expr::ToolCall {
1313 tool: tool.clone(),
1314 function: method,
1315 args,
1316 span,
1317 }
1318 } else {
1319 let span = make_span(&src, object.span().start..call_span.end);
1322 Expr::FieldAccess {
1323 object: Box::new(object),
1324 field: method,
1325 span,
1326 }
1327 }
1328 }
1329 }
1330 })
1331 .boxed();
1332
1333 let unary = just(Token::Minus)
1335 .to(UnaryOp::Neg)
1336 .or(just(Token::Bang).to(UnaryOp::Not))
1337 .repeated()
1338 .then(postfix.clone())
1339 .foldr(|op, operand| {
1340 let span = operand.span().clone();
1341 Expr::Unary {
1342 op,
1343 operand: Box::new(operand),
1344 span,
1345 }
1346 })
1347 .boxed();
1348
1349 let try_expr = just(Token::KwTry)
1352 .ignore_then(postfix.clone())
1353 .map_with_span({
1354 let src = src.clone();
1355 move |inner, span: Range<usize>| Expr::Try {
1356 expr: Box::new(inner),
1357 span: make_span(&src, span),
1358 }
1359 })
1360 .boxed();
1361
1362 let fail_expr = just(Token::KwFail)
1365 .ignore_then(postfix.clone())
1366 .map_with_span({
1367 let src = src.clone();
1368 move |error, span: Range<usize>| Expr::Fail {
1369 error: Box::new(error),
1370 span: make_span(&src, span),
1371 }
1372 })
1373 .boxed();
1374
1375 let retry_delay = just(Token::Comma)
1380 .ignore_then(just(Token::KwDelay))
1381 .ignore_then(just(Token::Colon))
1382 .ignore_then(postfix.clone());
1383
1384 let retry_on = just(Token::Comma)
1385 .ignore_then(just(Token::KwOn))
1386 .ignore_then(just(Token::Colon))
1387 .ignore_then(
1388 postfix
1389 .clone()
1390 .separated_by(just(Token::Comma))
1391 .allow_trailing()
1392 .delimited_by(just(Token::LBracket), just(Token::RBracket)),
1393 );
1394
1395 let retry_expr = just(Token::KwRetry)
1396 .ignore_then(just(Token::LParen))
1397 .ignore_then(postfix.clone())
1398 .then(retry_delay.or_not())
1399 .then(retry_on.or_not())
1400 .then_ignore(just(Token::RParen))
1401 .then(
1402 expr.clone()
1403 .delimited_by(just(Token::LBrace), just(Token::RBrace)),
1404 )
1405 .map_with_span({
1406 let src = src.clone();
1407 move |(((count, delay), on_errors), body), span: Range<usize>| Expr::Retry {
1408 count: Box::new(count),
1409 delay: delay.map(Box::new),
1410 on_errors,
1411 body: Box::new(body),
1412 span: make_span(&src, span),
1413 }
1414 })
1415 .boxed();
1416
1417 let unary = retry_expr.or(fail_expr).or(try_expr).or(unary).boxed();
1419
1420 let mul_div_op = just(Token::Star)
1423 .to(BinOp::Mul)
1424 .or(just(Token::Slash).to(BinOp::Div))
1425 .or(just(Token::Percent).to(BinOp::Rem));
1426
1427 let mul_div = unary
1428 .clone()
1429 .then(mul_div_op.then(unary.clone()).repeated())
1430 .foldl({
1431 let src = src.clone();
1432 move |left, (op, right)| {
1433 let span = make_span(&src, left.span().start..right.span().end);
1434 Expr::Binary {
1435 op,
1436 left: Box::new(left),
1437 right: Box::new(right),
1438 span,
1439 }
1440 }
1441 })
1442 .boxed();
1443
1444 let add_sub_op = just(Token::Plus)
1446 .to(BinOp::Add)
1447 .or(just(Token::Minus).to(BinOp::Sub));
1448
1449 let add_sub = mul_div
1450 .clone()
1451 .then(add_sub_op.then(mul_div).repeated())
1452 .foldl({
1453 let src = src.clone();
1454 move |left, (op, right)| {
1455 let span = make_span(&src, left.span().start..right.span().end);
1456 Expr::Binary {
1457 op,
1458 left: Box::new(left),
1459 right: Box::new(right),
1460 span,
1461 }
1462 }
1463 })
1464 .boxed();
1465
1466 let concat_op = just(Token::PlusPlus).to(BinOp::Concat);
1468
1469 let concat = add_sub
1470 .clone()
1471 .then(concat_op.then(add_sub).repeated())
1472 .foldl({
1473 let src = src.clone();
1474 move |left, (op, right)| {
1475 let span = make_span(&src, left.span().start..right.span().end);
1476 Expr::Binary {
1477 op,
1478 left: Box::new(left),
1479 right: Box::new(right),
1480 span,
1481 }
1482 }
1483 })
1484 .boxed();
1485
1486 let cmp_op = choice((
1488 just(Token::Le).to(BinOp::Le),
1489 just(Token::Ge).to(BinOp::Ge),
1490 just(Token::Lt).to(BinOp::Lt),
1491 just(Token::Gt).to(BinOp::Gt),
1492 ));
1493
1494 let comparison = concat
1495 .clone()
1496 .then(cmp_op.then(concat).repeated())
1497 .foldl({
1498 let src = src.clone();
1499 move |left, (op, right)| {
1500 let span = make_span(&src, left.span().start..right.span().end);
1501 Expr::Binary {
1502 op,
1503 left: Box::new(left),
1504 right: Box::new(right),
1505 span,
1506 }
1507 }
1508 })
1509 .boxed();
1510
1511 let eq_op = just(Token::EqEq)
1513 .to(BinOp::Eq)
1514 .or(just(Token::Ne).to(BinOp::Ne));
1515
1516 let equality = comparison
1517 .clone()
1518 .then(eq_op.then(comparison).repeated())
1519 .foldl({
1520 let src = src.clone();
1521 move |left, (op, right)| {
1522 let span = make_span(&src, left.span().start..right.span().end);
1523 Expr::Binary {
1524 op,
1525 left: Box::new(left),
1526 right: Box::new(right),
1527 span,
1528 }
1529 }
1530 })
1531 .boxed();
1532
1533 let and_op = just(Token::And).to(BinOp::And);
1535
1536 let and = equality
1537 .clone()
1538 .then(and_op.then(equality).repeated())
1539 .foldl({
1540 let src = src.clone();
1541 move |left, (op, right)| {
1542 let span = make_span(&src, left.span().start..right.span().end);
1543 Expr::Binary {
1544 op,
1545 left: Box::new(left),
1546 right: Box::new(right),
1547 span,
1548 }
1549 }
1550 })
1551 .boxed();
1552
1553 let or_op = just(Token::Or).to(BinOp::Or);
1555
1556 let or_expr = and.clone().then(or_op.then(and).repeated()).foldl({
1557 let src = src.clone();
1558 move |left, (op, right)| {
1559 let span = make_span(&src, left.span().start..right.span().end);
1560 Expr::Binary {
1561 op,
1562 left: Box::new(left),
1563 right: Box::new(right),
1564 span,
1565 }
1566 }
1567 });
1568
1569 let catch_recovery = just(Token::KwCatch)
1572 .ignore_then(
1573 ident_token_parser(src.clone())
1574 .delimited_by(just(Token::LParen), just(Token::RParen))
1575 .or_not(),
1576 )
1577 .then(
1578 expr.clone()
1579 .delimited_by(just(Token::LBrace), just(Token::RBrace)),
1580 );
1581
1582 or_expr.then(catch_recovery.or_not()).map_with_span({
1583 let src = src.clone();
1584 move |(inner, catch_opt), span: Range<usize>| match catch_opt {
1585 Some((error_bind, recovery)) => Expr::Catch {
1586 expr: Box::new(inner),
1587 error_bind,
1588 recovery: Box::new(recovery),
1589 span: make_span(&src, span),
1590 },
1591 None => inner,
1592 }
1593 })
1594 })
1595 .boxed()
1596}
1597
1598fn make_span(source: &Arc<str>, range: Range<usize>) -> Span {
1604 Span::new(range.start, range.end, Arc::clone(source))
1605}
1606
1607fn ident_token_parser(source: Arc<str>) -> impl Parser<Token, Ident, Error = ParseError> + Clone {
1609 filter_map(move |span: Range<usize>, token| match token {
1610 Token::Ident => {
1611 let text = &source[span.start..span.end];
1612 Ok(Ident::new(text.to_string(), make_span(&source, span)))
1613 }
1614 _ => Err(Simple::expected_input_found(
1615 span,
1616 vec![Some(Token::Ident)],
1617 Some(token),
1618 )),
1619 })
1620}
1621
1622fn var_parser(source: Arc<str>) -> impl Parser<Token, Expr, Error = ParseError> + Clone {
1624 ident_token_parser(source.clone()).map_with_span(move |name, span: Range<usize>| Expr::Var {
1625 name,
1626 span: make_span(&source, span),
1627 })
1628}
1629
1630fn type_parser(source: Arc<str>) -> impl Parser<Token, TypeExpr, Error = ParseError> + Clone {
1632 recursive(move |ty| {
1633 let src = source.clone();
1634
1635 let primitive = choice((
1636 just(Token::TyInt).to(TypeExpr::Int),
1637 just(Token::TyFloat).to(TypeExpr::Float),
1638 just(Token::TyBool).to(TypeExpr::Bool),
1639 just(Token::TyString).to(TypeExpr::String),
1640 just(Token::TyUnit).to(TypeExpr::Unit),
1641 ));
1642
1643 let list_ty = just(Token::TyList)
1644 .ignore_then(just(Token::Lt))
1645 .ignore_then(ty.clone())
1646 .then_ignore(just(Token::Gt))
1647 .map(|inner| TypeExpr::List(Box::new(inner)));
1648
1649 let option_ty = just(Token::TyOption)
1650 .ignore_then(just(Token::Lt))
1651 .ignore_then(ty.clone())
1652 .then_ignore(just(Token::Gt))
1653 .map(|inner| TypeExpr::Option(Box::new(inner)));
1654
1655 let inferred_ty = just(Token::TyInferred)
1656 .ignore_then(just(Token::Lt))
1657 .ignore_then(ty.clone())
1658 .then_ignore(just(Token::Gt))
1659 .map(|inner| TypeExpr::Inferred(Box::new(inner)));
1660
1661 let agent_ty = just(Token::TyAgent)
1662 .ignore_then(just(Token::Lt))
1663 .ignore_then(ident_token_parser(src.clone()))
1664 .then_ignore(just(Token::Gt))
1665 .map(TypeExpr::Agent);
1666
1667 let named_ty = ident_token_parser(src.clone()).map(TypeExpr::Named);
1668
1669 let fn_ty = just(Token::TyFn)
1671 .ignore_then(
1672 ty.clone()
1673 .separated_by(just(Token::Comma))
1674 .allow_trailing()
1675 .delimited_by(just(Token::LParen), just(Token::RParen)),
1676 )
1677 .then_ignore(just(Token::Arrow))
1678 .then(ty.clone())
1679 .map(|(params, ret)| TypeExpr::Fn(params, Box::new(ret)));
1680
1681 let map_ty = just(Token::TyMap)
1683 .ignore_then(just(Token::Lt))
1684 .ignore_then(ty.clone())
1685 .then_ignore(just(Token::Comma))
1686 .then(ty.clone())
1687 .then_ignore(just(Token::Gt))
1688 .map(|(k, v)| TypeExpr::Map(Box::new(k), Box::new(v)));
1689
1690 let result_ty = just(Token::TyResult)
1692 .ignore_then(just(Token::Lt))
1693 .ignore_then(ty.clone())
1694 .then_ignore(just(Token::Comma))
1695 .then(ty.clone())
1696 .then_ignore(just(Token::Gt))
1697 .map(|(ok, err)| TypeExpr::Result(Box::new(ok), Box::new(err)));
1698
1699 let tuple_ty = ty
1701 .clone()
1702 .separated_by(just(Token::Comma))
1703 .at_least(2)
1704 .allow_trailing()
1705 .delimited_by(just(Token::LParen), just(Token::RParen))
1706 .map(TypeExpr::Tuple);
1707
1708 primitive
1709 .or(list_ty)
1710 .or(option_ty)
1711 .or(inferred_ty)
1712 .or(agent_ty)
1713 .or(fn_ty)
1714 .or(map_ty)
1715 .or(result_ty)
1716 .or(tuple_ty)
1717 .or(named_ty)
1718 })
1719}
1720
1721fn for_pattern_parser(source: Arc<str>) -> impl Parser<Token, Pattern, Error = ParseError> + Clone {
1724 recursive(move |pattern| {
1725 let src = source.clone();
1726 let src2 = source.clone();
1727
1728 let binding = ident_token_parser(src.clone()).map_with_span({
1730 let src = src.clone();
1731 move |name, span: Range<usize>| Pattern::Binding {
1732 name,
1733 span: make_span(&src, span),
1734 }
1735 });
1736
1737 let tuple_pattern = pattern
1739 .clone()
1740 .separated_by(just(Token::Comma))
1741 .at_least(2)
1742 .allow_trailing()
1743 .delimited_by(just(Token::LParen), just(Token::RParen))
1744 .map_with_span({
1745 let src = src2.clone();
1746 move |elements, span: Range<usize>| Pattern::Tuple {
1747 elements,
1748 span: make_span(&src, span),
1749 }
1750 });
1751
1752 tuple_pattern.or(binding)
1753 })
1754}
1755
1756fn pattern_parser(source: Arc<str>) -> impl Parser<Token, Pattern, Error = ParseError> + Clone {
1758 recursive(move |pattern| {
1759 let src = source.clone();
1760 let src2 = source.clone();
1761 let src3 = source.clone();
1762 let src4 = source.clone();
1763 let src5 = source.clone();
1764
1765 let wildcard = filter_map({
1767 let src = src.clone();
1768 move |span: Range<usize>, token| match &token {
1769 Token::Ident if src[span.start..span.end].eq("_") => Ok(()),
1770 _ => Err(Simple::expected_input_found(span, vec![], Some(token))),
1771 }
1772 })
1773 .map_with_span(move |_, span: Range<usize>| Pattern::Wildcard {
1774 span: make_span(&src2, span),
1775 });
1776
1777 let lit_int = filter_map({
1779 let src = src3.clone();
1780 move |span: Range<usize>, token| match token {
1781 Token::IntLit => {
1782 let text = &src[span.start..span.end];
1783 text.parse::<i64>()
1784 .map(Literal::Int)
1785 .map_err(|_| Simple::custom(span, "invalid integer literal"))
1786 }
1787 _ => Err(Simple::expected_input_found(
1788 span,
1789 vec![Some(Token::IntLit)],
1790 Some(token),
1791 )),
1792 }
1793 })
1794 .map_with_span({
1795 let src = src3.clone();
1796 move |value, span: Range<usize>| Pattern::Literal {
1797 value,
1798 span: make_span(&src, span),
1799 }
1800 });
1801
1802 let lit_bool = just(Token::KwTrue)
1803 .to(Literal::Bool(true))
1804 .or(just(Token::KwFalse).to(Literal::Bool(false)))
1805 .map_with_span({
1806 let src = src3.clone();
1807 move |value, span: Range<usize>| Pattern::Literal {
1808 value,
1809 span: make_span(&src, span),
1810 }
1811 });
1812
1813 let tuple_pattern = pattern
1815 .clone()
1816 .separated_by(just(Token::Comma))
1817 .at_least(2)
1818 .allow_trailing()
1819 .delimited_by(just(Token::LParen), just(Token::RParen))
1820 .map_with_span({
1821 let src = src5.clone();
1822 move |elements, span: Range<usize>| Pattern::Tuple {
1823 elements,
1824 span: make_span(&src, span),
1825 }
1826 });
1827
1828 let qualified_variant_with_payload = ident_token_parser(src4.clone())
1831 .then_ignore(just(Token::ColonColon))
1832 .then(ident_token_parser(src4.clone()))
1833 .then(
1834 pattern
1835 .clone()
1836 .delimited_by(just(Token::LParen), just(Token::RParen))
1837 .or_not(),
1838 )
1839 .map_with_span({
1840 let src = src4.clone();
1841 move |((enum_name, variant), payload), span: Range<usize>| Pattern::Variant {
1842 enum_name: Some(enum_name),
1843 variant,
1844 payload: payload.map(Box::new),
1845 span: make_span(&src, span),
1846 }
1847 });
1848
1849 let unqualified_with_payload = ident_token_parser(src4.clone())
1851 .then(
1852 pattern
1853 .clone()
1854 .delimited_by(just(Token::LParen), just(Token::RParen))
1855 .or_not(),
1856 )
1857 .map_with_span({
1858 let src = src4.clone();
1859 move |(name, payload), span: Range<usize>| {
1860 if name.name.chars().next().is_some_and(|c| c.is_uppercase()) || payload.is_some() {
1863 Pattern::Variant {
1864 enum_name: None,
1865 variant: name,
1866 payload: payload.map(Box::new),
1867 span: make_span(&src, span),
1868 }
1869 } else {
1870 Pattern::Binding {
1871 name,
1872 span: make_span(&src, span),
1873 }
1874 }
1875 }
1876 });
1877
1878 wildcard
1880 .or(tuple_pattern)
1881 .or(qualified_variant_with_payload)
1882 .or(lit_int)
1883 .or(lit_bool)
1884 .or(unqualified_with_payload)
1885 })
1886}
1887
1888fn literal_parser(source: Arc<str>) -> impl Parser<Token, Expr, Error = ParseError> + Clone {
1890 let src = source.clone();
1891 let src2 = source.clone();
1892 let src3 = source.clone();
1893 let src4 = source.clone();
1894 let src5 = source.clone();
1895
1896 let int_lit = filter_map(move |span: Range<usize>, token| match token {
1897 Token::IntLit => {
1898 let text = &src[span.start..span.end];
1899 text.parse::<i64>()
1900 .map(Literal::Int)
1901 .map_err(|_| Simple::custom(span, "invalid integer literal"))
1902 }
1903 _ => Err(Simple::expected_input_found(
1904 span,
1905 vec![Some(Token::IntLit)],
1906 Some(token),
1907 )),
1908 })
1909 .map_with_span(move |value, span: Range<usize>| Expr::Literal {
1910 value,
1911 span: make_span(&src2, span),
1912 });
1913
1914 let float_lit = filter_map(move |span: Range<usize>, token| match token {
1915 Token::FloatLit => {
1916 let text = &src3[span.start..span.end];
1917 text.parse::<f64>()
1918 .map(Literal::Float)
1919 .map_err(|_| Simple::custom(span, "invalid float literal"))
1920 }
1921 _ => Err(Simple::expected_input_found(
1922 span,
1923 vec![Some(Token::FloatLit)],
1924 Some(token),
1925 )),
1926 })
1927 .map_with_span(move |value, span: Range<usize>| Expr::Literal {
1928 value,
1929 span: make_span(&src4, span),
1930 });
1931
1932 let src6 = source.clone();
1933 let string_lit = filter_map(move |span: Range<usize>, token| match token {
1934 Token::StringLit => {
1935 let text = &src5[span.start..span.end];
1936 let inner = &text[1..text.len() - 1];
1937 let parts = parse_string_template(inner, &make_span(&src5, span.clone()));
1938 Ok(parts)
1939 }
1940 _ => Err(Simple::expected_input_found(
1941 span,
1942 vec![Some(Token::StringLit)],
1943 Some(token),
1944 )),
1945 })
1946 .map_with_span(move |parts, span: Range<usize>| {
1947 let span = make_span(&src6, span);
1948 if parts.len() == 1 {
1950 if let StringPart::Literal(s) = &parts[0] {
1951 return Expr::Literal {
1952 value: Literal::String(s.clone()),
1953 span,
1954 };
1955 }
1956 }
1957 Expr::StringInterp {
1959 template: StringTemplate {
1960 parts,
1961 span: span.clone(),
1962 },
1963 span,
1964 }
1965 });
1966
1967 let bool_lit = just(Token::KwTrue)
1968 .to(Literal::Bool(true))
1969 .or(just(Token::KwFalse).to(Literal::Bool(false)))
1970 .map_with_span(move |value, _span: Range<usize>| Expr::Literal {
1971 value,
1972 span: Span::dummy(), });
1974
1975 int_lit.or(float_lit).or(string_lit).or(bool_lit)
1976}
1977
1978fn string_template_parser(
1980 source: Arc<str>,
1981) -> impl Parser<Token, StringTemplate, Error = ParseError> + Clone {
1982 filter_map(move |span: Range<usize>, token| match token {
1983 Token::StringLit => {
1984 let text = &source[span.start..span.end];
1985 let inner = &text[1..text.len() - 1];
1986 let parts = parse_string_template(inner, &make_span(&source, span.clone()));
1987 Ok(StringTemplate {
1988 parts,
1989 span: make_span(&source, span),
1990 })
1991 }
1992 _ => Err(Simple::expected_input_found(
1993 span,
1994 vec![Some(Token::StringLit)],
1995 Some(token),
1996 )),
1997 })
1998}
1999
2000fn parse_string_template(s: &str, span: &Span) -> Vec<StringPart> {
2003 let mut parts = Vec::new();
2004 let mut current = String::new();
2005 let mut chars = s.chars().peekable();
2006
2007 while let Some(ch) = chars.next() {
2008 if ch == '{' {
2009 if !current.is_empty() {
2010 parts.push(StringPart::Literal(std::mem::take(&mut current)));
2011 }
2012
2013 let mut expr_str = String::new();
2015 while let Some(&c) = chars.peek() {
2016 if c == '}' {
2017 chars.next();
2018 break;
2019 }
2020 expr_str.push(c);
2021 chars.next();
2022 }
2023
2024 if !expr_str.is_empty() {
2025 let interp_expr = parse_interp_expr(&expr_str, span);
2026 parts.push(StringPart::Interpolation(interp_expr));
2027 }
2028 } else if ch == '\\' {
2029 if let Some(escaped) = chars.next() {
2030 current.push(match escaped {
2031 'n' => '\n',
2032 't' => '\t',
2033 'r' => '\r',
2034 '\\' => '\\',
2035 '"' => '"',
2036 '{' => '{',
2037 '}' => '}',
2038 other => other,
2039 });
2040 }
2041 } else {
2042 current.push(ch);
2043 }
2044 }
2045
2046 if !current.is_empty() {
2047 parts.push(StringPart::Literal(current));
2048 }
2049
2050 if parts.is_empty() {
2051 parts.push(StringPart::Literal(String::new()));
2052 }
2053
2054 parts
2055}
2056
2057fn parse_interp_expr(s: &str, span: &Span) -> InterpExpr {
2059 let segments: Vec<&str> = s.split('.').collect();
2060
2061 let mut expr = InterpExpr::Ident(Ident::new(segments[0].to_string(), span.clone()));
2063
2064 for segment in &segments[1..] {
2066 if let Ok(index) = segment.parse::<usize>() {
2067 expr = InterpExpr::TupleIndex {
2069 base: Box::new(expr),
2070 index,
2071 span: span.clone(),
2072 };
2073 } else {
2074 expr = InterpExpr::FieldAccess {
2076 base: Box::new(expr),
2077 field: Ident::new(segment.to_string(), span.clone()),
2078 span: span.clone(),
2079 };
2080 }
2081 }
2082
2083 expr
2084}
2085
2086#[cfg(test)]
2091mod tests {
2092 use super::*;
2093 use crate::lex;
2094
2095 fn parse_str(source: &str) -> (Option<Program>, Vec<ParseError>) {
2096 let lex_result = lex(source).expect("lexing should succeed");
2097 let source_arc: Arc<str> = Arc::from(source);
2098 parse(lex_result.tokens(), source_arc)
2099 }
2100
2101 #[test]
2102 fn parse_minimal_program() {
2103 let source = r#"
2104 agent Main {
2105 on start {
2106 emit(42);
2107 }
2108 }
2109 run Main;
2110 "#;
2111
2112 let (prog, errors) = parse_str(source);
2113 assert!(errors.is_empty(), "errors: {errors:?}");
2114 let prog = prog.expect("should parse");
2115
2116 assert_eq!(prog.agents.len(), 1);
2117 assert_eq!(prog.agents[0].name.name, "Main");
2118 assert_eq!(prog.run_agent.as_ref().unwrap().name, "Main");
2119 }
2120
2121 #[test]
2122 fn parse_agent_with_beliefs() {
2123 let source = r#"
2124 agent Researcher {
2125 topic: String
2126 max_words: Int
2127
2128 on start {
2129 emit(self.topic);
2130 }
2131 }
2132 run Researcher;
2133 "#;
2134
2135 let (prog, errors) = parse_str(source);
2136 assert!(errors.is_empty(), "errors: {errors:?}");
2137 let prog = prog.expect("should parse");
2138
2139 assert_eq!(prog.agents[0].beliefs.len(), 2);
2140 assert_eq!(prog.agents[0].beliefs[0].name.name, "topic");
2141 assert_eq!(prog.agents[0].beliefs[1].name.name, "max_words");
2142 }
2143
2144 #[test]
2145 fn parse_multiple_handlers() {
2146 let source = r#"
2147 agent Worker {
2148 on start {
2149 print("started");
2150 }
2151
2152 on message(msg: String) {
2153 print(msg);
2154 }
2155
2156 on stop {
2157 print("stopped");
2158 }
2159 }
2160 run Worker;
2161 "#;
2162
2163 let (prog, errors) = parse_str(source);
2164 assert!(errors.is_empty(), "errors: {errors:?}");
2165 let prog = prog.expect("should parse");
2166
2167 assert_eq!(prog.agents[0].handlers.len(), 3);
2168 assert_eq!(prog.agents[0].handlers[0].event, EventKind::Start);
2169 assert!(matches!(
2170 prog.agents[0].handlers[1].event,
2171 EventKind::Message { .. }
2172 ));
2173 assert_eq!(prog.agents[0].handlers[2].event, EventKind::Stop);
2174 }
2175
2176 #[test]
2177 fn parse_function() {
2178 let source = r#"
2179 fn greet(name: String) -> String {
2180 return "Hello, " ++ name;
2181 }
2182
2183 agent Main {
2184 on start {
2185 emit(greet("World"));
2186 }
2187 }
2188 run Main;
2189 "#;
2190
2191 let (prog, errors) = parse_str(source);
2192 assert!(errors.is_empty(), "errors: {errors:?}");
2193 let prog = prog.expect("should parse");
2194
2195 assert_eq!(prog.functions.len(), 1);
2196 assert_eq!(prog.functions[0].name.name, "greet");
2197 assert_eq!(prog.functions[0].params.len(), 1);
2198 }
2199
2200 #[test]
2201 fn parse_let_statement() {
2202 let source = r#"
2203 agent Main {
2204 on start {
2205 let x: Int = 42;
2206 let y = "hello";
2207 emit(x);
2208 }
2209 }
2210 run Main;
2211 "#;
2212
2213 let (prog, errors) = parse_str(source);
2214 assert!(errors.is_empty(), "errors: {errors:?}");
2215 let prog = prog.expect("should parse");
2216
2217 let stmts = &prog.agents[0].handlers[0].body.stmts;
2218 assert!(matches!(stmts[0], Stmt::Let { .. }));
2219 assert!(matches!(stmts[1], Stmt::Let { .. }));
2220 }
2221
2222 #[test]
2223 fn parse_if_statement() {
2224 let source = r#"
2225 agent Main {
2226 on start {
2227 if true {
2228 emit(1);
2229 } else {
2230 emit(2);
2231 }
2232 }
2233 }
2234 run Main;
2235 "#;
2236
2237 let (prog, errors) = parse_str(source);
2238 assert!(errors.is_empty(), "errors: {errors:?}");
2239 let prog = prog.expect("should parse");
2240
2241 let stmts = &prog.agents[0].handlers[0].body.stmts;
2242 assert!(matches!(stmts[0], Stmt::If { .. }));
2243 }
2244
2245 #[test]
2246 fn parse_for_loop() {
2247 let source = r#"
2248 agent Main {
2249 on start {
2250 for x in [1, 2, 3] {
2251 print(x);
2252 }
2253 emit(0);
2254 }
2255 }
2256 run Main;
2257 "#;
2258
2259 let (prog, errors) = parse_str(source);
2260 assert!(errors.is_empty(), "errors: {errors:?}");
2261 let prog = prog.expect("should parse");
2262
2263 let stmts = &prog.agents[0].handlers[0].body.stmts;
2264 assert!(matches!(stmts[0], Stmt::For { .. }));
2265 }
2266
2267 #[test]
2268 fn parse_spawn_await() {
2269 let source = r#"
2270 agent Worker {
2271 name: String
2272
2273 on start {
2274 emit(self.name);
2275 }
2276 }
2277
2278 agent Main {
2279 on start {
2280 let w = spawn Worker { name: "test" };
2281 let result = await w;
2282 emit(result);
2283 }
2284 }
2285 run Main;
2286 "#;
2287
2288 let (prog, errors) = parse_str(source);
2289 assert!(errors.is_empty(), "errors: {errors:?}");
2290 prog.expect("should parse");
2291 }
2292
2293 #[test]
2294 fn parse_await_with_timeout() {
2295 let source = r#"
2296 agent Worker {
2297 on start {
2298 emit("done");
2299 }
2300 }
2301
2302 agent Main {
2303 on start {
2304 let w = spawn Worker {};
2305 let result = await w timeout(5000);
2306 emit(result);
2307 }
2308 }
2309 run Main;
2310 "#;
2311
2312 let (prog, errors) = parse_str(source);
2313 assert!(errors.is_empty(), "errors: {errors:?}");
2314 let prog = prog.expect("should parse");
2315
2316 let main = &prog.agents[1];
2318 let stmts = &main.handlers[0].body.stmts;
2319 if let Stmt::Let { value, .. } = &stmts[1] {
2322 if let Expr::Await { timeout, .. } = value {
2323 assert!(timeout.is_some(), "timeout should be present");
2324 } else {
2325 panic!("expected Await expression");
2326 }
2327 } else {
2328 panic!("expected Let statement with value");
2329 }
2330 }
2331
2332 #[test]
2333 fn parse_infer() {
2334 let source = r#"
2335 agent Main {
2336 on start {
2337 let result = infer("What is 2+2?");
2338 emit(result);
2339 }
2340 }
2341 run Main;
2342 "#;
2343
2344 let (prog, errors) = parse_str(source);
2345 assert!(errors.is_empty(), "errors: {errors:?}");
2346 prog.expect("should parse");
2347 }
2348
2349 #[test]
2350 fn parse_binary_precedence() {
2351 let source = r#"
2352 agent Main {
2353 on start {
2354 let x = 2 + 3 * 4;
2355 emit(x);
2356 }
2357 }
2358 run Main;
2359 "#;
2360
2361 let (prog, errors) = parse_str(source);
2362 assert!(errors.is_empty(), "errors: {errors:?}");
2363 let prog = prog.expect("should parse");
2364
2365 let stmts = &prog.agents[0].handlers[0].body.stmts;
2366 if let Stmt::Let { value, .. } = &stmts[0] {
2367 if let Expr::Binary { op, .. } = value {
2368 assert_eq!(*op, BinOp::Add);
2369 } else {
2370 panic!("expected binary expression");
2371 }
2372 }
2373 }
2374
2375 #[test]
2376 fn parse_string_interpolation() {
2377 let source = r#"
2378 agent Main {
2379 on start {
2380 let name = "World";
2381 let msg = infer("Greet {name}");
2382 emit(msg);
2383 }
2384 }
2385 run Main;
2386 "#;
2387
2388 let (prog, errors) = parse_str(source);
2389 assert!(errors.is_empty(), "errors: {errors:?}");
2390 let prog = prog.expect("should parse");
2391
2392 let stmts = &prog.agents[0].handlers[0].body.stmts;
2393 if let Stmt::Let { value, .. } = &stmts[1] {
2394 if let Expr::Infer { template, .. } = value {
2395 assert!(template.has_interpolations());
2396 } else {
2397 panic!("expected infer expression");
2398 }
2399 }
2400 }
2401
2402 #[test]
2407 fn recover_from_malformed_agent_continues_to_next() {
2408 let source = r#"
2410 agent Broken {
2411 x:
2412 }
2413
2414 agent Main {
2415 on start {
2416 emit(42);
2417 }
2418 }
2419 run Main;
2420 "#;
2421
2422 let (prog, errors) = parse_str(source);
2423 assert!(!errors.is_empty(), "should have parse errors");
2425 let prog = prog.expect("should produce partial AST");
2427 assert!(prog.agents.iter().any(|a| a.name.name == "Main"));
2428 }
2429
2430 #[test]
2431 fn recover_from_mismatched_braces_in_block() {
2432 let source = r#"
2433 agent Main {
2434 on start {
2435 let x = [1, 2, 3;
2436 emit(42);
2437 }
2438 }
2439 run Main;
2440 "#;
2441
2442 let (prog, errors) = parse_str(source);
2443 assert!(!errors.is_empty(), "should have parse errors");
2445 assert!(prog.is_some(), "should produce partial AST despite errors");
2446 }
2447
2448 #[test]
2449 fn parse_mod_declaration() {
2450 let source = r#"
2451 mod agents;
2452 pub mod utils;
2453
2454 agent Main {
2455 on start {
2456 emit(42);
2457 }
2458 }
2459 run Main;
2460 "#;
2461
2462 let (prog, errors) = parse_str(source);
2463 assert!(errors.is_empty(), "errors: {errors:?}");
2464 let prog = prog.expect("should parse");
2465
2466 assert_eq!(prog.mod_decls.len(), 2);
2467 assert!(!prog.mod_decls[0].is_pub);
2468 assert_eq!(prog.mod_decls[0].name.name, "agents");
2469 assert!(prog.mod_decls[1].is_pub);
2470 assert_eq!(prog.mod_decls[1].name.name, "utils");
2471 }
2472
2473 #[test]
2474 fn parse_use_simple() {
2475 let source = r#"
2476 use agents::Researcher;
2477
2478 agent Main {
2479 on start {
2480 emit(42);
2481 }
2482 }
2483 run Main;
2484 "#;
2485
2486 let (prog, errors) = parse_str(source);
2487 assert!(errors.is_empty(), "errors: {errors:?}");
2488 let prog = prog.expect("should parse");
2489
2490 assert_eq!(prog.use_decls.len(), 1);
2491 assert!(!prog.use_decls[0].is_pub);
2492 assert_eq!(prog.use_decls[0].path.len(), 2);
2493 assert_eq!(prog.use_decls[0].path[0].name, "agents");
2494 assert_eq!(prog.use_decls[0].path[1].name, "Researcher");
2495 assert!(matches!(prog.use_decls[0].kind, UseKind::Simple(None)));
2496 }
2497
2498 #[test]
2499 fn parse_use_with_alias() {
2500 let source = r#"
2501 use agents::Researcher as R;
2502
2503 agent Main {
2504 on start {
2505 emit(42);
2506 }
2507 }
2508 run Main;
2509 "#;
2510
2511 let (prog, errors) = parse_str(source);
2512 assert!(errors.is_empty(), "errors: {errors:?}");
2513 let prog = prog.expect("should parse");
2514
2515 assert_eq!(prog.use_decls.len(), 1);
2516 if let UseKind::Simple(Some(alias)) = &prog.use_decls[0].kind {
2517 assert_eq!(alias.name, "R");
2518 } else {
2519 panic!("expected Simple with alias");
2520 }
2521 }
2522
2523 #[test]
2524 fn parse_pub_agent() {
2525 let source = r#"
2526 pub agent Worker {
2527 on start {
2528 emit(42);
2529 }
2530 }
2531
2532 agent Main {
2533 on start {
2534 emit(0);
2535 }
2536 }
2537 run Main;
2538 "#;
2539
2540 let (prog, errors) = parse_str(source);
2541 assert!(errors.is_empty(), "errors: {errors:?}");
2542 let prog = prog.expect("should parse");
2543
2544 assert_eq!(prog.agents.len(), 2);
2545 assert!(prog.agents[0].is_pub);
2546 assert_eq!(prog.agents[0].name.name, "Worker");
2547 assert!(!prog.agents[1].is_pub);
2548 }
2549
2550 #[test]
2551 fn parse_pub_function() {
2552 let source = r#"
2553 pub fn helper(x: Int) -> Int {
2554 return x;
2555 }
2556
2557 agent Main {
2558 on start {
2559 emit(helper(42));
2560 }
2561 }
2562 run Main;
2563 "#;
2564
2565 let (prog, errors) = parse_str(source);
2566 assert!(errors.is_empty(), "errors: {errors:?}");
2567 let prog = prog.expect("should parse");
2568
2569 assert_eq!(prog.functions.len(), 1);
2570 assert!(prog.functions[0].is_pub);
2571 assert_eq!(prog.functions[0].name.name, "helper");
2572 }
2573
2574 #[test]
2575 fn parse_library_no_run() {
2576 let source = r#"
2578 pub agent Worker {
2579 on start {
2580 emit(42);
2581 }
2582 }
2583
2584 pub fn helper(x: Int) -> Int {
2585 return x;
2586 }
2587 "#;
2588
2589 let (prog, errors) = parse_str(source);
2590 assert!(errors.is_empty(), "errors: {errors:?}");
2591 let prog = prog.expect("should parse");
2592
2593 assert!(prog.run_agent.is_none());
2594 assert_eq!(prog.agents.len(), 1);
2595 assert_eq!(prog.functions.len(), 1);
2596 }
2597
2598 #[test]
2599 fn recover_multiple_errors_reported() {
2600 let source = r#"
2602 agent A {
2603 x:
2604 }
2605
2606 agent Main {
2607 on start {
2608 emit(42);
2609 }
2610 }
2611 run Main;
2612 "#;
2613
2614 let (prog, errors) = parse_str(source);
2615 if errors.is_empty() {
2619 let prog = prog.expect("should have AST with recovery");
2621 assert!(prog.agents.iter().any(|a| a.name.name == "Main"));
2622 }
2623 }
2625
2626 #[test]
2627 fn parse_record_declaration() {
2628 let source = r#"
2629 record Point {
2630 x: Int,
2631 y: Int,
2632 }
2633
2634 agent Main {
2635 on start {
2636 emit(0);
2637 }
2638 }
2639 run Main;
2640 "#;
2641
2642 let (prog, errors) = parse_str(source);
2643 assert!(errors.is_empty(), "errors: {errors:?}");
2644 let prog = prog.expect("should parse");
2645
2646 assert_eq!(prog.records.len(), 1);
2647 assert!(!prog.records[0].is_pub);
2648 assert_eq!(prog.records[0].name.name, "Point");
2649 assert_eq!(prog.records[0].fields.len(), 2);
2650 assert_eq!(prog.records[0].fields[0].name.name, "x");
2651 assert_eq!(prog.records[0].fields[1].name.name, "y");
2652 }
2653
2654 #[test]
2655 fn parse_pub_record() {
2656 let source = r#"
2657 pub record Config {
2658 host: String,
2659 port: Int,
2660 }
2661
2662 agent Main {
2663 on start { emit(0); }
2664 }
2665 run Main;
2666 "#;
2667
2668 let (prog, errors) = parse_str(source);
2669 assert!(errors.is_empty(), "errors: {errors:?}");
2670 let prog = prog.expect("should parse");
2671
2672 assert_eq!(prog.records.len(), 1);
2673 assert!(prog.records[0].is_pub);
2674 assert_eq!(prog.records[0].name.name, "Config");
2675 }
2676
2677 #[test]
2678 fn parse_enum_declaration() {
2679 let source = r#"
2680 enum Status {
2681 Active,
2682 Pending,
2683 Done,
2684 }
2685
2686 agent Main {
2687 on start {
2688 emit(0);
2689 }
2690 }
2691 run Main;
2692 "#;
2693
2694 let (prog, errors) = parse_str(source);
2695 assert!(errors.is_empty(), "errors: {errors:?}");
2696 let prog = prog.expect("should parse");
2697
2698 assert_eq!(prog.enums.len(), 1);
2699 assert!(!prog.enums[0].is_pub);
2700 assert_eq!(prog.enums[0].name.name, "Status");
2701 assert_eq!(prog.enums[0].variants.len(), 3);
2702 assert_eq!(prog.enums[0].variants[0].name.name, "Active");
2703 assert_eq!(prog.enums[0].variants[1].name.name, "Pending");
2704 assert_eq!(prog.enums[0].variants[2].name.name, "Done");
2705 }
2706
2707 #[test]
2708 fn parse_pub_enum() {
2709 let source = r#"
2710 pub enum Priority { High, Medium, Low }
2711
2712 agent Main {
2713 on start { emit(0); }
2714 }
2715 run Main;
2716 "#;
2717
2718 let (prog, errors) = parse_str(source);
2719 assert!(errors.is_empty(), "errors: {errors:?}");
2720 let prog = prog.expect("should parse");
2721
2722 assert_eq!(prog.enums.len(), 1);
2723 assert!(prog.enums[0].is_pub);
2724 assert_eq!(prog.enums[0].name.name, "Priority");
2725 }
2726
2727 #[test]
2728 fn parse_const_declaration() {
2729 let source = r#"
2730 const MAX_RETRIES: Int = 3;
2731
2732 agent Main {
2733 on start {
2734 emit(0);
2735 }
2736 }
2737 run Main;
2738 "#;
2739
2740 let (prog, errors) = parse_str(source);
2741 assert!(errors.is_empty(), "errors: {errors:?}");
2742 let prog = prog.expect("should parse");
2743
2744 assert_eq!(prog.consts.len(), 1);
2745 assert!(!prog.consts[0].is_pub);
2746 assert_eq!(prog.consts[0].name.name, "MAX_RETRIES");
2747 assert!(matches!(prog.consts[0].ty, TypeExpr::Int));
2748 }
2749
2750 #[test]
2751 fn parse_pub_const() {
2752 let source = r#"
2753 pub const API_URL: String = "https://api.example.com";
2754
2755 agent Main {
2756 on start { emit(0); }
2757 }
2758 run Main;
2759 "#;
2760
2761 let (prog, errors) = parse_str(source);
2762 assert!(errors.is_empty(), "errors: {errors:?}");
2763 let prog = prog.expect("should parse");
2764
2765 assert_eq!(prog.consts.len(), 1);
2766 assert!(prog.consts[0].is_pub);
2767 assert_eq!(prog.consts[0].name.name, "API_URL");
2768 }
2769
2770 #[test]
2771 fn parse_multiple_type_declarations() {
2772 let source = r#"
2773 record Point { x: Int, y: Int }
2774 enum Color { Red, Green, Blue }
2775 const ORIGIN_X: Int = 0;
2776
2777 agent Main {
2778 on start { emit(0); }
2779 }
2780 run Main;
2781 "#;
2782
2783 let (prog, errors) = parse_str(source);
2784 assert!(errors.is_empty(), "errors: {errors:?}");
2785 let prog = prog.expect("should parse");
2786
2787 assert_eq!(prog.records.len(), 1);
2788 assert_eq!(prog.enums.len(), 1);
2789 assert_eq!(prog.consts.len(), 1);
2790 }
2791
2792 #[test]
2793 fn parse_match_expression() {
2794 let source = r#"
2795 enum Status { Active, Pending, Done }
2796
2797 agent Main {
2798 on start {
2799 let s: Int = match Active {
2800 Active => 1,
2801 Pending => 2,
2802 Done => 3,
2803 };
2804 emit(s);
2805 }
2806 }
2807 run Main;
2808 "#;
2809
2810 let (prog, errors) = parse_str(source);
2811 assert!(errors.is_empty(), "errors: {errors:?}");
2812 let prog = prog.expect("should parse");
2813
2814 assert_eq!(prog.agents.len(), 1);
2816 let handler = &prog.agents[0].handlers[0];
2818 let stmt = &handler.body.stmts[0];
2819 if let Stmt::Let { value, .. } = stmt {
2820 assert!(matches!(value, Expr::Match { .. }));
2821 } else {
2822 panic!("expected let statement with match");
2823 }
2824 }
2825
2826 #[test]
2827 fn parse_match_with_wildcard() {
2828 let source = r#"
2829 agent Main {
2830 on start {
2831 let x = 5;
2832 let result = match x {
2833 1 => 10,
2834 2 => 20,
2835 _ => 0,
2836 };
2837 emit(result);
2838 }
2839 }
2840 run Main;
2841 "#;
2842
2843 let (prog, errors) = parse_str(source);
2844 assert!(errors.is_empty(), "errors: {errors:?}");
2845 let prog = prog.expect("should parse");
2846
2847 assert_eq!(prog.agents.len(), 1);
2848 }
2849
2850 #[test]
2851 fn parse_record_construction() {
2852 let source = r#"
2853 record Point { x: Int, y: Int }
2854
2855 agent Main {
2856 on start {
2857 let p = Point { x: 10, y: 20 };
2858 emit(0);
2859 }
2860 }
2861 run Main;
2862 "#;
2863
2864 let (prog, errors) = parse_str(source);
2865 assert!(errors.is_empty(), "errors: {errors:?}");
2866 let prog = prog.expect("should parse");
2867
2868 assert_eq!(prog.records.len(), 1);
2869 assert_eq!(prog.agents.len(), 1);
2870
2871 let handler = &prog.agents[0].handlers[0];
2873 let stmt = &handler.body.stmts[0];
2874 if let Stmt::Let { value, .. } = stmt {
2875 if let Expr::RecordConstruct { name, fields, .. } = value {
2876 assert_eq!(name.name, "Point");
2877 assert_eq!(fields.len(), 2);
2878 assert_eq!(fields[0].name.name, "x");
2879 assert_eq!(fields[1].name.name, "y");
2880 } else {
2881 panic!("expected RecordConstruct");
2882 }
2883 } else {
2884 panic!("expected let statement");
2885 }
2886 }
2887
2888 #[test]
2889 fn parse_match_with_qualified_variant() {
2890 let source = r#"
2891 enum Status { Active, Pending }
2892
2893 fn get_status() -> Int {
2894 return 1;
2895 }
2896
2897 agent Main {
2898 on start {
2899 let s = get_status();
2900 let result = match s {
2901 Status::Active => 1,
2902 Status::Pending => 0,
2903 };
2904 emit(result);
2905 }
2906 }
2907 run Main;
2908 "#;
2909
2910 let (prog, errors) = parse_str(source);
2911 assert!(errors.is_empty(), "errors: {errors:?}");
2912 let prog = prog.expect("should parse");
2913
2914 assert_eq!(prog.enums.len(), 1);
2915 assert_eq!(prog.agents.len(), 1);
2916 }
2917
2918 #[test]
2919 fn parse_field_access() {
2920 let source = r#"
2921 record Point { x: Int, y: Int }
2922
2923 agent Main {
2924 on start {
2925 let p = Point { x: 10, y: 20 };
2926 let x_val = p.x;
2927 let y_val = p.y;
2928 emit(x_val);
2929 }
2930 }
2931 run Main;
2932 "#;
2933
2934 let (prog, errors) = parse_str(source);
2935 assert!(errors.is_empty(), "errors: {errors:?}");
2936 let prog = prog.expect("should parse");
2937
2938 assert_eq!(prog.records.len(), 1);
2939 assert_eq!(prog.agents.len(), 1);
2940
2941 let handler = &prog.agents[0].handlers[0];
2943 let stmt = &handler.body.stmts[1]; if let Stmt::Let { value, .. } = stmt {
2945 if let Expr::FieldAccess { field, .. } = value {
2946 assert_eq!(field.name, "x");
2947 } else {
2948 panic!("expected FieldAccess");
2949 }
2950 } else {
2951 panic!("expected let statement");
2952 }
2953 }
2954
2955 #[test]
2956 fn parse_chained_field_access() {
2957 let source = r#"
2958 record Inner { val: Int }
2959 record Outer { inner: Inner }
2960
2961 agent Main {
2962 on start {
2963 let inner = Inner { val: 42 };
2964 let outer = Outer { inner: inner };
2965 let v = outer.inner.val;
2966 emit(v);
2967 }
2968 }
2969 run Main;
2970 "#;
2971
2972 let (prog, errors) = parse_str(source);
2973 assert!(errors.is_empty(), "errors: {errors:?}");
2974 let prog = prog.expect("should parse");
2975
2976 assert_eq!(prog.records.len(), 2);
2977 assert_eq!(prog.agents.len(), 1);
2978
2979 let handler = &prog.agents[0].handlers[0];
2981 let stmt = &handler.body.stmts[2]; if let Stmt::Let { value, .. } = stmt {
2983 if let Expr::FieldAccess {
2984 object, field: val, ..
2985 } = value
2986 {
2987 assert_eq!(val.name, "val");
2988 if let Expr::FieldAccess { field: inner, .. } = object.as_ref() {
2990 assert_eq!(inner.name, "inner");
2991 } else {
2992 panic!("expected nested FieldAccess");
2993 }
2994 } else {
2995 panic!("expected FieldAccess");
2996 }
2997 } else {
2998 panic!("expected let statement");
2999 }
3000 }
3001
3002 #[test]
3007 fn parse_loop_break() {
3008 let source = r#"
3009 agent Main {
3010 on start {
3011 let count = 0;
3012 loop {
3013 count = count + 1;
3014 if count > 5 {
3015 break;
3016 }
3017 }
3018 emit(count);
3019 }
3020 }
3021 run Main;
3022 "#;
3023
3024 let (prog, errors) = parse_str(source);
3025 assert!(errors.is_empty(), "errors: {errors:?}");
3026 let prog = prog.expect("should parse");
3027
3028 assert_eq!(prog.agents.len(), 1);
3029 let handler = &prog.agents[0].handlers[0];
3030 let loop_stmt = &handler.body.stmts[1];
3032 assert!(matches!(loop_stmt, Stmt::Loop { .. }));
3033 if let Stmt::Loop { body, .. } = loop_stmt {
3035 let if_stmt = &body.stmts[1];
3036 if let Stmt::If { then_block, .. } = if_stmt {
3037 assert!(matches!(then_block.stmts[0], Stmt::Break { .. }));
3038 } else {
3039 panic!("expected if statement");
3040 }
3041 }
3042 }
3043
3044 #[test]
3045 fn parse_agent_receives() {
3046 let source = r#"
3047 enum WorkerMsg {
3048 Task,
3049 Shutdown,
3050 }
3051
3052 agent Worker receives WorkerMsg {
3053 id: Int
3054
3055 on start {
3056 emit(0);
3057 }
3058 }
3059
3060 agent Main {
3061 on start {
3062 emit(0);
3063 }
3064 }
3065 run Main;
3066 "#;
3067
3068 let (prog, errors) = parse_str(source);
3069 assert!(errors.is_empty(), "errors: {errors:?}");
3070 let prog = prog.expect("should parse");
3071
3072 assert_eq!(prog.agents.len(), 2);
3073
3074 let worker = &prog.agents[0];
3076 assert_eq!(worker.name.name, "Worker");
3077 assert!(worker.receives.is_some());
3078 if let Some(TypeExpr::Named(name)) = &worker.receives {
3079 assert_eq!(name.name, "WorkerMsg");
3080 } else {
3081 panic!("expected named type for receives");
3082 }
3083
3084 let main = &prog.agents[1];
3086 assert_eq!(main.name.name, "Main");
3087 assert!(main.receives.is_none());
3088 }
3089
3090 #[test]
3091 fn parse_receive_expression() {
3092 let source = r#"
3093 enum Msg { Ping }
3094
3095 agent Worker receives Msg {
3096 on start {
3097 let msg = receive();
3098 emit(0);
3099 }
3100 }
3101
3102 agent Main {
3103 on start { emit(0); }
3104 }
3105 run Main;
3106 "#;
3107
3108 let (prog, errors) = parse_str(source);
3109 assert!(errors.is_empty(), "errors: {errors:?}");
3110 let prog = prog.expect("should parse");
3111
3112 let worker = prog
3114 .agents
3115 .iter()
3116 .find(|a| a.name.name == "Worker")
3117 .unwrap();
3118 let handler = &worker.handlers[0];
3119 let stmt = &handler.body.stmts[0];
3120
3121 if let Stmt::Let { value, .. } = stmt {
3122 assert!(matches!(value, Expr::Receive { .. }));
3123 } else {
3124 panic!("expected let with receive");
3125 }
3126 }
3127
3128 #[test]
3129 fn parse_message_passing_full() {
3130 let source = r#"
3131 enum WorkerMsg {
3132 Task,
3133 Shutdown,
3134 }
3135
3136 agent Worker receives WorkerMsg {
3137 id: Int
3138
3139 on start {
3140 let msg = receive();
3141 let result = match msg {
3142 Task => 1,
3143 Shutdown => 0,
3144 };
3145 emit(result);
3146 }
3147 }
3148
3149 agent Main {
3150 on start {
3151 let w = spawn Worker { id: 1 };
3152 send(w, Task);
3153 send(w, Shutdown);
3154 await w;
3155 emit(0);
3156 }
3157 }
3158 run Main;
3159 "#;
3160
3161 let (prog, errors) = parse_str(source);
3162 assert!(errors.is_empty(), "errors: {errors:?}");
3163 let prog = prog.expect("should parse");
3164
3165 assert_eq!(prog.enums.len(), 1);
3166 assert_eq!(prog.agents.len(), 2);
3167
3168 let worker = prog
3170 .agents
3171 .iter()
3172 .find(|a| a.name.name == "Worker")
3173 .unwrap();
3174 assert!(worker.receives.is_some());
3175 }
3176
3177 #[test]
3182 fn parse_fallible_function() {
3183 let source = r#"
3184 fn get_data(url: String) -> String fails {
3185 return infer("Get data from {url}" -> String);
3186 }
3187
3188 agent Main {
3189 on start { emit(0); }
3190 }
3191 run Main;
3192 "#;
3193
3194 let (prog, errors) = parse_str(source);
3195 assert!(errors.is_empty(), "errors: {errors:?}");
3196 let prog = prog.expect("should parse");
3197
3198 assert_eq!(prog.functions.len(), 1);
3199 assert!(prog.functions[0].is_fallible);
3200 }
3201
3202 #[test]
3203 fn parse_try_expression() {
3204 let source = r#"
3205 fn fallible() -> Int fails { return 42; }
3206
3207 agent Main {
3208 on start {
3209 let x = try fallible();
3210 emit(x);
3211 }
3212 }
3213 run Main;
3214 "#;
3215
3216 let (prog, errors) = parse_str(source);
3217 assert!(errors.is_empty(), "errors: {errors:?}");
3218 let prog = prog.expect("should parse");
3219
3220 let handler = &prog.agents[0].handlers[0];
3222 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
3223 assert!(matches!(value, Expr::Try { .. }));
3224 } else {
3225 panic!("expected Let statement");
3226 }
3227 }
3228
3229 #[test]
3230 fn parse_catch_expression() {
3231 let source = r#"
3232 fn fallible() -> Int fails { return 42; }
3233
3234 agent Main {
3235 on start {
3236 let x = fallible() catch { 0 };
3237 emit(x);
3238 }
3239 }
3240 run Main;
3241 "#;
3242
3243 let (prog, errors) = parse_str(source);
3244 assert!(errors.is_empty(), "errors: {errors:?}");
3245 let prog = prog.expect("should parse");
3246
3247 let handler = &prog.agents[0].handlers[0];
3249 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
3250 if let Expr::Catch { error_bind, .. } = value {
3251 assert!(error_bind.is_none());
3252 } else {
3253 panic!("expected Catch expression");
3254 }
3255 } else {
3256 panic!("expected Let statement");
3257 }
3258 }
3259
3260 #[test]
3261 fn parse_catch_with_error_binding() {
3262 let source = r#"
3263 fn fallible() -> Int fails { return 42; }
3264
3265 agent Main {
3266 on start {
3267 let x = fallible() catch(e) { 0 };
3268 emit(x);
3269 }
3270 }
3271 run Main;
3272 "#;
3273
3274 let (prog, errors) = parse_str(source);
3275 assert!(errors.is_empty(), "errors: {errors:?}");
3276 let prog = prog.expect("should parse");
3277
3278 let handler = &prog.agents[0].handlers[0];
3280 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
3281 if let Expr::Catch { error_bind, .. } = value {
3282 assert!(error_bind.is_some());
3283 assert_eq!(error_bind.as_ref().unwrap().name, "e");
3284 } else {
3285 panic!("expected Catch expression");
3286 }
3287 } else {
3288 panic!("expected Let statement");
3289 }
3290 }
3291
3292 #[test]
3293 fn parse_fail_expression() {
3294 let source = r#"
3295 agent Main {
3296 on start {
3297 fail "something went wrong";
3298 }
3299 on error(e) {
3300 emit(0);
3301 }
3302 }
3303 run Main;
3304 "#;
3305
3306 let (prog, errors) = parse_str(source);
3307 assert!(errors.is_empty(), "errors: {errors:?}");
3308 let prog = prog.expect("should parse");
3309
3310 let handler = &prog.agents[0].handlers[0];
3312 if let Stmt::Expr { expr, .. } = &handler.body.stmts[0] {
3313 if let Expr::Fail { error, .. } = expr {
3314 assert!(matches!(**error, Expr::Literal { .. }));
3315 } else {
3316 panic!("expected Fail expression, got {expr:?}");
3317 }
3318 } else {
3319 panic!("expected Expr statement");
3320 }
3321 }
3322
3323 #[test]
3324 fn parse_retry_expression() {
3325 let source = r#"
3326 agent Main {
3327 topic: String
3328
3329 on start {
3330 let result = retry(3) {
3331 try infer("Summarize: {self.topic}")
3332 } catch { "fallback" };
3333 emit(result);
3334 }
3335
3336 on error(e) {
3337 emit("");
3338 }
3339 }
3340 run Main;
3341 "#;
3342
3343 let (prog, errors) = parse_str(source);
3344 assert!(errors.is_empty(), "errors: {errors:?}");
3345 let prog = prog.expect("should parse");
3346
3347 let handler = &prog.agents[0].handlers[0];
3349 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
3350 if let Expr::Catch { expr, .. } = value {
3352 if let Expr::Retry { count, delay, .. } = expr.as_ref() {
3353 assert!(matches!(**count, Expr::Literal { .. }));
3354 assert!(delay.is_none());
3355 } else {
3356 panic!("expected Retry expression");
3357 }
3358 } else {
3359 panic!("expected Catch expression");
3360 }
3361 } else {
3362 panic!("expected Let statement");
3363 }
3364 }
3365
3366 #[test]
3367 fn parse_retry_with_delay() {
3368 let source = r#"
3369 agent Main {
3370 on start {
3371 let result = retry(3, delay: 1000) {
3372 42
3373 } catch { 0 };
3374 emit(result);
3375 }
3376 }
3377 run Main;
3378 "#;
3379
3380 let (prog, errors) = parse_str(source);
3381 assert!(errors.is_empty(), "errors: {errors:?}");
3382 let prog = prog.expect("should parse");
3383
3384 let handler = &prog.agents[0].handlers[0];
3386 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
3387 if let Expr::Catch { expr, .. } = value {
3388 if let Expr::Retry { delay, .. } = expr.as_ref() {
3389 assert!(delay.is_some());
3390 } else {
3391 panic!("expected Retry expression");
3392 }
3393 } else {
3394 panic!("expected Catch expression");
3395 }
3396 } else {
3397 panic!("expected Let statement");
3398 }
3399 }
3400
3401 #[test]
3402 fn parse_on_error_handler() {
3403 let source = r#"
3404 agent Main {
3405 on start {
3406 emit(0);
3407 }
3408
3409 on error(e) {
3410 emit(1);
3411 }
3412 }
3413 run Main;
3414 "#;
3415
3416 let (prog, errors) = parse_str(source);
3417 assert!(errors.is_empty(), "errors: {errors:?}");
3418 let prog = prog.expect("should parse");
3419
3420 assert_eq!(prog.agents.len(), 1);
3421 assert_eq!(prog.agents[0].handlers.len(), 2);
3422
3423 let error_handler = prog.agents[0]
3425 .handlers
3426 .iter()
3427 .find(|h| matches!(h.event, EventKind::Error { .. }));
3428 assert!(error_handler.is_some());
3429
3430 if let EventKind::Error { param_name } = &error_handler.unwrap().event {
3431 assert_eq!(param_name.name, "e");
3432 } else {
3433 panic!("expected Error event kind");
3434 }
3435 }
3436
3437 #[test]
3442 fn parse_fn_type() {
3443 let source = r#"
3444 fn apply(f: Fn(Int) -> Int, x: Int) -> Int {
3445 return f(x);
3446 }
3447
3448 agent Main {
3449 on start {
3450 emit(0);
3451 }
3452 }
3453 run Main;
3454 "#;
3455
3456 let (prog, errors) = parse_str(source);
3457 assert!(errors.is_empty(), "errors: {errors:?}");
3458 let prog = prog.expect("should parse");
3459
3460 assert_eq!(prog.functions.len(), 1);
3461 let func = &prog.functions[0];
3462 assert_eq!(func.name.name, "apply");
3463 assert_eq!(func.params.len(), 2);
3464
3465 if let TypeExpr::Fn(params, ret) = &func.params[0].ty {
3467 assert_eq!(params.len(), 1);
3468 assert!(matches!(params[0], TypeExpr::Int));
3469 assert!(matches!(ret.as_ref(), TypeExpr::Int));
3470 } else {
3471 panic!("expected Fn type for first param");
3472 }
3473 }
3474
3475 #[test]
3476 fn parse_closure_with_params() {
3477 let source = r#"
3478 agent Main {
3479 on start {
3480 let f = |x: Int| x + 1;
3481 emit(0);
3482 }
3483 }
3484 run Main;
3485 "#;
3486
3487 let (prog, errors) = parse_str(source);
3488 assert!(errors.is_empty(), "errors: {errors:?}");
3489 let prog = prog.expect("should parse");
3490
3491 let handler = &prog.agents[0].handlers[0];
3493 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
3494 if let Expr::Closure { params, body, .. } = value {
3495 assert_eq!(params.len(), 1);
3496 assert_eq!(params[0].name.name, "x");
3497 assert!(matches!(¶ms[0].ty, Some(TypeExpr::Int)));
3498
3499 assert!(matches!(body.as_ref(), Expr::Binary { .. }));
3501 } else {
3502 panic!("expected closure expression");
3503 }
3504 } else {
3505 panic!("expected let statement");
3506 }
3507 }
3508
3509 #[test]
3510 fn parse_closure_empty_params() {
3511 let source = r#"
3512 agent Main {
3513 on start {
3514 let f = || 42;
3515 emit(0);
3516 }
3517 }
3518 run Main;
3519 "#;
3520
3521 let (prog, errors) = parse_str(source);
3522 assert!(errors.is_empty(), "errors: {errors:?}");
3523 let prog = prog.expect("should parse");
3524
3525 let handler = &prog.agents[0].handlers[0];
3527 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
3528 if let Expr::Closure { params, body, .. } = value {
3529 assert!(params.is_empty());
3530
3531 assert!(matches!(body.as_ref(), Expr::Literal { .. }));
3533 } else {
3534 panic!("expected closure expression");
3535 }
3536 } else {
3537 panic!("expected let statement");
3538 }
3539 }
3540
3541 #[test]
3542 fn parse_closure_multiple_params() {
3543 let source = r#"
3544 agent Main {
3545 on start {
3546 let add = |x: Int, y: Int| x + y;
3547 emit(0);
3548 }
3549 }
3550 run Main;
3551 "#;
3552
3553 let (prog, errors) = parse_str(source);
3554 assert!(errors.is_empty(), "errors: {errors:?}");
3555 let prog = prog.expect("should parse");
3556
3557 let handler = &prog.agents[0].handlers[0];
3558 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
3559 if let Expr::Closure { params, .. } = value {
3560 assert_eq!(params.len(), 2);
3561 assert_eq!(params[0].name.name, "x");
3562 assert_eq!(params[1].name.name, "y");
3563 } else {
3564 panic!("expected closure expression");
3565 }
3566 } else {
3567 panic!("expected let statement");
3568 }
3569 }
3570
3571 #[test]
3572 fn parse_fn_type_multiarg() {
3573 let source = r#"
3574 fn fold_left(f: Fn(Int, Int) -> Int, init: Int) -> Int {
3575 return init;
3576 }
3577
3578 agent Main {
3579 on start {
3580 emit(0);
3581 }
3582 }
3583 run Main;
3584 "#;
3585
3586 let (prog, errors) = parse_str(source);
3587 assert!(errors.is_empty(), "errors: {errors:?}");
3588 let prog = prog.expect("should parse");
3589
3590 if let TypeExpr::Fn(params, ret) = &prog.functions[0].params[0].ty {
3592 assert_eq!(params.len(), 2);
3593 assert!(matches!(params[0], TypeExpr::Int));
3594 assert!(matches!(params[1], TypeExpr::Int));
3595 assert!(matches!(ret.as_ref(), TypeExpr::Int));
3596 } else {
3597 panic!("expected Fn type");
3598 }
3599 }
3600
3601 #[test]
3602 fn parse_tuple_literal() {
3603 let source = r#"
3604 agent Main {
3605 on start {
3606 let t = (1, 2);
3607 emit(0);
3608 }
3609 }
3610 run Main;
3611 "#;
3612
3613 let (prog, errors) = parse_str(source);
3614 assert!(errors.is_empty(), "errors: {errors:?}");
3615 let prog = prog.expect("should parse");
3616
3617 let handler = &prog.agents[0].handlers[0];
3618 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
3619 if let Expr::Tuple { elements, .. } = value {
3620 assert_eq!(elements.len(), 2);
3621 } else {
3622 panic!("expected tuple expression, got {:?}", value);
3623 }
3624 } else {
3625 panic!("expected let statement");
3626 }
3627 }
3628
3629 #[test]
3634 fn parse_tool_declaration() {
3635 let source = r#"
3636 tool Http {
3637 fn get(url: String) -> Result<String, String>
3638 fn post(url: String, body: String) -> Result<String, String>
3639 }
3640 agent Main {
3641 on start { emit(0); }
3642 }
3643 run Main;
3644 "#;
3645
3646 let (prog, errors) = parse_str(source);
3647 assert!(errors.is_empty(), "errors: {errors:?}");
3648 let prog = prog.expect("should parse");
3649
3650 assert_eq!(prog.tools.len(), 1);
3651 assert_eq!(prog.tools[0].name.name, "Http");
3652 assert_eq!(prog.tools[0].functions.len(), 2);
3653 assert_eq!(prog.tools[0].functions[0].name.name, "get");
3654 assert_eq!(prog.tools[0].functions[1].name.name, "post");
3655 }
3656
3657 #[test]
3658 fn parse_pub_tool_declaration() {
3659 let source = r#"
3660 pub tool Database {
3661 fn query(sql: String) -> Result<List<String>, String>
3662 }
3663 agent Main {
3664 on start { emit(0); }
3665 }
3666 run Main;
3667 "#;
3668
3669 let (prog, errors) = parse_str(source);
3670 assert!(errors.is_empty(), "errors: {errors:?}");
3671 let prog = prog.expect("should parse");
3672
3673 assert!(prog.tools[0].is_pub);
3674 assert_eq!(prog.tools[0].name.name, "Database");
3675 }
3676
3677 #[test]
3678 fn parse_agent_with_tool_use() {
3679 let source = r#"
3680 agent Fetcher {
3681 use Http
3682
3683 url: String
3684
3685 on start {
3686 emit(0);
3687 }
3688 }
3689 run Fetcher;
3690 "#;
3691
3692 let (prog, errors) = parse_str(source);
3693 assert!(errors.is_empty(), "errors: {errors:?}");
3694 let prog = prog.expect("should parse");
3695
3696 assert_eq!(prog.agents[0].tool_uses.len(), 1);
3697 assert_eq!(prog.agents[0].tool_uses[0].name, "Http");
3698 assert_eq!(prog.agents[0].beliefs.len(), 1);
3699 }
3700
3701 #[test]
3702 fn parse_agent_with_multiple_tool_uses() {
3703 let source = r#"
3704 agent Pipeline {
3705 use Http, Fs
3706
3707 on start {
3708 emit(0);
3709 }
3710 }
3711 run Pipeline;
3712 "#;
3713
3714 let (prog, errors) = parse_str(source);
3715 assert!(errors.is_empty(), "errors: {errors:?}");
3716 let prog = prog.expect("should parse");
3717
3718 assert_eq!(prog.agents[0].tool_uses.len(), 2);
3719 assert_eq!(prog.agents[0].tool_uses[0].name, "Http");
3720 assert_eq!(prog.agents[0].tool_uses[1].name, "Fs");
3721 }
3722
3723 #[test]
3724 fn parse_tool_call_expression() {
3725 let source = r#"
3726 agent Fetcher {
3727 use Http
3728
3729 on start {
3730 let response = Http.get("https://example.com");
3731 emit(0);
3732 }
3733 }
3734 run Fetcher;
3735 "#;
3736
3737 let (prog, errors) = parse_str(source);
3738 assert!(errors.is_empty(), "errors: {errors:?}");
3739 let prog = prog.expect("should parse");
3740
3741 let handler = &prog.agents[0].handlers[0];
3742 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
3743 if let Expr::ToolCall {
3744 tool,
3745 function,
3746 args,
3747 ..
3748 } = value
3749 {
3750 assert_eq!(tool.name, "Http");
3751 assert_eq!(function.name, "get");
3752 assert_eq!(args.len(), 1);
3753 } else {
3754 panic!("expected ToolCall expression, got {:?}", value);
3755 }
3756 } else {
3757 panic!("expected let statement");
3758 }
3759 }
3760
3761 #[test]
3762 fn parse_tool_call_with_multiple_args() {
3763 let source = r#"
3764 agent Writer {
3765 use Fs
3766
3767 on start {
3768 let result = Fs.write("/tmp/test.txt", "hello world");
3769 emit(0);
3770 }
3771 }
3772 run Writer;
3773 "#;
3774
3775 let (prog, errors) = parse_str(source);
3776 assert!(errors.is_empty(), "errors: {errors:?}");
3777 let prog = prog.expect("should parse");
3778
3779 let handler = &prog.agents[0].handlers[0];
3780 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
3781 if let Expr::ToolCall { args, .. } = value {
3782 assert_eq!(args.len(), 2);
3783 } else {
3784 panic!("expected ToolCall expression, got {:?}", value);
3785 }
3786 } else {
3787 panic!("expected let statement");
3788 }
3789 }
3790
3791 #[test]
3792 fn parse_string_interp_with_field_access() {
3793 let source = r#"
3794 record Person { name: String }
3795 agent Main {
3796 on start {
3797 let p = Person { name: "Alice" };
3798 print("Hello, {p.name}!");
3799 emit(0);
3800 }
3801 }
3802 run Main;
3803 "#;
3804
3805 let (prog, errors) = parse_str(source);
3806 assert!(errors.is_empty(), "errors: {errors:?}");
3807 let prog = prog.expect("should parse");
3808
3809 let handler = &prog.agents[0].handlers[0];
3811 if let Stmt::Expr { expr, .. } = &handler.body.stmts[1] {
3812 if let Expr::Call { args, .. } = expr {
3813 if let Expr::StringInterp { template, .. } = &args[0] {
3814 assert!(template.has_interpolations());
3815 let interps: Vec<_> = template.interpolations().collect();
3816 assert_eq!(interps.len(), 1);
3817 match interps[0] {
3819 InterpExpr::FieldAccess { base, field, .. } => {
3820 assert_eq!(base.base_ident().name, "p");
3821 assert_eq!(field.name, "name");
3822 }
3823 _ => panic!("expected FieldAccess, got {:?}", interps[0]),
3824 }
3825 } else {
3826 panic!("expected StringInterp");
3827 }
3828 } else {
3829 panic!("expected Call");
3830 }
3831 } else {
3832 panic!("expected Expr statement");
3833 }
3834 }
3835
3836 #[test]
3837 fn parse_string_interp_with_tuple_index() {
3838 let source = r#"
3839 agent Main {
3840 on start {
3841 let pair = (1, 2);
3842 print("First: {pair.0}");
3843 emit(0);
3844 }
3845 }
3846 run Main;
3847 "#;
3848
3849 let (prog, errors) = parse_str(source);
3850 assert!(errors.is_empty(), "errors: {errors:?}");
3851 let prog = prog.expect("should parse");
3852
3853 let handler = &prog.agents[0].handlers[0];
3854 if let Stmt::Expr { expr, .. } = &handler.body.stmts[1] {
3855 if let Expr::Call { args, .. } = expr {
3856 if let Expr::StringInterp { template, .. } = &args[0] {
3857 let interps: Vec<_> = template.interpolations().collect();
3858 assert_eq!(interps.len(), 1);
3859 match interps[0] {
3860 InterpExpr::TupleIndex { base, index, .. } => {
3861 assert_eq!(base.base_ident().name, "pair");
3862 assert_eq!(*index, 0);
3863 }
3864 _ => panic!("expected TupleIndex, got {:?}", interps[0]),
3865 }
3866 } else {
3867 panic!("expected StringInterp");
3868 }
3869 } else {
3870 panic!("expected Call");
3871 }
3872 } else {
3873 panic!("expected Expr statement");
3874 }
3875 }
3876}