1mod 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
18pub fn transpile(ctx: &CodegenContext) -> ProjectOutput {
20 let mut sections = Vec::new();
21
22 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 sections.push(runtime::generate_runtime());
29 sections.push(String::new());
30
31 let used_services = detect_used_services(ctx);
33
34 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 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 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 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 for td in &ctx.type_defs {
89 sections.push(toplevel::emit_type_def(td));
90 sections.push(String::new());
91 }
92
93 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 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 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
148fn 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}