1mod config;
3mod error;
4mod result;
5
6pub use config::{CompilerConfig, OptimizationLevel};
7pub use error::LingError;
8pub use result::LingResult;
9
10use crate::mir;
11use ling_codegen::CodegenBackend;
12use std::path::Path;
13
14pub struct LingCompiler {
15 config: CompilerConfig,
16}
17
18impl LingCompiler {
19 pub fn new(config: CompilerConfig) -> Self {
20 Self { config }
21 }
22
23 pub fn compile<P: AsRef<Path>>(&self, input: P, output: P) -> LingResult<()> {
24 let source =
25 std::fs::read_to_string(input.as_ref()).map_err(|e| LingError::Io(e.to_string()))?;
26 let mir = mir::compile_and_optimize(&source, self.config.optimization)?;
27 println!(
28 "compiled {} functions, optimized at {:?}",
29 mir.functions.len(),
30 self.config.optimization
31 );
32
33 let mir_prog = ling_codegen::MirProgram::new(mir, input.as_ref().to_string_lossy());
34 let mut backend = ling_codegen::BytecodeBackend;
35 backend
36 .emit(&mir_prog, output.as_ref())
37 .map_err(|e| LingError::Codegen(e.to_string()))?;
38 println!("bytecode emitted to {}", output.as_ref().display());
39 Ok(())
40 }
41
42 pub fn compile_and_run<P: AsRef<Path>>(&self, input: P) -> LingResult<()> {
43 let source =
44 std::fs::read_to_string(input.as_ref()).map_err(|e| LingError::Io(e.to_string()))?;
45 let mir = mir::compile_and_optimize(&source, self.config.optimization)?;
46 println!(
47 "compiled {} functions, optimized at {:?}",
48 mir.functions.len(),
49 self.config.optimization
50 );
51
52 let vm_prog = ling_codegen::compile_mir_program(&mir);
53 let mut vm = ling_codegen::Vm::new();
54 vm.load(vm_prog);
55 vm.run_main()
56 .map_err(|e| LingError::Codegen(e.to_string()))?;
57 Ok(())
58 }
59
60 #[cfg(not(target_arch = "wasm32"))]
62 pub fn compile_and_run_jit<P: AsRef<Path>>(&self, input: P) -> LingResult<()> {
63 let flat = mir::flatten_path(input.as_ref())?;
64 let mir = mir::lower_and_optimize(&flat, self.config.optimization);
65 let mir_prog = ling_codegen::MirProgram::new(mir, input.as_ref().to_string_lossy());
66 let source_dir = input.as_ref().parent().map(|p| p.to_path_buf());
67 self.run_jit_mir(mir_prog, flat, source_dir)
68 }
69
70 #[cfg(not(target_arch = "wasm32"))]
75 pub fn compile_and_run_jit_source(
76 &self,
77 source: &str,
78 source_dir: Option<std::path::PathBuf>,
79 ) -> LingResult<()> {
80 let dir = source_dir.clone().unwrap_or_else(|| Path::new(".").to_path_buf());
81 let flat = mir::flatten_source(source, &dir)?;
82 let mir = mir::lower_and_optimize(&flat, self.config.optimization);
83 let mir_prog = ling_codegen::MirProgram::new(mir, "__main__".to_string());
84 self.run_jit_mir(mir_prog, flat, source_dir)
85 }
86
87 #[cfg(not(target_arch = "wasm32"))]
88 fn run_jit_mir(
89 &self,
90 mir_prog: ling_codegen::MirProgram,
91 fallback_ast: crate::parser::ast::Program,
92 source_dir: Option<std::path::PathBuf>,
93 ) -> LingResult<()> {
94 use crate::runtime::jit_abi::{
95 ling_abs, ling_add, ling_alloc, ling_and, ling_bool_to_u64, ling_builtin, ling_ceil,
96 ling_cos, ling_div, ling_eq, ling_f64_add, ling_f64_div, ling_f64_eq, ling_f64_ge,
97 ling_f64_gt, ling_f64_le, ling_f64_lt, ling_f64_mul, ling_f64_neg, ling_f64_rem,
98 ling_f64_sub, ling_floor, ling_free, ling_ge, ling_gt, ling_le, ling_list_get,
99 ling_list_len, ling_list_new, ling_list_push, ling_lt, ling_mul, ling_ne, ling_neg,
100 ling_not, ling_or, ling_panic, ling_print, ling_print_newline, ling_print_val,
101 ling_rem, ling_round, ling_sin, ling_sqrt, ling_str_concat, ling_str_eq, ling_str_len,
102 ling_str_new, ling_struct_get, ling_struct_new, ling_sub, ling_time_now,
103 };
104 use crate::runtime::Interpreter;
105
106 let mut jit = ling_codegen::JitBackend::new(|builder| {
107 macro_rules! reg {
108 ($rust:ident, $jit:literal) => {
109 builder.symbol(concat!("__ling_", $jit), $rust as *const u8);
110 };
111 ($name:ident) => {
112 reg!($name, stringify!($name));
113 };
114 }
115 reg!(ling_f64_add, "f64_add");
116 reg!(ling_f64_sub, "f64_sub");
117 reg!(ling_f64_mul, "f64_mul");
118 reg!(ling_f64_div, "f64_div");
119 reg!(ling_f64_rem, "f64_rem");
120 reg!(ling_f64_neg, "f64_neg");
121 reg!(ling_f64_eq, "f64_eq");
122 reg!(ling_f64_lt, "f64_lt");
123 reg!(ling_f64_gt, "f64_gt");
124 reg!(ling_f64_le, "f64_le");
125 reg!(ling_f64_ge, "f64_ge");
126 reg!(ling_sin, "sin");
127 reg!(ling_cos, "cos");
128 reg!(ling_sqrt, "sqrt");
129 reg!(ling_abs, "abs");
130 reg!(ling_floor, "floor");
131 reg!(ling_ceil, "ceil");
132 reg!(ling_round, "round");
133 reg!(ling_add, "add");
134 reg!(ling_sub, "sub");
135 reg!(ling_mul, "mul");
136 reg!(ling_div, "div");
137 reg!(ling_rem, "rem");
138 reg!(ling_neg, "neg");
139 reg!(ling_eq, "eq");
140 reg!(ling_ne, "ne");
141 reg!(ling_lt, "lt");
142 reg!(ling_le, "le");
143 reg!(ling_gt, "gt");
144 reg!(ling_ge, "ge");
145 reg!(ling_and, "and");
146 reg!(ling_or, "or");
147 reg!(ling_not, "not");
148 reg!(ling_bool_to_u64, "bool_to_u64");
149 reg!(ling_alloc, "alloc");
150 reg!(ling_free, "free");
151 reg!(ling_panic, "panic");
152 reg!(ling_str_new, "str_new");
153 reg!(ling_str_len, "str_len");
154 reg!(ling_str_concat, "str_concat");
155 reg!(ling_str_eq, "str_eq");
156 reg!(ling_list_new, "list_new");
157 reg!(ling_list_push, "list_push");
158 reg!(ling_list_get, "list_get");
159 reg!(ling_list_len, "list_len");
160 reg!(ling_struct_new, "struct_new");
161 reg!(ling_struct_get, "struct_get");
162 reg!(ling_print, "print");
163 reg!(ling_print_val, "print_val");
164 reg!(ling_print_newline, "print_newline");
165 reg!(ling_time_now, "time_now");
166 reg!(ling_builtin, "builtin");
167 });
168
169 let mut fallback = Interpreter::new();
174 fallback.source_dir = source_dir;
175 fallback
176 .register_program(&fallback_ast)
177 .map_err(|e| LingError::Mir(e))?;
178 crate::runtime::jit_abi::init(fallback);
179
180 jit.compile(&mir_prog)
183 .map_err(|e| LingError::Codegen(e.to_string()))?;
184
185 jit.run_main().map_err(|e| LingError::Mir(e.to_string()))?;
188 Ok(())
189 }
190
191 pub fn dump_mir<P: AsRef<Path>>(&self, input: P) -> LingResult<()> {
192 let source =
193 std::fs::read_to_string(input.as_ref()).map_err(|e| LingError::Io(e.to_string()))?;
194 let mir = mir::compile_and_optimize(&source, self.config.optimization)?;
195 for func in &mir.functions {
196 println!("=== function: {} ===", func.name);
197 println!(" args: {}, locals: {}", func.arg_count, func.locals.len());
198 for (i, decl) in func.locals.iter().enumerate() {
199 let name = decl.name.as_deref().unwrap_or("_");
200 println!(
201 " local {}: {} {:?} mut={} owning={}",
202 i, name, decl.ty, decl.is_mut, decl.is_owning
203 );
204 }
205 for (bi, bb) in func.basic_blocks.iter().enumerate() {
206 println!(" bb{}:", bi);
207 for stmt in &bb.statements {
208 println!(" {:?}", stmt.kind);
209 }
210 if let Some(term) = &bb.terminator {
211 println!(" term: {:?}", term.kind);
212 }
213 }
214 }
215 Ok(())
216 }
217}