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:
@@ -128,11 +128,11 @@ fn retry<F>(action: F, times: Int): Result
|
|||||||
|
|
||||||
| Feature | Effort | Why It Matters |
|
| Feature | Effort | Why It Matters |
|
||||||
|---------|--------|----------------|
|
|---------|--------|----------------|
|
||||||
| **Module System** | 2-3 weeks | Can't build real apps without imports |
|
| **Module System** | Done | Imports, exports, aliases, selective imports |
|
||||||
| **Standard Library** | Done | List.map, String.split, Option.map, etc. |
|
| **Standard Library** | Done | List.map, String.split, Option.map, etc. |
|
||||||
| **File/Network Effects** | 1-2 weeks | Real IO beyond Console |
|
| **File/Network Effects** | 1-2 weeks | Real IO beyond Console |
|
||||||
| **Better Error Messages** | 2-3 weeks | Elm-quality diagnostics |
|
| **Better Error Messages** | 2-3 weeks | Elm-quality diagnostics |
|
||||||
| **JS/WASM Compilation** | 4-6 weeks | Deploy to browsers/servers |
|
| **Full Compilation** | 4-6 weeks | Cranelift JIT exists for numeric code; needs strings, ADTs, effects |
|
||||||
|
|
||||||
### Needed for Full Vision (Phase 3: Differentiation)
|
### Needed for Full Vision (Phase 3: Differentiation)
|
||||||
|
|
||||||
@@ -245,7 +245,7 @@ Hint: Maybe you need to parse the string?
|
|||||||
## Immediate Next Steps
|
## Immediate Next Steps
|
||||||
|
|
||||||
1. ~~**Standard Library**~~ - Done! List, String, Option, Result operations
|
1. ~~**Standard Library**~~ - Done! List, String, Option, Result operations
|
||||||
2. **Module System** - `import`, `export`, namespaces
|
2. ~~**Module System**~~ - Done! Imports, exports, aliases, selective imports
|
||||||
3. **File Effect** - `FileSystem.read`, `FileSystem.write`
|
3. **File Effect** - `FileSystem.read`, `FileSystem.write`
|
||||||
4. **Error Message Overhaul** - Source snippets, suggestions, colors
|
4. **Error Message Overhaul** - Source snippets, suggestions, colors
|
||||||
5. **JavaScript Backend** - Compile to runnable JS
|
5. **JavaScript Backend** - Compile to runnable JS
|
||||||
|
|||||||
16
examples/jit_test.lux
Normal file
16
examples/jit_test.lux
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// Test file for JIT compilation
|
||||||
|
// This uses only features the JIT supports: integers, arithmetic, conditionals, functions
|
||||||
|
|
||||||
|
fn fib(n: Int): Int =
|
||||||
|
if n <= 1 then n
|
||||||
|
else fib(n - 1) + fib(n - 2)
|
||||||
|
|
||||||
|
fn factorial(n: Int): Int =
|
||||||
|
if n <= 1 then 1
|
||||||
|
else n * factorial(n - 1)
|
||||||
|
|
||||||
|
fn main(): Int = {
|
||||||
|
let a = fib(30)
|
||||||
|
let b = factorial(10)
|
||||||
|
a + b
|
||||||
|
}
|
||||||
113
src/main.rs
113
src/main.rs
@@ -139,6 +139,15 @@ fn main() {
|
|||||||
// Package manager
|
// Package manager
|
||||||
handle_pkg_command(&args[2..]);
|
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 => {
|
path => {
|
||||||
// Run a file
|
// Run a file
|
||||||
run_file(path);
|
run_file(path);
|
||||||
@@ -155,7 +164,8 @@ fn print_help() {
|
|||||||
println!();
|
println!();
|
||||||
println!("Usage:");
|
println!("Usage:");
|
||||||
println!(" lux Start the REPL");
|
println!(" lux Start the REPL");
|
||||||
println!(" lux <file.lux> Run a file");
|
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 fmt <file.lux> Format a file (--check to verify only)");
|
||||||
println!(" lux check <file.lux> Type check without running");
|
println!(" lux check <file.lux> Type check without running");
|
||||||
println!(" lux test [pattern] Run tests (optional pattern filter)");
|
println!(" lux test [pattern] Run tests (optional pattern filter)");
|
||||||
@@ -246,6 +256,107 @@ fn check_file(path: &str) {
|
|||||||
println!("{}: OK", path);
|
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]) {
|
fn run_tests(args: &[String]) {
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|||||||
Reference in New Issue
Block a user