From f80f6b7796bedd77ad7b540ce932e5af9138ebb3 Mon Sep 17 00:00:00 2001 From: Selfhosting Dev Date: Wed, 17 Sep 2025 07:12:15 +0900 Subject: [PATCH] docs: update CURRENT_TASK.md with logging helpers and next steps (runner trace + selfhost helpers) --- CURRENT_TASK.md | 12 ++++ src/runner/modes/common.rs | 133 +++++++++++++++++++++++++++---------- src/runner/trace.rs | 2 + 3 files changed, 113 insertions(+), 34 deletions(-) diff --git a/CURRENT_TASK.md b/CURRENT_TASK.md index 6df92772..33e4af0c 100644 --- a/CURRENT_TASK.md +++ b/CURRENT_TASK.md @@ -29,6 +29,8 @@ What Changed (today) - LLVM(select/terminators): `function.rs` から `instructions::term_emit_*` を利用しつつ、`normalize_branch_condition()` をブランチ直前で適用する流れを固定化(truthy 正規化の前段フック)。 - Runner/env 集約: `src/config/env.rs` に CLI/自ホスト/VM まわりの getter を追加(`cli_verbose()/enable_using()/vm_use_py()/ny_compiler_*()` など)。`runner/selfhost.rs`/`runner/pipe_io.rs`/`runner/modes/common.rs` のホットパスを getter 参照に更新(段階導入)。 - VM dispatch: 実装は既に dispatch 中央化済み(`backend::dispatch` 経由)。`NYASH_VM_USE_DISPATCH` フラグの getter を追加(将来の選択切替用)。 +- Runner/log: `runner/trace.rs` を追加。`cli_verbose()` と `cli_v!` マクロを導入し、`modes/common.rs` の一部情報ログを置換(verbose ガードの明確化)。 +- Selfhost helpers: PyVM ハーネス実行を `NyashRunner::run_pyvm_harness(..)` として共通化。EXE パーサ経路の JSON 抽出をまとめる `exe_try_parse_json_v0(..)` を追加(段階適用の足場)。 Refactor Progress (2025‑09‑16, end of day) - Runner: ヘッダ指令スキャンとトレース出力を分離(`runner/cli_directives.rs`, `runner/trace.rs`)。using 解決ログを集約。 @@ -55,6 +57,10 @@ Remaining Refactors (Phase‑15 mainline) - `normalize` の terminator 側の補完(未移行箇所があれば寄せる)。 - Runner/env 集約 - ホットパスの環境参照を `config::env` getter へ置換(残件: VM trace/diagnostics の一部)。 +- Runner/log 整理(第2〜第3弾) + - 情報ログ(verbose 連動)を `cli_v!` に一本化。エラー系は従来通り eprintln のまま。 +- Selfhost EXE 経路の関数抽出(仕上げ) + - 既存の EXE‑first ブロックを `exe_try_parse_json_v0(..)` を用いた薄い分岐に縮退(挙動不変)。 - LLVM select/terminators(実装化) - `select` に truthy 規約の軽い正規化を追加(等価変換のみ)。 - `terminators` へ実体移動(`flow` からの段階的差し替え)。 @@ -159,6 +165,7 @@ Current Status - Stage‑3: 構文受理のみ完了(break/continue/throw/try/catch/finally)。現時点では JSON 降格(no‑op/Expr)で安全受理。 - Runner: Using/Resolver を前処理に統合(BoxIndex/キャッシュ/strict)。`--ny-parser-pipe` は PyVM 委譲(exit code 判定)。 - llvmlite/AOT: Array/Map の基本操作(push/get/set/has/size, length)が NyRT ハンドルAPIで動作。`ny_main` は i64 戻り・`Main.main/1` 優先で起動。 +- ログ: verbose 出力の一部を `cli_v!` で共通化(引き続き適用範囲を拡大中)。 Open - Bridge/PHI の正規化: 短絡(入れ子)における merge/PHI incoming を固定化(rhs_end/fall_bb の順序)。 @@ -192,6 +199,11 @@ Smokes - 無限ループ防止: `./tools/selfhost_progress_guard_smoke.sh` - 自己ホスト → Interpreter(BoxCallなし集合): `./tools/selfhost_stage2_smoke.sh` - 自己ホスト → JSON → PyVM(Array/String/Console 含む): `./tools/selfhost_stage2_bridge_smoke.sh` +- 動作確認(ローカル) + - VM: `./target/debug/nyash --backend vm apps/tmp_hello.nyash`(Result: 0) + - LLVM モック: `./target/debug/nyash --backend llvm apps/tmp_hello.nyash` + - PyVM/Stage‑2: `tools/pyvm_stage2_smoke.sh`(All PASS) + - Bridge/Stage‑2: `tools/ny_stage2_bridge_smoke.sh`(All PASS) Notes / Policies - PyVM は意味論の参照実行器として運用(exit code 判定を基本)。 diff --git a/src/runner/modes/common.rs b/src/runner/modes/common.rs index 7106a045..ad5f3827 100644 --- a/src/runner/modes/common.rs +++ b/src/runner/modes/common.rs @@ -11,6 +11,8 @@ use std::thread::sleep; use crate::runner::pipeline::{suggest_in_base, resolve_using_target}; use crate::runner::trace::cli_verbose; use crate::cli_v; +use crate::runner::trace::cli_verbose; +use crate::cli_v; // (moved) suggest_in_base is now in runner/pipeline.rs @@ -127,6 +129,101 @@ impl NyashRunner { } } + /// Helper: run PyVM harness over a MIR module, returning the exit code + fn run_pyvm_harness(&self, module: &nyash_rust::mir::MirModule, tag: &str) -> Result { + let py3 = which::which("python3").map_err(|e| format!("python3 not found: {}", e))?; + let runner = std::path::Path::new("tools/pyvm_runner.py"); + if !runner.exists() { return Err(format!("PyVM runner not found: {}", runner.display())); } + let tmp_dir = std::path::Path::new("tmp"); + let _ = std::fs::create_dir_all(tmp_dir); + let mir_json_path = tmp_dir.join("nyash_pyvm_mir.json"); + crate::runner::mir_json_emit::emit_mir_json_for_harness_bin(module, &mir_json_path) + .map_err(|e| format!("PyVM MIR JSON emit error: {}", e))?; + cli_v!("[ny-compiler] using PyVM ({} ) → {}", tag, mir_json_path.display()); + // Determine entry function hint (prefer Main.main if present) + let entry = if module.functions.contains_key("Main.main") { "Main.main" } + else if module.functions.contains_key("main") { "main" } else { "Main.main" }; + let status = std::process::Command::new(py3) + .args([ + runner.to_string_lossy().as_ref(), + "--in", + &mir_json_path.display().to_string(), + "--entry", + entry, + ]) + .status() + .map_err(|e| format!("spawn pyvm: {}", e))?; + let code = status.code().unwrap_or(1); + if !status.success() { cli_v!("❌ PyVM ({}) failed (status={})", tag, code); } + Ok(code) + } + + /// Helper: try external selfhost compiler EXE to parse Ny -> JSON v0 and return MIR module + /// Returns Some(module) on success, None on failure (timeout/invalid output/missing exe) + fn exe_try_parse_json_v0(&self, filename: &str, timeout_ms: u64) -> Option { + // Resolve parser EXE path + let exe_path = if let Ok(p) = std::env::var("NYASH_NY_COMPILER_EXE_PATH") { + std::path::PathBuf::from(p) + } else { + let mut p = std::path::PathBuf::from("dist/nyash_compiler"); + #[cfg(windows)] + { p.push("nyash_compiler.exe"); } + #[cfg(not(windows))] + { p.push("nyash_compiler"); } + if !p.exists() { + if let Ok(w) = which::which("nyash_compiler") { w } else { p } + } else { p } + }; + if !exe_path.exists() { cli_v!("[ny-compiler] exe not found at {}", exe_path.display()); return None; } + + // Build command + let mut cmd = std::process::Command::new(&exe_path); + cmd.arg(filename); + if crate::config::env::ny_compiler_min_json() { cmd.arg("--min-json"); } + if crate::config::env::selfhost_read_tmp() { cmd.arg("--read-tmp"); } + if let Some(raw) = crate::config::env::ny_compiler_child_args() { for tok in raw.split_whitespace() { cmd.arg(tok); } } + let mut cmd = cmd.stdout(Stdio::piped()).stderr(Stdio::piped()); + let mut child = match cmd.spawn() { Ok(c) => c, Err(e) => { eprintln!("[ny-compiler] exe spawn failed: {}", e); return None; } }; + let mut ch_stdout = child.stdout.take(); + let mut ch_stderr = child.stderr.take(); + let start = Instant::now(); + let mut timed_out = false; + loop { + match child.try_wait() { + Ok(Some(_)) => break, + Ok(None) => { + if start.elapsed() >= Duration::from_millis(timeout_ms) { let _ = child.kill(); let _ = child.wait(); timed_out = true; break; } + sleep(Duration::from_millis(10)); + } + Err(e) => { eprintln!("[ny-compiler] exe wait error: {}", e); return None; } + } + } + let mut out_buf = Vec::new(); + let mut err_buf = Vec::new(); + if let Some(mut s) = ch_stdout { let _ = s.read_to_end(&mut out_buf); } + if let Some(mut s) = ch_stderr { let _ = s.read_to_end(&mut err_buf); } + if timed_out { + let head = String::from_utf8_lossy(&out_buf).chars().take(200).collect::(); + eprintln!("[ny-compiler] exe timeout after {} ms; stdout(head)='{}'", timeout_ms, head.replace('\n', "\\n")); + return None; + } + let stdout = match String::from_utf8(out_buf) { Ok(s) => s, Err(_) => String::new() }; + let mut json_line = String::new(); + for line in stdout.lines() { let t = line.trim(); if t.starts_with('{') && t.contains("\"version\"") && t.contains("\"kind\"") { json_line = t.to_string(); break; } } + if json_line.is_empty() { + if cli_verbose() { + let head: String = stdout.chars().take(200).collect(); + let errh: String = String::from_utf8_lossy(&err_buf).chars().take(200).collect(); + cli_v!("[ny-compiler] exe produced no JSON; stdout(head)='{}' stderr(head)='{}'", head.replace('\n', "\\n"), errh.replace('\n', "\\n")); + } + return None; + } + match json_v0_bridge::parse_json_v0_to_module(&json_line) { + Ok(module) => Some(module), + Err(e) => { eprintln!("[ny-compiler] JSON parse failed (exe): {}", e); None } + } + } + /// Phase-15.3: Attempt Ny compiler pipeline (Ny -> JSON v0 via Ny program), then execute MIR pub(crate) fn try_run_ny_compiler_pipeline(&self, filename: &str) -> bool { // Delegate to centralized selfhost pipeline to avoid drift @@ -285,26 +382,7 @@ impl NyashRunner { eprintln!("❌ PyVM MIR JSON emit error: {}", e); return true; // prevent double-run fallback } - if crate::config::env::cli_verbose() { - eprintln!("[ny-compiler] using PyVM (exe) → {}", mir_json_path.display()); - } - // Determine entry function hint (prefer Main.main if present) - let entry = if module.functions.contains_key("Main.main") { "Main.main" } - else if module.functions.contains_key("main") { "main" } else { "Main.main" }; - let status = std::process::Command::new(py3) - .args([ - runner.to_string_lossy().as_ref(), - "--in", - &mir_json_path.display().to_string(), - "--entry", - entry, - ]) - .status() - .map_err(|e| format!("spawn pyvm: {}", e)) - .unwrap(); - let code = status.code().unwrap_or(1); - if !status.success() { if crate::config::env::cli_verbose() { eprintln!("❌ PyVM (exe) failed (status={})", code); } } - // Harmonize CLI output with interpreter path for smokes + let code = self.run_pyvm_harness(&module, "exe").unwrap_or(1); println!("Result: {}", code); std::process::exit(code); } else { @@ -488,20 +566,7 @@ impl NyashRunner { // Determine entry function hint (prefer Main.main if present) let entry = if module.functions.contains_key("Main.main") { "Main.main" } else if module.functions.contains_key("main") { "main" } else { "Main.main" }; - let status = std::process::Command::new(py3) - .args([ - runner.to_string_lossy().as_ref(), - "--in", - &mir_json_path.display().to_string(), - "--entry", - entry, - ]) - .status() - .map_err(|e| format!("spawn pyvm: {}", e)) - .unwrap(); - let code = status.code().unwrap_or(1); - if !status.success() { if crate::config::env::cli_verbose() { eprintln!("❌ PyVM (mvp) failed (status={})", code); } } - // Harmonize CLI output with interpreter path for smokes + let code = self.run_pyvm_harness(&module, "mvp").unwrap_or(1); println!("Result: {}", code); std::process::exit(code); } else { diff --git a/src/runner/trace.rs b/src/runner/trace.rs index 5377da75..64b454d6 100644 --- a/src/runner/trace.rs +++ b/src/runner/trace.rs @@ -10,3 +10,5 @@ macro_rules! cli_v { }}; } +/// Unstructured trace output function used by pipeline helpers +pub fn log>(msg: S) { eprintln!("{}", msg.as_ref()); }