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 syntax;
11mod toplevel;
12mod types;
13
14use std::collections::HashSet;
15
16use crate::ast::TopLevel;
17use crate::codegen::{CodegenContext, ProjectOutput};
18use crate::types::Type;
19
20/// Transpile an Aver program to a Rust project.
21pub fn transpile(ctx: &CodegenContext) -> ProjectOutput {
22    let mut sections = Vec::new();
23
24    // Preamble
25    sections.push("#![allow(unused_variables, unused_mut, dead_code, unused_imports, unused_parens, non_snake_case, non_camel_case_types, unreachable_patterns)]".to_string());
26    sections.push("use std::collections::HashMap;".to_string());
27    sections.push(String::new());
28
29    // Runtime helpers
30    sections.push(runtime::generate_runtime());
31    sections.push(String::new());
32
33    // Collect info about which services are used at runtime
34    let used_services = detect_used_services(ctx);
35    let needs_http_types = needs_named_type(ctx, "Header")
36        || needs_named_type(ctx, "HttpResponse")
37        || needs_named_type(ctx, "HttpRequest");
38    let needs_tcp_types = needs_named_type(ctx, "Tcp.Connection");
39
40    // Service runtimes and service type definitions (separately gated).
41    let has_tcp_runtime = used_services.contains("Tcp");
42    let has_http_runtime = used_services.contains("Http");
43    let has_http_server_runtime = used_services.contains("HttpServer");
44
45    let has_tcp_types = has_tcp_runtime || needs_tcp_types;
46    let has_http_types = has_http_runtime || has_http_server_runtime || needs_http_types;
47    let has_http_server_types = has_http_server_runtime || needs_named_type(ctx, "HttpRequest");
48
49    if has_tcp_types {
50        sections.push(runtime::generate_tcp_types());
51        sections.push(String::new());
52    }
53
54    if has_http_types {
55        sections.push(runtime::generate_http_types());
56        sections.push(String::new());
57    }
58
59    if has_http_server_types {
60        sections.push(runtime::generate_http_server_types());
61        sections.push(String::new());
62    }
63
64    // Service runtime modules
65    if has_tcp_runtime {
66        sections.push(runtime::generate_tcp_runtime());
67        sections.push(String::new());
68    }
69
70    if has_http_runtime {
71        sections.push(runtime::generate_http_runtime());
72        sections.push(String::new());
73    }
74
75    if has_http_server_runtime {
76        sections.push(runtime::generate_http_server_runtime());
77        sections.push(String::new());
78    }
79
80    // Module type definitions (inlined from depends)
81    for module in &ctx.modules {
82        for td in &module.type_defs {
83            sections.push(toplevel::emit_type_def(td));
84            sections.push(String::new());
85        }
86    }
87
88    // Module function definitions (inlined from depends)
89    for module in &ctx.modules {
90        for fd in &module.fn_defs {
91            let is_memo = ctx.memo_fns.contains(&fd.name);
92            sections.push(toplevel::emit_fn_def(fd, is_memo, ctx));
93            sections.push(String::new());
94        }
95    }
96
97    // Type definitions (structs and enums)
98    for td in &ctx.type_defs {
99        sections.push(toplevel::emit_type_def(td));
100        sections.push(String::new());
101    }
102
103    // Function definitions (excluding main)
104    for fd in &ctx.fn_defs {
105        if fd.name == "main" {
106            continue;
107        }
108        let is_memo = ctx.memo_fns.contains(&fd.name);
109        sections.push(toplevel::emit_fn_def(fd, is_memo, ctx));
110        sections.push(String::new());
111    }
112
113    // Main function
114    let main_fn = ctx.fn_defs.iter().find(|fd| fd.name == "main");
115    let top_level_stmts: Vec<_> = ctx
116        .items
117        .iter()
118        .filter_map(|item| {
119            if let TopLevel::Stmt(stmt) = item {
120                Some(stmt)
121            } else {
122                None
123            }
124        })
125        .collect();
126
127    sections.push(toplevel::emit_main(main_fn, &top_level_stmts, ctx));
128    sections.push(String::new());
129
130    // Verify blocks → #[cfg(test)]
131    let verify_blocks: Vec<_> = ctx
132        .items
133        .iter()
134        .filter_map(|item| {
135            if let TopLevel::Verify(vb) = item {
136                Some(vb)
137            } else {
138                None
139            }
140        })
141        .collect();
142
143    if !verify_blocks.is_empty() {
144        sections.push(toplevel::emit_verify_blocks(&verify_blocks, ctx));
145    }
146
147    let main_rs = sections.join("\n");
148    let cargo_toml = project::generate_cargo_toml(&ctx.project_name, &used_services);
149
150    ProjectOutput {
151        files: vec![
152            ("Cargo.toml".to_string(), cargo_toml),
153            ("src/main.rs".to_string(), main_rs),
154        ],
155    }
156}
157
158/// Detect which effectful services are used in the program (including modules).
159fn detect_used_services(ctx: &CodegenContext) -> HashSet<String> {
160    let mut services = HashSet::new();
161    for item in &ctx.items {
162        if let TopLevel::FnDef(fd) = item {
163            for eff in &fd.effects {
164                services.insert(eff.clone());
165            }
166        }
167    }
168    for module in &ctx.modules {
169        for fd in &module.fn_defs {
170            for eff in &fd.effects {
171                services.insert(eff.clone());
172            }
173        }
174    }
175    services
176}
177
178fn needs_named_type(ctx: &CodegenContext, wanted: &str) -> bool {
179    ctx.fn_sigs.values().any(|(params, ret, _effects)| {
180        params.iter().any(|p| type_contains_named(p, wanted)) || type_contains_named(ret, wanted)
181    })
182}
183
184fn type_contains_named(ty: &Type, wanted: &str) -> bool {
185    match ty {
186        Type::Named(name) => name == wanted,
187        Type::Result(ok, err) => {
188            type_contains_named(ok, wanted) || type_contains_named(err, wanted)
189        }
190        Type::Option(inner) | Type::List(inner) => type_contains_named(inner, wanted),
191        Type::Tuple(items) => items.iter().any(|t| type_contains_named(t, wanted)),
192        Type::Map(k, v) => type_contains_named(k, wanted) || type_contains_named(v, wanted),
193        Type::Fn(params, ret, _effects) => {
194            params.iter().any(|t| type_contains_named(t, wanted))
195                || type_contains_named(ret, wanted)
196        }
197        Type::Int | Type::Float | Type::Str | Type::Bool | Type::Unit | Type::Unknown => false,
198    }
199}