1use crate::emit::Emitter;
4use sage_loader::ModuleTree;
5use sage_parser::{
6 AgentDecl, BinOp, Block, ConstDecl, EnumDecl, EventKind, Expr, FnDecl, Literal, MockValue,
7 Program, RecordDecl, Stmt, StringPart, TestDecl, TypeExpr, UnaryOp,
8};
9
10#[derive(Debug, Clone)]
12pub enum RuntimeDep {
13 CratesIo { version: String },
15 Path { path: String },
17}
18
19impl Default for RuntimeDep {
20 fn default() -> Self {
21 Self::CratesIo {
23 version: env!("CARGO_PKG_VERSION").to_string(),
24 }
25 }
26}
27
28impl RuntimeDep {
29 fn to_cargo_dep(&self) -> String {
31 match self {
32 RuntimeDep::CratesIo { version } => {
33 format!("sage-runtime = \"{version}\"")
34 }
35 RuntimeDep::Path { path } => {
36 format!("sage-runtime = {{ path = \"{path}\" }}")
37 }
38 }
39 }
40}
41
42pub struct GeneratedProject {
44 pub main_rs: String,
46 pub cargo_toml: String,
48}
49
50pub fn generate(program: &Program, project_name: &str) -> GeneratedProject {
52 generate_with_config(program, project_name, RuntimeDep::default())
53}
54
55pub fn generate_with_config(
57 program: &Program,
58 project_name: &str,
59 runtime_dep: RuntimeDep,
60) -> GeneratedProject {
61 let mut gen = Generator::new(runtime_dep);
62 let main_rs = gen.generate_program(program);
63 let cargo_toml = gen.generate_cargo_toml(project_name);
64 GeneratedProject {
65 main_rs,
66 cargo_toml,
67 }
68}
69
70pub fn generate_module_tree(tree: &ModuleTree, project_name: &str) -> GeneratedProject {
75 generate_module_tree_with_config(tree, project_name, RuntimeDep::default())
76}
77
78pub fn generate_module_tree_with_config(
80 tree: &ModuleTree,
81 project_name: &str,
82 runtime_dep: RuntimeDep,
83) -> GeneratedProject {
84 let mut gen = Generator::new(runtime_dep);
85 let main_rs = gen.generate_module_tree(tree);
86 let cargo_toml = gen.generate_cargo_toml(project_name);
87 GeneratedProject {
88 main_rs,
89 cargo_toml,
90 }
91}
92
93pub struct GeneratedTestProject {
95 pub main_rs: String,
97 pub cargo_toml: String,
99}
100
101pub fn generate_test_program(program: &Program, test_name: &str) -> GeneratedTestProject {
103 generate_test_program_with_config(program, test_name, RuntimeDep::default())
104}
105
106pub fn generate_test_program_with_config(
108 program: &Program,
109 test_name: &str,
110 runtime_dep: RuntimeDep,
111) -> GeneratedTestProject {
112 let mut gen = Generator::new(runtime_dep);
113 let main_rs = gen.generate_test_binary(program);
114 let cargo_toml = gen.generate_test_cargo_toml(test_name);
115 GeneratedTestProject {
116 main_rs,
117 cargo_toml,
118 }
119}
120
121struct Generator {
122 emit: Emitter,
123 runtime_dep: RuntimeDep,
124 reassigned_vars: std::collections::HashSet<String>,
126 agents_with_error_handlers: std::collections::HashSet<String>,
128}
129
130impl Generator {
131 fn new(runtime_dep: RuntimeDep) -> Self {
132 Self {
133 emit: Emitter::new(),
134 runtime_dep,
135 reassigned_vars: std::collections::HashSet::new(),
136 agents_with_error_handlers: std::collections::HashSet::new(),
137 }
138 }
139
140 fn collect_reassigned_vars(&mut self, block: &Block) {
142 for stmt in &block.stmts {
143 self.collect_reassigned_vars_stmt(stmt);
144 }
145 }
146
147 fn collect_reassigned_vars_stmt(&mut self, stmt: &Stmt) {
148 match stmt {
149 Stmt::Assign { name, .. } => {
150 self.reassigned_vars.insert(name.name.clone());
151 }
152 Stmt::If {
153 then_block,
154 else_block,
155 ..
156 } => {
157 self.collect_reassigned_vars(then_block);
158 if let Some(else_branch) = else_block {
159 match else_branch {
160 sage_parser::ElseBranch::Block(block) => {
161 self.collect_reassigned_vars(block)
162 }
163 sage_parser::ElseBranch::ElseIf(stmt) => {
164 self.collect_reassigned_vars_stmt(stmt)
165 }
166 }
167 }
168 }
169 Stmt::While { body, .. } | Stmt::Loop { body, .. } => {
170 self.collect_reassigned_vars(body);
171 }
172 Stmt::For { body, .. } => {
173 self.collect_reassigned_vars(body);
174 }
175 _ => {}
176 }
177 }
178
179 fn generate_program(&mut self, program: &Program) -> String {
180 self.emit
182 .writeln("//! Generated by Sage compiler. Do not edit.");
183 self.emit.blank_line();
184 self.emit.writeln("use sage_runtime::prelude::*;");
185 self.emit.blank_line();
186
187 for const_decl in &program.consts {
189 self.generate_const(const_decl);
190 self.emit.blank_line();
191 }
192
193 for enum_decl in &program.enums {
195 self.generate_enum(enum_decl);
196 self.emit.blank_line();
197 }
198
199 for record in &program.records {
201 self.generate_record(record);
202 self.emit.blank_line();
203 }
204
205 for func in &program.functions {
207 self.generate_function(func);
208 self.emit.blank_line();
209 }
210
211 for agent in &program.agents {
213 self.generate_agent(agent);
214 self.emit.blank_line();
215 }
216
217 if let Some(run_agent) = &program.run_agent {
219 if let Some(agent) = program
221 .agents
222 .iter()
223 .find(|a| a.name.name == run_agent.name)
224 {
225 self.generate_main(agent);
226 }
227 }
228
229 std::mem::take(&mut self.emit).finish()
230 }
231
232 fn generate_module_tree(&mut self, tree: &ModuleTree) -> String {
233 self.emit
235 .writeln("//! Generated by Sage compiler. Do not edit.");
236 self.emit.blank_line();
237 self.emit.writeln("use sage_runtime::prelude::*;");
238 self.emit.blank_line();
239
240 for (path, module) in &tree.modules {
246 if path != &tree.root {
247 self.emit.write("// Module: ");
248 if path.is_empty() {
249 self.emit.writeln("(root)");
250 } else {
251 self.emit.writeln(&path.join("::"));
252 }
253
254 for const_decl in &module.program.consts {
255 self.generate_const(const_decl);
256 self.emit.blank_line();
257 }
258
259 for enum_decl in &module.program.enums {
260 self.generate_enum(enum_decl);
261 self.emit.blank_line();
262 }
263
264 for record in &module.program.records {
265 self.generate_record(record);
266 self.emit.blank_line();
267 }
268
269 for func in &module.program.functions {
270 self.generate_function(func);
271 self.emit.blank_line();
272 }
273
274 for agent in &module.program.agents {
275 self.generate_agent(agent);
276 self.emit.blank_line();
277 }
278 }
279 }
280
281 if let Some(root_module) = tree.modules.get(&tree.root) {
283 self.emit.writeln("// Root module");
284
285 for const_decl in &root_module.program.consts {
286 self.generate_const(const_decl);
287 self.emit.blank_line();
288 }
289
290 for enum_decl in &root_module.program.enums {
291 self.generate_enum(enum_decl);
292 self.emit.blank_line();
293 }
294
295 for record in &root_module.program.records {
296 self.generate_record(record);
297 self.emit.blank_line();
298 }
299
300 for func in &root_module.program.functions {
301 self.generate_function(func);
302 self.emit.blank_line();
303 }
304
305 for agent in &root_module.program.agents {
306 self.generate_agent(agent);
307 self.emit.blank_line();
308 }
309
310 if let Some(run_agent) = &root_module.program.run_agent {
312 if let Some(agent) = root_module
314 .program
315 .agents
316 .iter()
317 .find(|a| a.name.name == run_agent.name)
318 {
319 self.generate_main(agent);
320 }
321 }
322 }
323
324 std::mem::take(&mut self.emit).finish()
325 }
326
327 fn generate_cargo_toml(&self, name: &str) -> String {
328 let runtime_dep = self.runtime_dep.to_cargo_dep();
329 format!(
330 r#"[package]
331name = "{name}"
332version = "0.1.0"
333edition = "2021"
334
335[dependencies]
336{runtime_dep}
337tokio = {{ version = "1", features = ["full"] }}
338serde = {{ version = "1", features = ["derive"] }}
339serde_json = "1"
340
341# Standalone project, not part of parent workspace
342[workspace]
343"#
344 )
345 }
346
347 fn generate_test_binary(&mut self, program: &Program) -> String {
352 self.emit
354 .writeln("//! Generated test file by Sage compiler. Do not edit.");
355 self.emit.blank_line();
356 self.emit.writeln("#![allow(unused_imports, dead_code)]");
357 self.emit.blank_line();
358 self.emit.writeln("use sage_runtime::prelude::*;");
359 self.emit.blank_line();
360
361 for const_decl in &program.consts {
363 self.generate_const(const_decl);
364 self.emit.blank_line();
365 }
366
367 for enum_decl in &program.enums {
369 self.generate_enum(enum_decl);
370 self.emit.blank_line();
371 }
372
373 for record in &program.records {
375 self.generate_record(record);
376 self.emit.blank_line();
377 }
378
379 for func in &program.functions {
381 self.generate_function(func);
382 self.emit.blank_line();
383 }
384
385 for agent in &program.agents {
387 self.generate_agent(agent);
388 self.emit.blank_line();
389 }
390
391 let (serial_tests, concurrent_tests): (Vec<_>, Vec<_>) =
393 program.tests.iter().partition(|t| t.is_serial);
394
395 for test in &concurrent_tests {
397 self.generate_test_function(test);
398 self.emit.blank_line();
399 }
400
401 for test in &serial_tests {
403 self.generate_test_function(test);
404 self.emit.blank_line();
405 }
406
407 self.emit.writeln("fn main() {}");
409
410 std::mem::take(&mut self.emit).finish()
411 }
412
413 fn generate_test_cargo_toml(&self, name: &str) -> String {
414 let runtime_dep = self.runtime_dep.to_cargo_dep();
415 format!(
416 r#"[package]
417name = "{name}"
418version = "0.1.0"
419edition = "2021"
420
421[dependencies]
422{runtime_dep}
423tokio = {{ version = "1", features = ["full"] }}
424serde = {{ version = "1", features = ["derive"] }}
425serde_json = "1"
426
427# Standalone project, not part of parent workspace
428[workspace]
429"#
430 )
431 }
432
433 fn generate_test_function(&mut self, test: &TestDecl) {
434 let mock_infers = self.collect_mock_infers(&test.body);
436 let mock_tools = self.collect_mock_tools(&test.body);
437
438 self.emit.writeln("#[tokio::test]");
440 let test_fn_name = self.sanitize_test_name(&test.name);
442 self.emit.write("async fn ");
443 self.emit.write(&test_fn_name);
444 self.emit.writeln("() {");
445 self.emit.indent();
446
447 if !mock_infers.is_empty() {
449 self.emit
450 .writeln("let _mock_client = MockLlmClient::with_responses(vec![");
451 self.emit.indent();
452 for mock in &mock_infers {
453 match mock {
454 MockValue::Value(expr) => {
455 self.emit.write("MockResponse::value(");
456 self.generate_expr(expr);
457 self.emit.writeln("),");
458 }
459 MockValue::Fail(expr) => {
460 self.emit.write("MockResponse::fail(");
461 self.generate_expr(expr);
462 self.emit.writeln("),");
463 }
464 }
465 }
466 self.emit.dedent();
467 self.emit.writeln("]);");
468 self.emit.blank_line();
469 }
470
471 if !mock_tools.is_empty() {
473 self.emit
474 .writeln("let _mock_tools = MockToolRegistry::new();");
475 for (tool_name, fn_name, value) in &mock_tools {
476 self.emit.write("_mock_tools.register(\"");
477 self.emit.write(tool_name);
478 self.emit.write("\", \"");
479 self.emit.write(fn_name);
480 self.emit.write("\", ");
481 match value {
482 MockValue::Value(expr) => {
483 self.emit.write("MockResponse::value(");
484 self.generate_expr(expr);
485 self.emit.write(")");
486 }
487 MockValue::Fail(expr) => {
488 self.emit.write("MockResponse::fail(");
489 self.generate_expr(expr);
490 self.emit.write(")");
491 }
492 }
493 self.emit.writeln(");");
494 }
495 self.emit.blank_line();
496 }
497
498 self.generate_test_block(&test.body);
500
501 self.emit.dedent();
502 self.emit.writeln("}");
503 }
504
505 fn collect_mock_infers(&self, block: &Block) -> Vec<MockValue> {
506 let mut mocks = Vec::new();
507 for stmt in &block.stmts {
508 if let Stmt::MockDivine { value, .. } = stmt {
509 mocks.push(value.clone());
510 }
511 }
512 mocks
513 }
514
515 fn collect_mock_tools(&self, block: &Block) -> Vec<(String, String, MockValue)> {
516 let mut mocks = Vec::new();
517 for stmt in &block.stmts {
518 if let Stmt::MockTool {
519 tool_name,
520 fn_name,
521 value,
522 ..
523 } = stmt
524 {
525 mocks.push((tool_name.name.clone(), fn_name.name.clone(), value.clone()));
526 }
527 }
528 mocks
529 }
530
531 fn generate_test_block(&mut self, block: &Block) {
532 for stmt in &block.stmts {
533 if matches!(stmt, Stmt::MockDivine { .. } | Stmt::MockTool { .. }) {
535 continue;
536 }
537 self.generate_test_stmt(stmt);
538 }
539 }
540
541 fn generate_test_stmt(&mut self, stmt: &Stmt) {
542 match stmt {
543 Stmt::Expr { expr, .. } => {
545 if let Expr::Call { name, args, .. } = expr {
546 if self.is_assertion_builtin(&name.name) {
547 self.generate_assertion(&name.name, args);
548 return;
549 }
550 }
551 self.generate_expr(expr);
553 self.emit.writeln(";");
554 }
555 _ => self.generate_stmt(stmt),
557 }
558 }
559
560 fn is_assertion_builtin(&self, name: &str) -> bool {
561 matches!(
562 name,
563 "assert"
564 | "assert_eq"
565 | "assert_neq"
566 | "assert_gt"
567 | "assert_lt"
568 | "assert_gte"
569 | "assert_lte"
570 | "assert_true"
571 | "assert_false"
572 | "assert_contains"
573 | "assert_not_contains"
574 | "assert_empty"
575 | "assert_not_empty"
576 | "assert_starts_with"
577 | "assert_ends_with"
578 | "assert_len"
579 | "assert_empty_list"
580 | "assert_not_empty_list"
581 | "assert_fails"
582 )
583 }
584
585 fn generate_assertion(&mut self, name: &str, args: &[Expr]) {
586 match name {
587 "assert" | "assert_true" => {
588 self.emit.write("assert!(");
589 if !args.is_empty() {
590 self.generate_expr(&args[0]);
591 }
592 self.emit.writeln(");");
593 }
594 "assert_false" => {
595 self.emit.write("assert!(!");
596 if !args.is_empty() {
597 self.generate_expr(&args[0]);
598 }
599 self.emit.writeln(");");
600 }
601 "assert_eq" => {
602 self.emit.write("assert_eq!(");
603 if args.len() >= 2 {
604 self.generate_expr(&args[0]);
605 self.emit.write(", ");
606 self.generate_expr(&args[1]);
607 }
608 self.emit.writeln(");");
609 }
610 "assert_neq" => {
611 self.emit.write("assert_ne!(");
612 if args.len() >= 2 {
613 self.generate_expr(&args[0]);
614 self.emit.write(", ");
615 self.generate_expr(&args[1]);
616 }
617 self.emit.writeln(");");
618 }
619 "assert_gt" => {
620 self.emit.write("assert!(");
621 if args.len() >= 2 {
622 self.generate_expr(&args[0]);
623 self.emit.write(" > ");
624 self.generate_expr(&args[1]);
625 }
626 self.emit.writeln(");");
627 }
628 "assert_lt" => {
629 self.emit.write("assert!(");
630 if args.len() >= 2 {
631 self.generate_expr(&args[0]);
632 self.emit.write(" < ");
633 self.generate_expr(&args[1]);
634 }
635 self.emit.writeln(");");
636 }
637 "assert_gte" => {
638 self.emit.write("assert!(");
639 if args.len() >= 2 {
640 self.generate_expr(&args[0]);
641 self.emit.write(" >= ");
642 self.generate_expr(&args[1]);
643 }
644 self.emit.writeln(");");
645 }
646 "assert_lte" => {
647 self.emit.write("assert!(");
648 if args.len() >= 2 {
649 self.generate_expr(&args[0]);
650 self.emit.write(" <= ");
651 self.generate_expr(&args[1]);
652 }
653 self.emit.writeln(");");
654 }
655 "assert_contains" => {
656 self.emit.write("assert!(");
657 if args.len() >= 2 {
658 self.generate_expr(&args[0]);
659 self.emit.write(".contains(&");
660 self.generate_expr(&args[1]);
661 self.emit.write(")");
662 }
663 self.emit.writeln(");");
664 }
665 "assert_not_contains" => {
666 self.emit.write("assert!(!");
667 if args.len() >= 2 {
668 self.generate_expr(&args[0]);
669 self.emit.write(".contains(&");
670 self.generate_expr(&args[1]);
671 self.emit.write(")");
672 }
673 self.emit.writeln(");");
674 }
675 "assert_empty" => {
676 self.emit.write("assert!(");
677 if !args.is_empty() {
678 self.generate_expr(&args[0]);
679 }
680 self.emit.writeln(".is_empty());");
681 }
682 "assert_not_empty" => {
683 self.emit.write("assert!(!");
684 if !args.is_empty() {
685 self.generate_expr(&args[0]);
686 }
687 self.emit.writeln(".is_empty());");
688 }
689 "assert_starts_with" => {
690 self.emit.write("assert!(");
691 if args.len() >= 2 {
692 self.generate_expr(&args[0]);
693 self.emit.write(".starts_with(&");
694 self.generate_expr(&args[1]);
695 self.emit.write(")");
696 }
697 self.emit.writeln(");");
698 }
699 "assert_ends_with" => {
700 self.emit.write("assert!(");
701 if args.len() >= 2 {
702 self.generate_expr(&args[0]);
703 self.emit.write(".ends_with(&");
704 self.generate_expr(&args[1]);
705 self.emit.write(")");
706 }
707 self.emit.writeln(");");
708 }
709 "assert_len" => {
710 self.emit.write("assert_eq!(");
711 if args.len() >= 2 {
712 self.generate_expr(&args[0]);
713 self.emit.write(".len() as i64, ");
714 self.generate_expr(&args[1]);
715 }
716 self.emit.writeln(");");
717 }
718 "assert_empty_list" => {
719 self.emit.write("assert!(");
720 if !args.is_empty() {
721 self.generate_expr(&args[0]);
722 }
723 self.emit.writeln(".is_empty());");
724 }
725 "assert_not_empty_list" => {
726 self.emit.write("assert!(!");
727 if !args.is_empty() {
728 self.generate_expr(&args[0]);
729 }
730 self.emit.writeln(".is_empty());");
731 }
732 "assert_fails" => {
733 self.emit.writeln("{");
735 self.emit.indent();
736 self.emit.write("let result = ");
737 if !args.is_empty() {
738 self.generate_expr(&args[0]);
739 }
740 self.emit.writeln(";");
741 self.emit.writeln(
742 "assert!(result.is_err(), \"Expected operation to fail but it succeeded\");",
743 );
744 self.emit.dedent();
745 self.emit.writeln("}");
746 }
747 _ => {
748 self.emit.write(name);
750 self.emit.write("(");
751 for (i, arg) in args.iter().enumerate() {
752 if i > 0 {
753 self.emit.write(", ");
754 }
755 self.generate_expr(arg);
756 }
757 self.emit.writeln(");");
758 }
759 }
760 }
761
762 fn sanitize_test_name(&self, name: &str) -> String {
763 name.chars()
765 .map(|c| if c.is_alphanumeric() { c } else { '_' })
766 .collect::<String>()
767 .to_lowercase()
768 }
769
770 fn generate_const(&mut self, const_decl: &ConstDecl) {
771 if const_decl.is_pub {
772 self.emit.write("pub ");
773 }
774 self.emit.write("const ");
775 self.emit.write(&const_decl.name.name);
776 self.emit.write(": ");
777 let is_string = matches!(const_decl.ty, TypeExpr::String);
779 if is_string {
780 self.emit.write("&'static str");
781 } else {
782 self.emit_type(&const_decl.ty);
783 }
784 self.emit.write(" = ");
785 if is_string {
787 if let Expr::Literal {
788 value: Literal::String(s),
789 ..
790 } = &const_decl.value
791 {
792 self.emit.write("\"");
793 self.emit
794 .write(&s.replace('\\', "\\\\").replace('"', "\\\""));
795 self.emit.write("\"");
796 } else {
797 self.generate_expr(&const_decl.value);
798 }
799 } else {
800 self.generate_expr(&const_decl.value);
801 }
802 self.emit.writeln(";");
803 }
804
805 fn generate_enum(&mut self, enum_decl: &EnumDecl) {
806 if enum_decl.is_pub {
807 self.emit.write("pub ");
808 }
809 if enum_decl.type_params.is_empty() {
811 self.emit
812 .writeln("#[derive(Debug, Clone, Copy, PartialEq, Eq)]");
813 } else {
814 self.emit.writeln("#[derive(Debug, Clone, PartialEq, Eq)]");
815 }
816 self.emit.write("enum ");
817 self.emit.write(&enum_decl.name.name);
818 if !enum_decl.type_params.is_empty() {
820 self.emit.write("<");
821 for (i, param) in enum_decl.type_params.iter().enumerate() {
822 if i > 0 {
823 self.emit.write(", ");
824 }
825 self.emit.write(¶m.name);
826 }
827 self.emit.write(">");
828 }
829 self.emit.writeln(" {");
830 self.emit.indent();
831 for variant in &enum_decl.variants {
832 self.emit.write(&variant.name.name);
833 if let Some(payload_ty) = &variant.payload {
834 self.emit.write("(");
835 self.emit_type(payload_ty);
836 self.emit.write(")");
837 }
838 self.emit.writeln(",");
839 }
840 self.emit.dedent();
841 self.emit.writeln("}");
842 }
843
844 fn generate_record(&mut self, record: &RecordDecl) {
845 if record.is_pub {
846 self.emit.write("pub ");
847 }
848 self.emit.writeln("#[derive(Debug, Clone)]");
849 self.emit.write("struct ");
850 self.emit.write(&record.name.name);
851 if !record.type_params.is_empty() {
853 self.emit.write("<");
854 for (i, param) in record.type_params.iter().enumerate() {
855 if i > 0 {
856 self.emit.write(", ");
857 }
858 self.emit.write(¶m.name);
859 }
860 self.emit.write(">");
861 }
862 self.emit.writeln(" {");
863 self.emit.indent();
864 for field in &record.fields {
865 self.emit.write(&field.name.name);
866 self.emit.write(": ");
867 self.emit_type(&field.ty);
868 self.emit.writeln(",");
869 }
870 self.emit.dedent();
871 self.emit.writeln("}");
872 }
873
874 fn generate_function(&mut self, func: &FnDecl) {
875 if func.is_pub {
877 self.emit.write("pub ");
878 }
879 self.emit.write("fn ");
880 self.emit.write(&func.name.name);
881 if !func.type_params.is_empty() {
883 self.emit.write("<");
884 for (i, param) in func.type_params.iter().enumerate() {
885 if i > 0 {
886 self.emit.write(", ");
887 }
888 self.emit.write(¶m.name);
889 }
890 self.emit.write(">");
891 }
892 self.emit.write("(");
893
894 for (i, param) in func.params.iter().enumerate() {
895 if i > 0 {
896 self.emit.write(", ");
897 }
898 self.emit.write(¶m.name.name);
899 self.emit.write(": ");
900 self.emit_type(¶m.ty);
901 }
902
903 self.emit.write(") -> ");
904
905 if func.is_fallible {
907 self.emit.write("SageResult<");
908 self.emit_type(&func.return_ty);
909 self.emit.write(">");
910 } else {
911 self.emit_type(&func.return_ty);
912 }
913
914 self.emit.write(" ");
915 self.generate_block(&func.body);
916 }
917
918 fn generate_agent(&mut self, agent: &AgentDecl) {
919 let name = &agent.name.name;
920
921 let has_error_handler = agent
923 .handlers
924 .iter()
925 .any(|h| matches!(h.event, EventKind::Error { .. }));
926 if has_error_handler {
927 self.agents_with_error_handlers.insert(name.clone());
928 }
929
930 let has_tools = !agent.tool_uses.is_empty();
932 let needs_struct_body = !agent.beliefs.is_empty() || has_tools;
933
934 if agent.is_pub {
936 self.emit.write("pub ");
937 }
938 self.emit.write("struct ");
939 self.emit.write(name);
940 if !needs_struct_body {
941 self.emit.writeln(";");
942 } else {
943 self.emit.writeln(" {");
944 self.emit.indent();
945
946 for tool_use in &agent.tool_uses {
948 self.emit.write(&tool_use.name.to_lowercase());
950 self.emit.write(": ");
951 self.emit.write(&tool_use.name);
952 self.emit.writeln("Client,");
953 }
954
955 for belief in &agent.beliefs {
957 self.emit.write(&belief.name.name);
958 self.emit.write(": ");
959 self.emit_type(&belief.ty);
960 self.emit.writeln(",");
961 }
962 self.emit.dedent();
963 self.emit.writeln("}");
964 }
965 self.emit.blank_line();
966
967 let output_type = self.infer_agent_output_type(agent);
969
970 self.emit.write("impl ");
972 self.emit.write(name);
973 self.emit.writeln(" {");
974 self.emit.indent();
975
976 for handler in &agent.handlers {
978 match &handler.event {
979 EventKind::Start => {
980 self.emit
981 .write("async fn on_start(&self, ctx: &mut AgentContext<");
982 self.emit.write(&output_type);
983 self.emit.write(">) -> SageResult<");
984 self.emit.write(&output_type);
985 self.emit.writeln("> {");
986 self.emit.indent();
987 self.generate_block_contents(&handler.body);
988 self.emit.dedent();
989 self.emit.writeln("}");
990 }
991
992 EventKind::Error { param_name } => {
994 self.emit.write("async fn on_error(&self, _");
995 self.emit.write(¶m_name.name);
996 self.emit.write(": SageError, ctx: &mut AgentContext<");
997 self.emit.write(&output_type);
998 self.emit.write(">) -> SageResult<");
999 self.emit.write(&output_type);
1000 self.emit.writeln("> {");
1001 self.emit.indent();
1002 self.generate_block_contents(&handler.body);
1003 self.emit.dedent();
1004 self.emit.writeln("}");
1005 }
1006
1007 EventKind::Stop => {
1009 self.emit.writeln("async fn on_stop(&self) {");
1010 self.emit.indent();
1011 self.generate_block_contents(&handler.body);
1012 self.emit.dedent();
1013 self.emit.writeln("}");
1014 }
1015
1016 _ => {}
1018 }
1019 }
1020
1021 self.emit.dedent();
1022 self.emit.writeln("}");
1023 }
1024
1025 fn generate_main(&mut self, agent: &AgentDecl) {
1026 let entry_agent = &agent.name.name;
1027 let has_error_handler = agent
1028 .handlers
1029 .iter()
1030 .any(|h| matches!(h.event, EventKind::Error { .. }));
1031
1032 let has_stop_handler = agent
1033 .handlers
1034 .iter()
1035 .any(|h| matches!(h.event, EventKind::Stop));
1036
1037 let has_tools = !agent.tool_uses.is_empty();
1039
1040 self.emit.writeln("#[tokio::main]");
1041 self.emit
1042 .writeln("async fn main() -> Result<(), Box<dyn std::error::Error>> {");
1043 self.emit.indent();
1044
1045 self.emit.writeln("sage_runtime::trace::init();");
1047 self.emit.writeln("");
1048
1049 let agent_construct = if has_tools {
1051 let mut s = format!("{entry_agent} {{ ");
1052 for (i, tool_use) in agent.tool_uses.iter().enumerate() {
1053 if i > 0 {
1054 s.push_str(", ");
1055 }
1056 s.push_str(&tool_use.name.to_lowercase());
1058 s.push_str(": ");
1059 s.push_str(&tool_use.name);
1060 s.push_str("Client::from_env()");
1061 }
1062 s.push_str(" }");
1063 s
1064 } else {
1065 entry_agent.to_string()
1066 };
1067
1068 self.emit
1070 .writeln("let ctrl_c = async { tokio::signal::ctrl_c().await.ok() };");
1071
1072 self.emit.writeln("#[cfg(unix)]");
1073 self.emit.writeln("let terminate = async {");
1074 self.emit.indent();
1075 self.emit.writeln(
1076 "if let Ok(mut s) = tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate()) {",
1077 );
1078 self.emit.indent();
1079 self.emit.writeln("s.recv().await;");
1080 self.emit.dedent();
1081 self.emit.writeln("} else {");
1082 self.emit.indent();
1083 self.emit.writeln("std::future::pending::<()>().await;");
1084 self.emit.dedent();
1085 self.emit.writeln("}");
1086 self.emit.dedent();
1087 self.emit.writeln("};");
1088 self.emit.writeln("#[cfg(not(unix))]");
1089 self.emit
1090 .writeln("let terminate = std::future::pending::<()>();");
1091 self.emit.writeln("");
1092
1093 self.emit
1094 .writeln("let handle = sage_runtime::spawn(|mut ctx| async move {");
1095 self.emit.indent();
1096 self.emit.write("let agent = ");
1097 self.emit.write(&agent_construct);
1098 self.emit.writeln(";");
1099
1100 if has_error_handler {
1101 self.emit
1103 .writeln("let result = match agent.on_start(&mut ctx).await {");
1104 self.emit.indent();
1105 self.emit.writeln("Ok(result) => Ok(result),");
1106 self.emit
1107 .writeln("Err(e) => agent.on_error(e, &mut ctx).await,");
1108 self.emit.dedent();
1109 self.emit.writeln("};");
1110 } else {
1111 self.emit
1113 .writeln("let result = agent.on_start(&mut ctx).await;");
1114 }
1115
1116 if has_stop_handler {
1117 self.emit.writeln("agent.on_stop().await;");
1119 }
1120
1121 self.emit.writeln("result");
1122 self.emit.dedent();
1123 self.emit.writeln("});");
1124
1125 self.emit.writeln("");
1127 self.emit.writeln("let _result = tokio::select! {");
1128 self.emit.indent();
1129 self.emit.writeln("result = handle.result() => result?,");
1130 self.emit.writeln("_ = ctrl_c => {");
1131 self.emit.indent();
1132 self.emit
1133 .writeln("eprintln!(\"\\nReceived interrupt signal, shutting down...\");");
1134 self.emit.writeln("std::process::exit(0);");
1135 self.emit.dedent();
1136 self.emit.writeln("}");
1137 self.emit.writeln("_ = terminate => {");
1138 self.emit.indent();
1139 self.emit
1140 .writeln("eprintln!(\"Received terminate signal, shutting down...\");");
1141 self.emit.writeln("std::process::exit(0);");
1142 self.emit.dedent();
1143 self.emit.writeln("}");
1144 self.emit.dedent();
1145 self.emit.writeln("};");
1146 self.emit.writeln("Ok(())");
1147
1148 self.emit.dedent();
1149 self.emit.writeln("}");
1150 }
1151
1152 fn generate_block(&mut self, block: &Block) {
1153 self.emit.open_brace();
1154 self.generate_block_contents(block);
1155 self.emit.close_brace();
1156 }
1157
1158 fn generate_block_inline(&mut self, block: &Block) {
1159 self.emit.open_brace();
1160 self.generate_block_contents(block);
1161 self.emit.close_brace_inline();
1162 }
1163
1164 fn generate_block_contents(&mut self, block: &Block) {
1165 self.collect_reassigned_vars(block);
1167 for stmt in &block.stmts {
1168 self.generate_stmt(stmt);
1169 }
1170 }
1171
1172 fn generate_stmt(&mut self, stmt: &Stmt) {
1173 match stmt {
1174 Stmt::Let {
1175 name, ty, value, ..
1176 } => {
1177 if self.reassigned_vars.contains(&name.name) {
1179 self.emit.write("let mut ");
1180 } else {
1181 self.emit.write("let ");
1182 }
1183 if ty.is_some() {
1184 self.emit.write(&name.name);
1185 self.emit.write(": ");
1186 self.emit_type(ty.as_ref().unwrap());
1187 } else {
1188 self.emit.write(&name.name);
1189 }
1190 self.emit.write(" = ");
1191 self.generate_expr(value);
1192 self.emit.writeln(";");
1193 }
1194
1195 Stmt::Assign { name, value, .. } => {
1196 self.emit.write(&name.name);
1197 self.emit.write(" = ");
1198 self.generate_expr(value);
1199 self.emit.writeln(";");
1200 }
1201
1202 Stmt::Return { value, .. } => {
1203 self.emit.write("return ");
1204 if let Some(expr) = value {
1205 self.generate_expr(expr);
1206 }
1207 self.emit.writeln(";");
1208 }
1209
1210 Stmt::If {
1211 condition,
1212 then_block,
1213 else_block,
1214 ..
1215 } => {
1216 self.emit.write("if ");
1217 self.generate_expr(condition);
1218 self.emit.write(" ");
1219 if else_block.is_some() {
1220 self.generate_block_inline(then_block);
1221 self.emit.write(" else ");
1222 match else_block.as_ref().unwrap() {
1223 sage_parser::ElseBranch::Block(block) => {
1224 self.generate_block(block);
1225 }
1226 sage_parser::ElseBranch::ElseIf(stmt) => {
1227 self.generate_stmt(stmt);
1228 }
1229 }
1230 } else {
1231 self.generate_block(then_block);
1232 }
1233 }
1234
1235 Stmt::For {
1236 pattern,
1237 iter,
1238 body,
1239 ..
1240 } => {
1241 self.emit.write("for ");
1242 self.emit_pattern(pattern);
1243 self.emit.write(" in ");
1244 self.generate_expr(iter);
1245 self.emit.write(" ");
1246 self.generate_block(body);
1247 }
1248
1249 Stmt::While {
1250 condition, body, ..
1251 } => {
1252 self.emit.write("while ");
1253 self.generate_expr(condition);
1254 self.emit.write(" ");
1255 self.generate_block(body);
1256 }
1257
1258 Stmt::Loop { body, .. } => {
1259 self.emit.write("loop ");
1260 self.generate_block(body);
1261 }
1262
1263 Stmt::Break { .. } => {
1264 self.emit.writeln("break;");
1265 }
1266
1267 Stmt::Expr { expr, .. } => {
1268 if let Expr::Yield { value, .. } = expr {
1270 self.emit.write("return ctx.emit(");
1271 self.generate_expr(value);
1272 self.emit.writeln(");");
1273 } else {
1274 self.generate_expr(expr);
1275 self.emit.writeln(";");
1276 }
1277 }
1278
1279 Stmt::LetTuple { names, value, .. } => {
1280 self.emit.write("let (");
1281 for (i, name) in names.iter().enumerate() {
1282 if i > 0 {
1283 self.emit.write(", ");
1284 }
1285 self.emit.write(&name.name);
1286 }
1287 self.emit.write(") = ");
1288 self.generate_expr(value);
1289 self.emit.writeln(";");
1290 }
1291
1292 Stmt::MockDivine { value, .. } => {
1294 self.emit.write("// mock divine: ");
1297 match value {
1298 sage_parser::MockValue::Value(expr) => {
1299 self.generate_expr(expr);
1300 }
1301 sage_parser::MockValue::Fail(expr) => {
1302 self.emit.write("fail(");
1303 self.generate_expr(expr);
1304 self.emit.write(")");
1305 }
1306 }
1307 self.emit.writeln(";");
1308 }
1309
1310 Stmt::MockTool {
1312 tool_name,
1313 fn_name,
1314 value,
1315 ..
1316 } => {
1317 self.emit.write("// mock tool ");
1320 self.emit.write(&tool_name.name);
1321 self.emit.write(".");
1322 self.emit.write(&fn_name.name);
1323 self.emit.write(": ");
1324 match value {
1325 sage_parser::MockValue::Value(expr) => {
1326 self.generate_expr(expr);
1327 }
1328 sage_parser::MockValue::Fail(expr) => {
1329 self.emit.write("fail(");
1330 self.generate_expr(expr);
1331 self.emit.write(")");
1332 }
1333 }
1334 self.emit.writeln(";");
1335 }
1336 }
1337 }
1338
1339 fn generate_expr(&mut self, expr: &Expr) {
1340 match expr {
1341 Expr::Literal { value, .. } => {
1342 self.emit_literal(value);
1343 }
1344
1345 Expr::Var { name, .. } => {
1346 match name.name.as_str() {
1348 "PI" => self.emit.write("std::f64::consts::PI"),
1349 "E" => self.emit.write("std::f64::consts::E"),
1350 "MS_PER_SECOND" => self.emit.write("1000_i64"),
1352 "MS_PER_MINUTE" => self.emit.write("60000_i64"),
1353 "MS_PER_HOUR" => self.emit.write("3600000_i64"),
1354 "MS_PER_DAY" => self.emit.write("86400000_i64"),
1355 _ => self.emit.write(&name.name),
1356 }
1357 }
1358
1359 Expr::Binary {
1360 op, left, right, ..
1361 } => {
1362 if matches!(op, BinOp::Concat) {
1364 self.emit.write("format!(\"{}{}\", ");
1365 self.generate_expr(left);
1366 self.emit.write(", ");
1367 self.generate_expr(right);
1368 self.emit.write(")");
1369 } else {
1370 self.generate_expr(left);
1371 self.emit.write(" ");
1372 self.emit_binop(op);
1373 self.emit.write(" ");
1374 self.generate_expr(right);
1375 }
1376 }
1377
1378 Expr::Unary { op, operand, .. } => {
1379 self.emit_unaryop(op);
1380 self.generate_expr(operand);
1381 }
1382
1383 Expr::Call {
1384 name,
1385 type_args,
1386 args,
1387 ..
1388 } => {
1389 let fn_name = &name.name;
1390
1391 match fn_name.as_str() {
1393 "print" => {
1394 self.emit.write("println!(\"{}\", ");
1395 self.generate_expr(&args[0]);
1396 self.emit.write(")");
1397 }
1398 "str" => {
1399 self.generate_expr(&args[0]);
1400 self.emit.write(".to_string()");
1401 }
1402 "len" => {
1403 self.generate_expr(&args[0]);
1404 self.emit.write(".len() as i64");
1405 }
1406
1407 "split" => {
1409 self.generate_expr(&args[0]);
1410 self.emit.write(".split(&*");
1411 self.generate_expr(&args[1]);
1412 self.emit.write(").map(str::to_string).collect::<Vec<_>>()");
1413 }
1414 "lines" => {
1415 self.generate_expr(&args[0]);
1416 self.emit
1417 .write(".lines().map(str::to_string).collect::<Vec<_>>()");
1418 }
1419 "chars" => {
1420 self.generate_expr(&args[0]);
1421 self.emit
1422 .write(".chars().map(|c| c.to_string()).collect::<Vec<_>>()");
1423 }
1424 "join" => {
1425 self.generate_expr(&args[0]);
1426 self.emit.write(".join(&*");
1427 self.generate_expr(&args[1]);
1428 self.emit.write(")");
1429 }
1430 "trim" => {
1431 self.generate_expr(&args[0]);
1432 self.emit.write(".trim().to_string()");
1433 }
1434 "trim_start" => {
1435 self.generate_expr(&args[0]);
1436 self.emit.write(".trim_start().to_string()");
1437 }
1438 "trim_end" => {
1439 self.generate_expr(&args[0]);
1440 self.emit.write(".trim_end().to_string()");
1441 }
1442 "starts_with" => {
1443 self.generate_expr(&args[0]);
1444 self.emit.write(".starts_with(&*");
1445 self.generate_expr(&args[1]);
1446 self.emit.write(")");
1447 }
1448 "ends_with" => {
1449 self.generate_expr(&args[0]);
1450 self.emit.write(".ends_with(&*");
1451 self.generate_expr(&args[1]);
1452 self.emit.write(")");
1453 }
1454 "str_contains" => {
1455 self.generate_expr(&args[0]);
1456 self.emit.write(".contains(&*");
1457 self.generate_expr(&args[1]);
1458 self.emit.write(")");
1459 }
1460 "replace" => {
1461 self.generate_expr(&args[0]);
1462 self.emit.write(".replace(&*");
1463 self.generate_expr(&args[1]);
1464 self.emit.write(", &*");
1465 self.generate_expr(&args[2]);
1466 self.emit.write(")");
1467 }
1468 "replace_first" => {
1469 self.generate_expr(&args[0]);
1470 self.emit.write(".replacen(&*");
1471 self.generate_expr(&args[1]);
1472 self.emit.write(", &*");
1473 self.generate_expr(&args[2]);
1474 self.emit.write(", 1)");
1475 }
1476 "to_upper" => {
1477 self.generate_expr(&args[0]);
1478 self.emit.write(".to_uppercase()");
1479 }
1480 "to_lower" => {
1481 self.generate_expr(&args[0]);
1482 self.emit.write(".to_lowercase()");
1483 }
1484 "str_len" => {
1485 self.generate_expr(&args[0]);
1486 self.emit.write(".chars().count() as i64");
1487 }
1488 "str_slice" => {
1489 self.emit.write("sage_runtime::stdlib::str_slice(&");
1490 self.generate_expr(&args[0]);
1491 self.emit.write(", ");
1492 self.generate_expr(&args[1]);
1493 self.emit.write(", ");
1494 self.generate_expr(&args[2]);
1495 self.emit.write(")");
1496 }
1497 "str_index_of" => {
1498 self.emit.write("sage_runtime::stdlib::str_index_of(&");
1499 self.generate_expr(&args[0]);
1500 self.emit.write(", &");
1501 self.generate_expr(&args[1]);
1502 self.emit.write(")");
1503 }
1504 "str_repeat" => {
1505 self.generate_expr(&args[0]);
1506 self.emit.write(".repeat(");
1507 self.generate_expr(&args[1]);
1508 self.emit.write(" as usize)");
1509 }
1510 "str_pad_start" => {
1511 self.emit.write("sage_runtime::stdlib::str_pad_start(&");
1512 self.generate_expr(&args[0]);
1513 self.emit.write(", ");
1514 self.generate_expr(&args[1]);
1515 self.emit.write(", &");
1516 self.generate_expr(&args[2]);
1517 self.emit.write(")");
1518 }
1519 "str_pad_end" => {
1520 self.emit.write("sage_runtime::stdlib::str_pad_end(&");
1521 self.generate_expr(&args[0]);
1522 self.emit.write(", ");
1523 self.generate_expr(&args[1]);
1524 self.emit.write(", &");
1525 self.generate_expr(&args[2]);
1526 self.emit.write(")");
1527 }
1528
1529 "abs" => {
1531 self.emit.write("(");
1532 self.generate_expr(&args[0]);
1533 self.emit.write(").abs()");
1534 }
1535 "abs_float" => {
1536 self.emit.write("(");
1537 self.generate_expr(&args[0]);
1538 self.emit.write(").abs()");
1539 }
1540 "min" => {
1541 self.generate_expr(&args[0]);
1542 self.emit.write(".min(");
1543 self.generate_expr(&args[1]);
1544 self.emit.write(")");
1545 }
1546 "max" => {
1547 self.generate_expr(&args[0]);
1548 self.emit.write(".max(");
1549 self.generate_expr(&args[1]);
1550 self.emit.write(")");
1551 }
1552 "min_float" => {
1553 self.generate_expr(&args[0]);
1554 self.emit.write(".min(");
1555 self.generate_expr(&args[1]);
1556 self.emit.write(")");
1557 }
1558 "max_float" => {
1559 self.generate_expr(&args[0]);
1560 self.emit.write(".max(");
1561 self.generate_expr(&args[1]);
1562 self.emit.write(")");
1563 }
1564 "clamp" => {
1565 self.emit.write("(");
1566 self.generate_expr(&args[0]);
1567 self.emit.write(").clamp(");
1568 self.generate_expr(&args[1]);
1569 self.emit.write(", ");
1570 self.generate_expr(&args[2]);
1571 self.emit.write(")");
1572 }
1573 "clamp_float" => {
1574 self.emit.write("(");
1575 self.generate_expr(&args[0]);
1576 self.emit.write(").clamp(");
1577 self.generate_expr(&args[1]);
1578 self.emit.write(", ");
1579 self.generate_expr(&args[2]);
1580 self.emit.write(")");
1581 }
1582 "floor" => {
1583 self.generate_expr(&args[0]);
1584 self.emit.write(".floor() as i64");
1585 }
1586 "ceil" => {
1587 self.generate_expr(&args[0]);
1588 self.emit.write(".ceil() as i64");
1589 }
1590 "round" => {
1591 self.generate_expr(&args[0]);
1592 self.emit.write(".round() as i64");
1593 }
1594 "floor_float" => {
1595 self.generate_expr(&args[0]);
1596 self.emit.write(".floor()");
1597 }
1598 "ceil_float" => {
1599 self.generate_expr(&args[0]);
1600 self.emit.write(".ceil()");
1601 }
1602 "pow" => {
1603 self.emit.write("{ let __base = ");
1605 self.generate_expr(&args[0]);
1606 self.emit.write("; let __exp = ");
1607 self.generate_expr(&args[1]);
1608 self.emit
1609 .write("; if __exp < 0 { 0 } else { __base.pow(__exp as u32) } }");
1610 }
1611 "pow_float" => {
1612 self.generate_expr(&args[0]);
1613 self.emit.write(".powf(");
1614 self.generate_expr(&args[1]);
1615 self.emit.write(")");
1616 }
1617 "sqrt" => {
1618 self.generate_expr(&args[0]);
1619 self.emit.write(".sqrt()");
1620 }
1621 "int_to_float" => {
1622 self.generate_expr(&args[0]);
1623 self.emit.write(" as f64");
1624 }
1625 "float_to_int" => {
1626 self.generate_expr(&args[0]);
1627 self.emit.write(" as i64");
1628 }
1629
1630 "parse_int" => {
1632 self.generate_expr(&args[0]);
1633 self.emit
1634 .write(".trim().parse::<i64>().map_err(|e| e.to_string())");
1635 }
1636 "parse_float" => {
1637 self.generate_expr(&args[0]);
1638 self.emit
1639 .write(".trim().parse::<f64>().map_err(|e| e.to_string())");
1640 }
1641 "parse_bool" => {
1642 self.emit.write("sage_runtime::stdlib::parse_bool(&");
1643 self.generate_expr(&args[0]);
1644 self.emit.write(")");
1645 }
1646 "float_to_str" => {
1647 self.generate_expr(&args[0]);
1648 self.emit.write(".to_string()");
1649 }
1650 "bool_to_str" => {
1651 self.emit.write("if ");
1652 self.generate_expr(&args[0]);
1653 self.emit
1654 .write(" { \"true\".to_string() } else { \"false\".to_string() }");
1655 }
1656 "int_to_str" => {
1657 self.emit.write("(");
1658 self.generate_expr(&args[0]);
1659 self.emit.write(").to_string()");
1660 }
1661
1662 "map" => {
1664 self.generate_expr(&args[0]);
1665 self.emit.write(".into_iter().map(");
1666 self.generate_expr(&args[1]);
1667 self.emit.write(").collect::<Vec<_>>()");
1668 }
1669 "filter" => {
1670 self.generate_expr(&args[0]);
1671 self.emit.write(".into_iter().filter(|__x| (");
1672 self.generate_expr(&args[1]);
1673 self.emit.write(")((__x).clone())).collect::<Vec<_>>()");
1674 }
1675 "reduce" => {
1676 self.generate_expr(&args[0]);
1677 self.emit.write(".into_iter().fold(");
1678 self.generate_expr(&args[1]);
1679 self.emit.write(", ");
1680 self.generate_expr(&args[2]);
1681 self.emit.write(")");
1682 }
1683 "any" => {
1684 self.generate_expr(&args[0]);
1685 self.emit.write(".into_iter().any(|__x| (");
1686 self.generate_expr(&args[1]);
1687 self.emit.write(")((__x).clone()))");
1688 }
1689 "all" => {
1690 self.generate_expr(&args[0]);
1691 self.emit.write(".into_iter().all(|__x| (");
1692 self.generate_expr(&args[1]);
1693 self.emit.write(")((__x).clone()))");
1694 }
1695 "find" => {
1696 self.generate_expr(&args[0]);
1697 self.emit.write(".into_iter().find(|__x| (");
1698 self.generate_expr(&args[1]);
1699 self.emit.write(")((__x).clone()))");
1700 }
1701 "flat_map" => {
1702 self.generate_expr(&args[0]);
1703 self.emit.write(".into_iter().flat_map(");
1704 self.generate_expr(&args[1]);
1705 self.emit.write(").collect::<Vec<_>>()");
1706 }
1707 "zip" => {
1708 self.generate_expr(&args[0]);
1709 self.emit.write(".into_iter().zip(");
1710 self.generate_expr(&args[1]);
1711 self.emit.write(".into_iter()).collect::<Vec<_>>()");
1712 }
1713 "sort_by" => {
1714 self.emit.write("{ let mut __v = ");
1715 self.generate_expr(&args[0]);
1716 self.emit.write("; __v.sort_by(|__a, __b| { let __cmp = (");
1717 self.generate_expr(&args[1]);
1718 self.emit.write(")((__a).clone(), (__b).clone()); if __cmp < 0 { std::cmp::Ordering::Less } else if __cmp > 0 { std::cmp::Ordering::Greater } else { std::cmp::Ordering::Equal } }); __v }");
1719 }
1720 "enumerate" => {
1721 self.generate_expr(&args[0]);
1722 self.emit
1723 .write(".into_iter().enumerate().map(|(__i, __x)| (__i as i64, __x)).collect::<Vec<_>>()");
1724 }
1725 "take" => {
1726 self.generate_expr(&args[0]);
1727 self.emit.write(".into_iter().take(");
1728 self.generate_expr(&args[1]);
1729 self.emit.write(" as usize).collect::<Vec<_>>()");
1730 }
1731 "drop" => {
1732 self.generate_expr(&args[0]);
1733 self.emit.write(".into_iter().skip(");
1734 self.generate_expr(&args[1]);
1735 self.emit.write(" as usize).collect::<Vec<_>>()");
1736 }
1737 "flatten" => {
1738 self.generate_expr(&args[0]);
1739 self.emit
1740 .write(".into_iter().flatten().collect::<Vec<_>>()");
1741 }
1742 "reverse" => {
1743 self.emit.write("{ let mut __v = ");
1744 self.generate_expr(&args[0]);
1745 self.emit.write("; __v.reverse(); __v }");
1746 }
1747 "unique" => {
1748 self.emit
1749 .write("{ let mut __seen = std::collections::HashSet::new(); ");
1750 self.generate_expr(&args[0]);
1751 self.emit.write(".into_iter().filter(|__x| __seen.insert(format!(\"{:?}\", __x))).collect::<Vec<_>>() }");
1752 }
1753 "count_where" => {
1754 self.generate_expr(&args[0]);
1755 self.emit.write(".into_iter().filter(|__x| (");
1756 self.generate_expr(&args[1]);
1757 self.emit.write(")((__x).clone())).count() as i64");
1758 }
1759 "sum" => {
1760 self.generate_expr(&args[0]);
1761 self.emit.write(".iter().sum::<i64>()");
1762 }
1763 "sum_floats" => {
1764 self.generate_expr(&args[0]);
1765 self.emit.write(".iter().sum::<f64>()");
1766 }
1767
1768 "range" => {
1772 self.emit.write("(");
1773 self.generate_expr(&args[0]);
1774 self.emit.write("..");
1775 self.generate_expr(&args[1]);
1776 self.emit.write(").collect::<Vec<_>>()");
1777 }
1778 "range_step" => {
1779 self.emit.write("(");
1780 self.generate_expr(&args[0]);
1781 self.emit.write("..");
1782 self.generate_expr(&args[1]);
1783 self.emit.write(").step_by(");
1784 self.generate_expr(&args[2]);
1785 self.emit.write(" as usize).collect::<Vec<_>>()");
1786 }
1787 "first" => {
1788 self.generate_expr(&args[0]);
1789 self.emit.write(".first().cloned()");
1790 }
1791 "last" => {
1792 self.generate_expr(&args[0]);
1793 self.emit.write(".last().cloned()");
1794 }
1795 "get" => {
1796 self.generate_expr(&args[0]);
1797 self.emit.write(".get(");
1798 self.generate_expr(&args[1]);
1799 self.emit.write(" as usize).cloned()");
1800 }
1801 "list_contains" => {
1802 self.generate_expr(&args[0]);
1803 self.emit.write(".contains(&");
1804 self.generate_expr(&args[1]);
1805 self.emit.write(")");
1806 }
1807 "sort" => {
1808 self.emit.write("{ let mut __v = ");
1809 self.generate_expr(&args[0]);
1810 self.emit.write("; __v.sort(); __v }");
1811 }
1812 "list_slice" => {
1813 self.emit.write("sage_runtime::stdlib::list_slice(");
1814 self.generate_expr(&args[0]);
1815 self.emit.write(", ");
1816 self.generate_expr(&args[1]);
1817 self.emit.write(", ");
1818 self.generate_expr(&args[2]);
1819 self.emit.write(")");
1820 }
1821 "chunk" => {
1822 self.generate_expr(&args[0]);
1823 self.emit.write(".chunks(");
1824 self.generate_expr(&args[1]);
1825 self.emit
1826 .write(" as usize).map(|c| c.to_vec()).collect::<Vec<_>>()");
1827 }
1828 "pop" => {
1829 self.emit.write("{ let mut __v = ");
1830 self.generate_expr(&args[0]);
1831 self.emit.write("; __v.pop() }");
1832 }
1833 "push" => {
1834 self.emit.write("{ let mut __v = ");
1835 self.generate_expr(&args[0]);
1836 self.emit.write("; __v.push(");
1837 self.generate_expr(&args[1]);
1838 self.emit.write("); __v }");
1839 }
1840 "concat" => {
1841 self.emit.write("{ let mut __v = ");
1842 self.generate_expr(&args[0]);
1843 self.emit.write("; __v.extend(");
1844 self.generate_expr(&args[1]);
1845 self.emit.write("); __v }");
1846 }
1847 "take_while" => {
1848 self.generate_expr(&args[0]);
1849 self.emit.write(".into_iter().take_while(|__x| (");
1850 self.generate_expr(&args[1]);
1851 self.emit.write(")((__x).clone())).collect::<Vec<_>>()");
1852 }
1853 "drop_while" => {
1854 self.generate_expr(&args[0]);
1855 self.emit.write(".into_iter().skip_while(|__x| (");
1856 self.generate_expr(&args[1]);
1857 self.emit.write(")((__x).clone())).collect::<Vec<_>>()");
1858 }
1859
1860 "is_some" => {
1864 self.generate_expr(&args[0]);
1865 self.emit.write(".is_some()");
1866 }
1867 "is_none" => {
1868 self.generate_expr(&args[0]);
1869 self.emit.write(".is_none()");
1870 }
1871 "unwrap" => {
1872 self.generate_expr(&args[0]);
1873 self.emit.write(".expect(\"unwrap called on None\")");
1874 }
1875 "unwrap_or" => {
1876 self.generate_expr(&args[0]);
1877 self.emit.write(".unwrap_or(");
1878 self.generate_expr(&args[1]);
1879 self.emit.write(")");
1880 }
1881 "unwrap_or_else" => {
1882 self.generate_expr(&args[0]);
1883 self.emit.write(".unwrap_or_else(");
1884 self.generate_expr(&args[1]);
1885 self.emit.write(")");
1886 }
1887 "map_option" => {
1888 self.generate_expr(&args[0]);
1889 self.emit.write(".map(");
1890 self.generate_expr(&args[1]);
1891 self.emit.write(")");
1892 }
1893 "or_option" => {
1894 self.generate_expr(&args[0]);
1895 self.emit.write(".or(");
1896 self.generate_expr(&args[1]);
1897 self.emit.write(")");
1898 }
1899
1900 "read_file" => {
1904 self.emit.write("sage_runtime::stdlib::read_file(&");
1905 self.generate_expr(&args[0]);
1906 self.emit
1907 .write(").map_err(sage_runtime::SageError::agent)?");
1908 }
1909 "write_file" => {
1910 self.emit.write("sage_runtime::stdlib::write_file(&");
1911 self.generate_expr(&args[0]);
1912 self.emit.write(", &");
1913 self.generate_expr(&args[1]);
1914 self.emit
1915 .write(").map_err(sage_runtime::SageError::agent)?");
1916 }
1917 "append_file" => {
1918 self.emit.write("sage_runtime::stdlib::append_file(&");
1919 self.generate_expr(&args[0]);
1920 self.emit.write(", &");
1921 self.generate_expr(&args[1]);
1922 self.emit
1923 .write(").map_err(sage_runtime::SageError::agent)?");
1924 }
1925 "file_exists" => {
1926 self.emit.write("sage_runtime::stdlib::file_exists(&");
1927 self.generate_expr(&args[0]);
1928 self.emit.write(")");
1929 }
1930 "delete_file" => {
1931 self.emit.write("sage_runtime::stdlib::delete_file(&");
1932 self.generate_expr(&args[0]);
1933 self.emit
1934 .write(").map_err(sage_runtime::SageError::agent)?");
1935 }
1936 "list_dir" => {
1937 self.emit.write("sage_runtime::stdlib::list_dir(&");
1938 self.generate_expr(&args[0]);
1939 self.emit
1940 .write(").map_err(sage_runtime::SageError::agent)?");
1941 }
1942 "make_dir" => {
1943 self.emit.write("sage_runtime::stdlib::make_dir(&");
1944 self.generate_expr(&args[0]);
1945 self.emit
1946 .write(").map_err(sage_runtime::SageError::agent)?");
1947 }
1948 "read_line" => {
1949 self.emit.write("sage_runtime::stdlib::read_line().map_err(sage_runtime::SageError::agent)?");
1950 }
1951 "read_all" => {
1952 self.emit.write("sage_runtime::stdlib::read_all().map_err(sage_runtime::SageError::agent)?");
1953 }
1954 "print_err" => {
1955 self.emit.write("eprintln!(\"{}\", ");
1956 self.generate_expr(&args[0]);
1957 self.emit.write(")");
1958 }
1959
1960 "now_ms" => {
1964 self.emit.write("sage_runtime::stdlib::now_ms()");
1965 }
1966 "now_s" => {
1967 self.emit.write("sage_runtime::stdlib::now_s()");
1968 }
1969 "sleep_ms" => {
1970 self.emit
1971 .write("tokio::time::sleep(std::time::Duration::from_millis(");
1972 self.generate_expr(&args[0]);
1973 self.emit.write(" as u64)).await");
1974 }
1975 "format_timestamp" => {
1976 self.emit.write("sage_runtime::stdlib::format_timestamp(");
1977 self.generate_expr(&args[0]);
1978 self.emit.write(", &");
1979 self.generate_expr(&args[1]);
1980 self.emit.write(")");
1981 }
1982 "parse_timestamp" => {
1983 self.emit.write("sage_runtime::stdlib::parse_timestamp(&");
1984 self.generate_expr(&args[0]);
1985 self.emit.write(", &");
1986 self.generate_expr(&args[1]);
1987 self.emit
1988 .write(").map_err(sage_runtime::SageError::agent)?");
1989 }
1990
1991 "json_parse" => {
1995 self.emit.write("sage_runtime::stdlib::json_parse(&");
1996 self.generate_expr(&args[0]);
1997 self.emit
1998 .write(").map_err(sage_runtime::SageError::agent)?");
1999 }
2000 "json_get" => {
2001 self.emit.write("sage_runtime::stdlib::json_get(&");
2002 self.generate_expr(&args[0]);
2003 self.emit.write(", &");
2004 self.generate_expr(&args[1]);
2005 self.emit.write(")");
2006 }
2007 "json_get_int" => {
2008 self.emit.write("sage_runtime::stdlib::json_get_int(&");
2009 self.generate_expr(&args[0]);
2010 self.emit.write(", &");
2011 self.generate_expr(&args[1]);
2012 self.emit.write(")");
2013 }
2014 "json_get_float" => {
2015 self.emit.write("sage_runtime::stdlib::json_get_float(&");
2016 self.generate_expr(&args[0]);
2017 self.emit.write(", &");
2018 self.generate_expr(&args[1]);
2019 self.emit.write(")");
2020 }
2021 "json_get_bool" => {
2022 self.emit.write("sage_runtime::stdlib::json_get_bool(&");
2023 self.generate_expr(&args[0]);
2024 self.emit.write(", &");
2025 self.generate_expr(&args[1]);
2026 self.emit.write(")");
2027 }
2028 "json_get_list" => {
2029 self.emit.write("sage_runtime::stdlib::json_get_list(&");
2030 self.generate_expr(&args[0]);
2031 self.emit.write(", &");
2032 self.generate_expr(&args[1]);
2033 self.emit.write(")");
2034 }
2035 "json_stringify" => {
2036 self.emit
2037 .write("sage_runtime::stdlib::json_stringify_string(&");
2038 self.generate_expr(&args[0]);
2039 self.emit.write(".to_string())");
2040 }
2041
2042 _ => {
2043 self.emit.write(fn_name);
2045 if !type_args.is_empty() {
2047 self.emit.write("::<");
2048 for (i, arg) in type_args.iter().enumerate() {
2049 if i > 0 {
2050 self.emit.write(", ");
2051 }
2052 self.emit_type(arg);
2053 }
2054 self.emit.write(">");
2055 }
2056 self.emit.write("(");
2057 for (i, arg) in args.iter().enumerate() {
2058 if i > 0 {
2059 self.emit.write(", ");
2060 }
2061 self.emit.write("(");
2064 self.generate_expr(arg);
2065 self.emit.write(").clone()");
2066 }
2067 self.emit.write(")");
2068 }
2069 }
2070 }
2071
2072 Expr::SelfField { field, .. } => {
2073 self.emit.write("self.");
2074 self.emit.write(&field.name);
2075 }
2076
2077 Expr::SelfMethodCall { method, args, .. } => {
2078 self.emit.write("self.");
2079 self.emit.write(&method.name);
2080 self.emit.write("(");
2081 for (i, arg) in args.iter().enumerate() {
2082 if i > 0 {
2083 self.emit.write(", ");
2084 }
2085 self.generate_expr(arg);
2086 }
2087 self.emit.write(")");
2088 }
2089
2090 Expr::List { elements, .. } => {
2091 self.emit.write("vec![");
2092 for (i, elem) in elements.iter().enumerate() {
2093 if i > 0 {
2094 self.emit.write(", ");
2095 }
2096 self.generate_expr(elem);
2097 }
2098 self.emit.write("]");
2099 }
2100
2101 Expr::Paren { inner, .. } => {
2102 self.emit.write("(");
2103 self.generate_expr(inner);
2104 self.emit.write(")");
2105 }
2106
2107 Expr::Divine { template, .. } => {
2108 self.emit.write("ctx.infer_string(&");
2110 self.emit_string_template(template);
2111 self.emit.write(").await");
2112 }
2113
2114 Expr::Summon { agent, fields, .. } => {
2115 let has_error_handler = self.agents_with_error_handlers.contains(&agent.name);
2116 self.emit
2117 .write("sage_runtime::spawn(|mut ctx| async move { ");
2118 self.emit.write("let agent = ");
2119 self.emit.write(&agent.name);
2120 if fields.is_empty() {
2121 self.emit.write("; ");
2122 } else {
2123 self.emit.write(" { ");
2124 for (i, field) in fields.iter().enumerate() {
2125 if i > 0 {
2126 self.emit.write(", ");
2127 }
2128 self.emit.write(&field.name.name);
2129 self.emit.write(": ");
2130 self.generate_expr(&field.value);
2131 }
2132 self.emit.write(" }; ");
2133 }
2134 if has_error_handler {
2135 self.emit.write("match agent.on_start(&mut ctx).await { ");
2137 self.emit.write("Ok(result) => Ok(result), ");
2138 self.emit
2139 .write("Err(e) => agent.on_error(e, &mut ctx).await } })");
2140 } else {
2141 self.emit.write("agent.on_start(&mut ctx).await })");
2142 }
2143 }
2144
2145 Expr::Await {
2146 handle, timeout, ..
2147 } => {
2148 if let Some(timeout_expr) = timeout {
2150 self.emit.write("tokio::time::timeout(");
2152 self.emit.write("std::time::Duration::from_millis(");
2153 self.generate_expr(timeout_expr);
2154 self.emit.write(" as u64), ");
2155 self.generate_expr(handle);
2156 self.emit
2157 .write(".result()).await.map_err(|_| sage_runtime::SageError::agent(");
2158 self.emit.write("\"await timed out\"))?");
2159 } else {
2160 self.generate_expr(handle);
2162 self.emit.write(".result().await");
2163 }
2164 }
2165
2166 Expr::Send {
2167 handle, message, ..
2168 } => {
2169 self.generate_expr(handle);
2170 self.emit.write(".send(sage_runtime::Message::new(");
2171 self.generate_expr(message);
2172 self.emit.write(")?).await?");
2173 }
2174
2175 Expr::Yield { value, .. } => {
2176 self.emit.write("ctx.emit(");
2177 self.generate_expr(value);
2178 self.emit.write(")");
2179 }
2180
2181 Expr::StringInterp { template, .. } => {
2182 self.emit_string_template(template);
2183 }
2184
2185 Expr::Match {
2186 scrutinee, arms, ..
2187 } => {
2188 self.emit.write("match ");
2189 self.generate_expr(scrutinee);
2190 self.emit.writeln(" {");
2191 self.emit.indent();
2192 for arm in arms {
2193 self.emit_pattern(&arm.pattern);
2194 self.emit.write(" => ");
2195 self.generate_expr(&arm.body);
2196 self.emit.writeln(",");
2197 }
2198 self.emit.dedent();
2199 self.emit.write("}");
2200 }
2201
2202 Expr::RecordConstruct { name, fields, .. } => {
2203 self.emit.write(&name.name);
2204 self.emit.write(" { ");
2205 for (i, field) in fields.iter().enumerate() {
2206 if i > 0 {
2207 self.emit.write(", ");
2208 }
2209 self.emit.write(&field.name.name);
2210 self.emit.write(": ");
2211 self.generate_expr(&field.value);
2212 }
2213 self.emit.write(" }");
2214 }
2215
2216 Expr::FieldAccess { object, field, .. } => {
2217 self.generate_expr(object);
2218 self.emit.write(".");
2219 self.emit.write(&field.name);
2220 }
2221
2222 Expr::Receive { .. } => {
2223 self.emit.write("ctx.receive().await?");
2224 }
2225
2226 Expr::Try { expr, .. } => {
2228 self.generate_expr(expr);
2230 self.emit.write("?");
2231 }
2232
2233 Expr::Catch {
2234 expr,
2235 error_bind,
2236 recovery,
2237 ..
2238 } => {
2239 self.emit.write("match ");
2242 if let Expr::Try { expr: inner, .. } = expr.as_ref() {
2243 self.generate_expr(inner);
2244 } else {
2245 self.generate_expr(expr);
2246 }
2247 self.emit.writeln(" {");
2248 self.emit.indent();
2249
2250 self.emit.writeln("Ok(__val) => __val,");
2252
2253 if let Some(err_name) = error_bind {
2255 self.emit.write("Err(");
2256 self.emit.write(&err_name.name);
2257 self.emit.write(") => ");
2258 } else {
2259 self.emit.write("Err(_) => ");
2260 }
2261 self.generate_expr(recovery);
2262 self.emit.writeln(",");
2263
2264 self.emit.dedent();
2265 self.emit.write("}");
2266 }
2267
2268 Expr::Fail { error, .. } => {
2270 self.emit
2273 .write("return Err(sage_runtime::SageError::agent(");
2274 self.generate_expr(error);
2275 self.emit.write("))");
2276 }
2277
2278 Expr::Retry {
2280 count,
2281 delay,
2282 on_errors: _,
2283 body,
2284 ..
2285 } => {
2286 self.emit.writeln("'_retry: {");
2288 self.emit.indent();
2289
2290 self.emit.write("let _retry_max: i64 = ");
2291 self.generate_expr(count);
2292 self.emit.writeln(";");
2293
2294 if let Some(delay_expr) = delay {
2295 self.emit.write("let _retry_delay: u64 = ");
2296 self.generate_expr(delay_expr);
2297 self.emit.writeln(" as u64;");
2298 }
2299
2300 self.emit
2301 .writeln("let mut _last_error: Option<sage_runtime::SageError> = None;");
2302 self.emit.writeln("for _attempt in 0.._retry_max {");
2303 self.emit.indent();
2304
2305 self.emit.writeln("let _result = (async {");
2307 self.emit.indent();
2308 self.emit.write("Ok::<_, sage_runtime::SageError>(");
2309 self.generate_expr(body);
2310 self.emit.writeln(")");
2311 self.emit.dedent();
2312 self.emit.writeln("}).await;");
2313
2314 self.emit.writeln("match _result {");
2315 self.emit.indent();
2316 self.emit.writeln("Ok(v) => break '_retry v,");
2317 self.emit.writeln("Err(e) => {");
2318 self.emit.indent();
2319 self.emit.writeln("_last_error = Some(e);");
2320
2321 if delay.is_some() {
2323 self.emit.writeln("if _attempt < _retry_max - 1 {");
2324 self.emit.indent();
2325 self.emit.writeln(
2326 "tokio::time::sleep(std::time::Duration::from_millis(_retry_delay)).await;",
2327 );
2328 self.emit.dedent();
2329 self.emit.writeln("}");
2330 }
2331
2332 self.emit.dedent();
2333 self.emit.writeln("}");
2334 self.emit.dedent();
2335 self.emit.writeln("}");
2336
2337 self.emit.dedent();
2338 self.emit.writeln("}");
2339
2340 self.emit.writeln("return Err(_last_error.unwrap());");
2342
2343 self.emit.dedent();
2344 self.emit.write("}");
2345 }
2346
2347 Expr::Trace { message, .. } => {
2349 self.emit.write("sage_runtime::trace::user(&");
2350 self.generate_expr(message);
2351 self.emit.write(")");
2352 }
2353
2354 Expr::Closure { params, body, .. } => {
2356 self.emit.write("Box::new(move |");
2358 for (i, param) in params.iter().enumerate() {
2359 if i > 0 {
2360 self.emit.write(", ");
2361 }
2362 self.emit.write(¶m.name.name);
2363 if let Some(ty) = ¶m.ty {
2364 self.emit.write(": ");
2365 self.emit_type(ty);
2366 }
2367 }
2368 self.emit.write("| ");
2369 self.generate_expr(body);
2370 self.emit.write(")");
2371 }
2372
2373 Expr::Tuple { elements, .. } => {
2375 self.emit.write("(");
2376 for (i, elem) in elements.iter().enumerate() {
2377 if i > 0 {
2378 self.emit.write(", ");
2379 }
2380 self.generate_expr(elem);
2381 }
2382 self.emit.write(")");
2383 }
2384
2385 Expr::TupleIndex { tuple, index, .. } => {
2386 self.generate_expr(tuple);
2387 self.emit.write(&format!(".{index}"));
2388 }
2389
2390 Expr::Map { entries, .. } => {
2391 if entries.is_empty() {
2392 self.emit.write("std::collections::HashMap::new()");
2393 } else {
2394 self.emit.write("std::collections::HashMap::from([");
2395 for (i, entry) in entries.iter().enumerate() {
2396 if i > 0 {
2397 self.emit.write(", ");
2398 }
2399 self.emit.write("(");
2400 self.generate_expr(&entry.key);
2401 self.emit.write(", ");
2402 self.generate_expr(&entry.value);
2403 self.emit.write(")");
2404 }
2405 self.emit.write("])");
2406 }
2407 }
2408
2409 Expr::VariantConstruct {
2410 enum_name,
2411 type_args,
2412 variant,
2413 payload,
2414 ..
2415 } => {
2416 self.emit.write(&enum_name.name);
2417 if !type_args.is_empty() {
2419 self.emit.write("::<");
2420 for (i, arg) in type_args.iter().enumerate() {
2421 if i > 0 {
2422 self.emit.write(", ");
2423 }
2424 self.emit_type(arg);
2425 }
2426 self.emit.write(">");
2427 }
2428 self.emit.write("::");
2429 self.emit.write(&variant.name);
2430 if let Some(payload_expr) = payload {
2431 self.emit.write("(");
2432 self.generate_expr(payload_expr);
2433 self.emit.write(")");
2434 }
2435 }
2436
2437 Expr::ToolCall {
2439 tool,
2440 function,
2441 args,
2442 ..
2443 } => {
2444 self.emit.write("self.");
2447 self.emit.write(&tool.name.to_lowercase());
2448 self.emit.write(".");
2449 self.emit.write(&function.name);
2450 self.emit.write("(");
2451 for (i, arg) in args.iter().enumerate() {
2452 if i > 0 {
2453 self.emit.write(", ");
2454 }
2455 self.generate_expr(arg);
2456 }
2457 self.emit.write(").await");
2458 }
2459 }
2460 }
2461
2462 fn emit_pattern(&mut self, pattern: &sage_parser::Pattern) {
2463 use sage_parser::Pattern;
2464 match pattern {
2465 Pattern::Wildcard { .. } => {
2466 self.emit.write("_");
2467 }
2468 Pattern::Variant {
2469 enum_name,
2470 variant,
2471 payload,
2472 ..
2473 } => {
2474 if let Some(enum_name) = enum_name {
2475 self.emit.write(&enum_name.name);
2476 self.emit.write("::");
2477 }
2478 self.emit.write(&variant.name);
2479 if let Some(inner_pattern) = payload {
2480 self.emit.write("(");
2481 self.emit_pattern(inner_pattern);
2482 self.emit.write(")");
2483 }
2484 }
2485 Pattern::Literal { value, .. } => {
2486 self.emit_literal(value);
2487 }
2488 Pattern::Binding { name, .. } => {
2489 self.emit.write(&name.name);
2490 }
2491 Pattern::Tuple { elements, .. } => {
2492 self.emit.write("(");
2493 for (i, elem) in elements.iter().enumerate() {
2494 if i > 0 {
2495 self.emit.write(", ");
2496 }
2497 self.emit_pattern(elem);
2498 }
2499 self.emit.write(")");
2500 }
2501 }
2502 }
2503
2504 fn emit_literal(&mut self, lit: &Literal) {
2505 match lit {
2506 Literal::Int(n) => {
2507 self.emit.write(&format!("{n}_i64"));
2508 }
2509 Literal::Float(f) => {
2510 self.emit.write(&format!("{f}_f64"));
2511 }
2512 Literal::Bool(b) => {
2513 self.emit.write(if *b { "true" } else { "false" });
2514 }
2515 Literal::String(s) => {
2516 self.emit.write("\"");
2518 for c in s.chars() {
2519 match c {
2520 '"' => self.emit.write_raw("\\\""),
2521 '\\' => self.emit.write_raw("\\\\"),
2522 '\n' => self.emit.write_raw("\\n"),
2523 '\r' => self.emit.write_raw("\\r"),
2524 '\t' => self.emit.write_raw("\\t"),
2525 _ => self.emit.write_raw(&c.to_string()),
2526 }
2527 }
2528 self.emit.write("\".to_string()");
2529 }
2530 }
2531 }
2532
2533 fn emit_string_template(&mut self, template: &sage_parser::StringTemplate) {
2534 if !template.has_interpolations() {
2535 if let Some(StringPart::Literal(s)) = template.parts.first() {
2537 self.emit.write("\"");
2538 self.emit.write_raw(s);
2539 self.emit.write("\".to_string()");
2540 }
2541 return;
2542 }
2543
2544 self.emit.write("format!(\"");
2546 for part in &template.parts {
2547 match part {
2548 StringPart::Literal(s) => {
2549 let escaped = s.replace('{', "{{").replace('}', "}}");
2551 self.emit.write_raw(&escaped);
2552 }
2553 StringPart::Interpolation(_) => {
2554 self.emit.write_raw("{}");
2555 }
2556 }
2557 }
2558 self.emit.write("\"");
2559
2560 for part in &template.parts {
2562 if let StringPart::Interpolation(expr) = part {
2563 self.emit.write(", ");
2564 self.generate_expr(expr);
2565 }
2566 }
2567 self.emit.write(")");
2568 }
2569
2570 fn emit_type(&mut self, ty: &TypeExpr) {
2571 match ty {
2572 TypeExpr::Int => self.emit.write("i64"),
2573 TypeExpr::Float => self.emit.write("f64"),
2574 TypeExpr::Bool => self.emit.write("bool"),
2575 TypeExpr::String => self.emit.write("String"),
2576 TypeExpr::Unit => self.emit.write("()"),
2577 TypeExpr::List(inner) => {
2578 self.emit.write("Vec<");
2579 self.emit_type(inner);
2580 self.emit.write(">");
2581 }
2582 TypeExpr::Option(inner) => {
2583 self.emit.write("Option<");
2584 self.emit_type(inner);
2585 self.emit.write(">");
2586 }
2587 TypeExpr::Oracle(inner) => {
2588 self.emit_type(inner);
2590 }
2591 TypeExpr::Agent(agent_name) => {
2592 self.emit.write("AgentHandle<");
2595 self.emit.write(&agent_name.name);
2596 self.emit.write("Output>");
2597 }
2598 TypeExpr::Named(name, type_args) => {
2599 self.emit.write(&name.name);
2600 if !type_args.is_empty() {
2601 self.emit.write("<");
2602 for (i, arg) in type_args.iter().enumerate() {
2603 if i > 0 {
2604 self.emit.write(", ");
2605 }
2606 self.emit_type(arg);
2607 }
2608 self.emit.write(">");
2609 }
2610 }
2611
2612 TypeExpr::Error => {
2614 self.emit.write("sage_runtime::SageError");
2615 }
2616
2617 TypeExpr::Fn(params, ret) => {
2619 self.emit.write("Box<dyn Fn(");
2620 for (i, param) in params.iter().enumerate() {
2621 if i > 0 {
2622 self.emit.write(", ");
2623 }
2624 self.emit_type(param);
2625 }
2626 self.emit.write(") -> ");
2627 self.emit_type(ret);
2628 self.emit.write(" + Send + 'static>");
2629 }
2630
2631 TypeExpr::Map(key, value) => {
2633 self.emit.write("std::collections::HashMap<");
2634 self.emit_type(key);
2635 self.emit.write(", ");
2636 self.emit_type(value);
2637 self.emit.write(">");
2638 }
2639 TypeExpr::Tuple(elems) => {
2640 self.emit.write("(");
2641 for (i, elem) in elems.iter().enumerate() {
2642 if i > 0 {
2643 self.emit.write(", ");
2644 }
2645 self.emit_type(elem);
2646 }
2647 self.emit.write(")");
2648 }
2649 TypeExpr::Result(ok, err) => {
2650 self.emit.write("Result<");
2651 self.emit_type(ok);
2652 self.emit.write(", ");
2653 self.emit_type(err);
2654 self.emit.write(">");
2655 }
2656 }
2657 }
2658
2659 fn emit_binop(&mut self, op: &BinOp) {
2660 let s = match op {
2661 BinOp::Add => "+",
2662 BinOp::Sub => "-",
2663 BinOp::Mul => "*",
2664 BinOp::Div => "/",
2665 BinOp::Rem => "%",
2666 BinOp::Eq => "==",
2667 BinOp::Ne => "!=",
2668 BinOp::Lt => "<",
2669 BinOp::Gt => ">",
2670 BinOp::Le => "<=",
2671 BinOp::Ge => ">=",
2672 BinOp::And => "&&",
2673 BinOp::Or => "||",
2674 BinOp::Concat => "++", };
2676 self.emit.write(s);
2677 }
2678
2679 fn emit_unaryop(&mut self, op: &UnaryOp) {
2680 let s = match op {
2681 UnaryOp::Neg => "-",
2682 UnaryOp::Not => "!",
2683 };
2684 self.emit.write(s);
2685 }
2686
2687 fn infer_agent_output_type(&self, agent: &AgentDecl) -> String {
2688 for handler in &agent.handlers {
2691 if let EventKind::Start = &handler.event {
2692 if let Some(ty) = self.find_emit_type(&handler.body) {
2693 return ty;
2694 }
2695 }
2696 }
2697 "i64".to_string()
2698 }
2699
2700 fn find_emit_type(&self, block: &Block) -> Option<String> {
2701 let mut var_types: std::collections::HashMap<String, String> =
2703 std::collections::HashMap::new();
2704
2705 for stmt in &block.stmts {
2706 if let Stmt::Let { name, value, .. } = stmt {
2708 let ty = self.infer_expr_type_with_vars(value, &var_types);
2709 var_types.insert(name.name.clone(), ty);
2710 }
2711
2712 if let Stmt::Expr { expr, .. } = stmt {
2713 if let Expr::Yield { value, .. } = expr {
2714 return Some(self.infer_expr_type_with_vars(value, &var_types));
2715 }
2716 }
2717 if let Stmt::If {
2719 then_block,
2720 else_block,
2721 ..
2722 } = stmt
2723 {
2724 if let Some(ty) = self.find_emit_type(then_block) {
2725 return Some(ty);
2726 }
2727 if let Some(else_branch) = else_block {
2728 if let sage_parser::ElseBranch::Block(block) = else_branch {
2729 if let Some(ty) = self.find_emit_type(block) {
2730 return Some(ty);
2731 }
2732 }
2733 }
2734 }
2735 }
2736 None
2737 }
2738
2739 fn infer_expr_type_with_vars(
2740 &self,
2741 expr: &Expr,
2742 var_types: &std::collections::HashMap<String, String>,
2743 ) -> String {
2744 match expr {
2745 Expr::Var { name, .. } => {
2746 if let Some(ty) = var_types.get(&name.name) {
2748 return ty.clone();
2749 }
2750 "i64".to_string() }
2752 Expr::Try { expr, .. } => self.infer_expr_type_with_vars(expr, var_types),
2754 Expr::Catch { expr, .. } => self.infer_expr_type_with_vars(expr, var_types),
2756 _ => self.infer_expr_type(expr),
2758 }
2759 }
2760
2761 fn infer_expr_type(&self, expr: &Expr) -> String {
2762 match expr {
2763 Expr::Literal { value, .. } => match value {
2764 Literal::Int(_) => "i64".to_string(),
2765 Literal::Float(_) => "f64".to_string(),
2766 Literal::Bool(_) => "bool".to_string(),
2767 Literal::String(_) => "String".to_string(),
2768 },
2769 Expr::Var { .. } => "i64".to_string(), Expr::Binary { op, .. } => {
2771 if matches!(
2772 op,
2773 BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Gt | BinOp::Le | BinOp::Ge
2774 ) {
2775 "bool".to_string()
2776 } else if matches!(op, BinOp::Concat) {
2777 "String".to_string()
2778 } else {
2779 "i64".to_string()
2780 }
2781 }
2782 Expr::Divine { .. } | Expr::StringInterp { .. } => "String".to_string(),
2783 Expr::Call { name, .. } if name.name == "str" => "String".to_string(),
2784 Expr::Call { name, .. } if name.name == "len" => "i64".to_string(),
2785 _ => "i64".to_string(),
2786 }
2787 }
2788}
2789
2790#[cfg(test)]
2791mod tests {
2792 use super::*;
2793 use sage_parser::{lex, parse};
2794 use std::sync::Arc;
2795
2796 fn generate_source(source: &str) -> String {
2797 let lex_result = lex(source).expect("lexing failed");
2798 let source_arc: Arc<str> = Arc::from(source);
2799 let (program, errors) = parse(lex_result.tokens(), source_arc);
2800 assert!(errors.is_empty(), "parse errors: {errors:?}");
2801 let program = program.expect("should parse");
2802 generate(&program, "test").main_rs
2803 }
2804
2805 #[test]
2806 fn generate_minimal_program() {
2807 let source = r#"
2808 agent Main {
2809 on start {
2810 yield(42);
2811 }
2812 }
2813 run Main;
2814 "#;
2815
2816 let output = generate_source(source);
2817 assert!(output.contains("struct Main;"));
2818 assert!(output.contains("async fn on_start"));
2819 assert!(output.contains("ctx.emit(42_i64)"));
2820 assert!(output.contains("#[tokio::main]"));
2821 }
2822
2823 #[test]
2824 fn generate_function() {
2825 let source = r#"
2826 fn add(a: Int, b: Int) -> Int {
2827 return a + b;
2828 }
2829 agent Main {
2830 on start {
2831 yield(add(1, 2));
2832 }
2833 }
2834 run Main;
2835 "#;
2836
2837 let output = generate_source(source);
2838 assert!(output.contains("fn add(a: i64, b: i64) -> i64"));
2839 assert!(output.contains("return a + b;"));
2840 }
2841
2842 #[test]
2843 fn generate_agent_with_beliefs() {
2844 let source = r#"
2845 agent Worker {
2846 value: Int
2847
2848 on start {
2849 yield(self.value * 2);
2850 }
2851 }
2852 agent Main {
2853 on start {
2854 yield(0);
2855 }
2856 }
2857 run Main;
2858 "#;
2859
2860 let output = generate_source(source);
2861 assert!(output.contains("struct Worker {"));
2862 assert!(output.contains("value: i64,"));
2863 assert!(output.contains("self.value"));
2864 }
2865
2866 #[test]
2867 fn generate_string_interpolation() {
2868 let source = r#"
2869 agent Main {
2870 on start {
2871 let name = "World";
2872 let msg = "Hello, {name}!";
2873 print(msg);
2874 yield(0);
2875 }
2876 }
2877 run Main;
2878 "#;
2879
2880 let output = generate_source(source);
2881 assert!(output.contains("format!(\"Hello, {}!\", name)"));
2882 }
2883
2884 #[test]
2885 fn generate_control_flow() {
2886 let source = r#"
2887 agent Main {
2888 on start {
2889 let x = 10;
2890 if x > 5 {
2891 yield(1);
2892 } else {
2893 yield(0);
2894 }
2895 }
2896 }
2897 run Main;
2898 "#;
2899
2900 let output = generate_source(source);
2901 assert!(output.contains("if x > 5_i64"), "output:\n{output}");
2902 assert!(output.contains("else"), "output:\n{output}");
2904 }
2905
2906 #[test]
2907 fn generate_loops() {
2908 let source = r#"
2909 agent Main {
2910 on start {
2911 for x in [1, 2, 3] {
2912 print(str(x));
2913 }
2914 let n = 0;
2915 while n < 5 {
2916 n = n + 1;
2917 }
2918 yield(n);
2919 }
2920 }
2921 run Main;
2922 "#;
2923
2924 let output = generate_source(source);
2925 assert!(output.contains("for x in vec![1_i64, 2_i64, 3_i64]"));
2926 assert!(output.contains("while n < 5_i64"));
2927 }
2928
2929 #[test]
2930 fn generate_pub_function() {
2931 let source = r#"
2932 pub fn helper(x: Int) -> Int {
2933 return x * 2;
2934 }
2935 agent Main {
2936 on start {
2937 yield(helper(21));
2938 }
2939 }
2940 run Main;
2941 "#;
2942
2943 let output = generate_source(source);
2944 assert!(output.contains("pub fn helper(x: i64) -> i64"));
2945 }
2946
2947 #[test]
2948 fn generate_pub_agent() {
2949 let source = r#"
2950 pub agent Worker {
2951 on start {
2952 yield(42);
2953 }
2954 }
2955 agent Main {
2956 on start {
2957 yield(0);
2958 }
2959 }
2960 run Main;
2961 "#;
2962
2963 let output = generate_source(source);
2964 assert!(output.contains("pub struct Worker;"));
2965 }
2966
2967 #[test]
2968 fn generate_module_tree_simple() {
2969 use sage_loader::load_single_file;
2970 use std::fs;
2971 use tempfile::TempDir;
2972
2973 let dir = TempDir::new().unwrap();
2974 let file = dir.path().join("test.sg");
2975 fs::write(
2976 &file,
2977 r#"
2978agent Main {
2979 on start {
2980 yield(42);
2981 }
2982}
2983run Main;
2984"#,
2985 )
2986 .unwrap();
2987
2988 let tree = load_single_file(&file).unwrap();
2989 let project = generate_module_tree(&tree, "test");
2990
2991 assert!(project.main_rs.contains("struct Main;"));
2992 assert!(project.main_rs.contains("async fn on_start"));
2993 assert!(project.main_rs.contains("#[tokio::main]"));
2994 }
2995
2996 #[test]
2997 fn generate_record_declaration() {
2998 let source = r#"
2999 record Point {
3000 x: Int,
3001 y: Int,
3002 }
3003 agent Main {
3004 on start {
3005 let p = Point { x: 10, y: 20 };
3006 yield(p.x);
3007 }
3008 }
3009 run Main;
3010 "#;
3011
3012 let output = generate_source(source);
3013 assert!(output.contains("#[derive(Debug, Clone)]"));
3014 assert!(output.contains("struct Point {"));
3015 assert!(output.contains("x: i64,"));
3016 assert!(output.contains("y: i64,"));
3017 assert!(output.contains("Point { x: 10_i64, y: 20_i64 }"));
3018 assert!(output.contains("p.x"));
3019 }
3020
3021 #[test]
3022 fn generate_enum_declaration() {
3023 let source = r#"
3024 enum Status {
3025 Active,
3026 Inactive,
3027 Pending,
3028 }
3029 agent Main {
3030 on start {
3031 yield(0);
3032 }
3033 }
3034 run Main;
3035 "#;
3036
3037 let output = generate_source(source);
3038 assert!(output.contains("#[derive(Debug, Clone, Copy, PartialEq, Eq)]"));
3039 assert!(output.contains("enum Status {"));
3040 assert!(output.contains("Active,"));
3041 assert!(output.contains("Inactive,"));
3042 assert!(output.contains("Pending,"));
3043 }
3044
3045 #[test]
3046 fn generate_const_declaration() {
3047 let source = r#"
3048 const MAX_SIZE: Int = 100;
3049 const GREETING: String = "Hello";
3050 agent Main {
3051 on start {
3052 yield(MAX_SIZE);
3053 }
3054 }
3055 run Main;
3056 "#;
3057
3058 let output = generate_source(source);
3059 assert!(output.contains("const MAX_SIZE: i64 = 100_i64;"));
3060 assert!(output.contains("const GREETING: &'static str = \"Hello\";"));
3062 }
3063
3064 #[test]
3065 fn generate_match_expression() {
3066 let source = r#"
3067 enum Status {
3068 Active,
3069 Inactive,
3070 }
3071 fn check_status(s: Status) -> Int {
3072 return match s {
3073 Active => 1,
3074 Inactive => 0,
3075 };
3076 }
3077 agent Main {
3078 on start {
3079 yield(0);
3080 }
3081 }
3082 run Main;
3083 "#;
3084
3085 let output = generate_source(source);
3086 assert!(output.contains("match s {"));
3087 assert!(output.contains("Active => 1_i64,"));
3088 assert!(output.contains("Inactive => 0_i64,"));
3089 }
3090
3091 #[test]
3096 fn generate_fallible_function() {
3097 let source = r#"
3098 fn get_data(url: String) -> String fails {
3099 return url;
3100 }
3101 agent Main {
3102 on start { yield(0); }
3103 }
3104 run Main;
3105 "#;
3106
3107 let output = generate_source(source);
3108 assert!(output.contains("fn get_data(url: String) -> SageResult<String>"));
3110 }
3111
3112 #[test]
3113 fn generate_try_expression() {
3114 let source = r#"
3115 fn fallible() -> Int fails { return 42; }
3116 fn caller() -> Int fails {
3117 let x = try fallible();
3118 return x;
3119 }
3120 agent Main {
3121 on start { yield(0); }
3122 }
3123 run Main;
3124 "#;
3125
3126 let output = generate_source(source);
3127 assert!(output.contains("fallible()?"));
3129 }
3130
3131 #[test]
3132 fn generate_catch_expression() {
3133 let source = r#"
3134 fn fallible() -> Int fails { return 42; }
3135 agent Main {
3136 on start {
3137 let x = fallible() catch { 0 };
3138 yield(x);
3139 }
3140 }
3141 run Main;
3142 "#;
3143
3144 let output = generate_source(source);
3145 assert!(output.contains("match fallible()"));
3147 assert!(output.contains("Ok(__val) => __val"));
3148 assert!(output.contains("Err(_) => 0_i64"));
3149 }
3150
3151 #[test]
3152 fn generate_catch_with_binding() {
3153 let source = r#"
3154 fn fallible() -> Int fails { return 42; }
3155 agent Main {
3156 on start {
3157 let x = fallible() catch(e) { 0 };
3158 yield(x);
3159 }
3160 }
3161 run Main;
3162 "#;
3163
3164 let output = generate_source(source);
3165 assert!(output.contains("Err(e) => 0_i64"));
3167 }
3168
3169 #[test]
3170 fn generate_on_error_handler() {
3171 let source = r#"
3172 agent Main {
3173 on start {
3174 yield(0);
3175 }
3176 on error(e) {
3177 yield(1);
3178 }
3179 }
3180 run Main;
3181 "#;
3182
3183 let output = generate_source(source);
3184 assert!(output.contains("async fn on_error(&self, _e: SageError, ctx: &mut AgentContext"));
3186 assert!(output.contains(".on_error(e, &mut ctx)"));
3188 }
3189
3190 #[test]
3195 fn generate_agent_with_tool_use() {
3196 let source = r#"
3197 agent Fetcher {
3198 use Http
3199
3200 on start {
3201 let r = Http.get("https://example.com");
3202 yield(0);
3203 }
3204 }
3205 run Fetcher;
3206 "#;
3207
3208 let output = generate_source(source);
3209 assert!(output.contains("struct Fetcher {"));
3211 assert!(output.contains("http: HttpClient,"));
3212 assert!(output.contains("http: HttpClient::from_env()"));
3214 assert!(output.contains("self.http.get("));
3216 }
3217
3218 #[test]
3219 fn generate_tool_call_expression() {
3220 let source = r#"
3221 agent Fetcher {
3222 use Http
3223
3224 on start {
3225 let response = Http.get("https://httpbin.org/get");
3226 yield(0);
3227 }
3228 }
3229 run Fetcher;
3230 "#;
3231
3232 let output = generate_source(source);
3233 assert!(output.contains("self.http.get(\"https://httpbin.org/get\".to_string()).await"));
3235 }
3236
3237 fn generate_test_source(source: &str) -> String {
3238 let lex_result = lex(source).expect("lexing failed");
3239 let source_arc: Arc<str> = Arc::from(source);
3240 let (program, errors) = parse(lex_result.tokens(), source_arc);
3241 assert!(errors.is_empty(), "parse errors: {errors:?}");
3242 let program = program.expect("should parse");
3243 super::generate_test_program(&program, "test").main_rs
3244 }
3245
3246 #[test]
3247 fn generate_mock_tool() {
3248 let source = r#"
3249 test "mocks http tool" {
3250 mock tool Http.get -> "mocked response";
3251 mock tool Http.post -> fail("network error");
3252 assert_eq(1, 1);
3253 }
3254 "#;
3255
3256 let output = generate_test_source(source);
3257 assert!(output.contains("let _mock_tools = MockToolRegistry::new();"));
3259 assert!(output.contains("_mock_tools.register(\"Http\", \"get\", MockResponse::value("));
3261 assert!(output.contains("_mock_tools.register(\"Http\", \"post\", MockResponse::fail("));
3262 }
3263
3264 #[test]
3265 fn generate_mock_infer_and_tool() {
3266 let source = r#"
3267 test "mocks both infer and tool" {
3268 mock divine -> "hello";
3269 mock tool Http.get -> "response";
3270 assert_true(true);
3271 }
3272 "#;
3273
3274 let output = generate_test_source(source);
3275 assert!(output.contains("MockLlmClient::with_responses"));
3277 assert!(output.contains("MockToolRegistry::new()"));
3278 }
3279}