1use crate::ast::{
6 AgentDecl, BeliefDecl, BinOp, Block, ClosureParam, ConstDecl, ElseBranch, EnumDecl, EventKind,
7 Expr, FieldInit, FnDecl, HandlerDecl, Literal, MapEntry, MatchArm, MockValue, ModDecl, Param,
8 Pattern, Program, RecordDecl, RecordField, Stmt, StringPart, StringTemplate, TestDecl,
9 ToolDecl, ToolFnDecl, UnaryOp, UseDecl, UseKind,
10};
11use crate::{Ident, Span, TypeExpr};
12use crate::{Spanned, Token};
13use chumsky::prelude::*;
14use chumsky::BoxedParser;
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 type_params_parser(
261 source: Arc<str>,
262) -> impl Parser<Token, Vec<Ident>, Error = ParseError> + Clone {
263 ident_token_parser(source)
264 .separated_by(just(Token::Comma))
265 .allow_trailing()
266 .delimited_by(just(Token::Lt), just(Token::Gt))
267 .or_not()
268 .map(|params| params.unwrap_or_default())
269}
270
271fn record_parser(source: Arc<str>) -> impl Parser<Token, TopLevel, Error = ParseError> {
272 let src = source.clone();
273 let src2 = source.clone();
274
275 let field = ident_token_parser(src.clone())
277 .then_ignore(just(Token::Colon))
278 .then(type_parser(src.clone()))
279 .map_with_span(move |(name, ty), span: Range<usize>| RecordField {
280 name,
281 ty,
282 span: make_span(&src, span),
283 });
284
285 just(Token::KwPub)
286 .or_not()
287 .then_ignore(just(Token::KwRecord))
288 .then(ident_token_parser(src2.clone()))
289 .then(type_params_parser(src2.clone()))
290 .then(
291 field
292 .separated_by(just(Token::Comma))
293 .allow_trailing()
294 .delimited_by(just(Token::LBrace), just(Token::RBrace)),
295 )
296 .map_with_span(
297 move |(((is_pub, name), type_params), fields), span: Range<usize>| {
298 TopLevel::Record(RecordDecl {
299 is_pub: is_pub.is_some(),
300 name,
301 type_params,
302 fields,
303 span: make_span(&src2, span),
304 })
305 },
306 )
307}
308
309#[allow(clippy::needless_pass_by_value)]
311fn enum_parser(source: Arc<str>) -> impl Parser<Token, TopLevel, Error = ParseError> {
312 let src = source.clone();
313 let src2 = source.clone();
314 let src3 = source.clone();
315
316 let variant = ident_token_parser(src.clone())
318 .then(
319 type_parser(src.clone())
320 .delimited_by(just(Token::LParen), just(Token::RParen))
321 .or_not(),
322 )
323 .map_with_span({
324 let src = src.clone();
325 move |(name, payload), span: Range<usize>| crate::ast::EnumVariant {
326 name,
327 payload,
328 span: make_span(&src, span),
329 }
330 });
331
332 just(Token::KwPub)
333 .or_not()
334 .then_ignore(just(Token::KwEnum))
335 .then(ident_token_parser(src3.clone()))
336 .then(type_params_parser(src3.clone()))
337 .then(
338 variant
339 .separated_by(just(Token::Comma))
340 .allow_trailing()
341 .delimited_by(just(Token::LBrace), just(Token::RBrace)),
342 )
343 .map_with_span(
344 move |(((is_pub, name), type_params), variants), span: Range<usize>| {
345 TopLevel::Enum(EnumDecl {
346 is_pub: is_pub.is_some(),
347 name,
348 type_params,
349 variants,
350 span: make_span(&src2, span),
351 })
352 },
353 )
354}
355
356#[allow(clippy::needless_pass_by_value)]
358fn const_parser(source: Arc<str>) -> impl Parser<Token, TopLevel, Error = ParseError> {
359 let src = source.clone();
360 let src2 = source.clone();
361
362 just(Token::KwPub)
363 .or_not()
364 .then_ignore(just(Token::KwConst))
365 .then(ident_token_parser(src.clone()))
366 .then_ignore(just(Token::Colon))
367 .then(type_parser(src.clone()))
368 .then_ignore(just(Token::Eq))
369 .then(expr_parser(src.clone()))
370 .then_ignore(just(Token::Semicolon))
371 .map_with_span(move |(((is_pub, name), ty), value), span: Range<usize>| {
372 TopLevel::Const(ConstDecl {
373 is_pub: is_pub.is_some(),
374 name,
375 ty,
376 value,
377 span: make_span(&src2, span),
378 })
379 })
380}
381
382#[allow(clippy::needless_pass_by_value)]
388fn tool_parser(source: Arc<str>) -> impl Parser<Token, TopLevel, Error = ParseError> {
389 let src = source.clone();
390 let src2 = source.clone();
391 let src3 = source.clone();
392
393 let param = ident_token_parser(src.clone())
395 .then_ignore(just(Token::Colon))
396 .then(type_parser(src.clone()))
397 .map_with_span(move |(name, ty), span: Range<usize>| Param {
398 name,
399 ty,
400 span: make_span(&src, span),
401 });
402
403 let params = param
404 .separated_by(just(Token::Comma))
405 .allow_trailing()
406 .delimited_by(just(Token::LParen), just(Token::RParen));
407
408 let tool_fn = just(Token::KwFn)
410 .ignore_then(ident_token_parser(src2.clone()))
411 .then(params)
412 .then_ignore(just(Token::Arrow))
413 .then(type_parser(src2.clone()))
414 .map_with_span(
415 move |((name, params), return_ty), span: Range<usize>| ToolFnDecl {
416 name,
417 params,
418 return_ty,
419 span: make_span(&src2, span),
420 },
421 );
422
423 just(Token::KwPub)
424 .or_not()
425 .then_ignore(just(Token::KwTool))
426 .then(ident_token_parser(src3.clone()))
427 .then(
428 tool_fn
429 .repeated()
430 .delimited_by(just(Token::LBrace), just(Token::RBrace)),
431 )
432 .map_with_span(move |((is_pub, name), functions), span: Range<usize>| {
433 TopLevel::Tool(ToolDecl {
434 is_pub: is_pub.is_some(),
435 name,
436 functions,
437 span: make_span(&src3, span),
438 })
439 })
440}
441
442#[allow(clippy::needless_pass_by_value)]
448fn test_parser(source: Arc<str>) -> impl Parser<Token, TopLevel, Error = ParseError> {
449 let src = source.clone();
450 let src2 = source.clone();
451
452 let serial_annotation = just(Token::At)
455 .then(filter(|t: &Token| matches!(t, Token::Ident)))
456 .or_not()
457 .map(|opt| opt.is_some());
458
459 let test_name = filter_map(|span: Range<usize>, tok: Token| match tok {
461 Token::StringLit => Ok(()),
462 _ => Err(Simple::expected_input_found(span, [], Some(tok))),
463 })
464 .map_with_span(move |_, span: Range<usize>| {
465 let s = &src[span.clone()];
467 s[1..s.len() - 1].to_string()
468 });
469
470 let body = block_parser(src2.clone());
472
473 serial_annotation
474 .then_ignore(just(Token::KwTest))
475 .then(test_name)
476 .then(body)
477 .map_with_span(move |((is_serial, name), body), span: Range<usize>| {
478 TopLevel::Test(TestDecl {
479 name,
480 is_serial,
481 body,
482 span: make_span(&src2, span),
483 })
484 })
485}
486
487#[allow(clippy::needless_pass_by_value)]
493fn agent_parser(source: Arc<str>) -> impl Parser<Token, TopLevel, Error = ParseError> {
494 let src = source.clone();
495 let src2 = source.clone();
496 let src3 = source.clone();
497 let src4 = source.clone();
498 let src5 = source.clone();
499
500 let tool_use = just(Token::KwUse)
502 .ignore_then(
503 ident_token_parser(src5.clone())
504 .separated_by(just(Token::Comma))
505 .at_least(1),
506 )
507 .or_not()
508 .map(|tools| tools.unwrap_or_default());
509
510 let belief = ident_token_parser(src.clone())
513 .then_ignore(just(Token::Colon))
514 .then(type_parser(src.clone()))
515 .map_with_span(move |(name, ty), span: Range<usize>| BeliefDecl {
516 name,
517 ty,
518 span: make_span(&src, span),
519 });
520
521 let handler = just(Token::KwOn)
522 .ignore_then(event_kind_parser(src2.clone()))
523 .then(block_parser(src2.clone()))
524 .map_with_span(move |(event, body), span: Range<usize>| HandlerDecl {
525 event,
526 body,
527 span: make_span(&src2, span),
528 });
529
530 let receives_clause = just(Token::KwReceives)
532 .ignore_then(type_parser(src3.clone()))
533 .or_not();
534
535 just(Token::KwPub)
536 .or_not()
537 .then_ignore(just(Token::KwAgent))
538 .then(ident_token_parser(src3.clone()))
539 .then(receives_clause)
540 .then_ignore(just(Token::LBrace))
541 .then(tool_use)
542 .then(belief.repeated())
543 .then(handler.repeated())
544 .then_ignore(just(Token::RBrace))
545 .map_with_span(
546 move |(((((is_pub, name), receives), tool_uses), beliefs), handlers),
547 span: Range<usize>| {
548 TopLevel::Agent(AgentDecl {
549 is_pub: is_pub.is_some(),
550 name,
551 receives,
552 tool_uses,
553 beliefs,
554 handlers,
555 span: make_span(&src4, span),
556 })
557 },
558 )
559}
560
561#[allow(clippy::needless_pass_by_value)]
563fn event_kind_parser(source: Arc<str>) -> impl Parser<Token, EventKind, Error = ParseError> {
564 let src = source.clone();
565
566 let start = just(Token::KwStart).to(EventKind::Start);
567 let stop = just(Token::KwStop).to(EventKind::Stop);
568
569 let message = just(Token::KwMessage)
570 .ignore_then(just(Token::LParen))
571 .ignore_then(ident_token_parser(src.clone()))
572 .then_ignore(just(Token::Colon))
573 .then(type_parser(src.clone()))
574 .then_ignore(just(Token::RParen))
575 .map(|(param_name, param_ty)| EventKind::Message {
576 param_name,
577 param_ty,
578 });
579
580 let error = just(Token::KwError)
582 .ignore_then(just(Token::LParen))
583 .ignore_then(ident_token_parser(src))
584 .then_ignore(just(Token::RParen))
585 .map(|param_name| EventKind::Error { param_name });
586
587 start.or(stop).or(message).or(error)
588}
589
590#[allow(clippy::needless_pass_by_value)]
596fn fn_parser(source: Arc<str>) -> impl Parser<Token, TopLevel, Error = ParseError> {
597 let src = source.clone();
598 let src2 = source.clone();
599 let src3 = source.clone();
600
601 let param = ident_token_parser(src.clone())
602 .then_ignore(just(Token::Colon))
603 .then(type_parser(src.clone()))
604 .map_with_span(move |(name, ty), span: Range<usize>| Param {
605 name,
606 ty,
607 span: make_span(&src, span),
608 });
609
610 let params = param
611 .separated_by(just(Token::Comma))
612 .allow_trailing()
613 .delimited_by(just(Token::LParen), just(Token::RParen));
614
615 just(Token::KwPub)
616 .or_not()
617 .then_ignore(just(Token::KwFn))
618 .then(ident_token_parser(src2.clone()))
619 .then(type_params_parser(src2.clone()))
620 .then(params)
621 .then_ignore(just(Token::Arrow))
622 .then(type_parser(src2.clone()))
623 .then(just(Token::KwFails).or_not())
624 .then(block_parser(src2))
625 .map_with_span(
626 move |((((((is_pub, name), type_params), params), return_ty), is_fallible), body),
627 span: Range<usize>| {
628 TopLevel::Function(FnDecl {
629 is_pub: is_pub.is_some(),
630 name,
631 type_params,
632 params,
633 return_ty,
634 is_fallible: is_fallible.is_some(),
635 body,
636 span: make_span(&src3, span),
637 })
638 },
639 )
640}
641
642#[allow(clippy::needless_pass_by_value)]
649fn block_parser(source: Arc<str>) -> BoxedParser<'static, Token, Block, ParseError> {
650 let src = source.clone();
651
652 recursive(move |block: Recursive<Token, Block, ParseError>| {
653 let src_inner = src.clone();
654 stmt_parser(src.clone(), block)
655 .repeated()
656 .delimited_by(just(Token::LBrace), just(Token::RBrace))
657 .recover_with(nested_delimiters(
658 Token::LBrace,
659 Token::RBrace,
660 [
661 (Token::LParen, Token::RParen),
662 (Token::LBracket, Token::RBracket),
663 ],
664 |_span: Range<usize>| vec![],
665 ))
666 .map_with_span(move |stmts, span: Range<usize>| Block {
667 stmts,
668 span: make_span(&src_inner, span),
669 })
670 })
671 .boxed()
672}
673
674#[allow(clippy::needless_pass_by_value)]
676fn stmt_parser(
677 source: Arc<str>,
678 block: impl Parser<Token, Block, Error = ParseError> + Clone + 'static,
679) -> impl Parser<Token, Stmt, Error = ParseError> + Clone {
680 let src = source.clone();
681 let src2 = source.clone();
682 let src3 = source.clone();
683 let src4 = source.clone();
684 let src5 = source.clone();
685 let src6 = source.clone();
686 let src7 = source.clone();
687
688 let src10 = source.clone();
690 let let_tuple_stmt = just(Token::KwLet)
691 .ignore_then(
692 ident_token_parser(src10.clone())
693 .separated_by(just(Token::Comma))
694 .at_least(2)
695 .allow_trailing()
696 .delimited_by(just(Token::LParen), just(Token::RParen)),
697 )
698 .then(
699 just(Token::Colon)
700 .ignore_then(type_parser(src10.clone()))
701 .or_not(),
702 )
703 .then_ignore(just(Token::Eq))
704 .then(expr_parser(src10.clone()))
705 .then_ignore(just(Token::Semicolon))
706 .map_with_span(
707 move |((names, ty), value), span: Range<usize>| Stmt::LetTuple {
708 names,
709 ty,
710 value,
711 span: make_span(&src10, span),
712 },
713 );
714
715 let let_stmt = just(Token::KwLet)
716 .ignore_then(ident_token_parser(src.clone()))
717 .then(
718 just(Token::Colon)
719 .ignore_then(type_parser(src.clone()))
720 .or_not(),
721 )
722 .then_ignore(just(Token::Eq))
723 .then(expr_parser(src.clone()))
724 .then_ignore(just(Token::Semicolon))
725 .map_with_span(move |((name, ty), value), span: Range<usize>| Stmt::Let {
726 name,
727 ty,
728 value,
729 span: make_span(&src, span),
730 });
731
732 let return_stmt = just(Token::KwReturn)
733 .ignore_then(expr_parser(src2.clone()).or_not())
734 .then_ignore(just(Token::Semicolon))
735 .map_with_span(move |value, span: Range<usize>| Stmt::Return {
736 value,
737 span: make_span(&src2, span),
738 });
739
740 let if_stmt = recursive(|if_stmt| {
741 let src_if = src3.clone();
742 let block_clone = block.clone();
743
744 just(Token::KwIf)
745 .ignore_then(expr_parser(src3.clone()))
746 .then(block_clone.clone())
747 .then(
748 just(Token::KwElse)
749 .ignore_then(
750 if_stmt
751 .map(|s| ElseBranch::ElseIf(Box::new(s)))
752 .or(block_clone.map(ElseBranch::Block)),
753 )
754 .or_not(),
755 )
756 .map_with_span(
757 move |((condition, then_block), else_block), span: Range<usize>| Stmt::If {
758 condition,
759 then_block,
760 else_block,
761 span: make_span(&src_if, span),
762 },
763 )
764 });
765
766 let for_stmt = just(Token::KwFor)
767 .ignore_then(for_pattern_parser(src4.clone()))
768 .then_ignore(just(Token::KwIn))
769 .then(expr_parser(src4.clone()))
770 .then(block.clone())
771 .map_with_span(
772 move |((pattern, iter), body), span: Range<usize>| Stmt::For {
773 pattern,
774 iter,
775 body,
776 span: make_span(&src4, span),
777 },
778 );
779
780 let while_stmt = just(Token::KwWhile)
781 .ignore_then(expr_parser(src7.clone()))
782 .then(block.clone())
783 .map_with_span(move |(condition, body), span: Range<usize>| Stmt::While {
784 condition,
785 body,
786 span: make_span(&src7, span),
787 });
788
789 let src8 = source.clone();
790 let loop_stmt = just(Token::KwLoop)
791 .ignore_then(block.clone())
792 .map_with_span(move |body, span: Range<usize>| Stmt::Loop {
793 body,
794 span: make_span(&src8, span),
795 });
796
797 let src9 = source.clone();
798 let break_stmt = just(Token::KwBreak)
799 .then_ignore(just(Token::Semicolon))
800 .map_with_span(move |_, span: Range<usize>| Stmt::Break {
801 span: make_span(&src9, span),
802 });
803
804 let src12 = source.clone();
806 let mock_divine_stmt = just(Token::KwMock)
807 .ignore_then(just(Token::KwDivine))
808 .ignore_then(just(Token::Arrow))
809 .ignore_then(expr_parser(src12.clone()).map(|expr| {
810 if let Expr::Fail { error, .. } = expr {
812 MockValue::Fail(*error)
813 } else {
814 MockValue::Value(expr)
815 }
816 }))
817 .then_ignore(just(Token::Semicolon))
818 .map_with_span(move |value, span: Range<usize>| Stmt::MockDivine {
819 value,
820 span: make_span(&src12, span),
821 });
822
823 let src13 = source.clone();
825 let src14 = source.clone();
826 let src15 = source.clone();
827 let mock_tool_stmt = just(Token::KwMock)
828 .ignore_then(just(Token::KwTool))
829 .ignore_then(ident_token_parser(src13.clone())) .then_ignore(just(Token::Dot))
831 .then(ident_token_parser(src14.clone())) .then_ignore(just(Token::Arrow))
833 .then(expr_parser(src15.clone()).map(|expr| {
834 if let Expr::Fail { error, .. } = expr {
836 MockValue::Fail(*error)
837 } else {
838 MockValue::Value(expr)
839 }
840 }))
841 .then_ignore(just(Token::Semicolon))
842 .map_with_span(
843 move |((tool_name, fn_name), value), span: Range<usize>| Stmt::MockTool {
844 tool_name,
845 fn_name,
846 value,
847 span: make_span(&src15, span),
848 },
849 );
850
851 let assign_stmt = ident_token_parser(src5.clone())
852 .then_ignore(just(Token::Eq))
853 .then(expr_parser(src5.clone()))
854 .then_ignore(just(Token::Semicolon))
855 .map_with_span(move |(name, value), span: Range<usize>| Stmt::Assign {
856 name,
857 value,
858 span: make_span(&src5, span),
859 });
860
861 let expr_stmt = expr_parser(src6.clone())
862 .then_ignore(just(Token::Semicolon))
863 .map_with_span(move |expr, span: Range<usize>| Stmt::Expr {
864 expr,
865 span: make_span(&src6, span),
866 });
867
868 let_tuple_stmt
869 .or(let_stmt)
870 .or(return_stmt)
871 .or(if_stmt)
872 .or(for_stmt)
873 .or(while_stmt)
874 .or(loop_stmt)
875 .or(break_stmt)
876 .or(mock_divine_stmt)
877 .or(mock_tool_stmt)
878 .or(assign_stmt)
879 .or(expr_stmt)
880}
881
882#[allow(clippy::needless_pass_by_value, clippy::too_many_lines)]
889fn expr_parser(source: Arc<str>) -> BoxedParser<'static, Token, Expr, ParseError> {
890 recursive(move |expr: Recursive<Token, Expr, ParseError>| {
891 let src = source.clone();
892
893 let literal = literal_parser(src.clone());
894 let var = var_parser(src.clone());
895
896 let paren_or_tuple = just(Token::LParen)
899 .ignore_then(
900 expr.clone()
901 .separated_by(just(Token::Comma))
902 .allow_trailing(),
903 )
904 .then_ignore(just(Token::RParen))
905 .map_with_span({
906 let src = src.clone();
907 move |elements, span: Range<usize>| {
908 if elements.len() == 1 {
909 Expr::Paren {
911 inner: Box::new(elements.into_iter().next().unwrap()),
912 span: make_span(&src, span),
913 }
914 } else {
915 Expr::Tuple {
917 elements,
918 span: make_span(&src, span),
919 }
920 }
921 }
922 });
923
924 let list = expr
925 .clone()
926 .separated_by(just(Token::Comma))
927 .allow_trailing()
928 .delimited_by(just(Token::LBracket), just(Token::RBracket))
929 .map_with_span({
930 let src = src.clone();
931 move |elements, span: Range<usize>| Expr::List {
932 elements,
933 span: make_span(&src, span),
934 }
935 });
936
937 let self_access = just(Token::KwSelf)
939 .ignore_then(just(Token::Dot))
940 .ignore_then(ident_token_parser(src.clone()))
941 .then(
942 expr.clone()
943 .separated_by(just(Token::Comma))
944 .allow_trailing()
945 .delimited_by(just(Token::LParen), just(Token::RParen))
946 .or_not(),
947 )
948 .map_with_span({
949 let src = src.clone();
950 move |(field, args), span: Range<usize>| match args {
951 Some(args) => Expr::SelfMethodCall {
952 method: field,
953 args,
954 span: make_span(&src, span),
955 },
956 None => Expr::SelfField {
957 field,
958 span: make_span(&src, span),
959 },
960 }
961 });
962
963 let divine_expr = just(Token::KwDivine)
965 .ignore_then(just(Token::LParen))
966 .ignore_then(string_template_parser(src.clone()))
967 .then(
968 just(Token::Arrow)
969 .ignore_then(type_parser(src.clone()))
970 .or_not(),
971 )
972 .then_ignore(just(Token::RParen))
973 .map_with_span({
974 let src = src.clone();
975 move |(template, result_ty), span: Range<usize>| Expr::Divine {
976 template,
977 result_ty,
978 span: make_span(&src, span),
979 }
980 });
981
982 let summon_field_init = ident_token_parser(src.clone())
984 .then_ignore(just(Token::Colon))
985 .then(expr.clone())
986 .map_with_span({
987 let src = src.clone();
988 move |(name, value), span: Range<usize>| FieldInit {
989 name,
990 value,
991 span: make_span(&src, span),
992 }
993 });
994
995 let summon_expr = just(Token::KwSummon)
996 .ignore_then(ident_token_parser(src.clone()))
997 .then_ignore(just(Token::LBrace))
998 .then(
999 summon_field_init
1000 .separated_by(just(Token::Comma))
1001 .allow_trailing(),
1002 )
1003 .then_ignore(just(Token::RBrace))
1004 .map_with_span({
1005 let src = src.clone();
1006 move |(agent, fields), span: Range<usize>| Expr::Summon {
1007 agent,
1008 fields,
1009 span: make_span(&src, span),
1010 }
1011 });
1012
1013 let timeout_clause = just(Token::KwTimeout)
1016 .ignore_then(just(Token::LParen))
1017 .ignore_then(expr.clone())
1018 .then_ignore(just(Token::RParen));
1019
1020 let await_expr = just(Token::KwAwait)
1021 .ignore_then(ident_token_parser(src.clone()).map_with_span({
1022 let src = src.clone();
1023 move |name, span: Range<usize>| Expr::Var {
1024 name,
1025 span: make_span(&src, span),
1026 }
1027 }))
1028 .then(timeout_clause.or_not())
1029 .map_with_span({
1030 let src = src.clone();
1031 move |(handle, timeout), span: Range<usize>| Expr::Await {
1032 handle: Box::new(handle),
1033 timeout: timeout.map(Box::new),
1034 span: make_span(&src, span),
1035 }
1036 });
1037
1038 let send_expr = just(Token::KwSend)
1040 .ignore_then(just(Token::LParen))
1041 .ignore_then(expr.clone())
1042 .then_ignore(just(Token::Comma))
1043 .then(expr.clone())
1044 .then_ignore(just(Token::RParen))
1045 .map_with_span({
1046 let src = src.clone();
1047 move |(handle, message), span: Range<usize>| Expr::Send {
1048 handle: Box::new(handle),
1049 message: Box::new(message),
1050 span: make_span(&src, span),
1051 }
1052 });
1053
1054 let yield_expr = just(Token::KwYield)
1056 .ignore_then(just(Token::LParen))
1057 .ignore_then(expr.clone())
1058 .then_ignore(just(Token::RParen))
1059 .map_with_span({
1060 let src = src.clone();
1061 move |value, span: Range<usize>| Expr::Yield {
1062 value: Box::new(value),
1063 span: make_span(&src, span),
1064 }
1065 });
1066
1067 let turbofish = just(Token::ColonColon)
1069 .ignore_then(
1070 type_parser(src.clone())
1071 .separated_by(just(Token::Comma))
1072 .allow_trailing()
1073 .delimited_by(just(Token::Lt), just(Token::Gt)),
1074 )
1075 .or_not()
1076 .map(|args| args.unwrap_or_default());
1077
1078 let call_expr = ident_token_parser(src.clone())
1080 .then(turbofish.clone())
1081 .then(
1082 expr.clone()
1083 .separated_by(just(Token::Comma))
1084 .allow_trailing()
1085 .delimited_by(just(Token::LParen), just(Token::RParen)),
1086 )
1087 .map_with_span({
1088 let src = src.clone();
1089 move |((name, type_args), args), span: Range<usize>| Expr::Call {
1090 name,
1091 type_args,
1092 args,
1093 span: make_span(&src, span),
1094 }
1095 });
1096
1097 let pattern = pattern_parser(src.clone());
1099
1100 let match_arm = pattern
1102 .then_ignore(just(Token::FatArrow))
1103 .then(expr.clone())
1104 .map_with_span({
1105 let src = src.clone();
1106 move |(pattern, body), span: Range<usize>| MatchArm {
1107 pattern,
1108 body,
1109 span: make_span(&src, span),
1110 }
1111 });
1112
1113 let match_expr = just(Token::KwMatch)
1114 .ignore_then(expr.clone())
1115 .then(
1116 match_arm
1117 .separated_by(just(Token::Comma))
1118 .allow_trailing()
1119 .delimited_by(just(Token::LBrace), just(Token::RBrace)),
1120 )
1121 .map_with_span({
1122 let src = src.clone();
1123 move |(scrutinee, arms), span: Range<usize>| Expr::Match {
1124 scrutinee: Box::new(scrutinee),
1125 arms,
1126 span: make_span(&src, span),
1127 }
1128 });
1129
1130 let receive_expr = just(Token::KwReceive)
1132 .ignore_then(just(Token::LParen))
1133 .ignore_then(just(Token::RParen))
1134 .map_with_span({
1135 let src = src.clone();
1136 move |_, span: Range<usize>| Expr::Receive {
1137 span: make_span(&src, span),
1138 }
1139 });
1140
1141 let trace_expr = just(Token::KwTrace)
1143 .ignore_then(just(Token::LParen))
1144 .ignore_then(expr.clone())
1145 .then_ignore(just(Token::RParen))
1146 .map_with_span({
1147 let src = src.clone();
1148 move |message, span: Range<usize>| Expr::Trace {
1149 message: Box::new(message),
1150 span: make_span(&src, span),
1151 }
1152 });
1153
1154 let record_field_init = ident_token_parser(src.clone())
1158 .then_ignore(just(Token::Colon))
1159 .then(expr.clone())
1160 .map_with_span({
1161 let src = src.clone();
1162 move |(name, value), span: Range<usize>| FieldInit {
1163 name,
1164 value,
1165 span: make_span(&src, span),
1166 }
1167 });
1168
1169 let record_turbofish = just(Token::ColonColon)
1171 .ignore_then(
1172 type_parser(src.clone())
1173 .separated_by(just(Token::Comma))
1174 .allow_trailing()
1175 .delimited_by(just(Token::Lt), just(Token::Gt)),
1176 )
1177 .or_not()
1178 .map(|args| args.unwrap_or_default());
1179
1180 let record_construct = ident_token_parser(src.clone())
1181 .then(record_turbofish)
1182 .then_ignore(just(Token::LBrace))
1183 .then(
1184 record_field_init
1185 .separated_by(just(Token::Comma))
1186 .allow_trailing(),
1187 )
1188 .then_ignore(just(Token::RBrace))
1189 .map_with_span({
1190 let src = src.clone();
1191 move |((name, type_args), fields), span: Range<usize>| Expr::RecordConstruct {
1192 name,
1193 type_args,
1194 fields,
1195 span: make_span(&src, span),
1196 }
1197 });
1198
1199 let closure_param = ident_token_parser(src.clone())
1201 .then(
1202 just(Token::Colon)
1203 .ignore_then(type_parser(src.clone()))
1204 .or_not(),
1205 )
1206 .map_with_span({
1207 let src = src.clone();
1208 move |(name, ty), span: Range<usize>| ClosureParam {
1209 name,
1210 ty,
1211 span: make_span(&src, span),
1212 }
1213 });
1214
1215 let closure_empty = just(Token::Or).ignore_then(expr.clone()).map_with_span({
1218 let src = src.clone();
1219 move |body, span: Range<usize>| Expr::Closure {
1220 params: vec![],
1221 body: Box::new(body),
1222 span: make_span(&src, span),
1223 }
1224 });
1225
1226 let closure_with_params = just(Token::Pipe)
1227 .ignore_then(
1228 closure_param
1229 .separated_by(just(Token::Comma))
1230 .allow_trailing(),
1231 )
1232 .then_ignore(just(Token::Pipe))
1233 .then(expr.clone())
1234 .map_with_span({
1235 let src = src.clone();
1236 move |(params, body), span: Range<usize>| Expr::Closure {
1237 params,
1238 body: Box::new(body),
1239 span: make_span(&src, span),
1240 }
1241 });
1242
1243 let closure = closure_with_params.or(closure_empty);
1244
1245 let map_entry = expr
1248 .clone()
1249 .then_ignore(just(Token::Colon))
1250 .then(expr.clone())
1251 .map_with_span({
1252 let src = src.clone();
1253 move |(key, value), span: Range<usize>| MapEntry {
1254 key,
1255 value,
1256 span: make_span(&src, span),
1257 }
1258 });
1259
1260 let map_literal = map_entry
1261 .separated_by(just(Token::Comma))
1262 .allow_trailing()
1263 .delimited_by(just(Token::LBrace), just(Token::RBrace))
1264 .map_with_span({
1265 let src = src.clone();
1266 move |entries, span: Range<usize>| Expr::Map {
1267 entries,
1268 span: make_span(&src, span),
1269 }
1270 });
1271
1272 let variant_turbofish = just(Token::ColonColon)
1275 .ignore_then(
1276 type_parser(src.clone())
1277 .separated_by(just(Token::Comma))
1278 .allow_trailing()
1279 .delimited_by(just(Token::Lt), just(Token::Gt)),
1280 )
1281 .or_not()
1282 .map(|args| args.unwrap_or_default());
1283
1284 let variant_construct = ident_token_parser(src.clone())
1285 .then(variant_turbofish)
1286 .then_ignore(just(Token::ColonColon))
1287 .then(ident_token_parser(src.clone()))
1288 .then(
1289 expr.clone()
1290 .delimited_by(just(Token::LParen), just(Token::RParen))
1291 .or_not(),
1292 )
1293 .map_with_span({
1294 let src = src.clone();
1295 move |(((enum_name, type_args), variant), payload), span: Range<usize>| {
1296 Expr::VariantConstruct {
1297 enum_name,
1298 type_args,
1299 variant,
1300 payload: payload.map(Box::new),
1301 span: make_span(&src, span),
1302 }
1303 }
1304 });
1305
1306 let atom = closure
1314 .or(divine_expr)
1315 .or(summon_expr)
1316 .or(await_expr)
1317 .or(send_expr)
1318 .or(yield_expr)
1319 .or(receive_expr)
1320 .or(trace_expr)
1321 .or(match_expr)
1322 .or(self_access)
1323 .or(record_construct)
1324 .or(variant_construct)
1325 .or(call_expr)
1326 .or(map_literal)
1327 .or(list)
1328 .or(paren_or_tuple)
1329 .or(literal)
1330 .or(var)
1331 .boxed();
1332
1333 enum PostfixOp {
1336 Field(Ident),
1337 TupleIndex(usize, Range<usize>),
1338 MethodCall(Ident, Vec<Expr>, Range<usize>), }
1340
1341 let method_call = ident_token_parser(src.clone())
1343 .then(
1344 expr.clone()
1345 .separated_by(just(Token::Comma))
1346 .allow_trailing()
1347 .delimited_by(just(Token::LParen), just(Token::RParen)),
1348 )
1349 .map_with_span(|(name, args), span: Range<usize>| {
1350 PostfixOp::MethodCall(name, args, span)
1351 });
1352
1353 let postfix_op = just(Token::Dot).ignore_then(
1354 filter_map({
1356 let src = src.clone();
1357 move |span: Range<usize>, token| match token {
1358 Token::IntLit => {
1359 let text = &src[span.start..span.end];
1360 text.parse::<usize>()
1361 .map(|idx| PostfixOp::TupleIndex(idx, span.clone()))
1362 .map_err(|_| Simple::custom(span, "invalid tuple index"))
1363 }
1364 _ => Err(Simple::expected_input_found(
1365 span,
1366 vec![Some(Token::IntLit)],
1367 Some(token),
1368 )),
1369 }
1370 })
1371 .or(method_call)
1373 .or(ident_token_parser(src.clone()).map(PostfixOp::Field)),
1374 );
1375
1376 let postfix = atom
1377 .then(postfix_op.repeated())
1378 .foldl({
1379 let src = src.clone();
1380 move |object, op| match op {
1381 PostfixOp::Field(field) => {
1382 let span = make_span(&src, object.span().start..field.span.end);
1383 Expr::FieldAccess {
1384 object: Box::new(object),
1385 field,
1386 span,
1387 }
1388 }
1389 PostfixOp::TupleIndex(index, idx_span) => {
1390 let span = make_span(&src, object.span().start..idx_span.end);
1391 Expr::TupleIndex {
1392 tuple: Box::new(object),
1393 index,
1394 span,
1395 }
1396 }
1397 PostfixOp::MethodCall(method, args, call_span) => {
1398 if let Expr::Var { name: tool, .. } = &object {
1401 let span = make_span(&src, object.span().start..call_span.end);
1402 Expr::ToolCall {
1403 tool: tool.clone(),
1404 function: method,
1405 args,
1406 span,
1407 }
1408 } else {
1409 let span = make_span(&src, object.span().start..call_span.end);
1412 Expr::FieldAccess {
1413 object: Box::new(object),
1414 field: method,
1415 span,
1416 }
1417 }
1418 }
1419 }
1420 })
1421 .boxed();
1422
1423 let unary = just(Token::Minus)
1425 .to(UnaryOp::Neg)
1426 .or(just(Token::Bang).to(UnaryOp::Not))
1427 .repeated()
1428 .then(postfix.clone())
1429 .foldr(|op, operand| {
1430 let span = operand.span().clone();
1431 Expr::Unary {
1432 op,
1433 operand: Box::new(operand),
1434 span,
1435 }
1436 })
1437 .boxed();
1438
1439 let try_expr = just(Token::KwTry)
1442 .ignore_then(postfix.clone())
1443 .map_with_span({
1444 let src = src.clone();
1445 move |inner, span: Range<usize>| Expr::Try {
1446 expr: Box::new(inner),
1447 span: make_span(&src, span),
1448 }
1449 })
1450 .boxed();
1451
1452 let fail_expr = just(Token::KwFail)
1455 .ignore_then(postfix.clone())
1456 .map_with_span({
1457 let src = src.clone();
1458 move |error, span: Range<usize>| Expr::Fail {
1459 error: Box::new(error),
1460 span: make_span(&src, span),
1461 }
1462 })
1463 .boxed();
1464
1465 let retry_delay = just(Token::Comma)
1470 .ignore_then(just(Token::KwDelay))
1471 .ignore_then(just(Token::Colon))
1472 .ignore_then(postfix.clone());
1473
1474 let retry_on = just(Token::Comma)
1475 .ignore_then(just(Token::KwOn))
1476 .ignore_then(just(Token::Colon))
1477 .ignore_then(
1478 postfix
1479 .clone()
1480 .separated_by(just(Token::Comma))
1481 .allow_trailing()
1482 .delimited_by(just(Token::LBracket), just(Token::RBracket)),
1483 );
1484
1485 let retry_expr = just(Token::KwRetry)
1486 .ignore_then(just(Token::LParen))
1487 .ignore_then(postfix.clone())
1488 .then(retry_delay.or_not())
1489 .then(retry_on.or_not())
1490 .then_ignore(just(Token::RParen))
1491 .then(
1492 expr.clone()
1493 .delimited_by(just(Token::LBrace), just(Token::RBrace)),
1494 )
1495 .map_with_span({
1496 let src = src.clone();
1497 move |(((count, delay), on_errors), body), span: Range<usize>| Expr::Retry {
1498 count: Box::new(count),
1499 delay: delay.map(Box::new),
1500 on_errors,
1501 body: Box::new(body),
1502 span: make_span(&src, span),
1503 }
1504 })
1505 .boxed();
1506
1507 let unary = retry_expr.or(fail_expr).or(try_expr).or(unary).boxed();
1509
1510 let mul_div_op = just(Token::Star)
1513 .to(BinOp::Mul)
1514 .or(just(Token::Slash).to(BinOp::Div))
1515 .or(just(Token::Percent).to(BinOp::Rem));
1516
1517 let mul_div = unary
1518 .clone()
1519 .then(mul_div_op.then(unary.clone()).repeated())
1520 .foldl({
1521 let src = src.clone();
1522 move |left, (op, right)| {
1523 let span = make_span(&src, left.span().start..right.span().end);
1524 Expr::Binary {
1525 op,
1526 left: Box::new(left),
1527 right: Box::new(right),
1528 span,
1529 }
1530 }
1531 })
1532 .boxed();
1533
1534 let add_sub_op = just(Token::Plus)
1536 .to(BinOp::Add)
1537 .or(just(Token::Minus).to(BinOp::Sub));
1538
1539 let add_sub = mul_div
1540 .clone()
1541 .then(add_sub_op.then(mul_div).repeated())
1542 .foldl({
1543 let src = src.clone();
1544 move |left, (op, right)| {
1545 let span = make_span(&src, left.span().start..right.span().end);
1546 Expr::Binary {
1547 op,
1548 left: Box::new(left),
1549 right: Box::new(right),
1550 span,
1551 }
1552 }
1553 })
1554 .boxed();
1555
1556 let concat_op = just(Token::PlusPlus).to(BinOp::Concat);
1558
1559 let concat = add_sub
1560 .clone()
1561 .then(concat_op.then(add_sub).repeated())
1562 .foldl({
1563 let src = src.clone();
1564 move |left, (op, right)| {
1565 let span = make_span(&src, left.span().start..right.span().end);
1566 Expr::Binary {
1567 op,
1568 left: Box::new(left),
1569 right: Box::new(right),
1570 span,
1571 }
1572 }
1573 })
1574 .boxed();
1575
1576 let cmp_op = choice((
1578 just(Token::Le).to(BinOp::Le),
1579 just(Token::Ge).to(BinOp::Ge),
1580 just(Token::Lt).to(BinOp::Lt),
1581 just(Token::Gt).to(BinOp::Gt),
1582 ));
1583
1584 let comparison = concat
1585 .clone()
1586 .then(cmp_op.then(concat).repeated())
1587 .foldl({
1588 let src = src.clone();
1589 move |left, (op, right)| {
1590 let span = make_span(&src, left.span().start..right.span().end);
1591 Expr::Binary {
1592 op,
1593 left: Box::new(left),
1594 right: Box::new(right),
1595 span,
1596 }
1597 }
1598 })
1599 .boxed();
1600
1601 let eq_op = just(Token::EqEq)
1603 .to(BinOp::Eq)
1604 .or(just(Token::Ne).to(BinOp::Ne));
1605
1606 let equality = comparison
1607 .clone()
1608 .then(eq_op.then(comparison).repeated())
1609 .foldl({
1610 let src = src.clone();
1611 move |left, (op, right)| {
1612 let span = make_span(&src, left.span().start..right.span().end);
1613 Expr::Binary {
1614 op,
1615 left: Box::new(left),
1616 right: Box::new(right),
1617 span,
1618 }
1619 }
1620 })
1621 .boxed();
1622
1623 let and_op = just(Token::And).to(BinOp::And);
1625
1626 let and = equality
1627 .clone()
1628 .then(and_op.then(equality).repeated())
1629 .foldl({
1630 let src = src.clone();
1631 move |left, (op, right)| {
1632 let span = make_span(&src, left.span().start..right.span().end);
1633 Expr::Binary {
1634 op,
1635 left: Box::new(left),
1636 right: Box::new(right),
1637 span,
1638 }
1639 }
1640 })
1641 .boxed();
1642
1643 let or_op = just(Token::Or).to(BinOp::Or);
1645
1646 let or_expr = and.clone().then(or_op.then(and).repeated()).foldl({
1647 let src = src.clone();
1648 move |left, (op, right)| {
1649 let span = make_span(&src, left.span().start..right.span().end);
1650 Expr::Binary {
1651 op,
1652 left: Box::new(left),
1653 right: Box::new(right),
1654 span,
1655 }
1656 }
1657 });
1658
1659 let catch_recovery = just(Token::KwCatch)
1662 .ignore_then(
1663 ident_token_parser(src.clone())
1664 .delimited_by(just(Token::LParen), just(Token::RParen))
1665 .or_not(),
1666 )
1667 .then(
1668 expr.clone()
1669 .delimited_by(just(Token::LBrace), just(Token::RBrace)),
1670 );
1671
1672 or_expr.then(catch_recovery.or_not()).map_with_span({
1673 let src = src.clone();
1674 move |(inner, catch_opt), span: Range<usize>| match catch_opt {
1675 Some((error_bind, recovery)) => Expr::Catch {
1676 expr: Box::new(inner),
1677 error_bind,
1678 recovery: Box::new(recovery),
1679 span: make_span(&src, span),
1680 },
1681 None => inner,
1682 }
1683 })
1684 })
1685 .boxed()
1686}
1687
1688fn make_span(source: &Arc<str>, range: Range<usize>) -> Span {
1694 Span::new(range.start, range.end, Arc::clone(source))
1695}
1696
1697fn ident_token_parser(source: Arc<str>) -> impl Parser<Token, Ident, Error = ParseError> + Clone {
1699 filter_map(move |span: Range<usize>, token| match token {
1700 Token::Ident => {
1701 let text = &source[span.start..span.end];
1702 Ok(Ident::new(text.to_string(), make_span(&source, span)))
1703 }
1704 _ => Err(Simple::expected_input_found(
1705 span,
1706 vec![Some(Token::Ident)],
1707 Some(token),
1708 )),
1709 })
1710}
1711
1712fn var_parser(source: Arc<str>) -> impl Parser<Token, Expr, Error = ParseError> + Clone {
1714 ident_token_parser(source.clone()).map_with_span(move |name, span: Range<usize>| Expr::Var {
1715 name,
1716 span: make_span(&source, span),
1717 })
1718}
1719
1720fn type_parser(source: Arc<str>) -> impl Parser<Token, TypeExpr, Error = ParseError> + Clone {
1722 recursive(move |ty| {
1723 let src = source.clone();
1724
1725 let primitive = choice((
1726 just(Token::TyInt).to(TypeExpr::Int),
1727 just(Token::TyFloat).to(TypeExpr::Float),
1728 just(Token::TyBool).to(TypeExpr::Bool),
1729 just(Token::TyString).to(TypeExpr::String),
1730 just(Token::TyUnit).to(TypeExpr::Unit),
1731 ));
1732
1733 let list_ty = just(Token::TyList)
1734 .ignore_then(just(Token::Lt))
1735 .ignore_then(ty.clone())
1736 .then_ignore(just(Token::Gt))
1737 .map(|inner| TypeExpr::List(Box::new(inner)));
1738
1739 let option_ty = just(Token::TyOption)
1740 .ignore_then(just(Token::Lt))
1741 .ignore_then(ty.clone())
1742 .then_ignore(just(Token::Gt))
1743 .map(|inner| TypeExpr::Option(Box::new(inner)));
1744
1745 let oracle_ty = just(Token::TyOracle)
1746 .ignore_then(just(Token::Lt))
1747 .ignore_then(ty.clone())
1748 .then_ignore(just(Token::Gt))
1749 .map(|inner| TypeExpr::Oracle(Box::new(inner)));
1750
1751 let agent_ty = just(Token::TyAgent)
1752 .ignore_then(just(Token::Lt))
1753 .ignore_then(ident_token_parser(src.clone()))
1754 .then_ignore(just(Token::Gt))
1755 .map(TypeExpr::Agent);
1756
1757 let named_ty = ident_token_parser(src.clone())
1759 .then(
1760 ty.clone()
1761 .separated_by(just(Token::Comma))
1762 .allow_trailing()
1763 .delimited_by(just(Token::Lt), just(Token::Gt))
1764 .or_not(),
1765 )
1766 .map(|(name, type_args)| TypeExpr::Named(name, type_args.unwrap_or_default()));
1767
1768 let fn_ty = just(Token::TyFn)
1770 .ignore_then(
1771 ty.clone()
1772 .separated_by(just(Token::Comma))
1773 .allow_trailing()
1774 .delimited_by(just(Token::LParen), just(Token::RParen)),
1775 )
1776 .then_ignore(just(Token::Arrow))
1777 .then(ty.clone())
1778 .map(|(params, ret)| TypeExpr::Fn(params, Box::new(ret)));
1779
1780 let map_ty = just(Token::TyMap)
1782 .ignore_then(just(Token::Lt))
1783 .ignore_then(ty.clone())
1784 .then_ignore(just(Token::Comma))
1785 .then(ty.clone())
1786 .then_ignore(just(Token::Gt))
1787 .map(|(k, v)| TypeExpr::Map(Box::new(k), Box::new(v)));
1788
1789 let result_ty = just(Token::TyResult)
1791 .ignore_then(just(Token::Lt))
1792 .ignore_then(ty.clone())
1793 .then_ignore(just(Token::Comma))
1794 .then(ty.clone())
1795 .then_ignore(just(Token::Gt))
1796 .map(|(ok, err)| TypeExpr::Result(Box::new(ok), Box::new(err)));
1797
1798 let tuple_ty = ty
1800 .clone()
1801 .separated_by(just(Token::Comma))
1802 .at_least(2)
1803 .allow_trailing()
1804 .delimited_by(just(Token::LParen), just(Token::RParen))
1805 .map(TypeExpr::Tuple);
1806
1807 primitive
1808 .or(list_ty)
1809 .or(option_ty)
1810 .or(oracle_ty)
1811 .or(agent_ty)
1812 .or(fn_ty)
1813 .or(map_ty)
1814 .or(result_ty)
1815 .or(tuple_ty)
1816 .or(named_ty)
1817 })
1818}
1819
1820fn for_pattern_parser(source: Arc<str>) -> impl Parser<Token, Pattern, Error = ParseError> + Clone {
1823 recursive(move |pattern| {
1824 let src = source.clone();
1825 let src2 = source.clone();
1826
1827 let binding = ident_token_parser(src.clone()).map_with_span({
1829 let src = src.clone();
1830 move |name, span: Range<usize>| Pattern::Binding {
1831 name,
1832 span: make_span(&src, span),
1833 }
1834 });
1835
1836 let tuple_pattern = pattern
1838 .clone()
1839 .separated_by(just(Token::Comma))
1840 .at_least(2)
1841 .allow_trailing()
1842 .delimited_by(just(Token::LParen), just(Token::RParen))
1843 .map_with_span({
1844 let src = src2.clone();
1845 move |elements, span: Range<usize>| Pattern::Tuple {
1846 elements,
1847 span: make_span(&src, span),
1848 }
1849 });
1850
1851 tuple_pattern.or(binding)
1852 })
1853}
1854
1855fn pattern_parser(source: Arc<str>) -> impl Parser<Token, Pattern, Error = ParseError> + Clone {
1857 recursive(move |pattern| {
1858 let src = source.clone();
1859 let src2 = source.clone();
1860 let src3 = source.clone();
1861 let src4 = source.clone();
1862 let src5 = source.clone();
1863
1864 let wildcard = filter_map({
1866 let src = src.clone();
1867 move |span: Range<usize>, token| match &token {
1868 Token::Ident if src[span.start..span.end].eq("_") => Ok(()),
1869 _ => Err(Simple::expected_input_found(span, vec![], Some(token))),
1870 }
1871 })
1872 .map_with_span(move |_, span: Range<usize>| Pattern::Wildcard {
1873 span: make_span(&src2, span),
1874 });
1875
1876 let lit_int = filter_map({
1878 let src = src3.clone();
1879 move |span: Range<usize>, token| match token {
1880 Token::IntLit => {
1881 let text = &src[span.start..span.end];
1882 text.parse::<i64>()
1883 .map(Literal::Int)
1884 .map_err(|_| Simple::custom(span, "invalid integer literal"))
1885 }
1886 _ => Err(Simple::expected_input_found(
1887 span,
1888 vec![Some(Token::IntLit)],
1889 Some(token),
1890 )),
1891 }
1892 })
1893 .map_with_span({
1894 let src = src3.clone();
1895 move |value, span: Range<usize>| Pattern::Literal {
1896 value,
1897 span: make_span(&src, span),
1898 }
1899 });
1900
1901 let lit_bool = just(Token::KwTrue)
1902 .to(Literal::Bool(true))
1903 .or(just(Token::KwFalse).to(Literal::Bool(false)))
1904 .map_with_span({
1905 let src = src3.clone();
1906 move |value, span: Range<usize>| Pattern::Literal {
1907 value,
1908 span: make_span(&src, span),
1909 }
1910 });
1911
1912 let tuple_pattern = pattern
1914 .clone()
1915 .separated_by(just(Token::Comma))
1916 .at_least(2)
1917 .allow_trailing()
1918 .delimited_by(just(Token::LParen), just(Token::RParen))
1919 .map_with_span({
1920 let src = src5.clone();
1921 move |elements, span: Range<usize>| Pattern::Tuple {
1922 elements,
1923 span: make_span(&src, span),
1924 }
1925 });
1926
1927 let qualified_variant_with_payload = ident_token_parser(src4.clone())
1930 .then_ignore(just(Token::ColonColon))
1931 .then(ident_token_parser(src4.clone()))
1932 .then(
1933 pattern
1934 .clone()
1935 .delimited_by(just(Token::LParen), just(Token::RParen))
1936 .or_not(),
1937 )
1938 .map_with_span({
1939 let src = src4.clone();
1940 move |((enum_name, variant), payload), span: Range<usize>| Pattern::Variant {
1941 enum_name: Some(enum_name),
1942 variant,
1943 payload: payload.map(Box::new),
1944 span: make_span(&src, span),
1945 }
1946 });
1947
1948 let unqualified_with_payload = ident_token_parser(src4.clone())
1950 .then(
1951 pattern
1952 .clone()
1953 .delimited_by(just(Token::LParen), just(Token::RParen))
1954 .or_not(),
1955 )
1956 .map_with_span({
1957 let src = src4.clone();
1958 move |(name, payload), span: Range<usize>| {
1959 if name.name.chars().next().is_some_and(|c| c.is_uppercase())
1962 || payload.is_some()
1963 {
1964 Pattern::Variant {
1965 enum_name: None,
1966 variant: name,
1967 payload: payload.map(Box::new),
1968 span: make_span(&src, span),
1969 }
1970 } else {
1971 Pattern::Binding {
1972 name,
1973 span: make_span(&src, span),
1974 }
1975 }
1976 }
1977 });
1978
1979 wildcard
1981 .or(tuple_pattern)
1982 .or(qualified_variant_with_payload)
1983 .or(lit_int)
1984 .or(lit_bool)
1985 .or(unqualified_with_payload)
1986 })
1987}
1988
1989fn literal_parser(source: Arc<str>) -> impl Parser<Token, Expr, Error = ParseError> + Clone {
1991 let src = source.clone();
1992 let src2 = source.clone();
1993 let src3 = source.clone();
1994 let src4 = source.clone();
1995 let src5 = source.clone();
1996
1997 let int_lit = filter_map(move |span: Range<usize>, token| match token {
1998 Token::IntLit => {
1999 let text = &src[span.start..span.end];
2000 text.parse::<i64>()
2001 .map(Literal::Int)
2002 .map_err(|_| Simple::custom(span, "invalid integer literal"))
2003 }
2004 _ => Err(Simple::expected_input_found(
2005 span,
2006 vec![Some(Token::IntLit)],
2007 Some(token),
2008 )),
2009 })
2010 .map_with_span(move |value, span: Range<usize>| Expr::Literal {
2011 value,
2012 span: make_span(&src2, span),
2013 });
2014
2015 let float_lit = filter_map(move |span: Range<usize>, token| match token {
2016 Token::FloatLit => {
2017 let text = &src3[span.start..span.end];
2018 text.parse::<f64>()
2019 .map(Literal::Float)
2020 .map_err(|_| Simple::custom(span, "invalid float literal"))
2021 }
2022 _ => Err(Simple::expected_input_found(
2023 span,
2024 vec![Some(Token::FloatLit)],
2025 Some(token),
2026 )),
2027 })
2028 .map_with_span(move |value, span: Range<usize>| Expr::Literal {
2029 value,
2030 span: make_span(&src4, span),
2031 });
2032
2033 let src6 = source.clone();
2034 let string_lit = filter_map(move |span: Range<usize>, token| match token {
2035 Token::StringLit => {
2036 let text = &src5[span.start..span.end];
2037 let inner = &text[1..text.len() - 1];
2038 let parts = parse_string_template(inner, &make_span(&src5, span.clone()));
2039 Ok(parts)
2040 }
2041 _ => Err(Simple::expected_input_found(
2042 span,
2043 vec![Some(Token::StringLit)],
2044 Some(token),
2045 )),
2046 })
2047 .map_with_span(move |parts, span: Range<usize>| {
2048 let span = make_span(&src6, span);
2049 if parts.len() == 1 {
2051 if let StringPart::Literal(s) = &parts[0] {
2052 return Expr::Literal {
2053 value: Literal::String(s.clone()),
2054 span,
2055 };
2056 }
2057 }
2058 Expr::StringInterp {
2060 template: StringTemplate {
2061 parts,
2062 span: span.clone(),
2063 },
2064 span,
2065 }
2066 });
2067
2068 let bool_lit = just(Token::KwTrue)
2069 .to(Literal::Bool(true))
2070 .or(just(Token::KwFalse).to(Literal::Bool(false)))
2071 .map_with_span(move |value, _span: Range<usize>| Expr::Literal {
2072 value,
2073 span: Span::dummy(), });
2075
2076 int_lit.or(float_lit).or(string_lit).or(bool_lit)
2077}
2078
2079fn string_template_parser(
2081 source: Arc<str>,
2082) -> impl Parser<Token, StringTemplate, Error = ParseError> + Clone {
2083 filter_map(move |span: Range<usize>, token| match token {
2084 Token::StringLit => {
2085 let text = &source[span.start..span.end];
2086 let inner = &text[1..text.len() - 1];
2087 let parts = parse_string_template(inner, &make_span(&source, span.clone()));
2088 Ok(StringTemplate {
2089 parts,
2090 span: make_span(&source, span),
2091 })
2092 }
2093 _ => Err(Simple::expected_input_found(
2094 span,
2095 vec![Some(Token::StringLit)],
2096 Some(token),
2097 )),
2098 })
2099}
2100
2101fn parse_string_template(s: &str, span: &Span) -> Vec<StringPart> {
2104 let mut parts = Vec::new();
2105 let mut current = String::new();
2106 let mut chars = s.chars().peekable();
2107
2108 while let Some(ch) = chars.next() {
2109 if ch == '{' {
2110 if !current.is_empty() {
2111 parts.push(StringPart::Literal(std::mem::take(&mut current)));
2112 }
2113
2114 let mut expr_str = String::new();
2116 let mut brace_depth = 1;
2117 let mut string_quote: Option<char> = None; let mut escape_next = false;
2119
2120 while let Some(&c) = chars.peek() {
2121 if escape_next {
2122 expr_str.push(c);
2123 chars.next();
2124 escape_next = false;
2125 continue;
2126 }
2127
2128 if c == '\\' && string_quote.is_some() {
2129 escape_next = true;
2130 expr_str.push(c);
2131 chars.next();
2132 continue;
2133 }
2134
2135 if c == '"' || c == '\'' {
2137 match string_quote {
2138 None => string_quote = Some(c), Some(q) if q == c => string_quote = None, Some(_) => {} }
2142 }
2143
2144 if string_quote.is_none() {
2145 if c == '{' {
2146 brace_depth += 1;
2147 } else if c == '}' {
2148 brace_depth -= 1;
2149 if brace_depth == 0 {
2150 chars.next();
2151 break;
2152 }
2153 }
2154 }
2155
2156 expr_str.push(c);
2157 chars.next();
2158 }
2159
2160 if !expr_str.is_empty() {
2161 let expr = parse_interp_expr(&expr_str, span);
2162 parts.push(StringPart::Interpolation(Box::new(expr)));
2163 }
2164 } else if ch == '\\' {
2165 if let Some(escaped) = chars.next() {
2166 current.push(match escaped {
2167 'n' => '\n',
2168 't' => '\t',
2169 'r' => '\r',
2170 '\\' => '\\',
2171 '"' => '"',
2172 '{' => '{',
2173 '}' => '}',
2174 other => other,
2175 });
2176 }
2177 } else {
2178 current.push(ch);
2179 }
2180 }
2181
2182 if !current.is_empty() {
2183 parts.push(StringPart::Literal(current));
2184 }
2185
2186 if parts.is_empty() {
2187 parts.push(StringPart::Literal(String::new()));
2188 }
2189
2190 parts
2191}
2192
2193fn parse_interp_expr(s: &str, span: &Span) -> Expr {
2196 let trimmed = s.trim();
2197 if trimmed.is_empty() {
2198 return Expr::Literal {
2200 value: Literal::String(String::new()),
2201 span: span.clone(),
2202 };
2203 }
2204
2205 let lex_result = crate::lex(trimmed);
2207 let (tokens, source) = match lex_result {
2208 Ok(result) => (result.tokens().to_vec(), trimmed.to_string()),
2209 Err(_) => {
2210 return Expr::Var {
2212 name: Ident::new(trimmed.to_string(), span.clone()),
2213 span: span.clone(),
2214 };
2215 }
2216 };
2217
2218 if tokens.is_empty() {
2219 return Expr::Var {
2220 name: Ident::new(trimmed.to_string(), span.clone()),
2221 span: span.clone(),
2222 };
2223 }
2224
2225 let mut parser = InterpExprParser::new(&tokens, &source, span.clone());
2227 parser.parse_expr()
2228}
2229
2230struct InterpExprParser<'a> {
2233 tokens: &'a [crate::Spanned],
2234 source: &'a str,
2235 pos: usize,
2236 span: Span,
2237}
2238
2239impl<'a> InterpExprParser<'a> {
2240 fn new(tokens: &'a [crate::Spanned], source: &'a str, span: Span) -> Self {
2241 Self {
2242 tokens,
2243 source,
2244 pos: 0,
2245 span,
2246 }
2247 }
2248
2249 fn current(&self) -> Option<&Token> {
2250 self.tokens.get(self.pos).map(|s| &s.token)
2251 }
2252
2253 fn current_text(&self) -> Option<&str> {
2254 self.tokens
2255 .get(self.pos)
2256 .map(|s| &self.source[s.start..s.end])
2257 }
2258
2259 fn advance(&mut self) {
2260 if self.pos < self.tokens.len() {
2261 self.pos += 1;
2262 }
2263 }
2264
2265 fn parse_expr(&mut self) -> Expr {
2266 self.parse_or()
2267 }
2268
2269 fn parse_or(&mut self) -> Expr {
2270 let mut left = self.parse_and();
2271 while matches!(self.current(), Some(Token::Or)) {
2272 self.advance();
2273 let right = self.parse_and();
2274 left = Expr::Binary {
2275 left: Box::new(left),
2276 op: BinOp::Or,
2277 right: Box::new(right),
2278 span: self.span.clone(),
2279 };
2280 }
2281 left
2282 }
2283
2284 fn parse_and(&mut self) -> Expr {
2285 let mut left = self.parse_comparison();
2286 while matches!(self.current(), Some(Token::And)) {
2287 self.advance();
2288 let right = self.parse_comparison();
2289 left = Expr::Binary {
2290 left: Box::new(left),
2291 op: BinOp::And,
2292 right: Box::new(right),
2293 span: self.span.clone(),
2294 };
2295 }
2296 left
2297 }
2298
2299 fn parse_comparison(&mut self) -> Expr {
2300 let mut left = self.parse_additive();
2301 loop {
2302 let op = match self.current() {
2303 Some(Token::EqEq) => BinOp::Eq,
2304 Some(Token::Ne) => BinOp::Ne,
2305 Some(Token::Lt) => BinOp::Lt,
2306 Some(Token::Le) => BinOp::Le,
2307 Some(Token::Gt) => BinOp::Gt,
2308 Some(Token::Ge) => BinOp::Ge,
2309 _ => break,
2310 };
2311 self.advance();
2312 let right = self.parse_additive();
2313 left = Expr::Binary {
2314 left: Box::new(left),
2315 op,
2316 right: Box::new(right),
2317 span: self.span.clone(),
2318 };
2319 }
2320 left
2321 }
2322
2323 fn parse_additive(&mut self) -> Expr {
2324 let mut left = self.parse_multiplicative();
2325 loop {
2326 let op = match self.current() {
2327 Some(Token::Plus) => BinOp::Add,
2328 Some(Token::Minus) => BinOp::Sub,
2329 Some(Token::PlusPlus) => BinOp::Concat,
2330 _ => break,
2331 };
2332 self.advance();
2333 let right = self.parse_multiplicative();
2334 left = Expr::Binary {
2335 left: Box::new(left),
2336 op,
2337 right: Box::new(right),
2338 span: self.span.clone(),
2339 };
2340 }
2341 left
2342 }
2343
2344 fn parse_multiplicative(&mut self) -> Expr {
2345 let mut left = self.parse_unary();
2346 loop {
2347 let op = match self.current() {
2348 Some(Token::Star) => BinOp::Mul,
2349 Some(Token::Slash) => BinOp::Div,
2350 Some(Token::Percent) => BinOp::Rem,
2351 _ => break,
2352 };
2353 self.advance();
2354 let right = self.parse_unary();
2355 left = Expr::Binary {
2356 left: Box::new(left),
2357 op,
2358 right: Box::new(right),
2359 span: self.span.clone(),
2360 };
2361 }
2362 left
2363 }
2364
2365 fn parse_unary(&mut self) -> Expr {
2366 match self.current() {
2367 Some(Token::Minus) => {
2368 self.advance();
2369 let operand = self.parse_unary();
2370 Expr::Unary {
2371 op: UnaryOp::Neg,
2372 operand: Box::new(operand),
2373 span: self.span.clone(),
2374 }
2375 }
2376 Some(Token::Bang) => {
2377 self.advance();
2378 let operand = self.parse_unary();
2379 Expr::Unary {
2380 op: UnaryOp::Not,
2381 operand: Box::new(operand),
2382 span: self.span.clone(),
2383 }
2384 }
2385 _ => self.parse_postfix(),
2386 }
2387 }
2388
2389 fn parse_postfix(&mut self) -> Expr {
2390 let mut expr = self.parse_primary();
2391
2392 loop {
2393 match self.current() {
2394 Some(Token::Dot) => {
2395 self.advance();
2396 match self.current() {
2397 Some(Token::IntLit) => {
2398 let text = self.current_text().unwrap_or("0");
2399 let index = text.parse::<usize>().unwrap_or(0);
2400 self.advance();
2401 expr = Expr::TupleIndex {
2402 tuple: Box::new(expr),
2403 index,
2404 span: self.span.clone(),
2405 };
2406 }
2407 Some(Token::Ident) => {
2408 let name = self.current_text().unwrap_or("").to_string();
2409 let field = Ident::new(name, self.span.clone());
2410 self.advance();
2411 expr = Expr::FieldAccess {
2412 object: Box::new(expr),
2413 field,
2414 span: self.span.clone(),
2415 };
2416 }
2417 _ => break,
2418 }
2419 }
2420 Some(Token::LParen) if matches!(expr, Expr::Var { .. }) => {
2421 if let Expr::Var { name, .. } = expr {
2423 self.advance();
2424 let args = self.parse_args();
2425 expr = Expr::Call {
2426 name,
2427 type_args: vec![], args,
2429 span: self.span.clone(),
2430 };
2431 }
2432 }
2433 _ => break,
2434 }
2435 }
2436
2437 expr
2438 }
2439
2440 fn parse_primary(&mut self) -> Expr {
2441 match self.current() {
2442 Some(Token::IntLit) => {
2443 let text = self.current_text().unwrap_or("0");
2444 let n = text.parse::<i64>().unwrap_or(0);
2445 self.advance();
2446 Expr::Literal {
2447 value: Literal::Int(n),
2448 span: self.span.clone(),
2449 }
2450 }
2451 Some(Token::FloatLit) => {
2452 let text = self.current_text().unwrap_or("0.0");
2453 let f = text.parse::<f64>().unwrap_or(0.0);
2454 self.advance();
2455 Expr::Literal {
2456 value: Literal::Float(f),
2457 span: self.span.clone(),
2458 }
2459 }
2460 Some(Token::StringLit) => {
2461 let text = self.current_text().unwrap_or("\"\"");
2462 let s = if text.len() >= 2 {
2464 text[1..text.len() - 1].to_string()
2465 } else {
2466 String::new()
2467 };
2468 self.advance();
2469 Expr::Literal {
2470 value: Literal::String(s),
2471 span: self.span.clone(),
2472 }
2473 }
2474 Some(Token::KwTrue) => {
2475 self.advance();
2476 Expr::Literal {
2477 value: Literal::Bool(true),
2478 span: self.span.clone(),
2479 }
2480 }
2481 Some(Token::KwFalse) => {
2482 self.advance();
2483 Expr::Literal {
2484 value: Literal::Bool(false),
2485 span: self.span.clone(),
2486 }
2487 }
2488 Some(Token::Ident) => {
2489 let name = self.current_text().unwrap_or("").to_string();
2490 self.advance();
2491 Expr::Var {
2492 name: Ident::new(name, self.span.clone()),
2493 span: self.span.clone(),
2494 }
2495 }
2496 Some(Token::KwSelf) => {
2497 self.advance();
2498 if matches!(self.current(), Some(Token::Dot)) {
2500 self.advance();
2501 if let Some(Token::Ident) = self.current() {
2502 let field_name = self.current_text().unwrap_or("").to_string();
2503 let field = Ident::new(field_name, self.span.clone());
2504 self.advance();
2505 return Expr::SelfField {
2506 field,
2507 span: self.span.clone(),
2508 };
2509 }
2510 }
2511 Expr::Var {
2512 name: Ident::new("self".to_string(), self.span.clone()),
2513 span: self.span.clone(),
2514 }
2515 }
2516 Some(Token::LParen) => {
2517 self.advance();
2518 let inner = self.parse_expr();
2519 if matches!(self.current(), Some(Token::RParen)) {
2520 self.advance();
2521 }
2522 Expr::Paren {
2523 inner: Box::new(inner),
2524 span: self.span.clone(),
2525 }
2526 }
2527 Some(Token::LBracket) => {
2528 self.advance();
2530 let mut elements = Vec::new();
2531 while !matches!(self.current(), Some(Token::RBracket) | None) {
2532 elements.push(self.parse_expr());
2533 if matches!(self.current(), Some(Token::Comma)) {
2534 self.advance();
2535 } else {
2536 break;
2537 }
2538 }
2539 if matches!(self.current(), Some(Token::RBracket)) {
2540 self.advance();
2541 }
2542 Expr::List {
2543 elements,
2544 span: self.span.clone(),
2545 }
2546 }
2547 _ => {
2548 Expr::Literal {
2550 value: Literal::String(String::new()),
2551 span: self.span.clone(),
2552 }
2553 }
2554 }
2555 }
2556
2557 fn parse_args(&mut self) -> Vec<Expr> {
2558 let mut args = Vec::new();
2559 while !matches!(self.current(), Some(Token::RParen) | None) {
2560 args.push(self.parse_expr());
2561 if matches!(self.current(), Some(Token::Comma)) {
2562 self.advance();
2563 } else {
2564 break;
2565 }
2566 }
2567 if matches!(self.current(), Some(Token::RParen)) {
2568 self.advance();
2569 }
2570 args
2571 }
2572}
2573
2574#[cfg(test)]
2579mod tests {
2580 use super::*;
2581 use crate::lex;
2582
2583 fn parse_str(source: &str) -> (Option<Program>, Vec<ParseError>) {
2584 let lex_result = lex(source).expect("lexing should succeed");
2585 let source_arc: Arc<str> = Arc::from(source);
2586 parse(lex_result.tokens(), source_arc)
2587 }
2588
2589 #[test]
2590 fn parse_minimal_program() {
2591 let source = r#"
2592 agent Main {
2593 on start {
2594 yield(42);
2595 }
2596 }
2597 run Main;
2598 "#;
2599
2600 let (prog, errors) = parse_str(source);
2601 assert!(errors.is_empty(), "errors: {errors:?}");
2602 let prog = prog.expect("should parse");
2603
2604 assert_eq!(prog.agents.len(), 1);
2605 assert_eq!(prog.agents[0].name.name, "Main");
2606 assert_eq!(prog.run_agent.as_ref().unwrap().name, "Main");
2607 }
2608
2609 #[test]
2610 fn parse_agent_with_beliefs() {
2611 let source = r#"
2612 agent Researcher {
2613 topic: String
2614 max_words: Int
2615
2616 on start {
2617 yield(self.topic);
2618 }
2619 }
2620 run Researcher;
2621 "#;
2622
2623 let (prog, errors) = parse_str(source);
2624 assert!(errors.is_empty(), "errors: {errors:?}");
2625 let prog = prog.expect("should parse");
2626
2627 assert_eq!(prog.agents[0].beliefs.len(), 2);
2628 assert_eq!(prog.agents[0].beliefs[0].name.name, "topic");
2629 assert_eq!(prog.agents[0].beliefs[1].name.name, "max_words");
2630 }
2631
2632 #[test]
2633 fn parse_multiple_handlers() {
2634 let source = r#"
2635 agent Worker {
2636 on start {
2637 print("started");
2638 }
2639
2640 on message(msg: String) {
2641 print(msg);
2642 }
2643
2644 on stop {
2645 print("stopped");
2646 }
2647 }
2648 run Worker;
2649 "#;
2650
2651 let (prog, errors) = parse_str(source);
2652 assert!(errors.is_empty(), "errors: {errors:?}");
2653 let prog = prog.expect("should parse");
2654
2655 assert_eq!(prog.agents[0].handlers.len(), 3);
2656 assert_eq!(prog.agents[0].handlers[0].event, EventKind::Start);
2657 assert!(matches!(
2658 prog.agents[0].handlers[1].event,
2659 EventKind::Message { .. }
2660 ));
2661 assert_eq!(prog.agents[0].handlers[2].event, EventKind::Stop);
2662 }
2663
2664 #[test]
2665 fn parse_function() {
2666 let source = r#"
2667 fn greet(name: String) -> String {
2668 return "Hello, " ++ name;
2669 }
2670
2671 agent Main {
2672 on start {
2673 yield(greet("World"));
2674 }
2675 }
2676 run Main;
2677 "#;
2678
2679 let (prog, errors) = parse_str(source);
2680 assert!(errors.is_empty(), "errors: {errors:?}");
2681 let prog = prog.expect("should parse");
2682
2683 assert_eq!(prog.functions.len(), 1);
2684 assert_eq!(prog.functions[0].name.name, "greet");
2685 assert_eq!(prog.functions[0].params.len(), 1);
2686 }
2687
2688 #[test]
2689 fn parse_let_statement() {
2690 let source = r#"
2691 agent Main {
2692 on start {
2693 let x: Int = 42;
2694 let y = "hello";
2695 yield(x);
2696 }
2697 }
2698 run Main;
2699 "#;
2700
2701 let (prog, errors) = parse_str(source);
2702 assert!(errors.is_empty(), "errors: {errors:?}");
2703 let prog = prog.expect("should parse");
2704
2705 let stmts = &prog.agents[0].handlers[0].body.stmts;
2706 assert!(matches!(stmts[0], Stmt::Let { .. }));
2707 assert!(matches!(stmts[1], Stmt::Let { .. }));
2708 }
2709
2710 #[test]
2711 fn parse_if_statement() {
2712 let source = r#"
2713 agent Main {
2714 on start {
2715 if true {
2716 yield(1);
2717 } else {
2718 yield(2);
2719 }
2720 }
2721 }
2722 run Main;
2723 "#;
2724
2725 let (prog, errors) = parse_str(source);
2726 assert!(errors.is_empty(), "errors: {errors:?}");
2727 let prog = prog.expect("should parse");
2728
2729 let stmts = &prog.agents[0].handlers[0].body.stmts;
2730 assert!(matches!(stmts[0], Stmt::If { .. }));
2731 }
2732
2733 #[test]
2734 fn parse_for_loop() {
2735 let source = r#"
2736 agent Main {
2737 on start {
2738 for x in [1, 2, 3] {
2739 print(x);
2740 }
2741 yield(0);
2742 }
2743 }
2744 run Main;
2745 "#;
2746
2747 let (prog, errors) = parse_str(source);
2748 assert!(errors.is_empty(), "errors: {errors:?}");
2749 let prog = prog.expect("should parse");
2750
2751 let stmts = &prog.agents[0].handlers[0].body.stmts;
2752 assert!(matches!(stmts[0], Stmt::For { .. }));
2753 }
2754
2755 #[test]
2756 fn parse_spawn_await() {
2757 let source = r#"
2758 agent Worker {
2759 name: String
2760
2761 on start {
2762 yield(self.name);
2763 }
2764 }
2765
2766 agent Main {
2767 on start {
2768 let w = summon Worker { name: "test" };
2769 let result = await w;
2770 yield(result);
2771 }
2772 }
2773 run Main;
2774 "#;
2775
2776 let (prog, errors) = parse_str(source);
2777 assert!(errors.is_empty(), "errors: {errors:?}");
2778 prog.expect("should parse");
2779 }
2780
2781 #[test]
2782 fn parse_await_with_timeout() {
2783 let source = r#"
2784 agent Worker {
2785 on start {
2786 yield("done");
2787 }
2788 }
2789
2790 agent Main {
2791 on start {
2792 let w = summon Worker {};
2793 let result = await w timeout(5000);
2794 yield(result);
2795 }
2796 }
2797 run Main;
2798 "#;
2799
2800 let (prog, errors) = parse_str(source);
2801 assert!(errors.is_empty(), "errors: {errors:?}");
2802 let prog = prog.expect("should parse");
2803
2804 let main = &prog.agents[1];
2806 let stmts = &main.handlers[0].body.stmts;
2807 if let Stmt::Let { value, .. } = &stmts[1] {
2810 if let Expr::Await { timeout, .. } = value {
2811 assert!(timeout.is_some(), "timeout should be present");
2812 } else {
2813 panic!("expected Await expression");
2814 }
2815 } else {
2816 panic!("expected Let statement with value");
2817 }
2818 }
2819
2820 #[test]
2821 fn parse_divine() {
2822 let source = r#"
2823 agent Main {
2824 on start {
2825 let result = divine("What is 2+2?");
2826 yield(result);
2827 }
2828 }
2829 run Main;
2830 "#;
2831
2832 let (prog, errors) = parse_str(source);
2833 assert!(errors.is_empty(), "errors: {errors:?}");
2834 prog.expect("should parse");
2835 }
2836
2837 #[test]
2838 fn parse_binary_precedence() {
2839 let source = r#"
2840 agent Main {
2841 on start {
2842 let x = 2 + 3 * 4;
2843 yield(x);
2844 }
2845 }
2846 run Main;
2847 "#;
2848
2849 let (prog, errors) = parse_str(source);
2850 assert!(errors.is_empty(), "errors: {errors:?}");
2851 let prog = prog.expect("should parse");
2852
2853 let stmts = &prog.agents[0].handlers[0].body.stmts;
2854 if let Stmt::Let { value, .. } = &stmts[0] {
2855 if let Expr::Binary { op, .. } = value {
2856 assert_eq!(*op, BinOp::Add);
2857 } else {
2858 panic!("expected binary expression");
2859 }
2860 }
2861 }
2862
2863 #[test]
2864 fn parse_string_interpolation() {
2865 let source = r#"
2866 agent Main {
2867 on start {
2868 let name = "World";
2869 let msg = divine("Greet {name}");
2870 yield(msg);
2871 }
2872 }
2873 run Main;
2874 "#;
2875
2876 let (prog, errors) = parse_str(source);
2877 assert!(errors.is_empty(), "errors: {errors:?}");
2878 let prog = prog.expect("should parse");
2879
2880 let stmts = &prog.agents[0].handlers[0].body.stmts;
2881 if let Stmt::Let { value, .. } = &stmts[1] {
2882 if let Expr::Divine { template, .. } = value {
2883 assert!(template.has_interpolations());
2884 } else {
2885 panic!("expected infer expression");
2886 }
2887 }
2888 }
2889
2890 #[test]
2891 fn parse_single_quoted_string() {
2892 let source = r#"
2893 agent Main {
2894 on start {
2895 let x = 'hello';
2896 yield(0);
2897 }
2898 }
2899 run Main;
2900 "#;
2901
2902 let (prog, errors) = parse_str(source);
2903 assert!(errors.is_empty(), "errors: {errors:?}");
2904 let prog = prog.expect("should parse");
2905
2906 let stmts = &prog.agents[0].handlers[0].body.stmts;
2907 if let Stmt::Let { value, .. } = &stmts[0] {
2908 if let Expr::Literal {
2909 value: Literal::String(s),
2910 ..
2911 } = value
2912 {
2913 assert_eq!(s, "hello");
2914 } else {
2915 panic!("expected string literal, got {:?}", value);
2916 }
2917 } else {
2918 panic!("expected let statement");
2919 }
2920 }
2921
2922 #[test]
2923 fn parse_single_quoted_string_in_interpolation() {
2924 let source = r#"
2927 fn reverse(s: String) -> String {
2928 return s;
2929 }
2930 agent Main {
2931 on start {
2932 print("Result: {reverse('hello')}");
2933 print("Concat: {'abc' ++ 'def'}");
2934 yield(0);
2935 }
2936 }
2937 run Main;
2938 "#;
2939
2940 let (prog, errors) = parse_str(source);
2941 assert!(errors.is_empty(), "errors: {errors:?}");
2942 let prog = prog.expect("should parse");
2943
2944 let stmts = &prog.agents[0].handlers[0].body.stmts;
2946 if let Stmt::Expr {
2947 expr: Expr::Call { args, .. },
2948 ..
2949 } = &stmts[0]
2950 {
2951 if let Expr::StringInterp { template, .. } = &args[0] {
2952 assert!(template.has_interpolations());
2953 } else {
2954 panic!("expected string interpolation");
2955 }
2956 } else {
2957 panic!("expected print call");
2958 }
2959 }
2960
2961 #[test]
2966 fn recover_from_malformed_agent_continues_to_next() {
2967 let source = r#"
2969 agent Broken {
2970 x:
2971 }
2972
2973 agent Main {
2974 on start {
2975 yield(42);
2976 }
2977 }
2978 run Main;
2979 "#;
2980
2981 let (prog, errors) = parse_str(source);
2982 assert!(!errors.is_empty(), "should have parse errors");
2984 let prog = prog.expect("should produce partial AST");
2986 assert!(prog.agents.iter().any(|a| a.name.name == "Main"));
2987 }
2988
2989 #[test]
2990 fn recover_from_mismatched_braces_in_block() {
2991 let source = r#"
2992 agent Main {
2993 on start {
2994 let x = [1, 2, 3;
2995 yield(42);
2996 }
2997 }
2998 run Main;
2999 "#;
3000
3001 let (prog, errors) = parse_str(source);
3002 assert!(!errors.is_empty(), "should have parse errors");
3004 assert!(prog.is_some(), "should produce partial AST despite errors");
3005 }
3006
3007 #[test]
3008 fn parse_mod_declaration() {
3009 let source = r#"
3010 mod agents;
3011 pub mod utils;
3012
3013 agent Main {
3014 on start {
3015 yield(42);
3016 }
3017 }
3018 run Main;
3019 "#;
3020
3021 let (prog, errors) = parse_str(source);
3022 assert!(errors.is_empty(), "errors: {errors:?}");
3023 let prog = prog.expect("should parse");
3024
3025 assert_eq!(prog.mod_decls.len(), 2);
3026 assert!(!prog.mod_decls[0].is_pub);
3027 assert_eq!(prog.mod_decls[0].name.name, "agents");
3028 assert!(prog.mod_decls[1].is_pub);
3029 assert_eq!(prog.mod_decls[1].name.name, "utils");
3030 }
3031
3032 #[test]
3033 fn parse_use_simple() {
3034 let source = r#"
3035 use agents::Researcher;
3036
3037 agent Main {
3038 on start {
3039 yield(42);
3040 }
3041 }
3042 run Main;
3043 "#;
3044
3045 let (prog, errors) = parse_str(source);
3046 assert!(errors.is_empty(), "errors: {errors:?}");
3047 let prog = prog.expect("should parse");
3048
3049 assert_eq!(prog.use_decls.len(), 1);
3050 assert!(!prog.use_decls[0].is_pub);
3051 assert_eq!(prog.use_decls[0].path.len(), 2);
3052 assert_eq!(prog.use_decls[0].path[0].name, "agents");
3053 assert_eq!(prog.use_decls[0].path[1].name, "Researcher");
3054 assert!(matches!(prog.use_decls[0].kind, UseKind::Simple(None)));
3055 }
3056
3057 #[test]
3058 fn parse_use_with_alias() {
3059 let source = r#"
3060 use agents::Researcher as R;
3061
3062 agent Main {
3063 on start {
3064 yield(42);
3065 }
3066 }
3067 run Main;
3068 "#;
3069
3070 let (prog, errors) = parse_str(source);
3071 assert!(errors.is_empty(), "errors: {errors:?}");
3072 let prog = prog.expect("should parse");
3073
3074 assert_eq!(prog.use_decls.len(), 1);
3075 if let UseKind::Simple(Some(alias)) = &prog.use_decls[0].kind {
3076 assert_eq!(alias.name, "R");
3077 } else {
3078 panic!("expected Simple with alias");
3079 }
3080 }
3081
3082 #[test]
3083 fn parse_pub_agent() {
3084 let source = r#"
3085 pub agent Worker {
3086 on start {
3087 yield(42);
3088 }
3089 }
3090
3091 agent Main {
3092 on start {
3093 yield(0);
3094 }
3095 }
3096 run Main;
3097 "#;
3098
3099 let (prog, errors) = parse_str(source);
3100 assert!(errors.is_empty(), "errors: {errors:?}");
3101 let prog = prog.expect("should parse");
3102
3103 assert_eq!(prog.agents.len(), 2);
3104 assert!(prog.agents[0].is_pub);
3105 assert_eq!(prog.agents[0].name.name, "Worker");
3106 assert!(!prog.agents[1].is_pub);
3107 }
3108
3109 #[test]
3110 fn parse_pub_function() {
3111 let source = r#"
3112 pub fn helper(x: Int) -> Int {
3113 return x;
3114 }
3115
3116 agent Main {
3117 on start {
3118 yield(helper(42));
3119 }
3120 }
3121 run Main;
3122 "#;
3123
3124 let (prog, errors) = parse_str(source);
3125 assert!(errors.is_empty(), "errors: {errors:?}");
3126 let prog = prog.expect("should parse");
3127
3128 assert_eq!(prog.functions.len(), 1);
3129 assert!(prog.functions[0].is_pub);
3130 assert_eq!(prog.functions[0].name.name, "helper");
3131 }
3132
3133 #[test]
3134 fn parse_library_no_run() {
3135 let source = r#"
3137 pub agent Worker {
3138 on start {
3139 yield(42);
3140 }
3141 }
3142
3143 pub fn helper(x: Int) -> Int {
3144 return x;
3145 }
3146 "#;
3147
3148 let (prog, errors) = parse_str(source);
3149 assert!(errors.is_empty(), "errors: {errors:?}");
3150 let prog = prog.expect("should parse");
3151
3152 assert!(prog.run_agent.is_none());
3153 assert_eq!(prog.agents.len(), 1);
3154 assert_eq!(prog.functions.len(), 1);
3155 }
3156
3157 #[test]
3158 fn recover_multiple_errors_reported() {
3159 let source = r#"
3161 agent A {
3162 x:
3163 }
3164
3165 agent Main {
3166 on start {
3167 yield(42);
3168 }
3169 }
3170 run Main;
3171 "#;
3172
3173 let (prog, errors) = parse_str(source);
3174 if errors.is_empty() {
3178 let prog = prog.expect("should have AST with recovery");
3180 assert!(prog.agents.iter().any(|a| a.name.name == "Main"));
3181 }
3182 }
3184
3185 #[test]
3186 fn parse_record_declaration() {
3187 let source = r#"
3188 record Point {
3189 x: Int,
3190 y: Int,
3191 }
3192
3193 agent Main {
3194 on start {
3195 yield(0);
3196 }
3197 }
3198 run Main;
3199 "#;
3200
3201 let (prog, errors) = parse_str(source);
3202 assert!(errors.is_empty(), "errors: {errors:?}");
3203 let prog = prog.expect("should parse");
3204
3205 assert_eq!(prog.records.len(), 1);
3206 assert!(!prog.records[0].is_pub);
3207 assert_eq!(prog.records[0].name.name, "Point");
3208 assert_eq!(prog.records[0].fields.len(), 2);
3209 assert_eq!(prog.records[0].fields[0].name.name, "x");
3210 assert_eq!(prog.records[0].fields[1].name.name, "y");
3211 }
3212
3213 #[test]
3214 fn parse_pub_record() {
3215 let source = r#"
3216 pub record Config {
3217 host: String,
3218 port: Int,
3219 }
3220
3221 agent Main {
3222 on start { yield(0); }
3223 }
3224 run Main;
3225 "#;
3226
3227 let (prog, errors) = parse_str(source);
3228 assert!(errors.is_empty(), "errors: {errors:?}");
3229 let prog = prog.expect("should parse");
3230
3231 assert_eq!(prog.records.len(), 1);
3232 assert!(prog.records[0].is_pub);
3233 assert_eq!(prog.records[0].name.name, "Config");
3234 }
3235
3236 #[test]
3237 fn parse_enum_declaration() {
3238 let source = r#"
3239 enum Status {
3240 Active,
3241 Pending,
3242 Done,
3243 }
3244
3245 agent Main {
3246 on start {
3247 yield(0);
3248 }
3249 }
3250 run Main;
3251 "#;
3252
3253 let (prog, errors) = parse_str(source);
3254 assert!(errors.is_empty(), "errors: {errors:?}");
3255 let prog = prog.expect("should parse");
3256
3257 assert_eq!(prog.enums.len(), 1);
3258 assert!(!prog.enums[0].is_pub);
3259 assert_eq!(prog.enums[0].name.name, "Status");
3260 assert_eq!(prog.enums[0].variants.len(), 3);
3261 assert_eq!(prog.enums[0].variants[0].name.name, "Active");
3262 assert_eq!(prog.enums[0].variants[1].name.name, "Pending");
3263 assert_eq!(prog.enums[0].variants[2].name.name, "Done");
3264 }
3265
3266 #[test]
3267 fn parse_pub_enum() {
3268 let source = r#"
3269 pub enum Priority { High, Medium, Low }
3270
3271 agent Main {
3272 on start { yield(0); }
3273 }
3274 run Main;
3275 "#;
3276
3277 let (prog, errors) = parse_str(source);
3278 assert!(errors.is_empty(), "errors: {errors:?}");
3279 let prog = prog.expect("should parse");
3280
3281 assert_eq!(prog.enums.len(), 1);
3282 assert!(prog.enums[0].is_pub);
3283 assert_eq!(prog.enums[0].name.name, "Priority");
3284 }
3285
3286 #[test]
3287 fn parse_const_declaration() {
3288 let source = r#"
3289 const MAX_RETRIES: Int = 3;
3290
3291 agent Main {
3292 on start {
3293 yield(0);
3294 }
3295 }
3296 run Main;
3297 "#;
3298
3299 let (prog, errors) = parse_str(source);
3300 assert!(errors.is_empty(), "errors: {errors:?}");
3301 let prog = prog.expect("should parse");
3302
3303 assert_eq!(prog.consts.len(), 1);
3304 assert!(!prog.consts[0].is_pub);
3305 assert_eq!(prog.consts[0].name.name, "MAX_RETRIES");
3306 assert!(matches!(prog.consts[0].ty, TypeExpr::Int));
3307 }
3308
3309 #[test]
3310 fn parse_pub_const() {
3311 let source = r#"
3312 pub const API_URL: String = "https://api.example.com";
3313
3314 agent Main {
3315 on start { yield(0); }
3316 }
3317 run Main;
3318 "#;
3319
3320 let (prog, errors) = parse_str(source);
3321 assert!(errors.is_empty(), "errors: {errors:?}");
3322 let prog = prog.expect("should parse");
3323
3324 assert_eq!(prog.consts.len(), 1);
3325 assert!(prog.consts[0].is_pub);
3326 assert_eq!(prog.consts[0].name.name, "API_URL");
3327 }
3328
3329 #[test]
3330 fn parse_multiple_type_declarations() {
3331 let source = r#"
3332 record Point { x: Int, y: Int }
3333 enum Color { Red, Green, Blue }
3334 const ORIGIN_X: Int = 0;
3335
3336 agent Main {
3337 on start { yield(0); }
3338 }
3339 run Main;
3340 "#;
3341
3342 let (prog, errors) = parse_str(source);
3343 assert!(errors.is_empty(), "errors: {errors:?}");
3344 let prog = prog.expect("should parse");
3345
3346 assert_eq!(prog.records.len(), 1);
3347 assert_eq!(prog.enums.len(), 1);
3348 assert_eq!(prog.consts.len(), 1);
3349 }
3350
3351 #[test]
3352 fn parse_match_expression() {
3353 let source = r#"
3354 enum Status { Active, Pending, Done }
3355
3356 agent Main {
3357 on start {
3358 let s: Int = match Active {
3359 Active => 1,
3360 Pending => 2,
3361 Done => 3,
3362 };
3363 yield(s);
3364 }
3365 }
3366 run Main;
3367 "#;
3368
3369 let (prog, errors) = parse_str(source);
3370 assert!(errors.is_empty(), "errors: {errors:?}");
3371 let prog = prog.expect("should parse");
3372
3373 assert_eq!(prog.agents.len(), 1);
3375 let handler = &prog.agents[0].handlers[0];
3377 let stmt = &handler.body.stmts[0];
3378 if let Stmt::Let { value, .. } = stmt {
3379 assert!(matches!(value, Expr::Match { .. }));
3380 } else {
3381 panic!("expected let statement with match");
3382 }
3383 }
3384
3385 #[test]
3386 fn parse_match_with_wildcard() {
3387 let source = r#"
3388 agent Main {
3389 on start {
3390 let x = 5;
3391 let result = match x {
3392 1 => 10,
3393 2 => 20,
3394 _ => 0,
3395 };
3396 yield(result);
3397 }
3398 }
3399 run Main;
3400 "#;
3401
3402 let (prog, errors) = parse_str(source);
3403 assert!(errors.is_empty(), "errors: {errors:?}");
3404 let prog = prog.expect("should parse");
3405
3406 assert_eq!(prog.agents.len(), 1);
3407 }
3408
3409 #[test]
3410 fn parse_record_construction() {
3411 let source = r#"
3412 record Point { x: Int, y: Int }
3413
3414 agent Main {
3415 on start {
3416 let p = Point { x: 10, y: 20 };
3417 yield(0);
3418 }
3419 }
3420 run Main;
3421 "#;
3422
3423 let (prog, errors) = parse_str(source);
3424 assert!(errors.is_empty(), "errors: {errors:?}");
3425 let prog = prog.expect("should parse");
3426
3427 assert_eq!(prog.records.len(), 1);
3428 assert_eq!(prog.agents.len(), 1);
3429
3430 let handler = &prog.agents[0].handlers[0];
3432 let stmt = &handler.body.stmts[0];
3433 if let Stmt::Let { value, .. } = stmt {
3434 if let Expr::RecordConstruct { name, fields, .. } = value {
3435 assert_eq!(name.name, "Point");
3436 assert_eq!(fields.len(), 2);
3437 assert_eq!(fields[0].name.name, "x");
3438 assert_eq!(fields[1].name.name, "y");
3439 } else {
3440 panic!("expected RecordConstruct");
3441 }
3442 } else {
3443 panic!("expected let statement");
3444 }
3445 }
3446
3447 #[test]
3448 fn parse_match_with_qualified_variant() {
3449 let source = r#"
3450 enum Status { Active, Pending }
3451
3452 fn get_status() -> Int {
3453 return 1;
3454 }
3455
3456 agent Main {
3457 on start {
3458 let s = get_status();
3459 let result = match s {
3460 Status::Active => 1,
3461 Status::Pending => 0,
3462 };
3463 yield(result);
3464 }
3465 }
3466 run Main;
3467 "#;
3468
3469 let (prog, errors) = parse_str(source);
3470 assert!(errors.is_empty(), "errors: {errors:?}");
3471 let prog = prog.expect("should parse");
3472
3473 assert_eq!(prog.enums.len(), 1);
3474 assert_eq!(prog.agents.len(), 1);
3475 }
3476
3477 #[test]
3478 fn parse_field_access() {
3479 let source = r#"
3480 record Point { x: Int, y: Int }
3481
3482 agent Main {
3483 on start {
3484 let p = Point { x: 10, y: 20 };
3485 let x_val = p.x;
3486 let y_val = p.y;
3487 yield(x_val);
3488 }
3489 }
3490 run Main;
3491 "#;
3492
3493 let (prog, errors) = parse_str(source);
3494 assert!(errors.is_empty(), "errors: {errors:?}");
3495 let prog = prog.expect("should parse");
3496
3497 assert_eq!(prog.records.len(), 1);
3498 assert_eq!(prog.agents.len(), 1);
3499
3500 let handler = &prog.agents[0].handlers[0];
3502 let stmt = &handler.body.stmts[1]; if let Stmt::Let { value, .. } = stmt {
3504 if let Expr::FieldAccess { field, .. } = value {
3505 assert_eq!(field.name, "x");
3506 } else {
3507 panic!("expected FieldAccess");
3508 }
3509 } else {
3510 panic!("expected let statement");
3511 }
3512 }
3513
3514 #[test]
3515 fn parse_chained_field_access() {
3516 let source = r#"
3517 record Inner { val: Int }
3518 record Outer { inner: Inner }
3519
3520 agent Main {
3521 on start {
3522 let inner = Inner { val: 42 };
3523 let outer = Outer { inner: inner };
3524 let v = outer.inner.val;
3525 yield(v);
3526 }
3527 }
3528 run Main;
3529 "#;
3530
3531 let (prog, errors) = parse_str(source);
3532 assert!(errors.is_empty(), "errors: {errors:?}");
3533 let prog = prog.expect("should parse");
3534
3535 assert_eq!(prog.records.len(), 2);
3536 assert_eq!(prog.agents.len(), 1);
3537
3538 let handler = &prog.agents[0].handlers[0];
3540 let stmt = &handler.body.stmts[2]; if let Stmt::Let { value, .. } = stmt {
3542 if let Expr::FieldAccess {
3543 object, field: val, ..
3544 } = value
3545 {
3546 assert_eq!(val.name, "val");
3547 if let Expr::FieldAccess { field: inner, .. } = object.as_ref() {
3549 assert_eq!(inner.name, "inner");
3550 } else {
3551 panic!("expected nested FieldAccess");
3552 }
3553 } else {
3554 panic!("expected FieldAccess");
3555 }
3556 } else {
3557 panic!("expected let statement");
3558 }
3559 }
3560
3561 #[test]
3566 fn parse_loop_break() {
3567 let source = r#"
3568 agent Main {
3569 on start {
3570 let count = 0;
3571 loop {
3572 count = count + 1;
3573 if count > 5 {
3574 break;
3575 }
3576 }
3577 yield(count);
3578 }
3579 }
3580 run Main;
3581 "#;
3582
3583 let (prog, errors) = parse_str(source);
3584 assert!(errors.is_empty(), "errors: {errors:?}");
3585 let prog = prog.expect("should parse");
3586
3587 assert_eq!(prog.agents.len(), 1);
3588 let handler = &prog.agents[0].handlers[0];
3589 let loop_stmt = &handler.body.stmts[1];
3591 assert!(matches!(loop_stmt, Stmt::Loop { .. }));
3592 if let Stmt::Loop { body, .. } = loop_stmt {
3594 let if_stmt = &body.stmts[1];
3595 if let Stmt::If { then_block, .. } = if_stmt {
3596 assert!(matches!(then_block.stmts[0], Stmt::Break { .. }));
3597 } else {
3598 panic!("expected if statement");
3599 }
3600 }
3601 }
3602
3603 #[test]
3604 fn parse_agent_receives() {
3605 let source = r#"
3606 enum WorkerMsg {
3607 Task,
3608 Shutdown,
3609 }
3610
3611 agent Worker receives WorkerMsg {
3612 id: Int
3613
3614 on start {
3615 yield(0);
3616 }
3617 }
3618
3619 agent Main {
3620 on start {
3621 yield(0);
3622 }
3623 }
3624 run Main;
3625 "#;
3626
3627 let (prog, errors) = parse_str(source);
3628 assert!(errors.is_empty(), "errors: {errors:?}");
3629 let prog = prog.expect("should parse");
3630
3631 assert_eq!(prog.agents.len(), 2);
3632
3633 let worker = &prog.agents[0];
3635 assert_eq!(worker.name.name, "Worker");
3636 assert!(worker.receives.is_some());
3637 if let Some(TypeExpr::Named(name, _)) = &worker.receives {
3638 assert_eq!(name.name, "WorkerMsg");
3639 } else {
3640 panic!("expected named type for receives");
3641 }
3642
3643 let main = &prog.agents[1];
3645 assert_eq!(main.name.name, "Main");
3646 assert!(main.receives.is_none());
3647 }
3648
3649 #[test]
3650 fn parse_receive_expression() {
3651 let source = r#"
3652 enum Msg { Ping }
3653
3654 agent Worker receives Msg {
3655 on start {
3656 let msg = receive();
3657 yield(0);
3658 }
3659 }
3660
3661 agent Main {
3662 on start { yield(0); }
3663 }
3664 run Main;
3665 "#;
3666
3667 let (prog, errors) = parse_str(source);
3668 assert!(errors.is_empty(), "errors: {errors:?}");
3669 let prog = prog.expect("should parse");
3670
3671 let worker = prog
3673 .agents
3674 .iter()
3675 .find(|a| a.name.name == "Worker")
3676 .unwrap();
3677 let handler = &worker.handlers[0];
3678 let stmt = &handler.body.stmts[0];
3679
3680 if let Stmt::Let { value, .. } = stmt {
3681 assert!(matches!(value, Expr::Receive { .. }));
3682 } else {
3683 panic!("expected let with receive");
3684 }
3685 }
3686
3687 #[test]
3688 fn parse_message_passing_full() {
3689 let source = r#"
3690 enum WorkerMsg {
3691 Task,
3692 Shutdown,
3693 }
3694
3695 agent Worker receives WorkerMsg {
3696 id: Int
3697
3698 on start {
3699 let msg = receive();
3700 let result = match msg {
3701 Task => 1,
3702 Shutdown => 0,
3703 };
3704 yield(result);
3705 }
3706 }
3707
3708 agent Main {
3709 on start {
3710 let w = summon Worker { id: 1 };
3711 send(w, Task);
3712 send(w, Shutdown);
3713 await w;
3714 yield(0);
3715 }
3716 }
3717 run Main;
3718 "#;
3719
3720 let (prog, errors) = parse_str(source);
3721 assert!(errors.is_empty(), "errors: {errors:?}");
3722 let prog = prog.expect("should parse");
3723
3724 assert_eq!(prog.enums.len(), 1);
3725 assert_eq!(prog.agents.len(), 2);
3726
3727 let worker = prog
3729 .agents
3730 .iter()
3731 .find(|a| a.name.name == "Worker")
3732 .unwrap();
3733 assert!(worker.receives.is_some());
3734 }
3735
3736 #[test]
3741 fn parse_fallible_function() {
3742 let source = r#"
3743 fn get_data(url: String) -> String fails {
3744 return divine("Get data from {url}" -> String);
3745 }
3746
3747 agent Main {
3748 on start { yield(0); }
3749 }
3750 run Main;
3751 "#;
3752
3753 let (prog, errors) = parse_str(source);
3754 assert!(errors.is_empty(), "errors: {errors:?}");
3755 let prog = prog.expect("should parse");
3756
3757 assert_eq!(prog.functions.len(), 1);
3758 assert!(prog.functions[0].is_fallible);
3759 }
3760
3761 #[test]
3762 fn parse_try_expression() {
3763 let source = r#"
3764 fn fallible() -> Int fails { return 42; }
3765
3766 agent Main {
3767 on start {
3768 let x = try fallible();
3769 yield(x);
3770 }
3771 }
3772 run Main;
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];
3781 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
3782 assert!(matches!(value, Expr::Try { .. }));
3783 } else {
3784 panic!("expected Let statement");
3785 }
3786 }
3787
3788 #[test]
3789 fn parse_catch_expression() {
3790 let source = r#"
3791 fn fallible() -> Int fails { return 42; }
3792
3793 agent Main {
3794 on start {
3795 let x = fallible() catch { 0 };
3796 yield(x);
3797 }
3798 }
3799 run Main;
3800 "#;
3801
3802 let (prog, errors) = parse_str(source);
3803 assert!(errors.is_empty(), "errors: {errors:?}");
3804 let prog = prog.expect("should parse");
3805
3806 let handler = &prog.agents[0].handlers[0];
3808 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
3809 if let Expr::Catch { error_bind, .. } = value {
3810 assert!(error_bind.is_none());
3811 } else {
3812 panic!("expected Catch expression");
3813 }
3814 } else {
3815 panic!("expected Let statement");
3816 }
3817 }
3818
3819 #[test]
3820 fn parse_catch_with_error_binding() {
3821 let source = r#"
3822 fn fallible() -> Int fails { return 42; }
3823
3824 agent Main {
3825 on start {
3826 let x = fallible() catch(e) { 0 };
3827 yield(x);
3828 }
3829 }
3830 run Main;
3831 "#;
3832
3833 let (prog, errors) = parse_str(source);
3834 assert!(errors.is_empty(), "errors: {errors:?}");
3835 let prog = prog.expect("should parse");
3836
3837 let handler = &prog.agents[0].handlers[0];
3839 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
3840 if let Expr::Catch { error_bind, .. } = value {
3841 assert!(error_bind.is_some());
3842 assert_eq!(error_bind.as_ref().unwrap().name, "e");
3843 } else {
3844 panic!("expected Catch expression");
3845 }
3846 } else {
3847 panic!("expected Let statement");
3848 }
3849 }
3850
3851 #[test]
3852 fn parse_fail_expression() {
3853 let source = r#"
3854 agent Main {
3855 on start {
3856 fail "something went wrong";
3857 }
3858 on error(e) {
3859 yield(0);
3860 }
3861 }
3862 run Main;
3863 "#;
3864
3865 let (prog, errors) = parse_str(source);
3866 assert!(errors.is_empty(), "errors: {errors:?}");
3867 let prog = prog.expect("should parse");
3868
3869 let handler = &prog.agents[0].handlers[0];
3871 if let Stmt::Expr { expr, .. } = &handler.body.stmts[0] {
3872 if let Expr::Fail { error, .. } = expr {
3873 assert!(matches!(**error, Expr::Literal { .. }));
3874 } else {
3875 panic!("expected Fail expression, got {expr:?}");
3876 }
3877 } else {
3878 panic!("expected Expr statement");
3879 }
3880 }
3881
3882 #[test]
3883 fn parse_retry_expression() {
3884 let source = r#"
3885 agent Main {
3886 topic: String
3887
3888 on start {
3889 let result = retry(3) {
3890 try divine("Summarize: {self.topic}")
3891 } catch { "fallback" };
3892 yield(result);
3893 }
3894
3895 on error(e) {
3896 yield("");
3897 }
3898 }
3899 run Main;
3900 "#;
3901
3902 let (prog, errors) = parse_str(source);
3903 assert!(errors.is_empty(), "errors: {errors:?}");
3904 let prog = prog.expect("should parse");
3905
3906 let handler = &prog.agents[0].handlers[0];
3908 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
3909 if let Expr::Catch { expr, .. } = value {
3911 if let Expr::Retry { count, delay, .. } = expr.as_ref() {
3912 assert!(matches!(**count, Expr::Literal { .. }));
3913 assert!(delay.is_none());
3914 } else {
3915 panic!("expected Retry expression");
3916 }
3917 } else {
3918 panic!("expected Catch expression");
3919 }
3920 } else {
3921 panic!("expected Let statement");
3922 }
3923 }
3924
3925 #[test]
3926 fn parse_retry_with_delay() {
3927 let source = r#"
3928 agent Main {
3929 on start {
3930 let result = retry(3, delay: 1000) {
3931 42
3932 } catch { 0 };
3933 yield(result);
3934 }
3935 }
3936 run Main;
3937 "#;
3938
3939 let (prog, errors) = parse_str(source);
3940 assert!(errors.is_empty(), "errors: {errors:?}");
3941 let prog = prog.expect("should parse");
3942
3943 let handler = &prog.agents[0].handlers[0];
3945 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
3946 if let Expr::Catch { expr, .. } = value {
3947 if let Expr::Retry { delay, .. } = expr.as_ref() {
3948 assert!(delay.is_some());
3949 } else {
3950 panic!("expected Retry expression");
3951 }
3952 } else {
3953 panic!("expected Catch expression");
3954 }
3955 } else {
3956 panic!("expected Let statement");
3957 }
3958 }
3959
3960 #[test]
3961 fn parse_on_error_handler() {
3962 let source = r#"
3963 agent Main {
3964 on start {
3965 yield(0);
3966 }
3967
3968 on error(e) {
3969 yield(1);
3970 }
3971 }
3972 run Main;
3973 "#;
3974
3975 let (prog, errors) = parse_str(source);
3976 assert!(errors.is_empty(), "errors: {errors:?}");
3977 let prog = prog.expect("should parse");
3978
3979 assert_eq!(prog.agents.len(), 1);
3980 assert_eq!(prog.agents[0].handlers.len(), 2);
3981
3982 let error_handler = prog.agents[0]
3984 .handlers
3985 .iter()
3986 .find(|h| matches!(h.event, EventKind::Error { .. }));
3987 assert!(error_handler.is_some());
3988
3989 if let EventKind::Error { param_name } = &error_handler.unwrap().event {
3990 assert_eq!(param_name.name, "e");
3991 } else {
3992 panic!("expected Error event kind");
3993 }
3994 }
3995
3996 #[test]
4001 fn parse_fn_type() {
4002 let source = r#"
4003 fn apply(f: Fn(Int) -> Int, x: Int) -> Int {
4004 return f(x);
4005 }
4006
4007 agent Main {
4008 on start {
4009 yield(0);
4010 }
4011 }
4012 run Main;
4013 "#;
4014
4015 let (prog, errors) = parse_str(source);
4016 assert!(errors.is_empty(), "errors: {errors:?}");
4017 let prog = prog.expect("should parse");
4018
4019 assert_eq!(prog.functions.len(), 1);
4020 let func = &prog.functions[0];
4021 assert_eq!(func.name.name, "apply");
4022 assert_eq!(func.params.len(), 2);
4023
4024 if let TypeExpr::Fn(params, ret) = &func.params[0].ty {
4026 assert_eq!(params.len(), 1);
4027 assert!(matches!(params[0], TypeExpr::Int));
4028 assert!(matches!(ret.as_ref(), TypeExpr::Int));
4029 } else {
4030 panic!("expected Fn type for first param");
4031 }
4032 }
4033
4034 #[test]
4035 fn parse_closure_with_params() {
4036 let source = r#"
4037 agent Main {
4038 on start {
4039 let f = |x: Int| x + 1;
4040 yield(0);
4041 }
4042 }
4043 run Main;
4044 "#;
4045
4046 let (prog, errors) = parse_str(source);
4047 assert!(errors.is_empty(), "errors: {errors:?}");
4048 let prog = prog.expect("should parse");
4049
4050 let handler = &prog.agents[0].handlers[0];
4052 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
4053 if let Expr::Closure { params, body, .. } = value {
4054 assert_eq!(params.len(), 1);
4055 assert_eq!(params[0].name.name, "x");
4056 assert!(matches!(¶ms[0].ty, Some(TypeExpr::Int)));
4057
4058 assert!(matches!(body.as_ref(), Expr::Binary { .. }));
4060 } else {
4061 panic!("expected closure expression");
4062 }
4063 } else {
4064 panic!("expected let statement");
4065 }
4066 }
4067
4068 #[test]
4069 fn parse_closure_empty_params() {
4070 let source = r#"
4071 agent Main {
4072 on start {
4073 let f = || 42;
4074 yield(0);
4075 }
4076 }
4077 run Main;
4078 "#;
4079
4080 let (prog, errors) = parse_str(source);
4081 assert!(errors.is_empty(), "errors: {errors:?}");
4082 let prog = prog.expect("should parse");
4083
4084 let handler = &prog.agents[0].handlers[0];
4086 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
4087 if let Expr::Closure { params, body, .. } = value {
4088 assert!(params.is_empty());
4089
4090 assert!(matches!(body.as_ref(), Expr::Literal { .. }));
4092 } else {
4093 panic!("expected closure expression");
4094 }
4095 } else {
4096 panic!("expected let statement");
4097 }
4098 }
4099
4100 #[test]
4101 fn parse_closure_multiple_params() {
4102 let source = r#"
4103 agent Main {
4104 on start {
4105 let add = |x: Int, y: Int| x + y;
4106 yield(0);
4107 }
4108 }
4109 run Main;
4110 "#;
4111
4112 let (prog, errors) = parse_str(source);
4113 assert!(errors.is_empty(), "errors: {errors:?}");
4114 let prog = prog.expect("should parse");
4115
4116 let handler = &prog.agents[0].handlers[0];
4117 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
4118 if let Expr::Closure { params, .. } = value {
4119 assert_eq!(params.len(), 2);
4120 assert_eq!(params[0].name.name, "x");
4121 assert_eq!(params[1].name.name, "y");
4122 } else {
4123 panic!("expected closure expression");
4124 }
4125 } else {
4126 panic!("expected let statement");
4127 }
4128 }
4129
4130 #[test]
4131 fn parse_fn_type_multiarg() {
4132 let source = r#"
4133 fn fold_left(f: Fn(Int, Int) -> Int, init: Int) -> Int {
4134 return init;
4135 }
4136
4137 agent Main {
4138 on start {
4139 yield(0);
4140 }
4141 }
4142 run Main;
4143 "#;
4144
4145 let (prog, errors) = parse_str(source);
4146 assert!(errors.is_empty(), "errors: {errors:?}");
4147 let prog = prog.expect("should parse");
4148
4149 if let TypeExpr::Fn(params, ret) = &prog.functions[0].params[0].ty {
4151 assert_eq!(params.len(), 2);
4152 assert!(matches!(params[0], TypeExpr::Int));
4153 assert!(matches!(params[1], TypeExpr::Int));
4154 assert!(matches!(ret.as_ref(), TypeExpr::Int));
4155 } else {
4156 panic!("expected Fn type");
4157 }
4158 }
4159
4160 #[test]
4161 fn parse_tuple_literal() {
4162 let source = r#"
4163 agent Main {
4164 on start {
4165 let t = (1, 2);
4166 yield(0);
4167 }
4168 }
4169 run Main;
4170 "#;
4171
4172 let (prog, errors) = parse_str(source);
4173 assert!(errors.is_empty(), "errors: {errors:?}");
4174 let prog = prog.expect("should parse");
4175
4176 let handler = &prog.agents[0].handlers[0];
4177 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
4178 if let Expr::Tuple { elements, .. } = value {
4179 assert_eq!(elements.len(), 2);
4180 } else {
4181 panic!("expected tuple expression, got {:?}", value);
4182 }
4183 } else {
4184 panic!("expected let statement");
4185 }
4186 }
4187
4188 #[test]
4193 fn parse_tool_declaration() {
4194 let source = r#"
4195 tool Http {
4196 fn get(url: String) -> Result<String, String>
4197 fn post(url: String, body: String) -> Result<String, String>
4198 }
4199 agent Main {
4200 on start { yield(0); }
4201 }
4202 run Main;
4203 "#;
4204
4205 let (prog, errors) = parse_str(source);
4206 assert!(errors.is_empty(), "errors: {errors:?}");
4207 let prog = prog.expect("should parse");
4208
4209 assert_eq!(prog.tools.len(), 1);
4210 assert_eq!(prog.tools[0].name.name, "Http");
4211 assert_eq!(prog.tools[0].functions.len(), 2);
4212 assert_eq!(prog.tools[0].functions[0].name.name, "get");
4213 assert_eq!(prog.tools[0].functions[1].name.name, "post");
4214 }
4215
4216 #[test]
4217 fn parse_pub_tool_declaration() {
4218 let source = r#"
4219 pub tool Database {
4220 fn query(sql: String) -> Result<List<String>, String>
4221 }
4222 agent Main {
4223 on start { yield(0); }
4224 }
4225 run Main;
4226 "#;
4227
4228 let (prog, errors) = parse_str(source);
4229 assert!(errors.is_empty(), "errors: {errors:?}");
4230 let prog = prog.expect("should parse");
4231
4232 assert!(prog.tools[0].is_pub);
4233 assert_eq!(prog.tools[0].name.name, "Database");
4234 }
4235
4236 #[test]
4237 fn parse_agent_with_tool_use() {
4238 let source = r#"
4239 agent Fetcher {
4240 use Http
4241
4242 url: String
4243
4244 on start {
4245 yield(0);
4246 }
4247 }
4248 run Fetcher;
4249 "#;
4250
4251 let (prog, errors) = parse_str(source);
4252 assert!(errors.is_empty(), "errors: {errors:?}");
4253 let prog = prog.expect("should parse");
4254
4255 assert_eq!(prog.agents[0].tool_uses.len(), 1);
4256 assert_eq!(prog.agents[0].tool_uses[0].name, "Http");
4257 assert_eq!(prog.agents[0].beliefs.len(), 1);
4258 }
4259
4260 #[test]
4261 fn parse_agent_with_multiple_tool_uses() {
4262 let source = r#"
4263 agent Pipeline {
4264 use Http, Fs
4265
4266 on start {
4267 yield(0);
4268 }
4269 }
4270 run Pipeline;
4271 "#;
4272
4273 let (prog, errors) = parse_str(source);
4274 assert!(errors.is_empty(), "errors: {errors:?}");
4275 let prog = prog.expect("should parse");
4276
4277 assert_eq!(prog.agents[0].tool_uses.len(), 2);
4278 assert_eq!(prog.agents[0].tool_uses[0].name, "Http");
4279 assert_eq!(prog.agents[0].tool_uses[1].name, "Fs");
4280 }
4281
4282 #[test]
4283 fn parse_tool_call_expression() {
4284 let source = r#"
4285 agent Fetcher {
4286 use Http
4287
4288 on start {
4289 let response = Http.get("https://example.com");
4290 yield(0);
4291 }
4292 }
4293 run Fetcher;
4294 "#;
4295
4296 let (prog, errors) = parse_str(source);
4297 assert!(errors.is_empty(), "errors: {errors:?}");
4298 let prog = prog.expect("should parse");
4299
4300 let handler = &prog.agents[0].handlers[0];
4301 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
4302 if let Expr::ToolCall {
4303 tool,
4304 function,
4305 args,
4306 ..
4307 } = value
4308 {
4309 assert_eq!(tool.name, "Http");
4310 assert_eq!(function.name, "get");
4311 assert_eq!(args.len(), 1);
4312 } else {
4313 panic!("expected ToolCall expression, got {:?}", value);
4314 }
4315 } else {
4316 panic!("expected let statement");
4317 }
4318 }
4319
4320 #[test]
4321 fn parse_tool_call_with_multiple_args() {
4322 let source = r#"
4323 agent Writer {
4324 use Fs
4325
4326 on start {
4327 let result = Fs.write("/tmp/test.txt", "hello world");
4328 yield(0);
4329 }
4330 }
4331 run Writer;
4332 "#;
4333
4334 let (prog, errors) = parse_str(source);
4335 assert!(errors.is_empty(), "errors: {errors:?}");
4336 let prog = prog.expect("should parse");
4337
4338 let handler = &prog.agents[0].handlers[0];
4339 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
4340 if let Expr::ToolCall { args, .. } = value {
4341 assert_eq!(args.len(), 2);
4342 } else {
4343 panic!("expected ToolCall expression, got {:?}", value);
4344 }
4345 } else {
4346 panic!("expected let statement");
4347 }
4348 }
4349
4350 #[test]
4351 fn parse_string_interp_with_field_access() {
4352 let source = r#"
4353 record Person { name: String }
4354 agent Main {
4355 on start {
4356 let p = Person { name: "Alice" };
4357 print("Hello, {p.name}!");
4358 yield(0);
4359 }
4360 }
4361 run Main;
4362 "#;
4363
4364 let (prog, errors) = parse_str(source);
4365 assert!(errors.is_empty(), "errors: {errors:?}");
4366 let prog = prog.expect("should parse");
4367
4368 let handler = &prog.agents[0].handlers[0];
4370 if let Stmt::Expr { expr, .. } = &handler.body.stmts[1] {
4371 if let Expr::Call { args, .. } = expr {
4372 if let Expr::StringInterp { template, .. } = &args[0] {
4373 assert!(template.has_interpolations());
4374 let interps: Vec<_> = template.interpolations().collect();
4375 assert_eq!(interps.len(), 1);
4376 match interps[0] {
4378 Expr::FieldAccess { object, field, .. } => {
4379 if let Expr::Var { name, .. } = object.as_ref() {
4380 assert_eq!(name.name, "p");
4381 } else {
4382 panic!("expected Var as base");
4383 }
4384 assert_eq!(field.name, "name");
4385 }
4386 _ => panic!("expected FieldAccess, got {:?}", interps[0]),
4387 }
4388 } else {
4389 panic!("expected StringInterp");
4390 }
4391 } else {
4392 panic!("expected Call");
4393 }
4394 } else {
4395 panic!("expected Expr statement");
4396 }
4397 }
4398
4399 #[test]
4400 fn parse_string_interp_with_tuple_index() {
4401 let source = r#"
4402 agent Main {
4403 on start {
4404 let pair = (1, 2);
4405 print("First: {pair.0}");
4406 yield(0);
4407 }
4408 }
4409 run Main;
4410 "#;
4411
4412 let (prog, errors) = parse_str(source);
4413 assert!(errors.is_empty(), "errors: {errors:?}");
4414 let prog = prog.expect("should parse");
4415
4416 let handler = &prog.agents[0].handlers[0];
4417 if let Stmt::Expr { expr, .. } = &handler.body.stmts[1] {
4418 if let Expr::Call { args, .. } = expr {
4419 if let Expr::StringInterp { template, .. } = &args[0] {
4420 let interps: Vec<_> = template.interpolations().collect();
4421 assert_eq!(interps.len(), 1);
4422 match interps[0] {
4423 Expr::TupleIndex { tuple, index, .. } => {
4424 if let Expr::Var { name, .. } = tuple.as_ref() {
4425 assert_eq!(name.name, "pair");
4426 } else {
4427 panic!("expected Var as tuple base");
4428 }
4429 assert_eq!(*index, 0);
4430 }
4431 _ => panic!("expected TupleIndex, got {:?}", interps[0]),
4432 }
4433 } else {
4434 panic!("expected StringInterp");
4435 }
4436 } else {
4437 panic!("expected Call");
4438 }
4439 } else {
4440 panic!("expected Expr statement");
4441 }
4442 }
4443
4444 #[test]
4445 fn parse_mock_tool_with_fail() {
4446 let source = r#"
4447 test "mock tool fail" {
4448 mock tool Http.get -> fail("network error");
4449 }
4450 "#;
4451
4452 let (prog, errors) = parse_str(source);
4453 assert!(errors.is_empty(), "errors: {errors:?}");
4454 let prog = prog.expect("should parse");
4455
4456 let test = &prog.tests[0];
4457 assert_eq!(test.body.stmts.len(), 1);
4458
4459 if let Stmt::MockTool {
4460 tool_name,
4461 fn_name,
4462 value,
4463 ..
4464 } = &test.body.stmts[0]
4465 {
4466 assert_eq!(tool_name.name, "Http");
4467 assert_eq!(fn_name.name, "get");
4468 assert!(
4469 matches!(value, MockValue::Fail(_)),
4470 "expected MockValue::Fail, got {:?}",
4471 value
4472 );
4473 } else {
4474 panic!("expected MockTool statement, got {:?}", test.body.stmts[0]);
4475 }
4476 }
4477
4478 #[test]
4479 fn parse_mock_tool_with_value() {
4480 let source = r#"
4481 test "mock tool value" {
4482 mock tool Http.get -> "response";
4483 }
4484 "#;
4485
4486 let (prog, errors) = parse_str(source);
4487 assert!(errors.is_empty(), "errors: {errors:?}");
4488 let prog = prog.expect("should parse");
4489
4490 let test = &prog.tests[0];
4491 if let Stmt::MockTool { value, .. } = &test.body.stmts[0] {
4492 assert!(
4493 matches!(value, MockValue::Value(_)),
4494 "expected MockValue::Value, got {:?}",
4495 value
4496 );
4497 } else {
4498 panic!("expected MockTool statement");
4499 }
4500 }
4501
4502 #[test]
4507 fn parse_generic_function() {
4508 let source = r#"
4509 fn identity<T>(x: T) -> T {
4510 return x;
4511 }
4512
4513 agent Main {
4514 on start { yield(0); }
4515 }
4516 run Main;
4517 "#;
4518
4519 let (prog, errors) = parse_str(source);
4520 assert!(errors.is_empty(), "errors: {errors:?}");
4521 let prog = prog.expect("should parse");
4522
4523 assert_eq!(prog.functions.len(), 1);
4524 let func = &prog.functions[0];
4525 assert_eq!(func.name.name, "identity");
4526 assert_eq!(func.type_params.len(), 1);
4527 assert_eq!(func.type_params[0].name, "T");
4528 }
4529
4530 #[test]
4531 fn parse_generic_function_multiple_params() {
4532 let source = r#"
4533 fn map<T, U>(list: List<T>, f: Fn(T) -> U) -> List<U> {
4534 return [];
4535 }
4536
4537 agent Main {
4538 on start { yield(0); }
4539 }
4540 run Main;
4541 "#;
4542
4543 let (prog, errors) = parse_str(source);
4544 assert!(errors.is_empty(), "errors: {errors:?}");
4545 let prog = prog.expect("should parse");
4546
4547 let func = &prog.functions[0];
4548 assert_eq!(func.name.name, "map");
4549 assert_eq!(func.type_params.len(), 2);
4550 assert_eq!(func.type_params[0].name, "T");
4551 assert_eq!(func.type_params[1].name, "U");
4552 }
4553
4554 #[test]
4555 fn parse_generic_record() {
4556 let source = r#"
4557 record Pair<A, B> {
4558 first: A,
4559 second: B,
4560 }
4561
4562 agent Main {
4563 on start { yield(0); }
4564 }
4565 run Main;
4566 "#;
4567
4568 let (prog, errors) = parse_str(source);
4569 assert!(errors.is_empty(), "errors: {errors:?}");
4570 let prog = prog.expect("should parse");
4571
4572 assert_eq!(prog.records.len(), 1);
4573 let record = &prog.records[0];
4574 assert_eq!(record.name.name, "Pair");
4575 assert_eq!(record.type_params.len(), 2);
4576 assert_eq!(record.type_params[0].name, "A");
4577 assert_eq!(record.type_params[1].name, "B");
4578 }
4579
4580 #[test]
4581 fn parse_generic_enum() {
4582 let source = r#"
4583 enum Tree<T> {
4584 Leaf(T),
4585 Node(Tree<T>),
4586 }
4587
4588 agent Main {
4589 on start { yield(0); }
4590 }
4591 run Main;
4592 "#;
4593
4594 let (prog, errors) = parse_str(source);
4595 assert!(errors.is_empty(), "errors: {errors:?}");
4596 let prog = prog.expect("should parse");
4597
4598 assert_eq!(prog.enums.len(), 1);
4599 let enumm = &prog.enums[0];
4600 assert_eq!(enumm.name.name, "Tree");
4601 assert_eq!(enumm.type_params.len(), 1);
4602 assert_eq!(enumm.type_params[0].name, "T");
4603 }
4604
4605 #[test]
4606 fn parse_generic_type_argument() {
4607 let source = r#"
4608 record Wrapper<T> {
4609 value: T,
4610 }
4611
4612 fn make_wrapper<T>(value: T) -> Wrapper<T> {
4613 return Wrapper { value: value };
4614 }
4615
4616 agent Main {
4617 on start { yield(0); }
4618 }
4619 run Main;
4620 "#;
4621
4622 let (prog, errors) = parse_str(source);
4623 assert!(errors.is_empty(), "errors: {errors:?}");
4624 let prog = prog.expect("should parse");
4625
4626 let func = &prog.functions[0];
4627 if let TypeExpr::Named(name, type_args) = &func.return_ty {
4629 assert_eq!(name.name, "Wrapper");
4630 assert_eq!(type_args.len(), 1);
4631 if let TypeExpr::Named(inner_name, _) = &type_args[0] {
4632 assert_eq!(inner_name.name, "T");
4633 } else {
4634 panic!("expected Named type argument");
4635 }
4636 } else {
4637 panic!("expected Named return type");
4638 }
4639 }
4640
4641 #[test]
4642 fn parse_turbofish_function_call() {
4643 let source = r#"
4644 fn identity<T>(x: T) -> T {
4645 return x;
4646 }
4647
4648 agent Main {
4649 on start {
4650 let result = identity::<Int>(42);
4651 yield(0);
4652 }
4653 }
4654 run Main;
4655 "#;
4656
4657 let (prog, errors) = parse_str(source);
4658 assert!(errors.is_empty(), "errors: {errors:?}");
4659 let prog = prog.expect("should parse");
4660
4661 let handler = &prog.agents[0].handlers[0];
4662 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
4663 if let Expr::Call {
4664 name, type_args, ..
4665 } = value
4666 {
4667 assert_eq!(name.name, "identity");
4668 assert_eq!(type_args.len(), 1);
4669 assert!(matches!(type_args[0], TypeExpr::Int));
4670 } else {
4671 panic!("expected Call expression");
4672 }
4673 } else {
4674 panic!("expected Let statement");
4675 }
4676 }
4677
4678 #[test]
4679 fn parse_turbofish_multiple_type_args() {
4680 let source = r#"
4681 fn make_pair<A, B>(a: A, b: B) -> (A, B) {
4682 return (a, b);
4683 }
4684
4685 agent Main {
4686 on start {
4687 let pair = make_pair::<Int, String>(42, "hello");
4688 yield(0);
4689 }
4690 }
4691 run Main;
4692 "#;
4693
4694 let (prog, errors) = parse_str(source);
4695 assert!(errors.is_empty(), "errors: {errors:?}");
4696 let prog = prog.expect("should parse");
4697
4698 let handler = &prog.agents[0].handlers[0];
4699 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
4700 if let Expr::Call {
4701 name, type_args, ..
4702 } = value
4703 {
4704 assert_eq!(name.name, "make_pair");
4705 assert_eq!(type_args.len(), 2);
4706 assert!(matches!(type_args[0], TypeExpr::Int));
4707 assert!(matches!(type_args[1], TypeExpr::String));
4708 } else {
4709 panic!("expected Call expression");
4710 }
4711 } else {
4712 panic!("expected Let statement");
4713 }
4714 }
4715
4716 #[test]
4717 fn parse_turbofish_record_construction() {
4718 let source = r#"
4719 record Pair<A, B> {
4720 first: A,
4721 second: B,
4722 }
4723
4724 agent Main {
4725 on start {
4726 let p = Pair::<Int, String> { first: 42, second: "hi" };
4727 yield(0);
4728 }
4729 }
4730 run Main;
4731 "#;
4732
4733 let (prog, errors) = parse_str(source);
4734 assert!(errors.is_empty(), "errors: {errors:?}");
4735 let prog = prog.expect("should parse");
4736
4737 let handler = &prog.agents[0].handlers[0];
4738 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
4739 if let Expr::RecordConstruct {
4740 name, type_args, ..
4741 } = value
4742 {
4743 assert_eq!(name.name, "Pair");
4744 assert_eq!(type_args.len(), 2);
4745 assert!(matches!(type_args[0], TypeExpr::Int));
4746 assert!(matches!(type_args[1], TypeExpr::String));
4747 } else {
4748 panic!("expected RecordConstruct expression");
4749 }
4750 } else {
4751 panic!("expected Let statement");
4752 }
4753 }
4754
4755 #[test]
4756 fn parse_turbofish_variant_construction() {
4757 let source = r#"
4758 enum Either<L, R> {
4759 Left(L),
4760 Right(R),
4761 }
4762
4763 agent Main {
4764 on start {
4765 let e = Either::<String, Int>::Left("hello");
4766 yield(0);
4767 }
4768 }
4769 run Main;
4770 "#;
4771
4772 let (prog, errors) = parse_str(source);
4773 assert!(errors.is_empty(), "errors: {errors:?}");
4774 let prog = prog.expect("should parse");
4775
4776 let handler = &prog.agents[0].handlers[0];
4777 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
4778 if let Expr::VariantConstruct {
4779 enum_name,
4780 type_args,
4781 variant,
4782 ..
4783 } = value
4784 {
4785 assert_eq!(enum_name.name, "Either");
4786 assert_eq!(variant.name, "Left");
4787 assert_eq!(type_args.len(), 2);
4788 assert!(matches!(type_args[0], TypeExpr::String));
4789 assert!(matches!(type_args[1], TypeExpr::Int));
4790 } else {
4791 panic!("expected VariantConstruct expression");
4792 }
4793 } else {
4794 panic!("expected Let statement");
4795 }
4796 }
4797
4798 #[test]
4799 fn parse_generic_in_type_annotation() {
4800 let source = r#"
4801 record Page<T> {
4802 items: List<T>,
4803 count: Int,
4804 }
4805
4806 agent Main {
4807 on start {
4808 let page: Page<String> = Page { items: [], count: 0 };
4809 yield(0);
4810 }
4811 }
4812 run Main;
4813 "#;
4814
4815 let (prog, errors) = parse_str(source);
4816 assert!(errors.is_empty(), "errors: {errors:?}");
4817 let prog = prog.expect("should parse");
4818
4819 let handler = &prog.agents[0].handlers[0];
4820 if let Stmt::Let { ty: Some(ty), .. } = &handler.body.stmts[0] {
4821 if let TypeExpr::Named(name, type_args) = ty {
4822 assert_eq!(name.name, "Page");
4823 assert_eq!(type_args.len(), 1);
4824 assert!(matches!(type_args[0], TypeExpr::String));
4825 } else {
4826 panic!("expected Named type");
4827 }
4828 } else {
4829 panic!("expected Let statement with type annotation");
4830 }
4831 }
4832
4833 #[test]
4834 fn parse_nested_generic_types() {
4835 let source = r#"
4836 record Nested<T> {
4837 value: Option<List<T>>,
4838 }
4839
4840 agent Main {
4841 on start { yield(0); }
4842 }
4843 run Main;
4844 "#;
4845
4846 let (prog, errors) = parse_str(source);
4847 assert!(errors.is_empty(), "errors: {errors:?}");
4848 let prog = prog.expect("should parse");
4849
4850 let record = &prog.records[0];
4851 let field_ty = &record.fields[0].ty;
4852 if let TypeExpr::Option(inner) = field_ty {
4854 if let TypeExpr::List(elem) = inner.as_ref() {
4855 if let TypeExpr::Named(name, _) = elem.as_ref() {
4856 assert_eq!(name.name, "T");
4857 } else {
4858 panic!("expected Named type T");
4859 }
4860 } else {
4861 panic!("expected List type");
4862 }
4863 } else {
4864 panic!("expected Option type");
4865 }
4866 }
4867}