Skip to main content

aver/codegen/rust/
mod.rs

1/// Rust backend for the Aver transpiler.
2///
3/// Transforms Aver AST → valid Rust source code.
4mod builtins;
5mod expr;
6mod liveness;
7mod pattern;
8mod project;
9mod runtime;
10mod toplevel;
11mod types;
12
13use std::collections::HashSet;
14
15use crate::ast::TopLevel;
16use crate::codegen::{CodegenContext, ProjectOutput};
17
18/// Transpile an Aver program to a Rust project.
19pub fn transpile(ctx: &CodegenContext) -> ProjectOutput {
20    let mut sections = Vec::new();
21
22    // Preamble
23    sections.push("#![allow(unused_variables, unused_mut, dead_code, unused_imports, unused_parens, non_snake_case, non_camel_case_types, unreachable_patterns)]".to_string());
24    sections.push("use std::collections::HashMap;".to_string());
25    sections.push(String::new());
26
27    // Runtime helpers
28    sections.push(runtime::generate_runtime());
29    sections.push(String::new());
30
31    // Collect info about which services are used
32    let used_services = detect_used_services(ctx);
33
34    // Service type definitions (conditionally emitted)
35    let has_tcp = used_services.contains("Tcp");
36    let has_http = used_services.contains("Http");
37    let has_http_server = used_services.contains("HttpServer");
38
39    if has_tcp {
40        sections.push(runtime::generate_tcp_types());
41        sections.push(String::new());
42    }
43
44    if has_http || has_http_server {
45        sections.push(runtime::generate_http_types());
46        sections.push(String::new());
47    }
48
49    if has_http_server {
50        sections.push(runtime::generate_http_server_types());
51        sections.push(String::new());
52    }
53
54    // Service runtime modules
55    if has_tcp {
56        sections.push(runtime::generate_tcp_runtime());
57        sections.push(String::new());
58    }
59
60    if has_http {
61        sections.push(runtime::generate_http_runtime());
62        sections.push(String::new());
63    }
64
65    if has_http_server {
66        sections.push(runtime::generate_http_server_runtime());
67        sections.push(String::new());
68    }
69
70    // Module type definitions (inlined from depends)
71    for module in &ctx.modules {
72        for td in &module.type_defs {
73            sections.push(toplevel::emit_type_def(td));
74            sections.push(String::new());
75        }
76    }
77
78    // Module function definitions (inlined from depends)
79    for module in &ctx.modules {
80        for fd in &module.fn_defs {
81            let is_memo = ctx.memo_fns.contains(&fd.name);
82            sections.push(toplevel::emit_fn_def(fd, is_memo, ctx));
83            sections.push(String::new());
84        }
85    }
86
87    // Type definitions (structs and enums)
88    for td in &ctx.type_defs {
89        sections.push(toplevel::emit_type_def(td));
90        sections.push(String::new());
91    }
92
93    // Function definitions (excluding main)
94    for fd in &ctx.fn_defs {
95        if fd.name == "main" {
96            continue;
97        }
98        let is_memo = ctx.memo_fns.contains(&fd.name);
99        sections.push(toplevel::emit_fn_def(fd, is_memo, ctx));
100        sections.push(String::new());
101    }
102
103    // Main function
104    let main_fn = ctx.fn_defs.iter().find(|fd| fd.name == "main");
105    let top_level_stmts: Vec<_> = ctx
106        .items
107        .iter()
108        .filter_map(|item| {
109            if let TopLevel::Stmt(stmt) = item {
110                Some(stmt)
111            } else {
112                None
113            }
114        })
115        .collect();
116
117    sections.push(toplevel::emit_main(main_fn, &top_level_stmts, ctx));
118    sections.push(String::new());
119
120    // Verify blocks → #[cfg(test)]
121    let verify_blocks: Vec<_> = ctx
122        .items
123        .iter()
124        .filter_map(|item| {
125            if let TopLevel::Verify(vb) = item {
126                Some(vb)
127            } else {
128                None
129            }
130        })
131        .collect();
132
133    if !verify_blocks.is_empty() {
134        sections.push(toplevel::emit_verify_blocks(&verify_blocks, ctx));
135    }
136
137    let main_rs = sections.join("\n");
138    let cargo_toml = project::generate_cargo_toml(&ctx.project_name, &used_services);
139
140    ProjectOutput {
141        files: vec![
142            ("Cargo.toml".to_string(), cargo_toml),
143            ("src/main.rs".to_string(), main_rs),
144        ],
145    }
146}
147
148/// Detect which effectful services are used in the program (including modules).
149fn detect_used_services(ctx: &CodegenContext) -> HashSet<String> {
150    let mut services = HashSet::new();
151    for item in &ctx.items {
152        if let TopLevel::FnDef(fd) = item {
153            for eff in &fd.effects {
154                services.insert(eff.clone());
155            }
156        }
157    }
158    for module in &ctx.modules {
159        for fd in &module.fn_defs {
160            for eff in &fd.effects {
161                services.insert(eff.clone());
162            }
163        }
164    }
165    services
166}