Skip to main content

sage_codegen/
generator.rs

1//! Main code generator.
2
3use crate::emit::Emitter;
4use sage_loader::ModuleTree;
5use sage_parser::{
6    AgentDecl, BinOp, Block, ConstDecl, EnumDecl, EventKind, Expr, FnDecl, InterpExpr, Literal,
7    MockValue, Program, RecordDecl, Stmt, StringPart, TestDecl, TypeExpr, UnaryOp,
8};
9
10/// How to specify the sage-runtime dependency in generated Cargo.toml.
11#[derive(Debug, Clone)]
12pub enum RuntimeDep {
13    /// Use the published crates.io version.
14    CratesIo { version: String },
15    /// Use a local path (for development).
16    Path { path: String },
17}
18
19impl Default for RuntimeDep {
20    fn default() -> Self {
21        // Default to crates.io with the current version
22        Self::CratesIo {
23            version: env!("CARGO_PKG_VERSION").to_string(),
24        }
25    }
26}
27
28impl RuntimeDep {
29    /// Generate the Cargo.toml dependency line.
30    fn to_cargo_dep(&self) -> String {
31        match self {
32            RuntimeDep::CratesIo { version } => {
33                format!("sage-runtime = \"{version}\"")
34            }
35            RuntimeDep::Path { path } => {
36                format!("sage-runtime = {{ path = \"{path}\" }}")
37            }
38        }
39    }
40}
41
42/// Generated Rust project files.
43pub struct GeneratedProject {
44    /// The main.rs content.
45    pub main_rs: String,
46    /// The Cargo.toml content.
47    pub cargo_toml: String,
48}
49
50/// Generate Rust code from a Sage program (single file).
51pub fn generate(program: &Program, project_name: &str) -> GeneratedProject {
52    generate_with_config(program, project_name, RuntimeDep::default())
53}
54
55/// Generate Rust code from a Sage program with custom runtime dependency.
56pub fn generate_with_config(
57    program: &Program,
58    project_name: &str,
59    runtime_dep: RuntimeDep,
60) -> GeneratedProject {
61    let mut gen = Generator::new(runtime_dep);
62    let main_rs = gen.generate_program(program);
63    let cargo_toml = gen.generate_cargo_toml(project_name);
64    GeneratedProject {
65        main_rs,
66        cargo_toml,
67    }
68}
69
70/// Generate Rust code from a module tree (multi-file project).
71///
72/// This flattens all modules into a single Rust file, generating all agents
73/// and functions with appropriate visibility modifiers.
74pub fn generate_module_tree(tree: &ModuleTree, project_name: &str) -> GeneratedProject {
75    generate_module_tree_with_config(tree, project_name, RuntimeDep::default())
76}
77
78/// Generate Rust code from a module tree with custom runtime dependency.
79pub fn generate_module_tree_with_config(
80    tree: &ModuleTree,
81    project_name: &str,
82    runtime_dep: RuntimeDep,
83) -> GeneratedProject {
84    let mut gen = Generator::new(runtime_dep);
85    let main_rs = gen.generate_module_tree(tree);
86    let cargo_toml = gen.generate_cargo_toml(project_name);
87    GeneratedProject {
88        main_rs,
89        cargo_toml,
90    }
91}
92
93/// Generated test project files (RFC-0012).
94pub struct GeneratedTestProject {
95    /// The test main.rs content.
96    pub main_rs: String,
97    /// The Cargo.toml content.
98    pub cargo_toml: String,
99}
100
101/// Generate a test binary from a Sage test file (RFC-0012).
102pub fn generate_test_program(program: &Program, test_name: &str) -> GeneratedTestProject {
103    generate_test_program_with_config(program, test_name, RuntimeDep::default())
104}
105
106/// Generate a test binary with custom runtime dependency.
107pub fn generate_test_program_with_config(
108    program: &Program,
109    test_name: &str,
110    runtime_dep: RuntimeDep,
111) -> GeneratedTestProject {
112    let mut gen = Generator::new(runtime_dep);
113    let main_rs = gen.generate_test_binary(program);
114    let cargo_toml = gen.generate_test_cargo_toml(test_name);
115    GeneratedTestProject {
116        main_rs,
117        cargo_toml,
118    }
119}
120
121struct Generator {
122    emit: Emitter,
123    runtime_dep: RuntimeDep,
124}
125
126impl Generator {
127    fn new(runtime_dep: RuntimeDep) -> Self {
128        Self {
129            emit: Emitter::new(),
130            runtime_dep,
131        }
132    }
133
134    fn generate_program(&mut self, program: &Program) -> String {
135        // Prelude
136        self.emit
137            .writeln("//! Generated by Sage compiler. Do not edit.");
138        self.emit.blank_line();
139        self.emit.writeln("use sage_runtime::prelude::*;");
140        self.emit.blank_line();
141
142        // Constants
143        for const_decl in &program.consts {
144            self.generate_const(const_decl);
145            self.emit.blank_line();
146        }
147
148        // Enums
149        for enum_decl in &program.enums {
150            self.generate_enum(enum_decl);
151            self.emit.blank_line();
152        }
153
154        // Records
155        for record in &program.records {
156            self.generate_record(record);
157            self.emit.blank_line();
158        }
159
160        // Functions
161        for func in &program.functions {
162            self.generate_function(func);
163            self.emit.blank_line();
164        }
165
166        // Agents
167        for agent in &program.agents {
168            self.generate_agent(agent);
169            self.emit.blank_line();
170        }
171
172        // Entry point (required for executables)
173        if let Some(run_agent) = &program.run_agent {
174            // Find the entry agent
175            if let Some(agent) = program.agents.iter().find(|a| a.name.name == run_agent.name) {
176                self.generate_main(agent);
177            }
178        }
179
180        std::mem::take(&mut self.emit).finish()
181    }
182
183    fn generate_module_tree(&mut self, tree: &ModuleTree) -> String {
184        // Prelude
185        self.emit
186            .writeln("//! Generated by Sage compiler. Do not edit.");
187        self.emit.blank_line();
188        self.emit.writeln("use sage_runtime::prelude::*;");
189        self.emit.blank_line();
190
191        // Generate all modules, starting with the root
192        // We flatten everything into one file for simplicity
193        // (A more advanced implementation would generate mod.rs files)
194
195        // First, generate non-root modules
196        for (path, module) in &tree.modules {
197            if path != &tree.root {
198                self.emit.write("// Module: ");
199                if path.is_empty() {
200                    self.emit.writeln("(root)");
201                } else {
202                    self.emit.writeln(&path.join("::"));
203                }
204
205                for const_decl in &module.program.consts {
206                    self.generate_const(const_decl);
207                    self.emit.blank_line();
208                }
209
210                for enum_decl in &module.program.enums {
211                    self.generate_enum(enum_decl);
212                    self.emit.blank_line();
213                }
214
215                for record in &module.program.records {
216                    self.generate_record(record);
217                    self.emit.blank_line();
218                }
219
220                for func in &module.program.functions {
221                    self.generate_function(func);
222                    self.emit.blank_line();
223                }
224
225                for agent in &module.program.agents {
226                    self.generate_agent(agent);
227                    self.emit.blank_line();
228                }
229            }
230        }
231
232        // Then, generate the root module
233        if let Some(root_module) = tree.modules.get(&tree.root) {
234            self.emit.writeln("// Root module");
235
236            for const_decl in &root_module.program.consts {
237                self.generate_const(const_decl);
238                self.emit.blank_line();
239            }
240
241            for enum_decl in &root_module.program.enums {
242                self.generate_enum(enum_decl);
243                self.emit.blank_line();
244            }
245
246            for record in &root_module.program.records {
247                self.generate_record(record);
248                self.emit.blank_line();
249            }
250
251            for func in &root_module.program.functions {
252                self.generate_function(func);
253                self.emit.blank_line();
254            }
255
256            for agent in &root_module.program.agents {
257                self.generate_agent(agent);
258                self.emit.blank_line();
259            }
260
261            // Entry point (only in root module)
262            if let Some(run_agent) = &root_module.program.run_agent {
263                // Find the entry agent
264                if let Some(agent) = root_module
265                    .program
266                    .agents
267                    .iter()
268                    .find(|a| a.name.name == run_agent.name)
269                {
270                    self.generate_main(agent);
271                }
272            }
273        }
274
275        std::mem::take(&mut self.emit).finish()
276    }
277
278    fn generate_cargo_toml(&self, name: &str) -> String {
279        let runtime_dep = self.runtime_dep.to_cargo_dep();
280        format!(
281            r#"[package]
282name = "{name}"
283version = "0.1.0"
284edition = "2021"
285
286[dependencies]
287{runtime_dep}
288tokio = {{ version = "1", features = ["full"] }}
289serde = {{ version = "1", features = ["derive"] }}
290serde_json = "1"
291
292# Standalone project, not part of parent workspace
293[workspace]
294"#
295        )
296    }
297
298    // =========================================================================
299    // RFC-0012: Test generation
300    // =========================================================================
301
302    fn generate_test_binary(&mut self, program: &Program) -> String {
303        // Test prelude
304        self.emit
305            .writeln("//! Generated test file by Sage compiler. Do not edit.");
306        self.emit.blank_line();
307        self.emit.writeln("use sage_runtime::prelude::*;");
308        self.emit.blank_line();
309
310        // Constants (test files may import types/constants from main code)
311        for const_decl in &program.consts {
312            self.generate_const(const_decl);
313            self.emit.blank_line();
314        }
315
316        // Enums
317        for enum_decl in &program.enums {
318            self.generate_enum(enum_decl);
319            self.emit.blank_line();
320        }
321
322        // Records
323        for record in &program.records {
324            self.generate_record(record);
325            self.emit.blank_line();
326        }
327
328        // Functions
329        for func in &program.functions {
330            self.generate_function(func);
331            self.emit.blank_line();
332        }
333
334        // Agents (test files may define helper agents)
335        for agent in &program.agents {
336            self.generate_agent(agent);
337            self.emit.blank_line();
338        }
339
340        // Separate serial and concurrent tests
341        let (serial_tests, concurrent_tests): (Vec<_>, Vec<_>) =
342            program.tests.iter().partition(|t| t.is_serial);
343
344        // Generate concurrent test functions
345        for test in &concurrent_tests {
346            self.generate_test_function(test);
347            self.emit.blank_line();
348        }
349
350        // Generate serial test functions (marked with #[serial])
351        for test in &serial_tests {
352            self.generate_test_function(test);
353            self.emit.blank_line();
354        }
355
356        // Generate an empty main function (required for bin crates)
357        self.emit.writeln("fn main() {}");
358
359        std::mem::take(&mut self.emit).finish()
360    }
361
362    fn generate_test_cargo_toml(&self, name: &str) -> String {
363        let runtime_dep = self.runtime_dep.to_cargo_dep();
364        format!(
365            r#"[package]
366name = "{name}"
367version = "0.1.0"
368edition = "2021"
369
370[dependencies]
371{runtime_dep}
372tokio = {{ version = "1", features = ["full"] }}
373serde = {{ version = "1", features = ["derive"] }}
374serde_json = "1"
375
376# Standalone project, not part of parent workspace
377[workspace]
378"#
379        )
380    }
381
382    fn generate_test_function(&mut self, test: &TestDecl) {
383        // Collect mock infer statements from the test body
384        let mocks = self.collect_mock_infers(&test.body);
385
386        // Generate test function
387        self.emit.writeln("#[tokio::test]");
388        // Convert test name to valid Rust identifier
389        let test_fn_name = self.sanitize_test_name(&test.name);
390        self.emit.write("async fn ");
391        self.emit.write(&test_fn_name);
392        self.emit.writeln("() {");
393        self.emit.indent();
394
395        // Generate mock client if there are mocks
396        if !mocks.is_empty() {
397            self.emit.writeln("let _mock_client = MockLlmClient::with_responses(vec![");
398            self.emit.indent();
399            for mock in &mocks {
400                match mock {
401                    MockValue::Value(expr) => {
402                        self.emit.write("MockResponse::value(");
403                        self.generate_expr(expr);
404                        self.emit.writeln("),");
405                    }
406                    MockValue::Fail(expr) => {
407                        self.emit.write("MockResponse::fail(");
408                        self.generate_expr(expr);
409                        self.emit.writeln("),");
410                    }
411                }
412            }
413            self.emit.dedent();
414            self.emit.writeln("]);");
415            self.emit.blank_line();
416        }
417
418        // Generate test body (excluding mock infer statements)
419        self.generate_test_block(&test.body);
420
421        self.emit.dedent();
422        self.emit.writeln("}");
423    }
424
425    fn collect_mock_infers(&self, block: &Block) -> Vec<MockValue> {
426        let mut mocks = Vec::new();
427        for stmt in &block.stmts {
428            if let Stmt::MockInfer { value, .. } = stmt {
429                mocks.push(value.clone());
430            }
431        }
432        mocks
433    }
434
435    fn generate_test_block(&mut self, block: &Block) {
436        for stmt in &block.stmts {
437            // Skip mock infer statements - they were collected separately
438            if matches!(stmt, Stmt::MockInfer { .. }) {
439                continue;
440            }
441            self.generate_test_stmt(stmt);
442        }
443    }
444
445    fn generate_test_stmt(&mut self, stmt: &Stmt) {
446        match stmt {
447            // Handle assertion builtins specially
448            Stmt::Expr { expr, .. } => {
449                if let Expr::Call { name, args, .. } = expr {
450                    if self.is_assertion_builtin(&name.name) {
451                        self.generate_assertion(&name.name, args);
452                        return;
453                    }
454                }
455                // Regular expression statement
456                self.generate_expr(expr);
457                self.emit.writeln(";");
458            }
459            // For other statements, use the normal generation
460            _ => self.generate_stmt(stmt),
461        }
462    }
463
464    fn is_assertion_builtin(&self, name: &str) -> bool {
465        matches!(
466            name,
467            "assert"
468                | "assert_eq"
469                | "assert_neq"
470                | "assert_gt"
471                | "assert_lt"
472                | "assert_gte"
473                | "assert_lte"
474                | "assert_true"
475                | "assert_false"
476                | "assert_contains"
477                | "assert_not_contains"
478                | "assert_empty"
479                | "assert_not_empty"
480                | "assert_starts_with"
481                | "assert_ends_with"
482                | "assert_len"
483                | "assert_empty_list"
484                | "assert_not_empty_list"
485                | "assert_fails"
486        )
487    }
488
489    fn generate_assertion(&mut self, name: &str, args: &[Expr]) {
490        match name {
491            "assert" | "assert_true" => {
492                self.emit.write("assert!(");
493                if !args.is_empty() {
494                    self.generate_expr(&args[0]);
495                }
496                self.emit.writeln(");");
497            }
498            "assert_false" => {
499                self.emit.write("assert!(!");
500                if !args.is_empty() {
501                    self.generate_expr(&args[0]);
502                }
503                self.emit.writeln(");");
504            }
505            "assert_eq" => {
506                self.emit.write("assert_eq!(");
507                if args.len() >= 2 {
508                    self.generate_expr(&args[0]);
509                    self.emit.write(", ");
510                    self.generate_expr(&args[1]);
511                }
512                self.emit.writeln(");");
513            }
514            "assert_neq" => {
515                self.emit.write("assert_ne!(");
516                if args.len() >= 2 {
517                    self.generate_expr(&args[0]);
518                    self.emit.write(", ");
519                    self.generate_expr(&args[1]);
520                }
521                self.emit.writeln(");");
522            }
523            "assert_gt" => {
524                self.emit.write("assert!(");
525                if args.len() >= 2 {
526                    self.generate_expr(&args[0]);
527                    self.emit.write(" > ");
528                    self.generate_expr(&args[1]);
529                }
530                self.emit.writeln(");");
531            }
532            "assert_lt" => {
533                self.emit.write("assert!(");
534                if args.len() >= 2 {
535                    self.generate_expr(&args[0]);
536                    self.emit.write(" < ");
537                    self.generate_expr(&args[1]);
538                }
539                self.emit.writeln(");");
540            }
541            "assert_gte" => {
542                self.emit.write("assert!(");
543                if args.len() >= 2 {
544                    self.generate_expr(&args[0]);
545                    self.emit.write(" >= ");
546                    self.generate_expr(&args[1]);
547                }
548                self.emit.writeln(");");
549            }
550            "assert_lte" => {
551                self.emit.write("assert!(");
552                if args.len() >= 2 {
553                    self.generate_expr(&args[0]);
554                    self.emit.write(" <= ");
555                    self.generate_expr(&args[1]);
556                }
557                self.emit.writeln(");");
558            }
559            "assert_contains" => {
560                self.emit.write("assert!(");
561                if args.len() >= 2 {
562                    self.generate_expr(&args[0]);
563                    self.emit.write(".contains(&");
564                    self.generate_expr(&args[1]);
565                    self.emit.write(")");
566                }
567                self.emit.writeln(");");
568            }
569            "assert_not_contains" => {
570                self.emit.write("assert!(!");
571                if args.len() >= 2 {
572                    self.generate_expr(&args[0]);
573                    self.emit.write(".contains(&");
574                    self.generate_expr(&args[1]);
575                    self.emit.write(")");
576                }
577                self.emit.writeln(");");
578            }
579            "assert_empty" => {
580                self.emit.write("assert!(");
581                if !args.is_empty() {
582                    self.generate_expr(&args[0]);
583                }
584                self.emit.writeln(".is_empty());");
585            }
586            "assert_not_empty" => {
587                self.emit.write("assert!(!");
588                if !args.is_empty() {
589                    self.generate_expr(&args[0]);
590                }
591                self.emit.writeln(".is_empty());");
592            }
593            "assert_starts_with" => {
594                self.emit.write("assert!(");
595                if args.len() >= 2 {
596                    self.generate_expr(&args[0]);
597                    self.emit.write(".starts_with(&");
598                    self.generate_expr(&args[1]);
599                    self.emit.write(")");
600                }
601                self.emit.writeln(");");
602            }
603            "assert_ends_with" => {
604                self.emit.write("assert!(");
605                if args.len() >= 2 {
606                    self.generate_expr(&args[0]);
607                    self.emit.write(".ends_with(&");
608                    self.generate_expr(&args[1]);
609                    self.emit.write(")");
610                }
611                self.emit.writeln(");");
612            }
613            "assert_len" => {
614                self.emit.write("assert_eq!(");
615                if args.len() >= 2 {
616                    self.generate_expr(&args[0]);
617                    self.emit.write(".len() as i64, ");
618                    self.generate_expr(&args[1]);
619                }
620                self.emit.writeln(");");
621            }
622            "assert_empty_list" => {
623                self.emit.write("assert!(");
624                if !args.is_empty() {
625                    self.generate_expr(&args[0]);
626                }
627                self.emit.writeln(".is_empty());");
628            }
629            "assert_not_empty_list" => {
630                self.emit.write("assert!(!");
631                if !args.is_empty() {
632                    self.generate_expr(&args[0]);
633                }
634                self.emit.writeln(".is_empty());");
635            }
636            "assert_fails" => {
637                // assert_fails expects an expression that should fail
638                self.emit.writeln("{");
639                self.emit.indent();
640                self.emit.write("let result = ");
641                if !args.is_empty() {
642                    self.generate_expr(&args[0]);
643                }
644                self.emit.writeln(";");
645                self.emit.writeln("assert!(result.is_err(), \"Expected operation to fail but it succeeded\");");
646                self.emit.dedent();
647                self.emit.writeln("}");
648            }
649            _ => {
650                // Unknown assertion - just call it as a regular function
651                self.emit.write(name);
652                self.emit.write("(");
653                for (i, arg) in args.iter().enumerate() {
654                    if i > 0 {
655                        self.emit.write(", ");
656                    }
657                    self.generate_expr(arg);
658                }
659                self.emit.writeln(");");
660            }
661        }
662    }
663
664    fn sanitize_test_name(&self, name: &str) -> String {
665        // Convert test name to valid Rust identifier
666        name.chars()
667            .map(|c| {
668                if c.is_alphanumeric() {
669                    c
670                } else {
671                    '_'
672                }
673            })
674            .collect::<String>()
675            .to_lowercase()
676    }
677
678    fn generate_const(&mut self, const_decl: &ConstDecl) {
679        if const_decl.is_pub {
680            self.emit.write("pub ");
681        }
682        self.emit.write("const ");
683        self.emit.write(&const_decl.name.name);
684        self.emit.write(": ");
685        self.emit_type(&const_decl.ty);
686        self.emit.write(" = ");
687        self.generate_expr(&const_decl.value);
688        self.emit.writeln(";");
689    }
690
691    fn generate_enum(&mut self, enum_decl: &EnumDecl) {
692        if enum_decl.is_pub {
693            self.emit.write("pub ");
694        }
695        self.emit
696            .writeln("#[derive(Debug, Clone, Copy, PartialEq, Eq)]");
697        self.emit.write("enum ");
698        self.emit.write(&enum_decl.name.name);
699        self.emit.writeln(" {");
700        self.emit.indent();
701        for variant in &enum_decl.variants {
702            self.emit.write(&variant.name.name);
703            if let Some(payload_ty) = &variant.payload {
704                self.emit.write("(");
705                self.emit_type(payload_ty);
706                self.emit.write(")");
707            }
708            self.emit.writeln(",");
709        }
710        self.emit.dedent();
711        self.emit.writeln("}");
712    }
713
714    fn generate_record(&mut self, record: &RecordDecl) {
715        if record.is_pub {
716            self.emit.write("pub ");
717        }
718        self.emit.writeln("#[derive(Debug, Clone)]");
719        self.emit.write("struct ");
720        self.emit.write(&record.name.name);
721        self.emit.writeln(" {");
722        self.emit.indent();
723        for field in &record.fields {
724            self.emit.write(&field.name.name);
725            self.emit.write(": ");
726            self.emit_type(&field.ty);
727            self.emit.writeln(",");
728        }
729        self.emit.dedent();
730        self.emit.writeln("}");
731    }
732
733    fn generate_function(&mut self, func: &FnDecl) {
734        // Function signature with visibility
735        if func.is_pub {
736            self.emit.write("pub ");
737        }
738        self.emit.write("fn ");
739        self.emit.write(&func.name.name);
740        self.emit.write("(");
741
742        for (i, param) in func.params.iter().enumerate() {
743            if i > 0 {
744                self.emit.write(", ");
745            }
746            self.emit.write(&param.name.name);
747            self.emit.write(": ");
748            self.emit_type(&param.ty);
749        }
750
751        self.emit.write(") -> ");
752
753        // RFC-0007: Wrap return type in SageResult if fallible
754        if func.is_fallible {
755            self.emit.write("SageResult<");
756            self.emit_type(&func.return_ty);
757            self.emit.write(">");
758        } else {
759            self.emit_type(&func.return_ty);
760        }
761
762        self.emit.write(" ");
763        self.generate_block(&func.body);
764    }
765
766    fn generate_agent(&mut self, agent: &AgentDecl) {
767        let name = &agent.name.name;
768
769        // RFC-0011: Check for tool usage
770        let has_tools = !agent.tool_uses.is_empty();
771        let needs_struct_body = !agent.beliefs.is_empty() || has_tools;
772
773        // Struct definition with visibility
774        if agent.is_pub {
775            self.emit.write("pub ");
776        }
777        self.emit.write("struct ");
778        self.emit.write(name);
779        if !needs_struct_body {
780            self.emit.writeln(";");
781        } else {
782            self.emit.writeln(" {");
783            self.emit.indent();
784
785            // RFC-0011: Generate tool fields
786            for tool_use in &agent.tool_uses {
787                // Generate field like: http: HttpClient
788                self.emit.write(&tool_use.name.to_lowercase());
789                self.emit.write(": ");
790                self.emit.write(&tool_use.name);
791                self.emit.writeln("Client,");
792            }
793
794            // Regular belief fields
795            for belief in &agent.beliefs {
796                self.emit.write(&belief.name.name);
797                self.emit.write(": ");
798                self.emit_type(&belief.ty);
799                self.emit.writeln(",");
800            }
801            self.emit.dedent();
802            self.emit.writeln("}");
803        }
804        self.emit.blank_line();
805
806        // Find the output type from the start handler
807        let output_type = self.infer_agent_output_type(agent);
808
809        // Impl block
810        self.emit.write("impl ");
811        self.emit.write(name);
812        self.emit.writeln(" {");
813        self.emit.indent();
814
815        // Generate handlers
816        for handler in &agent.handlers {
817            match &handler.event {
818                EventKind::Start => {
819                    self.emit
820                        .write("async fn on_start(&self, ctx: &mut AgentContext<");
821                    self.emit.write(&output_type);
822                    self.emit.write(">) -> SageResult<");
823                    self.emit.write(&output_type);
824                    self.emit.writeln("> {");
825                    self.emit.indent();
826                    self.generate_block_contents(&handler.body);
827                    self.emit.dedent();
828                    self.emit.writeln("}");
829                }
830
831                // RFC-0007: Generate on_error handler
832                EventKind::Error { param_name } => {
833                    self.emit.write("async fn on_error(&self, ");
834                    self.emit.write(&param_name.name);
835                    self.emit.write(": SageError, ctx: &mut AgentContext<");
836                    self.emit.write(&output_type);
837                    self.emit.write(">) -> SageResult<");
838                    self.emit.write(&output_type);
839                    self.emit.writeln("> {");
840                    self.emit.indent();
841                    self.generate_block_contents(&handler.body);
842                    self.emit.dedent();
843                    self.emit.writeln("}");
844                }
845
846                // on stop handler - cleanup before termination
847                EventKind::Stop => {
848                    self.emit
849                        .writeln("async fn on_stop(&self) {");
850                    self.emit.indent();
851                    self.generate_block_contents(&handler.body);
852                    self.emit.dedent();
853                    self.emit.writeln("}");
854                }
855
856                // Other handlers (message) - future work
857                _ => {}
858            }
859        }
860
861        self.emit.dedent();
862        self.emit.writeln("}");
863    }
864
865    fn generate_main(&mut self, agent: &AgentDecl) {
866        let entry_agent = &agent.name.name;
867        let has_error_handler = agent
868            .handlers
869            .iter()
870            .any(|h| matches!(h.event, EventKind::Error { .. }));
871
872        let has_stop_handler = agent
873            .handlers
874            .iter()
875            .any(|h| matches!(h.event, EventKind::Stop));
876
877        // RFC-0011: Check if agent uses tools
878        let has_tools = !agent.tool_uses.is_empty();
879
880        self.emit.writeln("#[tokio::main]");
881        self.emit
882            .writeln("async fn main() -> Result<(), Box<dyn std::error::Error>> {");
883        self.emit.indent();
884
885        // Initialize tracing from environment variables
886        self.emit.writeln("sage_runtime::trace::init();");
887        self.emit.writeln("");
888
889        // Helper to generate agent construction (with or without tool fields)
890        let agent_construct = if has_tools {
891            let mut s = format!("{entry_agent} {{ ");
892            for (i, tool_use) in agent.tool_uses.iter().enumerate() {
893                if i > 0 {
894                    s.push_str(", ");
895                }
896                // Generate: http: HttpClient::from_env()
897                s.push_str(&tool_use.name.to_lowercase());
898                s.push_str(": ");
899                s.push_str(&tool_use.name);
900                s.push_str("Client::from_env()");
901            }
902            s.push_str(" }");
903            s
904        } else {
905            entry_agent.to_string()
906        };
907
908        // Set up graceful shutdown signal handling
909        self.emit
910            .writeln("let ctrl_c = async { tokio::signal::ctrl_c().await.ok() };");
911
912        self.emit.writeln("#[cfg(unix)]");
913        self.emit.writeln("let terminate = async {");
914        self.emit.indent();
915        self.emit.writeln(
916            "if let Ok(mut s) = tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate()) {",
917        );
918        self.emit.indent();
919        self.emit.writeln("s.recv().await;");
920        self.emit.dedent();
921        self.emit.writeln("} else {");
922        self.emit.indent();
923        self.emit.writeln("std::future::pending::<()>().await;");
924        self.emit.dedent();
925        self.emit.writeln("}");
926        self.emit.dedent();
927        self.emit.writeln("};");
928        self.emit.writeln("#[cfg(not(unix))]");
929        self.emit.writeln("let terminate = std::future::pending::<()>();");
930        self.emit.writeln("");
931
932        self.emit
933            .writeln("let handle = sage_runtime::spawn(|mut ctx| async move {");
934        self.emit.indent();
935        self.emit.write("let agent = ");
936        self.emit.write(&agent_construct);
937        self.emit.writeln(";");
938
939        if has_error_handler {
940            // RFC-0007: Generate error dispatch code
941            self.emit
942                .writeln("let result = match agent.on_start(&mut ctx).await {");
943            self.emit.indent();
944            self.emit.writeln("Ok(result) => Ok(result),");
945            self.emit.writeln("Err(e) => agent.on_error(e, &mut ctx).await,");
946            self.emit.dedent();
947            self.emit.writeln("};");
948        } else {
949            // Simple case: no error handler
950            self.emit
951                .writeln("let result = agent.on_start(&mut ctx).await;");
952        }
953
954        if has_stop_handler {
955            // Call on_stop for cleanup (errors are ignored)
956            self.emit.writeln("agent.on_stop().await;");
957        }
958
959        self.emit.writeln("result");
960        self.emit.dedent();
961        self.emit.writeln("});");
962
963        // Use tokio::select! to race between agent completion and shutdown signals
964        self.emit.writeln("");
965        self.emit.writeln("let result = tokio::select! {");
966        self.emit.indent();
967        self.emit.writeln("result = handle.result() => result?,");
968        self.emit.writeln("_ = ctrl_c => {");
969        self.emit.indent();
970        self.emit.writeln("eprintln!(\"\\nReceived interrupt signal, shutting down...\");");
971        self.emit.writeln("std::process::exit(0);");
972        self.emit.dedent();
973        self.emit.writeln("}");
974        self.emit.writeln("_ = terminate => {");
975        self.emit.indent();
976        self.emit.writeln("eprintln!(\"Received terminate signal, shutting down...\");");
977        self.emit.writeln("std::process::exit(0);");
978        self.emit.dedent();
979        self.emit.writeln("}");
980        self.emit.dedent();
981        self.emit.writeln("};");
982        self.emit.writeln("println!(\"{:?}\", result);");
983        self.emit.writeln("Ok(())");
984
985        self.emit.dedent();
986        self.emit.writeln("}");
987    }
988
989    fn generate_block(&mut self, block: &Block) {
990        self.emit.open_brace();
991        self.generate_block_contents(block);
992        self.emit.close_brace();
993    }
994
995    fn generate_block_inline(&mut self, block: &Block) {
996        self.emit.open_brace();
997        self.generate_block_contents(block);
998        self.emit.close_brace_inline();
999    }
1000
1001    fn generate_block_contents(&mut self, block: &Block) {
1002        for stmt in &block.stmts {
1003            self.generate_stmt(stmt);
1004        }
1005    }
1006
1007    fn generate_stmt(&mut self, stmt: &Stmt) {
1008        match stmt {
1009            Stmt::Let {
1010                name, ty, value, ..
1011            } => {
1012                self.emit.write("let ");
1013                if ty.is_some() {
1014                    self.emit.write(&name.name);
1015                    self.emit.write(": ");
1016                    self.emit_type(ty.as_ref().unwrap());
1017                } else {
1018                    self.emit.write(&name.name);
1019                }
1020                self.emit.write(" = ");
1021                self.generate_expr(value);
1022                self.emit.writeln(";");
1023            }
1024
1025            Stmt::Assign { name, value, .. } => {
1026                self.emit.write(&name.name);
1027                self.emit.write(" = ");
1028                self.generate_expr(value);
1029                self.emit.writeln(";");
1030            }
1031
1032            Stmt::Return { value, .. } => {
1033                self.emit.write("return ");
1034                if let Some(expr) = value {
1035                    self.generate_expr(expr);
1036                }
1037                self.emit.writeln(";");
1038            }
1039
1040            Stmt::If {
1041                condition,
1042                then_block,
1043                else_block,
1044                ..
1045            } => {
1046                self.emit.write("if ");
1047                self.generate_expr(condition);
1048                self.emit.write(" ");
1049                if else_block.is_some() {
1050                    self.generate_block_inline(then_block);
1051                    self.emit.write(" else ");
1052                    match else_block.as_ref().unwrap() {
1053                        sage_parser::ElseBranch::Block(block) => {
1054                            self.generate_block(block);
1055                        }
1056                        sage_parser::ElseBranch::ElseIf(stmt) => {
1057                            self.generate_stmt(stmt);
1058                        }
1059                    }
1060                } else {
1061                    self.generate_block(then_block);
1062                }
1063            }
1064
1065            Stmt::For {
1066                pattern,
1067                iter,
1068                body,
1069                ..
1070            } => {
1071                self.emit.write("for ");
1072                self.emit_pattern(pattern);
1073                self.emit.write(" in ");
1074                self.generate_expr(iter);
1075                self.emit.write(" ");
1076                self.generate_block(body);
1077            }
1078
1079            Stmt::While {
1080                condition, body, ..
1081            } => {
1082                self.emit.write("while ");
1083                self.generate_expr(condition);
1084                self.emit.write(" ");
1085                self.generate_block(body);
1086            }
1087
1088            Stmt::Loop { body, .. } => {
1089                self.emit.write("loop ");
1090                self.generate_block(body);
1091            }
1092
1093            Stmt::Break { .. } => {
1094                self.emit.writeln("break;");
1095            }
1096
1097            Stmt::Expr { expr, .. } => {
1098                // Handle emit specially
1099                if let Expr::Emit { value, .. } = expr {
1100                    self.emit.write("return ctx.emit(");
1101                    self.generate_expr(value);
1102                    self.emit.writeln(");");
1103                } else {
1104                    self.generate_expr(expr);
1105                    self.emit.writeln(";");
1106                }
1107            }
1108
1109            Stmt::LetTuple { names, value, .. } => {
1110                self.emit.write("let (");
1111                for (i, name) in names.iter().enumerate() {
1112                    if i > 0 {
1113                        self.emit.write(", ");
1114                    }
1115                    self.emit.write(&name.name);
1116                }
1117                self.emit.write(") = ");
1118                self.generate_expr(value);
1119                self.emit.writeln(";");
1120            }
1121
1122            // RFC-0012: mock infer - codegen will be handled in test harness generation
1123            Stmt::MockInfer { value, .. } => {
1124                // Mock statements are collected during test codegen, not emitted inline
1125                // This placeholder ensures the match is exhaustive
1126                self.emit.write("// mock infer: ");
1127                match value {
1128                    sage_parser::MockValue::Value(expr) => {
1129                        self.generate_expr(expr);
1130                    }
1131                    sage_parser::MockValue::Fail(expr) => {
1132                        self.emit.write("fail(");
1133                        self.generate_expr(expr);
1134                        self.emit.write(")");
1135                    }
1136                }
1137                self.emit.writeln(";");
1138            }
1139        }
1140    }
1141
1142    fn generate_expr(&mut self, expr: &Expr) {
1143        match expr {
1144            Expr::Literal { value, .. } => {
1145                self.emit_literal(value);
1146            }
1147
1148            Expr::Var { name, .. } => {
1149                // Handle builtin constants (RFC-0013)
1150                match name.name.as_str() {
1151                    "PI" => self.emit.write("std::f64::consts::PI"),
1152                    "E" => self.emit.write("std::f64::consts::E"),
1153                    _ => self.emit.write(&name.name),
1154                }
1155            }
1156
1157            Expr::Binary {
1158                op, left, right, ..
1159            } => {
1160                // Handle string concatenation specially
1161                if matches!(op, BinOp::Concat) {
1162                    self.emit.write("format!(\"{}{}\", ");
1163                    self.generate_expr(left);
1164                    self.emit.write(", ");
1165                    self.generate_expr(right);
1166                    self.emit.write(")");
1167                } else {
1168                    self.emit.write("(");
1169                    self.generate_expr(left);
1170                    self.emit.write(" ");
1171                    self.emit_binop(op);
1172                    self.emit.write(" ");
1173                    self.generate_expr(right);
1174                    self.emit.write(")");
1175                }
1176            }
1177
1178            Expr::Unary { op, operand, .. } => {
1179                self.emit_unaryop(op);
1180                self.generate_expr(operand);
1181            }
1182
1183            Expr::Call { name, args, .. } => {
1184                let fn_name = &name.name;
1185
1186                // Handle builtins
1187                match fn_name.as_str() {
1188                    "print" => {
1189                        self.emit.write("println!(\"{}\", ");
1190                        self.generate_expr(&args[0]);
1191                        self.emit.write(")");
1192                    }
1193                    "str" => {
1194                        self.generate_expr(&args[0]);
1195                        self.emit.write(".to_string()");
1196                    }
1197                    "len" => {
1198                        self.generate_expr(&args[0]);
1199                        self.emit.write(".len() as i64");
1200                    }
1201
1202                    // RFC-0013: String functions
1203                    "split" => {
1204                        self.generate_expr(&args[0]);
1205                        self.emit.write(".split(&*");
1206                        self.generate_expr(&args[1]);
1207                        self.emit.write(").map(str::to_string).collect::<Vec<_>>()");
1208                    }
1209                    "trim" => {
1210                        self.generate_expr(&args[0]);
1211                        self.emit.write(".trim().to_string()");
1212                    }
1213                    "trim_start" => {
1214                        self.generate_expr(&args[0]);
1215                        self.emit.write(".trim_start().to_string()");
1216                    }
1217                    "trim_end" => {
1218                        self.generate_expr(&args[0]);
1219                        self.emit.write(".trim_end().to_string()");
1220                    }
1221                    "starts_with" => {
1222                        self.generate_expr(&args[0]);
1223                        self.emit.write(".starts_with(&*");
1224                        self.generate_expr(&args[1]);
1225                        self.emit.write(")");
1226                    }
1227                    "ends_with" => {
1228                        self.generate_expr(&args[0]);
1229                        self.emit.write(".ends_with(&*");
1230                        self.generate_expr(&args[1]);
1231                        self.emit.write(")");
1232                    }
1233                    "replace" => {
1234                        self.generate_expr(&args[0]);
1235                        self.emit.write(".replace(&*");
1236                        self.generate_expr(&args[1]);
1237                        self.emit.write(", &*");
1238                        self.generate_expr(&args[2]);
1239                        self.emit.write(")");
1240                    }
1241                    "replace_first" => {
1242                        self.generate_expr(&args[0]);
1243                        self.emit.write(".replacen(&*");
1244                        self.generate_expr(&args[1]);
1245                        self.emit.write(", &*");
1246                        self.generate_expr(&args[2]);
1247                        self.emit.write(", 1)");
1248                    }
1249                    "to_upper" => {
1250                        self.generate_expr(&args[0]);
1251                        self.emit.write(".to_uppercase()");
1252                    }
1253                    "to_lower" => {
1254                        self.generate_expr(&args[0]);
1255                        self.emit.write(".to_lowercase()");
1256                    }
1257                    "str_len" => {
1258                        self.generate_expr(&args[0]);
1259                        self.emit.write(".chars().count() as i64");
1260                    }
1261                    "str_slice" => {
1262                        self.emit.write("sage_runtime::stdlib::str_slice(&");
1263                        self.generate_expr(&args[0]);
1264                        self.emit.write(", ");
1265                        self.generate_expr(&args[1]);
1266                        self.emit.write(", ");
1267                        self.generate_expr(&args[2]);
1268                        self.emit.write(")");
1269                    }
1270                    "str_index_of" => {
1271                        self.emit.write("sage_runtime::stdlib::str_index_of(&");
1272                        self.generate_expr(&args[0]);
1273                        self.emit.write(", &");
1274                        self.generate_expr(&args[1]);
1275                        self.emit.write(")");
1276                    }
1277                    "str_repeat" => {
1278                        self.generate_expr(&args[0]);
1279                        self.emit.write(".repeat(");
1280                        self.generate_expr(&args[1]);
1281                        self.emit.write(" as usize)");
1282                    }
1283                    "str_pad_start" => {
1284                        self.emit.write("sage_runtime::stdlib::str_pad_start(&");
1285                        self.generate_expr(&args[0]);
1286                        self.emit.write(", ");
1287                        self.generate_expr(&args[1]);
1288                        self.emit.write(", &");
1289                        self.generate_expr(&args[2]);
1290                        self.emit.write(")");
1291                    }
1292                    "str_pad_end" => {
1293                        self.emit.write("sage_runtime::stdlib::str_pad_end(&");
1294                        self.generate_expr(&args[0]);
1295                        self.emit.write(", ");
1296                        self.generate_expr(&args[1]);
1297                        self.emit.write(", &");
1298                        self.generate_expr(&args[2]);
1299                        self.emit.write(")");
1300                    }
1301
1302                    // RFC-0013: Math functions
1303                    "abs" => {
1304                        self.generate_expr(&args[0]);
1305                        self.emit.write(".abs()");
1306                    }
1307                    "abs_float" => {
1308                        self.generate_expr(&args[0]);
1309                        self.emit.write(".abs()");
1310                    }
1311                    "min" => {
1312                        self.generate_expr(&args[0]);
1313                        self.emit.write(".min(");
1314                        self.generate_expr(&args[1]);
1315                        self.emit.write(")");
1316                    }
1317                    "max" => {
1318                        self.generate_expr(&args[0]);
1319                        self.emit.write(".max(");
1320                        self.generate_expr(&args[1]);
1321                        self.emit.write(")");
1322                    }
1323                    "min_float" => {
1324                        self.generate_expr(&args[0]);
1325                        self.emit.write(".min(");
1326                        self.generate_expr(&args[1]);
1327                        self.emit.write(")");
1328                    }
1329                    "max_float" => {
1330                        self.generate_expr(&args[0]);
1331                        self.emit.write(".max(");
1332                        self.generate_expr(&args[1]);
1333                        self.emit.write(")");
1334                    }
1335                    "clamp" => {
1336                        self.generate_expr(&args[0]);
1337                        self.emit.write(".clamp(");
1338                        self.generate_expr(&args[1]);
1339                        self.emit.write(", ");
1340                        self.generate_expr(&args[2]);
1341                        self.emit.write(")");
1342                    }
1343                    "clamp_float" => {
1344                        self.generate_expr(&args[0]);
1345                        self.emit.write(".clamp(");
1346                        self.generate_expr(&args[1]);
1347                        self.emit.write(", ");
1348                        self.generate_expr(&args[2]);
1349                        self.emit.write(")");
1350                    }
1351                    "floor" => {
1352                        self.generate_expr(&args[0]);
1353                        self.emit.write(".floor() as i64");
1354                    }
1355                    "ceil" => {
1356                        self.generate_expr(&args[0]);
1357                        self.emit.write(".ceil() as i64");
1358                    }
1359                    "round" => {
1360                        self.generate_expr(&args[0]);
1361                        self.emit.write(".round() as i64");
1362                    }
1363                    "floor_float" => {
1364                        self.generate_expr(&args[0]);
1365                        self.emit.write(".floor()");
1366                    }
1367                    "ceil_float" => {
1368                        self.generate_expr(&args[0]);
1369                        self.emit.write(".ceil()");
1370                    }
1371                    "pow" => {
1372                        // Safe power: handle negative exponents by returning 0
1373                        self.emit.write("{ let __base = ");
1374                        self.generate_expr(&args[0]);
1375                        self.emit.write("; let __exp = ");
1376                        self.generate_expr(&args[1]);
1377                        self.emit.write("; if __exp < 0 { 0 } else { __base.pow(__exp as u32) } }");
1378                    }
1379                    "pow_float" => {
1380                        self.generate_expr(&args[0]);
1381                        self.emit.write(".powf(");
1382                        self.generate_expr(&args[1]);
1383                        self.emit.write(")");
1384                    }
1385                    "sqrt" => {
1386                        self.generate_expr(&args[0]);
1387                        self.emit.write(".sqrt()");
1388                    }
1389                    "int_to_float" => {
1390                        self.generate_expr(&args[0]);
1391                        self.emit.write(" as f64");
1392                    }
1393                    "float_to_int" => {
1394                        self.generate_expr(&args[0]);
1395                        self.emit.write(" as i64");
1396                    }
1397
1398                    // RFC-0013: Parsing functions
1399                    "parse_int" => {
1400                        self.generate_expr(&args[0]);
1401                        self.emit.write(".trim().parse::<i64>().map_err(|e| e.to_string())");
1402                    }
1403                    "parse_float" => {
1404                        self.generate_expr(&args[0]);
1405                        self.emit.write(".trim().parse::<f64>().map_err(|e| e.to_string())");
1406                    }
1407                    "parse_bool" => {
1408                        self.emit.write("sage_runtime::stdlib::parse_bool(&");
1409                        self.generate_expr(&args[0]);
1410                        self.emit.write(")");
1411                    }
1412                    "float_to_str" => {
1413                        self.generate_expr(&args[0]);
1414                        self.emit.write(".to_string()");
1415                    }
1416                    "bool_to_str" => {
1417                        self.emit.write("if ");
1418                        self.generate_expr(&args[0]);
1419                        self.emit.write(" { \"true\".to_string() } else { \"false\".to_string() }");
1420                    }
1421
1422                    // RFC-0013: List Higher-Order Functions
1423                    "map" => {
1424                        self.generate_expr(&args[0]);
1425                        self.emit.write(".into_iter().map(");
1426                        self.generate_expr(&args[1]);
1427                        self.emit.write(").collect::<Vec<_>>()");
1428                    }
1429                    "filter" => {
1430                        self.generate_expr(&args[0]);
1431                        self.emit.write(".into_iter().filter(|__x| (");
1432                        self.generate_expr(&args[1]);
1433                        self.emit.write(")((__x).clone())).collect::<Vec<_>>()");
1434                    }
1435                    "reduce" => {
1436                        self.generate_expr(&args[0]);
1437                        self.emit.write(".into_iter().fold(");
1438                        self.generate_expr(&args[1]);
1439                        self.emit.write(", ");
1440                        self.generate_expr(&args[2]);
1441                        self.emit.write(")");
1442                    }
1443                    "any" => {
1444                        self.generate_expr(&args[0]);
1445                        self.emit.write(".into_iter().any(|__x| (");
1446                        self.generate_expr(&args[1]);
1447                        self.emit.write(")((__x).clone()))");
1448                    }
1449                    "all" => {
1450                        self.generate_expr(&args[0]);
1451                        self.emit.write(".into_iter().all(|__x| (");
1452                        self.generate_expr(&args[1]);
1453                        self.emit.write(")((__x).clone()))");
1454                    }
1455                    "find" => {
1456                        self.generate_expr(&args[0]);
1457                        self.emit.write(".into_iter().find(|__x| (");
1458                        self.generate_expr(&args[1]);
1459                        self.emit.write(")((__x).clone()))");
1460                    }
1461                    "flat_map" => {
1462                        self.generate_expr(&args[0]);
1463                        self.emit.write(".into_iter().flat_map(");
1464                        self.generate_expr(&args[1]);
1465                        self.emit.write(").collect::<Vec<_>>()");
1466                    }
1467                    "zip" => {
1468                        self.generate_expr(&args[0]);
1469                        self.emit.write(".into_iter().zip(");
1470                        self.generate_expr(&args[1]);
1471                        self.emit.write(".into_iter()).collect::<Vec<_>>()");
1472                    }
1473                    "sort_by" => {
1474                        self.emit.write("{ let mut __v = ");
1475                        self.generate_expr(&args[0]);
1476                        self.emit.write("; __v.sort_by(|__a, __b| { let __cmp = (");
1477                        self.generate_expr(&args[1]);
1478                        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 }");
1479                    }
1480                    "enumerate" => {
1481                        self.generate_expr(&args[0]);
1482                        self.emit
1483                            .write(".into_iter().enumerate().map(|(__i, __x)| (__i as i64, __x)).collect::<Vec<_>>()");
1484                    }
1485                    "take" => {
1486                        self.generate_expr(&args[0]);
1487                        self.emit.write(".into_iter().take(");
1488                        self.generate_expr(&args[1]);
1489                        self.emit.write(" as usize).collect::<Vec<_>>()");
1490                    }
1491                    "drop" => {
1492                        self.generate_expr(&args[0]);
1493                        self.emit.write(".into_iter().skip(");
1494                        self.generate_expr(&args[1]);
1495                        self.emit.write(" as usize).collect::<Vec<_>>()");
1496                    }
1497                    "flatten" => {
1498                        self.generate_expr(&args[0]);
1499                        self.emit.write(".into_iter().flatten().collect::<Vec<_>>()");
1500                    }
1501                    "reverse" => {
1502                        self.emit.write("{ let mut __v = ");
1503                        self.generate_expr(&args[0]);
1504                        self.emit.write("; __v.reverse(); __v }");
1505                    }
1506                    "unique" => {
1507                        self.emit.write("{ let mut __seen = std::collections::HashSet::new(); ");
1508                        self.generate_expr(&args[0]);
1509                        self.emit.write(".into_iter().filter(|__x| __seen.insert(format!(\"{:?}\", __x))).collect::<Vec<_>>() }");
1510                    }
1511                    "count_where" => {
1512                        self.generate_expr(&args[0]);
1513                        self.emit.write(".into_iter().filter(|__x| (");
1514                        self.generate_expr(&args[1]);
1515                        self.emit.write(")((__x).clone())).count() as i64");
1516                    }
1517                    "sum" => {
1518                        self.generate_expr(&args[0]);
1519                        self.emit.write(".iter().sum::<i64>()");
1520                    }
1521                    "sum_floats" => {
1522                        self.generate_expr(&args[0]);
1523                        self.emit.write(".iter().sum::<f64>()");
1524                    }
1525
1526                    _ => {
1527                        self.emit.write(fn_name);
1528                        self.emit.write("(");
1529                        for (i, arg) in args.iter().enumerate() {
1530                            if i > 0 {
1531                                self.emit.write(", ");
1532                            }
1533                            self.generate_expr(arg);
1534                        }
1535                        self.emit.write(")");
1536                    }
1537                }
1538            }
1539
1540            Expr::SelfField { field, .. } => {
1541                self.emit.write("self.");
1542                self.emit.write(&field.name);
1543            }
1544
1545            Expr::SelfMethodCall { method, args, .. } => {
1546                self.emit.write("self.");
1547                self.emit.write(&method.name);
1548                self.emit.write("(");
1549                for (i, arg) in args.iter().enumerate() {
1550                    if i > 0 {
1551                        self.emit.write(", ");
1552                    }
1553                    self.generate_expr(arg);
1554                }
1555                self.emit.write(")");
1556            }
1557
1558            Expr::List { elements, .. } => {
1559                self.emit.write("vec![");
1560                for (i, elem) in elements.iter().enumerate() {
1561                    if i > 0 {
1562                        self.emit.write(", ");
1563                    }
1564                    self.generate_expr(elem);
1565                }
1566                self.emit.write("]");
1567            }
1568
1569            Expr::Paren { inner, .. } => {
1570                self.emit.write("(");
1571                self.generate_expr(inner);
1572                self.emit.write(")");
1573            }
1574
1575            Expr::Infer { template, .. } => {
1576                self.emit.write("ctx.infer_string(&");
1577                self.emit_string_template(template);
1578                self.emit.write(").await?");
1579            }
1580
1581            Expr::Spawn { agent, fields, .. } => {
1582                self.emit.write("sage_runtime::spawn(|ctx| ");
1583                self.emit.write(&agent.name);
1584                if fields.is_empty() {
1585                    self.emit.write(".on_start(ctx))");
1586                } else {
1587                    self.emit.write(" { ");
1588                    for (i, field) in fields.iter().enumerate() {
1589                        if i > 0 {
1590                            self.emit.write(", ");
1591                        }
1592                        self.emit.write(&field.name.name);
1593                        self.emit.write(": ");
1594                        self.generate_expr(&field.value);
1595                    }
1596                    self.emit.write(" }.on_start(ctx))");
1597                }
1598            }
1599
1600            Expr::Await {
1601                handle, timeout, ..
1602            } => {
1603                if let Some(timeout_expr) = timeout {
1604                    // With timeout: wrap in tokio::time::timeout
1605                    self.emit.write("tokio::time::timeout(");
1606                    self.emit.write("std::time::Duration::from_millis(");
1607                    self.generate_expr(timeout_expr);
1608                    self.emit.write(" as u64), ");
1609                    self.generate_expr(handle);
1610                    self.emit
1611                        .write(".result()).await.map_err(|_| sage_runtime::SageError::agent(");
1612                    self.emit.write("\"await timed out\"))??");
1613                } else {
1614                    // Without timeout: simple await
1615                    self.generate_expr(handle);
1616                    self.emit.write(".result().await?");
1617                }
1618            }
1619
1620            Expr::Send {
1621                handle, message, ..
1622            } => {
1623                self.generate_expr(handle);
1624                self.emit.write(".send(sage_runtime::Message::new(");
1625                self.generate_expr(message);
1626                self.emit.write(")?).await?");
1627            }
1628
1629            Expr::Emit { value, .. } => {
1630                self.emit.write("ctx.emit(");
1631                self.generate_expr(value);
1632                self.emit.write(")");
1633            }
1634
1635            Expr::StringInterp { template, .. } => {
1636                self.emit_string_template(template);
1637            }
1638
1639            Expr::Match {
1640                scrutinee, arms, ..
1641            } => {
1642                self.emit.write("match ");
1643                self.generate_expr(scrutinee);
1644                self.emit.writeln(" {");
1645                self.emit.indent();
1646                for arm in arms {
1647                    self.emit_pattern(&arm.pattern);
1648                    self.emit.write(" => ");
1649                    self.generate_expr(&arm.body);
1650                    self.emit.writeln(",");
1651                }
1652                self.emit.dedent();
1653                self.emit.write("}");
1654            }
1655
1656            Expr::RecordConstruct { name, fields, .. } => {
1657                self.emit.write(&name.name);
1658                self.emit.write(" { ");
1659                for (i, field) in fields.iter().enumerate() {
1660                    if i > 0 {
1661                        self.emit.write(", ");
1662                    }
1663                    self.emit.write(&field.name.name);
1664                    self.emit.write(": ");
1665                    self.generate_expr(&field.value);
1666                }
1667                self.emit.write(" }");
1668            }
1669
1670            Expr::FieldAccess { object, field, .. } => {
1671                self.generate_expr(object);
1672                self.emit.write(".");
1673                self.emit.write(&field.name);
1674            }
1675
1676            Expr::Receive { .. } => {
1677                self.emit.write("ctx.receive().await?");
1678            }
1679
1680            // RFC-0007: Error handling
1681            Expr::Try { expr, .. } => {
1682                // Generate the inner expression with ? for error propagation
1683                self.generate_expr(expr);
1684                self.emit.write("?");
1685            }
1686
1687            Expr::Catch {
1688                expr,
1689                error_bind,
1690                recovery,
1691                ..
1692            } => {
1693                // Generate a match expression to handle the Result
1694                self.emit.write("match ");
1695                self.generate_expr(expr);
1696                self.emit.writeln(" {");
1697                self.emit.indent();
1698
1699                // Ok arm - unwrap the value
1700                self.emit.writeln("Ok(__val) => __val,");
1701
1702                // Err arm - run recovery
1703                if let Some(err_name) = error_bind {
1704                    self.emit.write("Err(");
1705                    self.emit.write(&err_name.name);
1706                    self.emit.write(") => ");
1707                } else {
1708                    self.emit.write("Err(_) => ");
1709                }
1710                self.generate_expr(recovery);
1711                self.emit.writeln(",");
1712
1713                self.emit.dedent();
1714                self.emit.write("}");
1715            }
1716
1717            // fail expression - explicit error raising
1718            Expr::Fail { error, .. } => {
1719                // Generate: return Err(SageError::agent(msg))
1720                // TODO: Use SageError::user once runtime 0.6.1 is published
1721                self.emit.write("return Err(sage_runtime::SageError::agent(");
1722                self.generate_expr(error);
1723                self.emit.write("))");
1724            }
1725
1726            // retry expression - retry a fallible operation
1727            Expr::Retry {
1728                count,
1729                delay,
1730                on_errors: _,
1731                body,
1732                ..
1733            } => {
1734                // Generate a retry loop with async block
1735                self.emit.writeln("'_retry: {");
1736                self.emit.indent();
1737
1738                self.emit.write("let _retry_max: i64 = ");
1739                self.generate_expr(count);
1740                self.emit.writeln(";");
1741
1742                if let Some(delay_expr) = delay {
1743                    self.emit.write("let _retry_delay: u64 = ");
1744                    self.generate_expr(delay_expr);
1745                    self.emit.writeln(" as u64;");
1746                }
1747
1748                self.emit
1749                    .writeln("let mut _last_error: Option<sage_runtime::SageError> = None;");
1750                self.emit.writeln("for _attempt in 0.._retry_max {");
1751                self.emit.indent();
1752
1753                // Wrap body in async block that returns Result
1754                self.emit.writeln("let _result = (async {");
1755                self.emit.indent();
1756                self.emit.write("Ok::<_, sage_runtime::SageError>(");
1757                self.generate_expr(body);
1758                self.emit.writeln(")");
1759                self.emit.dedent();
1760                self.emit.writeln("}).await;");
1761
1762                self.emit.writeln("match _result {");
1763                self.emit.indent();
1764                self.emit.writeln("Ok(v) => break '_retry v,");
1765                self.emit.writeln("Err(e) => {");
1766                self.emit.indent();
1767                self.emit.writeln("_last_error = Some(e);");
1768
1769                // Add delay between retries if specified
1770                if delay.is_some() {
1771                    self.emit.writeln("if _attempt < _retry_max - 1 {");
1772                    self.emit.indent();
1773                    self.emit.writeln(
1774                        "tokio::time::sleep(std::time::Duration::from_millis(_retry_delay)).await;",
1775                    );
1776                    self.emit.dedent();
1777                    self.emit.writeln("}");
1778                }
1779
1780                self.emit.dedent();
1781                self.emit.writeln("}");
1782                self.emit.dedent();
1783                self.emit.writeln("}");
1784
1785                self.emit.dedent();
1786                self.emit.writeln("}");
1787
1788                // After loop exhausted, return the last error
1789                self.emit.writeln("return Err(_last_error.unwrap());");
1790
1791                self.emit.dedent();
1792                self.emit.write("}");
1793            }
1794
1795            // trace(message) - emit a trace event
1796            Expr::Trace { message, .. } => {
1797                self.emit.write("sage_runtime::trace::user(&");
1798                self.generate_expr(message);
1799                self.emit.write(")");
1800            }
1801
1802            // RFC-0009: Closures
1803            Expr::Closure { params, body, .. } => {
1804                // Generate: Box::new(move |param1: Type1, param2: Type2| { body })
1805                self.emit.write("Box::new(move |");
1806                for (i, param) in params.iter().enumerate() {
1807                    if i > 0 {
1808                        self.emit.write(", ");
1809                    }
1810                    self.emit.write(&param.name.name);
1811                    if let Some(ty) = &param.ty {
1812                        self.emit.write(": ");
1813                        self.emit_type(ty);
1814                    }
1815                }
1816                self.emit.write("| ");
1817                self.generate_expr(body);
1818                self.emit.write(")");
1819            }
1820
1821            // RFC-0010: Tuples and Maps
1822            Expr::Tuple { elements, .. } => {
1823                self.emit.write("(");
1824                for (i, elem) in elements.iter().enumerate() {
1825                    if i > 0 {
1826                        self.emit.write(", ");
1827                    }
1828                    self.generate_expr(elem);
1829                }
1830                self.emit.write(")");
1831            }
1832
1833            Expr::TupleIndex { tuple, index, .. } => {
1834                self.generate_expr(tuple);
1835                self.emit.write(&format!(".{index}"));
1836            }
1837
1838            Expr::Map { entries, .. } => {
1839                if entries.is_empty() {
1840                    self.emit.write("std::collections::HashMap::new()");
1841                } else {
1842                    self.emit.write("std::collections::HashMap::from([");
1843                    for (i, entry) in entries.iter().enumerate() {
1844                        if i > 0 {
1845                            self.emit.write(", ");
1846                        }
1847                        self.emit.write("(");
1848                        self.generate_expr(&entry.key);
1849                        self.emit.write(", ");
1850                        self.generate_expr(&entry.value);
1851                        self.emit.write(")");
1852                    }
1853                    self.emit.write("])");
1854                }
1855            }
1856
1857            Expr::VariantConstruct {
1858                enum_name,
1859                variant,
1860                payload,
1861                ..
1862            } => {
1863                self.emit.write(&enum_name.name);
1864                self.emit.write("::");
1865                self.emit.write(&variant.name);
1866                if let Some(payload_expr) = payload {
1867                    self.emit.write("(");
1868                    self.generate_expr(payload_expr);
1869                    self.emit.write(")");
1870                }
1871            }
1872
1873            // RFC-0011: Tool calls
1874            Expr::ToolCall {
1875                tool,
1876                function,
1877                args,
1878                ..
1879            } => {
1880                // Generate: self.tool_name.function(args).await
1881                // Returns SageResult<T> - must be handled with try/catch
1882                self.emit.write("self.");
1883                self.emit.write(&tool.name.to_lowercase());
1884                self.emit.write(".");
1885                self.emit.write(&function.name);
1886                self.emit.write("(");
1887                for (i, arg) in args.iter().enumerate() {
1888                    if i > 0 {
1889                        self.emit.write(", ");
1890                    }
1891                    self.generate_expr(arg);
1892                }
1893                self.emit.write(").await");
1894            }
1895        }
1896    }
1897
1898    fn emit_pattern(&mut self, pattern: &sage_parser::Pattern) {
1899        use sage_parser::Pattern;
1900        match pattern {
1901            Pattern::Wildcard { .. } => {
1902                self.emit.write("_");
1903            }
1904            Pattern::Variant {
1905                enum_name,
1906                variant,
1907                payload,
1908                ..
1909            } => {
1910                if let Some(enum_name) = enum_name {
1911                    self.emit.write(&enum_name.name);
1912                    self.emit.write("::");
1913                }
1914                self.emit.write(&variant.name);
1915                if let Some(inner_pattern) = payload {
1916                    self.emit.write("(");
1917                    self.emit_pattern(inner_pattern);
1918                    self.emit.write(")");
1919                }
1920            }
1921            Pattern::Literal { value, .. } => {
1922                self.emit_literal(value);
1923            }
1924            Pattern::Binding { name, .. } => {
1925                self.emit.write(&name.name);
1926            }
1927            Pattern::Tuple { elements, .. } => {
1928                self.emit.write("(");
1929                for (i, elem) in elements.iter().enumerate() {
1930                    if i > 0 {
1931                        self.emit.write(", ");
1932                    }
1933                    self.emit_pattern(elem);
1934                }
1935                self.emit.write(")");
1936            }
1937        }
1938    }
1939
1940    fn emit_literal(&mut self, lit: &Literal) {
1941        match lit {
1942            Literal::Int(n) => {
1943                self.emit.write(&format!("{n}_i64"));
1944            }
1945            Literal::Float(f) => {
1946                self.emit.write(&format!("{f}_f64"));
1947            }
1948            Literal::Bool(b) => {
1949                self.emit.write(if *b { "true" } else { "false" });
1950            }
1951            Literal::String(s) => {
1952                // Escape the string for Rust
1953                self.emit.write("\"");
1954                for c in s.chars() {
1955                    match c {
1956                        '"' => self.emit.write_raw("\\\""),
1957                        '\\' => self.emit.write_raw("\\\\"),
1958                        '\n' => self.emit.write_raw("\\n"),
1959                        '\r' => self.emit.write_raw("\\r"),
1960                        '\t' => self.emit.write_raw("\\t"),
1961                        _ => self.emit.write_raw(&c.to_string()),
1962                    }
1963                }
1964                self.emit.write("\".to_string()");
1965            }
1966        }
1967    }
1968
1969    fn emit_string_template(&mut self, template: &sage_parser::StringTemplate) {
1970        if !template.has_interpolations() {
1971            // Simple string literal
1972            if let Some(StringPart::Literal(s)) = template.parts.first() {
1973                self.emit.write("\"");
1974                self.emit.write_raw(s);
1975                self.emit.write("\".to_string()");
1976            }
1977            return;
1978        }
1979
1980        // Build format string and args
1981        self.emit.write("format!(\"");
1982        for part in &template.parts {
1983            match part {
1984                StringPart::Literal(s) => {
1985                    // Escape braces for format string
1986                    let escaped = s.replace('{', "{{").replace('}', "}}");
1987                    self.emit.write_raw(&escaped);
1988                }
1989                StringPart::Interpolation(_) => {
1990                    self.emit.write_raw("{}");
1991                }
1992            }
1993        }
1994        self.emit.write("\"");
1995
1996        // Add the interpolation args
1997        for part in &template.parts {
1998            if let StringPart::Interpolation(interp_expr) = part {
1999                self.emit.write(", ");
2000                self.emit_interp_expr(interp_expr);
2001            }
2002        }
2003        self.emit.write(")");
2004    }
2005
2006    /// Emit code for an interpolation expression (RFC-0013).
2007    fn emit_interp_expr(&mut self, expr: &InterpExpr) {
2008        match expr {
2009            InterpExpr::Ident(ident) => {
2010                self.emit.write(&ident.name);
2011            }
2012            InterpExpr::FieldAccess { base, field, .. } => {
2013                self.emit_interp_expr(base);
2014                self.emit.write(".");
2015                self.emit.write(&field.name);
2016            }
2017            InterpExpr::TupleIndex { base, index, .. } => {
2018                self.emit_interp_expr(base);
2019                self.emit.write(".");
2020                self.emit.write(&index.to_string());
2021            }
2022        }
2023    }
2024
2025    fn emit_type(&mut self, ty: &TypeExpr) {
2026        match ty {
2027            TypeExpr::Int => self.emit.write("i64"),
2028            TypeExpr::Float => self.emit.write("f64"),
2029            TypeExpr::Bool => self.emit.write("bool"),
2030            TypeExpr::String => self.emit.write("String"),
2031            TypeExpr::Unit => self.emit.write("()"),
2032            TypeExpr::List(inner) => {
2033                self.emit.write("Vec<");
2034                self.emit_type(inner);
2035                self.emit.write(">");
2036            }
2037            TypeExpr::Option(inner) => {
2038                self.emit.write("Option<");
2039                self.emit_type(inner);
2040                self.emit.write(">");
2041            }
2042            TypeExpr::Inferred(inner) => {
2043                // Inferred<T> just becomes T at runtime
2044                self.emit_type(inner);
2045            }
2046            TypeExpr::Agent(agent_name) => {
2047                // Agent handles use the agent's output type, but we don't know it here
2048                // For now, just use a generic output type
2049                self.emit.write("AgentHandle<");
2050                self.emit.write(&agent_name.name);
2051                self.emit.write("Output>");
2052            }
2053            TypeExpr::Named(name) => {
2054                self.emit.write(&name.name);
2055            }
2056
2057            // RFC-0007: Error handling
2058            TypeExpr::Error => {
2059                self.emit.write("sage_runtime::SageError");
2060            }
2061
2062            // RFC-0009: Function types
2063            TypeExpr::Fn(params, ret) => {
2064                self.emit.write("Box<dyn Fn(");
2065                for (i, param) in params.iter().enumerate() {
2066                    if i > 0 {
2067                        self.emit.write(", ");
2068                    }
2069                    self.emit_type(param);
2070                }
2071                self.emit.write(") -> ");
2072                self.emit_type(ret);
2073                self.emit.write(" + Send + 'static>");
2074            }
2075
2076            // RFC-0010: Maps, tuples, Result
2077            TypeExpr::Map(key, value) => {
2078                self.emit.write("std::collections::HashMap<");
2079                self.emit_type(key);
2080                self.emit.write(", ");
2081                self.emit_type(value);
2082                self.emit.write(">");
2083            }
2084            TypeExpr::Tuple(elems) => {
2085                self.emit.write("(");
2086                for (i, elem) in elems.iter().enumerate() {
2087                    if i > 0 {
2088                        self.emit.write(", ");
2089                    }
2090                    self.emit_type(elem);
2091                }
2092                self.emit.write(")");
2093            }
2094            TypeExpr::Result(ok, err) => {
2095                self.emit.write("Result<");
2096                self.emit_type(ok);
2097                self.emit.write(", ");
2098                self.emit_type(err);
2099                self.emit.write(">");
2100            }
2101        }
2102    }
2103
2104    fn emit_binop(&mut self, op: &BinOp) {
2105        let s = match op {
2106            BinOp::Add => "+",
2107            BinOp::Sub => "-",
2108            BinOp::Mul => "*",
2109            BinOp::Div => "/",
2110            BinOp::Rem => "%",
2111            BinOp::Eq => "==",
2112            BinOp::Ne => "!=",
2113            BinOp::Lt => "<",
2114            BinOp::Gt => ">",
2115            BinOp::Le => "<=",
2116            BinOp::Ge => ">=",
2117            BinOp::And => "&&",
2118            BinOp::Or => "||",
2119            BinOp::Concat => "++", // Handled specially above
2120        };
2121        self.emit.write(s);
2122    }
2123
2124    fn emit_unaryop(&mut self, op: &UnaryOp) {
2125        let s = match op {
2126            UnaryOp::Neg => "-",
2127            UnaryOp::Not => "!",
2128        };
2129        self.emit.write(s);
2130    }
2131
2132    fn infer_agent_output_type(&self, agent: &AgentDecl) -> String {
2133        // Look for emit expression in start handler to infer return type
2134        // For now, default to i64
2135        for handler in &agent.handlers {
2136            if let EventKind::Start = &handler.event {
2137                if let Some(ty) = self.find_emit_type(&handler.body) {
2138                    return ty;
2139                }
2140            }
2141        }
2142        "i64".to_string()
2143    }
2144
2145    fn find_emit_type(&self, block: &Block) -> Option<String> {
2146        for stmt in &block.stmts {
2147            if let Stmt::Expr { expr, .. } = stmt {
2148                if let Expr::Emit { value, .. } = expr {
2149                    return Some(self.infer_expr_type(value));
2150                }
2151            }
2152            // Check nested blocks
2153            if let Stmt::If {
2154                then_block,
2155                else_block,
2156                ..
2157            } = stmt
2158            {
2159                if let Some(ty) = self.find_emit_type(then_block) {
2160                    return Some(ty);
2161                }
2162                if let Some(else_branch) = else_block {
2163                    if let sage_parser::ElseBranch::Block(block) = else_branch {
2164                        if let Some(ty) = self.find_emit_type(block) {
2165                            return Some(ty);
2166                        }
2167                    }
2168                }
2169            }
2170        }
2171        None
2172    }
2173
2174    fn infer_expr_type(&self, expr: &Expr) -> String {
2175        match expr {
2176            Expr::Literal { value, .. } => match value {
2177                Literal::Int(_) => "i64".to_string(),
2178                Literal::Float(_) => "f64".to_string(),
2179                Literal::Bool(_) => "bool".to_string(),
2180                Literal::String(_) => "String".to_string(),
2181            },
2182            Expr::Var { .. } => "i64".to_string(), // Conservative default
2183            Expr::Binary { op, .. } => {
2184                if matches!(
2185                    op,
2186                    BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Gt | BinOp::Le | BinOp::Ge
2187                ) {
2188                    "bool".to_string()
2189                } else if matches!(op, BinOp::Concat) {
2190                    "String".to_string()
2191                } else {
2192                    "i64".to_string()
2193                }
2194            }
2195            Expr::Infer { .. } | Expr::StringInterp { .. } => "String".to_string(),
2196            Expr::Call { name, .. } if name.name == "str" => "String".to_string(),
2197            Expr::Call { name, .. } if name.name == "len" => "i64".to_string(),
2198            _ => "i64".to_string(),
2199        }
2200    }
2201}
2202
2203#[cfg(test)]
2204mod tests {
2205    use super::*;
2206    use sage_parser::{lex, parse};
2207    use std::sync::Arc;
2208
2209    fn generate_source(source: &str) -> String {
2210        let lex_result = lex(source).expect("lexing failed");
2211        let source_arc: Arc<str> = Arc::from(source);
2212        let (program, errors) = parse(lex_result.tokens(), source_arc);
2213        assert!(errors.is_empty(), "parse errors: {errors:?}");
2214        let program = program.expect("should parse");
2215        generate(&program, "test").main_rs
2216    }
2217
2218    #[test]
2219    fn generate_minimal_program() {
2220        let source = r#"
2221            agent Main {
2222                on start {
2223                    emit(42);
2224                }
2225            }
2226            run Main;
2227        "#;
2228
2229        let output = generate_source(source);
2230        assert!(output.contains("struct Main;"));
2231        assert!(output.contains("async fn on_start"));
2232        assert!(output.contains("ctx.emit(42_i64)"));
2233        assert!(output.contains("#[tokio::main]"));
2234    }
2235
2236    #[test]
2237    fn generate_function() {
2238        let source = r#"
2239            fn add(a: Int, b: Int) -> Int {
2240                return a + b;
2241            }
2242            agent Main {
2243                on start {
2244                    emit(add(1, 2));
2245                }
2246            }
2247            run Main;
2248        "#;
2249
2250        let output = generate_source(source);
2251        assert!(output.contains("fn add(a: i64, b: i64) -> i64"));
2252        assert!(output.contains("return (a + b);"));
2253    }
2254
2255    #[test]
2256    fn generate_agent_with_beliefs() {
2257        let source = r#"
2258            agent Worker {
2259                value: Int
2260
2261                on start {
2262                    emit(self.value * 2);
2263                }
2264            }
2265            agent Main {
2266                on start {
2267                    emit(0);
2268                }
2269            }
2270            run Main;
2271        "#;
2272
2273        let output = generate_source(source);
2274        assert!(output.contains("struct Worker {"));
2275        assert!(output.contains("value: i64,"));
2276        assert!(output.contains("self.value"));
2277    }
2278
2279    #[test]
2280    fn generate_string_interpolation() {
2281        let source = r#"
2282            agent Main {
2283                on start {
2284                    let name = "World";
2285                    let msg = "Hello, {name}!";
2286                    print(msg);
2287                    emit(0);
2288                }
2289            }
2290            run Main;
2291        "#;
2292
2293        let output = generate_source(source);
2294        assert!(output.contains("format!(\"Hello, {}!\", name)"));
2295    }
2296
2297    #[test]
2298    fn generate_control_flow() {
2299        let source = r#"
2300            agent Main {
2301                on start {
2302                    let x = 10;
2303                    if x > 5 {
2304                        emit(1);
2305                    } else {
2306                        emit(0);
2307                    }
2308                }
2309            }
2310            run Main;
2311        "#;
2312
2313        let output = generate_source(source);
2314        assert!(output.contains("if (x > 5_i64)"), "output:\n{output}");
2315        // else is on the same line after close brace
2316        assert!(output.contains("else"), "output:\n{output}");
2317    }
2318
2319    #[test]
2320    fn generate_loops() {
2321        let source = r#"
2322            agent Main {
2323                on start {
2324                    for x in [1, 2, 3] {
2325                        print(str(x));
2326                    }
2327                    let n = 0;
2328                    while n < 5 {
2329                        n = n + 1;
2330                    }
2331                    emit(n);
2332                }
2333            }
2334            run Main;
2335        "#;
2336
2337        let output = generate_source(source);
2338        assert!(output.contains("for x in vec![1_i64, 2_i64, 3_i64]"));
2339        assert!(output.contains("while (n < 5_i64)"));
2340    }
2341
2342    #[test]
2343    fn generate_pub_function() {
2344        let source = r#"
2345            pub fn helper(x: Int) -> Int {
2346                return x * 2;
2347            }
2348            agent Main {
2349                on start {
2350                    emit(helper(21));
2351                }
2352            }
2353            run Main;
2354        "#;
2355
2356        let output = generate_source(source);
2357        assert!(output.contains("pub fn helper(x: i64) -> i64"));
2358    }
2359
2360    #[test]
2361    fn generate_pub_agent() {
2362        let source = r#"
2363            pub agent Worker {
2364                on start {
2365                    emit(42);
2366                }
2367            }
2368            agent Main {
2369                on start {
2370                    emit(0);
2371                }
2372            }
2373            run Main;
2374        "#;
2375
2376        let output = generate_source(source);
2377        assert!(output.contains("pub struct Worker;"));
2378    }
2379
2380    #[test]
2381    fn generate_module_tree_simple() {
2382        use sage_loader::load_single_file;
2383        use std::fs;
2384        use tempfile::TempDir;
2385
2386        let dir = TempDir::new().unwrap();
2387        let file = dir.path().join("test.sg");
2388        fs::write(
2389            &file,
2390            r#"
2391agent Main {
2392    on start {
2393        emit(42);
2394    }
2395}
2396run Main;
2397"#,
2398        )
2399        .unwrap();
2400
2401        let tree = load_single_file(&file).unwrap();
2402        let project = generate_module_tree(&tree, "test");
2403
2404        assert!(project.main_rs.contains("struct Main;"));
2405        assert!(project.main_rs.contains("async fn on_start"));
2406        assert!(project.main_rs.contains("#[tokio::main]"));
2407    }
2408
2409    #[test]
2410    fn generate_record_declaration() {
2411        let source = r#"
2412            record Point {
2413                x: Int,
2414                y: Int,
2415            }
2416            agent Main {
2417                on start {
2418                    let p = Point { x: 10, y: 20 };
2419                    emit(p.x);
2420                }
2421            }
2422            run Main;
2423        "#;
2424
2425        let output = generate_source(source);
2426        assert!(output.contains("#[derive(Debug, Clone)]"));
2427        assert!(output.contains("struct Point {"));
2428        assert!(output.contains("x: i64,"));
2429        assert!(output.contains("y: i64,"));
2430        assert!(output.contains("Point { x: 10_i64, y: 20_i64 }"));
2431        assert!(output.contains("p.x"));
2432    }
2433
2434    #[test]
2435    fn generate_enum_declaration() {
2436        let source = r#"
2437            enum Status {
2438                Active,
2439                Inactive,
2440                Pending,
2441            }
2442            agent Main {
2443                on start {
2444                    emit(0);
2445                }
2446            }
2447            run Main;
2448        "#;
2449
2450        let output = generate_source(source);
2451        assert!(output.contains("#[derive(Debug, Clone, Copy, PartialEq, Eq)]"));
2452        assert!(output.contains("enum Status {"));
2453        assert!(output.contains("Active,"));
2454        assert!(output.contains("Inactive,"));
2455        assert!(output.contains("Pending,"));
2456    }
2457
2458    #[test]
2459    fn generate_const_declaration() {
2460        let source = r#"
2461            const MAX_SIZE: Int = 100;
2462            const GREETING: String = "Hello";
2463            agent Main {
2464                on start {
2465                    emit(MAX_SIZE);
2466                }
2467            }
2468            run Main;
2469        "#;
2470
2471        let output = generate_source(source);
2472        assert!(output.contains("const MAX_SIZE: i64 = 100_i64;"));
2473        assert!(output.contains("const GREETING: String = \"Hello\".to_string();"));
2474    }
2475
2476    #[test]
2477    fn generate_match_expression() {
2478        let source = r#"
2479            enum Status {
2480                Active,
2481                Inactive,
2482            }
2483            fn check_status(s: Status) -> Int {
2484                return match s {
2485                    Active => 1,
2486                    Inactive => 0,
2487                };
2488            }
2489            agent Main {
2490                on start {
2491                    emit(0);
2492                }
2493            }
2494            run Main;
2495        "#;
2496
2497        let output = generate_source(source);
2498        assert!(output.contains("match s {"));
2499        assert!(output.contains("Active => 1_i64,"));
2500        assert!(output.contains("Inactive => 0_i64,"));
2501    }
2502
2503    // =========================================================================
2504    // RFC-0007: Error handling codegen tests
2505    // =========================================================================
2506
2507    #[test]
2508    fn generate_fallible_function() {
2509        let source = r#"
2510            fn get_data(url: String) -> String fails {
2511                return url;
2512            }
2513            agent Main {
2514                on start { emit(0); }
2515            }
2516            run Main;
2517        "#;
2518
2519        let output = generate_source(source);
2520        // Fallible function should return SageResult<T>
2521        assert!(output.contains("fn get_data(url: String) -> SageResult<String>"));
2522    }
2523
2524    #[test]
2525    fn generate_try_expression() {
2526        let source = r#"
2527            fn fallible() -> Int fails { return 42; }
2528            fn caller() -> Int fails {
2529                let x = try fallible();
2530                return x;
2531            }
2532            agent Main {
2533                on start { emit(0); }
2534            }
2535            run Main;
2536        "#;
2537
2538        let output = generate_source(source);
2539        // try should generate ? operator
2540        assert!(output.contains("fallible()?"));
2541    }
2542
2543    #[test]
2544    fn generate_catch_expression() {
2545        let source = r#"
2546            fn fallible() -> Int fails { return 42; }
2547            agent Main {
2548                on start {
2549                    let x = fallible() catch { 0 };
2550                    emit(x);
2551                }
2552            }
2553            run Main;
2554        "#;
2555
2556        let output = generate_source(source);
2557        // catch should generate match expression
2558        assert!(output.contains("match fallible()"));
2559        assert!(output.contains("Ok(__val) => __val"));
2560        assert!(output.contains("Err(_) => 0_i64"));
2561    }
2562
2563    #[test]
2564    fn generate_catch_with_binding() {
2565        let source = r#"
2566            fn fallible() -> Int fails { return 42; }
2567            agent Main {
2568                on start {
2569                    let x = fallible() catch(e) { 0 };
2570                    emit(x);
2571                }
2572            }
2573            run Main;
2574        "#;
2575
2576        let output = generate_source(source);
2577        // catch with binding should capture the error
2578        assert!(output.contains("Err(e) => 0_i64"));
2579    }
2580
2581    #[test]
2582    fn generate_on_error_handler() {
2583        let source = r#"
2584            agent Main {
2585                on start {
2586                    emit(0);
2587                }
2588                on error(e) {
2589                    emit(1);
2590                }
2591            }
2592            run Main;
2593        "#;
2594
2595        let output = generate_source(source);
2596        // Should generate on_error method with &self and &mut ctx
2597        assert!(output.contains("async fn on_error(&self, e: SageError, ctx: &mut AgentContext"));
2598        // Main should dispatch to on_error on failure with &mut ctx
2599        assert!(output.contains(".on_error(e, &mut ctx)"));
2600    }
2601
2602    // =========================================================================
2603    // RFC-0011: Tool support codegen tests
2604    // =========================================================================
2605
2606    #[test]
2607    fn generate_agent_with_tool_use() {
2608        let source = r#"
2609            agent Fetcher {
2610                use Http
2611
2612                on start {
2613                    let r = Http.get("https://example.com");
2614                    emit(0);
2615                }
2616            }
2617            run Fetcher;
2618        "#;
2619
2620        let output = generate_source(source);
2621        // Should generate struct with http field
2622        assert!(output.contains("struct Fetcher {"));
2623        assert!(output.contains("http: HttpClient,"));
2624        // Should initialize HttpClient in main
2625        assert!(output.contains("http: HttpClient::from_env()"));
2626        // Should generate tool call
2627        assert!(output.contains("self.http.get("));
2628    }
2629
2630    #[test]
2631    fn generate_tool_call_expression() {
2632        let source = r#"
2633            agent Fetcher {
2634                use Http
2635
2636                on start {
2637                    let response = Http.get("https://httpbin.org/get");
2638                    emit(0);
2639                }
2640            }
2641            run Fetcher;
2642        "#;
2643
2644        let output = generate_source(source);
2645        // Tool call should generate self.http.get(...).await (no ?, handled by try/catch)
2646        assert!(output.contains("self.http.get(\"https://httpbin.org/get\".to_string()).await"));
2647    }
2648}