runar_compiler_rust/
lib.rs1pub mod artifact;
8pub mod codegen;
9pub mod frontend;
10pub mod ir;
11
12use artifact::{assemble_artifact, RunarArtifact};
13use codegen::emit::emit;
14use codegen::optimizer::optimize_stack_ops;
15use codegen::stack::lower_to_stack;
16use ir::loader::{load_ir, load_ir_from_str};
17
18use std::path::Path;
19
20#[derive(Debug, Clone)]
22pub struct CompileOptions {
23 pub disable_constant_folding: bool,
25}
26
27impl Default for CompileOptions {
28 fn default() -> Self {
29 Self {
30 disable_constant_folding: false,
31 }
32 }
33}
34
35pub fn compile_from_ir(path: &Path) -> Result<RunarArtifact, String> {
37 compile_from_ir_with_options(path, &CompileOptions::default())
38}
39
40pub fn compile_from_ir_with_options(path: &Path, opts: &CompileOptions) -> Result<RunarArtifact, String> {
42 let program = load_ir(path)?;
43 compile_from_program_with_options(&program, opts)
44}
45
46pub fn compile_from_ir_str(json_str: &str) -> Result<RunarArtifact, String> {
48 compile_from_ir_str_with_options(json_str, &CompileOptions::default())
49}
50
51pub fn compile_from_ir_str_with_options(json_str: &str, opts: &CompileOptions) -> Result<RunarArtifact, String> {
53 let program = load_ir_from_str(json_str)?;
54 compile_from_program_with_options(&program, opts)
55}
56
57pub fn compile_from_source(path: &Path) -> Result<RunarArtifact, String> {
59 compile_from_source_with_options(path, &CompileOptions::default())
60}
61
62pub fn compile_from_source_with_options(path: &Path, opts: &CompileOptions) -> Result<RunarArtifact, String> {
64 let source = std::fs::read_to_string(path)
65 .map_err(|e| format!("reading source file: {}", e))?;
66 let file_name = path
67 .file_name()
68 .map(|n| n.to_string_lossy().to_string())
69 .unwrap_or_else(|| "contract.ts".to_string());
70 compile_from_source_str_with_options(&source, Some(&file_name), opts)
71}
72
73pub fn compile_from_source_str(
75 source: &str,
76 file_name: Option<&str>,
77) -> Result<RunarArtifact, String> {
78 compile_from_source_str_with_options(source, file_name, &CompileOptions::default())
79}
80
81pub fn compile_from_source_str_with_options(
83 source: &str,
84 file_name: Option<&str>,
85 opts: &CompileOptions,
86) -> Result<RunarArtifact, String> {
87 let parse_result = frontend::parser::parse_source(source, file_name);
89 if !parse_result.errors.is_empty() {
90 let error_msgs: Vec<String> = parse_result.errors.iter().map(|e| e.to_string()).collect();
91 return Err(format!("Parse errors:\n {}", error_msgs.join("\n ")));
92 }
93
94 let contract = parse_result
95 .contract
96 .ok_or_else(|| "No contract found in source file".to_string())?;
97
98 let validation = frontend::validator::validate(&contract);
100 if !validation.errors.is_empty() {
101 return Err(format!(
102 "Validation errors:\n {}",
103 validation.errors.join("\n ")
104 ));
105 }
106 for w in &validation.warnings {
107 eprintln!("Validation warning: {}", w);
108 }
109
110 let tc_result = frontend::typecheck::typecheck(&contract);
112 if !tc_result.errors.is_empty() {
113 return Err(format!(
114 "Type-check errors:\n {}",
115 tc_result.errors.join("\n ")
116 ));
117 }
118
119 let mut anf_program = frontend::anf_lower::lower_to_anf(&contract);
121
122 if !opts.disable_constant_folding {
124 anf_program = frontend::constant_fold::fold_constants(&anf_program);
125 }
126
127 let anf_program = frontend::anf_optimize::optimize_ec(anf_program);
129
130 let backend_opts = CompileOptions { disable_constant_folding: true };
133 compile_from_program_with_options(&anf_program, &backend_opts)
134}
135
136pub fn compile_source_to_ir(path: &Path) -> Result<ir::ANFProgram, String> {
138 compile_source_to_ir_with_options(path, &CompileOptions::default())
139}
140
141pub fn compile_source_to_ir_with_options(path: &Path, opts: &CompileOptions) -> Result<ir::ANFProgram, String> {
143 let source = std::fs::read_to_string(path)
144 .map_err(|e| format!("reading source file: {}", e))?;
145 let file_name = path
146 .file_name()
147 .map(|n| n.to_string_lossy().to_string())
148 .unwrap_or_else(|| "contract.ts".to_string());
149 compile_source_str_to_ir_with_options(&source, Some(&file_name), opts)
150}
151
152pub fn compile_source_str_to_ir(
154 source: &str,
155 file_name: Option<&str>,
156) -> Result<ir::ANFProgram, String> {
157 compile_source_str_to_ir_with_options(source, file_name, &CompileOptions::default())
158}
159
160pub fn compile_source_str_to_ir_with_options(
162 source: &str,
163 file_name: Option<&str>,
164 opts: &CompileOptions,
165) -> Result<ir::ANFProgram, String> {
166 let parse_result = frontend::parser::parse_source(source, file_name);
167 if !parse_result.errors.is_empty() {
168 let error_msgs: Vec<String> = parse_result.errors.iter().map(|e| e.to_string()).collect();
169 return Err(format!("Parse errors:\n {}", error_msgs.join("\n ")));
170 }
171
172 let contract = parse_result
173 .contract
174 .ok_or_else(|| "No contract found in source file".to_string())?;
175
176 let validation = frontend::validator::validate(&contract);
177 if !validation.errors.is_empty() {
178 return Err(format!(
179 "Validation errors:\n {}",
180 validation.errors.join("\n ")
181 ));
182 }
183
184 let tc_result = frontend::typecheck::typecheck(&contract);
185 if !tc_result.errors.is_empty() {
186 return Err(format!(
187 "Type-check errors:\n {}",
188 tc_result.errors.join("\n ")
189 ));
190 }
191
192 let mut anf_program = frontend::anf_lower::lower_to_anf(&contract);
193
194 if !opts.disable_constant_folding {
196 anf_program = frontend::constant_fold::fold_constants(&anf_program);
197 }
198
199 Ok(frontend::anf_optimize::optimize_ec(anf_program))
200}
201
202pub fn frontend_validate(source: &str, file_name: Option<&str>) -> (Vec<String>, Vec<String>) {
205 let parse_result = frontend::parser::parse_source(source, file_name);
206 if !parse_result.errors.is_empty() {
207 return (parse_result.errors, vec![]);
208 }
209 let contract = match parse_result.contract {
210 Some(c) => c,
211 None => return (vec!["No contract found".to_string()], vec![]),
212 };
213 let result = frontend::validator::validate(&contract);
214 (result.errors, result.warnings)
215}
216
217pub fn compile_from_program(program: &ir::ANFProgram) -> Result<RunarArtifact, String> {
219 compile_from_program_with_options(program, &CompileOptions::default())
220}
221
222pub fn compile_from_program_with_options(program: &ir::ANFProgram, opts: &CompileOptions) -> Result<RunarArtifact, String> {
224 let mut program = program.clone();
226 if !opts.disable_constant_folding {
227 program = frontend::constant_fold::fold_constants(&program);
228 }
229
230 let optimized = frontend::anf_optimize::optimize_ec(program);
232
233 let mut stack_methods = lower_to_stack(&optimized)?;
235
236 for method in &mut stack_methods {
238 method.ops = optimize_stack_ops(&method.ops);
239 }
240
241 let emit_result = emit(&stack_methods)?;
243
244 let artifact = assemble_artifact(
245 &optimized,
246 &emit_result.script_hex,
247 &emit_result.script_asm,
248 emit_result.constructor_slots,
249 emit_result.code_separator_index,
250 emit_result.code_separator_indices,
251 true, );
253 Ok(artifact)
254}