aver/codegen/mod.rs
1/// Aver → target language transpilation.
2///
3/// The codegen module transforms a type-checked Aver AST into source code
4/// for a target language. Current backends: Rust deployment and Lean proof export.
5pub(crate) mod builtins;
6pub(crate) mod common;
7pub mod dafny;
8pub mod lean;
9pub mod rust;
10#[cfg(feature = "wasm")]
11pub mod wasm;
12
13use std::collections::{HashMap, HashSet};
14
15use crate::ast::{FnDef, TopLevel, TypeDef};
16use crate::types::checker::TypeCheckResult;
17
18/// Information about a dependent module loaded for codegen.
19pub struct ModuleInfo {
20 /// Qualified module path, e.g. "Models.User".
21 pub prefix: String,
22 /// Direct `depends [...]` entries from the source module.
23 pub depends: Vec<String>,
24 /// Type definitions from the module.
25 pub type_defs: Vec<TypeDef>,
26 /// Function definitions from the module (excluding `main`).
27 pub fn_defs: Vec<FnDef>,
28}
29
30/// Collected context from the Aver program, shared across all backends.
31pub struct CodegenContext {
32 /// All top-level items (post-TCO transform, post-typecheck).
33 pub items: Vec<TopLevel>,
34 /// Function signatures: name → (param_types, return_type, effects).
35 pub fn_sigs: HashMap<String, (Vec<crate::types::Type>, crate::types::Type, Vec<String>)>,
36 /// Functions eligible for auto-memoization.
37 pub memo_fns: HashSet<String>,
38 /// Set of type names whose values are memo-safe.
39 pub memo_safe_types: HashSet<String>,
40 /// User-defined type definitions (for struct/enum generation).
41 pub type_defs: Vec<TypeDef>,
42 /// User-defined function definitions.
43 pub fn_defs: Vec<FnDef>,
44 /// Project/binary name.
45 pub project_name: String,
46 /// Dependent modules loaded for inlining.
47 pub modules: Vec<ModuleInfo>,
48 /// Set of module prefixes for qualified name resolution (e.g. "Models.User").
49 pub module_prefixes: HashSet<String>,
50 /// Embedded runtime policy from `aver.toml` for generated code.
51 pub policy: Option<crate::config::ProjectConfig>,
52 /// Emit generated scoped runtime support (replay and/or runtime-loaded policy).
53 pub emit_replay_runtime: bool,
54 /// Load runtime policy from the active module root instead of embedding it.
55 pub runtime_policy_from_env: bool,
56 /// Explicit guest entry boundary for scoped replay/policy.
57 pub guest_entry: Option<String>,
58 /// Emit extra generated helpers needed only by the cached self-host helper.
59 pub emit_self_host_support: bool,
60 /// Extra fn_defs visible during current module emission (not in `fn_defs` or `modules`).
61 /// Set temporarily by the Rust backend when emitting a dependent module so that
62 /// `find_fn_def_by_name` can resolve same-module calls.
63 pub extra_fn_defs: Vec<FnDef>,
64 /// Functions that are part of a mutual-TCO SCC group (emitted as trampoline + wrappers).
65 /// Functions NOT in this set but with TailCalls are emitted as plain self-TCO loops.
66 pub mutual_tco_members: HashSet<String>,
67}
68
69/// Output files from a codegen backend.
70pub struct ProjectOutput {
71 /// Files to write: (relative_path, content).
72 pub files: Vec<(String, String)>,
73}
74
75/// Build a CodegenContext from parsed + type-checked items.
76pub fn build_context(
77 items: Vec<TopLevel>,
78 tc_result: &TypeCheckResult,
79 memo_fns: HashSet<String>,
80 project_name: String,
81 modules: Vec<ModuleInfo>,
82) -> CodegenContext {
83 let type_defs: Vec<TypeDef> = items
84 .iter()
85 .filter_map(|item| {
86 if let TopLevel::TypeDef(td) = item {
87 Some(td.clone())
88 } else {
89 None
90 }
91 })
92 .collect();
93
94 let fn_defs: Vec<FnDef> = items
95 .iter()
96 .filter_map(|item| {
97 if let TopLevel::FnDef(fd) = item {
98 Some(fd.clone())
99 } else {
100 None
101 }
102 })
103 .collect();
104
105 let module_prefixes: HashSet<String> = modules.iter().map(|m| m.prefix.clone()).collect();
106
107 // Compute which functions are in mutual-TCO SCC groups (emitted as trampoline + wrappers).
108 let mut mutual_tco_members = HashSet::new();
109 {
110 // Entry module (non-main)
111 let entry_fns: Vec<&FnDef> = fn_defs.iter().filter(|fd| fd.name != "main").collect();
112 for group in crate::call_graph::tailcall_scc_components(&entry_fns) {
113 for fd in &group {
114 mutual_tco_members.insert(fd.name.clone());
115 }
116 }
117 // Dependent modules
118 for module in &modules {
119 let mod_fns: Vec<&FnDef> = module.fn_defs.iter().collect();
120 for group in crate::call_graph::tailcall_scc_components(&mod_fns) {
121 for fd in &group {
122 mutual_tco_members.insert(fd.name.clone());
123 }
124 }
125 }
126 }
127
128 CodegenContext {
129 items,
130 fn_sigs: tc_result.fn_sigs.clone(),
131 memo_fns,
132 memo_safe_types: tc_result.memo_safe_types.clone(),
133 type_defs,
134 fn_defs,
135 project_name,
136 modules,
137 module_prefixes,
138 policy: None,
139 emit_replay_runtime: false,
140 runtime_policy_from_env: false,
141 guest_entry: None,
142 emit_self_host_support: false,
143 extra_fn_defs: Vec::new(),
144 mutual_tco_members,
145 }
146}