Skip to main content

sage_codegen/
generator.rs

1//! Main code generator.
2
3use 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/// How to specify the sage-runtime dependency in generated Cargo.toml.
11#[derive(Debug, Clone)]
12pub enum RuntimeDep {
13    /// Use the published crates.io version.
14    CratesIo { version: String },
15    /// Use a local path (for development).
16    Path { path: String },
17}
18
19impl Default for RuntimeDep {
20    fn default() -> Self {
21        // Default to crates.io with the current version
22        Self::CratesIo {
23            version: env!("CARGO_PKG_VERSION").to_string(),
24        }
25    }
26}
27
28impl RuntimeDep {
29    /// Generate the Cargo.toml dependency line.
30    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
42/// Generated Rust project files.
43pub struct GeneratedProject {
44    /// The main.rs content.
45    pub main_rs: String,
46    /// The Cargo.toml content.
47    pub cargo_toml: String,
48}
49
50/// Generate Rust code from a Sage program (single file).
51pub fn generate(program: &Program, project_name: &str) -> GeneratedProject {
52    generate_with_config(program, project_name, RuntimeDep::default())
53}
54
55/// Generate Rust code from a Sage program with custom runtime dependency.
56pub 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
70/// Generate Rust code from a module tree (multi-file project).
71///
72/// This flattens all modules into a single Rust file, generating all agents
73/// and functions with appropriate visibility modifiers.
74pub fn generate_module_tree(tree: &ModuleTree, project_name: &str) -> GeneratedProject {
75    generate_module_tree_with_config(tree, project_name, RuntimeDep::default())
76}
77
78/// Generate Rust code from a module tree with custom runtime dependency.
79pub 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
93/// Generated test project files (RFC-0012).
94pub struct GeneratedTestProject {
95    /// The test main.rs content.
96    pub main_rs: String,
97    /// The Cargo.toml content.
98    pub cargo_toml: String,
99}
100
101/// Generate a test binary from a Sage test file (RFC-0012).
102pub fn generate_test_program(program: &Program, test_name: &str) -> GeneratedTestProject {
103    generate_test_program_with_config(program, test_name, RuntimeDep::default())
104}
105
106/// Generate a test binary with custom runtime dependency.
107pub 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        // Prelude
136        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        // Constants
143        for const_decl in &program.consts {
144            self.generate_const(const_decl);
145            self.emit.blank_line();
146        }
147
148        // Enums
149        for enum_decl in &program.enums {
150            self.generate_enum(enum_decl);
151            self.emit.blank_line();
152        }
153
154        // Records
155        for record in &program.records {
156            self.generate_record(record);
157            self.emit.blank_line();
158        }
159
160        // Functions
161        for func in &program.functions {
162            self.generate_function(func);
163            self.emit.blank_line();
164        }
165
166        // Agents
167        for agent in &program.agents {
168            self.generate_agent(agent);
169            self.emit.blank_line();
170        }
171
172        // Entry point (required for executables)
173        if let Some(run_agent) = &program.run_agent {
174            // Find the entry agent
175            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        // Prelude
185        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        // Generate all modules, starting with the root
192        // We flatten everything into one file for simplicity
193        // (A more advanced implementation would generate mod.rs files)
194
195        // First, generate non-root modules
196        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        // Then, generate the root module
233        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            // Entry point (only in root module)
262            if let Some(run_agent) = &root_module.program.run_agent {
263                // Find the entry agent
264                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    // =========================================================================
299    // RFC-0012: Test generation
300    // =========================================================================
301
302    fn generate_test_binary(&mut self, program: &Program) -> String {
303        // Test prelude
304        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        // Constants (test files may import types/constants from main code)
311        for const_decl in &program.consts {
312            self.generate_const(const_decl);
313            self.emit.blank_line();
314        }
315
316        // Enums
317        for enum_decl in &program.enums {
318            self.generate_enum(enum_decl);
319            self.emit.blank_line();
320        }
321
322        // Records
323        for record in &program.records {
324            self.generate_record(record);
325            self.emit.blank_line();
326        }
327
328        // Functions
329        for func in &program.functions {
330            self.generate_function(func);
331            self.emit.blank_line();
332        }
333
334        // Agents (test files may define helper agents)
335        for agent in &program.agents {
336            self.generate_agent(agent);
337            self.emit.blank_line();
338        }
339
340        // Separate serial and concurrent tests
341        let (serial_tests, concurrent_tests): (Vec<_>, Vec<_>) =
342            program.tests.iter().partition(|t| t.is_serial);
343
344        // Generate concurrent test functions
345        for test in &concurrent_tests {
346            self.generate_test_function(test);
347            self.emit.blank_line();
348        }
349
350        // Generate serial test functions (marked with #[serial])
351        for test in &serial_tests {
352            self.generate_test_function(test);
353            self.emit.blank_line();
354        }
355
356        // Generate an empty main function (required for bin crates)
357        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        // Collect mock statements from the test body
384        let mock_infers = self.collect_mock_infers(&test.body);
385        let mock_tools = self.collect_mock_tools(&test.body);
386
387        // Generate test function
388        self.emit.writeln("#[tokio::test]");
389        // Convert test name to valid Rust identifier
390        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        // Generate mock LLM client if there are mock infers
397        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        // Generate mock tool registry if there are mock tools
421        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        // Generate test body (excluding mock statements)
447        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            // Skip mock infer and mock tool statements - they were collected separately
482            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            // Handle assertion builtins specially
492            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                // Regular expression statement
500                self.generate_expr(expr);
501                self.emit.writeln(";");
502            }
503            // For other statements, use the normal generation
504            _ => 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                // assert_fails expects an expression that should fail
682                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                // Unknown assertion - just call it as a regular function
695                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        // Convert test name to valid Rust identifier
710        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        // Function signature with visibility
779        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(&param.name.name);
791            self.emit.write(": ");
792            self.emit_type(&param.ty);
793        }
794
795        self.emit.write(") -> ");
796
797        // RFC-0007: Wrap return type in SageResult if fallible
798        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        // RFC-0011: Check for tool usage
814        let has_tools = !agent.tool_uses.is_empty();
815        let needs_struct_body = !agent.beliefs.is_empty() || has_tools;
816
817        // Struct definition with visibility
818        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            // RFC-0011: Generate tool fields
830            for tool_use in &agent.tool_uses {
831                // Generate field like: http: HttpClient
832                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            // Regular belief fields
839            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        // Find the output type from the start handler
851        let output_type = self.infer_agent_output_type(agent);
852
853        // Impl block
854        self.emit.write("impl ");
855        self.emit.write(name);
856        self.emit.writeln(" {");
857        self.emit.indent();
858
859        // Generate handlers
860        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                // RFC-0007: Generate on_error handler
876                EventKind::Error { param_name } => {
877                    self.emit.write("async fn on_error(&self, ");
878                    self.emit.write(&param_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                // on stop handler - cleanup before termination
891                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                // Other handlers (message) - future work
901                _ => {}
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        // RFC-0011: Check if agent uses tools
922        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        // Initialize tracing from environment variables
930        self.emit.writeln("sage_runtime::trace::init();");
931        self.emit.writeln("");
932
933        // Helper to generate agent construction (with or without tool fields)
934        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                // Generate: http: HttpClient::from_env()
941                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        // Set up graceful shutdown signal handling
953        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            // RFC-0007: Generate error dispatch code
985            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            // Simple case: no error handler
994            self.emit
995                .writeln("let result = agent.on_start(&mut ctx).await;");
996        }
997
998        if has_stop_handler {
999            // Call on_stop for cleanup (errors are ignored)
1000            self.emit.writeln("agent.on_stop().await;");
1001        }
1002
1003        self.emit.writeln("result");
1004        self.emit.dedent();
1005        self.emit.writeln("});");
1006
1007        // Use tokio::select! to race between agent completion and shutdown signals
1008        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                // Handle emit specially
1143                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            // RFC-0012: mock infer - codegen will be handled in test harness generation
1167            Stmt::MockInfer { value, .. } => {
1168                // Mock statements are collected during test codegen, not emitted inline
1169                // This placeholder ensures the match is exhaustive
1170                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            // RFC-0012: mock tool - codegen will be handled in test harness generation
1185            Stmt::MockTool {
1186                tool_name,
1187                fn_name,
1188                value,
1189                ..
1190            } => {
1191                // Mock statements are collected during test codegen, not emitted inline
1192                // This placeholder ensures the match is exhaustive
1193                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                // Handle builtin constants (RFC-0013)
1221                match name.name.as_str() {
1222                    "PI" => self.emit.write("std::f64::consts::PI"),
1223                    "E" => self.emit.write("std::f64::consts::E"),
1224                    // Time constants
1225                    "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                // Handle string concatenation specially
1237                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                // Handle builtins
1263                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                    // RFC-0013: String functions
1279                    "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                    // RFC-0013: Math functions
1399                    "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                        // Safe power: handle negative exponents by returning 0
1473                        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                    // RFC-0013: Parsing functions
1499                    "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                    // RFC-0013: List Higher-Order Functions
1528                    "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                    // =========================================================================
1632                    // RFC-0010: List Utilities
1633                    // =========================================================================
1634                    "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                    // =========================================================================
1723                    // RFC-0010: Option Utilities
1724                    // =========================================================================
1725                    "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                    // =========================================================================
1763                    // RFC-0010: I/O Functions
1764                    // =========================================================================
1765                    "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                    // =========================================================================
1817                    // RFC-0010: Time Functions
1818                    // =========================================================================
1819                    "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                    // =========================================================================
1846                    // RFC-0010: JSON Utilities
1847                    // =========================================================================
1848                    "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                    // With timeout: wrap in tokio::time::timeout
1973                    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                    // Without timeout: simple await
1983                    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            // RFC-0007: Error handling
2049            Expr::Try { expr, .. } => {
2050                // Generate the inner expression with ? for error propagation
2051                self.generate_expr(expr);
2052                self.emit.write("?");
2053            }
2054
2055            Expr::Catch {
2056                expr,
2057                error_bind,
2058                recovery,
2059                ..
2060            } => {
2061                // Generate a match expression to handle the Result
2062                self.emit.write("match ");
2063                self.generate_expr(expr);
2064                self.emit.writeln(" {");
2065                self.emit.indent();
2066
2067                // Ok arm - unwrap the value
2068                self.emit.writeln("Ok(__val) => __val,");
2069
2070                // Err arm - run recovery
2071                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            // fail expression - explicit error raising
2086            Expr::Fail { error, .. } => {
2087                // Generate: return Err(SageError::agent(msg))
2088                // TODO: Use SageError::user once runtime 0.6.1 is published
2089                self.emit.write("return Err(sage_runtime::SageError::agent(");
2090                self.generate_expr(error);
2091                self.emit.write("))");
2092            }
2093
2094            // retry expression - retry a fallible operation
2095            Expr::Retry {
2096                count,
2097                delay,
2098                on_errors: _,
2099                body,
2100                ..
2101            } => {
2102                // Generate a retry loop with async block
2103                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                // Wrap body in async block that returns Result
2122                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                // Add delay between retries if specified
2138                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                // After loop exhausted, return the last error
2157                self.emit.writeln("return Err(_last_error.unwrap());");
2158
2159                self.emit.dedent();
2160                self.emit.write("}");
2161            }
2162
2163            // trace(message) - emit a trace event
2164            Expr::Trace { message, .. } => {
2165                self.emit.write("sage_runtime::trace::user(&");
2166                self.generate_expr(message);
2167                self.emit.write(")");
2168            }
2169
2170            // RFC-0009: Closures
2171            Expr::Closure { params, body, .. } => {
2172                // Generate: Box::new(move |param1: Type1, param2: Type2| { body })
2173                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(&param.name.name);
2179                    if let Some(ty) = &param.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            // RFC-0010: Tuples and Maps
2190            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            // RFC-0011: Tool calls
2242            Expr::ToolCall {
2243                tool,
2244                function,
2245                args,
2246                ..
2247            } => {
2248                // Generate: self.tool_name.function(args).await
2249                // Returns SageResult<T> - must be handled with try/catch
2250                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                // Escape the string for Rust
2321                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            // Simple string literal
2340            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        // Build format string and args
2349        self.emit.write("format!(\"");
2350        for part in &template.parts {
2351            match part {
2352                StringPart::Literal(s) => {
2353                    // Escape braces for format string
2354                    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        // Add the interpolation args
2365        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    /// Emit code for an interpolation expression (RFC-0013).
2375    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                // Inferred<T> just becomes T at runtime
2412                self.emit_type(inner);
2413            }
2414            TypeExpr::Agent(agent_name) => {
2415                // Agent handles use the agent's output type, but we don't know it here
2416                // For now, just use a generic output type
2417                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            // RFC-0007: Error handling
2426            TypeExpr::Error => {
2427                self.emit.write("sage_runtime::SageError");
2428            }
2429
2430            // RFC-0009: Function types
2431            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            // RFC-0010: Maps, tuples, Result
2445            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 => "++", // Handled specially above
2488        };
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        // Look for emit expression in start handler to infer return type
2502        // For now, default to i64
2503        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            // Check nested blocks
2521            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(), // Conservative default
2551            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        // else is on the same line after close brace
2684        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    // =========================================================================
2872    // RFC-0007: Error handling codegen tests
2873    // =========================================================================
2874
2875    #[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        // Fallible function should return SageResult<T>
2889        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        // try should generate ? operator
2908        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        // catch should generate match expression
2926        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        // catch with binding should capture the error
2946        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        // Should generate on_error method with &self and &mut ctx
2965        assert!(output.contains("async fn on_error(&self, e: SageError, ctx: &mut AgentContext"));
2966        // Main should dispatch to on_error on failure with &mut ctx
2967        assert!(output.contains(".on_error(e, &mut ctx)"));
2968    }
2969
2970    // =========================================================================
2971    // RFC-0011: Tool support codegen tests
2972    // =========================================================================
2973
2974    #[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        // Should generate struct with http field
2990        assert!(output.contains("struct Fetcher {"));
2991        assert!(output.contains("http: HttpClient,"));
2992        // Should initialize HttpClient in main
2993        assert!(output.contains("http: HttpClient::from_env()"));
2994        // Should generate tool call
2995        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        // Tool call should generate self.http.get(...).await (no ?, handled by try/catch)
3014        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        // Should generate MockToolRegistry
3038        assert!(output.contains("let _mock_tools = MockToolRegistry::new();"));
3039        // Should register mock responses
3040        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        // Should have both mock client and registry
3056        assert!(output.contains("MockLlmClient::with_responses"));
3057        assert!(output.contains("MockToolRegistry::new()"));
3058    }
3059}