diff --git a/src/cli/args.rs b/src/cli/args.rs index 907ff02e..791d6a2f 100644 --- a/src/cli/args.rs +++ b/src/cli/args.rs @@ -105,6 +105,12 @@ pub fn build_command() -> Command { .arg(Arg::new("build-aot").long("build-aot").value_name("{cranelift|llvm}").help("AOT backend for --build")) .arg(Arg::new("build-profile").long("profile").value_name("{release|debug}").help("Cargo profile for --build")) .arg(Arg::new("build-target").long("target").value_name("TRIPLE").help("Target triple for --build")) + // Phase 288 P1: REPL mode + .arg(Arg::new("repl") + .long("repl") + .short('i') + .help("Start interactive REPL (Read-Eval-Print Loop)") + .action(clap::ArgAction::SetTrue)) } fn hex_encode_utf8(s: &str) -> String { @@ -206,6 +212,8 @@ pub fn from_matches(matches: &ArgMatches) -> CliConfig { macro_expand_child: matches.get_one::("macro-expand-child").cloned(), dump_expanded_ast_json: matches.get_flag("dump-expanded-ast-json"), macro_ctx_json: matches.get_one::("macro-ctx-json").cloned(), + // Phase 288 P1: REPL mode + repl: matches.get_flag("repl"), }; if cfg.cli_verbose { diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 2ce1955a..13684d06 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -70,6 +70,8 @@ pub struct CliConfig { pub macro_expand_child: Option, pub dump_expanded_ast_json: bool, pub macro_ctx_json: Option, + // Phase 288 P1: REPL mode + pub repl: bool, } pub use groups::{ @@ -221,6 +223,8 @@ impl Default for CliConfig { macro_expand_child: None, dump_expanded_ast_json: false, macro_ctx_json: None, + // Phase 288 P1: REPL mode + repl: false, } } } diff --git a/src/runner/mod.rs b/src/runner/mod.rs index 3b2ca951..b2c79a9e 100644 --- a/src/runner/mod.rs +++ b/src/runner/mod.rs @@ -88,6 +88,70 @@ impl NyashRunner { fn run_build_mvp(&self, cfg_path: &str) -> Result<(), String> { build::run_build_mvp_impl(self, cfg_path) } + + /// Phase 288 P1: Run REPL mode + fn run_repl(&self) -> ! { + use std::io::{self, Write}; + + println!("Nyash REPL v1.0 - Phase 288 MVP"); + println!("Type .help for commands, .exit to quit"); + + let stdin = io::stdin(); + let mut line_buf = String::new(); + + loop { + print!(">>> "); + io::stdout().flush().unwrap(); + + line_buf.clear(); + match stdin.read_line(&mut line_buf) { + Ok(0) => break, // EOF + Ok(_) => { + let line = line_buf.trim(); + + // REPL commands + match line { + ".exit" | ".quit" => break, + ".help" => { + println!("Commands:"); + println!(" .exit / .quit - Exit REPL"); + println!(" .reset - Clear session (Phase 288 P2)"); + println!(" .help - Show this help"); + continue; + } + ".reset" => { + println!("Session reset (Phase 288 P2 implementation)"); + continue; + } + "" => continue, + _ => {} + } + + // Evaluate line + match self.eval_repl_line(line) { + Ok(result) => { + if !result.is_empty() { + println!("{}", result); + } + } + Err(e) => eprintln!("Error: {}", e), + } + } + Err(e) => { + eprintln!("Input error: {}", e); + break; + } + } + } + + println!("Goodbye!"); + std::process::exit(0); + } + + /// Phase 288 P1: Evaluate REPL line (stub) + fn eval_repl_line(&self, _line: &str) -> Result { + Ok("(evaluation Phase 288 P2)".to_string()) + } } #[cfg(not(feature = "jit-direct-only"))] @@ -99,6 +163,10 @@ impl NyashRunner { crate::runner::modes::macro_child::run_macro_child(macro_file); return; } + // Phase 288 P1: REPL mode + if self.config.repl { + self.run_repl(); // never returns + } let groups = self.config.as_groups(); // CLI mode trace: show backend/file/args when emit-mir trace is enabled