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