//! Global environment configuration aggregator (管理棟) //! //! Consolidates NYASH_* environment variables across subsystems and //! optionally applies overrides from `nyash.toml`. mod catalog; pub mod dump; pub mod stage1; pub use catalog::{env_vars, AppliesTo, EnvVarMeta}; pub use dump::*; pub use stage1::*; use std::collections::BTreeMap; #[derive(Debug, Clone, Default)] pub struct NyashEnv { // ARCHIVED: JIT-related configuration moved to archive/jit-cranelift/ during Phase 15 // pub jit: crate::jit::config::JitConfig, /// Arbitrary key-value overrides loaded from nyash.toml [env] pub overrides: BTreeMap, } impl NyashEnv { pub fn from_env() -> Self { Self { // ARCHIVED: JIT config during Phase 15 // jit: crate::jit::config::JitConfig::from_env(), overrides: BTreeMap::new(), } } /// Apply current struct values into process environment pub fn apply_env(&self) { // ARCHIVED: JIT config during Phase 15 // self.jit.apply_env(); for (k, v) in &self.overrides { std::env::set_var(k, v); } } } // Global current env config (thread-safe) use once_cell::sync::OnceCell; use std::collections::HashSet; use std::sync::Mutex; use std::sync::RwLock; static GLOBAL_ENV: OnceCell> = OnceCell::new(); static WARNED_ALIASES: OnceCell>> = OnceCell::new(); // フェーズM.2: PHI_ON_GATED_WARNED削除(phi-legacy簡略化により不要) pub fn current() -> NyashEnv { if let Some(lock) = GLOBAL_ENV.get() { if let Ok(cfg) = lock.read() { return cfg.clone(); } } NyashEnv::from_env() } pub fn set_current(cfg: NyashEnv) { if let Some(lock) = GLOBAL_ENV.get() { if let Ok(mut w) = lock.write() { *w = cfg; return; } } let _ = GLOBAL_ENV.set(RwLock::new(cfg)); } /// Load overrides from nyash.toml `[env]` table and apply them to process env. /// /// Example: /// [env] /// NYASH_JIT_THRESHOLD = "1" /// NYASH_CLI_VERBOSE = "1" pub fn bootstrap_from_toml_env() { // Allow disabling nyash.toml env bootstrapping for isolated smokes/CI if std::env::var("NYASH_SKIP_TOML_ENV").ok().as_deref() == Some("1") { return; } // Prefer hakorune.toml, fallback to nyash.toml let alt = if std::path::Path::new("hakorune.toml").exists() { "hakorune.toml" } else { "nyash.toml" }; let path = alt; let content = match std::fs::read_to_string(path) { Ok(s) => s, Err(_) => return, }; let Ok(value) = toml::from_str::(&content) else { return; }; let Some(env_tbl) = value.get("env").and_then(|v| v.as_table()) else { return; }; let mut overrides: BTreeMap = BTreeMap::new(); for (k, v) in env_tbl { if let Some(s) = v.as_str() { std::env::set_var(k, s); overrides.insert(k.clone(), s.to_string()); } else if let Some(b) = v.as_bool() { let sv = if b { "1" } else { "0" }; std::env::set_var(k, sv); overrides.insert(k.clone(), sv.to_string()); } else if let Some(n) = v.as_integer() { let sv = n.to_string(); std::env::set_var(k, &sv); overrides.insert(k.clone(), sv); } } // Merge into global let mut cur = current(); cur.overrides.extend(overrides); set_current(cur); } /// Get await maximum milliseconds, centralized here for consistency. pub fn await_max_ms() -> u64 { std::env::var("NYASH_AWAIT_MAX_MS") .ok() .and_then(|s| s.parse().ok()) .unwrap_or(5000) } // ---- MIR PHI / PHI-less (edge-copy) mode ---- /// Enable MIR PHI non-generation for Bridge compatibility mode only. /// フェーズM.2: MirBuilder/LoopBuilderでPHI統一済み、Bridge層の互換性制御のみ /// Default: PHI-ON (Phase 15 direction), override with NYASH_MIR_NO_PHI=1 pub fn mir_no_phi() -> bool { env_bool("NYASH_MIR_NO_PHI") } /// Allow verifier to skip SSA/dominance/merge checks for PHI-less MIR. pub fn verify_allow_no_phi() -> bool { std::env::var("NYASH_VERIFY_ALLOW_NO_PHI").ok().as_deref() == Some("1") || mir_no_phi() } /// Enable strict edge-copy policy verification in PHI-off mode. /// When enabled, merge blocks must receive merged values via predecessor copies only, /// and the merge block itself must not introduce a self-copy to the merged destination. pub fn verify_edge_copy_strict() -> bool { env_bool("NYASH_VERIFY_EDGE_COPY_STRICT") } /// Enforce purity of return blocks: no side-effecting instructions allowed before Return /// Default: OFF. Enable with NYASH_VERIFY_RET_PURITY=1 in dev/profiling sessions. pub fn verify_ret_purity() -> bool { env_bool("NYASH_VERIFY_RET_PURITY") } // ---- LLVM harness toggle (llvmlite) ---- pub fn llvm_use_harness() -> bool { // Phase 15: デフォルトON(LLVMバックエンドはPythonハーネス使用) // NYASH_LLVM_USE_HARNESS=0 で明示的に無効化可能 match std::env::var("NYASH_LLVM_USE_HARNESS").ok().as_deref() { Some("0") | Some("false") | Some("off") => false, _ => true, // デフォルト: ON(ハーネス使用) } } /// Generic boolean env parser: accepts 1/true/on (case-insensitive) as true. pub fn env_bool(key: &str) -> bool { match std::env::var(key).ok() { Some(v) => { let lv = v.to_ascii_lowercase(); lv == "1" || lv == "true" || lv == "on" } None => false, } } /// Generic boolean env parser with default when unset. pub fn env_bool_default(key: &str, default: bool) -> bool { match std::env::var(key).ok() { Some(v) => { let lv = v.to_ascii_lowercase(); lv == "1" || lv == "true" || lv == "on" } None => default, } } /// Global fail-fast policy for runtime fallbacks. /// Default: ON (true) to prohibit silent/different-route fallbacks in Rust layer. /// Set NYASH_FAIL_FAST=0 to temporarily allow legacy fallbacks during bring-up. pub fn fail_fast() -> bool { env_bool_default("NYASH_FAIL_FAST", true) } // ---- Phase 29/30 JoinIR toggles ---- /// JoinIR experiment mode. Required for JoinIR-related experimental paths. /// Set NYASH_JOINIR_EXPERIMENT=1 to enable. pub fn joinir_experiment_enabled() -> bool { env_bool("NYASH_JOINIR_EXPERIMENT") } /// JoinIR VM bridge mode. When enabled with NYASH_JOINIR_EXPERIMENT=1, /// specific functions can be executed via JoinIR → VM bridge instead of direct MIR → VM. /// Set NYASH_JOINIR_VM_BRIDGE=1 to enable. pub fn joinir_vm_bridge_enabled() -> bool { env_bool("NYASH_JOINIR_VM_BRIDGE") } /// JoinIR VM bridge debug output. Enables verbose logging of JoinIR→MIR conversion. /// Set NYASH_JOINIR_VM_BRIDGE_DEBUG=1 to enable. pub fn joinir_vm_bridge_debug() -> bool { env_bool("NYASH_JOINIR_VM_BRIDGE_DEBUG") } /// JoinIR LLVM experiment mode. When enabled with NYASH_JOINIR_EXPERIMENT=1, /// enables experimental JoinIR→MIR'→LLVM path for specific functions (e.g., Main.skip/1). /// This is a dev-only toggle for testing PHI normalization via JoinIR in the LLVM path. /// Set NYASH_JOINIR_LLVM_EXPERIMENT=1 to enable. pub fn joinir_llvm_experiment_enabled() -> bool { env_bool("NYASH_JOINIR_LLVM_EXPERIMENT") } /// Phase 33: JoinIR If Select 実験の有効化 /// Set NYASH_JOINIR_IF_SELECT=1 to enable experimental If/Else → Select lowering. pub fn joinir_if_select_enabled() -> bool { env_bool("NYASH_JOINIR_IF_SELECT") } // VM legacy by-name call fallback was removed (Phase 2 complete). // ---- Phase 11.8 MIR cleanup toggles ---- /// Core-13 minimal MIR mode toggle. Default ON unless NYASH_MIR_CORE13=0. pub fn mir_core13() -> bool { match std::env::var("NYASH_MIR_CORE13").ok() { Some(v) => { let lv = v.to_ascii_lowercase(); !(lv == "0" || lv == "false" || lv == "off") } None => true, } } pub fn mir_ref_boxcall() -> bool { std::env::var("NYASH_MIR_REF_BOXCALL").ok().as_deref() == Some("1") || mir_core13() } pub fn mir_array_boxcall() -> bool { std::env::var("NYASH_MIR_ARRAY_BOXCALL").ok().as_deref() == Some("1") || mir_core13() } pub fn mir_plugin_invoke() -> bool { std::env::var("NYASH_MIR_PLUGIN_INVOKE").ok().as_deref() == Some("1") } pub fn plugin_only() -> bool { std::env::var("NYASH_PLUGIN_ONLY").ok().as_deref() == Some("1") } /// Core-13 "pure" mode: only the 13 canonical ops are allowed (verifier rejects others). pub fn mir_core13_pure() -> bool { env_bool("NYASH_MIR_CORE13_PURE") } // ---- Optimizer diagnostics ---- pub fn opt_debug() -> bool { std::env::var("NYASH_OPT_DEBUG").is_ok() } pub fn opt_diag() -> bool { std::env::var("NYASH_OPT_DIAG").is_ok() } pub fn opt_diag_forbid_legacy() -> bool { std::env::var("NYASH_OPT_DIAG_FORBID_LEGACY").is_ok() } pub fn opt_diag_fail() -> bool { std::env::var("NYASH_OPT_DIAG_FAIL").is_ok() } // ---- Legacy compatibility (dev-only) ---- /// Enable legacy InstanceBox fields (SharedNyashBox map) for compatibility. /// Default: OFF. Set NYASH_LEGACY_FIELDS_ENABLE=1 to materialize and use legacy fields. pub fn legacy_fields_enable() -> bool { env_bool("NYASH_LEGACY_FIELDS_ENABLE") } // ---- GC/Runtime tracing (execution-affecting visibility) ---- pub fn gc_trace() -> bool { env_bool("NYASH_GC_TRACE") } pub fn gc_barrier_trace() -> bool { env_bool("NYASH_GC_BARRIER_TRACE") } pub fn runtime_checkpoint_trace() -> bool { env_bool("NYASH_RUNTIME_CHECKPOINT_TRACE") } pub fn gc_barrier_strict() -> bool { std::env::var("NYASH_GC_BARRIER_STRICT").ok().as_deref() == Some("1") } /// Return 0 (off) to 3 (max) for `NYASH_GC_TRACE`. pub fn gc_trace_level() -> u8 { match std::env::var("NYASH_GC_TRACE").ok().as_deref() { Some("1") => 1, Some("2") => 2, Some("3") => 3, Some(_) => 1, None => 0, } } // ---- GC mode and instrumentation ---- /// Return current GC mode string (auto default = "rc+cycle"). /// Allowed: "auto", "rc+cycle", "minorgen", "stw", "rc", "off" pub fn gc_mode() -> String { match std::env::var("NYASH_GC_MODE").ok() { Some(m) if !m.trim().is_empty() => m, _ => "rc+cycle".to_string(), } } /// Brief metrics emission (text) pub fn gc_metrics() -> bool { std::env::var("NYASH_GC_METRICS").ok().as_deref() == Some("1") } /// JSON metrics emission (single line) pub fn gc_metrics_json() -> bool { std::env::var("NYASH_GC_METRICS_JSON").ok().as_deref() == Some("1") } /// Optional allocation threshold; if Some(n) and exceeded, print warning pub fn gc_alloc_threshold() -> Option { std::env::var("NYASH_GC_ALLOC_THRESHOLD").ok()?.parse().ok() } // ---- Cleanup (method-level postfix) policy toggles ---- /// Allow `return` inside a cleanup block. Default: false (0) pub fn cleanup_allow_return() -> bool { match std::env::var("NYASH_CLEANUP_ALLOW_RETURN").ok() { Some(v) => { let lv = v.to_ascii_lowercase(); !(lv == "0" || lv == "false" || lv == "off") } None => false, } } /// Allow `throw` inside a cleanup block. Default: false (0) pub fn cleanup_allow_throw() -> bool { match std::env::var("NYASH_CLEANUP_ALLOW_THROW").ok() { Some(v) => { let lv = v.to_ascii_lowercase(); !(lv == "0" || lv == "false" || lv == "off") } None => false, } } /// Run a collection every N safepoints (if Some) pub fn gc_collect_sp_interval() -> Option { std::env::var("NYASH_GC_COLLECT_SP").ok()?.parse().ok() } /// Run a collection when allocated bytes since last >= N (if Some) pub fn gc_collect_alloc_bytes() -> Option { std::env::var("NYASH_GC_COLLECT_ALLOC").ok()?.parse().ok() } // ---- Rewriter flags (optimizer transforms) pub fn rewrite_debug() -> bool { std::env::var("NYASH_REWRITE_DEBUG").ok().as_deref() == Some("1") } pub fn rewrite_safepoint() -> bool { std::env::var("NYASH_REWRITE_SAFEPOINT").ok().as_deref() == Some("1") } pub fn rewrite_future() -> bool { std::env::var("NYASH_REWRITE_FUTURE").ok().as_deref() == Some("1") } // ---- Phase 12: Nyash ABI (vtable) toggles ---- pub fn abi_vtable() -> bool { std::env::var("NYASH_ABI_VTABLE").ok().as_deref() == Some("1") } /// ABI strict diagnostics: missing vtable methods become errors when enabled. pub fn abi_strict() -> bool { std::env::var("NYASH_ABI_STRICT").ok().as_deref() == Some("1") } // ---- Operator Boxes adopt defaults ---- /// CompareOperator.apply adopt: default ON (prod/devともに採用) pub fn operator_box_compare_adopt() -> bool { match std::env::var("NYASH_OPERATOR_BOX_COMPARE_ADOPT") .ok() .as_deref() .map(|v| v.to_ascii_lowercase()) { Some(ref s) if s == "0" || s == "false" || s == "off" => false, Some(ref s) if s == "1" || s == "true" || s == "on" => true, _ => true, // default ON } } /// AddOperator.apply adopt: default OFF(順次昇格のため) pub fn operator_box_add_adopt() -> bool { match std::env::var("NYASH_OPERATOR_BOX_ADD_ADOPT") .ok() .as_deref() .map(|v| v.to_ascii_lowercase()) { Some(ref s) if s == "0" || s == "false" || s == "off" => false, _ => true, // default ON (promoted after validation) } } // ---- Null/Missing Boxes (dev-only observe → adopt) ---- /// Enable NullBox/MissingBox observation path (no behavior change by default). /// Default: OFF. Turn ON with `NYASH_NULL_MISSING_BOX=1`. May be auto-enabled in --dev later. pub fn null_missing_box_enabled() -> bool { std::env::var("NYASH_NULL_MISSING_BOX").ok().as_deref() == Some("1") } /// Strict null policy for operators (when enabled): null in arithmetic/compare is an error. /// Default: OFF (null propagates). Effective only when `null_missing_box_enabled()` is true. pub fn null_strict() -> bool { std::env::var("NYASH_NULL_STRICT").ok().as_deref() == Some("1") } // ---- Phase 12: thresholds and routing policies ---- // ---- Runner/CLI common toggles (hot-path centralization) pub fn cli_verbose() -> bool { cli_verbose_level() > 0 } pub fn enable_using() -> bool { // Phase 15: デフォルトON(using systemはメイン機能) // NYASH_ENABLE_USING=0 で明示的に無効化可能。HAKO_ENABLE_USING は互換のため受理(警告)。 match std::env::var("NYASH_ENABLE_USING").ok().as_deref() { Some("0") | Some("false") | Some("off") => return false, Some(_) => return true, None => {} } // Fallback to alias if let Some(v) = std::env::var("HAKO_ENABLE_USING").ok() { warn_alias_once("HAKO_ENABLE_USING", "NYASH_ENABLE_USING"); let lv = v.to_ascii_lowercase(); return !(lv == "0" || lv == "false" || lv == "off"); } true // default ON } // ---- Using profiles (dev|ci|prod) ---- /// Return using profile string; default is "dev". pub fn using_profile() -> String { std::env::var("NYASH_USING_PROFILE").unwrap_or_else(|_| "dev".to_string()) } /// True when using profile is prod (disables some dev-only behaviors). pub fn using_is_prod() -> bool { using_profile().eq_ignore_ascii_case("prod") } /// True when using profile is ci. pub fn using_is_ci() -> bool { using_profile().eq_ignore_ascii_case("ci") } /// True when using profile is dev (default). pub fn using_is_dev() -> bool { using_profile().eq_ignore_ascii_case("dev") } /// Allow `using "path"` statements in source (dev-only by default). pub fn allow_using_file() -> bool { // SSOT 徹底: 全プロファイルで既定禁止(nyash.toml を唯一の真実に) // 明示オーバーライドでのみ許可(開発用緊急時) match std::env::var("NYASH_ALLOW_USING_FILE").ok().as_deref() { Some("1") | Some("true") | Some("on") => true, _ => false, } } /// Determine whether AST prelude merge for `using` is enabled. /// Precedence: /// 1) Explicit env `NYASH_USING_AST` = 1/true/on → enabled, = 0/false/off → disabled /// 2) Default by profile: dev/ci → ON, prod → OFF pub fn using_ast_enabled() -> bool { match std::env::var("NYASH_USING_AST") .ok() .as_deref() .map(|v| v.to_ascii_lowercase()) { Some(ref s) if s == "1" || s == "true" || s == "on" => true, Some(ref s) if s == "0" || s == "false" || s == "off" => false, _ => !using_is_prod(), // dev/ci → true, prod → false } } /// Policy: allow VM to fallback-dispatch user Instance BoxCall (dev only by default). /// - prod: default false (disallow) /// - dev/ci: default true (allow, with WARN) /// Override with NYASH_VM_USER_INSTANCE_BOXCALL={0|1} pub fn vm_allow_user_instance_boxcall() -> bool { match std::env::var("NYASH_VM_USER_INSTANCE_BOXCALL") .ok() .as_deref() .map(|v| v.to_ascii_lowercase()) { Some(ref s) if s == "0" || s == "false" || s == "off" => false, Some(ref s) if s == "1" || s == "true" || s == "on" => true, _ => !using_is_prod(), } } // Legacy resolve_fix_braces() removed (Phase 15 cleanup) // AST-based integration handles syntax properly without text-level brace fixing pub fn vm_use_py() -> bool { std::env::var("NYASH_VM_USE_PY").ok().as_deref() == Some("1") } pub fn pipe_use_pyvm() -> bool { std::env::var("NYASH_PIPE_USE_PYVM").ok().as_deref() == Some("1") } /// (Deprecated) use dispatch-based VM route; currently disabled. pub fn vm_use_dispatch() -> bool { false } /// Force VM fallback interpreter route (dev-only escape hatch). pub fn vm_use_fallback() -> bool { std::env::var("NYASH_VM_USE_FALLBACK").ok().as_deref() == Some("1") } /// Trace VM route selection decisions. pub fn vm_route_trace() -> bool { std::env::var("NYASH_VM_ROUTE_TRACE").ok().as_deref() == Some("1") } // Self-host compiler knobs pub fn ny_compiler_timeout_ms() -> u64 { std::env::var("NYASH_NY_COMPILER_TIMEOUT_MS") .ok() .and_then(|s| s.parse().ok()) .unwrap_or(2000) } /// Emit-only flag for selfhost compiler (default ON to avoid execution). pub fn ny_compiler_emit_only() -> bool { std::env::var("NYASH_NY_COMPILER_EMIT_ONLY").unwrap_or_else(|_| "1".to_string()) == "1" } /// Path to external selfhost compiler executable (when enabled). pub fn use_ny_compiler_exe() -> bool { std::env::var("NYASH_USE_NY_COMPILER_EXE").ok().as_deref() == Some("1") } /// Path to external selfhost compiler executable (when enabled). pub fn ny_compiler_exe_path() -> Option { std::env::var("NYASH_NY_COMPILER_EXE_PATH").ok() } /// Pass `-- --min-json` to child selfhost compiler (minimal JSON output). pub fn ny_compiler_min_json() -> bool { std::env::var("NYASH_NY_COMPILER_MIN_JSON").ok().as_deref() == Some("1") } /// When true, child reads tmp/ny_parser_input.ny instead of stdin/source text. pub fn selfhost_read_tmp() -> bool { std::env::var("NYASH_SELFHOST_READ_TMP").ok().as_deref() == Some("1") } /// Pass `-- --stage3` to child selfhost compiler to allow Stage-3 surface. pub fn ny_compiler_stage3() -> bool { std::env::var("NYASH_NY_COMPILER_STAGE3").ok().as_deref() == Some("1") } /// Core (Rust) parser Stage-3 gate /// When enabled, the Rust parser accepts Stage-3 surface (try/catch/finally, throw). /// Default is OFF to keep Stage-2 stable. pub fn parser_stage3() -> bool { if std::env::var("NYASH_PARSER_STAGE3").ok().as_deref() == Some("1") { return true; } if std::env::var("HAKO_PARSER_STAGE3").ok().as_deref() == Some("1") { warn_alias_once("HAKO_PARSER_STAGE3", "NYASH_PARSER_STAGE3"); return true; } false } /// Parser gate for Block‑Postfix Catch acceptance /// Enabled when either NYASH_BLOCK_CATCH=1 or Stage‑3 gate is on. /// Phase 15.5 allows parsing a standalone `{ ... }` block optionally followed by /// a single `catch (...) { ... }` and/or `finally { ... }`, which is folded into /// ASTNode::TryCatch with the preceding block as the try body. pub fn block_postfix_catch() -> bool { std::env::var("NYASH_BLOCK_CATCH").ok().as_deref() == Some("1") || parser_stage3() } /// Bridge lowering: use Result-style try/throw lowering instead of MIR Catch/Throw /// When on, try/catch is lowered using structured blocks and direct jumps, /// without emitting MIR Throw/Catch. The thrown value is routed to catch via /// block parameters (PHI-off uses edge-copy). pub fn try_result_mode() -> bool { std::env::var("NYASH_TRY_RESULT_MODE").ok().as_deref() == Some("1") } /// Parser gate for method-level postfix catch/finally acceptance on method definitions. /// Enabled when either NYASH_METHOD_CATCH=1 or Stage‑3 gate is on. pub fn method_catch() -> bool { std::env::var("NYASH_METHOD_CATCH").ok().as_deref() == Some("1") || parser_stage3() } /// Entry policy: allow top-level `main` resolution in addition to `Main.main`. /// Default: true (prefer `Main.main` when both exist; otherwise accept `main`). pub fn entry_allow_toplevel_main() -> bool { match std::env::var("NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN").ok() { Some(v) => { let v = v.to_ascii_lowercase(); v == "1" || v == "true" || v == "on" } None => true, } } /// Parser gate for expression-level postfix catch/cleanup acceptance. /// Enabled when Stage-3 gate is on (NYASH_PARSER_STAGE3=1). Separate gate can /// be introduced in future if needed, but we keep minimal toggles now. pub fn expr_postfix_catch() -> bool { parser_stage3() } /// Parser gate for Unified Members (stored/computed/once/birth_once). /// Default: ON during Phase-15 (set NYASH_ENABLE_UNIFIED_MEMBERS=0|false|off to disable). pub fn unified_members() -> bool { match std::env::var("NYASH_ENABLE_UNIFIED_MEMBERS").ok() { Some(v) => { let lv = v.to_ascii_lowercase(); !(lv == "0" || lv == "false" || lv == "off") } None => true, } } pub fn ny_compiler_child_args() -> Option { // Pass-through args to selfhost child (space-separated). std::env::var("NYASH_NY_COMPILER_CHILD_ARGS").ok() } pub fn ny_compiler_use_tmp_only() -> bool { std::env::var("NYASH_NY_COMPILER_USE_TMP_ONLY") .ok() .as_deref() == Some("1") } /// Use Python MVP harness for Ny compiler (NYASH_NY_COMPILER_USE_PY=1). pub fn ny_compiler_use_py() -> bool { std::env::var("NYASH_NY_COMPILER_USE_PY") .ok() .as_deref() == Some("1") } /// Macro pre-expand mode for selfhost (NYASH_MACRO_SELFHOST_PRE_EXPAND). /// Returns "1", "auto", or None. pub fn macro_selfhost_pre_expand() -> Option { std::env::var("NYASH_MACRO_SELFHOST_PRE_EXPAND").ok() } /// ScopeBox enable flag (NYASH_SCOPEBOX_ENABLE=1). pub fn scopebox_enable() -> bool { std::env::var("NYASH_SCOPEBOX_ENABLE") .ok() .as_deref() == Some("1") } /// LoopForm normalize flag (NYASH_LOOPFORM_NORMALIZE=1). pub fn loopform_normalize() -> bool { std::env::var("NYASH_LOOPFORM_NORMALIZE") .ok() .as_deref() == Some("1") } /// Dev-only escape hatch: force inline selfhost path (NYASH_SELFHOST_INLINE_FORCE=1). pub fn selfhost_inline_force() -> bool { std::env::var("NYASH_SELFHOST_INLINE_FORCE") .ok() .as_deref() == Some("1") } /// Unicode decode toggle for string literals (\uXXXX, optional surrogate pairs). /// Enabled when either HAKO_PARSER_DECODE_UNICODE=1 or NYASH_PARSER_DECODE_UNICODE=1. /// Default: OFF (for strict backward compatibility). pub fn parser_decode_unicode() -> bool { env_flag("HAKO_PARSER_DECODE_UNICODE") .or_else(|| env_flag("NYASH_PARSER_DECODE_UNICODE")) .unwrap_or(false) } fn env_flag(var: &str) -> Option { std::env::var(var).ok().map(|v| { let lv = v.to_ascii_lowercase(); lv == "1" || lv == "true" || lv == "on" }) } pub fn nyvm_core_wrapper() -> bool { env_flag("HAKO_NYVM_CORE") .or_else(|| env_flag("NYASH_NYVM_CORE")) .unwrap_or(false) } pub fn nyvm_bridge_inject_singleton() -> bool { env_flag("HAKO_BRIDGE_INJECT_SINGLETON") .or_else(|| env_flag("NYASH_BRIDGE_INJECT_SINGLETON")) .unwrap_or(false) } pub fn nyvm_bridge_early_phi_materialize() -> bool { env_flag("HAKO_BRIDGE_EARLY_PHI_MATERIALIZE") .or_else(|| env_flag("NYASH_BRIDGE_EARLY_PHI_MATERIALIZE")) .unwrap_or(false) } pub fn nyvm_v1_downconvert() -> bool { env_flag("HAKO_NYVM_V1_DOWNCONVERT") .or_else(|| env_flag("NYASH_NYVM_V1_DOWNCONVERT")) .unwrap_or(false) } /// Gate‑C(Core) strict OOB handling: when enabled, any observed OOB tag /// (emitted by runtime during ArrayBox get/set with HAKO_OOB_STRICT=1) should /// cause non‑zero exit at the end of JSON→VM execution. pub fn oob_strict_fail() -> bool { env_flag("HAKO_OOB_STRICT_FAIL") .or_else(|| env_flag("NYASH_OOB_STRICT_FAIL")) .unwrap_or(false) } /// Primary verification route: return true when Hakorune VM is requested as primary. /// Accepts HAKO_VERIFY_PRIMARY=hakovm (preferred) or legacy HAKO_ROUTE_HAKOVM=1 (deprecated, warns). pub fn verify_primary_is_hakovm() -> bool { if std::env::var("HAKO_VERIFY_PRIMARY").ok().as_deref() == Some("hakovm") { return true; } if env_bool("HAKO_ROUTE_HAKOVM") { warn_alias_once("HAKO_ROUTE_HAKOVM", "HAKO_VERIFY_PRIMARY=hakovm"); return true; } false } pub(crate) fn warn_alias_once(alias: &str, primary: &str) { let set = WARNED_ALIASES.get_or_init(|| Mutex::new(HashSet::new())); if let Ok(mut s) = set.lock() { if !s.contains(alias) { eprintln!( "[deprecate/env] '{}' is deprecated; use '{}'", alias, primary ); s.insert(alias.to_string()); } } } // ---- ENV consolidation helpers (Phase 21.10/22.1) ---- /// LLVM opt level (primary: NYASH_LLVM_OPT_LEVEL; alias: HAKO_LLVM_OPT_LEVEL) /// Returns string level (e.g., "0", "1", ...). Default: "0" when unset. pub fn llvm_opt_level() -> String { if let Some(v) = std::env::var("NYASH_LLVM_OPT_LEVEL").ok() { return v; } if let Some(v) = std::env::var("HAKO_LLVM_OPT_LEVEL").ok() { warn_alias_once("HAKO_LLVM_OPT_LEVEL", "NYASH_LLVM_OPT_LEVEL"); return v; } "0".to_string() } /// Gate‑C(Core) route request (primary: NYASH_GATE_C_CORE; alias: HAKO_GATE_C_CORE) pub fn gate_c_core() -> bool { if env_bool("NYASH_GATE_C_CORE") { return true; } if env_bool("HAKO_GATE_C_CORE") { warn_alias_once("HAKO_GATE_C_CORE", "NYASH_GATE_C_CORE"); return true; } false } /// Consolidated toggle for selfhost NY compiler pipeline. /// Primary: NYASH_USE_NY_COMPILER=0|1(明示指定のみ有効)。Legacy disables accepted (with warning): /// NYASH_DISABLE_NY_COMPILER/HAKO_DISABLE_NY_COMPILER (any true value disables). pub fn use_ny_compiler() -> bool { // Primary knob takes precedence when explicitly set if let Some(v) = std::env::var("NYASH_USE_NY_COMPILER").ok() { let lv = v.trim().to_ascii_lowercase(); return lv == "1" || lv == "true" || lv == "on"; } // Legacy disable aliases — if any is true, treat as disabled and warn if env_bool("NYASH_DISABLE_NY_COMPILER") { warn_alias_once("NYASH_DISABLE_NY_COMPILER", "NYASH_USE_NY_COMPILER=0"); return false; } if env_bool("HAKO_DISABLE_NY_COMPILER") { warn_alias_once("HAKO_DISABLE_NY_COMPILER", "NYASH_USE_NY_COMPILER=0"); return false; } // Phase 25.1b: Default OFF(selfhost NY compiler は明示 opt-in のみ) false }