diff --git a/docs/VISION.md b/docs/VISION.md index a327165..a63fb33 100644 --- a/docs/VISION.md +++ b/docs/VISION.md @@ -128,11 +128,11 @@ fn retry(action: F, times: Int): Result | 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. | | **File/Network Effects** | 1-2 weeks | Real IO beyond Console | | **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) @@ -245,7 +245,7 @@ Hint: Maybe you need to parse the string? ## Immediate Next Steps 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` 4. **Error Message Overhaul** - Source snippets, suggestions, colors 5. **JavaScript Backend** - Compile to runnable JS diff --git a/examples/jit_test.lux b/examples/jit_test.lux new file mode 100644 index 0000000..e7bfdd5 --- /dev/null +++ b/examples/jit_test.lux @@ -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 +} diff --git a/src/main.rs b/src/main.rs index d630c56..0a6cd86 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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 [--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 Run a file"); - println!(" lux fmt Format a file (--check to verify only)"); - println!(" lux check Type check without running"); - println!(" lux test [pattern] Run tests (optional pattern filter)"); - println!(" lux watch Watch and re-run on changes"); - println!(" lux debug Start interactive debugger"); - println!(" lux init [name] Initialize a new project"); - println!(" lux pkg 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 Run a file (interpreter)"); + println!(" lux compile Compile and run with JIT (--benchmark for timing)"); + println!(" lux fmt Format a file (--check to verify only)"); + println!(" lux check Type check without running"); + println!(" lux test [pattern] Run tests (optional pattern filter)"); + println!(" lux watch Watch and re-run on changes"); + println!(" lux debug Start interactive debugger"); + println!(" lux init [name] Initialize a new project"); + println!(" lux pkg 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;