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