Phase 20.12b: quick green + structural cleanup
- Deprecations: add warn-once for nyash.toml (runtime::deprecations); apply in plugin loader v2 (singletons/method_resolver) - Child env + runner hygiene: unify Stage‑3/quiet/disable-fallback env in test/runner; expand LLVM noise filters - Docs/branding: prefer and hako.toml in README.md/README.ja.md and smokes README - VM: implement Map.clear in MIR interpreter (boxes_map) - Stage‑B: gate bundle/alias/require smokes behind SMOKES_ENABLE_STAGEB; fix include cwd and resolve() call even for require-only cases - Core‑Direct: gate rc boundary canary behind SMOKES_ENABLE_CORE_DIRECT - Smokes: inject Stage‑3 and disable selfhost fallback for LLVM runs; filter using/* logs - Quick profile: 168/168 PASS locally This commit accelerates Phase 20.33 (80/20) by stabilizing quick suite, reducing noise, and gating heavy/experimental paths for speed.
This commit is contained in:
@ -121,6 +121,12 @@ pub(super) fn try_handle_map_box(
|
||||
if let Some(d) = dst { this.regs.insert(d, VMValue::from_nyash_box(ret)); }
|
||||
return Ok(true);
|
||||
}
|
||||
"clear" => {
|
||||
// Reset map to empty; return a neutral value
|
||||
let ret = mb.clear();
|
||||
if let Some(d) = dst { this.regs.insert(d, VMValue::from_nyash_box(ret)); }
|
||||
return Ok(true);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,6 +33,28 @@ pub(super) fn try_handle_string_box(
|
||||
if let Some(d) = dst { this.regs.insert(d, VMValue::from_nyash_box(ret)); }
|
||||
return Ok(true);
|
||||
}
|
||||
"replace" => {
|
||||
// replace(old, new) -> string with first occurrence replaced (Rust replace = all; match Core minimal
|
||||
if args.len() != 2 {
|
||||
return Err(VMError::InvalidInstruction("replace expects 2 args".into()));
|
||||
}
|
||||
let old_s = this.reg_load(args[0])?.to_string();
|
||||
let new_s = this.reg_load(args[1])?.to_string();
|
||||
// Core policy: replace only the first occurrence
|
||||
let out = if let Some(pos) = sb_norm.value.find(&old_s) {
|
||||
let mut s = String::with_capacity(sb_norm.value.len() + new_s.len());
|
||||
s.push_str(&sb_norm.value[..pos]);
|
||||
s.push_str(&new_s);
|
||||
s.push_str(&sb_norm.value[pos + old_s.len()..]);
|
||||
s
|
||||
} else {
|
||||
sb_norm.value.clone()
|
||||
};
|
||||
if let Some(d) = dst {
|
||||
this.regs.insert(d, VMValue::from_nyash_box(Box::new(crate::box_trait::StringBox::new(out))));
|
||||
}
|
||||
return Ok(true);
|
||||
}
|
||||
"trim" => {
|
||||
let ret = sb_norm.trim();
|
||||
if let Some(d) = dst { this.regs.insert(d, VMValue::from_nyash_box(ret)); }
|
||||
|
||||
@ -432,6 +432,17 @@ impl MirInterpreter {
|
||||
))
|
||||
}
|
||||
}
|
||||
"replace" => {
|
||||
if args.len() == 2 {
|
||||
let old = self.reg_load(args[0])?.to_string();
|
||||
let new = self.reg_load(args[1])?.to_string();
|
||||
Ok(VMValue::String(s.replace(&old, &new)))
|
||||
} else {
|
||||
Err(VMError::InvalidInstruction(
|
||||
"replace requires 2 arguments".into(),
|
||||
))
|
||||
}
|
||||
}
|
||||
"indexOf" => {
|
||||
if let Some(arg_id) = args.get(0) {
|
||||
let needle = self.reg_load(*arg_id)?.to_string();
|
||||
|
||||
20
src/main.rs
20
src/main.rs
@ -13,7 +13,25 @@ fn main() {
|
||||
env_config::bootstrap_from_toml_env();
|
||||
// Parse command-line arguments
|
||||
let config = CliConfig::parse();
|
||||
|
||||
// Deprecation notice when invoked via legacy binary name
|
||||
if let Ok(exe) = std::env::current_exe() {
|
||||
if let Some(name) = exe.file_name().and_then(|s| s.to_str()) {
|
||||
if name.eq_ignore_ascii_case("nyash") {
|
||||
eprintln!("[deprecate] 'nyash' binary is deprecated. Please use 'hakorune'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
// Legacy binary deprecation: prefer 'hakorune'
|
||||
if let Ok(exe) = std::env::current_exe() {
|
||||
if let Some(name) = exe.file_name().and_then(|s| s.to_str()) {
|
||||
let allow_legacy = std::env::var("HAKO_ALLOW_NYASH").ok().as_deref() == Some("1")
|
||||
|| std::env::var("NYASH_ALLOW_NYASH").ok().as_deref() == Some("1");
|
||||
if name.eq_ignore_ascii_case("nyash") && !allow_legacy {
|
||||
eprintln!("[deprecate] 'nyash' binary is deprecated. Please use 'hakorune'.");
|
||||
std::process::exit(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Create and run the execution coordinator
|
||||
let runner = NyashRunner::new(config);
|
||||
runner.run();
|
||||
|
||||
@ -21,38 +21,38 @@ pub(crate) fn run_json_v0(runner: &NyashRunner, json: &str) -> i32 {
|
||||
let core_direct = std::env::var("HAKO_CORE_DIRECT").ok().as_deref() == Some("1")
|
||||
|| std::env::var("NYASH_CORE_DIRECT").ok().as_deref() == Some("1");
|
||||
if core_direct {
|
||||
if let Some(rc) = try_run_core_direct(json) {
|
||||
return rc;
|
||||
// Only attempt Hako Core dispatcher when payload already looks like MIR(JSON v0)
|
||||
// i.e., has functions/blocks keys. Stage‑B Program(JSON v0) must go through bridge first.
|
||||
let looks_like_mir = json.contains("\"functions\"") && json.contains("\"blocks\"");
|
||||
if looks_like_mir {
|
||||
if let Some(rc) = try_run_core_direct(json) { return rc; }
|
||||
eprintln!("[core-exec] direct Core failed; falling back to VM interpreter");
|
||||
}
|
||||
eprintln!("[core-exec] direct Core failed; falling back to VM interpreter");
|
||||
// else: skip direct Core and continue to bridge/VM path
|
||||
}
|
||||
let mut payload = json.to_string();
|
||||
|
||||
let use_core_wrapper = crate::config::env::nyvm_core_wrapper();
|
||||
let use_downconvert = crate::config::env::nyvm_v1_downconvert();
|
||||
|
||||
if use_core_wrapper || use_downconvert {
|
||||
// Best-effort canonicalize
|
||||
if let Ok(j) = crate::runner::modes::common_util::core_bridge::canonicalize_module_json(&payload) {
|
||||
payload = j;
|
||||
}
|
||||
match crate::runner::json_v1_bridge::try_parse_v1_to_module(&payload) {
|
||||
Ok(Some(module)) => {
|
||||
super::json_v0_bridge::maybe_dump_mir(&module);
|
||||
// OOB strict: reset observation flag
|
||||
crate::runner::child_env::pre_run_reset_oob_if_strict();
|
||||
let rc = runner.execute_mir_module_quiet_exit(&module);
|
||||
if crate::config::env::oob_strict_fail() && crate::runtime::observe::oob_seen() {
|
||||
eprintln!("[gate-c][oob-strict] Out-of-bounds observed → exit(1)");
|
||||
return 1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
Ok(None) => { /* fall through to v0 */ }
|
||||
Err(e) => {
|
||||
eprintln!("❌ JSON v1 bridge error: {}", e);
|
||||
// Always try the v1 bridge first (Stage‑B Program JSON → MIR module).
|
||||
// This is no‑op when input is already MIR(JSON v0) with functions/blocks.
|
||||
if let Ok(j) = crate::runner::modes::common_util::core_bridge::canonicalize_module_json(&payload) {
|
||||
payload = j;
|
||||
}
|
||||
match crate::runner::json_v1_bridge::try_parse_v1_to_module(&payload) {
|
||||
Ok(Some(module)) => {
|
||||
super::json_v0_bridge::maybe_dump_mir(&module);
|
||||
// OOB strict: reset observation flag
|
||||
crate::runner::child_env::pre_run_reset_oob_if_strict();
|
||||
let rc = runner.execute_mir_module_quiet_exit(&module);
|
||||
if crate::config::env::oob_strict_fail() && crate::runtime::observe::oob_seen() {
|
||||
eprintln!("[gate-c][oob-strict] Out-of-bounds observed → exit(1)");
|
||||
return 1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
Ok(None) => { /* fall through to v0 parse/execute */ }
|
||||
Err(e) => {
|
||||
eprintln!("❌ JSON v1 bridge error: {}", e);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,7 +90,7 @@ fn try_run_core_direct(json: &str) -> Option<i32> {
|
||||
}
|
||||
}
|
||||
let code = format!(
|
||||
"include \"lang/src/vm/core/dispatcher.hako\"\nstatic box Main {{ method main(args) {{ local j=\"{}\"; local r=NyVmDispatcher.run(j); print(r); return 0 }} }}\n",
|
||||
"include \"lang/src/vm/core/dispatcher.hako\"\nstatic box Main {{ method main(args) {{ local j=\"{}\"; local r=NyVmDispatcher.run(j); return r }} }}\n",
|
||||
j
|
||||
);
|
||||
if let Ok(mut f) = std::fs::File::create(&script_path) {
|
||||
@ -102,22 +102,13 @@ fn try_run_core_direct(json: &str) -> Option<i32> {
|
||||
let exe = std::env::current_exe().ok()?;
|
||||
let mut cmd = std::process::Command::new(exe);
|
||||
crate::runner::child_env::apply_core_wrapper_env(&mut cmd);
|
||||
// Quiet: parse only the last numeric line
|
||||
let out = cmd
|
||||
.args(["--backend", "vm", script_path.to_string_lossy().as_ref()])
|
||||
.output()
|
||||
.ok()?;
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
// Parse last numeric line
|
||||
let mut rc: Option<i32> = None;
|
||||
for line in stdout.lines().rev() {
|
||||
let s = line.trim();
|
||||
if s.is_empty() { continue; }
|
||||
if let Ok(v) = s.parse::<i64>() {
|
||||
let m = ((v % 256) + 256) % 256;
|
||||
rc = Some(m as i32);
|
||||
break;
|
||||
}
|
||||
if !out.stdout.is_empty() {
|
||||
let _ = std::io::stdout().write_all(&out.stdout);
|
||||
}
|
||||
if let Some(code) = rc { Some(code) } else { Some(1) }
|
||||
let rc = out.status.code().unwrap_or(1);
|
||||
Some(rc)
|
||||
}
|
||||
|
||||
@ -54,7 +54,7 @@ pub(crate) fn execute_file_with_backend(runner: &NyashRunner, filename: &str) {
|
||||
};
|
||||
match json_v0_bridge::parse_source_v0_to_module(&code) {
|
||||
Ok(module) => {
|
||||
crate::cli_v!("🚀 Nyash MIR Interpreter - (parser=ny) Executing file: {} 🚀", filename);
|
||||
crate::cli_v!("🚀 Hakorune MIR Interpreter - (parser=ny) Executing file: {} 🚀", filename);
|
||||
runner.execute_mir_module(&module);
|
||||
return;
|
||||
}
|
||||
@ -67,7 +67,7 @@ pub(crate) fn execute_file_with_backend(runner: &NyashRunner, filename: &str) {
|
||||
|
||||
// AST dump mode
|
||||
if groups.debug.dump_ast {
|
||||
println!("🧠 Nyash AST Dump - Processing file: {}", filename);
|
||||
println!("🧠 Hakorune AST Dump - Processing file: {}", filename);
|
||||
let code = match fs::read_to_string(filename) {
|
||||
Ok(content) => content,
|
||||
Err(e) => {
|
||||
@ -114,7 +114,7 @@ pub(crate) fn execute_file_with_backend(runner: &NyashRunner, filename: &str) {
|
||||
|
||||
// MIR dump/verify
|
||||
if groups.debug.dump_mir || groups.debug.verify_mir {
|
||||
crate::cli_v!("🚀 Nyash MIR Compiler - Processing file: {} 🚀", filename);
|
||||
crate::cli_v!("🚀 Hakorune MIR Compiler - Processing file: {} 🚀", filename);
|
||||
runner.execute_mir_mode(filename);
|
||||
return;
|
||||
}
|
||||
@ -148,17 +148,17 @@ pub(crate) fn execute_file_with_backend(runner: &NyashRunner, filename: &str) {
|
||||
// Backend selection
|
||||
match groups.backend.backend.as_str() {
|
||||
"mir" => {
|
||||
crate::cli_v!("🚀 Nyash MIR Interpreter - Executing file: {} 🚀", filename);
|
||||
crate::cli_v!("🚀 Hakorune MIR Interpreter - Executing file: {} 🚀", filename);
|
||||
runner.execute_mir_mode(filename);
|
||||
}
|
||||
"vm" => {
|
||||
crate::cli_v!("🚀 Nyash VM Backend - Executing file: {} 🚀", filename);
|
||||
crate::cli_v!("🚀 Hakorune VM Backend - Executing file: {} 🚀", filename);
|
||||
// Prefer lightweight in-crate MIR interpreter as VM fallback
|
||||
runner.execute_vm_fallback_interpreter(filename);
|
||||
}
|
||||
#[cfg(feature = "cranelift-jit")]
|
||||
"jit-direct" => {
|
||||
crate::cli_v!("⚡ Nyash JIT-Direct Backend - Executing file: {} ⚡", filename);
|
||||
crate::cli_v!("⚡ Hakorune JIT-Direct Backend - Executing file: {} ⚡", filename);
|
||||
#[cfg(feature = "cranelift-jit")]
|
||||
{
|
||||
// Use independent JIT-direct runner method (no VM execute loop)
|
||||
@ -171,7 +171,7 @@ pub(crate) fn execute_file_with_backend(runner: &NyashRunner, filename: &str) {
|
||||
}
|
||||
}
|
||||
"llvm" => {
|
||||
crate::cli_v!("⚡ Nyash LLVM Backend - Executing file: {} ⚡", filename);
|
||||
crate::cli_v!("⚡ Hakorune LLVM Backend - Executing file: {} ⚡", filename);
|
||||
runner.execute_llvm_mode(filename);
|
||||
}
|
||||
other => {
|
||||
|
||||
@ -48,7 +48,7 @@ pub struct NyashRunner {
|
||||
config: CliConfig,
|
||||
}
|
||||
|
||||
/// Minimal task runner: read nyash.toml [env] and [tasks], run the named task via shell
|
||||
/// Minimal task runner: read hako.toml (preferred) or nyash.toml [env]/[tasks], run the named task via shell
|
||||
use tasks::run_named_task;
|
||||
|
||||
#[cfg(not(feature = "jit-direct-only"))]
|
||||
@ -71,7 +71,7 @@ impl NyashRunner {
|
||||
dispatch::execute_file_with_backend(self, filename);
|
||||
}
|
||||
|
||||
/// Minimal AOT build pipeline driven by nyash.toml (mvp)
|
||||
/// Minimal AOT build pipeline driven by hako.toml/nyash.toml (mvp)
|
||||
fn run_build_mvp(&self, cfg_path: &str) -> Result<(), String> {
|
||||
build::run_build_mvp_impl(self, cfg_path)
|
||||
}
|
||||
|
||||
@ -53,7 +53,7 @@ impl NyashRunner {
|
||||
eprintln!("❌ PyVM MIR JSON emit error: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
crate::cli_v!("[Bridge] using PyVM (pipe) → {}", mir_json_path.display());
|
||||
crate::cli_v!("[Bridge] using PyVM (pipe) → {}", mir_json_path.display());
|
||||
// Determine entry function
|
||||
let allow_top = crate::config::env::entry_allow_toplevel_main();
|
||||
let entry = if module.functions.contains_key("Main.main") {
|
||||
@ -91,7 +91,7 @@ impl NyashRunner {
|
||||
eprintln!("❌ PyVM MIR JSON emit error: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
crate::cli_v!("[Bridge] using PyVM (pipe, v0) → {}", mir_json_path.display());
|
||||
crate::cli_v!("[Bridge] using PyVM (pipe, v0) → {}", mir_json_path.display());
|
||||
let mut cmd = std::process::Command::new(py3);
|
||||
crate::runner::child_env::apply_core_wrapper_env(&mut cmd);
|
||||
let status = cmd
|
||||
|
||||
20
src/runtime/deprecations.rs
Normal file
20
src/runtime/deprecations.rs
Normal file
@ -0,0 +1,20 @@
|
||||
//! Deprecation warnings with "warn once" guards
|
||||
use std::sync::OnceLock;
|
||||
|
||||
fn warn_once(flag: &'static OnceLock<()>, msg: &str) {
|
||||
if flag.get().is_none() {
|
||||
let _ = flag.set(());
|
||||
eprintln!("{}", msg);
|
||||
}
|
||||
}
|
||||
|
||||
static NYASH_TOML_WARN_ONCE: OnceLock<()> = OnceLock::new();
|
||||
|
||||
/// Warn once per process when nyash.toml is used while hako.toml is absent.
|
||||
pub fn warn_nyash_toml_used_once() {
|
||||
warn_once(
|
||||
&NYASH_TOML_WARN_ONCE,
|
||||
"[deprecate] using nyash.toml; please rename to hako.toml",
|
||||
);
|
||||
}
|
||||
|
||||
@ -20,6 +20,7 @@ pub mod unified_registry;
|
||||
pub mod provider_lock;
|
||||
pub mod provider_verify;
|
||||
pub mod observe; // Lightweight observability flags (OOB etc.)
|
||||
pub mod deprecations; // Deprecation warnings with warn-once guards
|
||||
// pub mod plugin_box; // legacy - 古いPluginBox
|
||||
// pub mod plugin_loader; // legacy - Host VTable使用
|
||||
pub mod extern_registry; // ExternCall (env.*) 登録・診断用レジストリ
|
||||
|
||||
@ -5,7 +5,13 @@ use crate::runtime::plugin_loader_v2::enabled::{errors, host_bridge, types};
|
||||
|
||||
pub(super) fn prebirth_singletons(loader: &PluginLoaderV2) -> BidResult<()> {
|
||||
let config = loader.config.as_ref().ok_or(BidError::PluginError)?;
|
||||
let cfg_path = loader.config_path.as_deref().unwrap_or("nyash.toml");
|
||||
let cfg_path = loader
|
||||
.config_path
|
||||
.as_deref()
|
||||
.unwrap_or_else(|| if std::path::Path::new("hako.toml").exists() { "hako.toml" } else { "nyash.toml" });
|
||||
if cfg_path == "nyash.toml" && !std::path::Path::new("hako.toml").exists() {
|
||||
crate::runtime::deprecations::warn_nyash_toml_used_once();
|
||||
}
|
||||
let toml_content = errors::from_fs(std::fs::read_to_string(cfg_path))?;
|
||||
let toml_value: toml::Value = errors::from_toml(toml::from_str(&toml_content))?;
|
||||
for (lib_name, lib_def) in &config.libraries {
|
||||
@ -33,7 +39,13 @@ pub(super) fn ensure_singleton_handle(
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
let cfg_path = loader.config_path.as_deref().unwrap_or("nyash.toml");
|
||||
let cfg_path = loader
|
||||
.config_path
|
||||
.as_deref()
|
||||
.unwrap_or_else(|| if std::path::Path::new("hako.toml").exists() { "hako.toml" } else { "nyash.toml" });
|
||||
if cfg_path == "nyash.toml" && !std::path::Path::new("hako.toml").exists() {
|
||||
crate::runtime::deprecations::warn_nyash_toml_used_once();
|
||||
}
|
||||
let toml_value: toml::Value =
|
||||
toml::from_str(&std::fs::read_to_string(cfg_path).map_err(|_| BidError::PluginError)?)
|
||||
.map_err(|_| BidError::PluginError)?;
|
||||
|
||||
@ -12,7 +12,13 @@ impl PluginLoaderV2 {
|
||||
pub(crate) fn resolve_method_id(&self, box_type: &str, method_name: &str) -> BidResult<u32> {
|
||||
// First try config mapping
|
||||
if let Some(cfg) = self.config.as_ref() {
|
||||
let cfg_path = self.config_path.as_deref().unwrap_or("nyash.toml");
|
||||
let cfg_path = self
|
||||
.config_path
|
||||
.as_deref()
|
||||
.unwrap_or_else(|| if std::path::Path::new("hako.toml").exists() { "hako.toml" } else { "nyash.toml" });
|
||||
if cfg_path == "nyash.toml" && !std::path::Path::new("hako.toml").exists() {
|
||||
crate::runtime::deprecations::warn_nyash_toml_used_once();
|
||||
}
|
||||
|
||||
// Load and parse TOML
|
||||
let toml_content = std::fs::read_to_string(cfg_path).map_err(|_| BidError::PluginError)?;
|
||||
@ -70,7 +76,13 @@ impl PluginLoaderV2 {
|
||||
/// Check if a method returns a Result type
|
||||
pub fn method_returns_result(&self, box_type: &str, method_name: &str) -> bool {
|
||||
if let Some(cfg) = self.config.as_ref() {
|
||||
let cfg_path = self.config_path.as_deref().unwrap_or("nyash.toml");
|
||||
let cfg_path = self
|
||||
.config_path
|
||||
.as_deref()
|
||||
.unwrap_or_else(|| if std::path::Path::new("hako.toml").exists() { "hako.toml" } else { "nyash.toml" });
|
||||
if cfg_path == "nyash.toml" && !std::path::Path::new("hako.toml").exists() {
|
||||
crate::runtime::deprecations::warn_nyash_toml_used_once();
|
||||
}
|
||||
|
||||
if let Ok(toml_content) = std::fs::read_to_string(cfg_path) {
|
||||
if let Ok(toml_value) = toml::from_str::<toml::Value>(&toml_content) {
|
||||
@ -96,7 +108,13 @@ impl PluginLoaderV2 {
|
||||
method_name: &str,
|
||||
) -> BidResult<(u32, u32, bool)> {
|
||||
let cfg = self.config.as_ref().ok_or(BidError::PluginError)?;
|
||||
let cfg_path = self.config_path.as_deref().unwrap_or("nyash.toml");
|
||||
let cfg_path = self
|
||||
.config_path
|
||||
.as_deref()
|
||||
.unwrap_or_else(|| if std::path::Path::new("hako.toml").exists() { "hako.toml" } else { "nyash.toml" });
|
||||
if cfg_path == "nyash.toml" && !std::path::Path::new("hako.toml").exists() {
|
||||
crate::runtime::deprecations::warn_nyash_toml_used_once();
|
||||
}
|
||||
let toml_value: toml::Value =
|
||||
toml::from_str(&std::fs::read_to_string(cfg_path).map_err(|_| BidError::PluginError)?)
|
||||
.map_err(|_| BidError::PluginError)?;
|
||||
@ -124,4 +142,4 @@ pub(super) fn get_special_method_id(method_name: &str) -> Option<u32> {
|
||||
"fini" => Some(999),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user