feat: replace Cranelift JIT with C backend

Remove Cranelift JIT compiler and expose the existing C backend as the
compilation target. Generated C code can be compiled with GCC/Clang.

Changes:
- Remove cranelift-* dependencies from Cargo.toml
- Delete src/compiler.rs (565 lines of Cranelift code)
- Add compile_to_c() function with -o and --run flags
- Fix C backend name mangling (main -> main_lux) to avoid conflicts
- Update CLI help text and documentation

Usage:
  lux compile <file.lux>           # Output C to stdout
  lux compile <file.lux> -o out.c  # Write to file
  lux compile <file.lux> --run     # Compile and execute

C backend supports: functions, basic types, operators, if/then/else,
records, enums, Console.print. Future work: closures, lists, patterns.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-14 03:37:35 -05:00
parent 8c7354131e
commit 67437b8273
8 changed files with 132 additions and 999 deletions

View File

@@ -82,7 +82,10 @@ impl CBackend {
self.emit_function(f)?;
}
Declaration::Let(let_decl) => {
self.emit_global_let(&let_decl.name, &let_decl.value)?;
// Skip run expressions - they're handled in the main wrapper
if !matches!(&let_decl.value, Expr::Run { .. }) {
self.emit_global_let(&let_decl.name, &let_decl.value)?;
}
}
_ => {}
}
@@ -245,12 +248,18 @@ impl CBackend {
Ok(())
}
fn mangle_name(&self, name: &str) -> String {
// Add suffix to avoid conflicts with C keywords and standard library
format!("{}_lux", name)
}
fn emit_forward_declarations(&mut self, program: &Program) -> Result<(), CGenError> {
for decl in &program.declarations {
if let Declaration::Function(f) = decl {
let ret_type = self.type_expr_to_c(&f.return_type)?;
let params = self.emit_params(&f.params)?;
self.writeln(&format!("{} {}({});", ret_type, f.name.name, params));
let mangled = self.mangle_name(&f.name.name);
self.writeln(&format!("{} {}({});", ret_type, mangled, params));
}
}
self.writeln("");
@@ -260,8 +269,9 @@ impl CBackend {
fn emit_function(&mut self, func: &FunctionDecl) -> Result<(), CGenError> {
let ret_type = self.type_expr_to_c(&func.return_type)?;
let params = self.emit_params(&func.params)?;
let mangled = self.mangle_name(&func.name.name);
self.writeln(&format!("{} {}({}) {{", ret_type, func.name.name, params));
self.writeln(&format!("{} {}({}) {{", ret_type, mangled, params));
self.indent += 1;
// Emit function body
@@ -365,7 +375,14 @@ impl CBackend {
let arg_strs: Result<Vec<_>, _> = args.iter().map(|a| self.emit_expr(a)).collect();
let args_str = arg_strs?.join(", ");
Ok(format!("{}({})", func_name, args_str))
// Mangle user-defined function names
let c_func_name = if self.functions.contains(&func_name) {
self.mangle_name(&func_name)
} else {
func_name
};
Ok(format!("{}({})", c_func_name, args_str))
}
Expr::Block { statements, result, .. } => {
@@ -517,7 +534,8 @@ impl CBackend {
if let Expr::Run { expr, .. } = &let_decl.value {
if let Expr::Call { func, .. } = expr.as_ref() {
if let Expr::Var(fn_name) = func.as_ref() {
self.writeln(&format!("{}();", fn_name.name));
let mangled = self.mangle_name(&fn_name.name);
self.writeln(&format!("{}();", mangled));
}
}
}
@@ -602,7 +620,7 @@ mod tests {
fn add(a: Int, b: Int): Int = a + b
"#;
let c_code = generate(source).unwrap();
assert!(c_code.contains("LuxInt add(LuxInt a, LuxInt b)"));
assert!(c_code.contains("LuxInt add_lux(LuxInt a, LuxInt b)"));
assert!(c_code.contains("return (a + b)"));
}
@@ -613,8 +631,8 @@ mod tests {
if n <= 1 then 1 else n * factorial(n - 1)
"#;
let c_code = generate(source).unwrap();
assert!(c_code.contains("LuxInt factorial(LuxInt n)"));
assert!(c_code.contains("factorial((n - 1))"));
assert!(c_code.contains("LuxInt factorial_lux(LuxInt n)"));
assert!(c_code.contains("factorial_lux((n - 1))"));
}
#[test]