diff --git a/src/mir/builder.rs b/src/mir/builder.rs index 88afd982..4bb41aa9 100644 --- a/src/mir/builder.rs +++ b/src/mir/builder.rs @@ -88,7 +88,7 @@ pub(crate) mod type_registry; mod types; // types::annotation / inference(型注釈/推論の箱: 推論は後段) mod utils; mod vars; // variables/scope helpers // small loop helpers (header/exit context) // TypeRegistryBox(型情報管理の一元化) -pub(crate) mod repl_session; // Phase 288 P2: REPL session state (VMValue-based persistence) +// Phase 288 Box化: repl_session moved to src/runner/repl/repl_session.rs // Unified member property kinds for computed/once/birth_once #[derive(Debug, Clone, PartialEq, Eq, Hash)] diff --git a/src/runner/mod.rs b/src/runner/mod.rs index 137eb0da..db5c4a49 100644 --- a/src/runner/mod.rs +++ b/src/runner/mod.rs @@ -34,6 +34,7 @@ pub mod modes; mod pipe_io; mod pipeline; mod plugins; +mod repl; // Phase 288: REPL module mod selfhost; mod stage1_bridge; mod tasks; @@ -51,8 +52,6 @@ use nyash_rust::runtime; /// Main execution coordinator pub struct NyashRunner { config: CliConfig, - /// Phase 288 P2: REPL session - stores runtime values across evaluations - repl_session: std::cell::RefCell>, } /// Minimal task runner: read hako.toml (preferred) or nyash.toml [env]/[tasks], run the named task via shell @@ -72,7 +71,6 @@ impl NyashRunner { Self { config, - repl_session: std::cell::RefCell::new(None), // Phase 288 P2 } } @@ -94,120 +92,6 @@ impl NyashRunner { 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"); - println!(" .help - Show this help"); - continue; - } - ".reset" => { - // Phase 288 P3: Reset session - let mut session_ref = self.repl_session.borrow_mut(); - if let Some(ref mut session) = *session_ref { - session.reset(); - println!("Session reset"); - } else { - println!("Session reset (no active session)"); - } - 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 P2: Evaluate REPL line (VMValue persistence) - fn eval_repl_line(&self, line: &str) -> Result { - use crate::parser::NyashParser; - use crate::mir::MirCompiler; - use crate::backend::mir_interpreter::MirInterpreter; - use crate::mir::builder::repl_session::ReplSessionBox; - - // Initialize session on first use - { - let mut session_ref = self.repl_session.borrow_mut(); - if session_ref.is_none() { - *session_ref = Some(ReplSessionBox::new()); - } - } - - // Parse (minimal wrapper for REPL context - use Main for VM entry point) - let code = format!("static box Main {{ main() {{ {} }} }}", line); - let ast = NyashParser::parse_from_string(&code) - .map_err(|e| format!("Parse error: {}", e))?; - - // Compile with REPL mode flag (暗黙 local 許可) - let mut compiler = MirCompiler::new(); - compiler.set_repl_mode(true); - - let mir_result = compiler.compile_with_source(ast, Some("")) - .map_err(|e| format!("Compile error: {}", e))?; - - // Execute - let mut vm = MirInterpreter::new(); - let result_box = vm.execute_module(&mir_result.module) - .map_err(|e| format!("Runtime error: {}", e))?; - - // Phase 288 P3: Convert to VMValue and store in session - use crate::backend::VMValue; - let vm_value = VMValue::from_nyash_box(result_box); - - { - let mut session_ref = self.repl_session.borrow_mut(); - if let Some(ref mut session) = *session_ref { - session.set_last_value(vm_value); - session.eval_count += 1; - } - } - - // Phase 288 P3: print() output already displayed via ExternCall - // Expression auto-display deferred to Phase 288.1 - Ok(String::new()) - } } #[cfg(not(feature = "jit-direct-only"))] @@ -221,7 +105,7 @@ impl NyashRunner { } // Phase 288 P1: REPL mode if self.config.repl { - self.run_repl(); // never returns + repl::run_repl(self.config.clone()); // never returns } let groups = self.config.as_groups(); diff --git a/src/runner/repl/mod.rs b/src/runner/repl/mod.rs new file mode 100644 index 00000000..49da8276 --- /dev/null +++ b/src/runner/repl/mod.rs @@ -0,0 +1,22 @@ +//! REPL Module - Box-First Architecture +//! +//! Phase 288: Box化モジュール化 +//! - ReplRunnerBox: REPL実行器の完全隔離 +//! - ReplSessionBox: セッション状態の管理 +//! +//! 公開API: run_repl() のみ + +mod repl_runner; +mod repl_session; + +use repl_runner::ReplRunnerBox; +use crate::cli::CliConfig; + +/// Phase 288: REPL モード起動(公開API) +/// +/// REPL ループを開始し、プログラムは終了しない(never returns)。 +/// `.exit` コマンドで終了する。 +pub(crate) fn run_repl(config: CliConfig) -> ! { + let runner = ReplRunnerBox::new(config); + runner.run() +} diff --git a/src/runner/repl/repl_runner.rs b/src/runner/repl/repl_runner.rs new file mode 100644 index 00000000..7c9a5cd8 --- /dev/null +++ b/src/runner/repl/repl_runner.rs @@ -0,0 +1,143 @@ +//! ReplRunnerBox - REPL execution engine +//! +//! Box-First Design: Complete isolation of REPL execution logic +//! Phase 288 P1-P3 +//! +//! Responsibilities: +//! - REPL loop management (.exit, .help, .reset commands) +//! - Line evaluation (parse → compile → execute) +//! - Session state management via ReplSessionBox + +use super::repl_session::ReplSessionBox; +use crate::cli::CliConfig; +use std::cell::RefCell; + +/// Phase 288: REPL実行器(箱理論モジュール化) +pub(super) struct ReplRunnerBox { + #[allow(dead_code)] + config: CliConfig, + session: RefCell>, +} + +impl ReplRunnerBox { + pub(super) fn new(config: CliConfig) -> Self { + Self { + config, + session: RefCell::new(None), + } + } + + /// REPL ループ(メインエントリーポイント) + pub(super) fn run(&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"); + println!(" .help - Show this help"); + continue; + } + ".reset" => { + // Phase 288 P3: Reset session + let mut session_ref = self.session.borrow_mut(); + if let Some(ref mut session) = *session_ref { + session.reset(); + println!("Session reset"); + } else { + println!("Session reset (no active session)"); + } + continue; + } + "" => continue, + _ => {} + } + + // Evaluate line + match self.eval_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); + } + + /// 1行評価(内部メソッド) + fn eval_line(&self, line: &str) -> Result { + use crate::parser::NyashParser; + use crate::mir::MirCompiler; + use crate::backend::mir_interpreter::MirInterpreter; + + // Initialize session on first use + { + let mut session_ref = self.session.borrow_mut(); + if session_ref.is_none() { + *session_ref = Some(ReplSessionBox::new()); + } + } + + // Parse (minimal wrapper for REPL context - use Main for VM entry point) + let code = format!("static box Main {{ main() {{ {} }} }}", line); + let ast = NyashParser::parse_from_string(&code) + .map_err(|e| format!("Parse error: {}", e))?; + + // Compile with REPL mode flag (暗黙 local 許可) + let mut compiler = MirCompiler::new(); + compiler.set_repl_mode(true); + + let mir_result = compiler.compile_with_source(ast, Some("")) + .map_err(|e| format!("Compile error: {}", e))?; + + // Execute + let mut vm = MirInterpreter::new(); + let result_box = vm.execute_module(&mir_result.module) + .map_err(|e| format!("Runtime error: {}", e))?; + + // Phase 288 P3: Convert to VMValue and store in session + use crate::backend::VMValue; + let vm_value = VMValue::from_nyash_box(result_box); + + { + let mut session_ref = self.session.borrow_mut(); + if let Some(ref mut session) = *session_ref { + session.set_last_value(vm_value); + session.eval_count += 1; + } + } + + // Phase 288 P3: print() output already displayed via ExternCall + // Expression auto-display deferred to Phase 288.1 + Ok(String::new()) + } +} diff --git a/src/mir/builder/repl_session.rs b/src/runner/repl/repl_session.rs similarity index 75% rename from src/mir/builder/repl_session.rs rename to src/runner/repl/repl_session.rs index 8ae13381..40f007b2 100644 --- a/src/mir/builder/repl_session.rs +++ b/src/runner/repl/repl_session.rs @@ -11,7 +11,7 @@ use std::collections::BTreeMap; /// REPL session context - isolated from file mode #[derive(Debug, Default)] -pub struct ReplSessionBox { +pub(super) struct ReplSessionBox { /// Session-level variables (runtime values, persists across evaluations) pub variables: BTreeMap, @@ -23,31 +23,34 @@ pub struct ReplSessionBox { } impl ReplSessionBox { - pub fn new() -> Self { + pub(super) fn new() -> Self { Self::default() } /// REPL set: 変数に実行時の値を保存 - pub fn set(&mut self, name: String, value: VMValue) { + #[allow(dead_code)] + pub(super) fn set(&mut self, name: String, value: VMValue) { self.variables.insert(name, value); } /// REPL get: 変数の実行時の値を取得(未定義は None) - pub fn get(&self, name: &str) -> Option<&VMValue> { + #[allow(dead_code)] + pub(super) fn get(&self, name: &str) -> Option<&VMValue> { self.variables.get(name) } /// セッションに変数が存在するか確認 - pub fn has(&self, name: &str) -> bool { + #[allow(dead_code)] + pub(super) fn has(&self, name: &str) -> bool { self.variables.contains_key(name) } - pub fn set_last_value(&mut self, value: VMValue) { + pub(super) fn set_last_value(&mut self, value: VMValue) { self.last_value = Some(value.clone()); self.variables.insert("_".to_string(), value); } - pub fn reset(&mut self) { + pub(super) fn reset(&mut self) { self.variables.clear(); self.last_value = None; self.eval_count = 0;