Files
hakorune/src/runner/mod.rs

451 lines
18 KiB
Rust
Raw Normal View History

/*!
* Execution Runner Module - Nyash File and Mode Execution Coordinator
*
* This module handles all execution logic, backend selection, and mode coordination,
* separated from CLI parsing and the main entry point.
*/
use nyash_rust::cli::CliConfig;
// prune heavy unused imports here; modules import what they need locally
// pruned unused runtime imports in this module
#[cfg(feature = "wasm-backend")]
use nyash_rust::backend::{aot::AotBackend, wasm::WasmBackend};
#[cfg(feature = "llvm-inkwell-legacy")]
use nyash_rust::backend::llvm_compile_and_execute;
use std::{fs, process};
mod box_index;
mod build;
pub(crate) mod child_env;
mod cli_directives;
mod demos;
mod dispatch;
pub mod json_v0_bridge;
mod json_v1_bridge;
pub mod mir_json {
pub mod common;
}
pub mod core_executor;
pub mod hv1_inline;
pub mod mir_json_emit;
mod mir_json_v0;
pub mod modes;
mod pipe_io;
mod pipeline;
mod plugins;
mod selfhost;
mod stage1_bridge;
mod tasks;
mod trace;
// v2 plugin system imports
use nyash_rust::runner_plugin_init;
use nyash_rust::runtime;
// use std::path::PathBuf; // not used in current runner
/// Resolve a using target according to priority: modules > relative > using-paths
/// Returns Ok(resolved_path_or_token). On strict mode, ambiguous matches cause error.
// use pipeline::resolve_using_target; // resolved within helpers; avoid unused warning
/// Main execution coordinator
pub struct NyashRunner {
config: CliConfig,
}
/// 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"))]
impl NyashRunner {
/// Create a new runner with the given configuration
pub fn new(config: CliConfig) -> Self {
Self { config }
}
/// Run Nyash based on the configuration
pub fn run(&self) {
// New behavior-preserving delegator
self.run_refactored();
}
// init_bid_plugins moved to runner_plugin_init.rs
/// Execute file-based mode with backend selection
pub(crate) fn run_file(&self, filename: &str) {
dispatch::execute_file_with_backend(self, filename);
}
/// 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)
}
}
#[cfg(not(feature = "jit-direct-only"))]
impl NyashRunner {
/// New behavior-preserving refactor of run(): structured into smaller helpers
fn run_refactored(&self) {
// Early: macro child
if let Some(ref macro_file) = self.config.macro_expand_child {
crate::runner::modes::macro_child::run_macro_child(macro_file);
return;
}
let groups = self.config.as_groups();
let skip_stage1_stub = groups.emit.hako_emit_program_json || groups.emit.hako_emit_mir_json;
if !skip_stage1_stub {
if let Some(code) = self.maybe_run_stage1_cli_stub(&groups) {
std::process::exit(code);
}
}
// Early: direct MIR JSON execution (no source file). Experimental diagnostics/exec.
if let Some(path) = groups.parser.mir_json_file.as_ref() {
match std::fs::read_to_string(path) {
Ok(text) => match crate::runner::json_v1_bridge::try_parse_v1_to_module(&text) {
Ok(Some(module)) => {
let rc = self.execute_mir_module_quiet_exit(&module);
std::process::exit(rc);
}
Ok(None) => {
if text.contains("\"functions\"") && text.contains("\"blocks\"") {
match crate::runner::mir_json_v0::parse_mir_v0_to_module(&text) {
Ok(module) => {
let rc = self.execute_mir_module_quiet_exit(&module);
std::process::exit(rc);
}
Err(e) => {
eprintln!("❌ MIR JSON v0 parse error: {}", e);
std::process::exit(1);
}
}
} else {
eprintln!("❌ MIR JSON invalid or unsupported shape: {}", path);
std::process::exit(1);
}
}
Err(e) => {
eprintln!("❌ MIR JSON parse error (v1): {}", e);
std::process::exit(1);
}
},
Err(e) => {
eprintln!("❌ Error reading MIR JSON {}: {}", path, e);
std::process::exit(1);
}
}
}
// Early: build
if let Some(cfg_path) = groups.build.path.clone() {
if let Err(e) = self.run_build_mvp(&cfg_path) {
eprintln!("❌ build error: {}", e);
std::process::exit(1);
}
return;
}
// Emit Program(JSON v0) and exit
if let Some(path) = groups.emit.emit_program_json.as_ref() {
// Prefer Stage-1/.hako route when requested via hako-* flags or env
let use_hako = groups.emit.hako_emit_program_json
|| crate::config::env::stage1::emit_program_json()
|| crate::config::env::stage1::enabled();
if use_hako {
if let Err(e) = self.emit_program_json_v0(&groups, path) {
eprintln!("❌ emit-program-json error: {}", e);
std::process::exit(1);
} else {
println!("Program JSON written: {}", path);
std::process::exit(0);
}
} else if let Some(file) = groups.input.file.as_ref() {
match std::fs::read_to_string(file) {
Ok(code) => match crate::parser::NyashParser::parse_from_string(&code) {
Ok(ast) => {
let prog = crate::r#macro::ast_json::ast_to_json(&ast);
let out_path = std::path::Path::new(path);
if let Err(e) = std::fs::write(out_path, prog.to_string()) {
eprintln!("❌ emit-program-json write error: {}", e);
std::process::exit(1);
}
println!("Program JSON written: {}", out_path.display());
std::process::exit(0);
}
Err(e) => {
crate::runner::modes::common_util::diag::print_parse_error_with_context(
file, &code, &e,
);
std::process::exit(1);
}
},
Err(e) => {
eprintln!("❌ Error reading file {}: {}", file, e);
std::process::exit(1);
}
}
} else {
eprintln!("❌ --emit-program-json requires an input file");
std::process::exit(1);
}
}
// Preprocess usings and directives (includes dep-tree log)
self.preprocess_usings_and_directives(&groups);
// JSON v0 bridge
if self.try_run_json_v0_pipe() {
return;
}
// Named task
if let Some(task) = groups.run_task.clone() {
if let Err(e) = run_named_task(&task) {
eprintln!("❌ Task error: {}", e);
process::exit(1);
}
return;
}
// Common env + runtime/plugins
self.apply_common_env(&groups);
self.init_runtime_and_plugins(&groups);
// Backend config + policy
self.configure_backend(&groups);
self.enforce_runtime_jit_policy(&groups);
// Benchmark
if self.maybe_run_benchmark(&groups) {
return;
}
// Dispatch
Phase 21.2 Complete: VM Adapter正規実装 + devブリッジ完全撤去 ## 🎉 Phase 21.2完全達成 ### ✅ 実装完了 - VM static box 永続化(singleton infrastructure) - devブリッジ完全撤去(adapter_dev.rs削除、by-name dispatch削除) - .hako正規実装(MirCallV1Handler, AbiAdapterRegistry等) - text-merge経路完全動作 - 全phase2120 adapter reps PASS(7テスト) ### 🐛 バグ修正 1. strip_local_decl修正 - トップレベルのみlocal削除、メソッド内は保持 - src/runner/modes/common_util/hako.rs:29 2. static box フィールド永続化 - MirInterpreter singleton storage実装 - me parameter binding修正(1:1マッピング) - getField/setField string→singleton解決 - src/backend/mir_interpreter/{mod,exec,handlers/boxes_object_fields}.rs 3. Map.len alias rc=0修正 - [map/missing]パターン検出でnull扱い(4箇所) - lang/src/vm/boxes/mir_call_v1_handler.hako:91-93,131-133,151-153,199-201 ### 📁 主要変更ファイル #### Rust(VM Runtime) - src/backend/mir_interpreter/mod.rs - static box singleton storage - src/backend/mir_interpreter/exec.rs - parameter binding fix - src/backend/mir_interpreter/handlers/boxes_object_fields.rs - singleton resolution - src/backend/mir_interpreter/handlers/calls.rs - dev bridge removal - src/backend/mir_interpreter/utils/mod.rs - adapter_dev module removal - src/backend/mir_interpreter/utils/adapter_dev.rs - DELETED (7555 bytes) - src/runner/modes/vm.rs - static box declaration collection - src/runner/modes/common_util/hako.rs - strip_local_decl fix - src/instance_v2.rs - Clone implementation #### Hako (.hako実装) - lang/src/vm/boxes/mir_call_v1_handler.hako - [map/missing] detection - lang/src/vm/boxes/abi_adapter_registry.hako - NEW (adapter registry) - lang/src/vm/helpers/method_alias_policy.hako - method alias support #### テスト - tools/smokes/v2/profiles/quick/core/phase2120/s3_vm_adapter_*.sh - 7 new tests ### 🎯 テスト結果 ``` ✅ s3_vm_adapter_array_len_canary_vm.sh ✅ s3_vm_adapter_array_len_per_recv_canary_vm.sh ✅ s3_vm_adapter_array_length_alias_canary_vm.sh ✅ s3_vm_adapter_array_size_alias_canary_vm.sh ✅ s3_vm_adapter_map_len_alias_state_canary_vm.sh ✅ s3_vm_adapter_map_length_alias_state_canary_vm.sh ✅ s3_vm_adapter_map_size_struct_canary_vm.sh ``` 環境フラグ: HAKO_ABI_ADAPTER=1 HAKO_ABI_ADAPTER_DEV=0 ### 🏆 設計品質 - ✅ ハードコード禁止(AGENTS.md 5.1)完全準拠 - ✅ 構造的・一般化設計(特定Box名のif分岐なし) - ✅ 後方互換性保持(既存コード破壊ゼロ) - ✅ text-merge経路(.hako依存関係正しくマージ) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 19:32:44 +09:00
if std::env::var("NYASH_VM_ROUTE_TRACE").ok().as_deref() == Some("1") {
let backend = &groups.backend.backend;
let file = groups.input.file.as_deref().unwrap_or("<none>");
eprintln!("[vm-route] pre-dispatch backend={} file={}", backend, file);
}
self.dispatch_entry(&groups);
}
// ---- Helpers (extracted from original run) ----
fn preprocess_usings_and_directives(&self, groups: &crate::cli::CliGroups) {
use pipeline::resolve_using_target;
// Initialize UsingContext (defaults + nyash.toml + env)
let mut using_ctx = self.init_using_context();
// Collect CLI --using SPEC into (target, alias)
📚 docs: Record field declaration design discussion in papers ## Summary Documented the "init block vs fields-at-top" design discussion as a valuable example of AI-human collaboration in language design. ## Changes ### Paper G (AI Collaboration) - Added field-declaration-design.md documenting the entire discussion flow - Showcased how complex init block proposal evolved to simple "fields at top" rule - Demonstrates AI's tendency toward complexity vs human intuition for simplicity ### Paper H (AI Practical Patterns) - Added Pattern #17: "Gradual Refinement Pattern" (段階的洗練型) - Documents the process: Complex AI proposal → Detailed analysis → Human insight → Convergence - Field declaration design as a typical example ### Paper K (Explosive Incidents) - Added Incident #046: "init block vs fields-at-top incident" - Updated total count to 46 incidents - Shows how a single human comment redirected entire design approach ## Design Decision After analysis, decided that BoxIndex should remain a compiler-internal structure, not a core Box: - Core Boxes: User-instantiable runtime values (String, Integer, Array, Map) - Compiler internals: BoxIndex for name resolution (compile-time only) - Clear separation of concerns between language features and compiler tools ## Philosophy This discussion exemplifies key principles: - The best design needs no explanation - Constraints provide clarity, not limitation - "Everything is Box" doesn't mean "compiler internals are Boxes" - AI tends toward theoretical completeness; humans toward practical simplicity 🐱 Sometimes the simplest answer is right in front of us\!
2025-09-16 14:57:05 +09:00
let mut pending_using: Vec<(String, Option<String>)> = Vec::new();
for spec in &groups.input.cli_usings {
📚 docs: Record field declaration design discussion in papers ## Summary Documented the "init block vs fields-at-top" design discussion as a valuable example of AI-human collaboration in language design. ## Changes ### Paper G (AI Collaboration) - Added field-declaration-design.md documenting the entire discussion flow - Showcased how complex init block proposal evolved to simple "fields at top" rule - Demonstrates AI's tendency toward complexity vs human intuition for simplicity ### Paper H (AI Practical Patterns) - Added Pattern #17: "Gradual Refinement Pattern" (段階的洗練型) - Documents the process: Complex AI proposal → Detailed analysis → Human insight → Convergence - Field declaration design as a typical example ### Paper K (Explosive Incidents) - Added Incident #046: "init block vs fields-at-top incident" - Updated total count to 46 incidents - Shows how a single human comment redirected entire design approach ## Design Decision After analysis, decided that BoxIndex should remain a compiler-internal structure, not a core Box: - Core Boxes: User-instantiable runtime values (String, Integer, Array, Map) - Compiler internals: BoxIndex for name resolution (compile-time only) - Clear separation of concerns between language features and compiler tools ## Philosophy This discussion exemplifies key principles: - The best design needs no explanation - Constraints provide clarity, not limitation - "Everything is Box" doesn't mean "compiler internals are Boxes" - AI tends toward theoretical completeness; humans toward practical simplicity 🐱 Sometimes the simplest answer is right in front of us\!
2025-09-16 14:57:05 +09:00
let s = spec.trim();
if s.is_empty() {
continue;
}
📚 docs: Record field declaration design discussion in papers ## Summary Documented the "init block vs fields-at-top" design discussion as a valuable example of AI-human collaboration in language design. ## Changes ### Paper G (AI Collaboration) - Added field-declaration-design.md documenting the entire discussion flow - Showcased how complex init block proposal evolved to simple "fields at top" rule - Demonstrates AI's tendency toward complexity vs human intuition for simplicity ### Paper H (AI Practical Patterns) - Added Pattern #17: "Gradual Refinement Pattern" (段階的洗練型) - Documents the process: Complex AI proposal → Detailed analysis → Human insight → Convergence - Field declaration design as a typical example ### Paper K (Explosive Incidents) - Added Incident #046: "init block vs fields-at-top incident" - Updated total count to 46 incidents - Shows how a single human comment redirected entire design approach ## Design Decision After analysis, decided that BoxIndex should remain a compiler-internal structure, not a core Box: - Core Boxes: User-instantiable runtime values (String, Integer, Array, Map) - Compiler internals: BoxIndex for name resolution (compile-time only) - Clear separation of concerns between language features and compiler tools ## Philosophy This discussion exemplifies key principles: - The best design needs no explanation - Constraints provide clarity, not limitation - "Everything is Box" doesn't mean "compiler internals are Boxes" - AI tends toward theoretical completeness; humans toward practical simplicity 🐱 Sometimes the simplest answer is right in front of us\!
2025-09-16 14:57:05 +09:00
let (target, alias) = if let Some(pos) = s.find(" as ") {
(
s[..pos].trim().to_string(),
Some(s[pos + 4..].trim().to_string()),
)
} else {
(s.to_string(), None)
};
let is_path = crate::runner::modes::common_util::resolve::path_util::is_using_target_path_original(&target);
📚 docs: Record field declaration design discussion in papers ## Summary Documented the "init block vs fields-at-top" design discussion as a valuable example of AI-human collaboration in language design. ## Changes ### Paper G (AI Collaboration) - Added field-declaration-design.md documenting the entire discussion flow - Showcased how complex init block proposal evolved to simple "fields at top" rule - Demonstrates AI's tendency toward complexity vs human intuition for simplicity ### Paper H (AI Practical Patterns) - Added Pattern #17: "Gradual Refinement Pattern" (段階的洗練型) - Documents the process: Complex AI proposal → Detailed analysis → Human insight → Convergence - Field declaration design as a typical example ### Paper K (Explosive Incidents) - Added Incident #046: "init block vs fields-at-top incident" - Updated total count to 46 incidents - Shows how a single human comment redirected entire design approach ## Design Decision After analysis, decided that BoxIndex should remain a compiler-internal structure, not a core Box: - Core Boxes: User-instantiable runtime values (String, Integer, Array, Map) - Compiler internals: BoxIndex for name resolution (compile-time only) - Clear separation of concerns between language features and compiler tools ## Philosophy This discussion exemplifies key principles: - The best design needs no explanation - Constraints provide clarity, not limitation - "Everything is Box" doesn't mean "compiler internals are Boxes" - AI tends toward theoretical completeness; humans toward practical simplicity 🐱 Sometimes the simplest answer is right in front of us\!
2025-09-16 14:57:05 +09:00
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()
📚 docs: Record field declaration design discussion in papers ## Summary Documented the "init block vs fields-at-top" design discussion as a valuable example of AI-human collaboration in language design. ## Changes ### Paper G (AI Collaboration) - Added field-declaration-design.md documenting the entire discussion flow - Showcased how complex init block proposal evolved to simple "fields at top" rule - Demonstrates AI's tendency toward complexity vs human intuition for simplicity ### Paper H (AI Practical Patterns) - Added Pattern #17: "Gradual Refinement Pattern" (段階的洗練型) - Documents the process: Complex AI proposal → Detailed analysis → Human insight → Convergence - Field declaration design as a typical example ### Paper K (Explosive Incidents) - Added Incident #046: "init block vs fields-at-top incident" - Updated total count to 46 incidents - Shows how a single human comment redirected entire design approach ## Design Decision After analysis, decided that BoxIndex should remain a compiler-internal structure, not a core Box: - Core Boxes: User-instantiable runtime values (String, Integer, Array, Map) - Compiler internals: BoxIndex for name resolution (compile-time only) - Clear separation of concerns between language features and compiler tools ## Philosophy This discussion exemplifies key principles: - The best design needs no explanation - Constraints provide clarity, not limitation - "Everything is Box" doesn't mean "compiler internals are Boxes" - AI tends toward theoretical completeness; humans toward practical simplicity 🐱 Sometimes the simplest answer is right in front of us\!
2025-09-16 14:57:05 +09:00
});
pending_using.push((name, Some(path)));
} else {
pending_using.push((target, alias));
}
}
// Apply pending modules (from context) to registry as StringBox
for (ns, path) in using_ctx.pending_modules.iter() {
let sb = crate::box_trait::StringBox::new(path.clone());
crate::runtime::modules_registry::set(ns.clone(), Box::new(sb));
}
// Optional dependency tree bridge (log-only)
if let Ok(dep_path) = std::env::var("NYASH_DEPS_JSON") {
match std::fs::read_to_string(&dep_path) {
Ok(s) => {
let bytes = s.as_bytes().len();
let mut root_info = String::new();
if let Ok(v) = serde_json::from_str::<serde_json::Value>(&s) {
if let Some(r) = v.get("root_path").and_then(|x| x.as_str()) {
root_info = format!(" root='{}'", r);
}
}
crate::cli_v!(
"[deps] loaded {} bytes from{} {}",
bytes,
if root_info.is_empty() { "" } else { ":" },
root_info
);
}
Err(e) => {
crate::cli_v!("[deps] read error: {}", e);
}
}
}
// If a file is provided, apply script-level directives and late using/env merges
if let Some(ref filename) = groups.input.file {
if let Ok(code) = fs::read_to_string(filename) {
// Apply directives and lint
let strict_fields =
std::env::var("NYASH_FIELDS_TOP_STRICT").ok().as_deref() == Some("1");
if let Err(e) = cli_directives::apply_cli_directives_from_source(
&code,
strict_fields,
groups.debug.cli_verbose,
) {
eprintln!("❌ Lint/Directive error: {}", e);
📚 docs: Record field declaration design discussion in papers ## Summary Documented the "init block vs fields-at-top" design discussion as a valuable example of AI-human collaboration in language design. ## Changes ### Paper G (AI Collaboration) - Added field-declaration-design.md documenting the entire discussion flow - Showcased how complex init block proposal evolved to simple "fields at top" rule - Demonstrates AI's tendency toward complexity vs human intuition for simplicity ### Paper H (AI Practical Patterns) - Added Pattern #17: "Gradual Refinement Pattern" (段階的洗練型) - Documents the process: Complex AI proposal → Detailed analysis → Human insight → Convergence - Field declaration design as a typical example ### Paper K (Explosive Incidents) - Added Incident #046: "init block vs fields-at-top incident" - Updated total count to 46 incidents - Shows how a single human comment redirected entire design approach ## Design Decision After analysis, decided that BoxIndex should remain a compiler-internal structure, not a core Box: - Core Boxes: User-instantiable runtime values (String, Integer, Array, Map) - Compiler internals: BoxIndex for name resolution (compile-time only) - Clear separation of concerns between language features and compiler tools ## Philosophy This discussion exemplifies key principles: - The best design needs no explanation - Constraints provide clarity, not limitation - "Everything is Box" doesn't mean "compiler internals are Boxes" - AI tends toward theoretical completeness; humans toward practical simplicity 🐱 Sometimes the simplest answer is right in front of us\!
2025-09-16 14:57:05 +09:00
std::process::exit(1);
}
// Late env overrides (paths/modules)
if let Ok(paths) = std::env::var("NYASH_USING_PATH") {
for p in paths.split(':') {
let p = p.trim();
if !p.is_empty() {
using_ctx.using_paths.push(p.to_string());
}
}
}
if let Ok(mods) = std::env::var("NYASH_MODULES") {
for ent in mods.split(',') {
if let Some((k, v)) = ent.split_once('=') {
let k = k.trim();
let v = v.trim();
if !k.is_empty() && !v.is_empty() {
using_ctx
.pending_modules
.push((k.to_string(), v.to_string()));
}
}
}
}
// Re-apply pending modules in case env added more (idempotent)
for (ns, path) in using_ctx.pending_modules.iter() {
let sb = nyash_rust::box_trait::StringBox::new(path.clone());
nyash_rust::runtime::modules_registry::set(ns.clone(), Box::new(sb));
}
// Resolve CLI --using entries against context and register values (with aliasing)
let strict = std::env::var("NYASH_USING_STRICT").ok().as_deref() == Some("1");
let verbose = crate::config::env::cli_verbose();
let ctx = std::path::Path::new(filename).parent();
for (ns, alias) in pending_using.iter() {
let value = match resolve_using_target(
ns,
false,
&using_ctx.pending_modules,
&using_ctx.using_paths,
&using_ctx.aliases,
&using_ctx.packages,
ctx,
strict,
verbose,
) {
Ok(v) => v,
Err(e) => {
eprintln!("❌ using: {}", e);
std::process::exit(1);
}
};
let sb = nyash_rust::box_trait::StringBox::new(value.clone());
nyash_rust::runtime::modules_registry::set(ns.clone(), Box::new(sb));
if let Some(a) = alias {
let sb2 = nyash_rust::box_trait::StringBox::new(value);
nyash_rust::runtime::modules_registry::set(a.clone(), Box::new(sb2));
}
}
}
}
}
/// Apply early environment toggles that affect CLI behavior and VM stats.
/// Side effects: sets `NYASH_CLI_VERBOSE`, `NYASH_GC_MODE` when specified by CLI groups.
fn apply_common_env(&self, groups: &crate::cli::CliGroups) {
if groups.debug.cli_verbose {
std::env::set_var("NYASH_CLI_VERBOSE", "1");
}
if let Some(ref m) = groups.gc_mode {
if !m.trim().is_empty() {
std::env::set_var("NYASH_GC_MODE", m);
}
}
}
// init_runtime_and_plugins moved to runner/plugins.rs
/// Configure backend knobs (VM) from CLI flags and env.
/// JIT configuration removed with JIT/Cranelift archival.
fn configure_backend(&self, groups: &crate::cli::CliGroups) {
if groups.backend.vm_stats {
std::env::set_var("NYASH_VM_STATS", "1");
}
if groups.backend.vm_stats_json {
std::env::set_var("NYASH_VM_STATS_JSON", "1");
}
// JIT configuration removed - archived to archive/jit-cranelift/
}
/// JIT runtime policy enforcement removed with JIT/Cranelift archival.
fn enforce_runtime_jit_policy(&self, _groups: &crate::cli::CliGroups) {
// JIT policy enforcement removed - archived to archive/jit-cranelift/
}
/// Optionally run the benchmark suite and exit, depending on CLI flags.
/// Returns true when a benchmark run occurred.
fn maybe_run_benchmark(&self, groups: &crate::cli::CliGroups) -> bool {
if groups.benchmark {
println!("📊 Nyash Performance Benchmark Suite");
println!("====================================");
println!("Running {} iterations per test...", groups.iterations);
println!();
// VM-legacy removed - benchmark mode no longer available
eprintln!(
"❌ Benchmark mode removed with vm-legacy. Use regular execution modes instead."
);
std::process::exit(1);
}
false
}
/// Final dispatch to selected execution mode (file/JIT-direct or demos).
fn dispatch_entry(&self, groups: &crate::cli::CliGroups) {
if let Some(ref filename) = groups.input.file {
if groups.backend.jit.direct {
self.run_file_jit_direct(filename);
return;
}
Phase 21.2 Complete: VM Adapter正規実装 + devブリッジ完全撤去 ## 🎉 Phase 21.2完全達成 ### ✅ 実装完了 - VM static box 永続化(singleton infrastructure) - devブリッジ完全撤去(adapter_dev.rs削除、by-name dispatch削除) - .hako正規実装(MirCallV1Handler, AbiAdapterRegistry等) - text-merge経路完全動作 - 全phase2120 adapter reps PASS(7テスト) ### 🐛 バグ修正 1. strip_local_decl修正 - トップレベルのみlocal削除、メソッド内は保持 - src/runner/modes/common_util/hako.rs:29 2. static box フィールド永続化 - MirInterpreter singleton storage実装 - me parameter binding修正(1:1マッピング) - getField/setField string→singleton解決 - src/backend/mir_interpreter/{mod,exec,handlers/boxes_object_fields}.rs 3. Map.len alias rc=0修正 - [map/missing]パターン検出でnull扱い(4箇所) - lang/src/vm/boxes/mir_call_v1_handler.hako:91-93,131-133,151-153,199-201 ### 📁 主要変更ファイル #### Rust(VM Runtime) - src/backend/mir_interpreter/mod.rs - static box singleton storage - src/backend/mir_interpreter/exec.rs - parameter binding fix - src/backend/mir_interpreter/handlers/boxes_object_fields.rs - singleton resolution - src/backend/mir_interpreter/handlers/calls.rs - dev bridge removal - src/backend/mir_interpreter/utils/mod.rs - adapter_dev module removal - src/backend/mir_interpreter/utils/adapter_dev.rs - DELETED (7555 bytes) - src/runner/modes/vm.rs - static box declaration collection - src/runner/modes/common_util/hako.rs - strip_local_decl fix - src/instance_v2.rs - Clone implementation #### Hako (.hako実装) - lang/src/vm/boxes/mir_call_v1_handler.hako - [map/missing] detection - lang/src/vm/boxes/abi_adapter_registry.hako - NEW (adapter registry) - lang/src/vm/helpers/method_alias_policy.hako - method alias support #### テスト - tools/smokes/v2/profiles/quick/core/phase2120/s3_vm_adapter_*.sh - 7 new tests ### 🎯 テスト結果 ``` ✅ s3_vm_adapter_array_len_canary_vm.sh ✅ s3_vm_adapter_array_len_per_recv_canary_vm.sh ✅ s3_vm_adapter_array_length_alias_canary_vm.sh ✅ s3_vm_adapter_array_size_alias_canary_vm.sh ✅ s3_vm_adapter_map_len_alias_state_canary_vm.sh ✅ s3_vm_adapter_map_length_alias_state_canary_vm.sh ✅ s3_vm_adapter_map_size_struct_canary_vm.sh ``` 環境フラグ: HAKO_ABI_ADAPTER=1 HAKO_ABI_ADAPTER_DEV=0 ### 🏆 設計品質 - ✅ ハードコード禁止(AGENTS.md 5.1)完全準拠 - ✅ 構造的・一般化設計(特定Box名のif分岐なし) - ✅ 後方互換性保持(既存コード破壊ゼロ) - ✅ text-merge経路(.hako依存関係正しくマージ) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 19:32:44 +09:00
// Optional route trace before delegating to backend dispatcher
if std::env::var("NYASH_VM_ROUTE_TRACE").ok().as_deref() == Some("1") {
eprintln!(
"[vm-route] pre-dispatch backend={} file={}",
groups.backend.backend, filename
);
}
self.run_file(filename);
} else {
demos::run_all_demos();
}
}
}
impl NyashRunner {
/// Run a file through independent JIT engine (no VM execute loop)
/// ARCHIVED: JIT/Cranelift functionality disabled for Phase 15
fn run_file_jit_direct(&self, filename: &str) {
eprintln!("❌ JIT-direct mode is archived for Phase 15. JIT/Cranelift moved to archive/jit-cranelift/");
eprintln!(" Use VM backend instead: nyash {}", filename);
eprintln!(" Or use LLVM backend: nyash --backend llvm {}", filename);
std::process::exit(1);
}
}
// moved to demos.rs
// moved to demos.rs
// moved to demos.rs
// moved to demos.rs
// moved to demos.rs
// moved to demos.rs