stage3: unify to cleanup; MIR return-defer; docs+smokes updated; LLVM(harness): finalize_phis ownership, ret.py simplified, uses-predeclare; cleanup return override green; method-postfix cleanup return WIP (PHI head)

This commit is contained in:
Selfhosting Dev
2025-09-19 02:07:38 +09:00
parent 951a050592
commit 5e818eeb7e
205 changed files with 9671 additions and 1849 deletions

View File

@ -61,9 +61,7 @@ impl NyashRunner {
// MIR dump/verify
if self.config.dump_mir || self.config.verify_mir {
if crate::config::env::cli_verbose() {
println!("🚀 Nyash MIR Compiler - Processing file: {} 🚀", filename);
}
crate::cli_v!("🚀 Nyash MIR Compiler - Processing file: {} 🚀", filename);
self.execute_mir_mode(filename);
return;
}
@ -85,21 +83,17 @@ impl NyashRunner {
// Backend selection
match self.config.backend.as_str() {
"mir" => {
if crate::config::env::cli_verbose() {
println!("🚀 Nyash MIR Interpreter - Executing file: {} 🚀", filename);
}
crate::cli_v!("🚀 Nyash MIR Interpreter - Executing file: {} 🚀", filename);
self.execute_mir_interpreter_mode(filename);
}
"vm" => {
if crate::config::env::cli_verbose() {
println!("🚀 Nyash VM Backend - Executing file: {} 🚀", filename);
}
crate::cli_v!("🚀 Nyash VM Backend - Executing file: {} 🚀", filename);
self.execute_vm_mode(filename);
}
"cranelift" => {
#[cfg(feature = "cranelift-jit")]
{
if cli_verbose() { println!("⚙️ Nyash Cranelift JIT - Executing file: {}", filename); }
crate::cli_v!("⚙️ Nyash Cranelift JIT - Executing file: {}", filename);
self.execute_cranelift_mode(filename);
}
#[cfg(not(feature = "cranelift-jit"))]
@ -109,7 +103,7 @@ impl NyashRunner {
}
}
"llvm" => {
if cli_verbose() { println!("⚡ Nyash LLVM Backend - Executing file: {}", filename); }
crate::cli_v!("⚡ Nyash LLVM Backend - Executing file: {}", filename);
self.execute_llvm_mode(filename);
}
_ => {
@ -494,79 +488,11 @@ impl NyashRunner {
// Optional Phase-15: strip `using` lines (gate) for minimal acceptance
let mut code_ref: &str = &code;
let enable_using = crate::config::env::enable_using();
let cleaned_code_owned;
if enable_using {
let mut out = String::with_capacity(code.len());
let mut used_names: Vec<(String, Option<String>)> = Vec::new();
for line in code.lines() {
let t = line.trim_start();
if t.starts_with("using ") {
// Skip `using ns` or `using ns as alias` lines (MVP)
if crate::config::env::cli_verbose() {
eprintln!("[using] stripped line: {}", line);
}
// Parse namespace or path and optional alias
let rest0 = t.strip_prefix("using ").unwrap().trim();
// allow trailing semicolon
let rest0 = rest0.strip_suffix(';').unwrap_or(rest0).trim();
// Split alias
let (target, alias) = if let Some(pos) = rest0.find(" as ") {
(rest0[..pos].trim().to_string(), Some(rest0[pos+4..].trim().to_string()))
} else { (rest0.to_string(), None) };
// If quoted or looks like relative/absolute path, treat as path; else as namespace
let is_path = target.starts_with('"') || target.starts_with("./") || target.starts_with('/') || target.ends_with(".nyash");
if is_path {
let mut path = target.trim_matches('"').to_string();
// existence check and strict handling
let missing = !std::path::Path::new(&path).exists();
if missing {
if std::env::var("NYASH_USING_STRICT").ok().as_deref() == Some("1") {
eprintln!("❌ using: path not found: {}", path);
std::process::exit(1);
} else if crate::config::env::cli_verbose() {
eprintln!("[using] path not found (continuing): {}", path);
}
}
// choose alias or derive from filename stem
let name = alias.clone().unwrap_or_else(|| {
std::path::Path::new(&path)
.file_stem().and_then(|s| s.to_str()).unwrap_or("module").to_string()
});
// register alias only (path-backed)
used_names.push((name, Some(path)));
} else {
used_names.push((target, alias));
}
continue;
}
out.push_str(line);
out.push('\n');
}
cleaned_code_owned = out;
code_ref = &cleaned_code_owned;
// Register modules with resolver (aliases/modules/paths)
let using_ctx = self.init_using_context();
let strict = std::env::var("NYASH_USING_STRICT").ok().as_deref() == Some("1");
let verbose = crate::config::env::cli_verbose();
let ctx_dir = std::path::Path::new(filename).parent();
for (ns_or_alias, alias_or_path) in used_names {
if let Some(path) = alias_or_path {
let sb = crate::box_trait::StringBox::new(path);
crate::runtime::modules_registry::set(ns_or_alias, Box::new(sb));
} else {
match resolve_using_target(&ns_or_alias, false, &using_ctx.pending_modules, &using_ctx.using_paths, &using_ctx.aliases, ctx_dir, strict, verbose) {
Ok(value) => {
let sb = crate::box_trait::StringBox::new(value);
crate::runtime::modules_registry::set(ns_or_alias, Box::new(sb));
}
Err(e) => {
eprintln!("❌ using: {}", e);
std::process::exit(1);
}
}
}
if crate::config::env::enable_using() {
match crate::runner::modes::common_util::resolve::strip_using_and_register(self, &code, filename) {
Ok(s) => { cleaned_code_owned = s; code_ref = &cleaned_code_owned; }
Err(e) => { eprintln!("{}", e); std::process::exit(1); }
}
}

View File

@ -0,0 +1,177 @@
use std::path::Path;
use super::io::spawn_with_timeout;
/// Emit MIR JSON and invoke the Python llvmlite harness to produce an object file.
/// - module: lib-side MIR module
/// - out_path: destination object path
/// - timeout_ms: process timeout
#[allow(dead_code)]
pub fn llvmlite_emit_object(
module: &nyash_rust::mir::MirModule,
out_path: &str,
timeout_ms: u64,
) -> Result<(), String> {
// Ensure parent directory exists
if let Some(parent) = Path::new(out_path).parent() {
let _ = std::fs::create_dir_all(parent);
}
// Locate python3 and harness
let py3 = which::which("python3").map_err(|e| format!("python3 not found: {}", e))?;
let harness = Path::new("tools/llvmlite_harness.py");
if !harness.exists() {
return Err(format!("llvmlite harness not found: {}", harness.display()));
}
// Emit MIR(JSON) to tmp
let tmp_dir = Path::new("tmp");
let _ = std::fs::create_dir_all(tmp_dir);
let mir_json_path = tmp_dir.join("nyash_harness_mir.json");
crate::runner::mir_json_emit::emit_mir_json_for_harness(module, &mir_json_path)
.map_err(|e| format!("MIR JSON emit error: {}", e))?;
crate::cli_v!(
"[Runner/LLVM] using llvmlite harness → {} (mir={})",
out_path,
mir_json_path.display()
);
// Spawn harness
let mut cmd = std::process::Command::new(py3);
cmd.args([
harness.to_string_lossy().as_ref(),
"--in",
&mir_json_path.display().to_string(),
"--out",
out_path,
]);
let out = spawn_with_timeout(cmd, timeout_ms).map_err(|e| format!("spawn harness: {}", e))?;
if out.timed_out || !out.status_ok {
return Err(format!(
"llvmlite harness failed (timeout={} code={:?})",
out.timed_out, out.exit_code
));
}
// Verify output
match std::fs::metadata(out_path) {
Ok(meta) if meta.len() > 0 => {
crate::cli_v!(
"[LLVM] object emitted: {} ({} bytes)",
out_path,
meta.len()
);
Ok(())
}
_ => Err(format!("harness output not found or empty: {}", out_path)),
}
}
/// Resolve ny-llvmc executable path with env/PATH fallbacks
fn resolve_ny_llvmc() -> std::path::PathBuf {
std::env::var("NYASH_NY_LLVM_COMPILER")
.ok()
.and_then(|s| if !s.is_empty() { Some(std::path::PathBuf::from(s)) } else { None })
.or_else(|| which::which("ny-llvmc").ok())
.unwrap_or_else(|| std::path::PathBuf::from("target/release/ny-llvmc"))
}
fn hint_ny_llvmc_missing(path: &std::path::Path) -> String {
format!(
"ny-llvmc not found (tried: {}).\nHints:\n - Build it: cargo build -p nyash-llvm-compiler --release\n - Use the built binary: target/release/ny-llvmc\n - Or set env NYASH_NY_LLVM_COMPILER=/full/path/to/ny-llvmc\n - Or add it to PATH\n",
path.display()
)
}
/// Emit native executable via ny-llvmc (lib-side MIR)
#[allow(dead_code)]
pub fn ny_llvmc_emit_exe_lib(
module: &nyash_rust::mir::MirModule,
exe_out: &str,
nyrt_dir: Option<&str>,
extra_libs: Option<&str>,
) -> Result<(), String> {
let tmp_dir = std::path::Path::new("tmp");
let _ = std::fs::create_dir_all(tmp_dir);
let json_path = tmp_dir.join("nyash_cli_emit.json");
crate::runner::mir_json_emit::emit_mir_json_for_harness(module, &json_path)
.map_err(|e| format!("MIR JSON emit error: {}", e))?;
let ny_llvmc = resolve_ny_llvmc();
if !ny_llvmc.exists() {
return Err(hint_ny_llvmc_missing(&ny_llvmc));
}
let mut cmd = std::process::Command::new(ny_llvmc);
cmd.arg("--in")
.arg(&json_path)
.arg("--emit")
.arg("exe")
.arg("--out")
.arg(exe_out);
if let Some(dir) = nyrt_dir { cmd.arg("--nyrt").arg(dir); } else { cmd.arg("--nyrt").arg("target/release"); }
if let Some(flags) = extra_libs { if !flags.trim().is_empty() { cmd.arg("--libs").arg(flags); } }
let status = cmd.status().map_err(|e| {
let prog_path = std::path::Path::new(cmd.get_program());
format!(
"failed to spawn ny-llvmc: {}\n{}",
e,
hint_ny_llvmc_missing(prog_path)
)
})?;
if !status.success() {
return Err(format!(
"ny-llvmc failed with status: {:?}.\nTry adding --emit-exe-libs (e.g. \"-ldl -lpthread -lm\") or set --emit-exe-nyrt to NyRT dir (e.g. target/release).",
status.code()
));
}
Ok(())
}
/// Emit native executable via ny-llvmc (bin-side MIR)
#[allow(dead_code)]
pub fn ny_llvmc_emit_exe_bin(
module: &crate::mir::MirModule,
exe_out: &str,
nyrt_dir: Option<&str>,
extra_libs: Option<&str>,
) -> Result<(), String> {
let tmp_dir = std::path::Path::new("tmp");
let _ = std::fs::create_dir_all(tmp_dir);
let json_path = tmp_dir.join("nyash_cli_emit.json");
crate::runner::mir_json_emit::emit_mir_json_for_harness_bin(module, &json_path)
.map_err(|e| format!("MIR JSON emit error: {}", e))?;
let ny_llvmc = resolve_ny_llvmc();
if !ny_llvmc.exists() {
return Err(hint_ny_llvmc_missing(&ny_llvmc));
}
let mut cmd = std::process::Command::new(ny_llvmc);
cmd.arg("--in")
.arg(&json_path)
.arg("--emit")
.arg("exe")
.arg("--out")
.arg(exe_out);
if let Some(dir) = nyrt_dir { cmd.arg("--nyrt").arg(dir); } else { cmd.arg("--nyrt").arg("target/release"); }
if let Some(flags) = extra_libs { if !flags.trim().is_empty() { cmd.arg("--libs").arg(flags); } }
let status = cmd.status().map_err(|e| {
let prog_path = std::path::Path::new(cmd.get_program());
format!(
"failed to spawn ny-llvmc: {}\n{}",
e,
hint_ny_llvmc_missing(prog_path)
)
})?;
if !status.success() {
return Err(format!(
"ny-llvmc failed with status: {:?}.\nTry adding --emit-exe-libs (e.g. \"-ldl -lpthread -lm\") or set --emit-exe-nyrt to NyRT dir (e.g. target/release).",
status.code()
));
}
Ok(())
}
/// Run an executable with arguments and a timeout. Returns (exit_code, timed_out).
#[allow(dead_code)]
pub fn run_executable(exe_path: &str, args: &[&str], timeout_ms: u64) -> Result<(i32, bool), String> {
let mut cmd = std::process::Command::new(exe_path);
for a in args { cmd.arg(a); }
let out = super::io::spawn_with_timeout(cmd, timeout_ms)
.map_err(|e| format!("spawn exe: {}", e))?;
let code = out.exit_code.unwrap_or(1);
Ok((code, out.timed_out))
}

View File

@ -8,3 +8,5 @@ pub mod pyvm;
pub mod selfhost_exe;
pub mod io;
pub mod selfhost;
pub mod resolve;
pub mod exec;

View File

@ -38,3 +38,42 @@ pub fn run_pyvm_harness(module: &crate::mir::MirModule, tag: &str) -> Result<i32
}
Ok(code)
}
/// Run PyVM harness over a nyash_rust (lib) MIR module, returning the exit code
#[allow(dead_code)]
pub fn run_pyvm_harness_lib(module: &nyash_rust::mir::MirModule, tag: &str) -> Result<i32, String> {
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(module, &mir_json_path)
.map_err(|e| format!("PyVM MIR JSON emit error: {}", e))?;
crate::cli_v!("[Runner] 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() {
crate::cli_v!("❌ PyVM ({}) failed (status={})", tag, code);
}
Ok(code)
}

View File

@ -0,0 +1,81 @@
use crate::NyashRunner;
/// Strip `using` lines and register modules/aliases into the runtime registry.
/// Returns cleaned source. No-op when `NYASH_ENABLE_USING` is not set.
#[allow(dead_code)]
pub fn strip_using_and_register(
runner: &NyashRunner,
code: &str,
filename: &str,
) -> Result<String, String> {
if !crate::config::env::enable_using() {
return Ok(code.to_string());
}
let mut out = String::with_capacity(code.len());
let mut used_names: Vec<(String, Option<String>)> = Vec::new();
for line in code.lines() {
let t = line.trim_start();
if t.starts_with("using ") {
crate::cli_v!("[using] stripped line: {}", line);
let rest0 = t.strip_prefix("using ").unwrap().trim();
let rest0 = rest0.strip_suffix(';').unwrap_or(rest0).trim();
let (target, alias) = if let Some(pos) = rest0.find(" as ") {
(rest0[..pos].trim().to_string(), Some(rest0[pos + 4..].trim().to_string()))
} else {
(rest0.to_string(), None)
};
let is_path = target.starts_with('"')
|| target.starts_with("./")
|| target.starts_with('/')
|| target.ends_with(".nyash");
if is_path {
let path = target.trim_matches('"').to_string();
let name = alias.clone().unwrap_or_else(|| {
std::path::Path::new(&path)
.file_stem()
.and_then(|s| s.to_str())
.unwrap_or("module")
.to_string()
});
used_names.push((name, Some(path)));
} else {
used_names.push((target, alias));
}
continue;
}
out.push_str(line);
out.push('\n');
}
// Register modules with resolver (aliases/modules/paths)
let using_ctx = runner.init_using_context();
let strict = std::env::var("NYASH_USING_STRICT").ok().as_deref() == Some("1");
let verbose = crate::config::env::cli_verbose();
let ctx_dir = std::path::Path::new(filename).parent();
for (ns_or_alias, alias_or_path) in used_names {
if let Some(path) = alias_or_path {
let sb = crate::box_trait::StringBox::new(path);
crate::runtime::modules_registry::set(ns_or_alias, Box::new(sb));
} else {
match crate::runner::pipeline::resolve_using_target(
&ns_or_alias,
false,
&using_ctx.pending_modules,
&using_ctx.using_paths,
&using_ctx.aliases,
ctx_dir,
strict,
verbose,
) {
Ok(value) => {
let sb = crate::box_trait::StringBox::new(value);
crate::runtime::modules_registry::set(ns_or_alias, Box::new(sb));
}
Err(e) => {
return Err(format!("using: {}", e));
}
}
}
}
Ok(out)
}

View File

@ -47,91 +47,19 @@ impl NyashRunner {
#[allow(unused_mut)]
let mut module = compile_result.module.clone();
let injected = inject_method_ids(&mut module);
if injected > 0 && std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
eprintln!("[LLVM] method_id injected: {} places", injected);
}
if injected > 0 { crate::cli_v!("[LLVM] method_id injected: {} places", injected); }
// If explicit object path is requested, emit object only
if let Ok(_out_path) = std::env::var("NYASH_LLVM_OBJ_OUT") {
#[cfg(feature = "llvm-harness")]
{
// Harness path (optional): if NYASH_LLVM_USE_HARNESS=1, try Python/llvmlite first.
let use_harness = crate::config::env::llvm_use_harness();
if use_harness {
if let Some(parent) = std::path::Path::new(&_out_path).parent() {
let _ = std::fs::create_dir_all(parent);
if crate::config::env::llvm_use_harness() {
if let Err(e) = crate::runner::modes::common_util::exec::llvmlite_emit_object(&module, &_out_path, 20_000) {
eprintln!("{}", e);
process::exit(1);
}
let py = which::which("python3").ok();
if let Some(py3) = py {
let harness = std::path::Path::new("tools/llvmlite_harness.py");
if harness.exists() {
// 1) Emit MIR(JSON) to a temp file
let tmp_dir = std::path::Path::new("tmp");
let _ = std::fs::create_dir_all(tmp_dir);
let mir_json_path = tmp_dir.join("nyash_harness_mir.json");
if let Err(e) = crate::runner::mir_json_emit::emit_mir_json_for_harness(
&module,
&mir_json_path,
) {
eprintln!("❌ MIR JSON emit error: {}", e);
process::exit(1);
}
if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
eprintln!(
"[Runner/LLVM] using llvmlite harness → {} (mir={})",
_out_path,
mir_json_path.display()
);
}
// 2) Run harness with --in/--out失敗時は即エラー
let mut cmd = std::process::Command::new(py3);
cmd.args([
harness.to_string_lossy().as_ref(),
"--in",
&mir_json_path.display().to_string(),
"--out",
&_out_path,
]);
let out = crate::runner::modes::common_util::io::spawn_with_timeout(cmd, 20_000)
.map_err(|e| format!("spawn harness: {}", e))
.unwrap();
if out.timed_out || !out.status_ok {
eprintln!(
"❌ llvmlite harness failed (timeout={} code={:?})",
out.timed_out,
out.exit_code
);
process::exit(1);
}
// Verify
match std::fs::metadata(&_out_path) {
Ok(meta) if meta.len() > 0 => {
if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref()
== Some("1")
{
eprintln!(
"[LLVM] object emitted by harness: {} ({} bytes)",
_out_path,
meta.len()
);
}
return;
}
_ => {
eprintln!(
"❌ harness output not found or empty: {}",
_out_path
);
process::exit(1);
}
}
} else {
eprintln!("❌ harness script not found: {}", harness.display());
process::exit(1);
}
}
eprintln!("❌ python3 not found in PATH. Install Python 3 to use the harness.");
process::exit(1);
return;
}
// Verify object presence and size (>0)
match std::fs::metadata(&_out_path) {
@ -165,28 +93,24 @@ impl NyashRunner {
if let Some(parent) = std::path::Path::new(&_out_path).parent() {
let _ = std::fs::create_dir_all(parent);
}
if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
eprintln!(
"[Runner/LLVM] emitting object to {} (cwd={})",
_out_path,
std::env::current_dir()
.map(|p| p.display().to_string())
.unwrap_or_default()
);
}
crate::cli_v!(
"[Runner/LLVM] emitting object to {} (cwd={})",
_out_path,
std::env::current_dir()
.map(|p| p.display().to_string())
.unwrap_or_default()
);
if let Err(e) = llvm_compile_to_object(&module, &_out_path) {
eprintln!("❌ LLVM object emit error: {}", e);
process::exit(1);
}
match std::fs::metadata(&_out_path) {
Ok(meta) if meta.len() > 0 => {
if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
eprintln!(
"[LLVM] object emitted: {} ({} bytes)",
_out_path,
meta.len()
);
}
crate::cli_v!(
"[LLVM] object emitted: {} ({} bytes)",
_out_path,
meta.len()
);
}
_ => {
eprintln!("❌ LLVM object not found or empty: {}", _out_path);
@ -202,6 +126,40 @@ impl NyashRunner {
}
}
// Execute via LLVM backend (harness preferred)
#[cfg(feature = "llvm-harness")]
{
if crate::config::env::llvm_use_harness() {
// Prefer producing a native executable via ny-llvmc, then execute it
let exe_out = "tmp/nyash_llvm_run";
let libs = std::env::var("NYASH_LLVM_EXE_LIBS").ok();
match crate::runner::modes::common_util::exec::ny_llvmc_emit_exe_lib(
&module,
exe_out,
None,
libs.as_deref(),
) {
Ok(()) => {
match crate::runner::modes::common_util::exec::run_executable(exe_out, &[], 20_000) {
Ok((code, _timed_out)) => {
println!("✅ LLVM (harness) execution completed (exit={})", code);
std::process::exit(code);
}
Err(e) => {
eprintln!("❌ run executable error: {}", e);
std::process::exit(1);
}
}
}
Err(e) => {
eprintln!("❌ ny-llvmc emit-exe error: {}", e);
eprintln!(" Hint: build ny-llvmc: cargo build -p nyash-llvm-compiler --release");
std::process::exit(1);
}
}
}
}
// Execute via LLVM backend (mock or real)
#[cfg(feature = "llvm-inkwell-legacy")]
{

View File

@ -78,38 +78,13 @@ impl NyashRunner {
// Emit native executable via ny-llvmc (crate) and exit
if let Some(exe_out) = self.config.emit_exe.as_ref() {
let tmp_dir = std::path::Path::new("tmp");
let _ = std::fs::create_dir_all(tmp_dir);
let json_path = tmp_dir.join("nyash_cli_emit.json");
if let Err(e) = crate::runner::mir_json_emit::emit_mir_json_for_harness(&compile_result.module, &json_path) {
eprintln!("❌ MIR JSON emit error: {}", e);
std::process::exit(1);
}
let ny_llvmc = std::env::var("NYASH_NY_LLVM_COMPILER")
.ok()
.and_then(|s| if !s.is_empty() { Some(std::path::PathBuf::from(s)) } else { None })
.or_else(|| which::which("ny-llvmc").ok())
.unwrap_or_else(|| std::path::PathBuf::from("target/release/ny-llvmc"));
let mut cmd = std::process::Command::new(ny_llvmc);
cmd.arg("--in").arg(&json_path)
.arg("--emit").arg("exe")
.arg("--out").arg(exe_out);
if let Some(dir) = self.config.emit_exe_nyrt.as_ref() {
cmd.arg("--nyrt").arg(dir);
} else {
cmd.arg("--nyrt").arg("target/release");
}
if let Some(flags) = self.config.emit_exe_libs.as_ref() {
if !flags.trim().is_empty() {
cmd.arg("--libs").arg(flags);
}
}
let status = cmd.status().unwrap_or_else(|e| {
eprintln!("❌ failed to spawn ny-llvmc: {}", e);
std::process::exit(1);
});
if !status.success() {
eprintln!("❌ ny-llvmc failed with status: {:?}", status.code());
if let Err(e) = crate::runner::modes::common_util::exec::ny_llvmc_emit_exe_lib(
&compile_result.module,
exe_out,
self.config.emit_exe_nyrt.as_deref(),
self.config.emit_exe_libs.as_deref(),
) {
eprintln!("{}", e);
std::process::exit(1);
}
println!("EXE written: {}", exe_out);

View File

@ -45,9 +45,7 @@ impl NyashRunner {
let mut module_interp = compile_result.module.clone();
if std::env::var("NYASH_VM_ESCAPE_ANALYSIS").ok().as_deref() == Some("1") {
let removed = nyash_rust::mir::passes::escape::escape_elide_barriers_vm(&mut module_interp);
if removed > 0 && std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
eprintln!("[MIR-Interp] escape_elide_barriers: removed {} barriers", removed);
}
if removed > 0 { crate::cli_v!("[MIR-Interp] escape_elide_barriers: removed {} barriers", removed); }
}
// Execute with MIR interpreter

View File

@ -35,65 +35,12 @@ pub fn execute_pyvm_only(_runner: &NyashRunner, filename: &str) {
// Optional: VM-only escape analysis elision pass retained for parity with VM path
if std::env::var("NYASH_VM_ESCAPE_ANALYSIS").ok().as_deref() == Some("1") {
let removed = nyash_rust::mir::passes::escape::escape_elide_barriers_vm(&mut compile_result.module);
if removed > 0 && std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
eprintln!("[PyVM] escape_elide_barriers: removed {} barriers", removed);
}
if removed > 0 { crate::cli_v!("[PyVM] escape_elide_barriers: removed {} barriers", removed); }
}
// Emit MIR JSON for PyVM harness
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");
if let Err(e) = crate::runner::mir_json_emit::emit_mir_json_for_harness(
&compile_result.module,
&mir_json_path,
) {
eprintln!("❌ PyVM MIR JSON emit error: {}", e);
process::exit(1);
}
// Pick entry: prefer Main.main or main
let entry = if compile_result.module.functions.contains_key("Main.main") {
"Main.main"
} else if compile_result.module.functions.contains_key("main") {
"main"
} else {
"Main.main"
};
// Locate python3 and run harness
let py = which::which("python3").ok();
if let Some(py3) = py {
let runner = std::path::Path::new("tools/pyvm_runner.py");
if !runner.exists() {
eprintln!("❌ PyVM runner not found: {}", runner.display());
process::exit(1);
}
if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
eprintln!(
"[Runner/PyVM] {} (mir={})",
filename,
mir_json_path.display()
);
}
let mut cmd = std::process::Command::new(py3);
cmd.args([
runner.to_string_lossy().as_ref(),
"--in",
&mir_json_path.display().to_string(),
"--entry",
entry,
]);
let out = crate::runner::modes::common_util::io::spawn_with_timeout(cmd, 10_000)
.map_err(|e| format!("spawn pyvm: {}", e))
.unwrap();
let code = if out.timed_out { 1 } else { out.exit_code.unwrap_or(1) };
if out.timed_out && std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
eprintln!("❌ PyVM timeout");
}
process::exit(code);
} else {
eprintln!("❌ python3 not found in PATH. Install Python 3 to use PyVM.");
process::exit(1);
// Delegate to common PyVM harness
match crate::runner::modes::common_util::pyvm::run_pyvm_harness_lib(&compile_result.module, "pyvm") {
Ok(code) => { process::exit(code); }
Err(e) => { eprintln!("❌ PyVM error: {}", e); process::exit(1); }
}
}

View File

@ -101,20 +101,12 @@ impl NyashRunner {
}
};
// Optional Phase-15: strip `using` lines (gate) for minimal acceptance in VM path
let enable_using = crate::config::env::enable_using();
let code = if enable_using {
let mut out = String::with_capacity(code.len());
for line in code.lines() {
let t = line.trim_start();
if t.starts_with("using ") {
// Strip using lines (module resolution handled by nyash.toml elsewhere)
continue;
}
out.push_str(line);
out.push('\n');
// Optional Phase-15: strip `using` lines and register aliases/modules
let code = if crate::config::env::enable_using() {
match crate::runner::modes::common::resolve::strip_using_and_register(self, &code, filename) {
Ok(s) => s,
Err(e) => { eprintln!("{}", e); process::exit(1); }
}
out
} else { code };
// Parse to AST
@ -185,67 +177,14 @@ impl NyashRunner {
let mut module_vm = compile_result.module.clone();
if std::env::var("NYASH_VM_ESCAPE_ANALYSIS").ok().as_deref() == Some("1") {
let removed = nyash_rust::mir::passes::escape::escape_elide_barriers_vm(&mut module_vm);
if removed > 0 && std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
eprintln!("[VM] escape_elide_barriers: removed {} barriers", removed);
}
if removed > 0 { crate::cli_v!("[VM] escape_elide_barriers: removed {} barriers", removed); }
}
// Optional: PyVM path. When NYASH_VM_USE_PY=1, emit MIR(JSON) and delegate execution to tools/pyvm_runner.py
if std::env::var("NYASH_VM_USE_PY").ok().as_deref() == Some("1") {
let py = which::which("python3").ok();
if let Some(py3) = py {
let runner = std::path::Path::new("tools/pyvm_runner.py");
if runner.exists() {
// Emit MIR(JSON)
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");
if let Err(e) = crate::runner::mir_json_emit::emit_mir_json_for_harness(
&module_vm,
&mir_json_path,
) {
eprintln!("❌ PyVM MIR JSON emit error: {}", e);
process::exit(1);
}
if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
eprintln!(
"[Runner/VM] using PyVM → {} (mir={})",
filename,
mir_json_path.display()
);
}
// Determine entry function hint (prefer Main.main if present)
let entry = if module_vm.functions.contains_key("Main.main") {
"Main.main"
} else if module_vm.functions.contains_key("main") {
"main"
} else {
"Main.main"
};
// Spawn runner
let mut cmd = std::process::Command::new(py3);
cmd.args([
runner.to_string_lossy().as_ref(),
"--in",
&mir_json_path.display().to_string(),
"--entry",
entry,
]);
let out = super::common_util::io::spawn_with_timeout(cmd, 10_000)
.map_err(|e| format!("spawn pyvm: {}", e))
.unwrap();
let code = if out.timed_out { 1 } else { out.exit_code.unwrap_or(1) };
if out.timed_out && std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
eprintln!("❌ PyVM timeout");
}
process::exit(code);
} else {
eprintln!("❌ PyVM runner not found: {}", runner.display());
process::exit(1);
}
} else {
eprintln!("❌ python3 not found in PATH. Install Python 3 to use PyVM.");
process::exit(1);
match super::common_util::pyvm::run_pyvm_harness_lib(&module_vm, "vm") {
Ok(code) => { process::exit(code); }
Err(e) => { eprintln!("❌ PyVM error: {}", e); process::exit(1); }
}
}