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 mocks = self.collect_mock_infers(&test.body);
385
386 self.emit.writeln("#[tokio::test]");
388 let test_fn_name = self.sanitize_test_name(&test.name);
390 self.emit.write("async fn ");
391 self.emit.write(&test_fn_name);
392 self.emit.writeln("() {");
393 self.emit.indent();
394
395 if !mocks.is_empty() {
397 self.emit.writeln("let _mock_client = MockLlmClient::with_responses(vec![");
398 self.emit.indent();
399 for mock in &mocks {
400 match mock {
401 MockValue::Value(expr) => {
402 self.emit.write("MockResponse::value(");
403 self.generate_expr(expr);
404 self.emit.writeln("),");
405 }
406 MockValue::Fail(expr) => {
407 self.emit.write("MockResponse::fail(");
408 self.generate_expr(expr);
409 self.emit.writeln("),");
410 }
411 }
412 }
413 self.emit.dedent();
414 self.emit.writeln("]);");
415 self.emit.blank_line();
416 }
417
418 self.generate_test_block(&test.body);
420
421 self.emit.dedent();
422 self.emit.writeln("}");
423 }
424
425 fn collect_mock_infers(&self, block: &Block) -> Vec<MockValue> {
426 let mut mocks = Vec::new();
427 for stmt in &block.stmts {
428 if let Stmt::MockInfer { value, .. } = stmt {
429 mocks.push(value.clone());
430 }
431 }
432 mocks
433 }
434
435 fn generate_test_block(&mut self, block: &Block) {
436 for stmt in &block.stmts {
437 if matches!(stmt, Stmt::MockInfer { .. }) {
439 continue;
440 }
441 self.generate_test_stmt(stmt);
442 }
443 }
444
445 fn generate_test_stmt(&mut self, stmt: &Stmt) {
446 match stmt {
447 Stmt::Expr { expr, .. } => {
449 if let Expr::Call { name, args, .. } = expr {
450 if self.is_assertion_builtin(&name.name) {
451 self.generate_assertion(&name.name, args);
452 return;
453 }
454 }
455 self.generate_expr(expr);
457 self.emit.writeln(";");
458 }
459 _ => self.generate_stmt(stmt),
461 }
462 }
463
464 fn is_assertion_builtin(&self, name: &str) -> bool {
465 matches!(
466 name,
467 "assert"
468 | "assert_eq"
469 | "assert_neq"
470 | "assert_gt"
471 | "assert_lt"
472 | "assert_gte"
473 | "assert_lte"
474 | "assert_true"
475 | "assert_false"
476 | "assert_contains"
477 | "assert_not_contains"
478 | "assert_empty"
479 | "assert_not_empty"
480 | "assert_starts_with"
481 | "assert_ends_with"
482 | "assert_len"
483 | "assert_empty_list"
484 | "assert_not_empty_list"
485 | "assert_fails"
486 )
487 }
488
489 fn generate_assertion(&mut self, name: &str, args: &[Expr]) {
490 match name {
491 "assert" | "assert_true" => {
492 self.emit.write("assert!(");
493 if !args.is_empty() {
494 self.generate_expr(&args[0]);
495 }
496 self.emit.writeln(");");
497 }
498 "assert_false" => {
499 self.emit.write("assert!(!");
500 if !args.is_empty() {
501 self.generate_expr(&args[0]);
502 }
503 self.emit.writeln(");");
504 }
505 "assert_eq" => {
506 self.emit.write("assert_eq!(");
507 if args.len() >= 2 {
508 self.generate_expr(&args[0]);
509 self.emit.write(", ");
510 self.generate_expr(&args[1]);
511 }
512 self.emit.writeln(");");
513 }
514 "assert_neq" => {
515 self.emit.write("assert_ne!(");
516 if args.len() >= 2 {
517 self.generate_expr(&args[0]);
518 self.emit.write(", ");
519 self.generate_expr(&args[1]);
520 }
521 self.emit.writeln(");");
522 }
523 "assert_gt" => {
524 self.emit.write("assert!(");
525 if args.len() >= 2 {
526 self.generate_expr(&args[0]);
527 self.emit.write(" > ");
528 self.generate_expr(&args[1]);
529 }
530 self.emit.writeln(");");
531 }
532 "assert_lt" => {
533 self.emit.write("assert!(");
534 if args.len() >= 2 {
535 self.generate_expr(&args[0]);
536 self.emit.write(" < ");
537 self.generate_expr(&args[1]);
538 }
539 self.emit.writeln(");");
540 }
541 "assert_gte" => {
542 self.emit.write("assert!(");
543 if args.len() >= 2 {
544 self.generate_expr(&args[0]);
545 self.emit.write(" >= ");
546 self.generate_expr(&args[1]);
547 }
548 self.emit.writeln(");");
549 }
550 "assert_lte" => {
551 self.emit.write("assert!(");
552 if args.len() >= 2 {
553 self.generate_expr(&args[0]);
554 self.emit.write(" <= ");
555 self.generate_expr(&args[1]);
556 }
557 self.emit.writeln(");");
558 }
559 "assert_contains" => {
560 self.emit.write("assert!(");
561 if args.len() >= 2 {
562 self.generate_expr(&args[0]);
563 self.emit.write(".contains(&");
564 self.generate_expr(&args[1]);
565 self.emit.write(")");
566 }
567 self.emit.writeln(");");
568 }
569 "assert_not_contains" => {
570 self.emit.write("assert!(!");
571 if args.len() >= 2 {
572 self.generate_expr(&args[0]);
573 self.emit.write(".contains(&");
574 self.generate_expr(&args[1]);
575 self.emit.write(")");
576 }
577 self.emit.writeln(");");
578 }
579 "assert_empty" => {
580 self.emit.write("assert!(");
581 if !args.is_empty() {
582 self.generate_expr(&args[0]);
583 }
584 self.emit.writeln(".is_empty());");
585 }
586 "assert_not_empty" => {
587 self.emit.write("assert!(!");
588 if !args.is_empty() {
589 self.generate_expr(&args[0]);
590 }
591 self.emit.writeln(".is_empty());");
592 }
593 "assert_starts_with" => {
594 self.emit.write("assert!(");
595 if args.len() >= 2 {
596 self.generate_expr(&args[0]);
597 self.emit.write(".starts_with(&");
598 self.generate_expr(&args[1]);
599 self.emit.write(")");
600 }
601 self.emit.writeln(");");
602 }
603 "assert_ends_with" => {
604 self.emit.write("assert!(");
605 if args.len() >= 2 {
606 self.generate_expr(&args[0]);
607 self.emit.write(".ends_with(&");
608 self.generate_expr(&args[1]);
609 self.emit.write(")");
610 }
611 self.emit.writeln(");");
612 }
613 "assert_len" => {
614 self.emit.write("assert_eq!(");
615 if args.len() >= 2 {
616 self.generate_expr(&args[0]);
617 self.emit.write(".len() as i64, ");
618 self.generate_expr(&args[1]);
619 }
620 self.emit.writeln(");");
621 }
622 "assert_empty_list" => {
623 self.emit.write("assert!(");
624 if !args.is_empty() {
625 self.generate_expr(&args[0]);
626 }
627 self.emit.writeln(".is_empty());");
628 }
629 "assert_not_empty_list" => {
630 self.emit.write("assert!(!");
631 if !args.is_empty() {
632 self.generate_expr(&args[0]);
633 }
634 self.emit.writeln(".is_empty());");
635 }
636 "assert_fails" => {
637 self.emit.writeln("{");
639 self.emit.indent();
640 self.emit.write("let result = ");
641 if !args.is_empty() {
642 self.generate_expr(&args[0]);
643 }
644 self.emit.writeln(";");
645 self.emit.writeln("assert!(result.is_err(), \"Expected operation to fail but it succeeded\");");
646 self.emit.dedent();
647 self.emit.writeln("}");
648 }
649 _ => {
650 self.emit.write(name);
652 self.emit.write("(");
653 for (i, arg) in args.iter().enumerate() {
654 if i > 0 {
655 self.emit.write(", ");
656 }
657 self.generate_expr(arg);
658 }
659 self.emit.writeln(");");
660 }
661 }
662 }
663
664 fn sanitize_test_name(&self, name: &str) -> String {
665 name.chars()
667 .map(|c| {
668 if c.is_alphanumeric() {
669 c
670 } else {
671 '_'
672 }
673 })
674 .collect::<String>()
675 .to_lowercase()
676 }
677
678 fn generate_const(&mut self, const_decl: &ConstDecl) {
679 if const_decl.is_pub {
680 self.emit.write("pub ");
681 }
682 self.emit.write("const ");
683 self.emit.write(&const_decl.name.name);
684 self.emit.write(": ");
685 self.emit_type(&const_decl.ty);
686 self.emit.write(" = ");
687 self.generate_expr(&const_decl.value);
688 self.emit.writeln(";");
689 }
690
691 fn generate_enum(&mut self, enum_decl: &EnumDecl) {
692 if enum_decl.is_pub {
693 self.emit.write("pub ");
694 }
695 self.emit
696 .writeln("#[derive(Debug, Clone, Copy, PartialEq, Eq)]");
697 self.emit.write("enum ");
698 self.emit.write(&enum_decl.name.name);
699 self.emit.writeln(" {");
700 self.emit.indent();
701 for variant in &enum_decl.variants {
702 self.emit.write(&variant.name.name);
703 if let Some(payload_ty) = &variant.payload {
704 self.emit.write("(");
705 self.emit_type(payload_ty);
706 self.emit.write(")");
707 }
708 self.emit.writeln(",");
709 }
710 self.emit.dedent();
711 self.emit.writeln("}");
712 }
713
714 fn generate_record(&mut self, record: &RecordDecl) {
715 if record.is_pub {
716 self.emit.write("pub ");
717 }
718 self.emit.writeln("#[derive(Debug, Clone)]");
719 self.emit.write("struct ");
720 self.emit.write(&record.name.name);
721 self.emit.writeln(" {");
722 self.emit.indent();
723 for field in &record.fields {
724 self.emit.write(&field.name.name);
725 self.emit.write(": ");
726 self.emit_type(&field.ty);
727 self.emit.writeln(",");
728 }
729 self.emit.dedent();
730 self.emit.writeln("}");
731 }
732
733 fn generate_function(&mut self, func: &FnDecl) {
734 if func.is_pub {
736 self.emit.write("pub ");
737 }
738 self.emit.write("fn ");
739 self.emit.write(&func.name.name);
740 self.emit.write("(");
741
742 for (i, param) in func.params.iter().enumerate() {
743 if i > 0 {
744 self.emit.write(", ");
745 }
746 self.emit.write(¶m.name.name);
747 self.emit.write(": ");
748 self.emit_type(¶m.ty);
749 }
750
751 self.emit.write(") -> ");
752
753 if func.is_fallible {
755 self.emit.write("SageResult<");
756 self.emit_type(&func.return_ty);
757 self.emit.write(">");
758 } else {
759 self.emit_type(&func.return_ty);
760 }
761
762 self.emit.write(" ");
763 self.generate_block(&func.body);
764 }
765
766 fn generate_agent(&mut self, agent: &AgentDecl) {
767 let name = &agent.name.name;
768
769 let has_tools = !agent.tool_uses.is_empty();
771 let needs_struct_body = !agent.beliefs.is_empty() || has_tools;
772
773 if agent.is_pub {
775 self.emit.write("pub ");
776 }
777 self.emit.write("struct ");
778 self.emit.write(name);
779 if !needs_struct_body {
780 self.emit.writeln(";");
781 } else {
782 self.emit.writeln(" {");
783 self.emit.indent();
784
785 for tool_use in &agent.tool_uses {
787 self.emit.write(&tool_use.name.to_lowercase());
789 self.emit.write(": ");
790 self.emit.write(&tool_use.name);
791 self.emit.writeln("Client,");
792 }
793
794 for belief in &agent.beliefs {
796 self.emit.write(&belief.name.name);
797 self.emit.write(": ");
798 self.emit_type(&belief.ty);
799 self.emit.writeln(",");
800 }
801 self.emit.dedent();
802 self.emit.writeln("}");
803 }
804 self.emit.blank_line();
805
806 let output_type = self.infer_agent_output_type(agent);
808
809 self.emit.write("impl ");
811 self.emit.write(name);
812 self.emit.writeln(" {");
813 self.emit.indent();
814
815 for handler in &agent.handlers {
817 match &handler.event {
818 EventKind::Start => {
819 self.emit
820 .write("async fn on_start(self, ctx: &mut AgentContext<");
821 self.emit.write(&output_type);
822 self.emit.write(">) -> SageResult<");
823 self.emit.write(&output_type);
824 self.emit.writeln("> {");
825 self.emit.indent();
826 self.generate_block_contents(&handler.body);
827 self.emit.dedent();
828 self.emit.writeln("}");
829 }
830
831 EventKind::Error { param_name } => {
833 self.emit.write("async fn on_error(self, ");
834 self.emit.write(¶m_name.name);
835 self.emit.write(": SageError, ctx: &mut AgentContext<");
836 self.emit.write(&output_type);
837 self.emit.write(">) -> SageResult<");
838 self.emit.write(&output_type);
839 self.emit.writeln("> {");
840 self.emit.indent();
841 self.generate_block_contents(&handler.body);
842 self.emit.dedent();
843 self.emit.writeln("}");
844 }
845
846 _ => {}
848 }
849 }
850
851 self.emit.dedent();
852 self.emit.writeln("}");
853 }
854
855 fn generate_main(&mut self, agent: &AgentDecl) {
856 let entry_agent = &agent.name.name;
857 let has_error_handler = agent
858 .handlers
859 .iter()
860 .any(|h| matches!(h.event, EventKind::Error { .. }));
861
862 let has_tools = !agent.tool_uses.is_empty();
864
865 self.emit.writeln("#[tokio::main]");
866 self.emit
867 .writeln("async fn main() -> Result<(), Box<dyn std::error::Error>> {");
868 self.emit.indent();
869
870 let agent_construct = if has_tools {
872 let mut s = format!("{entry_agent} {{ ");
873 for (i, tool_use) in agent.tool_uses.iter().enumerate() {
874 if i > 0 {
875 s.push_str(", ");
876 }
877 s.push_str(&tool_use.name.to_lowercase());
879 s.push_str(": ");
880 s.push_str(&tool_use.name);
881 s.push_str("Client::from_env()");
882 }
883 s.push_str(" }");
884 s
885 } else {
886 entry_agent.to_string()
887 };
888
889 if has_error_handler {
890 self.emit
893 .writeln("let handle = sage_runtime::spawn(|mut ctx| async move {");
894 self.emit.indent();
895 self.emit.write("let agent = ");
896 self.emit.write(&agent_construct);
897 self.emit.writeln(";");
898 self.emit.writeln("match agent.on_start(&mut ctx).await {");
899 self.emit.indent();
900 self.emit.writeln("Ok(result) => Ok(result),");
901 self.emit.write("Err(e) => ");
902 self.emit.write(&agent_construct);
903 self.emit.writeln(".on_error(e, &mut ctx).await,");
904 self.emit.dedent();
905 self.emit.writeln("}");
906 self.emit.dedent();
907 self.emit.writeln("});");
908 } else {
909 self.emit
912 .writeln("let handle = sage_runtime::spawn(|mut ctx| async move {");
913 self.emit.indent();
914 self.emit.write(&agent_construct);
915 self.emit.writeln(".on_start(&mut ctx).await");
916 self.emit.dedent();
917 self.emit.writeln("});");
918 }
919
920 self.emit.writeln("let result = handle.result().await?;");
921 self.emit.writeln("println!(\"{:?}\", result);");
922 self.emit.writeln("Ok(())");
923
924 self.emit.dedent();
925 self.emit.writeln("}");
926 }
927
928 fn generate_block(&mut self, block: &Block) {
929 self.emit.open_brace();
930 self.generate_block_contents(block);
931 self.emit.close_brace();
932 }
933
934 fn generate_block_inline(&mut self, block: &Block) {
935 self.emit.open_brace();
936 self.generate_block_contents(block);
937 self.emit.close_brace_inline();
938 }
939
940 fn generate_block_contents(&mut self, block: &Block) {
941 for stmt in &block.stmts {
942 self.generate_stmt(stmt);
943 }
944 }
945
946 fn generate_stmt(&mut self, stmt: &Stmt) {
947 match stmt {
948 Stmt::Let {
949 name, ty, value, ..
950 } => {
951 self.emit.write("let ");
952 if ty.is_some() {
953 self.emit.write(&name.name);
954 self.emit.write(": ");
955 self.emit_type(ty.as_ref().unwrap());
956 } else {
957 self.emit.write(&name.name);
958 }
959 self.emit.write(" = ");
960 self.generate_expr(value);
961 self.emit.writeln(";");
962 }
963
964 Stmt::Assign { name, value, .. } => {
965 self.emit.write(&name.name);
966 self.emit.write(" = ");
967 self.generate_expr(value);
968 self.emit.writeln(";");
969 }
970
971 Stmt::Return { value, .. } => {
972 self.emit.write("return ");
973 if let Some(expr) = value {
974 self.generate_expr(expr);
975 }
976 self.emit.writeln(";");
977 }
978
979 Stmt::If {
980 condition,
981 then_block,
982 else_block,
983 ..
984 } => {
985 self.emit.write("if ");
986 self.generate_expr(condition);
987 self.emit.write(" ");
988 if else_block.is_some() {
989 self.generate_block_inline(then_block);
990 self.emit.write(" else ");
991 match else_block.as_ref().unwrap() {
992 sage_parser::ElseBranch::Block(block) => {
993 self.generate_block(block);
994 }
995 sage_parser::ElseBranch::ElseIf(stmt) => {
996 self.generate_stmt(stmt);
997 }
998 }
999 } else {
1000 self.generate_block(then_block);
1001 }
1002 }
1003
1004 Stmt::For {
1005 pattern,
1006 iter,
1007 body,
1008 ..
1009 } => {
1010 self.emit.write("for ");
1011 self.emit_pattern(pattern);
1012 self.emit.write(" in ");
1013 self.generate_expr(iter);
1014 self.emit.write(" ");
1015 self.generate_block(body);
1016 }
1017
1018 Stmt::While {
1019 condition, body, ..
1020 } => {
1021 self.emit.write("while ");
1022 self.generate_expr(condition);
1023 self.emit.write(" ");
1024 self.generate_block(body);
1025 }
1026
1027 Stmt::Loop { body, .. } => {
1028 self.emit.write("loop ");
1029 self.generate_block(body);
1030 }
1031
1032 Stmt::Break { .. } => {
1033 self.emit.writeln("break;");
1034 }
1035
1036 Stmt::Expr { expr, .. } => {
1037 if let Expr::Emit { value, .. } = expr {
1039 self.emit.write("return ctx.emit(");
1040 self.generate_expr(value);
1041 self.emit.writeln(");");
1042 } else {
1043 self.generate_expr(expr);
1044 self.emit.writeln(";");
1045 }
1046 }
1047
1048 Stmt::LetTuple { names, value, .. } => {
1049 self.emit.write("let (");
1050 for (i, name) in names.iter().enumerate() {
1051 if i > 0 {
1052 self.emit.write(", ");
1053 }
1054 self.emit.write(&name.name);
1055 }
1056 self.emit.write(") = ");
1057 self.generate_expr(value);
1058 self.emit.writeln(";");
1059 }
1060
1061 Stmt::MockInfer { value, .. } => {
1063 self.emit.write("// mock infer: ");
1066 match value {
1067 sage_parser::MockValue::Value(expr) => {
1068 self.generate_expr(expr);
1069 }
1070 sage_parser::MockValue::Fail(expr) => {
1071 self.emit.write("fail(");
1072 self.generate_expr(expr);
1073 self.emit.write(")");
1074 }
1075 }
1076 self.emit.writeln(";");
1077 }
1078 }
1079 }
1080
1081 fn generate_expr(&mut self, expr: &Expr) {
1082 match expr {
1083 Expr::Literal { value, .. } => {
1084 self.emit_literal(value);
1085 }
1086
1087 Expr::Var { name, .. } => {
1088 match name.name.as_str() {
1090 "PI" => self.emit.write("std::f64::consts::PI"),
1091 "E" => self.emit.write("std::f64::consts::E"),
1092 _ => self.emit.write(&name.name),
1093 }
1094 }
1095
1096 Expr::Binary {
1097 op, left, right, ..
1098 } => {
1099 if matches!(op, BinOp::Concat) {
1101 self.emit.write("format!(\"{}{}\", ");
1102 self.generate_expr(left);
1103 self.emit.write(", ");
1104 self.generate_expr(right);
1105 self.emit.write(")");
1106 } else {
1107 self.emit.write("(");
1108 self.generate_expr(left);
1109 self.emit.write(" ");
1110 self.emit_binop(op);
1111 self.emit.write(" ");
1112 self.generate_expr(right);
1113 self.emit.write(")");
1114 }
1115 }
1116
1117 Expr::Unary { op, operand, .. } => {
1118 self.emit_unaryop(op);
1119 self.generate_expr(operand);
1120 }
1121
1122 Expr::Call { name, args, .. } => {
1123 let fn_name = &name.name;
1124
1125 match fn_name.as_str() {
1127 "print" => {
1128 self.emit.write("println!(\"{}\", ");
1129 self.generate_expr(&args[0]);
1130 self.emit.write(")");
1131 }
1132 "str" => {
1133 self.generate_expr(&args[0]);
1134 self.emit.write(".to_string()");
1135 }
1136 "len" => {
1137 self.generate_expr(&args[0]);
1138 self.emit.write(".len() as i64");
1139 }
1140
1141 "split" => {
1143 self.generate_expr(&args[0]);
1144 self.emit.write(".split(&*");
1145 self.generate_expr(&args[1]);
1146 self.emit.write(").map(str::to_string).collect::<Vec<_>>()");
1147 }
1148 "trim" => {
1149 self.generate_expr(&args[0]);
1150 self.emit.write(".trim().to_string()");
1151 }
1152 "trim_start" => {
1153 self.generate_expr(&args[0]);
1154 self.emit.write(".trim_start().to_string()");
1155 }
1156 "trim_end" => {
1157 self.generate_expr(&args[0]);
1158 self.emit.write(".trim_end().to_string()");
1159 }
1160 "starts_with" => {
1161 self.generate_expr(&args[0]);
1162 self.emit.write(".starts_with(&*");
1163 self.generate_expr(&args[1]);
1164 self.emit.write(")");
1165 }
1166 "ends_with" => {
1167 self.generate_expr(&args[0]);
1168 self.emit.write(".ends_with(&*");
1169 self.generate_expr(&args[1]);
1170 self.emit.write(")");
1171 }
1172 "replace" => {
1173 self.generate_expr(&args[0]);
1174 self.emit.write(".replace(&*");
1175 self.generate_expr(&args[1]);
1176 self.emit.write(", &*");
1177 self.generate_expr(&args[2]);
1178 self.emit.write(")");
1179 }
1180 "replace_first" => {
1181 self.generate_expr(&args[0]);
1182 self.emit.write(".replacen(&*");
1183 self.generate_expr(&args[1]);
1184 self.emit.write(", &*");
1185 self.generate_expr(&args[2]);
1186 self.emit.write(", 1)");
1187 }
1188 "to_upper" => {
1189 self.generate_expr(&args[0]);
1190 self.emit.write(".to_uppercase()");
1191 }
1192 "to_lower" => {
1193 self.generate_expr(&args[0]);
1194 self.emit.write(".to_lowercase()");
1195 }
1196 "str_len" => {
1197 self.generate_expr(&args[0]);
1198 self.emit.write(".chars().count() as i64");
1199 }
1200 "str_slice" => {
1201 self.emit.write("sage_runtime::stdlib::str_slice(&");
1202 self.generate_expr(&args[0]);
1203 self.emit.write(", ");
1204 self.generate_expr(&args[1]);
1205 self.emit.write(", ");
1206 self.generate_expr(&args[2]);
1207 self.emit.write(")");
1208 }
1209 "str_index_of" => {
1210 self.emit.write("sage_runtime::stdlib::str_index_of(&");
1211 self.generate_expr(&args[0]);
1212 self.emit.write(", &");
1213 self.generate_expr(&args[1]);
1214 self.emit.write(")");
1215 }
1216 "str_repeat" => {
1217 self.generate_expr(&args[0]);
1218 self.emit.write(".repeat(");
1219 self.generate_expr(&args[1]);
1220 self.emit.write(" as usize)");
1221 }
1222 "str_pad_start" => {
1223 self.emit.write("sage_runtime::stdlib::str_pad_start(&");
1224 self.generate_expr(&args[0]);
1225 self.emit.write(", ");
1226 self.generate_expr(&args[1]);
1227 self.emit.write(", &");
1228 self.generate_expr(&args[2]);
1229 self.emit.write(")");
1230 }
1231 "str_pad_end" => {
1232 self.emit.write("sage_runtime::stdlib::str_pad_end(&");
1233 self.generate_expr(&args[0]);
1234 self.emit.write(", ");
1235 self.generate_expr(&args[1]);
1236 self.emit.write(", &");
1237 self.generate_expr(&args[2]);
1238 self.emit.write(")");
1239 }
1240
1241 "abs" => {
1243 self.generate_expr(&args[0]);
1244 self.emit.write(".abs()");
1245 }
1246 "abs_float" => {
1247 self.generate_expr(&args[0]);
1248 self.emit.write(".abs()");
1249 }
1250 "min" => {
1251 self.generate_expr(&args[0]);
1252 self.emit.write(".min(");
1253 self.generate_expr(&args[1]);
1254 self.emit.write(")");
1255 }
1256 "max" => {
1257 self.generate_expr(&args[0]);
1258 self.emit.write(".max(");
1259 self.generate_expr(&args[1]);
1260 self.emit.write(")");
1261 }
1262 "min_float" => {
1263 self.generate_expr(&args[0]);
1264 self.emit.write(".min(");
1265 self.generate_expr(&args[1]);
1266 self.emit.write(")");
1267 }
1268 "max_float" => {
1269 self.generate_expr(&args[0]);
1270 self.emit.write(".max(");
1271 self.generate_expr(&args[1]);
1272 self.emit.write(")");
1273 }
1274 "clamp" => {
1275 self.generate_expr(&args[0]);
1276 self.emit.write(".clamp(");
1277 self.generate_expr(&args[1]);
1278 self.emit.write(", ");
1279 self.generate_expr(&args[2]);
1280 self.emit.write(")");
1281 }
1282 "clamp_float" => {
1283 self.generate_expr(&args[0]);
1284 self.emit.write(".clamp(");
1285 self.generate_expr(&args[1]);
1286 self.emit.write(", ");
1287 self.generate_expr(&args[2]);
1288 self.emit.write(")");
1289 }
1290 "floor" => {
1291 self.generate_expr(&args[0]);
1292 self.emit.write(".floor() as i64");
1293 }
1294 "ceil" => {
1295 self.generate_expr(&args[0]);
1296 self.emit.write(".ceil() as i64");
1297 }
1298 "round" => {
1299 self.generate_expr(&args[0]);
1300 self.emit.write(".round() as i64");
1301 }
1302 "floor_float" => {
1303 self.generate_expr(&args[0]);
1304 self.emit.write(".floor()");
1305 }
1306 "ceil_float" => {
1307 self.generate_expr(&args[0]);
1308 self.emit.write(".ceil()");
1309 }
1310 "pow" => {
1311 self.emit.write("{ let __base = ");
1313 self.generate_expr(&args[0]);
1314 self.emit.write("; let __exp = ");
1315 self.generate_expr(&args[1]);
1316 self.emit.write("; if __exp < 0 { 0 } else { __base.pow(__exp as u32) } }");
1317 }
1318 "pow_float" => {
1319 self.generate_expr(&args[0]);
1320 self.emit.write(".powf(");
1321 self.generate_expr(&args[1]);
1322 self.emit.write(")");
1323 }
1324 "sqrt" => {
1325 self.generate_expr(&args[0]);
1326 self.emit.write(".sqrt()");
1327 }
1328 "int_to_float" => {
1329 self.generate_expr(&args[0]);
1330 self.emit.write(" as f64");
1331 }
1332 "float_to_int" => {
1333 self.generate_expr(&args[0]);
1334 self.emit.write(" as i64");
1335 }
1336
1337 "parse_int" => {
1339 self.generate_expr(&args[0]);
1340 self.emit.write(".trim().parse::<i64>().map_err(|e| e.to_string())");
1341 }
1342 "parse_float" => {
1343 self.generate_expr(&args[0]);
1344 self.emit.write(".trim().parse::<f64>().map_err(|e| e.to_string())");
1345 }
1346 "parse_bool" => {
1347 self.emit.write("sage_runtime::stdlib::parse_bool(&");
1348 self.generate_expr(&args[0]);
1349 self.emit.write(")");
1350 }
1351 "float_to_str" => {
1352 self.generate_expr(&args[0]);
1353 self.emit.write(".to_string()");
1354 }
1355 "bool_to_str" => {
1356 self.emit.write("if ");
1357 self.generate_expr(&args[0]);
1358 self.emit.write(" { \"true\".to_string() } else { \"false\".to_string() }");
1359 }
1360
1361 "map" => {
1363 self.generate_expr(&args[0]);
1364 self.emit.write(".into_iter().map(");
1365 self.generate_expr(&args[1]);
1366 self.emit.write(").collect::<Vec<_>>()");
1367 }
1368 "filter" => {
1369 self.generate_expr(&args[0]);
1370 self.emit.write(".into_iter().filter(|__x| (");
1371 self.generate_expr(&args[1]);
1372 self.emit.write(")((__x).clone())).collect::<Vec<_>>()");
1373 }
1374 "reduce" => {
1375 self.generate_expr(&args[0]);
1376 self.emit.write(".into_iter().fold(");
1377 self.generate_expr(&args[1]);
1378 self.emit.write(", ");
1379 self.generate_expr(&args[2]);
1380 self.emit.write(")");
1381 }
1382 "any" => {
1383 self.generate_expr(&args[0]);
1384 self.emit.write(".into_iter().any(|__x| (");
1385 self.generate_expr(&args[1]);
1386 self.emit.write(")((__x).clone()))");
1387 }
1388 "all" => {
1389 self.generate_expr(&args[0]);
1390 self.emit.write(".into_iter().all(|__x| (");
1391 self.generate_expr(&args[1]);
1392 self.emit.write(")((__x).clone()))");
1393 }
1394 "find" => {
1395 self.generate_expr(&args[0]);
1396 self.emit.write(".into_iter().find(|__x| (");
1397 self.generate_expr(&args[1]);
1398 self.emit.write(")((__x).clone()))");
1399 }
1400 "flat_map" => {
1401 self.generate_expr(&args[0]);
1402 self.emit.write(".into_iter().flat_map(");
1403 self.generate_expr(&args[1]);
1404 self.emit.write(").collect::<Vec<_>>()");
1405 }
1406 "zip" => {
1407 self.generate_expr(&args[0]);
1408 self.emit.write(".into_iter().zip(");
1409 self.generate_expr(&args[1]);
1410 self.emit.write(".into_iter()).collect::<Vec<_>>()");
1411 }
1412 "sort_by" => {
1413 self.emit.write("{ let mut __v = ");
1414 self.generate_expr(&args[0]);
1415 self.emit.write("; __v.sort_by(|__a, __b| { let __cmp = (");
1416 self.generate_expr(&args[1]);
1417 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 }");
1418 }
1419 "enumerate" => {
1420 self.generate_expr(&args[0]);
1421 self.emit
1422 .write(".into_iter().enumerate().map(|(__i, __x)| (__i as i64, __x)).collect::<Vec<_>>()");
1423 }
1424 "take" => {
1425 self.generate_expr(&args[0]);
1426 self.emit.write(".into_iter().take(");
1427 self.generate_expr(&args[1]);
1428 self.emit.write(" as usize).collect::<Vec<_>>()");
1429 }
1430 "drop" => {
1431 self.generate_expr(&args[0]);
1432 self.emit.write(".into_iter().skip(");
1433 self.generate_expr(&args[1]);
1434 self.emit.write(" as usize).collect::<Vec<_>>()");
1435 }
1436 "flatten" => {
1437 self.generate_expr(&args[0]);
1438 self.emit.write(".into_iter().flatten().collect::<Vec<_>>()");
1439 }
1440 "reverse" => {
1441 self.emit.write("{ let mut __v = ");
1442 self.generate_expr(&args[0]);
1443 self.emit.write("; __v.reverse(); __v }");
1444 }
1445 "unique" => {
1446 self.emit.write("{ let mut __seen = std::collections::HashSet::new(); ");
1447 self.generate_expr(&args[0]);
1448 self.emit.write(".into_iter().filter(|__x| __seen.insert(format!(\"{:?}\", __x))).collect::<Vec<_>>() }");
1449 }
1450 "count_where" => {
1451 self.generate_expr(&args[0]);
1452 self.emit.write(".into_iter().filter(|__x| (");
1453 self.generate_expr(&args[1]);
1454 self.emit.write(")((__x).clone())).count() as i64");
1455 }
1456 "sum" => {
1457 self.generate_expr(&args[0]);
1458 self.emit.write(".iter().sum::<i64>()");
1459 }
1460 "sum_floats" => {
1461 self.generate_expr(&args[0]);
1462 self.emit.write(".iter().sum::<f64>()");
1463 }
1464
1465 _ => {
1466 self.emit.write(fn_name);
1467 self.emit.write("(");
1468 for (i, arg) in args.iter().enumerate() {
1469 if i > 0 {
1470 self.emit.write(", ");
1471 }
1472 self.generate_expr(arg);
1473 }
1474 self.emit.write(")");
1475 }
1476 }
1477 }
1478
1479 Expr::SelfField { field, .. } => {
1480 self.emit.write("self.");
1481 self.emit.write(&field.name);
1482 }
1483
1484 Expr::SelfMethodCall { method, args, .. } => {
1485 self.emit.write("self.");
1486 self.emit.write(&method.name);
1487 self.emit.write("(");
1488 for (i, arg) in args.iter().enumerate() {
1489 if i > 0 {
1490 self.emit.write(", ");
1491 }
1492 self.generate_expr(arg);
1493 }
1494 self.emit.write(")");
1495 }
1496
1497 Expr::List { elements, .. } => {
1498 self.emit.write("vec![");
1499 for (i, elem) in elements.iter().enumerate() {
1500 if i > 0 {
1501 self.emit.write(", ");
1502 }
1503 self.generate_expr(elem);
1504 }
1505 self.emit.write("]");
1506 }
1507
1508 Expr::Paren { inner, .. } => {
1509 self.emit.write("(");
1510 self.generate_expr(inner);
1511 self.emit.write(")");
1512 }
1513
1514 Expr::Infer { template, .. } => {
1515 self.emit.write("ctx.infer_string(&");
1516 self.emit_string_template(template);
1517 self.emit.write(").await?");
1518 }
1519
1520 Expr::Spawn { agent, fields, .. } => {
1521 self.emit.write("sage_runtime::spawn(|ctx| ");
1522 self.emit.write(&agent.name);
1523 if fields.is_empty() {
1524 self.emit.write(".on_start(ctx))");
1525 } else {
1526 self.emit.write(" { ");
1527 for (i, field) in fields.iter().enumerate() {
1528 if i > 0 {
1529 self.emit.write(", ");
1530 }
1531 self.emit.write(&field.name.name);
1532 self.emit.write(": ");
1533 self.generate_expr(&field.value);
1534 }
1535 self.emit.write(" }.on_start(ctx))");
1536 }
1537 }
1538
1539 Expr::Await { handle, .. } => {
1540 self.generate_expr(handle);
1541 self.emit.write(".result().await?");
1542 }
1543
1544 Expr::Send {
1545 handle, message, ..
1546 } => {
1547 self.generate_expr(handle);
1548 self.emit.write(".send(sage_runtime::Message::new(");
1549 self.generate_expr(message);
1550 self.emit.write(")?).await?");
1551 }
1552
1553 Expr::Emit { value, .. } => {
1554 self.emit.write("ctx.emit(");
1555 self.generate_expr(value);
1556 self.emit.write(")");
1557 }
1558
1559 Expr::StringInterp { template, .. } => {
1560 self.emit_string_template(template);
1561 }
1562
1563 Expr::Match {
1564 scrutinee, arms, ..
1565 } => {
1566 self.emit.write("match ");
1567 self.generate_expr(scrutinee);
1568 self.emit.writeln(" {");
1569 self.emit.indent();
1570 for arm in arms {
1571 self.emit_pattern(&arm.pattern);
1572 self.emit.write(" => ");
1573 self.generate_expr(&arm.body);
1574 self.emit.writeln(",");
1575 }
1576 self.emit.dedent();
1577 self.emit.write("}");
1578 }
1579
1580 Expr::RecordConstruct { name, fields, .. } => {
1581 self.emit.write(&name.name);
1582 self.emit.write(" { ");
1583 for (i, field) in fields.iter().enumerate() {
1584 if i > 0 {
1585 self.emit.write(", ");
1586 }
1587 self.emit.write(&field.name.name);
1588 self.emit.write(": ");
1589 self.generate_expr(&field.value);
1590 }
1591 self.emit.write(" }");
1592 }
1593
1594 Expr::FieldAccess { object, field, .. } => {
1595 self.generate_expr(object);
1596 self.emit.write(".");
1597 self.emit.write(&field.name);
1598 }
1599
1600 Expr::Receive { .. } => {
1601 self.emit.write("ctx.receive().await?");
1602 }
1603
1604 Expr::Try { expr, .. } => {
1606 self.generate_expr(expr);
1608 self.emit.write("?");
1609 }
1610
1611 Expr::Catch {
1612 expr,
1613 error_bind,
1614 recovery,
1615 ..
1616 } => {
1617 self.emit.write("match ");
1619 self.generate_expr(expr);
1620 self.emit.writeln(" {");
1621 self.emit.indent();
1622
1623 self.emit.writeln("Ok(__val) => __val,");
1625
1626 if let Some(err_name) = error_bind {
1628 self.emit.write("Err(");
1629 self.emit.write(&err_name.name);
1630 self.emit.write(") => ");
1631 } else {
1632 self.emit.write("Err(_) => ");
1633 }
1634 self.generate_expr(recovery);
1635 self.emit.writeln(",");
1636
1637 self.emit.dedent();
1638 self.emit.write("}");
1639 }
1640
1641 Expr::Closure { params, body, .. } => {
1643 self.emit.write("Box::new(move |");
1645 for (i, param) in params.iter().enumerate() {
1646 if i > 0 {
1647 self.emit.write(", ");
1648 }
1649 self.emit.write(¶m.name.name);
1650 if let Some(ty) = ¶m.ty {
1651 self.emit.write(": ");
1652 self.emit_type(ty);
1653 }
1654 }
1655 self.emit.write("| ");
1656 self.generate_expr(body);
1657 self.emit.write(")");
1658 }
1659
1660 Expr::Tuple { elements, .. } => {
1662 self.emit.write("(");
1663 for (i, elem) in elements.iter().enumerate() {
1664 if i > 0 {
1665 self.emit.write(", ");
1666 }
1667 self.generate_expr(elem);
1668 }
1669 self.emit.write(")");
1670 }
1671
1672 Expr::TupleIndex { tuple, index, .. } => {
1673 self.generate_expr(tuple);
1674 self.emit.write(&format!(".{index}"));
1675 }
1676
1677 Expr::Map { entries, .. } => {
1678 if entries.is_empty() {
1679 self.emit.write("std::collections::HashMap::new()");
1680 } else {
1681 self.emit.write("std::collections::HashMap::from([");
1682 for (i, entry) in entries.iter().enumerate() {
1683 if i > 0 {
1684 self.emit.write(", ");
1685 }
1686 self.emit.write("(");
1687 self.generate_expr(&entry.key);
1688 self.emit.write(", ");
1689 self.generate_expr(&entry.value);
1690 self.emit.write(")");
1691 }
1692 self.emit.write("])");
1693 }
1694 }
1695
1696 Expr::VariantConstruct {
1697 enum_name,
1698 variant,
1699 payload,
1700 ..
1701 } => {
1702 self.emit.write(&enum_name.name);
1703 self.emit.write("::");
1704 self.emit.write(&variant.name);
1705 if let Some(payload_expr) = payload {
1706 self.emit.write("(");
1707 self.generate_expr(payload_expr);
1708 self.emit.write(")");
1709 }
1710 }
1711
1712 Expr::ToolCall {
1714 tool,
1715 function,
1716 args,
1717 ..
1718 } => {
1719 self.emit.write("self.");
1722 self.emit.write(&tool.name.to_lowercase());
1723 self.emit.write(".");
1724 self.emit.write(&function.name);
1725 self.emit.write("(");
1726 for (i, arg) in args.iter().enumerate() {
1727 if i > 0 {
1728 self.emit.write(", ");
1729 }
1730 self.generate_expr(arg);
1731 }
1732 self.emit.write(").await");
1733 }
1734 }
1735 }
1736
1737 fn emit_pattern(&mut self, pattern: &sage_parser::Pattern) {
1738 use sage_parser::Pattern;
1739 match pattern {
1740 Pattern::Wildcard { .. } => {
1741 self.emit.write("_");
1742 }
1743 Pattern::Variant {
1744 enum_name,
1745 variant,
1746 payload,
1747 ..
1748 } => {
1749 if let Some(enum_name) = enum_name {
1750 self.emit.write(&enum_name.name);
1751 self.emit.write("::");
1752 }
1753 self.emit.write(&variant.name);
1754 if let Some(inner_pattern) = payload {
1755 self.emit.write("(");
1756 self.emit_pattern(inner_pattern);
1757 self.emit.write(")");
1758 }
1759 }
1760 Pattern::Literal { value, .. } => {
1761 self.emit_literal(value);
1762 }
1763 Pattern::Binding { name, .. } => {
1764 self.emit.write(&name.name);
1765 }
1766 Pattern::Tuple { elements, .. } => {
1767 self.emit.write("(");
1768 for (i, elem) in elements.iter().enumerate() {
1769 if i > 0 {
1770 self.emit.write(", ");
1771 }
1772 self.emit_pattern(elem);
1773 }
1774 self.emit.write(")");
1775 }
1776 }
1777 }
1778
1779 fn emit_literal(&mut self, lit: &Literal) {
1780 match lit {
1781 Literal::Int(n) => {
1782 self.emit.write(&format!("{n}_i64"));
1783 }
1784 Literal::Float(f) => {
1785 self.emit.write(&format!("{f}_f64"));
1786 }
1787 Literal::Bool(b) => {
1788 self.emit.write(if *b { "true" } else { "false" });
1789 }
1790 Literal::String(s) => {
1791 self.emit.write("\"");
1793 for c in s.chars() {
1794 match c {
1795 '"' => self.emit.write_raw("\\\""),
1796 '\\' => self.emit.write_raw("\\\\"),
1797 '\n' => self.emit.write_raw("\\n"),
1798 '\r' => self.emit.write_raw("\\r"),
1799 '\t' => self.emit.write_raw("\\t"),
1800 _ => self.emit.write_raw(&c.to_string()),
1801 }
1802 }
1803 self.emit.write("\".to_string()");
1804 }
1805 }
1806 }
1807
1808 fn emit_string_template(&mut self, template: &sage_parser::StringTemplate) {
1809 if !template.has_interpolations() {
1810 if let Some(StringPart::Literal(s)) = template.parts.first() {
1812 self.emit.write("\"");
1813 self.emit.write_raw(s);
1814 self.emit.write("\".to_string()");
1815 }
1816 return;
1817 }
1818
1819 self.emit.write("format!(\"");
1821 for part in &template.parts {
1822 match part {
1823 StringPart::Literal(s) => {
1824 let escaped = s.replace('{', "{{").replace('}', "}}");
1826 self.emit.write_raw(&escaped);
1827 }
1828 StringPart::Interpolation(_) => {
1829 self.emit.write_raw("{}");
1830 }
1831 }
1832 }
1833 self.emit.write("\"");
1834
1835 for part in &template.parts {
1837 if let StringPart::Interpolation(interp_expr) = part {
1838 self.emit.write(", ");
1839 self.emit_interp_expr(interp_expr);
1840 }
1841 }
1842 self.emit.write(")");
1843 }
1844
1845 fn emit_interp_expr(&mut self, expr: &InterpExpr) {
1847 match expr {
1848 InterpExpr::Ident(ident) => {
1849 self.emit.write(&ident.name);
1850 }
1851 InterpExpr::FieldAccess { base, field, .. } => {
1852 self.emit_interp_expr(base);
1853 self.emit.write(".");
1854 self.emit.write(&field.name);
1855 }
1856 InterpExpr::TupleIndex { base, index, .. } => {
1857 self.emit_interp_expr(base);
1858 self.emit.write(".");
1859 self.emit.write(&index.to_string());
1860 }
1861 }
1862 }
1863
1864 fn emit_type(&mut self, ty: &TypeExpr) {
1865 match ty {
1866 TypeExpr::Int => self.emit.write("i64"),
1867 TypeExpr::Float => self.emit.write("f64"),
1868 TypeExpr::Bool => self.emit.write("bool"),
1869 TypeExpr::String => self.emit.write("String"),
1870 TypeExpr::Unit => self.emit.write("()"),
1871 TypeExpr::List(inner) => {
1872 self.emit.write("Vec<");
1873 self.emit_type(inner);
1874 self.emit.write(">");
1875 }
1876 TypeExpr::Option(inner) => {
1877 self.emit.write("Option<");
1878 self.emit_type(inner);
1879 self.emit.write(">");
1880 }
1881 TypeExpr::Inferred(inner) => {
1882 self.emit_type(inner);
1884 }
1885 TypeExpr::Agent(agent_name) => {
1886 self.emit.write("AgentHandle<");
1889 self.emit.write(&agent_name.name);
1890 self.emit.write("Output>");
1891 }
1892 TypeExpr::Named(name) => {
1893 self.emit.write(&name.name);
1894 }
1895
1896 TypeExpr::Error => {
1898 self.emit.write("sage_runtime::SageError");
1899 }
1900
1901 TypeExpr::Fn(params, ret) => {
1903 self.emit.write("Box<dyn Fn(");
1904 for (i, param) in params.iter().enumerate() {
1905 if i > 0 {
1906 self.emit.write(", ");
1907 }
1908 self.emit_type(param);
1909 }
1910 self.emit.write(") -> ");
1911 self.emit_type(ret);
1912 self.emit.write(" + Send + 'static>");
1913 }
1914
1915 TypeExpr::Map(key, value) => {
1917 self.emit.write("std::collections::HashMap<");
1918 self.emit_type(key);
1919 self.emit.write(", ");
1920 self.emit_type(value);
1921 self.emit.write(">");
1922 }
1923 TypeExpr::Tuple(elems) => {
1924 self.emit.write("(");
1925 for (i, elem) in elems.iter().enumerate() {
1926 if i > 0 {
1927 self.emit.write(", ");
1928 }
1929 self.emit_type(elem);
1930 }
1931 self.emit.write(")");
1932 }
1933 TypeExpr::Result(ok, err) => {
1934 self.emit.write("Result<");
1935 self.emit_type(ok);
1936 self.emit.write(", ");
1937 self.emit_type(err);
1938 self.emit.write(">");
1939 }
1940 }
1941 }
1942
1943 fn emit_binop(&mut self, op: &BinOp) {
1944 let s = match op {
1945 BinOp::Add => "+",
1946 BinOp::Sub => "-",
1947 BinOp::Mul => "*",
1948 BinOp::Div => "/",
1949 BinOp::Rem => "%",
1950 BinOp::Eq => "==",
1951 BinOp::Ne => "!=",
1952 BinOp::Lt => "<",
1953 BinOp::Gt => ">",
1954 BinOp::Le => "<=",
1955 BinOp::Ge => ">=",
1956 BinOp::And => "&&",
1957 BinOp::Or => "||",
1958 BinOp::Concat => "++", };
1960 self.emit.write(s);
1961 }
1962
1963 fn emit_unaryop(&mut self, op: &UnaryOp) {
1964 let s = match op {
1965 UnaryOp::Neg => "-",
1966 UnaryOp::Not => "!",
1967 };
1968 self.emit.write(s);
1969 }
1970
1971 fn infer_agent_output_type(&self, agent: &AgentDecl) -> String {
1972 for handler in &agent.handlers {
1975 if let EventKind::Start = &handler.event {
1976 if let Some(ty) = self.find_emit_type(&handler.body) {
1977 return ty;
1978 }
1979 }
1980 }
1981 "i64".to_string()
1982 }
1983
1984 fn find_emit_type(&self, block: &Block) -> Option<String> {
1985 for stmt in &block.stmts {
1986 if let Stmt::Expr { expr, .. } = stmt {
1987 if let Expr::Emit { value, .. } = expr {
1988 return Some(self.infer_expr_type(value));
1989 }
1990 }
1991 if let Stmt::If {
1993 then_block,
1994 else_block,
1995 ..
1996 } = stmt
1997 {
1998 if let Some(ty) = self.find_emit_type(then_block) {
1999 return Some(ty);
2000 }
2001 if let Some(else_branch) = else_block {
2002 if let sage_parser::ElseBranch::Block(block) = else_branch {
2003 if let Some(ty) = self.find_emit_type(block) {
2004 return Some(ty);
2005 }
2006 }
2007 }
2008 }
2009 }
2010 None
2011 }
2012
2013 fn infer_expr_type(&self, expr: &Expr) -> String {
2014 match expr {
2015 Expr::Literal { value, .. } => match value {
2016 Literal::Int(_) => "i64".to_string(),
2017 Literal::Float(_) => "f64".to_string(),
2018 Literal::Bool(_) => "bool".to_string(),
2019 Literal::String(_) => "String".to_string(),
2020 },
2021 Expr::Var { .. } => "i64".to_string(), Expr::Binary { op, .. } => {
2023 if matches!(
2024 op,
2025 BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Gt | BinOp::Le | BinOp::Ge
2026 ) {
2027 "bool".to_string()
2028 } else if matches!(op, BinOp::Concat) {
2029 "String".to_string()
2030 } else {
2031 "i64".to_string()
2032 }
2033 }
2034 Expr::Infer { .. } | Expr::StringInterp { .. } => "String".to_string(),
2035 Expr::Call { name, .. } if name.name == "str" => "String".to_string(),
2036 Expr::Call { name, .. } if name.name == "len" => "i64".to_string(),
2037 _ => "i64".to_string(),
2038 }
2039 }
2040}
2041
2042#[cfg(test)]
2043mod tests {
2044 use super::*;
2045 use sage_parser::{lex, parse};
2046 use std::sync::Arc;
2047
2048 fn generate_source(source: &str) -> String {
2049 let lex_result = lex(source).expect("lexing failed");
2050 let source_arc: Arc<str> = Arc::from(source);
2051 let (program, errors) = parse(lex_result.tokens(), source_arc);
2052 assert!(errors.is_empty(), "parse errors: {errors:?}");
2053 let program = program.expect("should parse");
2054 generate(&program, "test").main_rs
2055 }
2056
2057 #[test]
2058 fn generate_minimal_program() {
2059 let source = r#"
2060 agent Main {
2061 on start {
2062 emit(42);
2063 }
2064 }
2065 run Main;
2066 "#;
2067
2068 let output = generate_source(source);
2069 assert!(output.contains("struct Main;"));
2070 assert!(output.contains("async fn on_start"));
2071 assert!(output.contains("ctx.emit(42_i64)"));
2072 assert!(output.contains("#[tokio::main]"));
2073 }
2074
2075 #[test]
2076 fn generate_function() {
2077 let source = r#"
2078 fn add(a: Int, b: Int) -> Int {
2079 return a + b;
2080 }
2081 agent Main {
2082 on start {
2083 emit(add(1, 2));
2084 }
2085 }
2086 run Main;
2087 "#;
2088
2089 let output = generate_source(source);
2090 assert!(output.contains("fn add(a: i64, b: i64) -> i64"));
2091 assert!(output.contains("return (a + b);"));
2092 }
2093
2094 #[test]
2095 fn generate_agent_with_beliefs() {
2096 let source = r#"
2097 agent Worker {
2098 value: Int
2099
2100 on start {
2101 emit(self.value * 2);
2102 }
2103 }
2104 agent Main {
2105 on start {
2106 emit(0);
2107 }
2108 }
2109 run Main;
2110 "#;
2111
2112 let output = generate_source(source);
2113 assert!(output.contains("struct Worker {"));
2114 assert!(output.contains("value: i64,"));
2115 assert!(output.contains("self.value"));
2116 }
2117
2118 #[test]
2119 fn generate_string_interpolation() {
2120 let source = r#"
2121 agent Main {
2122 on start {
2123 let name = "World";
2124 let msg = "Hello, {name}!";
2125 print(msg);
2126 emit(0);
2127 }
2128 }
2129 run Main;
2130 "#;
2131
2132 let output = generate_source(source);
2133 assert!(output.contains("format!(\"Hello, {}!\", name)"));
2134 }
2135
2136 #[test]
2137 fn generate_control_flow() {
2138 let source = r#"
2139 agent Main {
2140 on start {
2141 let x = 10;
2142 if x > 5 {
2143 emit(1);
2144 } else {
2145 emit(0);
2146 }
2147 }
2148 }
2149 run Main;
2150 "#;
2151
2152 let output = generate_source(source);
2153 assert!(output.contains("if (x > 5_i64)"), "output:\n{output}");
2154 assert!(output.contains("else"), "output:\n{output}");
2156 }
2157
2158 #[test]
2159 fn generate_loops() {
2160 let source = r#"
2161 agent Main {
2162 on start {
2163 for x in [1, 2, 3] {
2164 print(str(x));
2165 }
2166 let n = 0;
2167 while n < 5 {
2168 n = n + 1;
2169 }
2170 emit(n);
2171 }
2172 }
2173 run Main;
2174 "#;
2175
2176 let output = generate_source(source);
2177 assert!(output.contains("for x in vec![1_i64, 2_i64, 3_i64]"));
2178 assert!(output.contains("while (n < 5_i64)"));
2179 }
2180
2181 #[test]
2182 fn generate_pub_function() {
2183 let source = r#"
2184 pub fn helper(x: Int) -> Int {
2185 return x * 2;
2186 }
2187 agent Main {
2188 on start {
2189 emit(helper(21));
2190 }
2191 }
2192 run Main;
2193 "#;
2194
2195 let output = generate_source(source);
2196 assert!(output.contains("pub fn helper(x: i64) -> i64"));
2197 }
2198
2199 #[test]
2200 fn generate_pub_agent() {
2201 let source = r#"
2202 pub agent Worker {
2203 on start {
2204 emit(42);
2205 }
2206 }
2207 agent Main {
2208 on start {
2209 emit(0);
2210 }
2211 }
2212 run Main;
2213 "#;
2214
2215 let output = generate_source(source);
2216 assert!(output.contains("pub struct Worker;"));
2217 }
2218
2219 #[test]
2220 fn generate_module_tree_simple() {
2221 use sage_loader::load_single_file;
2222 use std::fs;
2223 use tempfile::TempDir;
2224
2225 let dir = TempDir::new().unwrap();
2226 let file = dir.path().join("test.sg");
2227 fs::write(
2228 &file,
2229 r#"
2230agent Main {
2231 on start {
2232 emit(42);
2233 }
2234}
2235run Main;
2236"#,
2237 )
2238 .unwrap();
2239
2240 let tree = load_single_file(&file).unwrap();
2241 let project = generate_module_tree(&tree, "test");
2242
2243 assert!(project.main_rs.contains("struct Main;"));
2244 assert!(project.main_rs.contains("async fn on_start"));
2245 assert!(project.main_rs.contains("#[tokio::main]"));
2246 }
2247
2248 #[test]
2249 fn generate_record_declaration() {
2250 let source = r#"
2251 record Point {
2252 x: Int,
2253 y: Int,
2254 }
2255 agent Main {
2256 on start {
2257 let p = Point { x: 10, y: 20 };
2258 emit(p.x);
2259 }
2260 }
2261 run Main;
2262 "#;
2263
2264 let output = generate_source(source);
2265 assert!(output.contains("#[derive(Debug, Clone)]"));
2266 assert!(output.contains("struct Point {"));
2267 assert!(output.contains("x: i64,"));
2268 assert!(output.contains("y: i64,"));
2269 assert!(output.contains("Point { x: 10_i64, y: 20_i64 }"));
2270 assert!(output.contains("p.x"));
2271 }
2272
2273 #[test]
2274 fn generate_enum_declaration() {
2275 let source = r#"
2276 enum Status {
2277 Active,
2278 Inactive,
2279 Pending,
2280 }
2281 agent Main {
2282 on start {
2283 emit(0);
2284 }
2285 }
2286 run Main;
2287 "#;
2288
2289 let output = generate_source(source);
2290 assert!(output.contains("#[derive(Debug, Clone, Copy, PartialEq, Eq)]"));
2291 assert!(output.contains("enum Status {"));
2292 assert!(output.contains("Active,"));
2293 assert!(output.contains("Inactive,"));
2294 assert!(output.contains("Pending,"));
2295 }
2296
2297 #[test]
2298 fn generate_const_declaration() {
2299 let source = r#"
2300 const MAX_SIZE: Int = 100;
2301 const GREETING: String = "Hello";
2302 agent Main {
2303 on start {
2304 emit(MAX_SIZE);
2305 }
2306 }
2307 run Main;
2308 "#;
2309
2310 let output = generate_source(source);
2311 assert!(output.contains("const MAX_SIZE: i64 = 100_i64;"));
2312 assert!(output.contains("const GREETING: String = \"Hello\".to_string();"));
2313 }
2314
2315 #[test]
2316 fn generate_match_expression() {
2317 let source = r#"
2318 enum Status {
2319 Active,
2320 Inactive,
2321 }
2322 fn check_status(s: Status) -> Int {
2323 return match s {
2324 Active => 1,
2325 Inactive => 0,
2326 };
2327 }
2328 agent Main {
2329 on start {
2330 emit(0);
2331 }
2332 }
2333 run Main;
2334 "#;
2335
2336 let output = generate_source(source);
2337 assert!(output.contains("match s {"));
2338 assert!(output.contains("Active => 1_i64,"));
2339 assert!(output.contains("Inactive => 0_i64,"));
2340 }
2341
2342 #[test]
2347 fn generate_fallible_function() {
2348 let source = r#"
2349 fn get_data(url: String) -> String fails {
2350 return url;
2351 }
2352 agent Main {
2353 on start { emit(0); }
2354 }
2355 run Main;
2356 "#;
2357
2358 let output = generate_source(source);
2359 assert!(output.contains("fn get_data(url: String) -> SageResult<String>"));
2361 }
2362
2363 #[test]
2364 fn generate_try_expression() {
2365 let source = r#"
2366 fn fallible() -> Int fails { return 42; }
2367 fn caller() -> Int fails {
2368 let x = try fallible();
2369 return x;
2370 }
2371 agent Main {
2372 on start { emit(0); }
2373 }
2374 run Main;
2375 "#;
2376
2377 let output = generate_source(source);
2378 assert!(output.contains("fallible()?"));
2380 }
2381
2382 #[test]
2383 fn generate_catch_expression() {
2384 let source = r#"
2385 fn fallible() -> Int fails { return 42; }
2386 agent Main {
2387 on start {
2388 let x = fallible() catch { 0 };
2389 emit(x);
2390 }
2391 }
2392 run Main;
2393 "#;
2394
2395 let output = generate_source(source);
2396 assert!(output.contains("match fallible()"));
2398 assert!(output.contains("Ok(__val) => __val"));
2399 assert!(output.contains("Err(_) => 0_i64"));
2400 }
2401
2402 #[test]
2403 fn generate_catch_with_binding() {
2404 let source = r#"
2405 fn fallible() -> Int fails { return 42; }
2406 agent Main {
2407 on start {
2408 let x = fallible() catch(e) { 0 };
2409 emit(x);
2410 }
2411 }
2412 run Main;
2413 "#;
2414
2415 let output = generate_source(source);
2416 assert!(output.contains("Err(e) => 0_i64"));
2418 }
2419
2420 #[test]
2421 fn generate_on_error_handler() {
2422 let source = r#"
2423 agent Main {
2424 on start {
2425 emit(0);
2426 }
2427 on error(e) {
2428 emit(1);
2429 }
2430 }
2431 run Main;
2432 "#;
2433
2434 let output = generate_source(source);
2435 assert!(output.contains("async fn on_error(self, e: SageError, ctx: &mut AgentContext"));
2437 assert!(output.contains(".on_error(e, &mut ctx)"));
2439 }
2440
2441 #[test]
2446 fn generate_agent_with_tool_use() {
2447 let source = r#"
2448 agent Fetcher {
2449 use Http
2450
2451 on start {
2452 let r = Http.get("https://example.com");
2453 emit(0);
2454 }
2455 }
2456 run Fetcher;
2457 "#;
2458
2459 let output = generate_source(source);
2460 assert!(output.contains("struct Fetcher {"));
2462 assert!(output.contains("http: HttpClient,"));
2463 assert!(output.contains("http: HttpClient::from_env()"));
2465 assert!(output.contains("self.http.get("));
2467 }
2468
2469 #[test]
2470 fn generate_tool_call_expression() {
2471 let source = r#"
2472 agent Fetcher {
2473 use Http
2474
2475 on start {
2476 let response = Http.get("https://httpbin.org/get");
2477 emit(0);
2478 }
2479 }
2480 run Fetcher;
2481 "#;
2482
2483 let output = generate_source(source);
2484 assert!(output.contains("self.http.get(\"https://httpbin.org/get\".to_string()).await"));
2486 }
2487}