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