diff --git a/src/runner/modes/common_util/entry_selection.rs b/src/runner/modes/common_util/entry_selection.rs new file mode 100644 index 00000000..913cd165 --- /dev/null +++ b/src/runner/modes/common_util/entry_selection.rs @@ -0,0 +1,37 @@ +/*! + * Entry function selection logic (Main.main → main fallback) + * + * NamingBox SSOT: Centralized entry point resolution with arity-aware fallback + */ + +/// Select entry function for execution (Main.main → main fallback with env control) +/// +/// Resolution order (NamingBox SSOT): +/// 1. Main.main/0 (arity-aware, future-proof for NYASH_BUILD_STATIC_MAIN_ENTRY=1) +/// 2. Main.main (legacy, arity-less, current default) +/// 3. main (top-level, only if NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1) +/// 4. "Main.main" (default fallback, caller handles missing function error) +pub fn select_entry_function(module: &crate::mir::MirModule) -> String { + use crate::config::env; + + // NamingBox SSOT: Try arity-aware names first (future-proof) + // Currently "Main.main" without arity is used by default (NYASH_BUILD_STATIC_MAIN_ENTRY=0) + let main_with_arity = crate::mir::naming::encode_static_method("Main", "main", 0); + if module.functions.contains_key(&main_with_arity) { + return main_with_arity; + } + + // Legacy: arity-less "Main.main" (current default) + if module.functions.contains_key("Main.main") { + return "Main.main".to_string(); + } + + // Fallback to top-level "main" if allowed + let allow_top = env::entry_allow_toplevel_main(); + if allow_top && module.functions.contains_key("main") { + return "main".to_string(); + } + + // Default: "Main.main" (may not exist, but caller will handle error) + "Main.main".to_string() +} diff --git a/src/runner/modes/common_util/mod.rs b/src/runner/modes/common_util/mod.rs index bc6355c9..c772a6b7 100644 --- a/src/runner/modes/common_util/mod.rs +++ b/src/runner/modes/common_util/mod.rs @@ -6,6 +6,7 @@ pub mod core_bridge; pub mod diag; +pub mod entry_selection; pub mod exec; pub mod hako; pub mod io; diff --git a/src/runner/modes/common_util/pyvm.rs b/src/runner/modes/common_util/pyvm.rs index 97079ca5..978b97f9 100644 --- a/src/runner/modes/common_util/pyvm.rs +++ b/src/runner/modes/common_util/pyvm.rs @@ -29,18 +29,8 @@ pub fn run_pyvm_harness(module: &crate::mir::MirModule, tag: &str) -> Result Result R tag, mir_json_path.display() ); - // Determine entry function (prefer Main.main; top-level main only if allowed) - let allow_top = crate::config::env::entry_allow_toplevel_main(); - let entry = if module.functions.contains_key("Main.main") { - "Main.main" - } else if allow_top && module.functions.contains_key("main") { - "main" - } else if module.functions.contains_key("main") { - eprintln!("[entry] Warning: using top-level 'main' without explicit allow; set NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 to silence."); - "main" - } else { - "Main.main" - }; + // NamingBox SSOT: Select entry (arity-aware, Main.main → main fallback) + let entry = super::entry_selection::select_entry_function(&module); let mut cmd = std::process::Command::new(py3); crate::runner::child_env::apply_core_wrapper_env(&mut cmd); if std::env::var("NYASH_MINIVM_READ_STDIN").ok().as_deref() == Some("1") { @@ -126,7 +106,7 @@ pub fn run_pyvm_harness_lib(module: &nyash_rust::mir::MirModule, tag: &str) -> R "--in", &mir_json_path.display().to_string(), "--entry", - entry, + &entry, "--args-env", "NYASH_SCRIPT_ARGS_JSON", ]) diff --git a/src/runner/modes/common_util/selfhost/json.rs b/src/runner/modes/common_util/selfhost/json.rs index f90dabd1..27788aa6 100644 --- a/src/runner/modes/common_util/selfhost/json.rs +++ b/src/runner/modes/common_util/selfhost/json.rs @@ -45,18 +45,8 @@ pub fn run_pyvm_module(module: &MirModule, label: &str) -> Option { mir_json_path.display() ); } - // Select entry (prefer Main.main; top-level main only if allowed) - let allow_top = crate::config::env::entry_allow_toplevel_main(); - let entry = if module.functions.contains_key("Main.main") { - "Main.main" - } else if allow_top && module.functions.contains_key("main") { - "main" - } else if module.functions.contains_key("main") { - eprintln!("[entry] Warning: using top-level 'main' without explicit allow; set NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 to silence."); - "main" - } else { - "Main.main" - }; + // NamingBox SSOT: Select entry (arity-aware, Main.main → main fallback) + let entry = super::super::entry_selection::select_entry_function(&module); let mut cmd = std::process::Command::new(py3); crate::runner::child_env::apply_core_wrapper_env(&mut cmd); let status = cmd @@ -65,7 +55,7 @@ pub fn run_pyvm_module(module: &MirModule, label: &str) -> Option { "--in", &mir_json_path.display().to_string(), "--entry", - entry, + &entry, ]) .status() .map_err(|e| format!("spawn pyvm: {}", e)) diff --git a/src/runner/modes/llvm.rs b/src/runner/modes/llvm.rs index a53675cc..63736973 100644 --- a/src/runner/modes/llvm.rs +++ b/src/runner/modes/llvm.rs @@ -289,7 +289,9 @@ impl NyashRunner { { println!("🔧 Mock LLVM Backend Execution:"); println!(" Build with --features llvm-inkwell-legacy for Rust/inkwell backend, or set NYASH_LLVM_OBJ_OUT and NYASH_LLVM_USE_HARNESS=1 for harness."); - if let Some(main_func) = module.functions.get("Main.main") { + // NamingBox SSOT: Select entry (arity-aware, Main.main → main fallback) + let entry = crate::runner::modes::common_util::entry_selection::select_entry_function(&module); + if let Some(main_func) = module.functions.get(&entry) { for (_bid, block) in &main_func.blocks { for inst in &block.instructions { match inst {