feat: expose JIT compiler via CLI command

Add `lux compile <file>` command that compiles and runs Lux code using
the Cranelift JIT compiler. Includes --benchmark flag for timing.

- Add compile_file() function in main.rs
- Add jit_test.lux example with fib(30) + factorial(10)
- Update VISION.md status

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-13 21:16:39 -05:00
parent 26546f9a6a
commit 554a1e7c3e
3 changed files with 142 additions and 15 deletions

View File

@@ -139,6 +139,15 @@ fn main() {
// Package manager
handle_pkg_command(&args[2..]);
}
"compile" => {
// Compile and run with JIT
if args.len() < 3 {
eprintln!("Usage: lux compile <file.lux> [--benchmark]");
std::process::exit(1);
}
let benchmark = args.iter().any(|a| a == "--benchmark");
compile_file(&args[2], benchmark);
}
path => {
// Run a file
run_file(path);
@@ -154,18 +163,19 @@ fn print_help() {
println!("Lux {} - A functional language with first-class effects", VERSION);
println!();
println!("Usage:");
println!(" lux Start the REPL");
println!(" lux <file.lux> Run a file");
println!(" lux fmt <file.lux> Format a file (--check to verify only)");
println!(" lux check <file.lux> Type check without running");
println!(" lux test [pattern] Run tests (optional pattern filter)");
println!(" lux watch <file.lux> Watch and re-run on changes");
println!(" lux debug <file.lux> Start interactive debugger");
println!(" lux init [name] Initialize a new project");
println!(" lux pkg <command> Package manager (install, add, remove, list, update)");
println!(" lux --lsp Start LSP server (for IDE integration)");
println!(" lux --help Show this help");
println!(" lux --version Show version");
println!(" lux Start the REPL");
println!(" lux <file.lux> Run a file (interpreter)");
println!(" lux compile <file.lux> Compile and run with JIT (--benchmark for timing)");
println!(" lux fmt <file.lux> Format a file (--check to verify only)");
println!(" lux check <file.lux> Type check without running");
println!(" lux test [pattern] Run tests (optional pattern filter)");
println!(" lux watch <file.lux> Watch and re-run on changes");
println!(" lux debug <file.lux> Start interactive debugger");
println!(" lux init [name] Initialize a new project");
println!(" lux pkg <command> Package manager (install, add, remove, list, update)");
println!(" lux --lsp Start LSP server (for IDE integration)");
println!(" lux --help Show this help");
println!(" lux --version Show version");
}
fn format_file(path: &str, check_only: bool) {
@@ -246,6 +256,107 @@ fn check_file(path: &str) {
println!("{}: OK", path);
}
fn compile_file(path: &str, benchmark: bool) {
use compiler::JitCompiler;
use modules::ModuleLoader;
use std::path::Path;
use std::time::Instant;
let file_path = Path::new(path);
let source = match std::fs::read_to_string(file_path) {
Ok(s) => s,
Err(e) => {
eprintln!("Error reading file '{}': {}", path, e);
std::process::exit(1);
}
};
// Parse
let parse_start = Instant::now();
let mut loader = ModuleLoader::new();
if let Some(parent) = file_path.parent() {
loader.add_search_path(parent.to_path_buf());
}
let program = match loader.load_source(&source, Some(file_path)) {
Ok(p) => p,
Err(e) => {
eprintln!("Module error: {}", e);
std::process::exit(1);
}
};
let parse_time = parse_start.elapsed();
// Type check
let check_start = Instant::now();
let mut checker = TypeChecker::new();
if let Err(errors) = checker.check_program_with_modules(&program, &loader) {
for error in errors {
let diagnostic = error.to_diagnostic();
eprint!("{}", render(&diagnostic, &source, Some(path)));
}
std::process::exit(1);
}
let check_time = check_start.elapsed();
// Compile with JIT
let compile_start = Instant::now();
let mut jit = match JitCompiler::new() {
Ok(j) => j,
Err(e) => {
eprintln!("JIT initialization error: {}", e);
std::process::exit(1);
}
};
if let Err(e) = jit.compile_program(&program) {
eprintln!("Compilation error: {}", e);
eprintln!();
eprintln!("Note: The JIT compiler currently only supports:");
eprintln!(" - Integer arithmetic and comparisons");
eprintln!(" - Conditionals (if/then/else)");
eprintln!(" - Let bindings and blocks");
eprintln!(" - Function calls (including recursion)");
eprintln!();
eprintln!("Not yet supported: strings, floats, lists, records,");
eprintln!("pattern matching, effects, ADTs.");
std::process::exit(1);
}
let compile_time = compile_start.elapsed();
// Find main function or last expression
let exec_start = Instant::now();
let result = if jit.get_function("main").is_some() {
unsafe { jit.call_function("main", &[]) }
} else {
// Try to find any function to call
eprintln!("No 'main' function found.");
eprintln!("Define a function like: fn main(): Int = ...");
std::process::exit(1);
};
let exec_time = exec_start.elapsed();
match result {
Ok(value) => {
println!("{}", value);
if benchmark {
println!();
println!("=== JIT Benchmark ===");
println!("Parse time: {:?}", parse_time);
println!("Check time: {:?}", check_time);
println!("Compile time: {:?}", compile_time);
println!("Execute time: {:?}", exec_time);
println!("Total time: {:?}", parse_time + check_time + compile_time + exec_time);
}
}
Err(e) => {
eprintln!("Execution error: {}", e);
std::process::exit(1);
}
}
}
fn run_tests(args: &[String]) {
use std::path::Path;
use std::fs;