Skip to main content

ling/core/
mod.rs

1// src/core/mod.rs
2mod 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    /// Compile and run using the Cranelift JIT backend.
61    pub fn compile_and_run_jit<P: AsRef<Path>>(&self, input: P) -> LingResult<()> {
62        let mir = mir::compile_path(input.as_ref(), self.config.optimization)?;
63        let mir_prog = ling_codegen::MirProgram::new(mir, input.as_ref().to_string_lossy());
64
65        use crate::runtime::jit_abi::{
66            ling_abs, ling_add, ling_alloc, ling_and, ling_bool_to_u64, ling_builtin, ling_ceil,
67            ling_cos, ling_div, ling_eq, ling_f64_add, ling_f64_div, ling_f64_eq, ling_f64_ge,
68            ling_f64_gt, ling_f64_le, ling_f64_lt, ling_f64_mul, ling_f64_neg, ling_f64_rem,
69            ling_f64_sub, ling_floor, ling_free, ling_ge, ling_gt, ling_le, ling_list_get,
70            ling_list_len, ling_list_new, ling_list_push, ling_lt, ling_mul, ling_ne, ling_neg,
71            ling_not, ling_or, ling_panic, ling_print, ling_print_newline, ling_print_val,
72            ling_rem, ling_round, ling_sin, ling_sqrt, ling_str_concat, ling_str_eq, ling_str_len,
73            ling_str_new, ling_struct_get, ling_struct_new, ling_sub, ling_time_now,
74        };
75        use crate::runtime::Interpreter;
76
77        let mut jit = ling_codegen::JitBackend::new(|builder| {
78            macro_rules! reg {
79                ($rust:ident, $jit:literal) => {
80                    builder.symbol(concat!("__ling_", $jit), $rust as *const u8);
81                };
82                ($name:ident) => {
83                    reg!($name, stringify!($name));
84                };
85            }
86            reg!(ling_f64_add, "f64_add");
87            reg!(ling_f64_sub, "f64_sub");
88            reg!(ling_f64_mul, "f64_mul");
89            reg!(ling_f64_div, "f64_div");
90            reg!(ling_f64_rem, "f64_rem");
91            reg!(ling_f64_neg, "f64_neg");
92            reg!(ling_f64_eq, "f64_eq");
93            reg!(ling_f64_lt, "f64_lt");
94            reg!(ling_f64_gt, "f64_gt");
95            reg!(ling_f64_le, "f64_le");
96            reg!(ling_f64_ge, "f64_ge");
97            reg!(ling_sin, "sin");
98            reg!(ling_cos, "cos");
99            reg!(ling_sqrt, "sqrt");
100            reg!(ling_abs, "abs");
101            reg!(ling_floor, "floor");
102            reg!(ling_ceil, "ceil");
103            reg!(ling_round, "round");
104            reg!(ling_add, "add");
105            reg!(ling_sub, "sub");
106            reg!(ling_mul, "mul");
107            reg!(ling_div, "div");
108            reg!(ling_rem, "rem");
109            reg!(ling_neg, "neg");
110            reg!(ling_eq, "eq");
111            reg!(ling_ne, "ne");
112            reg!(ling_lt, "lt");
113            reg!(ling_le, "le");
114            reg!(ling_gt, "gt");
115            reg!(ling_ge, "ge");
116            reg!(ling_and, "and");
117            reg!(ling_or, "or");
118            reg!(ling_not, "not");
119            reg!(ling_bool_to_u64, "bool_to_u64");
120            reg!(ling_alloc, "alloc");
121            reg!(ling_free, "free");
122            reg!(ling_panic, "panic");
123            reg!(ling_str_new, "str_new");
124            reg!(ling_str_len, "str_len");
125            reg!(ling_str_concat, "str_concat");
126            reg!(ling_str_eq, "str_eq");
127            reg!(ling_list_new, "list_new");
128            reg!(ling_list_push, "list_push");
129            reg!(ling_list_get, "list_get");
130            reg!(ling_list_len, "list_len");
131            reg!(ling_struct_new, "struct_new");
132            reg!(ling_struct_get, "struct_get");
133            reg!(ling_print, "print");
134            reg!(ling_print_val, "print_val");
135            reg!(ling_print_newline, "print_newline");
136            reg!(ling_time_now, "time_now");
137            reg!(ling_builtin, "builtin");
138        });
139
140        // Initialize JIT runtime with interpreter for fallback operations
141        crate::runtime::jit_abi::init(Interpreter::new());
142
143        // Compile all functions. A failure here is pre-execution (Codegen),
144        // so callers may safely fall back to the interpreter.
145        jit.compile(&mir_prog)
146            .map_err(|e| LingError::Codegen(e.to_string()))?;
147
148        // Execute main. A failure here happens mid-run (Mir): output may already
149        // have been emitted, so callers must not retry on another backend.
150        jit.run_main().map_err(|e| LingError::Mir(e.to_string()))?;
151        Ok(())
152    }
153
154    pub fn dump_mir<P: AsRef<Path>>(&self, input: P) -> LingResult<()> {
155        let source =
156            std::fs::read_to_string(input.as_ref()).map_err(|e| LingError::Io(e.to_string()))?;
157        let mir = mir::compile_and_optimize(&source, self.config.optimization)?;
158        for func in &mir.functions {
159            println!("=== function: {} ===", func.name);
160            println!("  args: {}, locals: {}", func.arg_count, func.locals.len());
161            for (i, decl) in func.locals.iter().enumerate() {
162                let name = decl.name.as_deref().unwrap_or("_");
163                println!(
164                    "  local {}: {} {:?} mut={} owning={}",
165                    i, name, decl.ty, decl.is_mut, decl.is_owning
166                );
167            }
168            for (bi, bb) in func.basic_blocks.iter().enumerate() {
169                println!("  bb{}:", bi);
170                for stmt in &bb.statements {
171                    println!("    {:?}", stmt.kind);
172                }
173                if let Some(term) = &bb.terminator {
174                    println!("    term: {:?}", term.kind);
175                }
176            }
177        }
178        Ok(())
179    }
180}