selfhost: introduce using-based imports for compiler/parser/tools; keep includes temporarily. llvm: add PHI wiring JSON trace + unit/integration tests; fast test suite extended. runner: split selfhost helpers, small cleanups.

This commit is contained in:
Selfhosting Dev
2025-09-18 13:35:38 +09:00
parent 3fe908eb0d
commit 951a050592
49 changed files with 644 additions and 287 deletions

View File

@ -0,0 +1,52 @@
use std::path::Path;
/// Run a Nyash program as a child (`nyash --backend vm <program>`) and capture the first JSON v0 line.
/// - `exe`: path to nyash executable
/// - `program`: path to the Nyash script to run (e.g., apps/selfhost-compiler/compiler.nyash)
/// - `timeout_ms`: kill child after this duration
/// - `extra_args`: additional args to pass after program (e.g., "--", "--read-tmp")
/// - `env_remove`: environment variable names to remove for the child
/// - `envs`: key/value pairs to set for the child
pub fn run_ny_program_capture_json(
exe: &Path,
program: &Path,
timeout_ms: u64,
extra_args: &[&str],
env_remove: &[&str],
envs: &[(&str, &str)],
) -> Option<String> {
use std::process::Command;
let mut cmd = Command::new(exe);
cmd.arg("--backend").arg("vm").arg(program);
for a in extra_args {
cmd.arg(a);
}
for k in env_remove {
cmd.env_remove(k);
}
for (k, v) in envs {
cmd.env(k, v);
}
let out = match crate::runner::modes::common_util::io::spawn_with_timeout(cmd, timeout_ms) {
Ok(o) => o,
Err(e) => {
eprintln!("[selfhost-child] spawn failed: {}", e);
return None;
}
};
if out.timed_out {
let head = String::from_utf8_lossy(&out.stdout).chars().take(200).collect::<String>();
eprintln!(
"[selfhost-child] timeout after {} ms; stdout(head)='{}'",
timeout_ms,
head.replace('\n', "\\n")
);
return None;
}
let stdout = match String::from_utf8(out.stdout) {
Ok(s) => s,
Err(_) => String::new(),
};
crate::runner::modes::common_util::selfhost::json::first_json_v0_line(stdout)
}

View File

@ -0,0 +1,62 @@
use crate::mir::MirModule;
use std::path::Path;
/// Extract the first JSON v0 line from stdout text.
/// Heuristic: a line starting with '{' and containing keys "version" and "kind".
pub fn first_json_v0_line<S: AsRef<str>>(s: S) -> Option<String> {
for line in s.as_ref().lines() {
let t = line.trim();
if t.starts_with('{') && t.contains("\"version\"") && t.contains("\"kind\"") {
return Some(t.to_string());
}
}
None
}
/// Parse a JSON v0 line into MirModule using the existing bridge.
pub fn parse_json_v0_line(line: &str) -> Result<MirModule, String> {
crate::runner::json_v0_bridge::parse_json_v0_to_module(line)
.map_err(|e| format!("JSON v0 parse error: {}", e))
}
/// Emit MIR JSON for PyVM and execute the Python runner. Returns exit code on success.
/// Prints a verbose note when `NYASH_CLI_VERBOSE=1`.
pub fn run_pyvm_module(module: &MirModule, label: &str) -> Option<i32> {
// Resolve python3 and runner path
let py3 = which::which("python3").ok()?;
let runner = Path::new("tools/pyvm_runner.py");
if !runner.exists() {
return None;
}
// Prepare JSON for harness
let tmp_dir = Path::new("tmp");
let _ = std::fs::create_dir_all(tmp_dir);
let mir_json_path = tmp_dir.join("nyash_pyvm_mir.json");
if let Err(e) = crate::runner::mir_json_emit::emit_mir_json_for_harness_bin(module, &mir_json_path) {
eprintln!("❌ PyVM MIR JSON emit error: {}", e);
return None;
}
if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
eprintln!("[Bridge] using PyVM ({}) → {}", label, mir_json_path.display());
}
// Select entry
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([
"tools/pyvm_runner.py",
"--in",
&mir_json_path.display().to_string(),
"--entry",
entry,
])
.status()
.map_err(|e| format!("spawn pyvm: {}", e))
.ok()?;
Some(status.code().unwrap_or(1))
}

View File

@ -0,0 +1,7 @@
/*!
* Selfhost runner helpers split: child process launcher and JSON utilities.
*/
pub mod child;
pub mod json;