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