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:
52
src/runner/modes/common_util/selfhost/child.rs
Normal file
52
src/runner/modes/common_util/selfhost/child.rs
Normal 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)
|
||||
}
|
||||
|
||||
62
src/runner/modes/common_util/selfhost/json.rs
Normal file
62
src/runner/modes/common_util/selfhost/json.rs
Normal 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))
|
||||
}
|
||||
7
src/runner/modes/common_util/selfhost/mod.rs
Normal file
7
src/runner/modes/common_util/selfhost/mod.rs
Normal file
@ -0,0 +1,7 @@
|
||||
/*!
|
||||
* Selfhost runner helpers split: child process launcher and JSON utilities.
|
||||
*/
|
||||
|
||||
pub mod child;
|
||||
pub mod json;
|
||||
|
||||
Reference in New Issue
Block a user