diff --git a/crates/oxide_cli/src/main.rs b/crates/oxide_cli/src/main.rs index 56843736..ae7c905e 100644 --- a/crates/oxide_cli/src/main.rs +++ b/crates/oxide_cli/src/main.rs @@ -21,11 +21,23 @@ struct Cli { #[derive(Subcommand)] enum Commands { - Eval { code: String }, - Run { file: String }, - Compile { file: String }, - Bench { suite: Option }, - Test { suite: Option }, + Eval { + code: String, + }, + Run { + file: String, + }, + Compile { + #[arg(short = 'e')] + expr: Option, + file: Option, + }, + Bench { + suite: Option, + }, + Test { + suite: Option, + }, } fn main() -> ExitCode { @@ -34,7 +46,7 @@ fn main() -> ExitCode { match cli.command { Some(Commands::Eval { code }) => eval(&code), Some(Commands::Run { file }) => run(&file), - Some(Commands::Compile { file }) => compile(&file), + Some(Commands::Compile { expr, file }) => compile(expr, file), Some(Commands::Bench { .. }) => not_implemented("bench"), Some(Commands::Test { .. }) => not_implemented("test"), None => repl(), @@ -43,15 +55,24 @@ fn main() -> ExitCode { fn eval(code: &str) -> ExitCode { let allocator = Allocator::default(); - match oxide_parser::parse(&allocator, code) { - Ok(program) => { - println!("{program:#?}"); - ExitCode::SUCCESS - } + let program = match oxide_parser::parse(&allocator, code) { + Ok(p) => p, Err(errors) => { for err in &errors { eprintln!("{}", Red.paint(err.to_string())); } + return ExitCode::FAILURE; + } + }; + + let compiler = Compiler::new(); + match compiler.compile(&program) { + Ok(module) => { + print!("{module}"); + ExitCode::SUCCESS + } + Err(err) => { + eprintln!("{}", Red.paint(err)); ExitCode::FAILURE } } @@ -67,13 +88,23 @@ fn run(file: &str) -> ExitCode { } } -fn compile(file: &str) -> ExitCode { - let source = match fs::read_to_string(file) { - Ok(s) => s, - Err(err) => { - eprintln!("{}", Red.paint(format!("Cannot read {file}: {err}"))); - return ExitCode::FAILURE; +fn compile(expr: Option, file: Option) -> ExitCode { + let source = if let Some(code) = expr { + code + } else if let Some(path) = file { + match fs::read_to_string(&path) { + Ok(s) => s, + Err(err) => { + eprintln!("{}", Red.paint(format!("Cannot read {path}: {err}"))); + return ExitCode::FAILURE; + } } + } else { + eprintln!( + "{}", + Red.paint("compile requires -e '' or a file path") + ); + return ExitCode::FAILURE; }; let allocator = Allocator::default(); diff --git a/crates/oxide_cli/tests/cli_smoke.rs b/crates/oxide_cli/tests/cli_smoke.rs index 30459e21..0715a55f 100644 --- a/crates/oxide_cli/tests/cli_smoke.rs +++ b/crates/oxide_cli/tests/cli_smoke.rs @@ -10,8 +10,8 @@ fn eval_simple_expression() { assert!(output.status.success(), "eval 1+2 should exit 0"); let stdout = String::from_utf8_lossy(&output.stdout); assert!( - stdout.contains("Program"), - "output should contain AST node: {stdout}" + stdout.contains("HALT"), + "output should contain HALT bytecode: {stdout}" ); } @@ -44,8 +44,8 @@ fn run_file() { assert!(output.status.success(), "run hello.js should exit 0"); let stdout = String::from_utf8_lossy(&output.stdout); assert!( - stdout.contains("Program"), - "run output should contain AST node" + stdout.contains("HALT"), + "run output should contain bytecode: {stdout}" ); }