1use crate::ast::{
6 AgentDecl, BeliefDecl, BinOp, Block, ClosureParam, ConstDecl, ElseBranch, EnumDecl, EventKind,
7 Expr, FieldInit, FnDecl, HandlerDecl, Literal, MapEntry, MatchArm, ModDecl, Param, Pattern,
8 Program, RecordDecl, RecordField, Stmt, StringPart, StringTemplate, UnaryOp, UseDecl, UseKind,
9};
10use chumsky::prelude::*;
11use chumsky::BoxedParser;
12use sage_lexer::{Spanned, Token};
13use sage_types::{Ident, Span, TypeExpr};
14use std::ops::Range;
15use std::sync::Arc;
16
17pub type ParseError = Simple<Token>;
19
20#[must_use]
26#[allow(clippy::needless_pass_by_value)] pub fn parse(tokens: &[Spanned], source: Arc<str>) -> (Option<Program>, Vec<ParseError>) {
28 let len = source.len();
29
30 let token_spans: Vec<(Token, Range<usize>)> = tokens
32 .iter()
33 .map(|s| (s.token.clone(), s.start..s.end))
34 .collect();
35
36 let stream = chumsky::Stream::from_iter(len..len, token_spans.into_iter());
37
38 let (ast, errors) = program_parser(Arc::clone(&source)).parse_recovery(stream);
39
40 (ast, errors)
41}
42
43#[allow(clippy::needless_pass_by_value)]
49fn program_parser(source: Arc<str>) -> impl Parser<Token, Program, Error = ParseError> {
50 let src = source.clone();
51 let src2 = source.clone();
52
53 let top_level = mod_parser(source.clone())
55 .or(use_parser(source.clone()))
56 .or(record_parser(source.clone()))
57 .or(enum_parser(source.clone()))
58 .or(const_parser(source.clone()))
59 .or(agent_parser(source.clone()))
60 .or(fn_parser(source.clone()))
61 .recover_with(skip_then_retry_until([
62 Token::KwMod,
63 Token::KwUse,
64 Token::KwPub,
65 Token::KwRecord,
66 Token::KwEnum,
67 Token::KwConst,
68 Token::KwAgent,
69 Token::KwFn,
70 Token::KwRun,
71 ]));
72
73 let run_stmt = just(Token::KwRun)
74 .ignore_then(ident_token_parser(src.clone()))
75 .then_ignore(just(Token::Semicolon))
76 .or_not();
77
78 top_level.repeated().then(run_stmt).map_with_span(
79 move |(items, run_agent), span: Range<usize>| {
80 let mut mod_decls = Vec::new();
81 let mut use_decls = Vec::new();
82 let mut records = Vec::new();
83 let mut enums = Vec::new();
84 let mut consts = Vec::new();
85 let mut agents = Vec::new();
86 let mut functions = Vec::new();
87
88 for item in items {
89 match item {
90 TopLevel::Mod(m) => mod_decls.push(m),
91 TopLevel::Use(u) => use_decls.push(u),
92 TopLevel::Record(r) => records.push(r),
93 TopLevel::Enum(e) => enums.push(e),
94 TopLevel::Const(c) => consts.push(c),
95 TopLevel::Agent(a) => agents.push(a),
96 TopLevel::Function(f) => functions.push(f),
97 }
98 }
99
100 Program {
101 mod_decls,
102 use_decls,
103 records,
104 enums,
105 consts,
106 agents,
107 functions,
108 run_agent,
109 span: make_span(&src2, span),
110 }
111 },
112 )
113}
114
115enum TopLevel {
117 Mod(ModDecl),
118 Use(UseDecl),
119 Record(RecordDecl),
120 Enum(EnumDecl),
121 Const(ConstDecl),
122 Agent(AgentDecl),
123 Function(FnDecl),
124}
125
126#[allow(clippy::needless_pass_by_value)]
132fn mod_parser(source: Arc<str>) -> impl Parser<Token, TopLevel, Error = ParseError> {
133 let src = source.clone();
134
135 just(Token::KwPub)
136 .or_not()
137 .then_ignore(just(Token::KwMod))
138 .then(ident_token_parser(src.clone()))
139 .then_ignore(just(Token::Semicolon))
140 .map_with_span(move |(is_pub, name), span: Range<usize>| {
141 TopLevel::Mod(ModDecl {
142 is_pub: is_pub.is_some(),
143 name,
144 span: make_span(&src, span),
145 })
146 })
147}
148
149#[allow(clippy::needless_pass_by_value)]
151fn use_parser(source: Arc<str>) -> impl Parser<Token, TopLevel, Error = ParseError> {
152 let src = source.clone();
153 let src2 = source.clone();
154 let src3 = source.clone();
155 let src4 = source.clone();
156
157 let simple_use = just(Token::KwPub)
159 .or_not()
160 .then_ignore(just(Token::KwUse))
161 .then(
162 ident_token_parser(src.clone())
163 .separated_by(just(Token::ColonColon))
164 .at_least(1),
165 )
166 .then(
167 just(Token::KwAs)
168 .ignore_then(ident_token_parser(src.clone()))
169 .or_not(),
170 )
171 .then_ignore(just(Token::Semicolon))
172 .map_with_span(move |((is_pub, path), alias), span: Range<usize>| {
173 TopLevel::Use(UseDecl {
174 is_pub: is_pub.is_some(),
175 path,
176 kind: UseKind::Simple(alias),
177 span: make_span(&src, span),
178 })
179 });
180
181 let group_item = ident_token_parser(src2.clone()).then(
183 just(Token::KwAs)
184 .ignore_then(ident_token_parser(src2.clone()))
185 .or_not(),
186 );
187
188 let group_use = just(Token::KwPub)
190 .or_not()
191 .then_ignore(just(Token::KwUse))
192 .then(
193 ident_token_parser(src3.clone())
194 .then_ignore(just(Token::ColonColon))
195 .repeated()
196 .at_least(1),
197 )
198 .then(
199 group_item
200 .separated_by(just(Token::Comma))
201 .allow_trailing()
202 .delimited_by(just(Token::LBrace), just(Token::RBrace)),
203 )
204 .then_ignore(just(Token::Semicolon))
205 .map_with_span(move |((is_pub, path), items), span: Range<usize>| {
206 TopLevel::Use(UseDecl {
207 is_pub: is_pub.is_some(),
208 path,
209 kind: UseKind::Group(items),
210 span: make_span(&src3, span),
211 })
212 });
213
214 let glob_use = just(Token::KwPub)
216 .or_not()
217 .then_ignore(just(Token::KwUse))
218 .then(
219 ident_token_parser(src4.clone())
220 .then_ignore(just(Token::ColonColon))
221 .repeated()
222 .at_least(1),
223 )
224 .then_ignore(just(Token::Star))
225 .then_ignore(just(Token::Semicolon))
226 .map_with_span(move |(is_pub, path), span: Range<usize>| {
227 TopLevel::Use(UseDecl {
228 is_pub: is_pub.is_some(),
229 path,
230 kind: UseKind::Glob,
231 span: make_span(&src4, span),
232 })
233 });
234
235 group_use.or(glob_use).or(simple_use)
237}
238
239#[allow(clippy::needless_pass_by_value)]
245fn record_parser(source: Arc<str>) -> impl Parser<Token, TopLevel, Error = ParseError> {
246 let src = source.clone();
247 let src2 = source.clone();
248
249 let field = ident_token_parser(src.clone())
251 .then_ignore(just(Token::Colon))
252 .then(type_parser(src.clone()))
253 .map_with_span(move |(name, ty), span: Range<usize>| RecordField {
254 name,
255 ty,
256 span: make_span(&src, span),
257 });
258
259 just(Token::KwPub)
260 .or_not()
261 .then_ignore(just(Token::KwRecord))
262 .then(ident_token_parser(src2.clone()))
263 .then(
264 field
265 .separated_by(just(Token::Comma))
266 .allow_trailing()
267 .delimited_by(just(Token::LBrace), just(Token::RBrace)),
268 )
269 .map_with_span(move |((is_pub, name), fields), span: Range<usize>| {
270 TopLevel::Record(RecordDecl {
271 is_pub: is_pub.is_some(),
272 name,
273 fields,
274 span: make_span(&src2, span),
275 })
276 })
277}
278
279#[allow(clippy::needless_pass_by_value)]
281fn enum_parser(source: Arc<str>) -> impl Parser<Token, TopLevel, Error = ParseError> {
282 let src = source.clone();
283 let src2 = source.clone();
284 let src3 = source.clone();
285
286 let variant = ident_token_parser(src.clone())
288 .then(
289 type_parser(src.clone())
290 .delimited_by(just(Token::LParen), just(Token::RParen))
291 .or_not(),
292 )
293 .map_with_span({
294 let src = src.clone();
295 move |(name, payload), span: Range<usize>| crate::ast::EnumVariant {
296 name,
297 payload,
298 span: make_span(&src, span),
299 }
300 });
301
302 just(Token::KwPub)
303 .or_not()
304 .then_ignore(just(Token::KwEnum))
305 .then(ident_token_parser(src3.clone()))
306 .then(
307 variant
308 .separated_by(just(Token::Comma))
309 .allow_trailing()
310 .delimited_by(just(Token::LBrace), just(Token::RBrace)),
311 )
312 .map_with_span(move |((is_pub, name), variants), span: Range<usize>| {
313 TopLevel::Enum(EnumDecl {
314 is_pub: is_pub.is_some(),
315 name,
316 variants,
317 span: make_span(&src2, span),
318 })
319 })
320}
321
322#[allow(clippy::needless_pass_by_value)]
324fn const_parser(source: Arc<str>) -> impl Parser<Token, TopLevel, Error = ParseError> {
325 let src = source.clone();
326 let src2 = source.clone();
327
328 just(Token::KwPub)
329 .or_not()
330 .then_ignore(just(Token::KwConst))
331 .then(ident_token_parser(src.clone()))
332 .then_ignore(just(Token::Colon))
333 .then(type_parser(src.clone()))
334 .then_ignore(just(Token::Eq))
335 .then(expr_parser(src.clone()))
336 .then_ignore(just(Token::Semicolon))
337 .map_with_span(move |(((is_pub, name), ty), value), span: Range<usize>| {
338 TopLevel::Const(ConstDecl {
339 is_pub: is_pub.is_some(),
340 name,
341 ty,
342 value,
343 span: make_span(&src2, span),
344 })
345 })
346}
347
348#[allow(clippy::needless_pass_by_value)]
354fn agent_parser(source: Arc<str>) -> impl Parser<Token, TopLevel, Error = ParseError> {
355 let src = source.clone();
356 let src2 = source.clone();
357 let src3 = source.clone();
358 let src4 = source.clone();
359
360 let belief = ident_token_parser(src.clone())
363 .then_ignore(just(Token::Colon))
364 .then(type_parser(src.clone()))
365 .map_with_span(move |(name, ty), span: Range<usize>| BeliefDecl {
366 name,
367 ty,
368 span: make_span(&src, span),
369 });
370
371 let handler = just(Token::KwOn)
372 .ignore_then(event_kind_parser(src2.clone()))
373 .then(block_parser(src2.clone()))
374 .map_with_span(move |(event, body), span: Range<usize>| HandlerDecl {
375 event,
376 body,
377 span: make_span(&src2, span),
378 });
379
380 let receives_clause = just(Token::KwReceives)
382 .ignore_then(type_parser(src3.clone()))
383 .or_not();
384
385 just(Token::KwPub)
386 .or_not()
387 .then_ignore(just(Token::KwAgent))
388 .then(ident_token_parser(src3.clone()))
389 .then(receives_clause)
390 .then_ignore(just(Token::LBrace))
391 .then(belief.repeated())
392 .then(handler.repeated())
393 .then_ignore(just(Token::RBrace))
394 .map_with_span(
395 move |((((is_pub, name), receives), beliefs), handlers), span: Range<usize>| {
396 TopLevel::Agent(AgentDecl {
397 is_pub: is_pub.is_some(),
398 name,
399 receives,
400 beliefs,
401 handlers,
402 span: make_span(&src4, span),
403 })
404 },
405 )
406}
407
408#[allow(clippy::needless_pass_by_value)]
410fn event_kind_parser(source: Arc<str>) -> impl Parser<Token, EventKind, Error = ParseError> {
411 let src = source.clone();
412
413 let start = just(Token::KwStart).to(EventKind::Start);
414 let stop = just(Token::KwStop).to(EventKind::Stop);
415
416 let message = just(Token::KwMessage)
417 .ignore_then(just(Token::LParen))
418 .ignore_then(ident_token_parser(src.clone()))
419 .then_ignore(just(Token::Colon))
420 .then(type_parser(src.clone()))
421 .then_ignore(just(Token::RParen))
422 .map(|(param_name, param_ty)| EventKind::Message {
423 param_name,
424 param_ty,
425 });
426
427 let error = just(Token::KwError)
429 .ignore_then(just(Token::LParen))
430 .ignore_then(ident_token_parser(src))
431 .then_ignore(just(Token::RParen))
432 .map(|param_name| EventKind::Error { param_name });
433
434 start.or(stop).or(message).or(error)
435}
436
437#[allow(clippy::needless_pass_by_value)]
443fn fn_parser(source: Arc<str>) -> impl Parser<Token, TopLevel, Error = ParseError> {
444 let src = source.clone();
445 let src2 = source.clone();
446 let src3 = source.clone();
447
448 let param = ident_token_parser(src.clone())
449 .then_ignore(just(Token::Colon))
450 .then(type_parser(src.clone()))
451 .map_with_span(move |(name, ty), span: Range<usize>| Param {
452 name,
453 ty,
454 span: make_span(&src, span),
455 });
456
457 let params = param
458 .separated_by(just(Token::Comma))
459 .allow_trailing()
460 .delimited_by(just(Token::LParen), just(Token::RParen));
461
462 just(Token::KwPub)
463 .or_not()
464 .then_ignore(just(Token::KwFn))
465 .then(ident_token_parser(src2.clone()))
466 .then(params)
467 .then_ignore(just(Token::Arrow))
468 .then(type_parser(src2.clone()))
469 .then(just(Token::KwFails).or_not())
470 .then(block_parser(src2))
471 .map_with_span(
472 move |(((((is_pub, name), params), return_ty), is_fallible), body),
473 span: Range<usize>| {
474 TopLevel::Function(FnDecl {
475 is_pub: is_pub.is_some(),
476 name,
477 params,
478 return_ty,
479 is_fallible: is_fallible.is_some(),
480 body,
481 span: make_span(&src3, span),
482 })
483 },
484 )
485}
486
487#[allow(clippy::needless_pass_by_value)]
494fn block_parser(source: Arc<str>) -> BoxedParser<'static, Token, Block, ParseError> {
495 let src = source.clone();
496
497 recursive(move |block: Recursive<Token, Block, ParseError>| {
498 let src_inner = src.clone();
499 stmt_parser(src.clone(), block)
500 .repeated()
501 .delimited_by(just(Token::LBrace), just(Token::RBrace))
502 .recover_with(nested_delimiters(
503 Token::LBrace,
504 Token::RBrace,
505 [
506 (Token::LParen, Token::RParen),
507 (Token::LBracket, Token::RBracket),
508 ],
509 |_span: Range<usize>| vec![],
510 ))
511 .map_with_span(move |stmts, span: Range<usize>| Block {
512 stmts,
513 span: make_span(&src_inner, span),
514 })
515 })
516 .boxed()
517}
518
519#[allow(clippy::needless_pass_by_value)]
521fn stmt_parser(
522 source: Arc<str>,
523 block: impl Parser<Token, Block, Error = ParseError> + Clone + 'static,
524) -> impl Parser<Token, Stmt, Error = ParseError> + Clone {
525 let src = source.clone();
526 let src2 = source.clone();
527 let src3 = source.clone();
528 let src4 = source.clone();
529 let src5 = source.clone();
530 let src6 = source.clone();
531 let src7 = source.clone();
532
533 let src10 = source.clone();
535 let let_tuple_stmt = just(Token::KwLet)
536 .ignore_then(
537 ident_token_parser(src10.clone())
538 .separated_by(just(Token::Comma))
539 .at_least(2)
540 .allow_trailing()
541 .delimited_by(just(Token::LParen), just(Token::RParen)),
542 )
543 .then(
544 just(Token::Colon)
545 .ignore_then(type_parser(src10.clone()))
546 .or_not(),
547 )
548 .then_ignore(just(Token::Eq))
549 .then(expr_parser(src10.clone()))
550 .then_ignore(just(Token::Semicolon))
551 .map_with_span(move |((names, ty), value), span: Range<usize>| Stmt::LetTuple {
552 names,
553 ty,
554 value,
555 span: make_span(&src10, span),
556 });
557
558 let let_stmt = just(Token::KwLet)
559 .ignore_then(ident_token_parser(src.clone()))
560 .then(
561 just(Token::Colon)
562 .ignore_then(type_parser(src.clone()))
563 .or_not(),
564 )
565 .then_ignore(just(Token::Eq))
566 .then(expr_parser(src.clone()))
567 .then_ignore(just(Token::Semicolon))
568 .map_with_span(move |((name, ty), value), span: Range<usize>| Stmt::Let {
569 name,
570 ty,
571 value,
572 span: make_span(&src, span),
573 });
574
575 let return_stmt = just(Token::KwReturn)
576 .ignore_then(expr_parser(src2.clone()).or_not())
577 .then_ignore(just(Token::Semicolon))
578 .map_with_span(move |value, span: Range<usize>| Stmt::Return {
579 value,
580 span: make_span(&src2, span),
581 });
582
583 let if_stmt = recursive(|if_stmt| {
584 let src_if = src3.clone();
585 let block_clone = block.clone();
586
587 just(Token::KwIf)
588 .ignore_then(expr_parser(src3.clone()))
589 .then(block_clone.clone())
590 .then(
591 just(Token::KwElse)
592 .ignore_then(
593 if_stmt
594 .map(|s| ElseBranch::ElseIf(Box::new(s)))
595 .or(block_clone.map(ElseBranch::Block)),
596 )
597 .or_not(),
598 )
599 .map_with_span(
600 move |((condition, then_block), else_block), span: Range<usize>| Stmt::If {
601 condition,
602 then_block,
603 else_block,
604 span: make_span(&src_if, span),
605 },
606 )
607 });
608
609 let for_stmt = just(Token::KwFor)
610 .ignore_then(for_pattern_parser(src4.clone()))
611 .then_ignore(just(Token::KwIn))
612 .then(expr_parser(src4.clone()))
613 .then(block.clone())
614 .map_with_span(move |((pattern, iter), body), span: Range<usize>| Stmt::For {
615 pattern,
616 iter,
617 body,
618 span: make_span(&src4, span),
619 });
620
621 let while_stmt = just(Token::KwWhile)
622 .ignore_then(expr_parser(src7.clone()))
623 .then(block.clone())
624 .map_with_span(move |(condition, body), span: Range<usize>| Stmt::While {
625 condition,
626 body,
627 span: make_span(&src7, span),
628 });
629
630 let src8 = source.clone();
631 let loop_stmt = just(Token::KwLoop)
632 .ignore_then(block.clone())
633 .map_with_span(move |body, span: Range<usize>| Stmt::Loop {
634 body,
635 span: make_span(&src8, span),
636 });
637
638 let src9 = source.clone();
639 let break_stmt = just(Token::KwBreak)
640 .then_ignore(just(Token::Semicolon))
641 .map_with_span(move |_, span: Range<usize>| Stmt::Break {
642 span: make_span(&src9, span),
643 });
644
645 let assign_stmt = ident_token_parser(src5.clone())
646 .then_ignore(just(Token::Eq))
647 .then(expr_parser(src5.clone()))
648 .then_ignore(just(Token::Semicolon))
649 .map_with_span(move |(name, value), span: Range<usize>| Stmt::Assign {
650 name,
651 value,
652 span: make_span(&src5, span),
653 });
654
655 let expr_stmt = expr_parser(src6.clone())
656 .then_ignore(just(Token::Semicolon))
657 .map_with_span(move |expr, span: Range<usize>| Stmt::Expr {
658 expr,
659 span: make_span(&src6, span),
660 });
661
662 let_tuple_stmt
663 .or(let_stmt)
664 .or(return_stmt)
665 .or(if_stmt)
666 .or(for_stmt)
667 .or(while_stmt)
668 .or(loop_stmt)
669 .or(break_stmt)
670 .or(assign_stmt)
671 .or(expr_stmt)
672}
673
674#[allow(clippy::needless_pass_by_value, clippy::too_many_lines)]
681fn expr_parser(source: Arc<str>) -> BoxedParser<'static, Token, Expr, ParseError> {
682 recursive(move |expr: Recursive<Token, Expr, ParseError>| {
683 let src = source.clone();
684
685 let literal = literal_parser(src.clone());
686 let var = var_parser(src.clone());
687
688 let paren_or_tuple = just(Token::LParen)
691 .ignore_then(
692 expr.clone()
693 .separated_by(just(Token::Comma))
694 .allow_trailing(),
695 )
696 .then_ignore(just(Token::RParen))
697 .map_with_span({
698 let src = src.clone();
699 move |elements, span: Range<usize>| {
700 if elements.len() == 1 {
701 Expr::Paren {
703 inner: Box::new(elements.into_iter().next().unwrap()),
704 span: make_span(&src, span),
705 }
706 } else {
707 Expr::Tuple {
709 elements,
710 span: make_span(&src, span),
711 }
712 }
713 }
714 });
715
716 let list = expr
717 .clone()
718 .separated_by(just(Token::Comma))
719 .allow_trailing()
720 .delimited_by(just(Token::LBracket), just(Token::RBracket))
721 .map_with_span({
722 let src = src.clone();
723 move |elements, span: Range<usize>| Expr::List {
724 elements,
725 span: make_span(&src, span),
726 }
727 });
728
729 let self_access = just(Token::KwSelf)
731 .ignore_then(just(Token::Dot))
732 .ignore_then(ident_token_parser(src.clone()))
733 .then(
734 expr.clone()
735 .separated_by(just(Token::Comma))
736 .allow_trailing()
737 .delimited_by(just(Token::LParen), just(Token::RParen))
738 .or_not(),
739 )
740 .map_with_span({
741 let src = src.clone();
742 move |(field, args), span: Range<usize>| match args {
743 Some(args) => Expr::SelfMethodCall {
744 method: field,
745 args,
746 span: make_span(&src, span),
747 },
748 None => Expr::SelfField {
749 field,
750 span: make_span(&src, span),
751 },
752 }
753 });
754
755 let infer_expr = just(Token::KwInfer)
757 .ignore_then(just(Token::LParen))
758 .ignore_then(string_template_parser(src.clone()))
759 .then(
760 just(Token::Arrow)
761 .ignore_then(type_parser(src.clone()))
762 .or_not(),
763 )
764 .then_ignore(just(Token::RParen))
765 .map_with_span({
766 let src = src.clone();
767 move |(template, result_ty), span: Range<usize>| Expr::Infer {
768 template,
769 result_ty,
770 span: make_span(&src, span),
771 }
772 });
773
774 let spawn_field_init = ident_token_parser(src.clone())
776 .then_ignore(just(Token::Colon))
777 .then(expr.clone())
778 .map_with_span({
779 let src = src.clone();
780 move |(name, value), span: Range<usize>| FieldInit {
781 name,
782 value,
783 span: make_span(&src, span),
784 }
785 });
786
787 let spawn_expr = just(Token::KwSpawn)
788 .ignore_then(ident_token_parser(src.clone()))
789 .then_ignore(just(Token::LBrace))
790 .then(
791 spawn_field_init
792 .separated_by(just(Token::Comma))
793 .allow_trailing(),
794 )
795 .then_ignore(just(Token::RBrace))
796 .map_with_span({
797 let src = src.clone();
798 move |(agent, fields), span: Range<usize>| Expr::Spawn {
799 agent,
800 fields,
801 span: make_span(&src, span),
802 }
803 });
804
805 let await_expr = just(Token::KwAwait)
807 .ignore_then(ident_token_parser(src.clone()).map_with_span({
808 let src = src.clone();
809 move |name, span: Range<usize>| Expr::Var {
810 name,
811 span: make_span(&src, span),
812 }
813 }))
814 .map_with_span({
815 let src = src.clone();
816 move |handle, span: Range<usize>| Expr::Await {
817 handle: Box::new(handle),
818 span: make_span(&src, span),
819 }
820 });
821
822 let send_expr = just(Token::KwSend)
824 .ignore_then(just(Token::LParen))
825 .ignore_then(expr.clone())
826 .then_ignore(just(Token::Comma))
827 .then(expr.clone())
828 .then_ignore(just(Token::RParen))
829 .map_with_span({
830 let src = src.clone();
831 move |(handle, message), span: Range<usize>| Expr::Send {
832 handle: Box::new(handle),
833 message: Box::new(message),
834 span: make_span(&src, span),
835 }
836 });
837
838 let emit_expr = just(Token::KwEmit)
840 .ignore_then(just(Token::LParen))
841 .ignore_then(expr.clone())
842 .then_ignore(just(Token::RParen))
843 .map_with_span({
844 let src = src.clone();
845 move |value, span: Range<usize>| Expr::Emit {
846 value: Box::new(value),
847 span: make_span(&src, span),
848 }
849 });
850
851 let call_expr = ident_token_parser(src.clone())
853 .then(
854 expr.clone()
855 .separated_by(just(Token::Comma))
856 .allow_trailing()
857 .delimited_by(just(Token::LParen), just(Token::RParen)),
858 )
859 .map_with_span({
860 let src = src.clone();
861 move |(name, args), span: Range<usize>| Expr::Call {
862 name,
863 args,
864 span: make_span(&src, span),
865 }
866 });
867
868 let pattern = pattern_parser(src.clone());
870
871 let match_arm = pattern
873 .then_ignore(just(Token::FatArrow))
874 .then(expr.clone())
875 .map_with_span({
876 let src = src.clone();
877 move |(pattern, body), span: Range<usize>| MatchArm {
878 pattern,
879 body,
880 span: make_span(&src, span),
881 }
882 });
883
884 let match_expr = just(Token::KwMatch)
885 .ignore_then(expr.clone())
886 .then(
887 match_arm
888 .separated_by(just(Token::Comma))
889 .allow_trailing()
890 .delimited_by(just(Token::LBrace), just(Token::RBrace)),
891 )
892 .map_with_span({
893 let src = src.clone();
894 move |(scrutinee, arms), span: Range<usize>| Expr::Match {
895 scrutinee: Box::new(scrutinee),
896 arms,
897 span: make_span(&src, span),
898 }
899 });
900
901 let receive_expr = just(Token::KwReceive)
903 .ignore_then(just(Token::LParen))
904 .ignore_then(just(Token::RParen))
905 .map_with_span({
906 let src = src.clone();
907 move |_, span: Range<usize>| Expr::Receive {
908 span: make_span(&src, span),
909 }
910 });
911
912 let record_field_init = ident_token_parser(src.clone())
916 .then_ignore(just(Token::Colon))
917 .then(expr.clone())
918 .map_with_span({
919 let src = src.clone();
920 move |(name, value), span: Range<usize>| FieldInit {
921 name,
922 value,
923 span: make_span(&src, span),
924 }
925 });
926
927 let record_construct = ident_token_parser(src.clone())
928 .then_ignore(just(Token::LBrace))
929 .then(
930 record_field_init
931 .separated_by(just(Token::Comma))
932 .allow_trailing(),
933 )
934 .then_ignore(just(Token::RBrace))
935 .map_with_span({
936 let src = src.clone();
937 move |(name, fields), span: Range<usize>| Expr::RecordConstruct {
938 name,
939 fields,
940 span: make_span(&src, span),
941 }
942 });
943
944 let closure_param = ident_token_parser(src.clone())
946 .then(just(Token::Colon).ignore_then(type_parser(src.clone())).or_not())
947 .map_with_span({
948 let src = src.clone();
949 move |(name, ty), span: Range<usize>| ClosureParam {
950 name,
951 ty,
952 span: make_span(&src, span),
953 }
954 });
955
956 let closure_empty = just(Token::Or)
959 .ignore_then(expr.clone())
960 .map_with_span({
961 let src = src.clone();
962 move |body, span: Range<usize>| Expr::Closure {
963 params: vec![],
964 body: Box::new(body),
965 span: make_span(&src, span),
966 }
967 });
968
969 let closure_with_params = just(Token::Pipe)
970 .ignore_then(
971 closure_param
972 .separated_by(just(Token::Comma))
973 .allow_trailing(),
974 )
975 .then_ignore(just(Token::Pipe))
976 .then(expr.clone())
977 .map_with_span({
978 let src = src.clone();
979 move |(params, body), span: Range<usize>| Expr::Closure {
980 params,
981 body: Box::new(body),
982 span: make_span(&src, span),
983 }
984 });
985
986 let closure = closure_with_params.or(closure_empty);
987
988 let map_entry = expr
991 .clone()
992 .then_ignore(just(Token::Colon))
993 .then(expr.clone())
994 .map_with_span({
995 let src = src.clone();
996 move |(key, value), span: Range<usize>| MapEntry {
997 key,
998 value,
999 span: make_span(&src, span),
1000 }
1001 });
1002
1003 let map_literal = map_entry
1004 .separated_by(just(Token::Comma))
1005 .allow_trailing()
1006 .delimited_by(just(Token::LBrace), just(Token::RBrace))
1007 .map_with_span({
1008 let src = src.clone();
1009 move |entries, span: Range<usize>| Expr::Map {
1010 entries,
1011 span: make_span(&src, span),
1012 }
1013 });
1014
1015 let variant_construct = ident_token_parser(src.clone())
1017 .then_ignore(just(Token::ColonColon))
1018 .then(ident_token_parser(src.clone()))
1019 .then(
1020 expr.clone()
1021 .delimited_by(just(Token::LParen), just(Token::RParen))
1022 .or_not(),
1023 )
1024 .map_with_span({
1025 let src = src.clone();
1026 move |((enum_name, variant), payload), span: Range<usize>| Expr::VariantConstruct {
1027 enum_name,
1028 variant,
1029 payload: payload.map(Box::new),
1030 span: make_span(&src, span),
1031 }
1032 });
1033
1034 let atom = closure
1042 .or(infer_expr)
1043 .or(spawn_expr)
1044 .or(await_expr)
1045 .or(send_expr)
1046 .or(emit_expr)
1047 .or(receive_expr)
1048 .or(match_expr)
1049 .or(self_access)
1050 .or(record_construct)
1051 .or(variant_construct)
1052 .or(call_expr)
1053 .or(map_literal)
1054 .or(list)
1055 .or(paren_or_tuple)
1056 .or(literal)
1057 .or(var)
1058 .boxed();
1059
1060 enum PostfixOp {
1063 Field(Ident),
1064 TupleIndex(usize, Range<usize>),
1065 }
1066
1067 let postfix_op = just(Token::Dot).ignore_then(
1068 filter_map({
1070 let src = src.clone();
1071 move |span: Range<usize>, token| match token {
1072 Token::IntLit => {
1073 let text = &src[span.start..span.end];
1074 text.parse::<usize>()
1075 .map(|idx| PostfixOp::TupleIndex(idx, span.clone()))
1076 .map_err(|_| Simple::custom(span, "invalid tuple index"))
1077 }
1078 _ => Err(Simple::expected_input_found(
1079 span,
1080 vec![Some(Token::IntLit)],
1081 Some(token),
1082 )),
1083 }
1084 })
1085 .or(ident_token_parser(src.clone()).map(PostfixOp::Field)),
1086 );
1087
1088 let postfix = atom
1089 .then(postfix_op.repeated())
1090 .foldl({
1091 let src = src.clone();
1092 move |object, op| match op {
1093 PostfixOp::Field(field) => {
1094 let span = make_span(&src, object.span().start..field.span.end);
1095 Expr::FieldAccess {
1096 object: Box::new(object),
1097 field,
1098 span,
1099 }
1100 }
1101 PostfixOp::TupleIndex(index, idx_span) => {
1102 let span = make_span(&src, object.span().start..idx_span.end);
1103 Expr::TupleIndex {
1104 tuple: Box::new(object),
1105 index,
1106 span,
1107 }
1108 }
1109 }
1110 })
1111 .boxed();
1112
1113 let unary = just(Token::Minus)
1115 .to(UnaryOp::Neg)
1116 .or(just(Token::Bang).to(UnaryOp::Not))
1117 .repeated()
1118 .then(postfix.clone())
1119 .foldr(|op, operand| {
1120 let span = operand.span().clone();
1121 Expr::Unary {
1122 op,
1123 operand: Box::new(operand),
1124 span,
1125 }
1126 })
1127 .boxed();
1128
1129 let try_expr = just(Token::KwTry)
1132 .ignore_then(postfix)
1133 .map_with_span({
1134 let src = src.clone();
1135 move |inner, span: Range<usize>| Expr::Try {
1136 expr: Box::new(inner),
1137 span: make_span(&src, span),
1138 }
1139 })
1140 .boxed();
1141
1142 let unary = try_expr.or(unary).boxed();
1144
1145 let mul_div_op = just(Token::Star)
1148 .to(BinOp::Mul)
1149 .or(just(Token::Slash).to(BinOp::Div));
1150
1151 let mul_div = unary
1152 .clone()
1153 .then(mul_div_op.then(unary.clone()).repeated())
1154 .foldl({
1155 let src = src.clone();
1156 move |left, (op, right)| {
1157 let span = make_span(&src, left.span().start..right.span().end);
1158 Expr::Binary {
1159 op,
1160 left: Box::new(left),
1161 right: Box::new(right),
1162 span,
1163 }
1164 }
1165 })
1166 .boxed();
1167
1168 let add_sub_op = just(Token::Plus)
1170 .to(BinOp::Add)
1171 .or(just(Token::Minus).to(BinOp::Sub));
1172
1173 let add_sub = mul_div
1174 .clone()
1175 .then(add_sub_op.then(mul_div).repeated())
1176 .foldl({
1177 let src = src.clone();
1178 move |left, (op, right)| {
1179 let span = make_span(&src, left.span().start..right.span().end);
1180 Expr::Binary {
1181 op,
1182 left: Box::new(left),
1183 right: Box::new(right),
1184 span,
1185 }
1186 }
1187 })
1188 .boxed();
1189
1190 let concat_op = just(Token::PlusPlus).to(BinOp::Concat);
1192
1193 let concat = add_sub
1194 .clone()
1195 .then(concat_op.then(add_sub).repeated())
1196 .foldl({
1197 let src = src.clone();
1198 move |left, (op, right)| {
1199 let span = make_span(&src, left.span().start..right.span().end);
1200 Expr::Binary {
1201 op,
1202 left: Box::new(left),
1203 right: Box::new(right),
1204 span,
1205 }
1206 }
1207 })
1208 .boxed();
1209
1210 let cmp_op = choice((
1212 just(Token::Le).to(BinOp::Le),
1213 just(Token::Ge).to(BinOp::Ge),
1214 just(Token::Lt).to(BinOp::Lt),
1215 just(Token::Gt).to(BinOp::Gt),
1216 ));
1217
1218 let comparison = concat
1219 .clone()
1220 .then(cmp_op.then(concat).repeated())
1221 .foldl({
1222 let src = src.clone();
1223 move |left, (op, right)| {
1224 let span = make_span(&src, left.span().start..right.span().end);
1225 Expr::Binary {
1226 op,
1227 left: Box::new(left),
1228 right: Box::new(right),
1229 span,
1230 }
1231 }
1232 })
1233 .boxed();
1234
1235 let eq_op = just(Token::EqEq)
1237 .to(BinOp::Eq)
1238 .or(just(Token::Ne).to(BinOp::Ne));
1239
1240 let equality = comparison
1241 .clone()
1242 .then(eq_op.then(comparison).repeated())
1243 .foldl({
1244 let src = src.clone();
1245 move |left, (op, right)| {
1246 let span = make_span(&src, left.span().start..right.span().end);
1247 Expr::Binary {
1248 op,
1249 left: Box::new(left),
1250 right: Box::new(right),
1251 span,
1252 }
1253 }
1254 })
1255 .boxed();
1256
1257 let and_op = just(Token::And).to(BinOp::And);
1259
1260 let and = equality
1261 .clone()
1262 .then(and_op.then(equality).repeated())
1263 .foldl({
1264 let src = src.clone();
1265 move |left, (op, right)| {
1266 let span = make_span(&src, left.span().start..right.span().end);
1267 Expr::Binary {
1268 op,
1269 left: Box::new(left),
1270 right: Box::new(right),
1271 span,
1272 }
1273 }
1274 })
1275 .boxed();
1276
1277 let or_op = just(Token::Or).to(BinOp::Or);
1279
1280 let or_expr = and.clone().then(or_op.then(and).repeated()).foldl({
1281 let src = src.clone();
1282 move |left, (op, right)| {
1283 let span = make_span(&src, left.span().start..right.span().end);
1284 Expr::Binary {
1285 op,
1286 left: Box::new(left),
1287 right: Box::new(right),
1288 span,
1289 }
1290 }
1291 });
1292
1293 let catch_recovery = just(Token::KwCatch)
1296 .ignore_then(
1297 ident_token_parser(src.clone())
1298 .delimited_by(just(Token::LParen), just(Token::RParen))
1299 .or_not(),
1300 )
1301 .then(
1302 expr.clone()
1303 .delimited_by(just(Token::LBrace), just(Token::RBrace)),
1304 );
1305
1306 or_expr.then(catch_recovery.or_not()).map_with_span({
1307 let src = src.clone();
1308 move |(inner, catch_opt), span: Range<usize>| match catch_opt {
1309 Some((error_bind, recovery)) => Expr::Catch {
1310 expr: Box::new(inner),
1311 error_bind,
1312 recovery: Box::new(recovery),
1313 span: make_span(&src, span),
1314 },
1315 None => inner,
1316 }
1317 })
1318 })
1319 .boxed()
1320}
1321
1322fn make_span(source: &Arc<str>, range: Range<usize>) -> Span {
1328 Span::new(range.start, range.end, Arc::clone(source))
1329}
1330
1331fn ident_token_parser(source: Arc<str>) -> impl Parser<Token, Ident, Error = ParseError> + Clone {
1333 filter_map(move |span: Range<usize>, token| match token {
1334 Token::Ident => {
1335 let text = &source[span.start..span.end];
1336 Ok(Ident::new(text.to_string(), make_span(&source, span)))
1337 }
1338 _ => Err(Simple::expected_input_found(
1339 span,
1340 vec![Some(Token::Ident)],
1341 Some(token),
1342 )),
1343 })
1344}
1345
1346fn var_parser(source: Arc<str>) -> impl Parser<Token, Expr, Error = ParseError> + Clone {
1348 ident_token_parser(source.clone()).map_with_span(move |name, span: Range<usize>| Expr::Var {
1349 name,
1350 span: make_span(&source, span),
1351 })
1352}
1353
1354fn type_parser(source: Arc<str>) -> impl Parser<Token, TypeExpr, Error = ParseError> + Clone {
1356 recursive(move |ty| {
1357 let src = source.clone();
1358
1359 let primitive = choice((
1360 just(Token::TyInt).to(TypeExpr::Int),
1361 just(Token::TyFloat).to(TypeExpr::Float),
1362 just(Token::TyBool).to(TypeExpr::Bool),
1363 just(Token::TyString).to(TypeExpr::String),
1364 just(Token::TyUnit).to(TypeExpr::Unit),
1365 ));
1366
1367 let list_ty = just(Token::TyList)
1368 .ignore_then(just(Token::Lt))
1369 .ignore_then(ty.clone())
1370 .then_ignore(just(Token::Gt))
1371 .map(|inner| TypeExpr::List(Box::new(inner)));
1372
1373 let option_ty = just(Token::TyOption)
1374 .ignore_then(just(Token::Lt))
1375 .ignore_then(ty.clone())
1376 .then_ignore(just(Token::Gt))
1377 .map(|inner| TypeExpr::Option(Box::new(inner)));
1378
1379 let inferred_ty = just(Token::TyInferred)
1380 .ignore_then(just(Token::Lt))
1381 .ignore_then(ty.clone())
1382 .then_ignore(just(Token::Gt))
1383 .map(|inner| TypeExpr::Inferred(Box::new(inner)));
1384
1385 let agent_ty = just(Token::TyAgent)
1386 .ignore_then(just(Token::Lt))
1387 .ignore_then(ident_token_parser(src.clone()))
1388 .then_ignore(just(Token::Gt))
1389 .map(TypeExpr::Agent);
1390
1391 let named_ty = ident_token_parser(src.clone()).map(TypeExpr::Named);
1392
1393 let fn_ty = just(Token::TyFn)
1395 .ignore_then(
1396 ty.clone()
1397 .separated_by(just(Token::Comma))
1398 .allow_trailing()
1399 .delimited_by(just(Token::LParen), just(Token::RParen)),
1400 )
1401 .then_ignore(just(Token::Arrow))
1402 .then(ty.clone())
1403 .map(|(params, ret)| TypeExpr::Fn(params, Box::new(ret)));
1404
1405 let map_ty = just(Token::TyMap)
1407 .ignore_then(just(Token::Lt))
1408 .ignore_then(ty.clone())
1409 .then_ignore(just(Token::Comma))
1410 .then(ty.clone())
1411 .then_ignore(just(Token::Gt))
1412 .map(|(k, v)| TypeExpr::Map(Box::new(k), Box::new(v)));
1413
1414 let result_ty = just(Token::TyResult)
1416 .ignore_then(just(Token::Lt))
1417 .ignore_then(ty.clone())
1418 .then_ignore(just(Token::Comma))
1419 .then(ty.clone())
1420 .then_ignore(just(Token::Gt))
1421 .map(|(ok, err)| TypeExpr::Result(Box::new(ok), Box::new(err)));
1422
1423 let tuple_ty = ty
1425 .clone()
1426 .separated_by(just(Token::Comma))
1427 .at_least(2)
1428 .allow_trailing()
1429 .delimited_by(just(Token::LParen), just(Token::RParen))
1430 .map(TypeExpr::Tuple);
1431
1432 primitive
1433 .or(list_ty)
1434 .or(option_ty)
1435 .or(inferred_ty)
1436 .or(agent_ty)
1437 .or(fn_ty)
1438 .or(map_ty)
1439 .or(result_ty)
1440 .or(tuple_ty)
1441 .or(named_ty)
1442 })
1443}
1444
1445fn for_pattern_parser(source: Arc<str>) -> impl Parser<Token, Pattern, Error = ParseError> + Clone {
1448 recursive(move |pattern| {
1449 let src = source.clone();
1450 let src2 = source.clone();
1451
1452 let binding = ident_token_parser(src.clone()).map_with_span({
1454 let src = src.clone();
1455 move |name, span: Range<usize>| Pattern::Binding {
1456 name,
1457 span: make_span(&src, span),
1458 }
1459 });
1460
1461 let tuple_pattern = pattern
1463 .clone()
1464 .separated_by(just(Token::Comma))
1465 .at_least(2)
1466 .allow_trailing()
1467 .delimited_by(just(Token::LParen), just(Token::RParen))
1468 .map_with_span({
1469 let src = src2.clone();
1470 move |elements, span: Range<usize>| Pattern::Tuple {
1471 elements,
1472 span: make_span(&src, span),
1473 }
1474 });
1475
1476 tuple_pattern.or(binding)
1477 })
1478}
1479
1480fn pattern_parser(source: Arc<str>) -> impl Parser<Token, Pattern, Error = ParseError> + Clone {
1482 recursive(move |pattern| {
1483 let src = source.clone();
1484 let src2 = source.clone();
1485 let src3 = source.clone();
1486 let src4 = source.clone();
1487 let src5 = source.clone();
1488
1489 let wildcard = filter_map({
1491 let src = src.clone();
1492 move |span: Range<usize>, token| match &token {
1493 Token::Ident if src[span.start..span.end].eq("_") => Ok(()),
1494 _ => Err(Simple::expected_input_found(span, vec![], Some(token))),
1495 }
1496 })
1497 .map_with_span(move |_, span: Range<usize>| Pattern::Wildcard {
1498 span: make_span(&src2, span),
1499 });
1500
1501 let lit_int = filter_map({
1503 let src = src3.clone();
1504 move |span: Range<usize>, token| match token {
1505 Token::IntLit => {
1506 let text = &src[span.start..span.end];
1507 text.parse::<i64>()
1508 .map(Literal::Int)
1509 .map_err(|_| Simple::custom(span, "invalid integer literal"))
1510 }
1511 _ => Err(Simple::expected_input_found(
1512 span,
1513 vec![Some(Token::IntLit)],
1514 Some(token),
1515 )),
1516 }
1517 })
1518 .map_with_span({
1519 let src = src3.clone();
1520 move |value, span: Range<usize>| Pattern::Literal {
1521 value,
1522 span: make_span(&src, span),
1523 }
1524 });
1525
1526 let lit_bool = just(Token::KwTrue)
1527 .to(Literal::Bool(true))
1528 .or(just(Token::KwFalse).to(Literal::Bool(false)))
1529 .map_with_span({
1530 let src = src3.clone();
1531 move |value, span: Range<usize>| Pattern::Literal {
1532 value,
1533 span: make_span(&src, span),
1534 }
1535 });
1536
1537 let tuple_pattern = pattern
1539 .clone()
1540 .separated_by(just(Token::Comma))
1541 .at_least(2)
1542 .allow_trailing()
1543 .delimited_by(just(Token::LParen), just(Token::RParen))
1544 .map_with_span({
1545 let src = src5.clone();
1546 move |elements, span: Range<usize>| Pattern::Tuple {
1547 elements,
1548 span: make_span(&src, span),
1549 }
1550 });
1551
1552 let qualified_variant_with_payload = ident_token_parser(src4.clone())
1555 .then_ignore(just(Token::ColonColon))
1556 .then(ident_token_parser(src4.clone()))
1557 .then(
1558 pattern
1559 .clone()
1560 .delimited_by(just(Token::LParen), just(Token::RParen))
1561 .or_not(),
1562 )
1563 .map_with_span({
1564 let src = src4.clone();
1565 move |((enum_name, variant), payload), span: Range<usize>| Pattern::Variant {
1566 enum_name: Some(enum_name),
1567 variant,
1568 payload: payload.map(Box::new),
1569 span: make_span(&src, span),
1570 }
1571 });
1572
1573 let unqualified_with_payload = ident_token_parser(src4.clone())
1575 .then(
1576 pattern
1577 .clone()
1578 .delimited_by(just(Token::LParen), just(Token::RParen))
1579 .or_not(),
1580 )
1581 .map_with_span({
1582 let src = src4.clone();
1583 move |(name, payload), span: Range<usize>| {
1584 if name.name.chars().next().is_some_and(|c| c.is_uppercase()) || payload.is_some() {
1587 Pattern::Variant {
1588 enum_name: None,
1589 variant: name,
1590 payload: payload.map(Box::new),
1591 span: make_span(&src, span),
1592 }
1593 } else {
1594 Pattern::Binding {
1595 name,
1596 span: make_span(&src, span),
1597 }
1598 }
1599 }
1600 });
1601
1602 wildcard
1604 .or(tuple_pattern)
1605 .or(qualified_variant_with_payload)
1606 .or(lit_int)
1607 .or(lit_bool)
1608 .or(unqualified_with_payload)
1609 })
1610}
1611
1612fn literal_parser(source: Arc<str>) -> impl Parser<Token, Expr, Error = ParseError> + Clone {
1614 let src = source.clone();
1615 let src2 = source.clone();
1616 let src3 = source.clone();
1617 let src4 = source.clone();
1618 let src5 = source.clone();
1619
1620 let int_lit = filter_map(move |span: Range<usize>, token| match token {
1621 Token::IntLit => {
1622 let text = &src[span.start..span.end];
1623 text.parse::<i64>()
1624 .map(Literal::Int)
1625 .map_err(|_| Simple::custom(span, "invalid integer literal"))
1626 }
1627 _ => Err(Simple::expected_input_found(
1628 span,
1629 vec![Some(Token::IntLit)],
1630 Some(token),
1631 )),
1632 })
1633 .map_with_span(move |value, span: Range<usize>| Expr::Literal {
1634 value,
1635 span: make_span(&src2, span),
1636 });
1637
1638 let float_lit = filter_map(move |span: Range<usize>, token| match token {
1639 Token::FloatLit => {
1640 let text = &src3[span.start..span.end];
1641 text.parse::<f64>()
1642 .map(Literal::Float)
1643 .map_err(|_| Simple::custom(span, "invalid float literal"))
1644 }
1645 _ => Err(Simple::expected_input_found(
1646 span,
1647 vec![Some(Token::FloatLit)],
1648 Some(token),
1649 )),
1650 })
1651 .map_with_span(move |value, span: Range<usize>| Expr::Literal {
1652 value,
1653 span: make_span(&src4, span),
1654 });
1655
1656 let src6 = source.clone();
1657 let string_lit = filter_map(move |span: Range<usize>, token| match token {
1658 Token::StringLit => {
1659 let text = &src5[span.start..span.end];
1660 let inner = &text[1..text.len() - 1];
1661 let parts = parse_string_template(inner, &make_span(&src5, span.clone()));
1662 Ok(parts)
1663 }
1664 _ => Err(Simple::expected_input_found(
1665 span,
1666 vec![Some(Token::StringLit)],
1667 Some(token),
1668 )),
1669 })
1670 .map_with_span(move |parts, span: Range<usize>| {
1671 let span = make_span(&src6, span);
1672 if parts.len() == 1 {
1674 if let StringPart::Literal(s) = &parts[0] {
1675 return Expr::Literal {
1676 value: Literal::String(s.clone()),
1677 span,
1678 };
1679 }
1680 }
1681 Expr::StringInterp {
1683 template: StringTemplate {
1684 parts,
1685 span: span.clone(),
1686 },
1687 span,
1688 }
1689 });
1690
1691 let bool_lit = just(Token::KwTrue)
1692 .to(Literal::Bool(true))
1693 .or(just(Token::KwFalse).to(Literal::Bool(false)))
1694 .map_with_span(move |value, _span: Range<usize>| Expr::Literal {
1695 value,
1696 span: Span::dummy(), });
1698
1699 int_lit.or(float_lit).or(string_lit).or(bool_lit)
1700}
1701
1702fn string_template_parser(
1704 source: Arc<str>,
1705) -> impl Parser<Token, StringTemplate, Error = ParseError> + Clone {
1706 filter_map(move |span: Range<usize>, token| match token {
1707 Token::StringLit => {
1708 let text = &source[span.start..span.end];
1709 let inner = &text[1..text.len() - 1];
1710 let parts = parse_string_template(inner, &make_span(&source, span.clone()));
1711 Ok(StringTemplate {
1712 parts,
1713 span: make_span(&source, span),
1714 })
1715 }
1716 _ => Err(Simple::expected_input_found(
1717 span,
1718 vec![Some(Token::StringLit)],
1719 Some(token),
1720 )),
1721 })
1722}
1723
1724fn parse_string_template(s: &str, span: &Span) -> Vec<StringPart> {
1726 let mut parts = Vec::new();
1727 let mut current = String::new();
1728 let mut chars = s.chars().peekable();
1729
1730 while let Some(ch) = chars.next() {
1731 if ch == '{' {
1732 if !current.is_empty() {
1733 parts.push(StringPart::Literal(std::mem::take(&mut current)));
1734 }
1735
1736 let mut ident_name = String::new();
1737 while let Some(&c) = chars.peek() {
1738 if c == '}' {
1739 chars.next();
1740 break;
1741 }
1742 ident_name.push(c);
1743 chars.next();
1744 }
1745
1746 if !ident_name.is_empty() {
1747 parts.push(StringPart::Interpolation(Ident::new(
1748 ident_name,
1749 span.clone(),
1750 )));
1751 }
1752 } else if ch == '\\' {
1753 if let Some(escaped) = chars.next() {
1754 current.push(match escaped {
1755 'n' => '\n',
1756 't' => '\t',
1757 'r' => '\r',
1758 '\\' => '\\',
1759 '"' => '"',
1760 '{' => '{',
1761 '}' => '}',
1762 other => other,
1763 });
1764 }
1765 } else {
1766 current.push(ch);
1767 }
1768 }
1769
1770 if !current.is_empty() {
1771 parts.push(StringPart::Literal(current));
1772 }
1773
1774 if parts.is_empty() {
1775 parts.push(StringPart::Literal(String::new()));
1776 }
1777
1778 parts
1779}
1780
1781#[cfg(test)]
1786mod tests {
1787 use super::*;
1788 use sage_lexer::lex;
1789
1790 fn parse_str(source: &str) -> (Option<Program>, Vec<ParseError>) {
1791 let lex_result = lex(source).expect("lexing should succeed");
1792 let source_arc: Arc<str> = Arc::from(source);
1793 parse(lex_result.tokens(), source_arc)
1794 }
1795
1796 #[test]
1797 fn parse_minimal_program() {
1798 let source = r#"
1799 agent Main {
1800 on start {
1801 emit(42);
1802 }
1803 }
1804 run Main;
1805 "#;
1806
1807 let (prog, errors) = parse_str(source);
1808 assert!(errors.is_empty(), "errors: {errors:?}");
1809 let prog = prog.expect("should parse");
1810
1811 assert_eq!(prog.agents.len(), 1);
1812 assert_eq!(prog.agents[0].name.name, "Main");
1813 assert_eq!(prog.run_agent.as_ref().unwrap().name, "Main");
1814 }
1815
1816 #[test]
1817 fn parse_agent_with_beliefs() {
1818 let source = r#"
1819 agent Researcher {
1820 topic: String
1821 max_words: Int
1822
1823 on start {
1824 emit(self.topic);
1825 }
1826 }
1827 run Researcher;
1828 "#;
1829
1830 let (prog, errors) = parse_str(source);
1831 assert!(errors.is_empty(), "errors: {errors:?}");
1832 let prog = prog.expect("should parse");
1833
1834 assert_eq!(prog.agents[0].beliefs.len(), 2);
1835 assert_eq!(prog.agents[0].beliefs[0].name.name, "topic");
1836 assert_eq!(prog.agents[0].beliefs[1].name.name, "max_words");
1837 }
1838
1839 #[test]
1840 fn parse_multiple_handlers() {
1841 let source = r#"
1842 agent Worker {
1843 on start {
1844 print("started");
1845 }
1846
1847 on message(msg: String) {
1848 print(msg);
1849 }
1850
1851 on stop {
1852 print("stopped");
1853 }
1854 }
1855 run Worker;
1856 "#;
1857
1858 let (prog, errors) = parse_str(source);
1859 assert!(errors.is_empty(), "errors: {errors:?}");
1860 let prog = prog.expect("should parse");
1861
1862 assert_eq!(prog.agents[0].handlers.len(), 3);
1863 assert_eq!(prog.agents[0].handlers[0].event, EventKind::Start);
1864 assert!(matches!(
1865 prog.agents[0].handlers[1].event,
1866 EventKind::Message { .. }
1867 ));
1868 assert_eq!(prog.agents[0].handlers[2].event, EventKind::Stop);
1869 }
1870
1871 #[test]
1872 fn parse_function() {
1873 let source = r#"
1874 fn greet(name: String) -> String {
1875 return "Hello, " ++ name;
1876 }
1877
1878 agent Main {
1879 on start {
1880 emit(greet("World"));
1881 }
1882 }
1883 run Main;
1884 "#;
1885
1886 let (prog, errors) = parse_str(source);
1887 assert!(errors.is_empty(), "errors: {errors:?}");
1888 let prog = prog.expect("should parse");
1889
1890 assert_eq!(prog.functions.len(), 1);
1891 assert_eq!(prog.functions[0].name.name, "greet");
1892 assert_eq!(prog.functions[0].params.len(), 1);
1893 }
1894
1895 #[test]
1896 fn parse_let_statement() {
1897 let source = r#"
1898 agent Main {
1899 on start {
1900 let x: Int = 42;
1901 let y = "hello";
1902 emit(x);
1903 }
1904 }
1905 run Main;
1906 "#;
1907
1908 let (prog, errors) = parse_str(source);
1909 assert!(errors.is_empty(), "errors: {errors:?}");
1910 let prog = prog.expect("should parse");
1911
1912 let stmts = &prog.agents[0].handlers[0].body.stmts;
1913 assert!(matches!(stmts[0], Stmt::Let { .. }));
1914 assert!(matches!(stmts[1], Stmt::Let { .. }));
1915 }
1916
1917 #[test]
1918 fn parse_if_statement() {
1919 let source = r#"
1920 agent Main {
1921 on start {
1922 if true {
1923 emit(1);
1924 } else {
1925 emit(2);
1926 }
1927 }
1928 }
1929 run Main;
1930 "#;
1931
1932 let (prog, errors) = parse_str(source);
1933 assert!(errors.is_empty(), "errors: {errors:?}");
1934 let prog = prog.expect("should parse");
1935
1936 let stmts = &prog.agents[0].handlers[0].body.stmts;
1937 assert!(matches!(stmts[0], Stmt::If { .. }));
1938 }
1939
1940 #[test]
1941 fn parse_for_loop() {
1942 let source = r#"
1943 agent Main {
1944 on start {
1945 for x in [1, 2, 3] {
1946 print(x);
1947 }
1948 emit(0);
1949 }
1950 }
1951 run Main;
1952 "#;
1953
1954 let (prog, errors) = parse_str(source);
1955 assert!(errors.is_empty(), "errors: {errors:?}");
1956 let prog = prog.expect("should parse");
1957
1958 let stmts = &prog.agents[0].handlers[0].body.stmts;
1959 assert!(matches!(stmts[0], Stmt::For { .. }));
1960 }
1961
1962 #[test]
1963 fn parse_spawn_await() {
1964 let source = r#"
1965 agent Worker {
1966 name: String
1967
1968 on start {
1969 emit(self.name);
1970 }
1971 }
1972
1973 agent Main {
1974 on start {
1975 let w = spawn Worker { name: "test" };
1976 let result = await w;
1977 emit(result);
1978 }
1979 }
1980 run Main;
1981 "#;
1982
1983 let (prog, errors) = parse_str(source);
1984 assert!(errors.is_empty(), "errors: {errors:?}");
1985 prog.expect("should parse");
1986 }
1987
1988 #[test]
1989 fn parse_infer() {
1990 let source = r#"
1991 agent Main {
1992 on start {
1993 let result = infer("What is 2+2?");
1994 emit(result);
1995 }
1996 }
1997 run Main;
1998 "#;
1999
2000 let (prog, errors) = parse_str(source);
2001 assert!(errors.is_empty(), "errors: {errors:?}");
2002 prog.expect("should parse");
2003 }
2004
2005 #[test]
2006 fn parse_binary_precedence() {
2007 let source = r#"
2008 agent Main {
2009 on start {
2010 let x = 2 + 3 * 4;
2011 emit(x);
2012 }
2013 }
2014 run Main;
2015 "#;
2016
2017 let (prog, errors) = parse_str(source);
2018 assert!(errors.is_empty(), "errors: {errors:?}");
2019 let prog = prog.expect("should parse");
2020
2021 let stmts = &prog.agents[0].handlers[0].body.stmts;
2022 if let Stmt::Let { value, .. } = &stmts[0] {
2023 if let Expr::Binary { op, .. } = value {
2024 assert_eq!(*op, BinOp::Add);
2025 } else {
2026 panic!("expected binary expression");
2027 }
2028 }
2029 }
2030
2031 #[test]
2032 fn parse_string_interpolation() {
2033 let source = r#"
2034 agent Main {
2035 on start {
2036 let name = "World";
2037 let msg = infer("Greet {name}");
2038 emit(msg);
2039 }
2040 }
2041 run Main;
2042 "#;
2043
2044 let (prog, errors) = parse_str(source);
2045 assert!(errors.is_empty(), "errors: {errors:?}");
2046 let prog = prog.expect("should parse");
2047
2048 let stmts = &prog.agents[0].handlers[0].body.stmts;
2049 if let Stmt::Let { value, .. } = &stmts[1] {
2050 if let Expr::Infer { template, .. } = value {
2051 assert!(template.has_interpolations());
2052 } else {
2053 panic!("expected infer expression");
2054 }
2055 }
2056 }
2057
2058 #[test]
2063 fn recover_from_malformed_agent_continues_to_next() {
2064 let source = r#"
2066 agent Broken {
2067 x:
2068 }
2069
2070 agent Main {
2071 on start {
2072 emit(42);
2073 }
2074 }
2075 run Main;
2076 "#;
2077
2078 let (prog, errors) = parse_str(source);
2079 assert!(!errors.is_empty(), "should have parse errors");
2081 let prog = prog.expect("should produce partial AST");
2083 assert!(prog.agents.iter().any(|a| a.name.name == "Main"));
2084 }
2085
2086 #[test]
2087 fn recover_from_mismatched_braces_in_block() {
2088 let source = r#"
2089 agent Main {
2090 on start {
2091 let x = [1, 2, 3;
2092 emit(42);
2093 }
2094 }
2095 run Main;
2096 "#;
2097
2098 let (prog, errors) = parse_str(source);
2099 assert!(!errors.is_empty(), "should have parse errors");
2101 assert!(prog.is_some(), "should produce partial AST despite errors");
2102 }
2103
2104 #[test]
2105 fn parse_mod_declaration() {
2106 let source = r#"
2107 mod agents;
2108 pub mod utils;
2109
2110 agent Main {
2111 on start {
2112 emit(42);
2113 }
2114 }
2115 run Main;
2116 "#;
2117
2118 let (prog, errors) = parse_str(source);
2119 assert!(errors.is_empty(), "errors: {errors:?}");
2120 let prog = prog.expect("should parse");
2121
2122 assert_eq!(prog.mod_decls.len(), 2);
2123 assert!(!prog.mod_decls[0].is_pub);
2124 assert_eq!(prog.mod_decls[0].name.name, "agents");
2125 assert!(prog.mod_decls[1].is_pub);
2126 assert_eq!(prog.mod_decls[1].name.name, "utils");
2127 }
2128
2129 #[test]
2130 fn parse_use_simple() {
2131 let source = r#"
2132 use agents::Researcher;
2133
2134 agent Main {
2135 on start {
2136 emit(42);
2137 }
2138 }
2139 run Main;
2140 "#;
2141
2142 let (prog, errors) = parse_str(source);
2143 assert!(errors.is_empty(), "errors: {errors:?}");
2144 let prog = prog.expect("should parse");
2145
2146 assert_eq!(prog.use_decls.len(), 1);
2147 assert!(!prog.use_decls[0].is_pub);
2148 assert_eq!(prog.use_decls[0].path.len(), 2);
2149 assert_eq!(prog.use_decls[0].path[0].name, "agents");
2150 assert_eq!(prog.use_decls[0].path[1].name, "Researcher");
2151 assert!(matches!(prog.use_decls[0].kind, UseKind::Simple(None)));
2152 }
2153
2154 #[test]
2155 fn parse_use_with_alias() {
2156 let source = r#"
2157 use agents::Researcher as R;
2158
2159 agent Main {
2160 on start {
2161 emit(42);
2162 }
2163 }
2164 run Main;
2165 "#;
2166
2167 let (prog, errors) = parse_str(source);
2168 assert!(errors.is_empty(), "errors: {errors:?}");
2169 let prog = prog.expect("should parse");
2170
2171 assert_eq!(prog.use_decls.len(), 1);
2172 if let UseKind::Simple(Some(alias)) = &prog.use_decls[0].kind {
2173 assert_eq!(alias.name, "R");
2174 } else {
2175 panic!("expected Simple with alias");
2176 }
2177 }
2178
2179 #[test]
2180 fn parse_pub_agent() {
2181 let source = r#"
2182 pub agent Worker {
2183 on start {
2184 emit(42);
2185 }
2186 }
2187
2188 agent Main {
2189 on start {
2190 emit(0);
2191 }
2192 }
2193 run Main;
2194 "#;
2195
2196 let (prog, errors) = parse_str(source);
2197 assert!(errors.is_empty(), "errors: {errors:?}");
2198 let prog = prog.expect("should parse");
2199
2200 assert_eq!(prog.agents.len(), 2);
2201 assert!(prog.agents[0].is_pub);
2202 assert_eq!(prog.agents[0].name.name, "Worker");
2203 assert!(!prog.agents[1].is_pub);
2204 }
2205
2206 #[test]
2207 fn parse_pub_function() {
2208 let source = r#"
2209 pub fn helper(x: Int) -> Int {
2210 return x;
2211 }
2212
2213 agent Main {
2214 on start {
2215 emit(helper(42));
2216 }
2217 }
2218 run Main;
2219 "#;
2220
2221 let (prog, errors) = parse_str(source);
2222 assert!(errors.is_empty(), "errors: {errors:?}");
2223 let prog = prog.expect("should parse");
2224
2225 assert_eq!(prog.functions.len(), 1);
2226 assert!(prog.functions[0].is_pub);
2227 assert_eq!(prog.functions[0].name.name, "helper");
2228 }
2229
2230 #[test]
2231 fn parse_library_no_run() {
2232 let source = r#"
2234 pub agent Worker {
2235 on start {
2236 emit(42);
2237 }
2238 }
2239
2240 pub fn helper(x: Int) -> Int {
2241 return x;
2242 }
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 assert!(prog.run_agent.is_none());
2250 assert_eq!(prog.agents.len(), 1);
2251 assert_eq!(prog.functions.len(), 1);
2252 }
2253
2254 #[test]
2255 fn recover_multiple_errors_reported() {
2256 let source = r#"
2258 agent A {
2259 x:
2260 }
2261
2262 agent Main {
2263 on start {
2264 emit(42);
2265 }
2266 }
2267 run Main;
2268 "#;
2269
2270 let (prog, errors) = parse_str(source);
2271 if errors.is_empty() {
2275 let prog = prog.expect("should have AST with recovery");
2277 assert!(prog.agents.iter().any(|a| a.name.name == "Main"));
2278 }
2279 }
2281
2282 #[test]
2283 fn parse_record_declaration() {
2284 let source = r#"
2285 record Point {
2286 x: Int,
2287 y: Int,
2288 }
2289
2290 agent Main {
2291 on start {
2292 emit(0);
2293 }
2294 }
2295 run Main;
2296 "#;
2297
2298 let (prog, errors) = parse_str(source);
2299 assert!(errors.is_empty(), "errors: {errors:?}");
2300 let prog = prog.expect("should parse");
2301
2302 assert_eq!(prog.records.len(), 1);
2303 assert!(!prog.records[0].is_pub);
2304 assert_eq!(prog.records[0].name.name, "Point");
2305 assert_eq!(prog.records[0].fields.len(), 2);
2306 assert_eq!(prog.records[0].fields[0].name.name, "x");
2307 assert_eq!(prog.records[0].fields[1].name.name, "y");
2308 }
2309
2310 #[test]
2311 fn parse_pub_record() {
2312 let source = r#"
2313 pub record Config {
2314 host: String,
2315 port: Int,
2316 }
2317
2318 agent Main {
2319 on start { emit(0); }
2320 }
2321 run Main;
2322 "#;
2323
2324 let (prog, errors) = parse_str(source);
2325 assert!(errors.is_empty(), "errors: {errors:?}");
2326 let prog = prog.expect("should parse");
2327
2328 assert_eq!(prog.records.len(), 1);
2329 assert!(prog.records[0].is_pub);
2330 assert_eq!(prog.records[0].name.name, "Config");
2331 }
2332
2333 #[test]
2334 fn parse_enum_declaration() {
2335 let source = r#"
2336 enum Status {
2337 Active,
2338 Pending,
2339 Done,
2340 }
2341
2342 agent Main {
2343 on start {
2344 emit(0);
2345 }
2346 }
2347 run Main;
2348 "#;
2349
2350 let (prog, errors) = parse_str(source);
2351 assert!(errors.is_empty(), "errors: {errors:?}");
2352 let prog = prog.expect("should parse");
2353
2354 assert_eq!(prog.enums.len(), 1);
2355 assert!(!prog.enums[0].is_pub);
2356 assert_eq!(prog.enums[0].name.name, "Status");
2357 assert_eq!(prog.enums[0].variants.len(), 3);
2358 assert_eq!(prog.enums[0].variants[0].name.name, "Active");
2359 assert_eq!(prog.enums[0].variants[1].name.name, "Pending");
2360 assert_eq!(prog.enums[0].variants[2].name.name, "Done");
2361 }
2362
2363 #[test]
2364 fn parse_pub_enum() {
2365 let source = r#"
2366 pub enum Priority { High, Medium, Low }
2367
2368 agent Main {
2369 on start { emit(0); }
2370 }
2371 run Main;
2372 "#;
2373
2374 let (prog, errors) = parse_str(source);
2375 assert!(errors.is_empty(), "errors: {errors:?}");
2376 let prog = prog.expect("should parse");
2377
2378 assert_eq!(prog.enums.len(), 1);
2379 assert!(prog.enums[0].is_pub);
2380 assert_eq!(prog.enums[0].name.name, "Priority");
2381 }
2382
2383 #[test]
2384 fn parse_const_declaration() {
2385 let source = r#"
2386 const MAX_RETRIES: Int = 3;
2387
2388 agent Main {
2389 on start {
2390 emit(0);
2391 }
2392 }
2393 run Main;
2394 "#;
2395
2396 let (prog, errors) = parse_str(source);
2397 assert!(errors.is_empty(), "errors: {errors:?}");
2398 let prog = prog.expect("should parse");
2399
2400 assert_eq!(prog.consts.len(), 1);
2401 assert!(!prog.consts[0].is_pub);
2402 assert_eq!(prog.consts[0].name.name, "MAX_RETRIES");
2403 assert!(matches!(prog.consts[0].ty, sage_types::TypeExpr::Int));
2404 }
2405
2406 #[test]
2407 fn parse_pub_const() {
2408 let source = r#"
2409 pub const API_URL: String = "https://api.example.com";
2410
2411 agent Main {
2412 on start { emit(0); }
2413 }
2414 run Main;
2415 "#;
2416
2417 let (prog, errors) = parse_str(source);
2418 assert!(errors.is_empty(), "errors: {errors:?}");
2419 let prog = prog.expect("should parse");
2420
2421 assert_eq!(prog.consts.len(), 1);
2422 assert!(prog.consts[0].is_pub);
2423 assert_eq!(prog.consts[0].name.name, "API_URL");
2424 }
2425
2426 #[test]
2427 fn parse_multiple_type_declarations() {
2428 let source = r#"
2429 record Point { x: Int, y: Int }
2430 enum Color { Red, Green, Blue }
2431 const ORIGIN_X: Int = 0;
2432
2433 agent Main {
2434 on start { emit(0); }
2435 }
2436 run Main;
2437 "#;
2438
2439 let (prog, errors) = parse_str(source);
2440 assert!(errors.is_empty(), "errors: {errors:?}");
2441 let prog = prog.expect("should parse");
2442
2443 assert_eq!(prog.records.len(), 1);
2444 assert_eq!(prog.enums.len(), 1);
2445 assert_eq!(prog.consts.len(), 1);
2446 }
2447
2448 #[test]
2449 fn parse_match_expression() {
2450 let source = r#"
2451 enum Status { Active, Pending, Done }
2452
2453 agent Main {
2454 on start {
2455 let s: Int = match Active {
2456 Active => 1,
2457 Pending => 2,
2458 Done => 3,
2459 };
2460 emit(s);
2461 }
2462 }
2463 run Main;
2464 "#;
2465
2466 let (prog, errors) = parse_str(source);
2467 assert!(errors.is_empty(), "errors: {errors:?}");
2468 let prog = prog.expect("should parse");
2469
2470 assert_eq!(prog.agents.len(), 1);
2472 let handler = &prog.agents[0].handlers[0];
2474 let stmt = &handler.body.stmts[0];
2475 if let Stmt::Let { value, .. } = stmt {
2476 assert!(matches!(value, Expr::Match { .. }));
2477 } else {
2478 panic!("expected let statement with match");
2479 }
2480 }
2481
2482 #[test]
2483 fn parse_match_with_wildcard() {
2484 let source = r#"
2485 agent Main {
2486 on start {
2487 let x = 5;
2488 let result = match x {
2489 1 => 10,
2490 2 => 20,
2491 _ => 0,
2492 };
2493 emit(result);
2494 }
2495 }
2496 run Main;
2497 "#;
2498
2499 let (prog, errors) = parse_str(source);
2500 assert!(errors.is_empty(), "errors: {errors:?}");
2501 let prog = prog.expect("should parse");
2502
2503 assert_eq!(prog.agents.len(), 1);
2504 }
2505
2506 #[test]
2507 fn parse_record_construction() {
2508 let source = r#"
2509 record Point { x: Int, y: Int }
2510
2511 agent Main {
2512 on start {
2513 let p = Point { x: 10, y: 20 };
2514 emit(0);
2515 }
2516 }
2517 run Main;
2518 "#;
2519
2520 let (prog, errors) = parse_str(source);
2521 assert!(errors.is_empty(), "errors: {errors:?}");
2522 let prog = prog.expect("should parse");
2523
2524 assert_eq!(prog.records.len(), 1);
2525 assert_eq!(prog.agents.len(), 1);
2526
2527 let handler = &prog.agents[0].handlers[0];
2529 let stmt = &handler.body.stmts[0];
2530 if let Stmt::Let { value, .. } = stmt {
2531 if let Expr::RecordConstruct { name, fields, .. } = value {
2532 assert_eq!(name.name, "Point");
2533 assert_eq!(fields.len(), 2);
2534 assert_eq!(fields[0].name.name, "x");
2535 assert_eq!(fields[1].name.name, "y");
2536 } else {
2537 panic!("expected RecordConstruct");
2538 }
2539 } else {
2540 panic!("expected let statement");
2541 }
2542 }
2543
2544 #[test]
2545 fn parse_match_with_qualified_variant() {
2546 let source = r#"
2547 enum Status { Active, Pending }
2548
2549 fn get_status() -> Int {
2550 return 1;
2551 }
2552
2553 agent Main {
2554 on start {
2555 let s = get_status();
2556 let result = match s {
2557 Status::Active => 1,
2558 Status::Pending => 0,
2559 };
2560 emit(result);
2561 }
2562 }
2563 run Main;
2564 "#;
2565
2566 let (prog, errors) = parse_str(source);
2567 assert!(errors.is_empty(), "errors: {errors:?}");
2568 let prog = prog.expect("should parse");
2569
2570 assert_eq!(prog.enums.len(), 1);
2571 assert_eq!(prog.agents.len(), 1);
2572 }
2573
2574 #[test]
2575 fn parse_field_access() {
2576 let source = r#"
2577 record Point { x: Int, y: Int }
2578
2579 agent Main {
2580 on start {
2581 let p = Point { x: 10, y: 20 };
2582 let x_val = p.x;
2583 let y_val = p.y;
2584 emit(x_val);
2585 }
2586 }
2587 run Main;
2588 "#;
2589
2590 let (prog, errors) = parse_str(source);
2591 assert!(errors.is_empty(), "errors: {errors:?}");
2592 let prog = prog.expect("should parse");
2593
2594 assert_eq!(prog.records.len(), 1);
2595 assert_eq!(prog.agents.len(), 1);
2596
2597 let handler = &prog.agents[0].handlers[0];
2599 let stmt = &handler.body.stmts[1]; if let Stmt::Let { value, .. } = stmt {
2601 if let Expr::FieldAccess { field, .. } = value {
2602 assert_eq!(field.name, "x");
2603 } else {
2604 panic!("expected FieldAccess");
2605 }
2606 } else {
2607 panic!("expected let statement");
2608 }
2609 }
2610
2611 #[test]
2612 fn parse_chained_field_access() {
2613 let source = r#"
2614 record Inner { val: Int }
2615 record Outer { inner: Inner }
2616
2617 agent Main {
2618 on start {
2619 let inner = Inner { val: 42 };
2620 let outer = Outer { inner: inner };
2621 let v = outer.inner.val;
2622 emit(v);
2623 }
2624 }
2625 run Main;
2626 "#;
2627
2628 let (prog, errors) = parse_str(source);
2629 assert!(errors.is_empty(), "errors: {errors:?}");
2630 let prog = prog.expect("should parse");
2631
2632 assert_eq!(prog.records.len(), 2);
2633 assert_eq!(prog.agents.len(), 1);
2634
2635 let handler = &prog.agents[0].handlers[0];
2637 let stmt = &handler.body.stmts[2]; if let Stmt::Let { value, .. } = stmt {
2639 if let Expr::FieldAccess {
2640 object, field: val, ..
2641 } = value
2642 {
2643 assert_eq!(val.name, "val");
2644 if let Expr::FieldAccess { field: inner, .. } = object.as_ref() {
2646 assert_eq!(inner.name, "inner");
2647 } else {
2648 panic!("expected nested FieldAccess");
2649 }
2650 } else {
2651 panic!("expected FieldAccess");
2652 }
2653 } else {
2654 panic!("expected let statement");
2655 }
2656 }
2657
2658 #[test]
2663 fn parse_loop_break() {
2664 let source = r#"
2665 agent Main {
2666 on start {
2667 let count = 0;
2668 loop {
2669 count = count + 1;
2670 if count > 5 {
2671 break;
2672 }
2673 }
2674 emit(count);
2675 }
2676 }
2677 run Main;
2678 "#;
2679
2680 let (prog, errors) = parse_str(source);
2681 assert!(errors.is_empty(), "errors: {errors:?}");
2682 let prog = prog.expect("should parse");
2683
2684 assert_eq!(prog.agents.len(), 1);
2685 let handler = &prog.agents[0].handlers[0];
2686 let loop_stmt = &handler.body.stmts[1];
2688 assert!(matches!(loop_stmt, Stmt::Loop { .. }));
2689 if let Stmt::Loop { body, .. } = loop_stmt {
2691 let if_stmt = &body.stmts[1];
2692 if let Stmt::If { then_block, .. } = if_stmt {
2693 assert!(matches!(then_block.stmts[0], Stmt::Break { .. }));
2694 } else {
2695 panic!("expected if statement");
2696 }
2697 }
2698 }
2699
2700 #[test]
2701 fn parse_agent_receives() {
2702 let source = r#"
2703 enum WorkerMsg {
2704 Task,
2705 Shutdown,
2706 }
2707
2708 agent Worker receives WorkerMsg {
2709 id: Int
2710
2711 on start {
2712 emit(0);
2713 }
2714 }
2715
2716 agent Main {
2717 on start {
2718 emit(0);
2719 }
2720 }
2721 run Main;
2722 "#;
2723
2724 let (prog, errors) = parse_str(source);
2725 assert!(errors.is_empty(), "errors: {errors:?}");
2726 let prog = prog.expect("should parse");
2727
2728 assert_eq!(prog.agents.len(), 2);
2729
2730 let worker = &prog.agents[0];
2732 assert_eq!(worker.name.name, "Worker");
2733 assert!(worker.receives.is_some());
2734 if let Some(TypeExpr::Named(name)) = &worker.receives {
2735 assert_eq!(name.name, "WorkerMsg");
2736 } else {
2737 panic!("expected named type for receives");
2738 }
2739
2740 let main = &prog.agents[1];
2742 assert_eq!(main.name.name, "Main");
2743 assert!(main.receives.is_none());
2744 }
2745
2746 #[test]
2747 fn parse_receive_expression() {
2748 let source = r#"
2749 enum Msg { Ping }
2750
2751 agent Worker receives Msg {
2752 on start {
2753 let msg = receive();
2754 emit(0);
2755 }
2756 }
2757
2758 agent Main {
2759 on start { emit(0); }
2760 }
2761 run Main;
2762 "#;
2763
2764 let (prog, errors) = parse_str(source);
2765 assert!(errors.is_empty(), "errors: {errors:?}");
2766 let prog = prog.expect("should parse");
2767
2768 let worker = prog
2770 .agents
2771 .iter()
2772 .find(|a| a.name.name == "Worker")
2773 .unwrap();
2774 let handler = &worker.handlers[0];
2775 let stmt = &handler.body.stmts[0];
2776
2777 if let Stmt::Let { value, .. } = stmt {
2778 assert!(matches!(value, Expr::Receive { .. }));
2779 } else {
2780 panic!("expected let with receive");
2781 }
2782 }
2783
2784 #[test]
2785 fn parse_message_passing_full() {
2786 let source = r#"
2787 enum WorkerMsg {
2788 Task,
2789 Shutdown,
2790 }
2791
2792 agent Worker receives WorkerMsg {
2793 id: Int
2794
2795 on start {
2796 let msg = receive();
2797 let result = match msg {
2798 Task => 1,
2799 Shutdown => 0,
2800 };
2801 emit(result);
2802 }
2803 }
2804
2805 agent Main {
2806 on start {
2807 let w = spawn Worker { id: 1 };
2808 send(w, Task);
2809 send(w, Shutdown);
2810 await w;
2811 emit(0);
2812 }
2813 }
2814 run Main;
2815 "#;
2816
2817 let (prog, errors) = parse_str(source);
2818 assert!(errors.is_empty(), "errors: {errors:?}");
2819 let prog = prog.expect("should parse");
2820
2821 assert_eq!(prog.enums.len(), 1);
2822 assert_eq!(prog.agents.len(), 2);
2823
2824 let worker = prog
2826 .agents
2827 .iter()
2828 .find(|a| a.name.name == "Worker")
2829 .unwrap();
2830 assert!(worker.receives.is_some());
2831 }
2832
2833 #[test]
2838 fn parse_fallible_function() {
2839 let source = r#"
2840 fn get_data(url: String) -> String fails {
2841 return infer("Get data from {url}" -> String);
2842 }
2843
2844 agent Main {
2845 on start { emit(0); }
2846 }
2847 run Main;
2848 "#;
2849
2850 let (prog, errors) = parse_str(source);
2851 assert!(errors.is_empty(), "errors: {errors:?}");
2852 let prog = prog.expect("should parse");
2853
2854 assert_eq!(prog.functions.len(), 1);
2855 assert!(prog.functions[0].is_fallible);
2856 }
2857
2858 #[test]
2859 fn parse_try_expression() {
2860 let source = r#"
2861 fn fallible() -> Int fails { return 42; }
2862
2863 agent Main {
2864 on start {
2865 let x = try fallible();
2866 emit(x);
2867 }
2868 }
2869 run Main;
2870 "#;
2871
2872 let (prog, errors) = parse_str(source);
2873 assert!(errors.is_empty(), "errors: {errors:?}");
2874 let prog = prog.expect("should parse");
2875
2876 let handler = &prog.agents[0].handlers[0];
2878 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
2879 assert!(matches!(value, Expr::Try { .. }));
2880 } else {
2881 panic!("expected Let statement");
2882 }
2883 }
2884
2885 #[test]
2886 fn parse_catch_expression() {
2887 let source = r#"
2888 fn fallible() -> Int fails { return 42; }
2889
2890 agent Main {
2891 on start {
2892 let x = fallible() catch { 0 };
2893 emit(x);
2894 }
2895 }
2896 run Main;
2897 "#;
2898
2899 let (prog, errors) = parse_str(source);
2900 assert!(errors.is_empty(), "errors: {errors:?}");
2901 let prog = prog.expect("should parse");
2902
2903 let handler = &prog.agents[0].handlers[0];
2905 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
2906 if let Expr::Catch { error_bind, .. } = value {
2907 assert!(error_bind.is_none());
2908 } else {
2909 panic!("expected Catch expression");
2910 }
2911 } else {
2912 panic!("expected Let statement");
2913 }
2914 }
2915
2916 #[test]
2917 fn parse_catch_with_error_binding() {
2918 let source = r#"
2919 fn fallible() -> Int fails { return 42; }
2920
2921 agent Main {
2922 on start {
2923 let x = fallible() catch(e) { 0 };
2924 emit(x);
2925 }
2926 }
2927 run Main;
2928 "#;
2929
2930 let (prog, errors) = parse_str(source);
2931 assert!(errors.is_empty(), "errors: {errors:?}");
2932 let prog = prog.expect("should parse");
2933
2934 let handler = &prog.agents[0].handlers[0];
2936 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
2937 if let Expr::Catch { error_bind, .. } = value {
2938 assert!(error_bind.is_some());
2939 assert_eq!(error_bind.as_ref().unwrap().name, "e");
2940 } else {
2941 panic!("expected Catch expression");
2942 }
2943 } else {
2944 panic!("expected Let statement");
2945 }
2946 }
2947
2948 #[test]
2949 fn parse_on_error_handler() {
2950 let source = r#"
2951 agent Main {
2952 on start {
2953 emit(0);
2954 }
2955
2956 on error(e) {
2957 emit(1);
2958 }
2959 }
2960 run Main;
2961 "#;
2962
2963 let (prog, errors) = parse_str(source);
2964 assert!(errors.is_empty(), "errors: {errors:?}");
2965 let prog = prog.expect("should parse");
2966
2967 assert_eq!(prog.agents.len(), 1);
2968 assert_eq!(prog.agents[0].handlers.len(), 2);
2969
2970 let error_handler = prog.agents[0]
2972 .handlers
2973 .iter()
2974 .find(|h| matches!(h.event, EventKind::Error { .. }));
2975 assert!(error_handler.is_some());
2976
2977 if let EventKind::Error { param_name } = &error_handler.unwrap().event {
2978 assert_eq!(param_name.name, "e");
2979 } else {
2980 panic!("expected Error event kind");
2981 }
2982 }
2983
2984 #[test]
2989 fn parse_fn_type() {
2990 let source = r#"
2991 fn apply(f: Fn(Int) -> Int, x: Int) -> Int {
2992 return f(x);
2993 }
2994
2995 agent Main {
2996 on start {
2997 emit(0);
2998 }
2999 }
3000 run Main;
3001 "#;
3002
3003 let (prog, errors) = parse_str(source);
3004 assert!(errors.is_empty(), "errors: {errors:?}");
3005 let prog = prog.expect("should parse");
3006
3007 assert_eq!(prog.functions.len(), 1);
3008 let func = &prog.functions[0];
3009 assert_eq!(func.name.name, "apply");
3010 assert_eq!(func.params.len(), 2);
3011
3012 if let TypeExpr::Fn(params, ret) = &func.params[0].ty {
3014 assert_eq!(params.len(), 1);
3015 assert!(matches!(params[0], TypeExpr::Int));
3016 assert!(matches!(ret.as_ref(), TypeExpr::Int));
3017 } else {
3018 panic!("expected Fn type for first param");
3019 }
3020 }
3021
3022 #[test]
3023 fn parse_closure_with_params() {
3024 let source = r#"
3025 agent Main {
3026 on start {
3027 let f = |x: Int| x + 1;
3028 emit(0);
3029 }
3030 }
3031 run Main;
3032 "#;
3033
3034 let (prog, errors) = parse_str(source);
3035 assert!(errors.is_empty(), "errors: {errors:?}");
3036 let prog = prog.expect("should parse");
3037
3038 let handler = &prog.agents[0].handlers[0];
3040 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
3041 if let Expr::Closure { params, body, .. } = value {
3042 assert_eq!(params.len(), 1);
3043 assert_eq!(params[0].name.name, "x");
3044 assert!(matches!(¶ms[0].ty, Some(TypeExpr::Int)));
3045
3046 assert!(matches!(body.as_ref(), Expr::Binary { .. }));
3048 } else {
3049 panic!("expected closure expression");
3050 }
3051 } else {
3052 panic!("expected let statement");
3053 }
3054 }
3055
3056 #[test]
3057 fn parse_closure_empty_params() {
3058 let source = r#"
3059 agent Main {
3060 on start {
3061 let f = || 42;
3062 emit(0);
3063 }
3064 }
3065 run Main;
3066 "#;
3067
3068 let (prog, errors) = parse_str(source);
3069 assert!(errors.is_empty(), "errors: {errors:?}");
3070 let prog = prog.expect("should parse");
3071
3072 let handler = &prog.agents[0].handlers[0];
3074 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
3075 if let Expr::Closure { params, body, .. } = value {
3076 assert!(params.is_empty());
3077
3078 assert!(matches!(body.as_ref(), Expr::Literal { .. }));
3080 } else {
3081 panic!("expected closure expression");
3082 }
3083 } else {
3084 panic!("expected let statement");
3085 }
3086 }
3087
3088 #[test]
3089 fn parse_closure_multiple_params() {
3090 let source = r#"
3091 agent Main {
3092 on start {
3093 let add = |x: Int, y: Int| x + y;
3094 emit(0);
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];
3105 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
3106 if let Expr::Closure { params, .. } = value {
3107 assert_eq!(params.len(), 2);
3108 assert_eq!(params[0].name.name, "x");
3109 assert_eq!(params[1].name.name, "y");
3110 } else {
3111 panic!("expected closure expression");
3112 }
3113 } else {
3114 panic!("expected let statement");
3115 }
3116 }
3117
3118 #[test]
3119 fn parse_fn_type_multiarg() {
3120 let source = r#"
3121 fn fold_left(f: Fn(Int, Int) -> Int, init: Int) -> Int {
3122 return init;
3123 }
3124
3125 agent Main {
3126 on start {
3127 emit(0);
3128 }
3129 }
3130 run Main;
3131 "#;
3132
3133 let (prog, errors) = parse_str(source);
3134 assert!(errors.is_empty(), "errors: {errors:?}");
3135 let prog = prog.expect("should parse");
3136
3137 if let TypeExpr::Fn(params, ret) = &prog.functions[0].params[0].ty {
3139 assert_eq!(params.len(), 2);
3140 assert!(matches!(params[0], TypeExpr::Int));
3141 assert!(matches!(params[1], TypeExpr::Int));
3142 assert!(matches!(ret.as_ref(), TypeExpr::Int));
3143 } else {
3144 panic!("expected Fn type");
3145 }
3146 }
3147
3148 #[test]
3149 fn parse_tuple_literal() {
3150 let source = r#"
3151 agent Main {
3152 on start {
3153 let t = (1, 2);
3154 emit(0);
3155 }
3156 }
3157 run Main;
3158 "#;
3159
3160 let (prog, errors) = parse_str(source);
3161 assert!(errors.is_empty(), "errors: {errors:?}");
3162 let prog = prog.expect("should parse");
3163
3164 let handler = &prog.agents[0].handlers[0];
3165 if let Stmt::Let { value, .. } = &handler.body.stmts[0] {
3166 if let Expr::Tuple { elements, .. } = value {
3167 assert_eq!(elements.len(), 2);
3168 } else {
3169 panic!("expected tuple expression, got {:?}", value);
3170 }
3171 } else {
3172 panic!("expected let statement");
3173 }
3174 }
3175}