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