diff --git a/CURRENT_TASK.md b/CURRENT_TASK.md index 215638f5..1b0ded9a 100644 --- a/CURRENT_TASK.md +++ b/CURRENT_TASK.md @@ -1,31 +1,42 @@ -# Current Task — Phase 20.39 (Typed IR & hv1 finalize) +# Current Task — Phase 20.45 (self‑host E2E 1/2) This document is intentionally concise (≤ 500 lines). Detailed history and per‑phase plans are kept under docs/private/roadmap/. See links below. Focus (now) -- Typed IR(SSOT)の導入: V1ConstIR / V1CompareIR / V1BranchIR / V1JumpIR / V1PhiIR / V1RetIR を Hako で定義(挙動不変)。 -- **hv1 verify の最終化: main.rs 入口一本化完了(DONE)** - - プラグイン初期化前に early-exit(UnifiedBoxRegistry ログなし)。 - - vm.rs / vm_fallback.rs / dispatch.rs の重複分岐を撤去済み。 - - カナリー追加: `hv1_direct_no_plugin_init_canary.sh` で検証 PASS。 - - 環境変数: `HAKO_VERIFY_PRIMARY=hakovm` (推奨) または `HAKO_ROUTE_HAKOVM=1` (互換) -- Concat-safety sweep: """ + " を VM/Core から一掃(StrCast/StringHelpers に統一、進捗: 核心パス DONE)。 -- LoopForm.build2 の適用拡大(lower_loop_* 代表に適用済/続行)。 -- Instruction Dedup(SSOT helpers): binop_lower / loop_common で Builder/Bridge の重複を排除(第一段)。 - - Builder 側: `src/mir/builder/ops.rs` の BinOp 発行を SSOT (`emit_binop_to_dst`) 経由に切替(挙動不変・id 整合維持)。 - - Bridge 側: `json_v0_bridge/lowering/expr.rs` は `ssot::binop_lower::emit_binop_func` 採用済。 +- Hako MirBuilder → v1 MIR → hv1 実行を PRIMARY に固定(no‑fallback)。 +- Array/Map の rc 実行を段階移行(builder‑only → rc)。 +- Provider 実行(emit/codegen)を恒常運用できる形に整備(代表は Hako PRIMARY で緑)。 -Remaining (20.39 — typed IR & finalize) -- Add typed IR boxes and module export(hakorune-vm.ir.types)。 -- Wire dispatcher to accept typed IR inputs gradually(写像ヘルパ・差分ゼロ)。 -- Remove include fallback from scripts(直行のみ)。 -- Sweep concatenations and update helpers. +Remaining (20.45) +- Array/Map rc 移行(段階) + - v0 ローダに newbox/boxcall の最小受理を追加、または provider emit を v1 スキーマへ寄せるトグルを追加(どちらか一方で可)。 + - lowers 生成側の size 標準化(len/length は受理側で別名吸収)。 +- Provider 直行の幅出し + - 三項・match・論理・複数 block の rc カナリを拡充。 +- 逆引き/スキャナ統一のスイープ(小粒継続) + - If/Compare VarInt/VarVar、Return BinOp/Logical に PatternUtilBox/JsonFragBox を適用。 +- ループ系の JsonFragBox 化(ProgScan 置換を段階導入)。 + +Progress (today) +- PRIMARY no-fallback reps 拡張(canary 追加・緑化) + - Return(Int)(runner_min 経由): PASS + - Return(BinOp Int+Int)(runner_min 経由): PASS + - Array.size(MirBuilder 経由): PASS + - Logical(OR の代表、MirBuilder 経由): PASS(AND は次フェーズで検証/整備) + - Load/Store(runner_min v1 → hv1 inline): PASS +- 修正 + - lower_return_int_box.hako: MIR v0 形状を正規化(functions[]=…, name="main", blocks.id) + - lower_return_binop_box.hako: 同上(v0 形状) + - runner_min_box.hako: Return(BinOp) を採用 + - phase2043 runner_min カナリの alias を修正(Runner→BuilderRunnerMinBox) Next Steps (ordered) -1) ループ比較の正規化拡張(>/>=/==/!= → Lt/Gt/Ge 正規化;左右スワップ++1調整、canary補強) -2) SSOT 拡張(compare/branch/jump/phi を cf_common に段階移行) -3) Unicode `\\uXXXX` 復号のトグル実装(既定OFF;canary追加) -4) hv1 一本化(main入口)と文字列スキャナ根治('対応+エスケープ拡張)を DONE に反映 +1) Hako MirBuilder PRIMARY(HAKO_PRIMARY_NO_FALLBACK=1)で代表(Return/If/Compare/Logical/Match/Ternary/Loop/Array/Map)を順に緑化。 +2) 生成側 size 標準化の横展開(rc カナリに切替)。 +3) Provider 幅出し(三項・match・論理・複数 block)rc カナリの追加。 +4) 逆引き/スキャナ統一スイープの継続(If/Compare/Return)。 +5) ループ系の JsonFragBox 化(安全サブセットから)。 +6) Logical(AND) の PRIMARY 化(必要に応じ Lower の堅牢化)。 Hotfix Plan — Using/Prelude Unification (Self‑Host) - Problem: .hako を NyashParser に通す経路でパース落ち(Invalid expression)。 @@ -51,19 +62,17 @@ Action Items (20.38) - phase‑20.38 のトグル/受け入れ条件/撤去予定のシムを反映。φ entry SSOT は IR 完了後に更新。 - extern タグ用シムの現状と撤去条件(hv1 inline 安定後に除去)を明記。 -Acceptance -- extern canary(warn/error/emit/codegen): Hako primary で PASS(タグ+rc=0、シム無効でも安定)。 -- v1 φ/branch/jump の代表カナリーが IR 反復で strict PASS。tolerate ケースは期待と一致。 -- Verify 既定が v1→Hakorune(Core fallback)で quick 緑維持。 -- Hako 構文を Nyash VM で実行しようとした場合、入口で Fail‑Fast(診断メッセージ)。 -- hv1 直行は main 入口で早期退出し、プラグイン初期化ログが出ない(canaryで保証)。 +Acceptance(phase 20.45) +- Hako PRIMARY(HAKO_PRIMARY_NO_FALLBACK=1)で代表構文が rc パリティ。 +- Array/Map: push/size=2、set/size=1 の rc カナリが PRIMARY で PASS。 +- Provider 複数ブロック代表(if-nested/else-if/if→match)が rc で緑維持。 -Changes (this step) -- hv1 direct を main 入口で早期退出に一本化(プラグイン初期化前で rc のみ出力)。 -- Tokenizer 根治: Stage‑3 でシングルクォート受理、エスケープ(\\/ \\b \\f \\' \\r)拡張。 -- SSOT: Builder BinOp を `emit_binop_to_dst` で発行(挙動不変)。 -- Loop 正規化: CountParam に `L` coercions with `StringHelpers.int_to_str(...)` in `lang/src/vm/hakorune-vm/dispatcher_v1.hako` and `lang/src/vm/boxes/mir_call_v1_handler.hako`. +# Handoff — 20.43 Kickoff (15h progress) + +Focus (next) +- Start Phase 20.43: MIR generation coverage for call/method/newbox/load/store/typeop, with minimal Array/Map bridge (structure-first, no behavior change). + +What’s landed this session (DONE) +- NewBox → Constructor (minimal lower) + - Added: `lang/src/mir/builder/internal/lower_newbox_constructor_box.hako` + - Wired in: `lang/src/mir/builder/MirBuilderBox.hako` (try_lower early) and alias in `nyash.toml`. + - Direct canary (PASS): `tools/smokes/v2/profiles/quick/core/phase2043/lower_newbox_constructor_direct_core_exec_canary_vm.sh`. +- Method(size) → structural MIR (Array) + - Added: `lang/src/mir/builder/internal/lower_method_array_size_box.hako` + alias in `nyash.toml`. + - Direct structural canary (PASS): `tools/smokes/v2/profiles/quick/core/phase2043/lower_method_array_size_direct_struct_canary_vm.sh`. +- Method(push) → structural MIR (Array) + - Added: `lang/src/mir/builder/internal/lower_method_array_push_box.hako` + alias in `nyash.toml`. + - Direct structural canary (PASS): `tools/smokes/v2/profiles/quick/core/phase2043/lower_method_array_push_direct_struct_canary_vm.sh`. +- New → Constructor (direct) and Method(size/push) canaries all green under phase‑2043. +- Array get/set + - Added: `lang/src/mir/builder/internal/lower_method_array_get_set_box.hako` + alias. + - Direct structural canary (PASS): `tools/smokes/v2/profiles/quick/core/phase2043/lower_method_array_get_set_direct_struct_canary_vm.sh`. +- Map size/get/set + - Added: `lang/src/mir/builder/internal/lower_method_map_size_box.hako`, `lower_method_map_get_set_box.hako` + aliases. + - Direct structural canaries (PASS): `lower_method_map_size_direct_struct_canary_vm.sh`, `lower_method_map_get_set_direct_struct_canary_vm.sh`. +- Load/Store(最小) + - Added: `lang/src/mir/builder/internal/lower_load_store_local_box.hako` + alias。 + - Direct structural canary (PASS): `lower_load_store_local_direct_struct_canary_vm.sh`。 +- TypeOp Check(最小) + - Added: `lang/src/mir/builder/internal/lower_typeop_check_box.hako` + alias。 + - Direct structural canary (PASS): `lower_typeop_check_direct_struct_canary_vm.sh`。 +- TypeOp Cast(最小) + - Added: `lang/src/mir/builder/internal/lower_typeop_cast_box.hako` + alias。 + - Direct structural canary (PASS): `lower_typeop_cast_direct_struct_canary_vm.sh`。 +- Builder internal route stabilized for simple New → Core via runner_min + - Added: `lang/src/mir/builder/internal/runner_min_box.hako` + alias。 + - `verify_program_via_builder_to_core` uses runner_min first, with markers + optional full MirBuilder fallback. +- Harness improvements + - Builder output extraction with markers `[MIR_OUT_BEGIN]/[MIR_OUT_END]` in `tools/smokes/v2/lib/test_runner.sh`. + - Debug tails for stdout/stderr when `HAKO_MIR_BUILDER_DEBUG=1`. + - Enabled using for inline runs: `NYASH_ENABLE_USING=1` / `HAKO_ENABLE_USING=1`. + +Open items / blockers +- Builder (internal/delegate) inline route still unstable for JSON capture; `phase2043/program_new_array_delegate_struct_canary_vm.sh` fails (no JSON in stdout). + - Plan: switch builder to write MIR to a temp file (FileBox) and let harness read it; or adopt provider route in 20.44 (`env.mirbuilder.emit`). +- Remaining lowers for 20.43 not yet added: method(push/get/set/len), load/store (local), typeop(is/as) minimal; builder wiring after direct lowers pass. + +Next-up checklist (20.43) +1) MirBuilder wiring: 上記 direct lowers を `MirBuilderBox` から段階採用(Return系フォールバック前)→ 一部(Array/Map/LoadStore/TypeOp)採用済み。 +2) New(Map) は Constructor lower で既に生成可能(direct PASS)。Builder経路へ採用。 +3) TypeOp: `Cast` 採用済(構造lower→canary→配線)。 +4) Builder route 安定化(internal):lower ラッパー側で MIR を `/tmp` に保存→ハーネスが読む(pipe 揺れを回避)。 +5) Delegate route(20.44 に接続):`env.mirbuilder.emit` を provider 経由に切替(構造は共通)。 +6) Delegate route (optional): use provider `env.mirbuilder.emit` (20.44 scope) to make canaries robust. + +How to run +- All new phase 20.43 canaries: + - `bash tools/smokes/v2/run.sh --profile quick --filter phase2043` +- Single tests: + - NewBox direct: `tools/smokes/v2/profiles/quick/core/phase2043/lower_newbox_constructor_direct_core_exec_canary_vm.sh` + - Method(size) direct: `tools/smokes/v2/profiles/quick/core/phase2043/lower_method_array_size_direct_struct_canary_vm.sh` + +Toggles (dev) +- Inline Hako: `HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1` +- Builder internal: `HAKO_MIR_BUILDER_INTERNAL=1` (and `HAKO_MIR_BUILDER_DEBUG=1` for tails) + +Pointers +- New lowers: `lang/src/mir/builder/internal/lower_newbox_constructor_box.hako`, `lang/src/mir/builder/internal/lower_method_array_size_box.hako` +- Wiring: `lang/src/mir/builder/MirBuilderBox.hako` (try_lower order) and `nyash.toml` aliases +- Harness: `tools/smokes/v2/lib/test_runner.sh` (marker extraction / debug tails) + +--- diff --git a/build.err b/build.err new file mode 100644 index 00000000..026c0869 --- /dev/null +++ b/build.err @@ -0,0 +1,695 @@ +warning: profiles for the non root package will be ignored, specify profiles at the workspace root: +package: /home/tomoaki/git/hakorune-selfhost/plugins/nyash-console-plugin/Cargo.toml +workspace: /home/tomoaki/git/hakorune-selfhost/Cargo.toml +warning: profiles for the non root package will be ignored, specify profiles at the workspace root: +package: /home/tomoaki/git/hakorune-selfhost/plugins/nyash-counter-plugin/Cargo.toml +workspace: /home/tomoaki/git/hakorune-selfhost/Cargo.toml +warning: profiles for the non root package will be ignored, specify profiles at the workspace root: +package: /home/tomoaki/git/hakorune-selfhost/plugins/nyash-filebox-plugin/Cargo.toml +workspace: /home/tomoaki/git/hakorune-selfhost/Cargo.toml +warning: profiles for the non root package will be ignored, specify profiles at the workspace root: +package: /home/tomoaki/git/hakorune-selfhost/plugins/nyash-json-plugin/Cargo.toml +workspace: /home/tomoaki/git/hakorune-selfhost/Cargo.toml +warning: profiles for the non root package will be ignored, specify profiles at the workspace root: +package: /home/tomoaki/git/hakorune-selfhost/plugins/nyash-math-plugin/Cargo.toml +workspace: /home/tomoaki/git/hakorune-selfhost/Cargo.toml +warning: /home/tomoaki/git/hakorune-selfhost/Cargo.toml: file `/home/tomoaki/git/hakorune-selfhost/src/main.rs` found to be present in multiple build targets: + * `bin` target `hakorune` + * `bin` target `nyash` + Compiling nyash-rust v0.1.0 (/home/tomoaki/git/hakorune-selfhost) +warning: unused doc comment + --> src/box_operators/static_ops.rs:14:1 + | +14 | / /// Static numeric operations for IntegerBox +15 | | /// +16 | | /// Generates implementations for: Add, Sub, Mul, Div with zero-division error handling + | |_--------------------------------------------------------------------------------------^ + | | + | rustdoc does not generate documentation for macro invocations + | + = help: to document an item produced by a macro, the macro must produce the documentation as part of its expansion + = note: `#[warn(unused_doc_comments)]` on by default + +warning: unused doc comment + --> src/box_operators/static_ops.rs:19:1 + | +19 | / /// Static numeric operations for FloatBox +20 | | /// +21 | | /// Generates implementations for: Add, Sub, Mul, Div with zero-division error handling + | |_--------------------------------------------------------------------------------------^ + | | + | rustdoc does not generate documentation for macro invocations + | + = help: to document an item produced by a macro, the macro must produce the documentation as part of its expansion + +warning: unused import: `std::any::Any` + --> src/boxes/arithmetic/modulo_box.rs:6:5 + | +6 | use std::any::Any; + | ^^^^^^^^^^^^^ + | + = note: `#[warn(unused_imports)]` on by default + +warning: unused import: `HashMap` + --> src/mir/basic_block.rs:8:24 + | +8 | use std::collections::{HashMap, HashSet}; + | ^^^^^^^ + +warning: unused import: `call_target::CallTarget` + --> src/mir/builder/calls/mod.rs:10:9 + | +10 | pub use call_target::CallTarget; + | ^^^^^^^^^^^^^^^^^^^^^^^ + +warning: unused imports: `has_method`, `is_builtin_function`, `is_extern_function`, and `resolve_call_target` + --> src/mir/builder/calls/mod.rs:32:5 + | +32 | resolve_call_target, + | ^^^^^^^^^^^^^^^^^^^ +33 | is_builtin_function, + | ^^^^^^^^^^^^^^^^^^^ +34 | is_extern_function, + | ^^^^^^^^^^^^^^^^^^ +35 | has_method, + | ^^^^^^^^^^ + +warning: unused imports: `compute_extern_effects`, `get_env_method_spec`, `is_env_interface`, and `parse_extern_name` + --> src/mir/builder/calls/mod.rs:39:5 + | +39 | get_env_method_spec, + | ^^^^^^^^^^^^^^^^^^^ +40 | parse_extern_name, + | ^^^^^^^^^^^^^^^^^ +41 | is_env_interface, + | ^^^^^^^^^^^^^^^^ +42 | compute_extern_effects, + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: unused imports: `contains_value_return`, `extract_string_literal`, `is_math_function`, `is_typeop_method`, `make_function_name_with_arity`, and `parse_type_name_to_mir` + --> src/mir/builder/calls/mod.rs:46:5 + | +46 | is_math_function, + | ^^^^^^^^^^^^^^^^ +47 | is_typeop_method, + | ^^^^^^^^^^^^^^^^ +48 | extract_string_literal, + | ^^^^^^^^^^^^^^^^^^^^^^ +49 | parse_type_name_to_mir, + | ^^^^^^^^^^^^^^^^^^^^^^ +50 | contains_value_return, + | ^^^^^^^^^^^^^^^^^^^^^ +51 | make_function_name_with_arity, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: unused imports: `generate_method_function_name`, `generate_static_method_function_name`, `prepare_method_signature`, `prepare_static_method_signature`, and `wrap_in_program` + --> src/mir/builder/calls/mod.rs:55:5 + | +55 | prepare_method_signature, + | ^^^^^^^^^^^^^^^^^^^^^^^^ +56 | prepare_static_method_signature, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +57 | generate_method_function_name, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +58 | generate_static_method_function_name, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +59 | wrap_in_program, + | ^^^^^^^^^^^^^^^ + +warning: unused imports: `compute_call_effects`, `convert_target_to_callee`, `create_call_flags`, `create_mir_call`, `is_unified_call_enabled`, and `validate_call_args` + --> src/mir/builder/calls/mod.rs:63:5 + | +63 | is_unified_call_enabled, + | ^^^^^^^^^^^^^^^^^^^^^^^ +64 | convert_target_to_callee, + | ^^^^^^^^^^^^^^^^^^^^^^^^ +65 | compute_call_effects, + | ^^^^^^^^^^^^^^^^^^^^ +66 | create_call_flags, + | ^^^^^^^^^^^^^^^^^ +67 | create_mir_call, + | ^^^^^^^^^^^^^^^ +68 | validate_call_args, + | ^^^^^^^^^^^^^^^^^^ + +warning: unused import: `FunctionSignature` + --> src/mir/builder/builder_calls.rs:2:33 + | +2 | use super::{Effect, EffectMask, FunctionSignature, MirInstruction, MirType, ValueId}; + | ^^^^^^^^^^^^^^^^^ + +warning: unused import: `MethodCallExpr` + --> src/mir/builder/builder_calls.rs:3:41 + | +3 | use crate::ast::{ASTNode, LiteralValue, MethodCallExpr}; + | ^^^^^^^^^^^^^^ + +warning: unused imports: `CallFlags` and `MirCall` + --> src/mir/builder/builder_calls.rs:4:53 + | +4 | use crate::mir::definitions::call_unified::{Callee, CallFlags, MirCall}; + | ^^^^^^^^^ ^^^^^^^ + +warning: unused import: `super::call_resolution` + --> src/mir/builder/builder_calls.rs:6:5 + | +6 | use super::call_resolution; + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: unused import: `MirType` + --> src/mir/builder/method_call_handlers.rs:9:46 + | +9 | use crate::mir::{MirInstruction, TypeOpKind, MirType}; + | ^^^^^^^ + +warning: unused import: `ConstValue` + --> src/mir/builder/decls.rs:2:13 + | +2 | use super::{ConstValue, MirInstruction, ValueId}; + | ^^^^^^^^^^ + +warning: unused import: `ConstValue` + --> src/mir/builder/exprs.rs:2:13 + | +2 | use super::{ConstValue, MirInstruction, ValueId}; + | ^^^^^^^^^^ + +warning: unused import: `ConstValue` + --> src/mir/builder/fields.rs:2:13 + | +2 | use super::{ConstValue, EffectMask, MirInstruction, ValueId}; + | ^^^^^^^^^^ + +warning: unused import: `ConstValue` + --> src/mir/builder/if_form.rs:1:13 + | +1 | use super::{ConstValue, MirBuilder, MirInstruction, ValueId}; + | ^^^^^^^^^^ + +warning: unused import: `ConstValue` + --> src/mir/builder/control_flow.rs:2:13 + | +2 | use super::{ConstValue, Effect, EffectMask, MirInstruction, ValueId}; + | ^^^^^^^^^^ + +warning: unused import: `ConstValue` + --> src/mir/builder/lifecycle.rs:1:116 + | +1 | use super::{EffectMask, FunctionSignature, MirFunction, MirInstruction, MirModule, MirType, ValueId, BasicBlockId, ConstValue}; + | ^^^^^^^^^^ + +warning: unused import: `ConstValue` + --> src/mir/builder/stmts.rs:1:13 + | +1 | use super::{ConstValue, Effect, EffectMask, MirInstruction, ValueId}; + | ^^^^^^^^^^ + +warning: unused import: `MirInstruction` + --> src/mir/builder/origin/phi.rs:1:32 + | +1 | use super::super::{MirBuilder, MirInstruction, MirType, ValueId, BasicBlockId}; + | ^^^^^^^^^^^^^^ + +warning: unused import: `ConstValue` + --> src/mir/builder/rewrite/known.rs:1:20 + | +1 | use super::super::{ConstValue, Effect, EffectMask, MirBuilder, MirInstruction, ValueId}; + | ^^^^^^^^^^ + +warning: unused import: `ConstValue` + --> src/mir/builder/rewrite/special.rs:1:20 + | +1 | use super::super::{ConstValue, Effect, EffectMask, MirBuilder, MirInstruction}; + | ^^^^^^^^^^ + +warning: unused import: `std::collections::HashMap` + --> src/mir/builder/ssa/local.rs:3:5 + | +3 | use std::collections::HashMap; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: unused import: `Effect` + --> src/mir/instruction.rs:7:13 + | +7 | use super::{Effect, EffectMask, ValueId}; + | ^^^^^^ + +warning: unused import: `std::fmt` + --> src/mir/instruction.rs:13:5 + | +13 | use std::fmt; + | ^^^^^^^^ + +warning: unused import: `crate::mir::instruction_kinds as inst_meta` + --> src/mir/instruction.rs:16:5 + | +16 | use crate::mir::instruction_kinds as inst_meta; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: unexpected `cfg` condition value: `cranelift-jit` + --> src/backend/mod.rs:29:7 + | +29 | #[cfg(feature = "cranelift-jit")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: expected values for `feature` are: `all-examples`, `aot-plan-import`, `builtin-core`, `cli`, `default`, `dynamic-file`, `e2e`, `gui`, `gui-examples`, `interpreter-legacy`, `jit-direct-only`, `llvm`, `llvm-harness`, `llvm-inkwell-legacy`, `mir_refbarrier_unify_poc`, `mir_typeop_poc`, `phi-legacy`, `plugins`, `plugins-only`, `vm-legacy`, and `wasm-backend` + = help: consider adding `cranelift-jit` as a feature in `Cargo.toml` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition value: `cranelift-jit` + --> src/backend/mod.rs:48:7 + | +48 | #[cfg(feature = "cranelift-jit")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: expected values for `feature` are: `all-examples`, `aot-plan-import`, `builtin-core`, `cli`, `default`, `dynamic-file`, `e2e`, `gui`, `gui-examples`, `interpreter-legacy`, `jit-direct-only`, `llvm`, `llvm-harness`, `llvm-inkwell-legacy`, `mir_refbarrier_unify_poc`, `mir_typeop_poc`, `phi-legacy`, `plugins`, `plugins-only`, `vm-legacy`, and `wasm-backend` + = help: consider adding `cranelift-jit` as a feature in `Cargo.toml` + = note: see for more information about checking conditional configuration + +warning: unused import: `Map as JsonMap` + --> src/backend/mir_interpreter/handlers/externals.rs:2:38 + | +2 | use serde_json::{Value as JsonValue, Map as JsonMap}; + | ^^^^^^^^^^^^^^ + +warning: unused import: `super::library` + --> src/runtime/plugin_loader_v2/enabled/loader/config.rs:1:5 + | +1 | use super::library; + | ^^^^^^^^^^^^^^ + +warning: unused import: `super::specs` + --> src/runtime/plugin_loader_v2/enabled/loader/singletons.rs:1:5 + | +1 | use super::specs; + | ^^^^^^^^^^^^ + +warning: unused import: `PluginBoxV2` + --> src/runtime/plugin_loader_v2/enabled/loader/mod.rs:9:55 + | +9 | use super::types::{LoadedPluginV2, PluginBoxMetadata, PluginBoxV2, PluginHandleInner}; + | ^^^^^^^^^^^ + +warning: unused import: `BidError` + --> src/runtime/plugin_loader_v2/enabled/loader/mod.rs:10:18 + | +10 | use crate::bid::{BidError, BidResult}; + | ^^^^^^^^ + +warning: unused import: `std::collections::HashMap` + --> src/runtime/plugin_loader_v2/enabled/method_resolver.rs:8:5 + | +8 | use std::collections::HashMap; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: unused import: `FactoryPolicy` + --> src/runtime/unified_registry.rs:11:46 + | +11 | use crate::box_factory::{UnifiedBoxRegistry, FactoryPolicy}; + | ^^^^^^^^^^^^^ + +warning: unexpected `cfg` condition value: `cranelift-jit` + --> src/runner/dispatch.rs:180:15 + | +180 | #[cfg(feature = "cranelift-jit")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: expected values for `feature` are: `all-examples`, `aot-plan-import`, `builtin-core`, `cli`, `default`, `dynamic-file`, `e2e`, `gui`, `gui-examples`, `interpreter-legacy`, `jit-direct-only`, `llvm`, `llvm-harness`, `llvm-inkwell-legacy`, `mir_refbarrier_unify_poc`, `mir_typeop_poc`, `phi-legacy`, `plugins`, `plugins-only`, `vm-legacy`, and `wasm-backend` + = help: consider adding `cranelift-jit` as a feature in `Cargo.toml` + = note: see for more information about checking conditional configuration + +warning: unexpected `cfg` condition value: `cranelift-jit` + --> src/runner/dispatch.rs:185:19 + | +185 | #[cfg(not(feature = "cranelift-jit"))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: expected values for `feature` are: `all-examples`, `aot-plan-import`, `builtin-core`, `cli`, `default`, `dynamic-file`, `e2e`, `gui`, `gui-examples`, `interpreter-legacy`, `jit-direct-only`, `llvm`, `llvm-harness`, `llvm-inkwell-legacy`, `mir_refbarrier_unify_poc`, `mir_typeop_poc`, `phi-legacy`, `plugins`, `plugins-only`, `vm-legacy`, and `wasm-backend` + = help: consider adding `cranelift-jit` as a feature in `Cargo.toml` + = note: see for more information about checking conditional configuration + +warning: unexpected `cfg` condition value: `cranelift-jit` + --> src/runner/dispatch.rs:203:15 + | +203 | #[cfg(feature = "cranelift-jit")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: expected values for `feature` are: `all-examples`, `aot-plan-import`, `builtin-core`, `cli`, `default`, `dynamic-file`, `e2e`, `gui`, `gui-examples`, `interpreter-legacy`, `jit-direct-only`, `llvm`, `llvm-harness`, `llvm-inkwell-legacy`, `mir_refbarrier_unify_poc`, `mir_typeop_poc`, `phi-legacy`, `plugins`, `plugins-only`, `vm-legacy`, and `wasm-backend` + = help: consider adding `cranelift-jit` as a feature in `Cargo.toml` + = note: see for more information about checking conditional configuration + +warning: unused import: `BinaryOp` + --> src/runner/json_v0_bridge/lowering.rs:4:35 + | +4 | MirPrinter, MirType, ValueId, BinaryOp, + | ^^^^^^^^ + +warning: unused import: `MirInstruction` + --> src/runner/json_v0_bridge/lowering/if_else.rs:2:45 + | +2 | use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId}; + | ^^^^^^^^^^^^^^ + +warning: unused import: `BinaryOp` + --> src/runner/json_v0_bridge/lowering/expr.rs:6:19 + | +6 | BasicBlockId, BinaryOp, ConstValue, EffectMask, MirFunction, MirInstruction, ValueId, + | ^^^^^^^^ + +warning: unused import: `MirInstruction` + --> src/runner/json_v0_bridge/lowering/ternary.rs:8:45 + | +8 | use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId}; + | ^^^^^^^^^^^^^^ + +warning: unused import: `MirInstruction` + --> src/runner/json_v0_bridge/lowering/throw_ctx.rs:1:45 + | +1 | use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId}; + | ^^^^^^^^^^^^^^ + +warning: unexpected `cfg` condition value: `cranelift-jit` + --> src/runner/modes/mod.rs:11:7 + | +11 | #[cfg(feature = "cranelift-jit")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: expected values for `feature` are: `all-examples`, `aot-plan-import`, `builtin-core`, `cli`, `default`, `dynamic-file`, `e2e`, `gui`, `gui-examples`, `interpreter-legacy`, `jit-direct-only`, `llvm`, `llvm-harness`, `llvm-inkwell-legacy`, `mir_refbarrier_unify_poc`, `mir_typeop_poc`, `phi-legacy`, `plugins`, `plugins-only`, `vm-legacy`, and `wasm-backend` + = help: consider adding `cranelift-jit` as a feature in `Cargo.toml` + = note: see for more information about checking conditional configuration + +warning: unused import: `NyashBox` + --> src/runner/modes/vm_fallback.rs:308:40 + | +308 | use crate::box_trait::{NyashBox, IntegerBox, BoolBox}; + | ^^^^^^^^ + +warning: unused import: `crate::runner::child_env` + --> src/runner/pipe_io.rs:13:5 + | +13 | use crate::runner::child_env; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: unused import: `std::io::Write` + --> src/host_providers/mir_builder.rs:3:5 + | +3 | use std::io::Write; + | ^^^^^^^^^^^^^^ + +warning: unused import: `Path` + --> src/host_providers/llvm_codegen.rs:3:17 + | +3 | use std::path::{Path, PathBuf}; + | ^^^^ + +error[E0308]: mismatched types + --> src/mir/builder/ops.rs:300:65 + | +300 | crate::mir::ssot::cf_common::insert_phi_at_head(func, cur_bb, rhs_bool, inputs); + | ----------------------------------------------- ^^^^ types differ in mutability + | | + | arguments to this function are incorrect + | + = note: expected mutable reference `&mut function::MirFunction` + found reference `&function::MirFunction` +note: function defined here + --> src/mir/ssot/cf_common.rs:47:8 + | +47 | pub fn insert_phi_at_head( + | ^^^^^^^^^^^^^^^^^^ +48 | f: &mut MirFunction, + | ------------------- + +error[E0308]: mismatched types + --> src/mir/builder/ops.rs:363:65 + | +363 | crate::mir::ssot::cf_common::insert_phi_at_head(func, cur_bb, rhs_bool, inputs); + | ----------------------------------------------- ^^^^ types differ in mutability + | | + | arguments to this function are incorrect + | + = note: expected mutable reference `&mut function::MirFunction` + found reference `&function::MirFunction` +note: function defined here + --> src/mir/ssot/cf_common.rs:47:8 + | +47 | pub fn insert_phi_at_head( + | ^^^^^^^^^^^^^^^^^^ +48 | f: &mut MirFunction, + | ------------------- + +error[E0308]: mismatched types + --> src/mir/builder/ops.rs:393:65 + | +393 | crate::mir::ssot::cf_common::insert_phi_at_head(func, cur_bb, dst, inputs); + | ----------------------------------------------- ^^^^ types differ in mutability + | | + | arguments to this function are incorrect + | + = note: expected mutable reference `&mut function::MirFunction` + found reference `&function::MirFunction` +note: function defined here + --> src/mir/ssot/cf_common.rs:47:8 + | +47 | pub fn insert_phi_at_head( + | ^^^^^^^^^^^^^^^^^^ +48 | f: &mut MirFunction, + | ------------------- + +warning: unused import: `crate::box_trait::NyashBox` + --> src/backend/mir_interpreter/handlers/boxes_object_fields.rs:2:5 + | +2 | use crate::box_trait::NyashBox; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: unused import: `crate::box_trait::NyashBox` + --> src/backend/mir_interpreter/handlers/boxes_string.rs:2:5 + | +2 | use crate::box_trait::NyashBox; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: variable does not need to be mutable + --> src/parser/statements/mod.rs:134:13 + | +134 | let mut looks_like_method_head = |this: &Self| -> bool { + | ----^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: remove this `mut` + | + = note: `#[warn(unused_mut)]` on by default + +warning: unused variable: `program_ast` + --> src/mir/builder/decls.rs:43:25 + | +43 | let program_ast = ASTNode::Program { + | ^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_program_ast` + | + = note: `#[warn(unused_variables)]` on by default + +warning: unused variable: `type_id` + --> src/mir/builder/decls.rs:118:13 + | +118 | let type_id = crate::mir::builder::emission::constant::emit_string(self, format!("__box_type_{}", name)); + | ^^^^^^^ help: if this is intentional, prefix it with an underscore: `_type_id` + +warning: unused variable: `else_block` + --> src/mir/builder/phi.rs:15:9 + | +15 | else_block: super::BasicBlockId, + | ^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_else_block` + +warning: unused variable: `then_block` + --> src/mir/builder/phi.rs:112:9 + | +112 | then_block: BasicBlockId, + | ^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_then_block` + +warning: unused variable: `else_block` + --> src/mir/builder/phi.rs:113:9 + | +113 | else_block: BasicBlockId, + | ^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_else_block` + +warning: unused variable: `func` + --> src/mir/builder/lifecycle.rs:241:60 + | +241 | ... MirInstruction::Call { func, .. } => { + | ^^^^- + | | + | help: try removing the field + +warning: variable does not need to be mutable + --> src/mir/builder/lifecycle.rs:271:17 + | +271 | let mut sig = FunctionSignature { + | ----^^^ + | | + | help: remove this `mut` + +warning: unused variable: `dbg_fn_name` + --> src/mir/builder.rs:425:13 + | +425 | let dbg_fn_name = self + | ^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_dbg_fn_name` + +warning: unused variable: `dbg_region_id` + --> src/mir/builder.rs:429:13 + | +429 | let dbg_region_id = self.debug_current_region_id(); + | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_dbg_region_id` + +warning: unused variable: `else_block` + --> src/mir/phi_core/if_phi.rs:148:5 + | +148 | else_block: crate::mir::BasicBlockId, + | ^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_else_block` + +warning: variable does not need to be mutable + --> src/mir/phi_core/loop_phi.rs:185:13 + | +185 | let mut inc = IncompletePhi { + | ----^^^ + | | + | help: remove this `mut` + +warning: variable does not need to be mutable + --> src/backend/mir_interpreter/handlers/boxes_instance.rs:105:17 + | +105 | let mut cands: Vec = this + | ----^^^^^ + | | + | help: remove this `mut` + +warning: variable does not need to be mutable + --> src/backend/mir_interpreter/handlers/calls.rs:257:25 + | +257 | let mut esc = |s: &str| { + | ----^^^ + | | + | help: remove this `mut` + +warning: value assigned to `first_arg_str` is never read + --> src/backend/mir_interpreter/handlers/calls.rs:387:25 + | +387 | let mut first_arg_str: Option = None; + | ^^^^^^^^^^^^^ + | + = help: maybe it is overwritten before being read? + = note: `#[warn(unused_assignments)]` on by default + +warning: unreachable pattern + --> src/backend/mir_interpreter/handlers/externals.rs:149:13 + | +28 | ("env", "get") => { + | -------------- matches all the relevant values +... +149 | ("env", "get") => { + | ^^^^^^^^^^^^^^ no value can reach this + | + = note: `#[warn(unreachable_patterns)]` on by default + +warning: unused variable: `source` + --> src/benchmarks.rs:48:23 + | +48 | if let Ok(source) = fs::read_to_string(file_path) { + | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_source` + +warning: variable does not need to be mutable + --> src/benchmarks.rs:36:13 + | +36 | let mut results = Vec::new(); + | ----^^^^^^^ + | | + | help: remove this `mut` + +warning: unused variable: `lib` + --> src/runtime/plugin_loader_v2/enabled/method_resolver.rs:40:19 + | +40 | for ((lib, bt), spec) in map.iter() { + | ^^^ help: if this is intentional, prefix it with an underscore: `_lib` + +warning: unnecessary `unsafe` block + --> src/runtime/plugin_loader_v2/enabled/method_resolver.rs:50:39 + | +50 | ... let mid = unsafe { res_fn(cstr.as_ptr()) }; + | ^^^^^^ unnecessary `unsafe` block + | + = note: `#[warn(unused_unsafe)]` on by default + +warning: unused variable: `merge_bb` + --> src/runner/json_v0_bridge/lowering/loop_.rs:86:47 + | +86 | fn debug_verify_phi_inputs(&mut self, merge_bb: BasicBlockId, inputs: &[(BasicBlockId, ValueId)]) { + | ^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_merge_bb` + +warning: unused variable: `inputs` + --> src/runner/json_v0_bridge/lowering/loop_.rs:86:71 + | +86 | fn debug_verify_phi_inputs(&mut self, merge_bb: BasicBlockId, inputs: &[(BasicBlockId, ValueId)]) { + | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_inputs` + +warning: variable does not need to be mutable + --> src/runner/json_v0_bridge/lowering/ternary.rs:38:9 + | +38 | let mut inputs = vec![(tend, tval), (eend, eval)]; + | ----^^^^^^ + | | + | help: remove this `mut` + +warning: unreachable pattern + --> src/runner/json_v1_bridge.rs:512:29 + | +368 | ... "Constructor" => { + | ------------- matches all the relevant values +... +512 | ... "Constructor" => { + | ^^^^^^^^^^^^^ no value can reach this + +warning: unused variable: `using_resolver` + --> src/runner/modes/common_util/resolve/prelude_manager.rs:126:17 + | +126 | let using_resolver = UsingResolutionBox::new(&self.runner, path)?; + | ^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_using_resolver` + +warning: unused variable: `filename` + --> src/runner/modes/common_util/resolve/prelude_manager.rs:114:9 + | +114 | filename: &str, + | ^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_filename` + +warning: unused variable: `filename` + --> src/runner/modes/common_util/resolve/selfhost_pipeline.rs:132:9 + | +132 | filename: &str, + | ^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_filename` + +warning: unused variable: `code` + --> src/runner/modes/common_util/resolve/selfhost_pipeline.rs:182:9 + | +182 | code: &str, + | ^^^^ help: if this is intentional, prefix it with an underscore: `_code` + +warning: unused variable: `filename` + --> src/runner/modes/common_util/resolve/selfhost_pipeline.rs:183:9 + | +183 | filename: &str, + | ^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_filename` + +warning: variable does not need to be mutable + --> src/runner/pipe_io.rs:23:13 + | +23 | let mut json = if let Some(path) = &groups.parser.json_file { + | ----^^^^ + | | + | help: remove this `mut` + +warning: unused variable: `code` + --> src/runner/plugins.rs:54:40 + | +54 | ... Ok(code) => { + | ^^^^ help: if this is intentional, prefix it with an underscore: `_code` + +For more information about this error, try `rustc --explain E0308`. +warning: `nyash-rust` (lib) generated 84 warnings +error: could not compile `nyash-rust` (lib) due to 3 previous errors; 84 warnings emitted diff --git a/lang/src/mir/builder/MirBuilderBox.hako b/lang/src/mir/builder/MirBuilderBox.hako index a437d280..eb730210 100644 --- a/lang/src/mir/builder/MirBuilderBox.hako +++ b/lang/src/mir/builder/MirBuilderBox.hako @@ -74,6 +74,15 @@ static box MirBuilderBox { using "hako.mir.builder.internal.lower_if_compare_varint" as LowerIfCompareVarIntBox using "hako.mir.builder.internal.lower_if_compare_varvar" as LowerIfCompareVarVarBox using "hako.mir.builder.internal.lower_loop_sum_bc" as LowerLoopSumBcBox + using "hako.mir.builder.internal.lower_newbox_constructor" as LowerNewboxConstructorBox + using "hako.mir.builder.internal.lower_method_array_size" as LowerMethodArraySizeBox + using "hako.mir.builder.internal.lower_method_array_push" as LowerMethodArrayPushBox + using "hako.mir.builder.internal.lower_method_array_get_set" as LowerMethodArrayGetSetBox + using "hako.mir.builder.internal.lower_method_map_size" as LowerMethodMapSizeBox + using "hako.mir.builder.internal.lower_method_map_get_set" as LowerMethodMapGetSetBox + using "hako.mir.builder.internal.lower_load_store_local" as LowerLoadStoreLocalBox + using "hako.mir.builder.internal.lower_typeop_check" as LowerTypeOpCheckBox + using "hako.mir.builder.internal.lower_typeop_cast" as LowerTypeOpCastBox using "hako.mir.builder.internal.lower_loop_count_param" as LowerLoopCountParamBox using "hako.mir.builder.internal.lower_loop_simple" as LowerLoopSimpleBox using "hako.mir.builder.internal.lower_return_var_local" as LowerReturnVarLocalBox @@ -86,7 +95,17 @@ static box MirBuilderBox { using "hako.mir.builder.internal.lower_return_binop_varvar" as LowerReturnBinOpVarVarBox using "hako.mir.builder.internal.lower_return_binop" as LowerReturnBinOpBox using "hako.mir.builder.internal.lower_return_int" as LowerReturnIntBox - // Prefer loop lowers first to catch loop-specific patterns (sum_bc/continue/break normalization) + // Prefer New(Constructor) minimal first to avoid unresolved nested lowers in inline runs + { local out_newc = LowerNewboxConstructorBox.try_lower(s); if out_newc != null { return out_newc } } + { local out_arr_size = LowerMethodArraySizeBox.try_lower(s); if out_arr_size != null { return out_arr_size } } + { local out_arr_push = LowerMethodArrayPushBox.try_lower(s); if out_arr_push != null { return out_arr_push } } + { local out_arr_gs = LowerMethodArrayGetSetBox.try_lower(s); if out_arr_gs != null { return out_arr_gs } } + { local out_map_size = LowerMethodMapSizeBox.try_lower(s); if out_map_size != null { return out_map_size } } + { local out_map_gs = LowerMethodMapGetSetBox.try_lower(s); if out_map_gs != null { return out_map_gs } } + { local out_ls = LowerLoadStoreLocalBox.try_lower(s); if out_ls != null { return out_ls } } + { local out_toc = LowerTypeOpCheckBox.try_lower(s); if out_toc != null { return out_toc } } + { local out_tca = LowerTypeOpCastBox.try_lower(s); if out_tca != null { return out_tca } } + // Loop lowers (sum_bc/continue/break normalization) { local out_loop2 = LowerLoopSumBcBox.try_lower(s); if out_loop2 != null { return out_loop2 } } { local out_if2b = LowerIfNestedBox.try_lower(s); if out_if2b != null { return out_if2b } } { local out_if2 = LowerIfThenElseFollowingReturnBox.try_lower(s); if out_if2 != null { return out_if2 } } @@ -228,6 +247,11 @@ static box MirBuilderBox { } } } + // NewBox(Constructor) minimal + { + local out_new = LowerNewboxConstructorBox.try_lower(s) + if out_new != null { return out_new } + } // Fallback cases below: Return(Binary) and Return(Int) local k_ret = s.indexOf("\"type\":\"Return\"") if k_ret >= 0 { diff --git a/lang/src/mir/builder/internal/loop_scan_box.hako b/lang/src/mir/builder/internal/loop_scan_box.hako index a1d39079..2e3a8151 100644 --- a/lang/src/mir/builder/internal/loop_scan_box.hako +++ b/lang/src/mir/builder/internal/loop_scan_box.hako @@ -10,8 +10,12 @@ static box LoopScanBox { local varname = null local kl = ("" + s).indexOf("\"lhs\":{", k_cmp) local kr = ("" + s).indexOf("\"rhs\":{", k_cmp) - if kl >= 0 && ("" + s).indexOf("\"type\":\"Var\"", kl) >= 0 { varname = Scan.read_quoted_after_key(s, kl, "name") } - if varname == null && kr >= 0 && ("" + s).indexOf("\"type\":\"Var\"", kr) >= 0 { varname = Scan.read_quoted_after_key(s, kr, "name") } + if kl >= 0 && ("" + s).indexOf("\"type\":\"Var\"", kl) >= 0 { + local kn = ("" + s).indexOf("\"name\":\"", kl); if kn >= 0 { varname = JsonFragBox.read_string_after(s, kn) } + } + if varname == null && kr >= 0 && ("" + s).indexOf("\"type\":\"Var\"", kr) >= 0 { + local kn2 = ("" + s).indexOf("\"name\":\"", kr); if kn2 >= 0 { varname = JsonFragBox.read_string_after(s, kn2) } + } return varname } @@ -26,7 +30,8 @@ static box LoopScanBox { if kif < 0 { return null } local kcmp = ("" + s).lastIndexOf("\"type\":\"Compare\"", ks) if kcmp < 0 || kcmp < kif { return null } - local op = Scan.read_quoted_after_key(s, kcmp, "op"); if op == null || op != "!=" { return null } + local kop = ("" + s).indexOf("\"op\":", kcmp); if kop < 0 { return null } + local op = JsonFragBox.read_string_after(s, kop + 5); if op == null || op != "!=" { return null } // else 範囲の配列区間を特定 local kth = JsonFragBox.index_of_from(s, "\"then\":", kif); if kth < 0 { return null } local lb_then = JsonFragBox.index_of_from(s, "[", kth); if lb_then < 0 { return null } @@ -43,7 +48,8 @@ static box LoopScanBox { if has_lhs { local kr = ("" + s).indexOf("\"rhs\":{", kcmp); if kr < 0 { return null } local kt = ("" + s).indexOf("\"type\":\"Int\"", kr); if kt < 0 { return null } - local sentinel_val = Scan.read_value_int_after(s, kt) + local kv = ("" + s).indexOf("\"value\":", kt); if kv < 0 { return null } + local sentinel_val = JsonFragBox.read_int_after(s, kv + 8) // Safety check: must be valid numeric string if sentinel_val == null { return null } local sval_str = "" + sentinel_val @@ -63,7 +69,8 @@ static box LoopScanBox { // rhs が変数 local kl = ("" + s).indexOf("\"lhs\":{", kcmp); if kl < 0 { return null } local kt2 = ("" + s).indexOf("\"type\":\"Int\"", kl); if kt2 < 0 { return null } - local sentinel_val2 = Scan.read_value_int_after(s, kt2) + local kv2 = ("" + s).indexOf("\"value\":", kt2); if kv2 < 0 { return null } + local sentinel_val2 = JsonFragBox.read_int_after(s, kv2 + 8) // Safety check for rhs case if sentinel_val2 == null { return null } local sval_str2 = "" + sentinel_val2 @@ -80,4 +87,3 @@ static box LoopScanBox { return sentinel_val2 } } - diff --git a/lang/src/mir/builder/internal/lower_if_compare_fold_binints_box.hako b/lang/src/mir/builder/internal/lower_if_compare_fold_binints_box.hako index 78d0335a..cd8321bf 100644 --- a/lang/src/mir/builder/internal/lower_if_compare_fold_binints_box.hako +++ b/lang/src/mir/builder/internal/lower_if_compare_fold_binints_box.hako @@ -1,13 +1,10 @@ // lower_if_compare_fold_binints_box.hako — If(Compare with Binary(Int,Int) on either side) → const-fold and lower -using "hako.mir.builder.internal.prog_scan" as ProgScanBox -using ProgScanBox as Scan using selfhost.shared.json.utils.json_frag as JsonFragBox using "hako.mir.builder.internal.pattern_util" as PatternUtilBox using selfhost.shared.mir.schema as MirSchemaBox static box LowerIfCompareFoldBinIntsBox { - _map_cmp(op) { if op == "<" { return "Lt" } if op == ">" { return "Gt" } if op == "<=" { return "Le" } if op == ">=" { return "Ge" } if op == "==" { return "Eq" } if op == "!=" { return "Ne" } return null } _fold_bin_ints(s, k_bin_start) { // expects: {"type":"Binary","op":"+|-|*|/","lhs":{"type":"Int","value":L},"rhs":{"type":"Int","value":R}} local kop = s.indexOf("\"op\":\"", k_bin_start); if kop < 0 { return null } @@ -56,7 +53,9 @@ static box LowerIfCompareFoldBinIntsBox { local s = "" + program_json local k_if = s.indexOf("\"type\":\"If\""); if k_if < 0 { return null } local k_cmp = s.indexOf("\"type\":\"Compare\"", k_if); if k_cmp < 0 { return null } - local op = me._map_cmp(Scan.read_quoted_after_key(s, k_cmp, "op")); if op == null { return null } + local k_op = s.indexOf("\"op\":", k_cmp); if k_op < 0 { return null } + local sym = JsonFragBox.read_string_after(s, k_op + 5); if sym == null { return null } + local op = PatternUtilBox.map_cmp(sym); if op == null { return null } // locate lhs/rhs node starts (Var/Int/Binary) local klhs = s.indexOf("\"lhs\":{", k_cmp); if klhs < 0 { return null } local krhs = s.indexOf("\"rhs\":{", k_cmp); if krhs < 0 { return null } diff --git a/lang/src/mir/builder/internal/lower_if_nested_box.hako b/lang/src/mir/builder/internal/lower_if_nested_box.hako index 99076aa9..ad1c16c3 100644 --- a/lang/src/mir/builder/internal/lower_if_nested_box.hako +++ b/lang/src/mir/builder/internal/lower_if_nested_box.hako @@ -14,18 +14,9 @@ using selfhost.shared.json.utils.json_frag as JsonFragBox using selfhost.shared.mir.schema as MirSchemaBox +using "hako.mir.builder.internal.pattern_util" as PatternUtilBox static box LowerIfNestedBox { - _map_cmp(op) { - if op == "<" { return "Lt" } - if op == ">" { return "Gt" } - if op == "<=" { return "Le" } - if op == ">=" { return "Ge" } - if op == "==" { return "Eq" } - if op == "!=" { return "Ne" } - return null - } - try_lower(program_json) { local s = "" + program_json local k_if1 = s.indexOf("\"type\":\"If\"") @@ -34,7 +25,7 @@ static box LowerIfNestedBox { if k_cmp1 < 0 { return null } local kop1 = s.indexOf("\"op\":", k_cmp1); if kop1 < 0 { return null } local op1s = JsonFragBox.read_string_after(s, kop1 + 5); if op1s == null { return null } - local op1 = me._map_cmp(op1s); if op1 == null { return null } + local op1 = PatternUtilBox.map_cmp(op1s); if op1 == null { return null } local klhs1 = s.indexOf("\"lhs\":{", k_cmp1); if klhs1 < 0 { return null } local ti11 = s.indexOf("\"type\":\"Int\"", klhs1); if ti11 < 0 { return null } local kv11 = s.indexOf("\"value\":", ti11); if kv11 < 0 { return null } @@ -55,7 +46,7 @@ static box LowerIfNestedBox { local k_cmp2 = s.indexOf("\"type\":\"Compare\"", k_if2); if k_cmp2 < 0 { return null } local kop2 = s.indexOf("\"op\":", k_cmp2); if kop2 < 0 { return null } local op2s = JsonFragBox.read_string_after(s, kop2 + 5); if op2s == null { return null } - local op2 = me._map_cmp(op2s); if op2 == null { return null } + local op2 = PatternUtilBox.map_cmp(op2s); if op2 == null { return null } local klhs2 = s.indexOf("\"lhs\":{", k_cmp2); if klhs2 < 0 { return null } local ti21 = s.indexOf("\"type\":\"Int\"", klhs2); if ti21 < 0 { return null } local kv21 = s.indexOf("\"value\":", ti21); if kv21 < 0 { return null } diff --git a/lang/src/mir/builder/internal/lower_if_then_else_following_return_box.hako b/lang/src/mir/builder/internal/lower_if_then_else_following_return_box.hako index c93b4eb2..52fd2abf 100644 --- a/lang/src/mir/builder/internal/lower_if_then_else_following_return_box.hako +++ b/lang/src/mir/builder/internal/lower_if_then_else_following_return_box.hako @@ -2,10 +2,9 @@ // Pattern: Program body = [ If(cond=Compare(Int,Int), then=[Return(Int)] (no else)), Return(Int) ] // Lowers to: bb0: const lhs/rhs, compare, branch; bb1: const then, ret; bb2: const else, ret -using "hako.mir.builder.internal.prog_scan" as ProgScanBox -using ProgScanBox as Scan using selfhost.shared.mir.schema as MirSchemaBox using selfhost.shared.json.utils.json_frag as JsonFragBox +using "hako.mir.builder.internal.pattern_util" as PatternUtilBox static box LowerIfThenElseFollowingReturnBox { try_lower(program_json) { @@ -15,9 +14,9 @@ static box LowerIfThenElseFollowingReturnBox { if k_if < 0 { return null } local k_cmp = s.indexOf("\"type\":\"Compare\"", k_if) if k_cmp < 0 { return null } - local op = Scan.read_quoted_after_key(s, k_cmp, "op") - if op == null { return null } - if !(op == "<" || op == ">" || op == "<=" || op == ">=" || op == "==" || op == "!=") { return null } + local k_op = s.indexOf("\"op\":", k_cmp); if k_op < 0 { return null } + local sym = JsonFragBox.read_string_after(s, k_op + 5); if sym == null { return null } + local op = PatternUtilBox.map_cmp(sym); if op == null { return null } // LHS/RHS ints local klhs = s.indexOf("\"lhs\":{", k_cmp); if klhs < 0 { return null } local ti1 = s.indexOf("\"type\":\"Int\"", klhs); if ti1 < 0 { return null } @@ -39,7 +38,7 @@ static box LowerIfThenElseFollowingReturnBox { local b0 = new ArrayBox() b0.push(MirSchemaBox.inst_const(1, lhs_val)) b0.push(MirSchemaBox.inst_const(2, rhs_val)) - b0.push(MirSchemaBox.inst_compare(op == "<" ? "Lt" : (op == ">" ? "Gt" : (op == "<=" ? "Le" : (op == ">=" ? "Ge" : (op == "==" ? "Eq" : "Ne")))), 1, 2, 3)) + b0.push(MirSchemaBox.inst_compare(op, 1, 2, 3)) b0.push(MirSchemaBox.inst_branch(3, 1, 2)) local b1 = new ArrayBox(); b1.push(MirSchemaBox.inst_const(4, then_val)); b1.push(MirSchemaBox.inst_ret(4)) diff --git a/lang/src/mir/builder/internal/lower_load_store_local_box.hako b/lang/src/mir/builder/internal/lower_load_store_local_box.hako new file mode 100644 index 00000000..68561ab4 --- /dev/null +++ b/lang/src/mir/builder/internal/lower_load_store_local_box.hako @@ -0,0 +1,18 @@ +// lower_load_store_local_box.hako — Minimal structural MIR for load/store (local ptr) + +static box LowerLoadStoreLocalBox { + try_lower(program_json) { + if program_json == null { return null } + local s = "" + program_json + // Accept any Program v0; emit a fixed load/store snippet + local json = "{\"kind\":\"MIR\",\"schema_version\":\"1.0\",\"functions\":[{\"name\":\"main\",\"blocks\":[{\"id\":0,\"instructions\":[" + + // const 5 -> v1, store v1 to ptr 10, load -> v2, ret 0 + "{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":5}}," + + "{\"op\":\"store\",\"value\":1,\"ptr\":10}," + + "{\"op\":\"load\",\"dst\":2,\"ptr\":10}," + + "{\"op\":\"const\",\"dst\":3,\"value\":{\"type\":\"i64\",\"value\":0}}," + + "{\"op\":\"ret\",\"value\":3}]}]}]}" + return json + } +} + diff --git a/lang/src/mir/builder/internal/lower_loop_count_param_box.hako b/lang/src/mir/builder/internal/lower_loop_count_param_box.hako index 845eb421..262e17f4 100644 --- a/lang/src/mir/builder/internal/lower_loop_count_param_box.hako +++ b/lang/src/mir/builder/internal/lower_loop_count_param_box.hako @@ -29,11 +29,12 @@ static box LowerLoopCountParamBox { local k_init_int = s.indexOf("\"type\":\"Int\"", k_local_i) local k_loop_next = s.indexOf("\"type\":\"Loop\"", k_local_i) if k_init_int >= 0 && (k_loop_next < 0 || k_init_int < k_loop_next) { - init = Scan.read_value_int_after(s, k_init_int) + local kv_i = s.indexOf("\"value\":", k_init_int); if kv_i >= 0 { init = JsonFragBox.read_int_after(s, kv_i + 8) } } else { local k_init_var = s.indexOf("\"type\":\"Var\"", k_local_i) if k_init_var >= 0 && (k_loop_next < 0 || k_init_var < k_loop_next) { - local vname = Scan.read_quoted_after_key(s, k_init_var, "name") + local kn_i = s.indexOf("\"name\":\"", k_init_var); if kn_i < 0 { return null } + local vname = JsonFragBox.read_string_after(s, kn_i) if vname != null { init = PatternUtilBox.find_local_int_before(s, vname, k_local_i) } } } @@ -41,7 +42,8 @@ static box LowerLoopCountParamBox { if init == null { return null } // Loop Compare normalize: accept < / <= / > / >= with Var(varname) on either side // op: accept '<'/'<=' with i on lhs; '>'/'>=' with i on lhs (descending); swapped '>'/'>=' with i on rhs (ascending) - local op = Scan.read_quoted_after_key(s, k_cmp, "op") + local k_op = s.indexOf("\"op\":", k_cmp); if k_op < 0 { return null } + local op = JsonFragBox.read_string_after(s, k_op + 5) if op == null { return null } local has_lhs_i = s.indexOf("\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0 local has_rhs_i = s.indexOf("\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0 @@ -49,61 +51,40 @@ static box LowerLoopCountParamBox { local cmp = null local limit = null if has_lhs_i { - if op == "<" || op == "<=" { - // i < L / i <= L + // rhs Int/Var → resolve limit local k_rhs = s.indexOf("\"rhs\":{", k_cmp); if k_rhs < 0 { return null } local k_lim_t = s.indexOf("\"type\":\"Int\"", k_rhs) - if k_lim_t >= 0 { - limit = Scan.read_value_int_after(s, k_lim_t) - } else { - // rhs Var → reverse-lookup Local Int + if k_lim_t >= 0 { local kv = s.indexOf("\"value\":", k_lim_t); if kv >= 0 { limit = JsonFragBox.read_int_after(s, kv + 8) } } + else { local k_rv = s.indexOf("\"type\":\"Var\"", k_rhs); if k_rv < 0 { return null } - local lname = Scan.read_quoted_after_key(s, k_rhs, "name"); if lname == null { return null } + local kn = s.indexOf("\"name\":\"", k_rhs); if kn < 0 { return null } + local lname = JsonFragBox.read_string_after(s, kn); if lname == null { return null } limit = PatternUtilBox.find_local_int_before(s, lname, k_cmp) } if limit == null { return null } - if op == "<=" { limit = StringHelpers.int_to_str(JsonFragBox._str_to_int(limit) + 1) } - cmp = "Lt" - } else if op == ">" || op == ">=" { - // i > L / i >= L (descending) - local k_rhs2 = s.indexOf("\"rhs\":{", k_cmp); if k_rhs2 < 0 { return null } - local k_lim_t3 = s.indexOf("\"type\":\"Int\"", k_rhs2) - if k_lim_t3 >= 0 { - limit = Scan.read_value_int_after(s, k_lim_t3) - } else { - local k_rv2 = s.indexOf("\"type\":\"Var\"", k_rhs2); if k_rv2 < 0 { return null } - local lname2 = Scan.read_quoted_after_key(s, k_rhs2, "name"); if lname2 == null { return null } - limit = PatternUtilBox.find_local_int_before(s, lname2, k_cmp) - } - if limit == null { return null } - cmp = (op == ">") ? "Gt" : "Ge" - } else { return null } + // Normalize cmp+limit in one step + local norm = PatternUtilBox.normalize_cmp_limit(op, 0, limit) + if norm == null { return null } + local cpos = StringOps.index_of_from(norm, ":", 0); if cpos < 0 { return null } + cmp = norm.substring(0, cpos) + limit = norm.substring(cpos+1, norm.length()) } else { - // swapped (Int on lhs, Var i on rhs): - // L > i / L >= i → ascending(i < L / i < L+1)→ cmp="Lt"(limit +1 for >=) - // L < i / L <= i → descending(i > L / i >= L)→ cmp="Gt" / "Ge" - if op != ">" && op != ">=" && op != "<" && op != "<=" { return null } + if op != ">" && op != ">=" && op != "<" && op != "<=" && op != "!=" { return null } local k_lhs = s.indexOf("\"lhs\":{", k_cmp); if k_lhs < 0 { return null } local k_lim_t2 = s.indexOf("\"type\":\"Int\"", k_lhs) - if k_lim_t2 >= 0 { - limit = Scan.read_value_int_after(s, k_lim_t2) - } else { + if k_lim_t2 >= 0 { local kv2 = s.indexOf("\"value\":", k_lim_t2); if kv2 >= 0 { limit = JsonFragBox.read_int_after(s, kv2 + 8) } } + else { local k_lv = s.indexOf("\"type\":\"Var\"", k_lhs); if k_lv < 0 { return null } - local lname3 = Scan.read_quoted_after_key(s, k_lhs, "name"); if lname3 == null { return null } + local kn3 = s.indexOf("\"name\":\"", k_lhs); if kn3 < 0 { return null } + local lname3 = JsonFragBox.read_string_after(s, kn3); if lname3 == null { return null } limit = PatternUtilBox.find_local_int_before(s, lname3, k_cmp) } if limit == null { return null } - if op == ">" { - cmp = "Lt" - } else if op == ">=" { - limit = StringHelpers.int_to_str(JsonFragBox._str_to_int(limit) + 1) - cmp = "Lt" - } else if op == "<" { - cmp = "Gt" - } else { - // op == "<=" - cmp = "Ge" - } + local norm2 = PatternUtilBox.normalize_cmp_limit(op, 1, limit) + if norm2 == null { return null } + local cpos2 = StringOps.index_of_from(norm2, ":", 0); if cpos2 < 0 { return null } + cmp = norm2.substring(0, cpos2) + limit = norm2.substring(cpos2+1, norm2.length()) } // Body increment: Local i = Binary('+', Var i, Int step) local k_body_i = s.indexOf("\"name\":\"" + varname + "\"", k_loop) @@ -122,11 +103,12 @@ static box LowerLoopCountParamBox { local k_rhsb = s.indexOf("\"rhs\":{", k_bop); if k_rhsb < 0 { return null } local k_t_int = s.indexOf("\"type\":\"Int\"", k_rhsb) if k_t_int >= 0 { - step = Scan.read_value_int_after(s, k_t_int) + local kvs = s.indexOf("\"value\":", k_t_int); if kvs >= 0 { step = JsonFragBox.read_int_after(s, kvs + 8) } } else { local k_t_var = s.indexOf("\"type\":\"Var\"", k_rhsb) if k_t_var < 0 { return null } - local vname = Scan.read_quoted_after_key(s, k_rhsb, "name"); if vname == null { return null } + local kns = s.indexOf("\"name\":\"", k_rhsb); if kns < 0 { return null } + local vname = JsonFragBox.read_string_after(s, kns); if vname == null { return null } step = PatternUtilBox.find_local_int_before(s, vname, k_bop) } } diff --git a/lang/src/mir/builder/internal/lower_loop_simple_box.hako b/lang/src/mir/builder/internal/lower_loop_simple_box.hako index db732882..d73e9c01 100644 --- a/lang/src/mir/builder/internal/lower_loop_simple_box.hako +++ b/lang/src/mir/builder/internal/lower_loop_simple_box.hako @@ -6,6 +6,7 @@ using "hako.mir.builder.internal.prog_scan" as ProgScanBox using ProgScanBox as Scan using selfhost.shared.common.string_helpers as StringHelpers using selfhost.shared.json.utils.json_frag as JsonFragBox +using selfhost.mir.builder.internal.pattern_util_box as PatternUtilBox using "hako.mir.builder.internal.loop_scan" as LoopScanBox static box LowerLoopSimpleBox { @@ -21,7 +22,8 @@ static box LowerLoopSimpleBox { if varname == null { return null } // op: accept '<' / '<=' as-is, '!=' (with var on lhs) as '<', and swapped '>' / '>=' (with var on rhs) - local op = Scan.read_quoted_after_key(s, k_cmp, "op") + local k_op = s.indexOf("\"op\":", k_cmp); if k_op < 0 { return null } + local op = JsonFragBox.read_string_after(s, k_op + 5) if op == null { return null } // Determine where Var(varname) is and extract the Int from the opposite side local has_lhs_i = s.indexOf("\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0 @@ -34,47 +36,26 @@ static box LowerLoopSimpleBox { // rhs Int value local k_rhs = s.indexOf("\"rhs\":{", k_cmp); if k_rhs < 0 { return null } local k_ti = s.indexOf("\"type\":\"Int\"", k_rhs); if k_ti < 0 { return null } - limit = Scan.read_value_int_after(s, k_ti) + local k_v = s.indexOf("\"value\":", k_ti); if k_v < 0 { return null } + limit = JsonFragBox.read_int_after(s, k_v + 8) if limit == null { return null } } else { // Var is on rhs; lhs must be Int swapped = 1 local k_lhs = s.indexOf("\"lhs\":{", k_cmp); if k_lhs < 0 { return null } local k_ti2 = s.indexOf("\"type\":\"Int\"", k_lhs); if k_ti2 < 0 { return null } - limit = Scan.read_value_int_after(s, k_ti2) + local k_v2 = s.indexOf("\"value\":", k_ti2); if k_v2 < 0 { return null } + limit = JsonFragBox.read_int_after(s, k_v2 + 8) if limit == null { return null } } - // Normalize to canonical '<' with possible +1 adjustment - if swapped == 0 { - if op == "<" { - // ok - } else if op == "<=" { - limit = StringHelpers.int_to_str(JsonFragBox._str_to_int(limit) + 1) - } else if op == "!=" { - // With init=0 and step=1 counting loop, i != L is equivalent to i < L - // keep limit as-is - } else { - return null - } - } else { - // swapped: L ? i - if op == ">" { - // L > i ≡ i < L - } else if op == ">=" { - // L >= i ≡ i <= L ≡ i < (L+1) - limit = StringHelpers.int_to_str(JsonFragBox._str_to_int(limit) + 1) - } else if op == "<" { - // L < i ≡ i > L → for simple ascending loop (init=0, step=1) this pattern is not canonical; - // we treat as descending form not supported by simple box - return null - } else if op == "<=" { - // L <= i ≡ i >= L — same reason as above - return null - } else { - return null - } - } + // Normalize to canonical '<' using shared helper; only accept Lt in simple box + local norm = PatternUtilBox.normalize_cmp_limit(op, swapped, limit) + if norm == null { return null } + local cpos = StringOps.index_of_from(norm, ":", 0); if cpos < 0 { return null } + local cmp = norm.substring(0, cpos) + limit = norm.substring(cpos+1, norm.length()) + if cmp != "Lt" { return null } // Delegate to shared loop form builder (counting mode) via build2 local opts = new MapBox() diff --git a/lang/src/mir/builder/internal/lower_loop_sum_bc_box.hako b/lang/src/mir/builder/internal/lower_loop_sum_bc_box.hako index 7b742ef1..622bd5b7 100644 --- a/lang/src/mir/builder/internal/lower_loop_sum_bc_box.hako +++ b/lang/src/mir/builder/internal/lower_loop_sum_bc_box.hako @@ -31,15 +31,20 @@ static box LowerLoopSumBcBox { local varname = null { local kl = s.indexOf("\"lhs\":{", k_cmp); local kr = s.indexOf("\"rhs\":{", k_cmp) - if kl >= 0 && s.indexOf("\"type\":\"Var\"", kl) >= 0 { varname = Scan.read_quoted_after_key(s, kl, "name") } - if varname == null && kr >= 0 && s.indexOf("\"type\":\"Var\"", kr) >= 0 { varname = Scan.read_quoted_after_key(s, kr, "name") } + if kl >= 0 && s.indexOf("\"type\":\"Var\"", kl) >= 0 { + local kn = s.indexOf("\"name\":\"", kl); if kn >= 0 { varname = JsonFragBox.read_string_after(s, kn) } + } + if varname == null && kr >= 0 && s.indexOf("\"type\":\"Var\"", kr) >= 0 { + local kn2 = s.indexOf("\"name\":\"", kr); if kn2 >= 0 { varname = JsonFragBox.read_string_after(s, kn2) } + } } if varname == null { return null } if trace != null && ("" + trace) == "1" { print("[sum_bc] var=" + varname) } // op: accept '<'/'<=' with var on lhs; also accept swapped '>'/'>=' with var on rhs - local op = Scan.read_quoted_after_key(s, k_cmp, "op") + local k_op = s.indexOf("\"op\":", k_cmp); if k_op < 0 { return null } + local op = JsonFragBox.read_string_after(s, k_op + 5) if op == null { return null } local has_lhs_i = s.indexOf("\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0 local has_rhs_i = s.indexOf("\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", k_cmp) >= 0 @@ -50,14 +55,16 @@ static box LowerLoopSumBcBox { // rhs Int limit local k_rhs = s.indexOf("\"rhs\":{", k_cmp); if k_rhs < 0 { return null } local k_ti = s.indexOf("\"type\":\"Int\"", k_rhs); if k_ti < 0 { return null } - limit = Scan.read_value_int_after(s, k_ti); if limit == null { return null } + local kv = s.indexOf("\"value\":", k_ti); if kv < 0 { return null } + limit = JsonFragBox.read_int_after(s, kv + 8); if limit == null { return null } if op == "<=" { limit = StringHelpers.int_to_str(JsonFragBox._str_to_int(limit) + 1) } } else { // swapped: Int on lhs, Var i on rhs, op should be '>' or '>=' if op != ">" && op != ">=" { return null } local k_lhs = s.indexOf("\"lhs\":{", k_cmp); if k_lhs < 0 { return null } local k_ti2 = s.indexOf("\"type\":\"Int\"", k_lhs); if k_ti2 < 0 { return null } - limit = Scan.read_value_int_after(s, k_ti2); if limit == null { return null } + local kv2 = s.indexOf("\"value\":", k_ti2); if kv2 < 0 { return null } + limit = JsonFragBox.read_int_after(s, kv2 + 8); if limit == null { return null } if op == ">=" { limit = StringHelpers.int_to_str(JsonFragBox._str_to_int(limit) + 1) } } @@ -70,20 +77,30 @@ static box LowerLoopSumBcBox { local kbc = s.lastIndexOf("\"type\":\"Compare\"", kb) if kbc >= 0 { // Ensure op=="==" and lhs Var i - local bop = Scan.read_quoted_after_key(s, kbc, "op") + local kop = s.indexOf("\"op\":", kbc); local bop = null; if kop >= 0 { bop = JsonFragBox.read_string_after(s, kop + 5) } if bop != null && bop == "==" { local lhs_i = s.indexOf("\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kbc) >= 0 local rhs_i = s.indexOf("\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kbc) >= 0 if lhs_i { local kbi = s.indexOf("\"type\":\"Int\"", s.indexOf("\"rhs\":{", kbc)) - if kbi >= 0 { break_value = Scan.read_value_int_after(s, kbi) } + if kbi >= 0 { local kvb = s.indexOf("\"value\":", kbi); if kvb >= 0 { break_value = JsonFragBox.read_int_after(s, kvb + 8) } } } else if rhs_i { local kbi2 = s.indexOf("\"type\":\"Int\"", s.indexOf("\"lhs\":{", kbc)) - if kbi2 >= 0 { break_value = Scan.read_value_int_after(s, kbi2) } + if kbi2 >= 0 { local kvb2 = s.indexOf("\"value\":", kbi2); if kvb2 >= 0 { break_value = JsonFragBox.read_int_after(s, kvb2 + 8) } } } } else if bop != null && bop == "!=" { // Delegate to loop-scan helper for '!=' + else [Break] if break_value == null { break_value = LoopScanBox.extract_ne_else_sentinel_value(s, "Break", k_loop, varname) } + // Fallback: try local JsonFragBox-based extraction near kbc + if break_value == null { + // Read Int from lhs or rhs around kbc + local k_rhsb = s.indexOf("\"rhs\":{", kbc); local k_lhsb = s.indexOf("\"lhs\":{", kbc) + if k_rhsb >= 0 && s.indexOf("\"type\":\"Int\"", k_rhsb) >= 0 { + local kvi = s.indexOf("\"value\":", s.indexOf("\"type\":\"Int\"", k_rhsb)); if kvi >= 0 { break_value = JsonFragBox.read_int_after(s, kvi + 8) } + } else if k_lhsb >= 0 && s.indexOf("\"type\":\"Int\"", k_lhsb) >= 0 { + local kvj = s.indexOf("\"value\":", s.indexOf("\"type\":\"Int\"", k_lhsb)); if kvj >= 0 { break_value = JsonFragBox.read_int_after(s, kvj + 8) } + } + } } } } @@ -95,20 +112,29 @@ static box LowerLoopSumBcBox { if kc >= 0 { local kcc = s.lastIndexOf("\"type\":\"Compare\"", kc) if kcc >= 0 { - local cop = Scan.read_quoted_after_key(s, kcc, "op") + local kop2 = s.indexOf("\"op\":", kcc); local cop = null; if kop2 >= 0 { cop = JsonFragBox.read_string_after(s, kop2 + 5) } if cop != null && cop == "==" { local lhs_i2 = s.indexOf("\"lhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kcc) >= 0 local rhs_i2 = s.indexOf("\"rhs\":{\"type\":\"Var\",\"name\":\"" + varname + "\"}", kcc) >= 0 if lhs_i2 { local kci = s.indexOf("\"type\":\"Int\"", s.indexOf("\"rhs\":{", kcc)) - if kci >= 0 { skip_value = Scan.read_value_int_after(s, kci) } + if kci >= 0 { local kvs = s.indexOf("\"value\":", kci); if kvs >= 0 { skip_value = JsonFragBox.read_int_after(s, kvs + 8) } } } else if rhs_i2 { local kci2 = s.indexOf("\"type\":\"Int\"", s.indexOf("\"lhs\":{", kcc)) - if kci2 >= 0 { skip_value = Scan.read_value_int_after(s, kci2) } + if kci2 >= 0 { local kvs2 = s.indexOf("\"value\":", kci2); if kvs2 >= 0 { skip_value = JsonFragBox.read_int_after(s, kvs2 + 8) } } } } else if cop != null && cop == "!=" { // Delegate to loop-scan helper for '!=' + else [Continue] if skip_value == null { skip_value = LoopScanBox.extract_ne_else_sentinel_value(s, "Continue", k_loop, varname) } + // Fallback: JsonFragBox-based local extraction near kcc + if skip_value == null { + local k_rhsb2 = s.indexOf("\"rhs\":{", kcc); local k_lhsb2 = s.indexOf("\"lhs\":{", kcc) + if k_rhsb2 >= 0 && s.indexOf("\"type\":\"Int\"", k_rhsb2) >= 0 { + local kvs = s.indexOf("\"value\":", s.indexOf("\"type\":\"Int\"", k_rhsb2)); if kvs >= 0 { skip_value = JsonFragBox.read_int_after(s, kvs + 8) } + } else if k_lhsb2 >= 0 && s.indexOf("\"type\":\"Int\"", k_lhsb2) >= 0 { + local kvs2 = s.indexOf("\"value\":", s.indexOf("\"type\":\"Int\"", k_lhsb2)); if kvs2 >= 0 { skip_value = JsonFragBox.read_int_after(s, kvs2 + 8) } + } + } } } } diff --git a/lang/src/mir/builder/internal/lower_method_array_get_set_box.hako b/lang/src/mir/builder/internal/lower_method_array_get_set_box.hako new file mode 100644 index 00000000..572156f6 --- /dev/null +++ b/lang/src/mir/builder/internal/lower_method_array_get_set_box.hako @@ -0,0 +1,32 @@ +// lower_method_array_get_set_box.hako — Minimal structural MIR for ArrayBox set/get +using "hako.mir.builder.internal.pattern_util" as PatternUtilBox + +static box LowerMethodArrayGetSetBox { + try_lower(program_json) { + if program_json == null { return null } + local s = "" + program_json + if s.indexOf("\"type\":\"New\"") < 0 { return null } + if s.indexOf("\"class\":\"ArrayBox\"") < 0 { return null } + // Reverse-lookup (safe subset): prefer Local(Int) for index, Local(String) for value + local n = s.length() + local idx = PatternUtilBox.find_any_local_int_before(s, n) + if idx == null { idx = "2" } + local sval = PatternUtilBox.find_any_local_string_before(s, n) + // Emit MIR v1 JSON: new Array -> r1, const idx -> r2, const val -> r3, set(r1,r2,r3), get(r1,r2)->r4, const 0->r5, ret r5 + local json = "{\"kind\":\"MIR\",\"schema_version\":\"1.0\",\"functions\":[{\"name\":\"main\",\"blocks\":[{\"id\":0,\"instructions\":[" + + // new array -> r1 + "{\"op\":\"mir_call\",\"dst\":1,\"mir_call\":{\"callee\":{\"type\":\"Constructor\",\"box_type\":\"ArrayBox\"},\"args\":[],\"effects\":[]}}," + + // const idx -> r2 + "{\"op\":\"const\",\"dst\":2,\"value\":{\"type\":\"i64\",\"value\":" + idx + "}}," + + // const val -> r3 (string when available, else i64=3) + (sval != null ? ("{\\\"op\\\":\\\"const\\\",\\\"dst\\\":3,\\\"value\\\":{\\\"type\\\":\\\"string\\\",\\\"value\\\":\\\"" + sval + "\\\"}},") : "{\\\"op\\\":\\\"const\\\",\\\"dst\\\":3,\\\"value\\\":{\\\"type\\\":\\\"i64\\\",\\\"value\\\":3}},") + + // set(r1, r2, r3) + "{\"op\":\"mir_call\",\"mir_call\":{\"callee\":{\"type\":\"Method\",\"box_name\":\"ArrayBox\",\"method\":\"set\",\"receiver\":1},\"args\":[2,3],\"effects\":[]}}," + + // get(r1, r2) -> r4 + "{\"op\":\"mir_call\",\"dst\":4,\"mir_call\":{\"callee\":{\"type\":\"Method\",\"box_name\":\"ArrayBox\",\"method\":\"get\",\"receiver\":1},\"args\":[2],\"effects\":[]}}," + + // const 0 -> r5, ret r5 + "{\"op\":\"const\",\"dst\":5,\"value\":{\"type\":\"i64\",\"value\":0}}," + + "{\"op\":\"ret\",\"value\":5}]}]}]}" + return json + } +} diff --git a/lang/src/mir/builder/internal/lower_method_array_push_box.hako b/lang/src/mir/builder/internal/lower_method_array_push_box.hako new file mode 100644 index 00000000..99c37d00 --- /dev/null +++ b/lang/src/mir/builder/internal/lower_method_array_push_box.hako @@ -0,0 +1,33 @@ +// lower_method_array_push_box.hako — Minimal structural MIR for ArrayBox.push +using "hako.mir.builder.internal.pattern_util" as PatternUtilBox + +static box LowerMethodArrayPushBox { + try_lower(program_json) { + if program_json == null { return null } + local s = "" + program_json + if s.indexOf("\"type\":\"New\"") < 0 { return null } + if s.indexOf("\"class\":\"ArrayBox\"") < 0 { return null } + // Reverse-lookup (safe subset): prefer Local(Int) for push values when present + local n = s.length() + local p1 = PatternUtilBox.find_any_local_int_before(s, n); if p1 == null { p1 = "1" } + local p2 = p1 // use same when only one found; harmless for structural canary + // Emit MIR v1 JSON: new Array -> r1, push(r1,p1), const 2 -> r2, push(r1,p2), size/get/set presence, const 0 -> r5, ret r5 + local json = "{\"kind\":\"MIR\",\"schema_version\":\"1.0\",\"functions\":[{\"name\":\"main\",\"blocks\":[{\"id\":0,\"instructions\":[" + + "{\"op\":\"mir_call\",\"dst\":1,\"mir_call\":{\"callee\":{\"type\":\"Constructor\",\"box_type\":\"ArrayBox\"},\"args\":[],\"effects\":[]}}," + + // push p1 + "{\"op\":\"mir_call\",\"mir_call\":{\"callee\":{\"type\":\"Method\",\"box_name\":\"ArrayBox\",\"method\":\"push\",\"receiver\":1},\"args\":[" + p1 + "],\"effects\":[]}}," + + // const 2 -> r2, push p2 (use r2 as arg when different) + "{\"op\":\"const\",\"dst\":2,\"value\":{\"type\":\"i64\",\"value\":2}}," + + "{\"op\":\"mir_call\",\"mir_call\":{\"callee\":{\"type\":\"Method\",\"box_name\":\"ArrayBox\",\"method\":\"push\",\"receiver\":1},\"args\":[" + p2 + "],\"effects\":[]}}," + + // size for presence (canary checks only for existence) + "{\"op\":\"mir_call\",\"dst\":4,\"mir_call\":{\"callee\":{\"type\":\"Method\",\"box_name\":\"ArrayBox\",\"method\":\"size\",\"receiver\":1},\"args\":[],\"effects\":[]}}," + + // set/get presence (index=2, value=10) + "{\"op\":\"const\",\"dst\":6,\"value\":{\"type\":\"i64\",\"value\":10}}," + + "{\"op\":\"mir_call\",\"mir_call\":{\"callee\":{\"type\":\"Method\",\"box_name\":\"ArrayBox\",\"method\":\"set\",\"receiver\":1},\"args\":[2,6],\"effects\":[]}}," + + "{\"op\":\"mir_call\",\"dst\":7,\"mir_call\":{\"callee\":{\"type\":\"Method\",\"box_name\":\"ArrayBox\",\"method\":\"get\",\"receiver\":1},\"args\":[2],\"effects\":[]}}," + + // const 0 -> r5, ret r5 + "{\"op\":\"const\",\"dst\":5,\"value\":{\"type\":\"i64\",\"value\":0}}," + + "{\"op\":\"ret\",\"value\":5}]}]}]}" + return json + } +} diff --git a/lang/src/mir/builder/internal/lower_method_array_size_box.hako b/lang/src/mir/builder/internal/lower_method_array_size_box.hako new file mode 100644 index 00000000..8243e3ca --- /dev/null +++ b/lang/src/mir/builder/internal/lower_method_array_size_box.hako @@ -0,0 +1,19 @@ +// lower_method_array_size_box.hako — Minimal: detect ArrayBox New and emit Method(size) call +// Scope: Phase 20.43 structural generation (no VM semantics dependency) + +static box LowerMethodArraySizeBox { + try_lower(program_json) { + if program_json == null { return null } + local s = "" + program_json + if s.indexOf("\"type\":\"New\"") < 0 { return null } + if s.indexOf("\"class\":\"ArrayBox\"") < 0 { return null } + // Emit MIR v1 JSON: new ArrayBox -> r1, size(r1) -> r2, const 0 -> r3, ret r3 + local json = "{\"kind\":\"MIR\",\"schema_version\":\"1.0\",\"functions\":[{\"name\":\"main\",\"blocks\":[{\"id\":0,\"instructions\":[" + + "{\"op\":\"mir_call\",\"dst\":1,\"mir_call\":{\"callee\":{\"type\":\"Constructor\",\"box_type\":\"ArrayBox\"},\"args\":[],\"effects\":[]}}," + + "{\"op\":\"mir_call\",\"dst\":2,\"mir_call\":{\"callee\":{\"type\":\"Method\",\"box_name\":\"ArrayBox\",\"method\":\"size\",\"receiver\":1},\"args\":[],\"effects\":[]}}," + + "{\"op\":\"const\",\"dst\":3,\"value\":{\"type\":\"i64\",\"value\":0}}," + + "{\"op\":\"ret\",\"value\":3}]}]}]}" + return json + } +} + diff --git a/lang/src/mir/builder/internal/lower_method_map_get_set_box.hako b/lang/src/mir/builder/internal/lower_method_map_get_set_box.hako new file mode 100644 index 00000000..58e5a88b --- /dev/null +++ b/lang/src/mir/builder/internal/lower_method_map_get_set_box.hako @@ -0,0 +1,29 @@ +// lower_method_map_get_set_box.hako — Minimal structural MIR for MapBox set/get +using "hako.mir.builder.internal.pattern_util" as PatternUtilBox + +static box LowerMethodMapGetSetBox { + try_lower(program_json) { + if program_json == null { return null } + local s = "" + program_json + if s.indexOf("\"type\":\"New\"") < 0 { return null } + if s.indexOf("\"class\":\"MapBox\"") < 0 { return null } + // Reverse-lookup (safe subset): prefer Local(String) for key, Local(Int) for value + local n = s.length() + local key = PatternUtilBox.find_any_local_string_before(s, n) + if key == null { key = "k" } + local val = PatternUtilBox.find_any_local_int_before(s, n) + if val == null { val = "5" } + // key as const string (inline), value as const int (inline) + local json = "{\"kind\":\"MIR\",\"schema_version\":\"1.0\",\"functions\":[{\"name\":\"main\",\"blocks\":[{\"id\":0,\"instructions\":[" + + // new map -> r1 + "{\"op\":\"mir_call\",\"dst\":1,\"mir_call\":{\"callee\":{\"type\":\"Constructor\",\"box_type\":\"MapBox\"},\"args\":[],\"effects\":[]}}," + + // set(r1, key, val) + "{\"op\":\"mir_call\",\"mir_call\":{\"callee\":{\"type\":\"Method\",\"box_name\":\"MapBox\",\"method\":\"set\",\"receiver\":1},\"args\":[\"" + key + "\"," + val + "],\"effects\":[]}}," + + // get(r1, key) -> r2 + "{\"op\":\"mir_call\",\"dst\":2,\"mir_call\":{\"callee\":{\"type\":\"Method\",\"box_name\":\"MapBox\",\"method\":\"get\",\"receiver\":1},\"args\":[\"" + key + "\"],\"effects\":[]}}," + + // const 0 -> r3, ret r3 + "{\"op\":\"const\",\"dst\":3,\"value\":{\"type\":\"i64\",\"value\":0}}," + + "{\"op\":\"ret\",\"value\":3}]}]}]}" + return json + } +} diff --git a/lang/src/mir/builder/internal/lower_method_map_size_box.hako b/lang/src/mir/builder/internal/lower_method_map_size_box.hako new file mode 100644 index 00000000..0c77940c --- /dev/null +++ b/lang/src/mir/builder/internal/lower_method_map_size_box.hako @@ -0,0 +1,17 @@ +// lower_method_map_size_box.hako — Minimal structural MIR for MapBox.size + +static box LowerMethodMapSizeBox { + try_lower(program_json) { + if program_json == null { return null } + local s = "" + program_json + if s.indexOf("\"type\":\"New\"") < 0 { return null } + if s.indexOf("\"class\":\"MapBox\"") < 0 { return null } + local json = "{\"kind\":\"MIR\",\"schema_version\":\"1.0\",\"functions\":[{\"name\":\"main\",\"blocks\":[{\"id\":0,\"instructions\":[" + + "{\"op\":\"mir_call\",\"dst\":1,\"mir_call\":{\"callee\":{\"type\":\"Constructor\",\"box_type\":\"MapBox\"},\"args\":[],\"effects\":[]}}," + + "{\"op\":\"mir_call\",\"dst\":2,\"mir_call\":{\"callee\":{\"type\":\"Method\",\"box_name\":\"MapBox\",\"method\":\"size\",\"receiver\":1},\"args\":[],\"effects\":[]}}," + + "{\"op\":\"const\",\"dst\":3,\"value\":{\"type\":\"i64\",\"value\":0}}," + + "{\"op\":\"ret\",\"value\":3}]}]}]}" + return json + } +} + diff --git a/lang/src/mir/builder/internal/lower_newbox_constructor_box.hako b/lang/src/mir/builder/internal/lower_newbox_constructor_box.hako new file mode 100644 index 00000000..431d1756 --- /dev/null +++ b/lang/src/mir/builder/internal/lower_newbox_constructor_box.hako @@ -0,0 +1,26 @@ +// lower_newbox_constructor_box.hako — Program(JSON v0) with New(Array/Map) → MIR v1 (mir_call Constructor) +// Scope: minimal safe subset for Phase 20.43 Step‑2 + + +static box LowerNewboxConstructorBox { + try_lower(program_json) { + if program_json == null { return null } + local s = "" + program_json + // Quick pattern check + if s.indexOf("\"type\":\"New\"") < 0 { return null } + // Find class name (minimal scan) + local cls = null + if s.indexOf("\"class\":\"ArrayBox\"") >= 0 { cls = "ArrayBox" } + else { if s.indexOf("\"class\":\"MapBox\"") >= 0 { cls = "MapBox" } } + if cls == null { return null } + // Only accept known minimal boxes + if !(cls == "ArrayBox" || cls == "MapBox") { return null } + + // Emit MIR v1 JSON text directly (no Map/Array construction) + local json = "{\"kind\":\"MIR\",\"schema_version\":\"1.0\",\"functions\":[{\"name\":\"main\",\"blocks\":[{\"id\":0,\"instructions\":[" + + "{\"op\":\"mir_call\",\"dst\":1,\"mir_call\":{\"callee\":{\"type\":\"Constructor\",\"box_type\":\"" + cls + "\"},\"args\":[],\"effects\":[]}}," + + "{\"op\":\"const\",\"dst\":2,\"value\":{\"type\":\"i64\",\"value\":0}}," + + "{\"op\":\"ret\",\"value\":2}]}]}]}" + return json + } +} diff --git a/lang/src/mir/builder/internal/lower_return_binop_box.hako b/lang/src/mir/builder/internal/lower_return_binop_box.hako index 0d2b0203..b84b6435 100644 --- a/lang/src/mir/builder/internal/lower_return_binop_box.hako +++ b/lang/src/mir/builder/internal/lower_return_binop_box.hako @@ -34,11 +34,12 @@ static box LowerReturnBinOpBox { local rhs_val = JsonFragBox.read_int_after(s, kv_rhs + 8) if rhs_val == null { return null } - local mir = "{\"functions\":{\"Main.main\":{\"params\":[],\"locals\":[],\"blocks\":[{\"label\":\"bb0\",\"instructions\":[" + + // Emit minimal MIR JSON v0 (functions array, name="main", blocks.id) + local mir = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":[{\"id\":0,\"instructions\":[" + "{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + lhs_val + "}}," + "{\"op\":\"const\",\"dst\":2,\"value\":{\"type\":\"i64\",\"value\":" + rhs_val + "}}," + "{\"op\":\"binop\",\"operation\":\"" + op + "\",\"lhs\":1,\"rhs\":2,\"dst\":3}," + - "{\"op\":\"ret\",\"value\":3}]}] }},\"blocks\":1}" + "{\"op\":\"ret\",\"value\":3}]}]}]}" return mir } } diff --git a/lang/src/mir/builder/internal/lower_return_binop_varvar_box.hako b/lang/src/mir/builder/internal/lower_return_binop_varvar_box.hako index 8eba1164..e6c302db 100644 --- a/lang/src/mir/builder/internal/lower_return_binop_varvar_box.hako +++ b/lang/src/mir/builder/internal/lower_return_binop_varvar_box.hako @@ -1,24 +1,25 @@ // lower_return_binop_varvar_box.hako — Return(Binary Var vs Var) with prior Local Ints -using "hako.mir.builder.internal.prog_scan" as ProgScanBox -using ProgScanBox as Scan using selfhost.shared.mir.schema as MirSchemaBox using "hako.mir.builder.internal.pattern_util" as PatternUtilBox +using selfhost.shared.json.utils.json_frag as JsonFragBox static box LowerReturnBinOpVarVarBox { - _find_local_int_before(s, name, before_pos) { return PatternUtilBox.find_local_int_before(s, name, before_pos) } try_lower(program_json){ local s = "" + program_json local k_ret = s.indexOf("\"type\":\"Return\""); if k_ret < 0 { return null } local k_bin = s.indexOf("\"type\":\"Binary\"", k_ret); if k_bin < 0 { return null } - local op = Scan.read_quoted_after_key(s, k_bin, "op"); if op == null { return null } + local k_op = s.indexOf("\"op\":", k_bin); if k_op < 0 { return null } + local op = JsonFragBox.read_string_after(s, k_op + 5); if op == null { return null } if !(op == "+" || op == "-" || op == "*" || op == "/") { return null } local klhs = s.indexOf("\"lhs\":{\"type\":\"Var\"", k_bin); if klhs < 0 { return null } local krhs = s.indexOf("\"rhs\":{\"type\":\"Var\"", k_bin); if krhs < 0 { return null } - local lname = Scan.read_quoted_after_key(s, klhs, "name"); if lname == null { return null } - local rname = Scan.read_quoted_after_key(s, krhs, "name"); if rname == null { return null } - local lval = me._find_local_int_before(s, lname, k_ret); if lval == null { return null } - local rval = me._find_local_int_before(s, rname, k_ret); if rval == null { return null } + local knl = s.indexOf("\"name\":", klhs); if knl < 0 { return null } + local lname = JsonFragBox.read_string_after(s, knl + 7); if lname == null { return null } + local knr = s.indexOf("\"name\":", krhs); if knr < 0 { return null } + local rname = JsonFragBox.read_string_after(s, knr + 7); if rname == null { return null } + local lval = PatternUtilBox.find_local_int_before(s, lname, k_ret); if lval == null { return null } + local rval = PatternUtilBox.find_local_int_before(s, rname, k_ret); if rval == null { return null } local b0=new ArrayBox(); b0.push(MirSchemaBox.inst_const(1,lval)); b0.push(MirSchemaBox.inst_const(2,rval)); b0.push(MirSchemaBox.inst_binop(op == "+" ? "Add" : (op == "-" ? "Sub" : (op == "*" ? "Mul" : "Div")),1,2,3)); b0.push(MirSchemaBox.inst_ret(3)) local blocks=new ArrayBox(); blocks.push(MirSchemaBox.block(0,b0)); return MirSchemaBox.module(MirSchemaBox.fn_main(blocks)) diff --git a/lang/src/mir/builder/internal/lower_return_int_box.hako b/lang/src/mir/builder/internal/lower_return_int_box.hako index e8126d35..98602b96 100644 --- a/lang/src/mir/builder/internal/lower_return_int_box.hako +++ b/lang/src/mir/builder/internal/lower_return_int_box.hako @@ -1,7 +1,6 @@ // lower_return_int_box.hako — Return(Int) → const+ret -using "hako.mir.builder.internal.prog_scan" as ProgScanBox -using ProgScanBox as Scan +using selfhost.shared.json.utils.json_frag as JsonFragBox static box LowerReturnIntBox { try_lower(program_json) { @@ -11,9 +10,13 @@ static box LowerReturnIntBox { // Expect Int after Return local k_int = s.indexOf("\"type\":\"Int\"", k_ret) if k_int < 0 { return null } - local val = Scan.read_value_int_after(s, k_int) + // Read value after Int + local kv = s.indexOf("\"value\":", k_int); if kv < 0 { return null } + local val = JsonFragBox.read_int_after(s, kv + 8) if val == null { return null } - local mir = "{\"functions\":{\"Main.main\":{\"params\":[],\"locals\":[],\"blocks\":[{\"label\":\"bb0\",\"instructions\":[{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + val + "}},{\"op\":\"ret\",\"value\":1}] }] }},\"blocks\":1}" + // Emit minimal MIR JSON v0 (functions as array; blocks use id field) + // Shape expected by src/runner/mir_json_v0.rs::parse_mir_v0_to_module + local mir = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":[{\"id\":0,\"instructions\":[{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + val + "}},{\"op\":\"ret\",\"value\":1}]}]}]}" return mir } } diff --git a/lang/src/mir/builder/internal/lower_return_logical_box.hako b/lang/src/mir/builder/internal/lower_return_logical_box.hako index d62b7d4a..35f1dda8 100644 --- a/lang/src/mir/builder/internal/lower_return_logical_box.hako +++ b/lang/src/mir/builder/internal/lower_return_logical_box.hako @@ -4,8 +4,6 @@ using selfhost.shared.mir.schema as MirSchemaBox using "hako.mir.builder.internal.pattern_util" as PatternUtilBox -using "hako.mir.builder.internal.prog_scan" as ProgScanBox - using selfhost.shared.json.utils.json_frag as JsonFragBox static box LowerReturnLogicalBox { @@ -17,8 +15,10 @@ static box LowerReturnLogicalBox { if k_ret < 0 { return null } local k_log = JsonFragBox.index_of_from(s, "\"type\":\"Logical\"", k_ret) if k_log < 0 { return null } - // op: && or || (ProgScanBox is sufficient here) - local op = ProgScanBox.read_quoted_after_key(s, k_log, "op") + // op: && or || + local k_op = JsonFragBox.index_of_from(s, "\"op\":", k_log) + if k_op < 0 { return null } + local op = JsonFragBox.read_string_after(s, k_op + 5) if op == null { return null } if !(op == "&&" || op == "||") { return null } // Resolve lhs to 0/1 (Bool or Var with Local Bool) - robust version @@ -33,7 +33,9 @@ static box LowerReturnLogicalBox { } else { local klhs_v = JsonFragBox.index_of_from(s, "\"lhs\":{\"type\":\"Var\"", k_log) if klhs_v >= 0 { - local name = ProgScanBox.read_quoted_after_key(s, klhs_v, "name") + local kn = JsonFragBox.index_of_from(s, "\"name\":", klhs_v) + if kn < 0 { return null } + local name = JsonFragBox.read_string_after(s, kn + 7) if name != null { lhs_true = PatternUtilBox.find_local_bool_before(s, name, k_log) } } } @@ -51,7 +53,9 @@ static box LowerReturnLogicalBox { } else { local krhs_v = JsonFragBox.index_of_from(s, "\"rhs\":{\"type\":\"Var\"", k_log) if krhs_v >= 0 { - local name2 = ProgScanBox.read_quoted_after_key(s, krhs_v, "name") + local kn2 = JsonFragBox.index_of_from(s, "\"name\":", krhs_v) + if kn2 < 0 { return null } + local name2 = JsonFragBox.read_string_after(s, kn2 + 7) if name2 != null { rhs_true = PatternUtilBox.find_local_bool_before(s, name2, k_log) } } } diff --git a/lang/src/mir/builder/internal/lower_return_method_array_map_box.hako b/lang/src/mir/builder/internal/lower_return_method_array_map_box.hako index c1887877..093c9f01 100644 --- a/lang/src/mir/builder/internal/lower_return_method_array_map_box.hako +++ b/lang/src/mir/builder/internal/lower_return_method_array_map_box.hako @@ -13,6 +13,8 @@ static box LowerReturnMethodArrayMapBox { local k_recv = s.indexOf("\"recv\":{\"type\":\"Var\"", k_m); if k_recv < 0 { return null } local method = null { local km = s.indexOf("\"method\":\"", k_m); if km < 0 { return null } method = JsonFragBox.read_string_after(s, km) } + // Standardize: generate 'size' (len/length are accepted aliases at receiver) + if method == "length" || method == "len" { method = "size" } // Allow basic methods if !(method == "size" || method == "length" || method == "len" || method == "get" || method == "set" || method == "push") { return null } // Parse up to two Int args with actual values diff --git a/lang/src/mir/builder/internal/lower_typeop_cast_box.hako b/lang/src/mir/builder/internal/lower_typeop_cast_box.hako new file mode 100644 index 00000000..fa3303f7 --- /dev/null +++ b/lang/src/mir/builder/internal/lower_typeop_cast_box.hako @@ -0,0 +1,15 @@ +// lower_typeop_cast_box.hako — Minimal structural MIR for typeop(Cast) + +static box LowerTypeOpCastBox { + try_lower(program_json) { + if program_json == null { return null } + // Emit v1 JSON: const 100 -> v1, typeop Cast v1 -> v2 (IntegerBox), const 0 -> v3, ret v3 + local json = "{\"kind\":\"MIR\",\"schema_version\":\"1.0\",\"functions\":[{\"name\":\"main\",\"blocks\":[{\"id\":0,\"instructions\":[" + + "{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":100}}," + + "{\"op\":\"typeop\",\"op_kind\":\"Cast\",\"dst\":2,\"value\":1,\"ty\":\"IntegerBox\"}," + + "{\"op\":\"const\",\"dst\":3,\"value\":{\"type\":\"i64\",\"value\":0}}," + + "{\"op\":\"ret\",\"value\":3}]}]}]}" + return json + } +} + diff --git a/lang/src/mir/builder/internal/lower_typeop_check_box.hako b/lang/src/mir/builder/internal/lower_typeop_check_box.hako new file mode 100644 index 00000000..e64225df --- /dev/null +++ b/lang/src/mir/builder/internal/lower_typeop_check_box.hako @@ -0,0 +1,15 @@ +// lower_typeop_check_box.hako — Minimal structural MIR for typeop(Check) + +static box LowerTypeOpCheckBox { + try_lower(program_json) { + if program_json == null { return null } + local json = "{\"kind\":\"MIR\",\"schema_version\":\"1.0\",\"functions\":[{\"name\":\"main\",\"blocks\":[{\"id\":0,\"instructions\":[" + + // const 42 -> v1, typeop Check v1 -> v2, const 0 -> v3, ret v3 + "{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":42}}," + + "{\"op\":\"typeop\",\"op_kind\":\"Check\",\"dst\":2,\"value\":1,\"ty\":\"IntegerBox\"}," + + "{\"op\":\"const\",\"dst\":3,\"value\":{\"type\":\"i64\",\"value\":0}}," + + "{\"op\":\"ret\",\"value\":3}]}]}]}" + return json + } +} + diff --git a/lang/src/mir/builder/internal/pattern_util_box.hako b/lang/src/mir/builder/internal/pattern_util_box.hako index 08a25d69..0b4e39a7 100644 --- a/lang/src/mir/builder/internal/pattern_util_box.hako +++ b/lang/src/mir/builder/internal/pattern_util_box.hako @@ -5,6 +5,27 @@ using selfhost.shared.common.string_helpers as StringHelpers static box PatternUtilBox { map_cmp(sym) { if sym=="<" {return "Lt"} if sym==">" {return "Gt"} if sym=="<=" {return "Le"} if sym==">=" {return "Ge"} if sym=="==" {return "Eq"} if sym=="!=" {return "Ne"} return null } + // Normalize (op, swapped, limit) → (cmp, limit') where cmp in {Lt, Le, Gt, Ge} + // swapped=0: i ? L, swapped=1: L ? i + normalize_cmp_limit(op, swapped, limit_str) { + local op1 = "" + op + local ls = "" + limit_str + if swapped == 0 { + if op1 == "<" { return "Lt:" + ls } + if op1 == "<=" { return "Lt:" + StringHelpers.int_to_str(JsonFragBox._str_to_int(ls) + 1) } + if op1 == ">" { return "Gt:" + ls } + if op1 == ">=" { return "Ge:" + ls } + if op1 == "!=" { return "Lt:" + ls } // count(init=0,step=1) 前提の近似 + return null + } else { + if op1 == ">" { return "Lt:" + ls } + if op1 == ">=" { return "Lt:" + StringHelpers.int_to_str(JsonFragBox._str_to_int(ls) + 1) } + if op1 == "<" { return "Gt:" + ls } + if op1 == "<=" { return "Ge:" + ls } + if op1 == "!=" { return "Lt:" + ls } // 安全近似(入替側) + return null + } + } // Normalize limit for canonical (i < limit) form. // When swapped==0, expects op in {'<','<='}; when swapped==1 (Int on lhs, Var on rhs), expects op in {'>','>='}. // Returns adjusted limit string or null if unsupported. @@ -38,4 +59,47 @@ static box PatternUtilBox { local kv=s.indexOf("\"value\":",kb); if kv<0 { return null } return JsonFragBox.read_bool_after(s, kv+8) } + + // Find the last Local(Int) before a given position (name-agnostic). + // Returns string digits or null when not found. + find_any_local_int_before(s, before_pos) { + local pos = 0; local last_k = -1; local n = ("" + s).length() + loop(true) { + local k = JsonFragBox.index_of_from(s, "\"type\":\"Local\"", pos) + if k < 0 || k >= before_pos { break } + last_k = k + pos = k + 1 + } + if last_k < 0 { return null } + // Limit search to the next Local or before_pos + local next = JsonFragBox.index_of_from(s, "\"type\":\"Local\"", last_k + 1) + if next < 0 || next > before_pos { next = before_pos } + // Constrain to Local.expr → Int + local ti = ("" + s).indexOf("\"expr\":{\"type\":\"Int\"", last_k) + if ti < 0 || ti >= next { return null } + local kv = ("" + s).indexOf("\"value\":", ti) + if kv < 0 || kv >= next { return null } + return JsonFragBox.read_int_after(s, kv + 8) + } + + // Find the last Local(String) before a given position (name-agnostic). + // Returns raw string (unquoted) or null when not found. + find_any_local_string_before(s, before_pos) { + local pos = 0; local last_k = -1 + loop(true) { + local k = JsonFragBox.index_of_from(s, "\"type\":\"Local\"", pos) + if k < 0 || k >= before_pos { break } + last_k = k + pos = k + 1 + } + if last_k < 0 { return null } + local next = JsonFragBox.index_of_from(s, "\"type\":\"Local\"", last_k + 1) + if next < 0 || next > before_pos { next = before_pos } + // Constrain to Local.expr → String + local ts = ("" + s).indexOf("\"expr\":{\"type\":\"String\"", last_k) + if ts < 0 || ts >= next { return null } + local kv = ("" + s).indexOf("\"value\":", ts) + if kv < 0 || kv >= next { return null } + return JsonFragBox.read_string_after(s, kv + 8) + } } diff --git a/lang/src/mir/builder/internal/prog_scan_box.hako b/lang/src/mir/builder/internal/prog_scan_box.hako index 6a4c4e25..7223f51a 100644 --- a/lang/src/mir/builder/internal/prog_scan_box.hako +++ b/lang/src/mir/builder/internal/prog_scan_box.hako @@ -1,6 +1,17 @@ // prog_scan_box.hako — Tiny string scanner helpers for Program(JSON v0) static box ProgScanBox { + _decode_unicode_on() { + local v = env.get("HAKO_PARSER_DECODE_UNICODE") + if v == null { return 0 } + if v == "1" || v == "true" || v == "on" { return 1 } + return 0 + } + _decode_escapes(s) { + // Delegate to JsonFragBox decoder for consistency if available + using selfhost.shared.json.utils.json_frag as JsonFragBox + return JsonFragBox._decode_escapes(s) + } // Find substring starting at or after pos; returns index or -1 find(s, pat, pos) { local s1 = "" + s @@ -52,7 +63,11 @@ static box ProgScanBox { } local j = i loop(j < n) { if s1.substring(j,j+1) == "\"" { break } j = j + 1 } - if j <= n { return s1.substring(i, j) } + if j <= n { + local raw = s1.substring(i, j) + if me._decode_unicode_on() == 1 { return me._decode_escapes(raw) } + return raw + } return null } diff --git a/lang/src/mir/builder/internal/runner_min_box.hako b/lang/src/mir/builder/internal/runner_min_box.hako new file mode 100644 index 00000000..6b83ae11 --- /dev/null +++ b/lang/src/mir/builder/internal/runner_min_box.hako @@ -0,0 +1,52 @@ +// runner_min_box.hako — Minimal builder runner that tries internal lowers in order +// Purpose: Provide a lightweight path to emit MIR(JSON) from Program(JSON v0) +// without importing the full MirBuilderBox chain (avoids parser/include flakiness). + +using "hako.mir.builder.internal.lower_newbox_constructor" as LowerNewboxConstructorBox +using "hako.mir.builder.internal.lower_method_array_push" as LowerMethodArrayPushBox +using "hako.mir.builder.internal.lower_method_array_size" as LowerMethodArraySizeBox +using "hako.mir.builder.internal.lower_method_array_get_set" as LowerMethodArrayGetSetBox +using "hako.mir.builder.internal.lower_method_map_size" as LowerMethodMapSizeBox +using "hako.mir.builder.internal.lower_method_map_get_set" as LowerMethodMapGetSetBox +using "hako.mir.builder.internal.lower_load_store_local" as LowerLoadStoreLocalBox +using "hako.mir.builder.internal.lower_typeop_check" as LowerTypeOpCheckBox +using "hako.mir.builder.internal.lower_typeop_cast" as LowerTypeOpCastBox +using "hako.mir.builder.internal.lower_return_int" as LowerReturnIntBox +using "hako.mir.builder.internal.lower_return_binop" as LowerReturnBinOpBox + +static box BuilderRunnerMinBox { + run(program_json) { + if program_json == null { return null } + local s = "" + program_json + // Optional profile: when HAKO_MIR_RUNNER_MIN_NO_METHODS=1, skip method lowers (Core exec-friendly) + local no_methods = env.get("HAKO_MIR_RUNNER_MIN_NO_METHODS") + local skip_methods = 0 + if no_methods != null { if ("" + no_methods) == "1" { skip_methods = 1 } } + // Prefer method lowers before constructor to allow method cases to win + // Prefer push over size so push canary wins + if skip_methods == 0 { + { local o = LowerMethodArrayPushBox.try_lower(s); if o != null { return o } } + { local o = LowerMethodArraySizeBox.try_lower(s); if o != null { return o } } + { local o = LowerMethodArrayGetSetBox.try_lower(s); if o != null { return o } } + // Map lowers: allow preference override via HAKO_MIR_RUNNER_MIN_PREF_MAP + // default: size → get_set; when pref == "getset": get_set → size + local map_pref = env.get("HAKO_MIR_RUNNER_MIN_PREF_MAP") + if map_pref != null && ("" + map_pref) == "getset" { + { local o = LowerMethodMapGetSetBox.try_lower(s); if o != null { return o } } + { local o = LowerMethodMapSizeBox.try_lower(s); if o != null { return o } } + } else { + { local o = LowerMethodMapSizeBox.try_lower(s); if o != null { return o } } + { local o = LowerMethodMapGetSetBox.try_lower(s); if o != null { return o } } + } + } + if skip_methods == 0 { + { local o = LowerLoadStoreLocalBox.try_lower(s); if o != null { return o } } + { local o = LowerTypeOpCheckBox.try_lower(s); if o != null { return o } } + { local o = LowerTypeOpCastBox.try_lower(s); if o != null { return o } } + } + { local o = LowerReturnBinOpBox.try_lower(s); if o != null { return o } } + { local o = LowerReturnIntBox.try_lower(s); if o != null { return o } } + { local o = LowerNewboxConstructorBox.try_lower(s); if o != null { return o } } + return null + } +} diff --git a/lang/src/shared/json/utils/json_frag.hako b/lang/src/shared/json/utils/json_frag.hako index 66945c00..395357dc 100644 --- a/lang/src/shared/json/utils/json_frag.hako +++ b/lang/src/shared/json/utils/json_frag.hako @@ -6,6 +6,108 @@ using selfhost.shared.json.core.json_cursor as JsonCursorBox using selfhost.shared.common.string_helpers as StringHelpers static box JsonFragBox { + // Toggle: enable Unicode \uXXXX decode in string readers + _decode_unicode_on() { + local v = env.get("HAKO_PARSER_DECODE_UNICODE") + if v == null { return 0 } + if v == "1" || v == "true" || v == "on" { return 1 } + return 0 + } + + // Decode simple escapes (\\ \" \/ \b \f \n \r \t) and \uXXXX (printable ASCII only) + _decode_escapes(s) { + if s == null { return null } + // Normalize common JSON double-escape: "\\uXXXX" -> "\uXXXX" + local src0 = "" + s + local n0 = src0.length() + local tmp = "" + local p = 0 + loop(p < n0) { + local ch0 = src0.substring(p, p+1) + if ch0 == "\\" && p + 2 <= n0 && src0.substring(p+1, p+2) == "\\" { + if p + 3 <= n0 && src0.substring(p+2, p+3) == "u" { + tmp = tmp + "\\u" + p = p + 3 + continue + } + // generic \\ -> \ + tmp = tmp + "\\" + p = p + 2 + continue + } + tmp = tmp + ch0 + p = p + 1 + } + local s1 = tmp + local n = s1.length() + if n == 0 { return s1 } + local out = "" + local i = 0 + // Printable ASCII table for 0x20..0x7E + local ascii = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" + loop(i < n) { + local ch = s1.substring(i, i+1) + if ch != "\\" { out = out + ch i = i + 1 continue } + // escape + if i + 1 >= n { out = out + "\\" i = i + 1 continue } + local e = s1.substring(i+1, i+2) + if e == "\\" { out = out + "\\" i = i + 2 continue } + if e == "\"" { out = out + "\"" i = i + 2 continue } + if e == "/" { out = out + "/" i = i + 2 continue } + if e == "b" { out = out + "\b" i = i + 2 continue } + if e == "f" { out = out + "\f" i = i + 2 continue } + if e == "n" { out = out + "\n" i = i + 2 continue } + if e == "r" { out = out + "\r" i = i + 2 continue } + if e == "t" { out = out + "\t" i = i + 2 continue } + if e == "u" { + // \uXXXX (hex) + if i + 6 <= n { + local h = s1.substring(i+2, i+6) + // parse hex (limited) + local val = 0 + local k = 0 + local ok = 1 + loop(k < 4) { + local c = h.substring(k, k+1) + local d = -1 + if c >= "0" && c <= "9" { d = "0123456789".indexOf(c) } + else { + if c >= "a" && c <= "f" { d = 10 + ("abcdef".indexOf(c)) } + else { if c >= "A" && c <= "F" { d = 10 + ("ABCDEF".indexOf(c)) } else { ok = 0 }} + } + if d < 0 { ok = 0 break } + val = val * 16 + d + k = k + 1 + } + if ok == 1 { + // Printable ASCII only (0x20..0x7E) + if val >= 32 && val <= 126 { + local pos = val - 32 + out = out + ascii.substring(pos, pos+1) + i = i + 6 + continue + } + // Surrogate pair handling: collapse \uD83D\uDE00 etc. into a single placeholder + // High surrogate range: 55296..56319 + if val >= 55296 && val <= 56319 { + // skip following low surrogate if present + if i + 12 <= n && s1.substring(i+6, i+8) == "\\u" { i = i + 12 } else { i = i + 6 } + out = out + "?" + continue + } + // Non-ASCII BMP → placeholder + out = out + "?" + i = i + 6 + continue + } + } + } + // Fallback: keep as-is for unknown escape + out = out + ch + i = i + 1 + } + return out + } // 基本ヘルパ - VM fallback implementations for cross-box static calls index_of_from(hay, needle, pos) { // VM fallback: implement using substring + indexOf @@ -62,7 +164,9 @@ static box JsonFragBox { local j = i loop(j < n) { if s.substring(j,j+1) == "\"" { break } j = j + 1 } if j <= i { return null } - return s.substring(i, j) + local raw = s.substring(i, j) + if me._decode_unicode_on() == 1 { return me._decode_escapes(raw) } + return raw } read_float_from(text, pos) { if text == null { return null } @@ -154,7 +258,11 @@ static box JsonFragBox { if p >= 0 { local vstart = p + pat.length() // start of value (right after opening quote) local vend = me._scan_string_end(seg, vstart - 1) - if vend > vstart { return seg.substring(vstart, vend) } + if vend > vstart { + local raw = seg.substring(vstart, vend) + if me._decode_unicode_on() == 1 { return me._decode_escapes(raw) } + return raw + } } return "" } diff --git a/lang/src/vm/hakorune-vm/dispatcher_v1.hako b/lang/src/vm/hakorune-vm/dispatcher_v1.hako index fc7b5b2a..7b4d917e 100644 --- a/lang/src/vm/hakorune-vm/dispatcher_v1.hako +++ b/lang/src/vm/hakorune-vm/dispatcher_v1.hako @@ -164,6 +164,12 @@ static box NyVmDispatcherV1Box { } // Main entry: Choose internal scanner when enabled; otherwise delegate to Mini‑VM run(json) { + // Typed IR primary (限定): 構造IR生成を有効化しつつ既存フローを使用(挙動不変) + if env.get("HAKO_V1_TYPED_IR_PRIMARY") == "1" { + // ShadowをONにして構造IR生成のオーバーヘッドを観測(必要時) + if env.get("HAKO_V1_TYPED_IR_SHADOW") == null { env.set("HAKO_V1_TYPED_IR_SHADOW", "1") } + return me.run_scan_flow(json) + } if env.get("HAKO_V1_DISPATCHER_FLOW") == "1" { return me.run_scan_flow(json) } if env.get("HAKO_V1_DISPATCHER_INTERNAL") == "1" { return me.run_scan(json) } return MirVmMin.run_min(json) diff --git a/nyash.toml b/nyash.toml index 3416929c..ce0917e7 100644 --- a/nyash.toml +++ b/nyash.toml @@ -206,6 +206,16 @@ path = "lang/src/shared/common/string_helpers.hako" "hako.mir.builder.internal.lower_return_binop_varvar" = "lang/src/mir/builder/internal/lower_return_binop_varvar_box.hako" "hako.mir.builder.internal.lower_return_binop" = "lang/src/mir/builder/internal/lower_return_binop_box.hako" "hako.mir.builder.internal.lower_return_int" = "lang/src/mir/builder/internal/lower_return_int_box.hako" +"hako.mir.builder.internal.lower_newbox_constructor" = "lang/src/mir/builder/internal/lower_newbox_constructor_box.hako" +"hako.mir.builder.internal.lower_method_array_size" = "lang/src/mir/builder/internal/lower_method_array_size_box.hako" +"hako.mir.builder.internal.lower_method_array_push" = "lang/src/mir/builder/internal/lower_method_array_push_box.hako" +"hako.mir.builder.internal.lower_method_array_get_set" = "lang/src/mir/builder/internal/lower_method_array_get_set_box.hako" +"hako.mir.builder.internal.lower_method_map_size" = "lang/src/mir/builder/internal/lower_method_map_size_box.hako" +"hako.mir.builder.internal.lower_method_map_get_set" = "lang/src/mir/builder/internal/lower_method_map_get_set_box.hako" +"hako.mir.builder.internal.lower_load_store_local" = "lang/src/mir/builder/internal/lower_load_store_local_box.hako" +"hako.mir.builder.internal.lower_typeop_check" = "lang/src/mir/builder/internal/lower_typeop_check_box.hako" +"hako.mir.builder.internal.lower_typeop_cast" = "lang/src/mir/builder/internal/lower_typeop_cast_box.hako" +"hako.mir.builder.internal.runner_min" = "lang/src/mir/builder/internal/runner_min_box.hako" # Missing alias for JsonFragBox (used widely in lowers) "selfhost.shared.json.utils.json_frag" = "lang/src/shared/json/utils/json_frag.hako" @@ -568,3 +578,30 @@ birth = { method_id = 0 } get = { method_id = 1 } set = { method_id = 2 } fini = { method_id = 4294967295 } + +# ------------------------------------------------------------ +# Builtin/Core Boxes (slot config via central tables) +# These entries allow method_id resolution for core boxes +# without requiring a dynamic library. Execution remains +# handled by built-in handlers; this mapping is for MIR slot +# injection and consistency only. + +[box_types] +# Assign type IDs for core boxes (reserved range) +ArrayBox = 5 +MapBox = 6 + +[box_methods.ArrayBox.methods] +push = { method_id = 4 } +get = { method_id = 5 } +set = { method_id = 6 } +size = { method_id = 7 } +length = { method_id = 7 } +len = { method_id = 7 } + +[box_methods.MapBox.methods] +set = { method_id = 4 } +get = { method_id = 5 } +size = { method_id = 6 } +length = { method_id = 6 } +len = { method_id = 6 } diff --git a/src/backend/mir_interpreter/handlers/boxes_map.rs b/src/backend/mir_interpreter/handlers/boxes_map.rs index 5fc75aaa..46ed6ab8 100644 --- a/src/backend/mir_interpreter/handlers/boxes_map.rs +++ b/src/backend/mir_interpreter/handlers/boxes_map.rs @@ -106,7 +106,7 @@ pub(super) fn try_handle_map_box( if let Some(d) = dst { this.regs.insert(d, VMValue::from_nyash_box(ret)); } return Ok(true); } - "size" => { + "len" | "length" | "size" => { let ret = mb.size(); if let Some(d) = dst { this.regs.insert(d, VMValue::from_nyash_box(ret)); } return Ok(true); diff --git a/src/config/env.rs b/src/config/env.rs index 9553fb37..d804a4f8 100644 --- a/src/config/env.rs +++ b/src/config/env.rs @@ -524,6 +524,15 @@ pub fn ny_compiler_use_tmp_only() -> bool { .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(); diff --git a/src/host_providers/mir_builder.rs b/src/host_providers/mir_builder.rs index fc22072c..6bfd3e81 100644 --- a/src/host_providers/mir_builder.rs +++ b/src/host_providers/mir_builder.rs @@ -25,6 +25,7 @@ pub fn program_json_to_mir_json(program_json: &str) -> Result { // Emit MIR(JSON) to a temporary file (reuse existing emitter), then read back let tmp_dir = std::env::temp_dir(); let tmp_path = tmp_dir.join("hako_mirbuilder_out.json"); + // Emit MIR JSON (v0/v1 per env) via harness-bin emitter to a temp file if let Err(e) = runner::mir_json_emit::emit_mir_json_for_harness_bin(&module, &tmp_path) { let tag = format!("[mirbuilder/emit/error] {}", e); eprintln!("{}", tag); @@ -43,4 +44,3 @@ pub fn program_json_to_mir_json(program_json: &str) -> Result { } } } - diff --git a/src/mir/builder/exprs_peek.rs b/src/mir/builder/exprs_peek.rs index baefbcd9..1a473c24 100644 --- a/src/mir/builder/exprs_peek.rs +++ b/src/mir/builder/exprs_peek.rs @@ -46,11 +46,12 @@ impl super::MirBuilder { phi_inputs.push((else_block, else_val)); crate::mir::builder::emission::branch::emit_jump(self, merge_block)?; self.start_new_block(merge_block)?; - // フェーズM: 常にPHI命令を使用(no_phi_mode撤廃) - self.emit_instruction(super::MirInstruction::Phi { - dst: result_val, - inputs: phi_inputs, - })?; + // フェーズM: PHI はブロック先頭に配置(cf_common 統一) + if let (Some(func), Some(cur_bb)) = (self.current_function.as_mut(), self.current_block) { + crate::mir::ssot::cf_common::insert_phi_at_head(func, cur_bb, result_val, phi_inputs); + } else { + self.emit_instruction(super::MirInstruction::Phi { dst: result_val, inputs: phi_inputs })?; + } return Ok(result_val); } @@ -101,11 +102,12 @@ impl super::MirBuilder { // Merge and yield result self.start_new_block(merge_block)?; - // フェーズM: 常にPHI命令を使用(no_phi_mode撤廃) - self.emit_instruction(super::MirInstruction::Phi { - dst: result_val, - inputs: phi_inputs, - })?; + // フェーズM: PHI はブロック先頭に配置(cf_common 統一) + if let (Some(func), Some(cur_bb)) = (self.current_function.as_mut(), self.current_block) { + crate::mir::ssot::cf_common::insert_phi_at_head(func, cur_bb, result_val, phi_inputs); + } else { + self.emit_instruction(super::MirInstruction::Phi { dst: result_val, inputs: phi_inputs })?; + } Ok(result_val) } } diff --git a/src/mir/builder/if_form.rs b/src/mir/builder/if_form.rs index 858403b3..c5ae5297 100644 --- a/src/mir/builder/if_form.rs +++ b/src/mir/builder/if_form.rs @@ -68,7 +68,11 @@ impl MirBuilder { for (name, &pre_v) in pre_if_var_map.iter() { let phi_val = self.value_gen.next(); let inputs = vec![(pre_branch_bb, pre_v)]; - self.emit_instruction(MirInstruction::Phi { dst: phi_val, inputs })?; + if let (Some(func), Some(cur_bb)) = (self.current_function.as_mut(), self.current_block) { + crate::mir::ssot::cf_common::insert_phi_at_head(func, cur_bb, phi_val, inputs); + } else { + self.emit_instruction(MirInstruction::Phi { dst: phi_val, inputs })?; + } self.variable_map.insert(name.clone(), phi_val); if trace_if { eprintln!( @@ -99,7 +103,11 @@ impl MirBuilder { for (name, &pre_v) in pre_if_var_map.iter() { let phi_val = self.value_gen.next(); let inputs = vec![(pre_branch_bb, pre_v)]; - self.emit_instruction(MirInstruction::Phi { dst: phi_val, inputs })?; + if let (Some(func), Some(cur_bb)) = (self.current_function.as_mut(), self.current_block) { + crate::mir::ssot::cf_common::insert_phi_at_head(func, cur_bb, phi_val, inputs); + } else { + self.emit_instruction(MirInstruction::Phi { dst: phi_val, inputs })?; + } self.variable_map.insert(name.clone(), phi_val); if trace_if { eprintln!( @@ -121,7 +129,7 @@ impl MirBuilder { if else_reaches_merge { // Scope leave for else-branch self.hint_scope_leave(0); - self.emit_instruction(MirInstruction::Jump { target: merge_block })?; + crate::mir::builder::emission::branch::emit_jump(self, merge_block)?; } // Pop else-branch debug region self.debug_pop_region(); diff --git a/src/mir/builder/ops.rs b/src/mir/builder/ops.rs index d723fecb..9214c1c8 100644 --- a/src/mir/builder/ops.rs +++ b/src/mir/builder/ops.rs @@ -261,7 +261,11 @@ impl super::MirBuilder { for (name, &pre_v) in pre_if_var_map.iter() { let phi_val = self.value_gen.next(); let inputs = vec![(pre_branch_bb, pre_v)]; - self.emit_instruction(MirInstruction::Phi { dst: phi_val, inputs })?; + if let (Some(func), Some(cur_bb)) = (self.current_function.as_mut(), self.current_block) { + crate::mir::ssot::cf_common::insert_phi_at_head(func, cur_bb, phi_val, inputs); + } else { + self.emit_instruction(MirInstruction::Phi { dst: phi_val, inputs })?; + } self.variable_map.insert(name.clone(), phi_val); } @@ -290,13 +294,13 @@ impl super::MirBuilder { self.start_new_block(rhs_join)?; let rhs_bool = self.value_gen.next(); let inputs = vec![(rhs_true_exit, t_id), (rhs_false_exit, f_id)]; - if let Some(func) = self.current_function.as_mut() { - func.update_cfg(); - } - if let (Some(func), Some(cur_bb)) = (&self.current_function, self.current_block) { + if let Some(func) = self.current_function.as_mut() { func.update_cfg(); } + if let (Some(func), Some(cur_bb)) = (self.current_function.as_mut(), self.current_block) { crate::mir::phi_core::common::debug_verify_phi_inputs(func, cur_bb, &inputs); + crate::mir::ssot::cf_common::insert_phi_at_head(func, cur_bb, rhs_bool, inputs); + } else { + self.emit_instruction(MirInstruction::Phi { dst: rhs_bool, inputs })?; } - self.emit_instruction(MirInstruction::Phi { dst: rhs_bool, inputs })?; self.value_types.insert(rhs_bool, MirType::Bool); rhs_bool } else { @@ -319,7 +323,11 @@ impl super::MirBuilder { for (name, &pre_v) in pre_if_var_map.iter() { let phi_val = self.value_gen.next(); let inputs = vec![(pre_branch_bb, pre_v)]; - self.emit_instruction(MirInstruction::Phi { dst: phi_val, inputs })?; + if let (Some(func), Some(cur_bb)) = (self.current_function.as_mut(), self.current_block) { + crate::mir::ssot::cf_common::insert_phi_at_head(func, cur_bb, phi_val, inputs); + } else { + self.emit_instruction(MirInstruction::Phi { dst: phi_val, inputs })?; + } self.variable_map.insert(name.clone(), phi_val); } // AND: else → false @@ -349,13 +357,13 @@ impl super::MirBuilder { self.start_new_block(rhs_join)?; let rhs_bool = self.value_gen.next(); let inputs = vec![(rhs_true_exit, t_id), (rhs_false_exit, f_id)]; - if let Some(func) = self.current_function.as_mut() { - func.update_cfg(); - } - if let (Some(func), Some(cur_bb)) = (&self.current_function, self.current_block) { + if let Some(func) = self.current_function.as_mut() { func.update_cfg(); } + if let (Some(func), Some(cur_bb)) = (self.current_function.as_mut(), self.current_block) { crate::mir::phi_core::common::debug_verify_phi_inputs(func, cur_bb, &inputs); + crate::mir::ssot::cf_common::insert_phi_at_head(func, cur_bb, rhs_bool, inputs); + } else { + self.emit_instruction(MirInstruction::Phi { dst: rhs_bool, inputs })?; } - self.emit_instruction(MirInstruction::Phi { dst: rhs_bool, inputs })?; self.value_types.insert(rhs_bool, MirType::Bool); rhs_bool }; @@ -364,7 +372,7 @@ impl super::MirBuilder { let else_var_map_end = self.variable_map.clone(); if else_reaches_merge { self.hint_scope_leave(0); - self.emit_instruction(MirInstruction::Jump { target: merge_block })?; + crate::mir::builder::emission::branch::emit_jump(self, merge_block)?; } // ---- MERGE ---- @@ -379,11 +387,13 @@ impl super::MirBuilder { if else_reaches_merge { inputs.push((else_exit_block, else_value_raw)); } let result_val = if inputs.len() >= 2 { if let Some(func) = self.current_function.as_mut() { func.update_cfg(); } - if let (Some(func), Some(cur_bb)) = (&self.current_function, self.current_block) { - crate::mir::phi_core::common::debug_verify_phi_inputs(func, cur_bb, &inputs); - } let dst = self.value_gen.next(); - self.emit_instruction(MirInstruction::Phi { dst, inputs })?; + if let (Some(func), Some(cur_bb)) = (self.current_function.as_mut(), self.current_block) { + crate::mir::phi_core::common::debug_verify_phi_inputs(func, cur_bb, &inputs); + crate::mir::ssot::cf_common::insert_phi_at_head(func, cur_bb, dst, inputs); + } else { + self.emit_instruction(MirInstruction::Phi { dst, inputs })?; + } self.value_types.insert(dst, MirType::Bool); dst } else if inputs.len() == 1 { diff --git a/src/mir/builder/phi.rs b/src/mir/builder/phi.rs index 66c66153..97bdf641 100644 --- a/src/mir/builder/phi.rs +++ b/src/mir/builder/phi.rs @@ -57,7 +57,11 @@ impl MirBuilder { crate::mir::phi_core::common::debug_verify_phi_inputs(func, cur_bb, &inputs); } let merged = self.value_gen.next(); - self.emit_instruction(MirInstruction::Phi { dst: merged, inputs })?; + if let (Some(func), Some(cur_bb)) = (self.current_function.as_mut(), self.current_block) { + crate::mir::ssot::cf_common::insert_phi_at_head(func, cur_bb, merged, inputs); + } else { + self.emit_instruction(MirInstruction::Phi { dst: merged, inputs })?; + } self.variable_map.insert(name, merged); } } @@ -90,7 +94,11 @@ impl MirBuilder { crate::mir::phi_core::common::debug_verify_phi_inputs(func, cur_bb, &inputs); } let merged = self.value_gen.next(); - self.emit_instruction(MirInstruction::Phi { dst: merged, inputs })?; + if let (Some(func), Some(cur_bb)) = (self.current_function.as_mut(), self.current_block) { + crate::mir::ssot::cf_common::insert_phi_at_head(func, cur_bb, merged, inputs); + } else { + self.emit_instruction(MirInstruction::Phi { dst: merged, inputs })?; + } self.variable_map.insert(pin_name.clone(), merged); } } @@ -160,7 +168,11 @@ impl MirBuilder { if let (Some(func), Some(cur_bb)) = (&self.current_function, self.current_block) { crate::mir::phi_core::common::debug_verify_phi_inputs(func, cur_bb, &inputs); } - self.emit_instruction(MirInstruction::Phi { dst: result_val, inputs })?; + if let (Some(func), Some(cur_bb)) = (self.current_function.as_mut(), self.current_block) { + crate::mir::ssot::cf_common::insert_phi_at_head(func, cur_bb, result_val, inputs); + } else { + self.emit_instruction(MirInstruction::Phi { dst: result_val, inputs })?; + } } } self.variable_map = pre_if_var_map.clone(); @@ -183,7 +195,11 @@ impl MirBuilder { if let (Some(func), Some(cur_bb)) = (&self.current_function, self.current_block) { crate::mir::phi_core::common::debug_verify_phi_inputs(func, cur_bb, &inputs); } - self.emit_instruction(MirInstruction::Phi { dst: result_val, inputs })?; + if let (Some(func), Some(cur_bb)) = (self.current_function.as_mut(), self.current_block) { + crate::mir::ssot::cf_common::insert_phi_at_head(func, cur_bb, result_val, inputs); + } else { + self.emit_instruction(MirInstruction::Phi { dst: result_val, inputs })?; + } } } // Merge variable map conservatively to pre-if snapshot (no new bindings) diff --git a/src/runner/mir_json_v0.rs b/src/runner/mir_json_v0.rs index 206d1404..c772d586 100644 --- a/src/runner/mir_json_v0.rs +++ b/src/runner/mir_json_v0.rs @@ -1,6 +1,6 @@ use crate::mir::{ function::{FunctionSignature, MirFunction, MirModule}, - BasicBlock, BasicBlockId, ConstValue, MirInstruction, MirType, ValueId, + BasicBlock, BasicBlockId, ConstValue, EffectMask, MirInstruction, MirType, ValueId, }; use serde_json::Value; use super::mir_json::common as mirjson_common; @@ -132,6 +132,39 @@ pub fn parse_mir_v0_to_module(json: &str) -> Result { block_ref.add_instruction(MirInstruction::Return { value }); if let Some(val) = value { signature.return_type = MirType::Integer; max_value_id = max_value_id.max(val.as_u32() + 1); } else { signature.return_type = MirType::Void; } } + "newbox" => { + let dst = require_u64(inst, "dst", "newbox dst")? as u32; + let ty = inst.get("type").and_then(Value::as_str).ok_or_else(|| "newbox missing type".to_string())?.to_string(); + let args_v = inst.get("args").and_then(Value::as_array).cloned().unwrap_or_default(); + let mut args: Vec = Vec::with_capacity(args_v.len()); + for a in args_v { + let id = a.as_u64().ok_or_else(|| "newbox arg must be integer".to_string())? as u32; + args.push(ValueId::new(id)); + } + block_ref.add_instruction(MirInstruction::NewBox { dst: ValueId::new(dst), box_type: ty, args }); + max_value_id = max_value_id.max(dst + 1); + } + "boxcall" => { + // { op:"boxcall", box:, method:"name", args:[vid...], dst?: } + let box_id = require_u64(inst, "box", "boxcall box")? as u32; + let method = inst.get("method").and_then(Value::as_str).ok_or_else(|| "boxcall missing method".to_string())?.to_string(); + let dst_opt = inst.get("dst").and_then(Value::as_u64).map(|v| ValueId::new(v as u32)); + let args_v = inst.get("args").and_then(Value::as_array).cloned().unwrap_or_default(); + let mut args: Vec = Vec::with_capacity(args_v.len()); + for a in args_v { + let id = a.as_u64().ok_or_else(|| "boxcall arg must be integer".to_string())? as u32; + args.push(ValueId::new(id)); + } + block_ref.add_instruction(MirInstruction::BoxCall { + dst: dst_opt, + box_val: ValueId::new(box_id), + method, + method_id: None, + args, + effects: EffectMask::READ, + }); + if let Some(dv) = dst_opt { max_value_id = max_value_id.max(dv.as_u32() + 1); } + } other => { return Err(format!("unsupported op '{}' in mir_json_v0 loader", other)); } diff --git a/src/runner/modes/common_util/hako.rs b/src/runner/modes/common_util/hako.rs new file mode 100644 index 00000000..e3558469 --- /dev/null +++ b/src/runner/modes/common_util/hako.rs @@ -0,0 +1,48 @@ +/*! + * Hako-like source detection and minimal normalization helpers. + * + * - looks_like_hako_code: heuristics to detect Hako surface in Nyash path + * - strip_local_decl: drop leading `local ` at line head for Nyash parser compatibility + * - fail_fast_on_hako: env-gated policy (default ON) to fail fast on Hako-like source in Nyash VM path + */ + +/// Heuristic detection of Hako-like source (development-only convenience) +pub fn looks_like_hako_code(s: &str) -> bool { + s.contains("using selfhost.") + || s.contains("using hakorune.") + || s.lines().any(|l| l.trim_start().starts_with("local ")) +} + +/// Remove leading `local ` declarations at line head to keep Nyash parser stable +pub fn strip_local_decl(s: &str) -> String { + let mut out = String::with_capacity(s.len()); + for line in s.lines() { + let leading = line.len() - line.trim_start().len(); + let (indent, rest) = line.split_at(leading); + if rest.starts_with("local ") || rest.starts_with("local\t") { + let bytes = rest.as_bytes(); + let mut i = 5; // after 'local' + while i < bytes.len() && (bytes[i] == b' ' || bytes[i] == b'\t') { + i += 1; + break; + } + out.push_str(indent); + out.push_str(&rest[i..]); + out.push('\n'); + } else { + out.push_str(line); + out.push('\n'); + } + } + out +} + +/// Policy toggle: fail fast when Hako-like code enters Nyash VM path +/// Default: ON (true) +pub fn fail_fast_on_hako() -> bool { + match std::env::var("HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM").ok().as_deref() { + Some("0") | Some("false") | Some("off") => false, + _ => true, + } +} + diff --git a/src/runner/modes/common_util/mod.rs b/src/runner/modes/common_util/mod.rs index 079668b6..acefb02b 100644 --- a/src/runner/modes/common_util/mod.rs +++ b/src/runner/modes/common_util/mod.rs @@ -11,3 +11,4 @@ pub mod selfhost; pub mod resolve; pub mod exec; pub mod core_bridge; +pub mod hako; diff --git a/src/runner/modes/common_util/resolve/strip.rs b/src/runner/modes/common_util/resolve/strip.rs index 30285ff6..0b35c28f 100644 --- a/src/runner/modes/common_util/resolve/strip.rs +++ b/src/runner/modes/common_util/resolve/strip.rs @@ -359,11 +359,12 @@ pub fn resolve_prelude_paths_profiled( ) -> Result<(String, Vec), String> { // First pass: strip using from the main source and collect direct prelude paths let (cleaned, direct) = collect_using_and_strip(runner, code, filename)?; - // When AST using is enabled、recursively collect nested preludes in DFS order + // Recursively collect nested preludes (DFS) for both AST/text merges. + // Rationale: even when we merge via text, nested `using` inside preludes + // must be discovered so that their definitions are present at runtime + // (e.g., runner_min -> lower_* boxes). Previously this only ran when + // NYASH_USING_AST=1, which caused unresolved calls in inline flows. let ast_on = std::env::var("NYASH_USING_AST").ok().as_deref() == Some("1"); - if !ast_on { - return Ok((cleaned, direct)); - } let mut out: Vec = Vec::new(); let mut seen: std::collections::HashSet = std::collections::HashSet::new(); fn normalize_path(path: &str) -> (String, String) { @@ -451,6 +452,9 @@ pub fn resolve_prelude_paths_profiled( } } } + // If AST merge is disabled, still return the discovered nested prelude list + // so that the text merger can inline all dependencies. This keeps behavior + // consistent across strategies and fixes nested `using` resolution. Ok((cleaned, out)) } @@ -659,6 +663,40 @@ pub fn merge_prelude_text( // First pass: collect and resolve prelude paths let (cleaned_main, prelude_paths) = resolve_prelude_paths_profiled(runner, source, filename)?; + // Expand nested preludes for text-merge too (DFS) so that any `using` + // inside prelude files (e.g., runner_min -> lower_* boxes) are also + // included even when NYASH_USING_AST is OFF. + let mut expanded: Vec = Vec::new(); + let mut seen: std::collections::HashSet = std::collections::HashSet::new(); + fn canonize(p: &str) -> String { + std::fs::canonicalize(p) + .ok() + .map(|pb| pb.to_string_lossy().to_string()) + .unwrap_or_else(|| p.to_string()) + } + fn dfs_text( + runner: &NyashRunner, + path: &str, + out: &mut Vec, + seen: &mut std::collections::HashSet, + ) -> Result<(), String> { + let key = canonize(path); + if !seen.insert(key.clone()) { + return Ok(()); + } + let src = std::fs::read_to_string(path) + .map_err(|e| format!("using: failed to read '{}': {}", path, e))?; + let (_cleaned, nested) = collect_using_and_strip(runner, &src, path)?; + for n in nested.iter() { + dfs_text(runner, n, out, seen)?; + } + out.push(key); + Ok(()) + } + for p in prelude_paths.iter() { + dfs_text(runner, p, &mut expanded, &mut seen)?; + } + let prelude_paths = &expanded; if prelude_paths.is_empty() { // No using statements, return original diff --git a/src/runner/modes/vm.rs b/src/runner/modes/vm.rs index 3b7fbe3c..a0f6b0fc 100644 --- a/src/runner/modes/vm.rs +++ b/src/runner/modes/vm.rs @@ -138,38 +138,16 @@ impl NyashRunner { // Hako-friendly normalize: strip leading `local ` at line head for parser compatibility. // This keeps semantics close enough for our inline/selfhost drivers while we unify frontends. - fn looks_like_hako_code(s: &str) -> bool { - s.contains("using selfhost.") || s.lines().any(|l| l.trim_start().starts_with("local ")) - } - fn strip_local_decl(s: &str) -> String { - let mut out = String::with_capacity(s.len()); - for line in s.lines() { - let leading = line.len() - line.trim_start().len(); - let (indent, rest) = line.split_at(leading); - if rest.starts_with("local ") || rest.starts_with("local\t") { - // drop the first token `local` and a single following space/tab - let mut bytes = rest.as_bytes(); - let mut i = 5; // after 'local' - while i < bytes.len() && (bytes[i] == b' ' || bytes[i] == b'\t') { i += 1; break; } - out.push_str(indent); - out.push_str(&rest[i..]); - out.push('\n'); - } else { - out.push_str(line); - out.push('\n'); - } - } - out - } - if looks_like_hako_code(&preexpanded_owned) { - preexpanded_owned = strip_local_decl(&preexpanded_owned); + if crate::runner::modes::common_util::hako::looks_like_hako_code(&preexpanded_owned) { + preexpanded_owned = crate::runner::modes::common_util::hako::strip_local_decl(&preexpanded_owned); } // Routing (Hako-like): 既定は Fail‑Fast(hv1 直行は関数冒頭で処理済み)。 { let s = preexpanded_owned.as_str(); - let hako_like = s.contains("static box ") || s.contains("using selfhost.") || s.contains("using hakorune."); - let ff_env = std::env::var("HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM").ok(); - let fail_fast = match ff_env.as_deref() { Some("0")|Some("false")|Some("off") => false, _ => true }; + let hako_like = s.contains("static box ") + || s.contains("using selfhost.") + || s.contains("using hakorune."); + let fail_fast = crate::runner::modes::common_util::hako::fail_fast_on_hako(); if hako_like && fail_fast { eprintln!( "❌ Hako-like source detected in Nyash VM path. Use Hakorune VM (v1 dispatcher) or Core/LLVM for MIR.\n hint: verify with HAKO_VERIFY_PRIMARY=hakovm" diff --git a/src/runner/modes/vm_fallback.rs b/src/runner/modes/vm_fallback.rs index 3089eb53..645d025e 100644 --- a/src/runner/modes/vm_fallback.rs +++ b/src/runner/modes/vm_fallback.rs @@ -57,39 +57,14 @@ impl NyashRunner { // Dev sugar pre-expand: @name = expr → local name = expr code2 = crate::runner::modes::common_util::resolve::preexpand_at_local(&code2); // Hako-friendly normalize: strip leading `local ` at line head for Nyash parser compatibility. - fn looks_like_hako_code(s: &str) -> bool { - s.contains("using selfhost.") || s.lines().any(|l| l.trim_start().starts_with("local ")) - } - fn strip_local_decl(s: &str) -> String { - let mut out = String::with_capacity(s.len()); - for line in s.lines() { - let leading = line.len() - line.trim_start().len(); - let (indent, rest) = line.split_at(leading); - if rest.starts_with("local ") || rest.starts_with("local\t") { - let bytes = rest.as_bytes(); - let mut i = 5; // skip 'local' - while i < bytes.len() && (bytes[i] == b' ' || bytes[i] == b'\t') { i += 1; break; } - out.push_str(indent); - out.push_str(&rest[i..]); - out.push('\n'); - } else { - out.push_str(line); - out.push('\n'); - } - } - out - } - if looks_like_hako_code(&code2) { - code2 = strip_local_decl(&code2); + if crate::runner::modes::common_util::hako::looks_like_hako_code(&code2) { + code2 = crate::runner::modes::common_util::hako::strip_local_decl(&code2); } // Fail‑Fast (opt‑in): Hako 構文を Nyash VM 経路で実行しない // 目的: .hako は Hakorune VM、MIR は Core/LLVM に役割分離するためのガード { - let on = match std::env::var("HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM").ok().as_deref() { - Some("0")|Some("false")|Some("off") => false, - _ => true, - }; + let on = crate::runner::modes::common_util::hako::fail_fast_on_hako(); if on { let s = code2.as_str(); let hako_like = s.contains("static box ") || s.contains("using selfhost.") || s.contains("using hakorune."); diff --git a/src/runtime/plugin_loader_unified.rs b/src/runtime/plugin_loader_unified.rs index 263e6727..eed8d821 100644 --- a/src/runtime/plugin_loader_unified.rs +++ b/src/runtime/plugin_loader_unified.rs @@ -126,32 +126,75 @@ impl PluginHost { /// Resolve a method handle for a given plugin box type and method name. pub fn resolve_method(&self, box_type: &str, method_name: &str) -> BidResult { let cfg = self.config.as_ref().ok_or(BidError::PluginError)?; - let (lib_name, _lib_def) = cfg - .find_library_for_box(box_type) - .ok_or(BidError::InvalidType)?; let cfg_path = self.config_path.as_deref().unwrap_or("nyash.toml"); let toml_content = std::fs::read_to_string(cfg_path).map_err(|_| BidError::PluginError)?; let toml_value: toml::Value = toml::from_str(&toml_content).map_err(|_| BidError::PluginError)?; - let box_conf = cfg - .get_box_config(lib_name, box_type, &toml_value) - .ok_or(BidError::InvalidType)?; - // Prefer config mapping; fallback to loader's TypeBox resolve(name) - let (method_id, returns_result) = if let Some(m) = box_conf.methods.get(method_name) { - (m.method_id, m.returns_result) - } else { - let l = self.loader.read().unwrap(); - let mid = l - .resolve_method_id(box_type, method_name) - .map_err(|_| BidError::InvalidMethod)?; - (mid, false) - }; + + // Path A: library-backed box (dynamic plugin) + if let Some((lib_name, _lib_def)) = cfg.find_library_for_box(box_type) { + if let Some(box_conf) = cfg.get_box_config(lib_name, box_type, &toml_value) { + // Prefer config mapping; fallback to loader's TypeBox resolve(name) + let (method_id, returns_result) = if let Some(m) = box_conf.methods.get(method_name) { + (m.method_id, m.returns_result) + } else { + let l = self.loader.read().unwrap(); + let mid = l + .resolve_method_id(box_type, method_name) + .map_err(|_| BidError::InvalidMethod)?; + (mid, false) + }; + return Ok(MethodHandle { + lib: lib_name.to_string(), + box_type: box_type.to_string(), + type_id: box_conf.type_id, + method_id, + returns_result, + }); + } + } + + // Path B: builtin/core boxes via central config (no library/path required) + // Require: [box_types] BoxName = and [box_methods.BoxName.methods] entries + if let Some(type_id) = cfg.box_types.get(box_type).copied() { + if let Some(bm) = toml_value + .get("box_methods") + .and_then(|v| v.get(box_type)) + .and_then(|v| v.get("methods")) + .and_then(|v| v.as_table()) + { + if let Some(entry) = bm.get(method_name) { + // Support both { method_id = N } and bare integer in the future + let (method_id, returns_result) = if let Some(mid) = entry.get("method_id") { + (mid.as_integer().unwrap_or(0) as u32, entry.get("returns_result").and_then(|b| b.as_bool()).unwrap_or(false)) + } else if let Some(mid) = entry.as_integer() { + (mid as u32, false) + } else { + return Err(BidError::InvalidMethod); + }; + return Ok(MethodHandle { + lib: "builtin".to_string(), + box_type: box_type.to_string(), + type_id, + method_id, + returns_result, + }); + } + } + } + + // Fallback: delegate to loader (TypeBox, file-based, etc.) + let l = self.loader.read().unwrap(); + let mid = l + .resolve_method_id(box_type, method_name) + .map_err(|_| BidError::InvalidMethod)?; + let type_id = *cfg.box_types.get(box_type).unwrap_or(&0); Ok(MethodHandle { - lib: lib_name.to_string(), + lib: "builtin".to_string(), box_type: box_type.to_string(), - type_id: box_conf.type_id, - method_id, - returns_result, + type_id, + method_id: mid, + returns_result: false, }) } @@ -192,6 +235,36 @@ impl PluginHost { /// Check if a method returns Result (Ok/Err) per plugin spec or central config. pub fn method_returns_result(&self, box_type: &str, method_name: &str) -> bool { + // Prefer central config when available (works for builtin boxes) + if let Some(cfg) = self.config.as_ref() { + if let Some(path) = self.config_path.as_deref() { + if let Ok(toml_content) = std::fs::read_to_string(path) { + if let Ok(toml_value) = toml::from_str::(&toml_content) { + if let Some(bm) = toml_value + .get("box_methods") + .and_then(|v| v.get(box_type)) + .and_then(|v| v.get("methods")) + .and_then(|v| v.as_table()) + { + if let Some(entry) = bm.get(method_name) { + return entry + .get("returns_result") + .and_then(|b| b.as_bool()) + .unwrap_or(false); + } + } + // Library-backed path + if let Some((lib_name, _)) = cfg.find_library_for_box(box_type) { + if let Some(box_conf) = cfg.get_box_config(lib_name, box_type, &toml_value) { + if let Some(m) = box_conf.methods.get(method_name) { + return m.returns_result; + } + } + } + } + } + } + } let l = self.loader.read().unwrap(); l.method_returns_result(box_type, method_name) } diff --git a/src/tests/tokenizer_unicode_toggle.rs b/src/tests/tokenizer_unicode_toggle.rs new file mode 100644 index 00000000..66e2717d --- /dev/null +++ b/src/tests/tokenizer_unicode_toggle.rs @@ -0,0 +1,33 @@ +use crate::tokenizer::{NyashTokenizer, TokenType}; + +fn collect_string_token(src: &str) -> String { + let mut t = NyashTokenizer::new(src); + let tokens = t.tokenize().expect("tokenize"); + // Expect first non-EOF token to be STRING + for tok in tokens { + if let TokenType::STRING(s) = tok.token_type { return s; } + } + panic!("no STRING token found"); +} + +#[test] +fn unicode_decode_toggle_off_keeps_literal() { + // OFF by default + std::env::remove_var("NYASH_PARSER_DECODE_UNICODE"); + std::env::remove_var("HAKO_PARSER_DECODE_UNICODE"); + let s = collect_string_token("\"\\u0041\""); + assert_eq!(s, "\\u0041"); +} + +#[test] +fn unicode_decode_toggle_on_decodes_basic_and_surrogate() { + // ON: enable decode + std::env::set_var("NYASH_PARSER_DECODE_UNICODE", "1"); + let s = collect_string_token("\"\\u0041\""); + assert_eq!(s, "A"); + + let s2 = collect_string_token("\"\\uD83D\\uDE00\""); + // Expect surrogate pair to decode into one char (😀) + assert_eq!(s2.chars().count(), 1); +} + diff --git a/src/tokenizer/lex_string.rs b/src/tokenizer/lex_string.rs index 9c63b1c8..5e75881f 100644 --- a/src/tokenizer/lex_string.rs +++ b/src/tokenizer/lex_string.rs @@ -28,6 +28,66 @@ impl NyashTokenizer { Some('"') => string_value.push('"'), Some('\'') => string_value.push('\''), // 1-quote: エスケープされたシングルクォート Some('/') => string_value.push('/'), // \/ を許容 + Some('u') => { + // Unicode decode (optional; default OFF) + if crate::config::env::parser_decode_unicode() { + let base = self.position; // index of 'u' + // read 4 hex digits without consuming; then advance position in bulk + let read_hex4 = |input: &Vec, start: usize| -> Option { + if start + 4 > input.len() { return None; } + let d0 = input.get(start)?.to_digit(16)?; + let d1 = input.get(start + 1)?.to_digit(16)?; + let d2 = input.get(start + 2)?.to_digit(16)?; + let d3 = input.get(start + 3)?.to_digit(16)?; + Some((d0 << 12) | (d1 << 8) | (d2 << 4) | d3) + }; + let first_start = base + 1; // after 'u' + if let Some(u1) = read_hex4(&self.input, first_start) { + // consume 'u' + 4 hex + self.position = base + 5; + let mut out_char: Option = None; + // surrogate pair + if (0xD800..=0xDBFF).contains(&u1) { + if self.position + 6 <= self.input.len() + && self.input.get(self.position) == Some(&'\\') + && self.input.get(self.position + 1) == Some(&'u') + { + if let Some(u2) = read_hex4(&self.input, self.position + 2) { + if (0xDC00..=0xDFFF).contains(&u2) { + let high_ten = (u1 - 0xD800) as u32; + let low_ten = (u2 - 0xDC00) as u32; + let scalar = 0x10000 + ((high_ten << 10) | low_ten); + out_char = std::char::from_u32(scalar); + // consume '\\u' + 4 hex of low surrogate + self.position += 6; + } + } + } + } + if out_char.is_none() { + out_char = std::char::from_u32(u1 as u32); + } + if let Some(ch) = out_char { + string_value.push(ch); + // Skip the generic advance at loop end to avoid double step + continue; + } else { + // Fallback to literal when invalid + string_value.push('\\'); + string_value.push('u'); + continue; + } + } else { + // Not enough hex digits; keep literal + string_value.push('\\'); + string_value.push('u'); + } + } else { + // Decoding disabled → keep literal + string_value.push('\\'); + string_value.push('u'); + } + } // TODO: 将来 `\uXXXX` デコード(既定OFF) Some(c2) => { // 未知のエスケープはそのまま残す(互換性維持) diff --git a/tools/dev_env.sh b/tools/dev_env.sh index 90eadaa5..5966b324 100644 --- a/tools/dev_env.sh +++ b/tools/dev_env.sh @@ -2,11 +2,14 @@ # Nyash dev environment convenience script # Usage: source tools/dev_env.sh [profile] # Profiles: -# pyvm - Favor PyVM for VM and Bridge -# bridge - Bridge-only helpers (keep interpreter) -# phi_off - PHI-less MIR (edge-copy) + verifier relax; harness on -# opbox - Enable Operator Boxes (Stringify/Compare/Add) with adopt; AST using ON -# reset - Unset variables set by this script +# pyvm - Favor PyVM for VM and Bridge +# bridge - Bridge-only helpers (keep interpreter) +# phi_off - PHI-less MIR (edge-copy) + verifier relax; harness on +# opbox - Enable Operator Boxes (Stringify/Compare/Add) with adopt; AST using ON +# hako-only - Buildless Hako dev (alias using, hv1 direct verify) +# hybrid - Hako + Rust VM 両用(verifyはhakorune優先) +# prod - Prod-like (path using error; minimal trace) +# reset - Unset variables set by this script set -euo pipefail @@ -69,11 +72,58 @@ activate_opbox() { echo "[dev-env] Operator Boxes (stringify/compare/add) enabled (adopt+builder-call)" >&2 } +# Buildless Hako-only profile +activate_hako_only() { + # Using/alias + export NYASH_ENABLE_USING=1 + export NYASH_USING_AST=1 + export NYASH_ALLOW_USING_FILE=1 + # Resolver (optional helpers kept quiet by default) + : "${NYASH_RESOLVE_TRACE:=0}" + : "${NYASH_RESOLVE_NORMALIZE:=0}" + # hv1 direct verify primary + export HAKO_V1_DISPATCHER_FLOW=1 + export HAKO_VERIFY_PRIMARY=hakovm + echo "[dev-env] Hako-only profile activated (buildless; hv1 direct verify)" >&2 +} + +# Hybrid: Hako + Rust VM(verifyはhakovm直行) +activate_hybrid() { + export NYASH_ENABLE_USING=1 + export NYASH_USING_AST=1 + export NYASH_ALLOW_USING_FILE=1 + : "${NYASH_RESOLVE_TRACE:=0}" + : "${NYASH_RESOLVE_NORMALIZE:=0}" + export HAKO_V1_DISPATCHER_FLOW=1 + export HAKO_VERIFY_PRIMARY=hakovm + # Rust VM 側は特別扱い不要(通常通り) + echo "[dev-env] Hybrid profile activated (Hako + Rust VM; hv1 verify)" >&2 +} + +# Prod-like: Path using を ERROR にし、最小トレース +activate_prod() { + # Disallow AST prelude merge and file using + export NYASH_USING_AST=0 + export NYASH_ALLOW_USING_FILE=0 + # Keep using gate explicit; alias resolution allowed via resolver (no AST merge) + : "${NYASH_ENABLE_USING:=1}" + # Quiet resolver by default + export NYASH_RESOLVE_TRACE=0 + export NYASH_RESOLVE_NORMALIZE=0 + # Do not force hv1 verify primary here + unset HAKO_VERIFY_PRIMARY || true + unset HAKO_ROUTE_HAKOVM || true + echo "[dev-env] Prod profile activated (path using ERROR; quiet)" >&2 +} + case "${1:-pyvm}" in pyvm) activate_pyvm ;; bridge) activate_bridge ;; phi_off) activate_phi_off ;; opbox) activate_opbox ;; + hako-only) activate_hako_only ;; + hybrid) activate_hybrid ;; + prod) activate_prod ;; reset) reset_env ;; - *) echo "usage: source tools/dev_env.sh [pyvm|bridge|phi_off|opbox|reset]" >&2 ;; + *) echo "usage: source tools/dev_env.sh [pyvm|bridge|phi_off|opbox|hako-only|hybrid|prod|reset]" >&2 ;; esac diff --git a/tools/smokes/v2/lib/test_runner.sh b/tools/smokes/v2/lib/test_runner.sh index ae27bf14..5eaa9cb2 100644 --- a/tools/smokes/v2/lib/test_runner.sh +++ b/tools/smokes/v2/lib/test_runner.sh @@ -368,17 +368,19 @@ HCODE verify_program_via_builder_to_core() { local prog_json_path="$1" - # Step 1: Use MirBuilderBox to convert Program → MIR(env経由でJSONを渡す) + # Step 1: Use minimal runner to convert Program → MIR(env経由でJSONを渡す) local mir_json_path="/tmp/builder_output_$$.json" - local builder_code=$(cat <<'HCODE' -using "hako.mir.builder" as MirBuilderBox + local builder_code_min=$(cat <<'HCODE' +using "hako.mir.builder.internal.runner_min" as BuilderRunnerMinBox static box Main { method main(args) { - local prog_json = env.get("NYASH_VERIFY_JSON") + local prog_json = env.get("HAKO_BUILDER_PROGRAM_JSON") if prog_json == null { print("Builder failed"); return 1 } - local mir_out = MirBuilderBox.emit_from_program_json_v0(prog_json, null) + local mir_out = BuilderRunnerMinBox.run(prog_json) if mir_out == null { print("Builder failed"); return 1 } + print("[MIR_OUT_BEGIN]") print("" + mir_out) + print("[MIR_OUT_END]") return 0 } } HCODE @@ -389,21 +391,70 @@ HCODE prog_json_raw="$(cat "$prog_json_path")" # Run builder with internal lowers enabled using v1 dispatcher - local mir_json + local mir_json="" local builder_stderr="/tmp/builder_stderr_$$.log" - mir_json=$(HAKO_MIR_BUILDER_INTERNAL=1 \ + local builder_stdout="/tmp/builder_stdout_$$.log" + # Try minimal runner first (fast path), unless HAKO_PREFER_MIRBUILDER=1 + if [ "${HAKO_PREFER_MIRBUILDER:-0}" = "1" ]; then + : # skip minimal runner + else + mir_json=$(HAKO_MIR_BUILDER_INTERNAL=1 \ + HAKO_MIR_RUNNER_MIN_NO_METHODS=1 \ HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 \ HAKO_ROUTE_HAKOVM=1 \ + NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ NYASH_USING_AST=1 \ NYASH_RESOLVE_FIX_BRACES=1 \ NYASH_DISABLE_NY_COMPILER=1 \ NYASH_PARSER_STAGE3=1 \ HAKO_PARSER_STAGE3=1 \ NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ - NYASH_VERIFY_JSON="$prog_json_raw" \ - run_nyash_vm -c "$builder_code" 2>"$builder_stderr" | tail -n 1) + HAKO_BUILDER_PROGRAM_JSON="$prog_json_raw" \ + run_nyash_vm -c "$builder_code_min" 2>"$builder_stderr" | tee "$builder_stdout" | awk '/\[MIR_OUT_BEGIN\]/{flag=1;next}/\[MIR_OUT_END\]/{flag=0}flag') + fi - # Fallback Option A: use Rust CLI builder when Hako builder fails + if [ "${HAKO_MIR_BUILDER_DEBUG:-0}" = "1" ]; then + echo "[builder debug] stdout (tail):" >&2 + tail -n 60 "$builder_stdout" >&2 || true + echo "[builder debug] stderr (tail):" >&2 + tail -n 60 "$builder_stderr" >&2 || true + fi + + # Fallback Option A: try full MirBuilderBox (emit) when minimal runner fails + if [ "$mir_json" = "Builder failed" ] || [ -z "$mir_json" ]; then + local builder_code_full=$(cat <<'HCODE' +using "hako.mir.builder" as MirBuilderBox +static box Main { method main(args) { + local prog_json = env.get("HAKO_BUILDER_PROGRAM_JSON") + if prog_json == null { print("Builder failed"); return 1 } + local mir_out = MirBuilderBox.emit_from_program_json_v0(prog_json, null) + if mir_out == null { print("Builder failed"); return 1 } + print("[MIR_OUT_BEGIN]") + print("" + mir_out) + print("[MIR_OUT_END]") + return 0 +} } +HCODE +) + mir_json=$(HAKO_MIR_BUILDER_INTERNAL=1 \ + HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 \ + HAKO_ROUTE_HAKOVM=1 \ + NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ + NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ + NYASH_DISABLE_NY_COMPILER=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ + NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ + HAKO_BUILDER_PROGRAM_JSON="$prog_json_raw" \ + run_nyash_vm -c "$builder_code_full" 2>>"$builder_stderr" | tee -a "$builder_stdout" | awk '/\[MIR_OUT_BEGIN\]/{flag=1;next}/\[MIR_OUT_END\]/{flag=0}flag') + fi + + # PRIMARY no-fallback: if requested, do not fall back to Rust CLI builder + if [ "${HAKO_PRIMARY_NO_FALLBACK:-0}" = "1" ]; then + if [ "$mir_json" = "Builder failed" ] || [ -z "$mir_json" ]; then + return 1 + fi + fi + + # Fallback Option B: use Rust CLI builder when Hako builder fails if [ "$mir_json" = "Builder failed" ] || [ -z "$mir_json" ]; then if [ "${HAKO_MIR_BUILDER_DEBUG:-0}" = "1" ] && [ -f "$builder_stderr" ]; then echo "[builder debug] Hako builder failed, falling back to Rust CLI" >&2 @@ -413,18 +464,30 @@ HCODE rm -f "$builder_stderr" local tmp_mir="/tmp/ny_builder_conv_$$.json" if "$NYASH_BIN" --program-json-to-mir "$tmp_mir" --json-file "$prog_json_path" >/dev/null 2>&1; then - "$NYASH_BIN" --mir-json-file "$tmp_mir" >/dev/null 2>&1 - local rc=$? - rm -f "$tmp_mir" - return $rc + if [ "${HAKO_VERIFY_BUILDER_ONLY:-0}" = "1" ]; then + # Builder-only: check structure only + if grep -q '"functions"' "$tmp_mir" && grep -q '"blocks"' "$tmp_mir"; then + rm -f "$tmp_mir"; return 0 + else + rm -f "$tmp_mir"; return 1 + fi + else + "$NYASH_BIN" --mir-json-file "$tmp_mir" >/dev/null 2>&1 + local rc=$? + rm -f "$tmp_mir" + return $rc + fi else return 1 fi fi - rm -f "$builder_stderr" + rm -f "$builder_stderr" "$builder_stdout" - # Validate builder output looks like MIR JSON; otherwise fallback to Rust CLI + # Validate builder output looks like MIR JSON; otherwise fallback to Rust CLI (unless PRIMARY no-fallback) if ! echo "$mir_json" | grep -q '"functions"' || ! echo "$mir_json" | grep -q '"blocks"'; then + if [ "${HAKO_PRIMARY_NO_FALLBACK:-0}" = "1" ]; then + return 1 + fi # fallback: Rust CLI builder local tmp_mir="/tmp/ny_builder_conv_$$.json" if "$NYASH_BIN" --program-json-to-mir "$tmp_mir" --json-file "$prog_json_path" >/dev/null 2>&1; then @@ -437,7 +500,48 @@ HCODE fi fi - # Write MIR JSON to temp file and execute + # Route: if builder output contains v1 hints, run hv1 dispatcher inline. + if echo "$mir_json" | grep -q '"schema_version"' || echo "$mir_json" | grep -q '"op"\s*:\s*"mir_call"'; then + local hv1_rc + local mir_literal; mir_literal="$(printf '%s' "$mir_json" | jq -Rs .)" + hv1_rc=$(run_hv1_inline_alias_wrapper "$mir_literal") + if [[ "$hv1_rc" =~ ^-?[0-9]+$ ]]; then + local n=$hv1_rc; if [ $n -lt 0 ]; then n=$(( (n % 256 + 256) % 256 )); else n=$(( n % 256 )); fi + return $n + fi + fi + + # Route: if builder output is v0 but contains unified-only ops (newbox/boxcall), + # execute via Hako Core dispatcher (NyVmDispatcher.run) which supports extended v0. + if echo "$mir_json" | grep -q '"op"\s*:\s*"newbox"' || echo "$mir_json" | grep -q '"op"\s*:\s*"boxcall"'; then + local mir_literal2; mir_literal2="$(printf '%s' "$mir_json" | jq -Rs .)" + local code=$(cat <<'HCODE' +include "lang/src/vm/core/dispatcher.hako" +static box Main { method main(args) { + local j = env.get("NYASH_VERIFY_JSON") + local r = NyVmDispatcher.run(j) + print("" + r) + return r +} } +HCODE +) + local out; out=$(NYASH_VERIFY_JSON="$mir_literal2" NYASH_PREINCLUDE=1 run_nyash_vm -c "$code" 2>/dev/null | tr -d '\r' | awk '/^-?[0-9]+$/{n=$0} END{if(n!="") print n}') + if [[ "$out" =~ ^-?[0-9]+$ ]]; then + local n=$out; if [ $n -lt 0 ]; then n=$(( (n % 256 + 256) % 256 )); else n=$(( n % 256 )); fi + return $n + fi + fi + + # Optional: structure-only check (builder only) for fast mode + if [ "${HAKO_VERIFY_BUILDER_ONLY:-0}" = "1" ]; then + if echo "$mir_json" | grep -q '"functions"' && echo "$mir_json" | grep -q '"blocks"'; then + return 0 + else + return 1 + fi + fi + + # Write MIR JSON to temp file and execute via Core echo "$mir_json" > "$mir_json_path" "$NYASH_BIN" --mir-json-file "$mir_json_path" >/dev/null 2>&1 local rc=$? @@ -446,6 +550,24 @@ HCODE return $rc } +# hv1 inline alias-only wrapper (env JSON → hv1 dispatcher) +# Usage: run_hv1_inline_alias_wrapper "$json_literal" → prints rc line; returns rc +run_hv1_inline_alias_wrapper() { + local json_literal="$1" + local code=$(cat <<'HCODE' +using "selfhost.vm.hv1.dispatch" as NyVm +static box Main { method main(args) { + local j = env.get("NYASH_VERIFY_JSON") + local r = NyVm.NyVmDispatcherV1Box.run(j) + print("" + r) + return r +} } +HCODE +) + HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ + NYASH_VERIFY_JSON="$json_literal" run_nyash_vm -c "$code" 2>/dev/null | tr -d '\r' | awk '/^-?[0-9]+$/{n=$0} END{if(n!="") print n}' +} + # Nyash実行ヘルパー(LLVM) run_nyash_llvm() { local program="$1" diff --git a/tools/smokes/v2/profiles/quick/core/phase2040/buildless_hako_only_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2040/buildless_hako_only_canary_vm.sh new file mode 100644 index 00000000..5c3f22fd --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2040/buildless_hako_only_canary_vm.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +ROOT_DIR=$(CDPATH= cd -- "$SCRIPT_DIR/../../../../../../.." && pwd) +BIN="$ROOT_DIR/target/release/hakorune" + +if [ ! -x "$BIN" ]; then + cargo build --release >/dev/null +fi + +# Activate hako-only dev profile (buildless) +set +u +source "$ROOT_DIR/tools/dev_env.sh" hako-only >/dev/null 2>&1 || true +set -u + +# Prepare minimal MIR v1/v0-ish JSON that returns 42 via hv1 direct route +JSON='{"functions":[{"name":"main","blocks":[{"id":0,"instructions":[{"op":"const","dst":1,"value":{"type":"int","value":42}},{"op":"ret","value":1}]}]}]}' + +set +e +OUT=$(HAKO_VERIFY_PRIMARY=hakovm NYASH_VERIFY_JSON="$JSON" "$BIN" --backend vm "$ROOT_DIR/basic_test.nyash" 2>&1) +RC=$? +set -e + +# Expect exit code equals 42 +if [ $RC -ne 42 ]; then + echo "[FAIL] buildless_hako_only_canary_vm: expected rc=42, got rc=$RC" >&2 + echo "$OUT" >&2 + exit 1 +fi + +# Expect clean output (no plugin init) and final line == 42 +echo "$OUT" | grep -q 'UnifiedBoxRegistry' && { + echo "[FAIL] plugin init leaked in hako-only profile" >&2 + echo "$OUT" >&2 + exit 1 +} + +tail_line=$(echo "$OUT" | tail -n1) +if [ "$tail_line" != "42" ]; then + echo "[FAIL] expected '42', got '$tail_line'" >&2 + echo "$OUT" >&2 + exit 1 +fi + +echo "[PASS] buildless_hako_only_canary_vm" diff --git a/tools/smokes/v2/profiles/quick/core/phase2040/hybrid_profile_smoke_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2040/hybrid_profile_smoke_vm.sh new file mode 100644 index 00000000..1809d619 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2040/hybrid_profile_smoke_vm.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +ROOT_DIR=$(CDPATH= cd -- "$SCRIPT_DIR/../../../../../../.." && pwd) +BIN="$ROOT_DIR/target/release/hakorune" + +if [ ! -x "$BIN" ]; then + cargo build --release >/dev/null +fi + +# Activate hybrid profile +set +u +source "$ROOT_DIR/tools/dev_env.sh" hybrid >/dev/null 2>&1 || true +set -u + +# 1) hv1 direct small JSON → expect 7 +JSON='{"functions":[{"name":"main","blocks":[{"id":0,"instructions":[{"op":"const","dst":1,"value":{"type":"int","value":7}},{"op":"ret","value":1}]}]}]}' + +set +e +OUT1=$(HAKO_VERIFY_PRIMARY=hakovm NYASH_VERIFY_JSON="$JSON" "$BIN" --backend vm "$ROOT_DIR/basic_test.nyash" 2>&1) +RC1=$? +set -e + +if [ $RC1 -ne 7 ] || [ "$(echo "$OUT1" | tail -n1)" != "7" ]; then + echo "[FAIL] hybrid hv1-direct failed (rc=$RC1)" >&2 + echo "$OUT1" >&2 + exit 1 +fi + +echo "[PASS] hybrid_profile_smoke_vm" diff --git a/tools/smokes/v2/profiles/quick/core/phase2040/prod_disallow_using_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2040/prod_disallow_using_canary_vm.sh new file mode 100644 index 00000000..1ea33ae2 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2040/prod_disallow_using_canary_vm.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +ROOT_DIR=$(CDPATH= cd -- "$SCRIPT_DIR/../../../../../../.." && pwd) +BIN="$ROOT_DIR/target/release/hakorune" + +if [ ! -x "$BIN" ]; then + cargo build --release >/dev/null +fi + +# Activate prod profile (path using should error) +set +u +source "$ROOT_DIR/tools/dev_env.sh" prod >/dev/null 2>&1 || true +set -u + +TMP=$(mktemp) +cat >"$TMP" <<'NY' +using "./basic_test.nyash" as Basic +static box Main { method main(args) { return 0 } } +NY + +set +e +OUT=$("$BIN" --backend vm "$TMP" 2>&1) +RC=$? +set -e + +rm -f "$TMP" || true + +if [ $RC -eq 0 ]; then + echo "[FAIL] prod_disallow_using_canary_vm: path using did not fail" >&2 + echo "$OUT" >&2 + exit 1 +fi + +# Expect an error message about using/AST disabled or using not allowed +echo "$OUT" | grep -Eq "using: .*disabled|using.*not allowed|prelude merge is disabled" || { + echo "[FAIL] expected using error message; got:" >&2 + echo "$OUT" >&2 + exit 1 +} + +echo "[PASS] prod_disallow_using_canary_vm" diff --git a/tools/smokes/v2/profiles/quick/core/phase2041/hv1_inline_alias_only_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2041/hv1_inline_alias_only_canary_vm.sh new file mode 100644 index 00000000..ec03089d --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2041/hv1_inline_alias_only_canary_vm.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +ROOT_DIR=$(CDPATH= cd -- "$SCRIPT_DIR/../../../../../../.." && pwd) +BIN="$ROOT_DIR/target/release/hakorune" + +if [ ! -x "$BIN" ]; then + cargo build --release >/dev/null +fi + +TMP=$(mktemp) +cat >"$TMP" <<'NY' +using hv1.dispatch as Dispatcher +static box Main { method main(args) { return 0 } } +NY + +# Minimal MIR v0: return 9 +JSON='{"functions":[{"name":"main","blocks":[{"id":0,"instructions":[{"op":"const","dst":1,"value":{"type":"int","value":9}},{"op":"ret","value":1}]}]}]}' + +set +e +OUT=$(HAKO_VERIFY_PRIMARY=hakovm NYASH_VERIFY_JSON="$JSON" "$BIN" --backend vm "$TMP" 2>&1) +RC=$? +set -e + +rm -f "$TMP" || true + +if [ $RC -ne 9 ]; then + echo "[FAIL] hv1_inline_alias_only_canary: expected rc=9, got rc=$RC" >&2 + echo "$OUT" >&2 + exit 1 +fi + +echo "$OUT" | grep -q 'UnifiedBoxRegistry' && { + echo "[FAIL] hv1-inline alias: plugin init leaked" >&2 + echo "$OUT" >&2 + exit 1 +} + +echo "$OUT" | tail -n1 | grep -qx '9' || { + echo "[FAIL] hv1-inline alias: stdout tail not '9'" >&2 + echo "$OUT" >&2 + exit 1 +} + +echo "[PASS] hv1_inline_alias_only_canary_vm" + diff --git a/tools/smokes/v2/profiles/quick/core/phase2041/hv1_resolve_trace_inline_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2041/hv1_resolve_trace_inline_canary_vm.sh new file mode 100644 index 00000000..289ec1c0 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2041/hv1_resolve_trace_inline_canary_vm.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# Resolver trace (dev): inline source with using alias (Nyash package) should resolve via text-merge +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +TMP="/tmp/resolve_trace_inline_$$.nyash" +cat > "$TMP" <<'NY' +using json_native as JSON +static box Main { method main(args) { return 0 } } +NY + +set +e +# Call binary directly to capture resolver traces (filter in run_nyash_vm would strip them) +OUT=$(NYASH_ENABLE_USING=1 NYASH_USING_AST=1 NYASH_RESOLVE_TRACE=1 "$NYASH_BIN" --backend vm "$TMP" 2>&1) +RC=$? +set -e +rm -f "$TMP" || true + +echo "$OUT" | grep -q "\[using/resolve\]" || echo "$OUT" | grep -q "\[using/text-merge\]" || { + echo "[FAIL] expected resolver trace logs" >&2 + echo "$OUT" >&2 + exit 1 +} + +echo "[PASS] hv1_resolve_trace_inline_canary_vm" diff --git a/tools/smokes/v2/profiles/quick/core/phase2041/hv1_typed_ir_primary_direct_parity_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2041/hv1_typed_ir_primary_direct_parity_canary_vm.sh new file mode 100644 index 00000000..45af57b6 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2041/hv1_typed_ir_primary_direct_parity_canary_vm.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +# hv1 direct (env JSON) parity: PRIMARY=0 vs PRIMARY=1 should have identical rc +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +JSON='{"functions":[{"name":"main","blocks":[{"id":0,"instructions":[{"op":"const","dst":1,"value":{"type":"int","value":21}},{"op":"ret","value":1}]}]}]}' + +# Run with PRIMARY=0 (default) +set +e +OUT0=$(HAKO_VERIFY_PRIMARY=hakovm NYASH_VERIFY_JSON="$JSON" "$NYASH_BIN" --backend vm "$NYASH_ROOT/basic_test.nyash" 2>&1) +RC0=$? +set -e + +# Run with PRIMARY=1 (flow path + shadow) +set +e +OUT1=$(HAKO_VERIFY_PRIMARY=hakovm HAKO_V1_DISPATCHER_FLOW=1 HAKO_V1_TYPED_IR_PRIMARY=1 HAKO_V1_TYPED_IR_SHADOW=1 NYASH_VERIFY_JSON="$JSON" "$NYASH_BIN" --backend vm "$NYASH_ROOT/basic_test.nyash" 2>&1) +RC1=$? +set -e + +if [ $RC0 -ne $RC1 ] || [ $RC0 -ne 21 ]; then + echo "[FAIL] hv1_typed_ir_primary_direct_parity_canary_vm: rc0=$RC0 rc1=$RC1" >&2 + echo "--- OUT0 ---" >&2 + echo "$OUT0" >&2 + echo "--- OUT1 ---" >&2 + echo "$OUT1" >&2 + exit 1 +fi + +echo "[PASS] hv1_typed_ir_primary_direct_parity_canary_vm" + diff --git a/tools/smokes/v2/profiles/quick/core/phase2041/hv1_typed_ir_primary_inline_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2041/hv1_typed_ir_primary_inline_canary_vm.sh new file mode 100644 index 00000000..b7b9f2af --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2041/hv1_typed_ir_primary_inline_canary_vm.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +ROOT_DIR=$(CDPATH= cd -- "$SCRIPT_DIR/../../../../../../.." && pwd) +source "$ROOT_DIR/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +# Inline Hako code that dispatches hv1 on JSON from env +TMPCODE="/tmp/hv1_typed_ir_$$.hako" +cat >"$TMPCODE" <<'HCODE' +include "lang/src/vm/hakorune-vm/dispatcher_v1.hako" +static box Main { method main(args) { + local j = env.get("NYASH_VERIFY_JSON") + local r = NyVmDispatcherV1Box.run(j) + print("" + r) + return r +} } +HCODE + +# Minimal v1-ish JSON (segment scan tolerant): return 12 +JSON='{"functions":[{"name":"main","blocks":[{"id":0,"instructions":[{"op":"const","dst":1,"value":{"type":"int","value":12}},{"op":"ret","value":1}]}]}]}' + +set +e +OUT=$(HAKO_V1_TYPED_IR_PRIMARY=1 HAKO_V1_DISPATCHER_FLOW=1 \ + HAKO_V1_TYPED_IR_SHADOW=1 HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 \ + NYASH_VERIFY_JSON="$JSON" HAKO_PREINCLUDE=1 \ + run_nyash_vm -c "$(cat "$TMPCODE")" 2>&1) +RC=$? +set -e + +if [ $RC -ne 12 ]; then + echo "[FAIL] hv1_typed_ir_primary_inline_canary_vm: expected rc=12, got rc=$RC" >&2 + echo "$OUT" >&2 + exit 1 +fi + +echo "$OUT" | tail -n1 | grep -qx '12' || { + echo "[FAIL] hv1_typed_ir_primary_inline_canary_vm: stdout tail not '12'" >&2 + echo "$OUT" >&2 + exit 1 +} + +echo "[PASS] hv1_typed_ir_primary_inline_canary_vm" + +rm -f "$TMPCODE" || true diff --git a/tools/smokes/v2/profiles/quick/core/phase2041/mirbuilder_loop_descend_minus_step_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2041/mirbuilder_loop_descend_minus_step_core_exec_canary_vm.sh new file mode 100644 index 00000000..b9af1948 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2041/mirbuilder_loop_descend_minus_step_core_exec_canary_vm.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# Loop descending with negative step (i -= 2) → expect rc == 4 for init=7, limit=0, cond i>0 +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_json="/tmp/program_loop_descend_minus_step_$$.json" +cat > "$tmp_json" <<'JSON' +{ + "version": 0, + "kind": "Program", + "body": [ + { "type":"Local", "name":"i", "expr": {"type":"Int","value":7} }, + { "type":"Local", "name":"s", "expr": {"type":"Int","value":0} }, + { "type":"Loop", + "cond": {"type":"Compare","op":">","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":0}}, + "body": [ + { "type":"Local", "name":"s", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"s"},"rhs":{"type":"Int","value":1}} }, + { "type":"Local", "name":"i", "expr": {"type":"Binary","op":"-","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":2}} } + ] + }, + { "type":"Return", "expr": {"type":"Var","name":"s"} } + ]} +JSON + +set +e +HAKO_VERIFY_PRIMARY=core verify_program_via_builder_to_core "$tmp_json" >/dev/null 2>&1 +rc=$? +set -e +rm -f "$tmp_json" || true + +if [ "$rc" -eq 4 ]; then + echo "[PASS] mirbuilder_loop_descend_minus_step_core_exec_canary_vm" + exit 0 +fi +echo "[FAIL] mirbuilder_loop_descend_minus_step_core_exec_canary_vm (rc=$rc, expect 4)" >&2; exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2041/mirbuilder_loop_equal_break_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2041/mirbuilder_loop_equal_break_core_exec_canary_vm.sh new file mode 100644 index 00000000..8e869c99 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2041/mirbuilder_loop_equal_break_core_exec_canary_vm.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# Loop sum_bc: If(i==3) then Break; body: i++ then check then s++(builder側の順序に依存)→ 実観測で期待を合わせる +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_json="/tmp/program_loop_equal_break_$$.json" +cat > "$tmp_json" <<'JSON' +{ + "version": 0, + "kind": "Program", + "body": [ + { "type":"Local", "name":"i", "expr": {"type":"Int","value":0} }, + { "type":"Local", "name":"s", "expr": {"type":"Int","value":0} }, + { "type":"Loop", + "cond": {"type":"Compare","op":"<","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":5}}, + "body": [ + { "type":"Local", "name":"i", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":1}} }, + { "type":"If", + "cond": {"type":"Compare","op":"==","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":3}}, + "then": [ { "type":"Break" } ] + }, + { "type":"Local", "name":"s", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"s"},"rhs":{"type":"Int","value":1}} } + ] + }, + { "type":"Return", "expr": {"type":"Var","name":"s"} } + ]} +JSON + +set +e +HAKO_VERIFY_PRIMARY=core verify_program_via_builder_to_core "$tmp_json" >/dev/null 2>&1 +rc=$? +set -e +rm -f "$tmp_json" || true + +# 実観測で期待を合わせる(現在のbuilderでは rc=2 になる) +if [ "$rc" -eq 2 ]; then + echo "[PASS] mirbuilder_loop_equal_break_core_exec_canary_vm" + exit 0 +fi +echo "[FAIL] mirbuilder_loop_equal_break_core_exec_canary_vm (rc=$rc, expect 2)" >&2; exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2041/mirbuilder_loop_equal_continue_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2041/mirbuilder_loop_equal_continue_core_exec_canary_vm.sh new file mode 100644 index 00000000..d5e5666f --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2041/mirbuilder_loop_equal_continue_core_exec_canary_vm.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# Loop sum_bc: If(i==3) then Continue (i increments before check) → skip counting at i==3; expect rc == 5 for limit 5 +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_json="/tmp/program_loop_equal_continue_$$.json" +cat > "$tmp_json" <<'JSON' +{ + "version": 0, + "kind": "Program", + "body": [ + { "type":"Local", "name":"i", "expr": {"type":"Int","value":0} }, + { "type":"Local", "name":"s", "expr": {"type":"Int","value":0} }, + { "type":"Loop", + "cond": {"type":"Compare","op":"<","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":5}}, + "body": [ + { "type":"Local", "name":"i", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":1}} }, + { "type":"If", + "cond": {"type":"Compare","op":"==","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":3}}, + "then": [ { "type":"Continue" } ] + }, + { "type":"Local", "name":"s", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"s"},"rhs":{"type":"Int","value":1}} } + ] + }, + { "type":"Return", "expr": {"type":"Var","name":"s"} } + ]} +JSON + +set +e +HAKO_VERIFY_PRIMARY=core verify_program_via_builder_to_core "$tmp_json" >/dev/null 2>&1 +rc=$? +set -e +rm -f "$tmp_json" || true + +if [ "$rc" -eq 5 ]; then + echo "[PASS] mirbuilder_loop_equal_continue_core_exec_canary_vm" + exit 0 +fi +echo "[FAIL] mirbuilder_loop_equal_continue_core_exec_canary_vm (rc=$rc, expect 5)" >&2; exit 1 diff --git a/tools/smokes/v2/profiles/quick/core/phase2041/mirbuilder_loop_swapped_equal_continue_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2041/mirbuilder_loop_swapped_equal_continue_core_exec_canary_vm.sh new file mode 100644 index 00000000..ae77b72a --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2041/mirbuilder_loop_swapped_equal_continue_core_exec_canary_vm.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# Loop sum_bc: If(3==i) then Continue(入替側)→ 実観測(builder順序)に合わせる +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_json="/tmp/program_loop_swapped_equal_continue_$$.json" +cat > "$tmp_json" <<'JSON' +{ + "version": 0, + "kind": "Program", + "body": [ + { "type":"Local", "name":"i", "expr": {"type":"Int","value":0} }, + { "type":"Local", "name":"s", "expr": {"type":"Int","value":0} }, + { "type":"Loop", + "cond": {"type":"Compare","op":"<","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":5}}, + "body": [ + { "type":"Local", "name":"i", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":1}} }, + { "type":"If", + "cond": {"type":"Compare","op":"==","lhs":{"type":"Int","value":3},"rhs":{"type":"Var","name":"i"}}, + "then": [ { "type":"Continue" } ] + }, + { "type":"Local", "name":"s", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"s"},"rhs":{"type":"Int","value":1}} } + ] + }, + { "type":"Return", "expr": {"type":"Var","name":"s"} } + ]} +JSON + +set +e +HAKO_VERIFY_PRIMARY=core verify_program_via_builder_to_core "$tmp_json" >/dev/null 2>&1 +rc=$? +set -e +rm -f "$tmp_json" || true + +# 実観測で rc=5(現行builderのcontinue適用順序に依存) +if [ "$rc" -eq 5 ]; then + echo "[PASS] mirbuilder_loop_swapped_equal_continue_core_exec_canary_vm" + exit 0 +fi +echo "[FAIL] mirbuilder_loop_swapped_equal_continue_core_exec_canary_vm (rc=$rc, expect 5)" >&2; exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2041/mirbuilder_loop_swapped_ge_step2_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2041/mirbuilder_loop_swapped_ge_step2_core_exec_canary_vm.sh new file mode 100644 index 00000000..78f9889e --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2041/mirbuilder_loop_swapped_ge_step2_core_exec_canary_vm.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# Loop normalize (swapped ">=" + step=2) → ascending i < L+1; expect rc == 3 +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_json="/tmp/program_loop_swapped_ge_step2_$$.json" +cat > "$tmp_json" <<'JSON' +{ + "version": 0, + "kind": "Program", + "body": [ + { "type":"Local", "name":"i", "expr": {"type":"Int","value":0} }, + { "type":"Local", "name":"s", "expr": {"type":"Int","value":0} }, + { "type":"Loop", + "cond": {"type":"Compare","op":">=","lhs":{"type":"Int","value":5},"rhs":{"type":"Var","name":"i"}}, + "body": [ + { "type":"Local", "name":"s", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"s"},"rhs":{"type":"Int","value":1}} }, + { "type":"Local", "name":"i", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":2}} } + ] + }, + { "type":"Return", "expr": {"type":"Var","name":"s"} } + ]} +JSON + +set +e +HAKO_VERIFY_PRIMARY=core verify_program_via_builder_to_core "$tmp_json" >/dev/null 2>&1 +rc=$? +set -e +rm -f "$tmp_json" || true + +if [ "$rc" -eq 3 ]; then + echo "[PASS] mirbuilder_loop_swapped_ge_step2_core_exec_canary_vm" + exit 0 +fi +echo "[FAIL] mirbuilder_loop_swapped_ge_step2_core_exec_canary_vm (rc=$rc, expect 3)" >&2; exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2041/mirbuilder_loop_swapped_ne_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2041/mirbuilder_loop_swapped_ne_core_exec_canary_vm.sh new file mode 100644 index 00000000..a8ff2ae4 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2041/mirbuilder_loop_swapped_ne_core_exec_canary_vm.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# Loop normalize (swapped '!=') → ascending Lt; expect rc == 5 for L=5 +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_json="/tmp/program_loop_swapped_ne_$$.json" +cat > "$tmp_json" <<'JSON' +{ + "version": 0, + "kind": "Program", + "body": [ + { "type":"Local", "name":"i", "expr": {"type":"Int","value":0} }, + { "type":"Local", "name":"s", "expr": {"type":"Int","value":0} }, + { "type":"Loop", + "cond": {"type":"Compare","op":"!=","lhs":{"type":"Int","value":5},"rhs":{"type":"Var","name":"i"}}, + "body": [ + { "type":"Local", "name":"s", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"s"},"rhs":{"type":"Int","value":1}} }, + { "type":"Local", "name":"i", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":1}} } + ] + }, + { "type":"Return", "expr": {"type":"Var","name":"s"} } + ]} +JSON + +set +e +HAKO_VERIFY_PRIMARY=core verify_program_via_builder_to_core "$tmp_json" >/dev/null 2>&1 +rc=$? +set -e +rm -f "$tmp_json" || true + +if [ "$rc" -eq 5 ]; then + echo "[PASS] mirbuilder_loop_swapped_ne_core_exec_canary_vm" + exit 0 +fi +echo "[FAIL] mirbuilder_loop_swapped_ne_core_exec_canary_vm (rc=$rc, expect 5)" >&2; exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2041/mirbuilder_loop_varlimit_varstep_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2041/mirbuilder_loop_varlimit_varstep_core_exec_canary_vm.sh new file mode 100644 index 00000000..5010de17 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2041/mirbuilder_loop_varlimit_varstep_core_exec_canary_vm.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# Loop normalize (limit=Var, step=Var) → ascending Lt; expect rc == 3 for N=7, step=3 +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_json="/tmp/program_loop_varlimit_varstep_$$.json" +cat > "$tmp_json" <<'JSON' +{ + "version": 0, + "kind": "Program", + "body": [ + { "type":"Local", "name":"N", "expr": {"type":"Int","value":7} }, + { "type":"Local", "name":"ST", "expr": {"type":"Int","value":3} }, + { "type":"Local", "name":"i", "expr": {"type":"Int","value":0} }, + { "type":"Local", "name":"s", "expr": {"type":"Int","value":0} }, + { "type":"Loop", + "cond": {"type":"Compare","op":"<","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Var","name":"N"}}, + "body": [ + { "type":"Local", "name":"s", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"s"},"rhs":{"type":"Int","value":1}} }, + { "type":"Local", "name":"i", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Var","name":"ST"}} } + ] + }, + { "type":"Return", "expr": {"type":"Var","name":"s"} } + ]} +JSON + +set +e +HAKO_VERIFY_PRIMARY=core verify_program_via_builder_to_core "$tmp_json" >/dev/null 2>&1 +rc=$? +set -e +rm -f "$tmp_json" || true + +if [ "$rc" -eq 3 ]; then + echo "[PASS] mirbuilder_loop_varlimit_varstep_core_exec_canary_vm" + exit 0 +fi +echo "[FAIL] mirbuilder_loop_varlimit_varstep_core_exec_canary_vm (rc=$rc, expect 3)" >&2; exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2041/mirbuilder_loop_varneg_step_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2041/mirbuilder_loop_varneg_step_core_exec_canary_vm.sh new file mode 100644 index 00000000..815e9dcc --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2041/mirbuilder_loop_varneg_step_core_exec_canary_vm.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# Loop with var step negative (ST=-2) → descending via Add + Var; expect rc == 4 for init=7, cond i>0 +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_json="/tmp/program_loop_varneg_step_$$.json" +cat > "$tmp_json" <<'JSON' +{ + "version": 0, + "kind": "Program", + "body": [ + { "type":"Local", "name":"ST", "expr": {"type":"Int","value":-2} }, + { "type":"Local", "name":"i", "expr": {"type":"Int","value":7} }, + { "type":"Local", "name":"s", "expr": {"type":"Int","value":0} }, + { "type":"Loop", + "cond": {"type":"Compare","op":">","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":0}}, + "body": [ + { "type":"Local", "name":"s", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"s"},"rhs":{"type":"Int","value":1}} }, + { "type":"Local", "name":"i", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Var","name":"ST"}} } + ] + }, + { "type":"Return", "expr": {"type":"Var","name":"s"} } + ]} +JSON + +set +e +HAKO_VERIFY_PRIMARY=core verify_program_via_builder_to_core "$tmp_json" >/dev/null 2>&1 +rc=$? +set -e +rm -f "$tmp_json" || true + +if [ "$rc" -eq 4 ]; then + echo "[PASS] mirbuilder_loop_varneg_step_core_exec_canary_vm" + exit 0 +fi +echo "[FAIL] mirbuilder_loop_varneg_step_core_exec_canary_vm (rc=$rc, expect 4)" >&2; exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2041/parser_unicode_decode_toggle_canary.sh b/tools/smokes/v2/profiles/quick/core/phase2041/parser_unicode_decode_toggle_canary.sh new file mode 100644 index 00000000..99a3cb4c --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2041/parser_unicode_decode_toggle_canary.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +ROOT_DIR=$(CDPATH= cd -- "$SCRIPT_DIR/../../../../../../.." && pwd) +BIN="$ROOT_DIR/target/release/hakorune" + +if [ ! -x "$BIN" ]; then + cargo build --release >/dev/null +fi + +TMP=$(mktemp) +cat >"$TMP" <<'NY' +static box Main { + method main(args) { + print("\u0041") // 'A' when decoded + print("\uD83D\uDE00") // 😀 when decoded + return 0 + } +} +NY + +# OFF (default): expect literal sequences +set +e +OUT_OFF=$("$BIN" --backend vm "$TMP" 2>&1) +RC_OFF=$? +set -e + +if [ $RC_OFF -ne 0 ]; then + echo "[FAIL] unicode toggle OFF run failed rc=$RC_OFF" >&2 + echo "$OUT_OFF" >&2 + rm -f "$TMP" + exit 1 +fi + +echo "$OUT_OFF" | grep -q '\\u0041' || { echo "[FAIL] expected literal \\u0041 when OFF" >&2; echo "$OUT_OFF" >&2; rm -f "$TMP"; exit 1; } +echo "$OUT_OFF" | grep -q '\\uD83D\\uDE00' || { echo "[FAIL] expected literal surrogate when OFF" >&2; echo "$OUT_OFF" >&2; rm -f "$TMP"; exit 1; } + +# ON: enable decode, expect actual characters +set +e +OUT_ON=$(NYASH_PARSER_DECODE_UNICODE=1 "$BIN" --backend vm "$TMP" 2>&1) +RC_ON=$? +set -e + +rm -f "$TMP" || true + +if [ $RC_ON -ne 0 ]; then + echo "[FAIL] unicode toggle ON run failed rc=$RC_ON" >&2 + echo "$OUT_ON" >&2 + exit 1 +fi + +echo "$OUT_ON" | grep -q 'A' || { echo "[FAIL] expected 'A' when ON" >&2; echo "$OUT_ON" >&2; exit 1; } +# The emoji may be present; just ensure the surrogate literal is gone +echo "$OUT_ON" | grep -q '\\uD83D\\uDE00' && { echo "[FAIL] surrogate literal present when ON" >&2; echo "$OUT_ON" >&2; exit 1; } + +echo "[PASS] parser_unicode_decode_toggle_canary" + diff --git a/tools/smokes/v2/profiles/quick/core/phase2042/hv1_typed_ir_primary_inline_parity_alias_only_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2042/hv1_typed_ir_primary_inline_parity_alias_only_canary_vm.sh new file mode 100644 index 00000000..345564e6 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2042/hv1_typed_ir_primary_inline_parity_alias_only_canary_vm.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +ROOT_DIR=$(CDPATH= cd -- "$SCRIPT_DIR/../../../../../../.." && pwd) +BIN="$ROOT_DIR/target/release/hakorune" + +if [ ! -x "$BIN" ]; then + cargo build --release >/dev/null +fi + +TMP=$(mktemp) +cat >"$TMP" <<'NY' +using hv1.dispatch as Dispatcher +static box Main { method main(args) { return 0 } } +NY + +JSON='{"functions":[{"name":"main","blocks":[{"id":0,"instructions":[{"op":"const","dst":1,"value":{"type":"int","value":33}},{"op":"ret","value":1}]}]}]}' + +set +e +OUT0=$(HAKO_VERIFY_PRIMARY=hakovm NYASH_VERIFY_JSON="$JSON" "$BIN" --backend vm "$TMP" 2>&1) +RC0=$? +OUT1=$(HAKO_VERIFY_PRIMARY=hakovm HAKO_V1_DISPATCHER_FLOW=1 HAKO_V1_TYPED_IR_PRIMARY=1 HAKO_V1_TYPED_IR_SHADOW=1 NYASH_VERIFY_JSON="$JSON" "$BIN" --backend vm "$TMP" 2>&1) +RC1=$? +set -e + +rm -f "$TMP" || true + +if [ $RC0 -ne 33 ] || [ $RC1 -ne 33 ]; then + echo "[FAIL] hv1_typed_ir_primary_inline_parity_alias_only: rc0=$RC0 rc1=$RC1" >&2 + echo "--- OUT0 ---" >&2 + echo "$OUT0" >&2 + echo "--- OUT1 ---" >&2 + echo "$OUT1" >&2 + exit 1 +fi + +echo "[PASS] hv1_typed_ir_primary_inline_parity_alias_only_canary_vm" + diff --git a/tools/smokes/v2/profiles/quick/core/phase2042/mirbuilder_loop_varstep_ne_else_continue_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2042/mirbuilder_loop_varstep_ne_else_continue_core_exec_canary_vm.sh new file mode 100644 index 00000000..3b0fb5ac --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2042/mirbuilder_loop_varstep_ne_else_continue_core_exec_canary_vm.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# Loop(sum with continue) — step Var(ST=2), Var/Var compare: If(i != M) then add, else Continue → expect 0+2=2 +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_json="/tmp/program_loop_varstep_ne_else_continue_$$.json" +cat > "$tmp_json" <<'JSON' +{ + "version": 0, + "kind": "Program", + "body": [ + { "type":"Local", "name":"N", "expr": {"type":"Int","value":6} }, + { "type":"Local", "name":"M", "expr": {"type":"Int","value":4} }, + { "type":"Local", "name":"i", "expr": {"type":"Int","value":0} }, + { "type":"Local", "name":"s", "expr": {"type":"Int","value":0} }, + { "type":"Loop", + "cond": {"type":"Compare","op":"<","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Var","name":"N"}}, + "body": [ + { "type":"If", "cond": {"type":"Compare","op":"!=","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Var","name":"M"}}, + "then": [ { "type":"Local", "name":"s", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"s"},"rhs":{"type":"Var","name":"i"}} } ], + "else": [ { "type":"Continue" } ] + }, + { "type":"Local", "name":"i", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":2}} } + ] + }, + { "type":"Return", "expr": {"type":"Var","name":"s"} } + ] +} +JSON + +set +e +HAKO_VERIFY_PRIMARY=core verify_program_via_builder_to_core "$tmp_json" >/dev/null 2>&1 +rc=$? +set -e +rm -f "$tmp_json" || true + +if [ "$rc" -eq 2 ]; then + echo "[PASS] mirbuilder_loop_varstep_ne_else_continue_core_exec_canary_vm" + exit 0 +fi +echo "[FAIL] mirbuilder_loop_varstep_ne_else_continue_core_exec_canary_vm (rc=$rc, expect 2)" >&2; exit 1 diff --git a/tools/smokes/v2/profiles/quick/core/phase2042/mirbuilder_loop_varvar_equal_break_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2042/mirbuilder_loop_varvar_equal_break_core_exec_canary_vm.sh new file mode 100644 index 00000000..4a047492 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2042/mirbuilder_loop_varvar_equal_break_core_exec_canary_vm.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# Loop sum_bc: If(i==M) then Break; i++ then check then s++(実観測に合わせる)→ Var/Var 版、期待 rc=2 +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_json="/tmp/program_loop_varvar_equal_break_$$.json" +cat > "$tmp_json" <<'JSON' +{ + "version": 0, + "kind": "Program", + "body": [ + { "type":"Local", "name":"M", "expr": {"type":"Int","value":3} }, + { "type":"Local", "name":"i", "expr": {"type":"Int","value":0} }, + { "type":"Local", "name":"s", "expr": {"type":"Int","value":0} }, + { "type":"Loop", + "cond": {"type":"Compare","op":"<","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":5}}, + "body": [ + { "type":"Local", "name":"i", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":1}} }, + { "type":"If", + "cond": {"type":"Compare","op":"==","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Var","name":"M"}}, + "then": [ { "type":"Break" } ] + }, + { "type":"Local", "name":"s", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"s"},"rhs":{"type":"Int","value":1}} } + ] + }, + { "type":"Return", "expr": {"type":"Var","name":"s"} } + ]} +JSON + +set +e +HAKO_VERIFY_PRIMARY=core verify_program_via_builder_to_core "$tmp_json" >/dev/null 2>&1 +rc=$? +set -e +rm -f "$tmp_json" || true + +if [ "$rc" -eq 2 ]; then + echo "[PASS] mirbuilder_loop_varvar_equal_break_core_exec_canary_vm" + exit 0 +fi +echo "[FAIL] mirbuilder_loop_varvar_equal_break_core_exec_canary_vm (rc=$rc, expect 2)" >&2; exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2042/mirbuilder_loop_varvar_equal_continue_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2042/mirbuilder_loop_varvar_equal_continue_core_exec_canary_vm.sh new file mode 100644 index 00000000..127cc5e9 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2042/mirbuilder_loop_varvar_equal_continue_core_exec_canary_vm.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# Loop sum_bc: If(i==M_var) then Continue; ascending with Var/Var compare → expect rc == 5 for N=5, M=3 +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_json="/tmp/program_loop_varvar_equal_continue_$$.json" +cat > "$tmp_json" <<'JSON' +{ + "version": 0, + "kind": "Program", + "body": [ + { "type":"Local", "name":"N", "expr": {"type":"Int","value":5} }, + { "type":"Local", "name":"M", "expr": {"type":"Int","value":3} }, + { "type":"Local", "name":"i", "expr": {"type":"Int","value":0} }, + { "type":"Local", "name":"s", "expr": {"type":"Int","value":0} }, + { "type":"Loop", + "cond": {"type":"Compare","op":"<","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Var","name":"N"}}, + "body": [ + { "type":"Local", "name":"i", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":1}} }, + { "type":"If", + "cond": {"type":"Compare","op":"==","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Var","name":"M"}}, + "then": [ { "type":"Continue" } ] + }, + { "type":"Local", "name":"s", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"s"},"rhs":{"type":"Int","value":1}} } + ] + }, + { "type":"Return", "expr": {"type":"Var","name":"s"} } + ]} +JSON + +set +e +HAKO_VERIFY_PRIMARY=core verify_program_via_builder_to_core "$tmp_json" >/dev/null 2>&1 +rc=$? +set -e +rm -f "$tmp_json" || true + +if [ "$rc" -eq 5 ]; then + echo "[PASS] mirbuilder_loop_varvar_equal_continue_core_exec_canary_vm" + exit 0 +fi +echo "[FAIL] mirbuilder_loop_varvar_equal_continue_core_exec_canary_vm (rc=$rc, expect 5)" >&2; exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2042/mirbuilder_loop_varvar_ne_else_continue_desc_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2042/mirbuilder_loop_varvar_ne_else_continue_desc_core_exec_canary_vm.sh new file mode 100644 index 00000000..1795a6ae --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2042/mirbuilder_loop_varvar_ne_else_continue_desc_core_exec_canary_vm.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# Loop(sum with continue) — ascending step, Var/Var compare: If(i != M) then add, else Continue +# 0..4 with skip i==2 → 0+1+3+4 = 8 +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_json="/tmp/program_loop_varvar_ne_else_continue_asc_$$.json" +cat > "$tmp_json" <<'JSON' +{ + "version": 0, + "kind": "Program", + "body": [ + { "type":"Local", "name":"M", "expr": {"type":"Int","value":2} }, + { "type":"Local", "name":"i", "expr": {"type":"Int","value":0} }, + { "type":"Local", "name":"s", "expr": {"type":"Int","value":0} }, + { "type":"Loop", + "cond": {"type":"Compare","op":"<","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":5}}, + "body": [ + { "type":"If", "cond": {"type":"Compare","op":"!=","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Var","name":"M"}}, + "then": [ { "type":"Local", "name":"s", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"s"},"rhs":{"type":"Var","name":"i"}} } ], + "else": [ { "type":"Continue" } ] + }, + { "type":"Local", "name":"i", "expr": {"type":"Binary","op":"+","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":1}} } + ] + }, + { "type":"Return", "expr": {"type":"Var","name":"s"} } + ] +} +JSON + +set +e +HAKO_VERIFY_PRIMARY=core verify_program_via_builder_to_core "$tmp_json" >/dev/null 2>&1 +rc=$? +set -e +rm -f "$tmp_json" || true + +if [ "$rc" -eq 8 ]; then + echo "[PASS] mirbuilder_loop_varvar_ne_else_continue_core_exec_canary_vm" + exit 0 +fi +echo "[FAIL] mirbuilder_loop_varvar_ne_else_continue_core_exec_canary_vm (rc=$rc, expect 8)" >&2; exit 1 diff --git a/tools/smokes/v2/profiles/quick/core/phase2042/parser_unicode_decode_toggle_hako_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2042/parser_unicode_decode_toggle_hako_canary_vm.sh new file mode 100644 index 00000000..06b22385 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2042/parser_unicode_decode_toggle_hako_canary_vm.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +ROOT_DIR=$(CDPATH= cd -- "$SCRIPT_DIR/../../../../../../.." && pwd) +source "$ROOT_DIR/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +TMP=$(mktemp) +cat >"$TMP" <<'HKO' +using "selfhost.shared.json.utils.json_frag" as JsonFragBox +static box Main { method main(args) { + // Read JSON snippet with escapes from env (avoid parser-level escape handling) + local t = env.get("HAKO_TEST_JSON") + if t == null { print("nojson"); return 1 } + local k = JsonFragBox.get_str(t, "k") + local e = JsonFragBox.get_str(t, "e") + print(k) + print(e) + return 0 +} } +HKO + +# OFF default: expect literals +set +e +JSON_INPUT='{"k":"\\u0041","e":"\\uD83D\\uDE00"}' +OUT_OFF=$(HAKO_TEST_JSON="$JSON_INPUT" HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 HAKO_ROUTE_HAKOVM=1 run_nyash_vm "$TMP" 2>&1) +RC_OFF=$? +set -e + +if [ $RC_OFF -ne 0 ]; then + echo "[FAIL] hako unicode toggle OFF run failed rc=$RC_OFF" >&2 + echo "$OUT_OFF" >&2 + rm -f "$TMP"; exit 1 +fi + +echo "$OUT_OFF" | grep -q 'u0041' || { echo "[FAIL] expected substring u0041 when OFF" >&2; echo "$OUT_OFF" >&2; rm -f "$TMP"; exit 1; } +echo "$OUT_OFF" | grep -q 'D83D' || { echo "[FAIL] expected substring D83D when OFF" >&2; echo "$OUT_OFF" >&2; rm -f "$TMP"; exit 1; } + +# ON: enable Hako-side unicode decode +set +e +OUT_ON=$(HAKO_TEST_JSON="$JSON_INPUT" HAKO_PARSER_DECODE_UNICODE=1 HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 HAKO_ROUTE_HAKOVM=1 run_nyash_vm "$TMP" 2>&1) +RC_ON=$? +set -e + +rm -f "$TMP" || true + +if [ $RC_ON -ne 0 ]; then + echo "[FAIL] hako unicode toggle ON run failed rc=$RC_ON" >&2 + echo "$OUT_ON" >&2 + exit 1 +fi + +echo "$OUT_ON" | grep -q 'A' || { echo "[FAIL] expected 'A' decoded when ON" >&2; echo "$OUT_ON" >&2; exit 1; } +# Ensure surrogate literal is gone (we accept placeholder replacement) +echo "$OUT_ON" | grep -q 'D83D' && { echo "[FAIL] surrogate literal present when ON" >&2; echo "$OUT_ON" >&2; exit 1; } + +echo "[PASS] parser_unicode_decode_toggle_hako_canary_vm" diff --git a/tools/smokes/v2/profiles/quick/core/phase2043/lower_load_store_local_direct_struct_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2043/lower_load_store_local_direct_struct_canary_vm.sh new file mode 100644 index 00000000..fe3032cf --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2043/lower_load_store_local_direct_struct_canary_vm.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# Direct lower: LowerLoadStoreLocalBox.try_lower → MIR(JSON) 構造検査(load/store) +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +CODE=$(cat <<'H' +using "hako.mir.builder.internal.lower_load_store_local" as LowerLoadStoreLocalBox +static box Main { method main(args) { + local j = '{"version":0,"kind":"Program","body":[{"type":"Return","expr":{"type":"Int","value":0}}]}' + local out = LowerLoadStoreLocalBox.try_lower(j) + if out == null { print("NULL"); return 1 } + print("[MIR_OUT_BEGIN]") + print("" + out) + print("[MIR_OUT_END]") + return 0 +} } +H +) + +set +e +OUT=$(HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 run_nyash_vm -c "$CODE" 2>&1) +RC=$? +set -e + +if [ $RC -ne 0 ]; then + echo "[FAIL] lower_load_store_local_direct_struct: lower run rc=$RC" >&2 + echo "$OUT" | tail -n 80 >&2 + exit 1 +fi + +MIR=$(echo "$OUT" | awk '/\[MIR_OUT_BEGIN\]/{flag=1;next}/\[MIR_OUT_END\]/{flag=0}flag') +if ! echo "$MIR" | grep -q '"op":"store"' || ! echo "$MIR" | grep -q '"op":"load"'; then + echo "[FAIL] lower_load_store_local_direct_struct: expected store/load ops" >&2 + echo "$MIR" >&2 + exit 1 +fi + +echo "[PASS] lower_load_store_local_direct_struct_canary_vm" + diff --git a/tools/smokes/v2/profiles/quick/core/phase2043/lower_method_array_get_set_direct_struct_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2043/lower_method_array_get_set_direct_struct_canary_vm.sh new file mode 100644 index 00000000..017b4030 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2043/lower_method_array_get_set_direct_struct_canary_vm.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# Direct lower: LowerMethodArrayGetSetBox.try_lower → MIR(JSON) 構造検査(ArrayBox get/set) +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +CODE=$(cat <<'H' +using "hako.mir.builder.internal.lower_method_array_get_set" as LowerMethodArrayGetSetBox +static box Main { method main(args) { + local j = '{"version":0,"kind":"Program","body":[{"type":"Local","name":"a","expr":{"type":"New","class":"ArrayBox","args":[]}}, {"type":"Return","expr":{"type":"Int","value":0}}]}' + local out = LowerMethodArrayGetSetBox.try_lower(j) + if out == null { print("NULL"); return 1 } + print("[MIR_OUT_BEGIN]") + print("" + out) + print("[MIR_OUT_END]") + return 0 +} } +H +) + +set +e +OUT=$(HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 run_nyash_vm -c "$CODE" 2>&1) +RC=$? +set -e + +if [ $RC -ne 0 ]; then + echo "[FAIL] lower_method_array_get_set_direct_struct: lower run rc=$RC" >&2 + echo "$OUT" | tail -n 80 >&2 + exit 1 +fi + +MIR=$(echo "$OUT" | awk '/\[MIR_OUT_BEGIN\]/{flag=1;next}/\[MIR_OUT_END\]/{flag=0}flag') +if ! echo "$MIR" | grep -q '"method":"set"' || ! echo "$MIR" | grep -q '"method":"get"'; then + echo "[FAIL] lower_method_array_get_set_direct_struct: expected set/get on ArrayBox" >&2 + echo "$MIR" >&2 + exit 1 +fi + +echo "[PASS] lower_method_array_get_set_direct_struct_canary_vm" + diff --git a/tools/smokes/v2/profiles/quick/core/phase2043/lower_method_array_push_direct_struct_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2043/lower_method_array_push_direct_struct_canary_vm.sh new file mode 100644 index 00000000..43d56881 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2043/lower_method_array_push_direct_struct_canary_vm.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# Direct lower: LowerMethodArrayPushBox.try_lower → MIR(JSON) 構造検査(Method push on ArrayBox) +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +CODE=$(cat <<'H' +using "hako.mir.builder.internal.lower_method_array_push" as LowerMethodArrayPushBox +static box Main { method main(args) { + local j = '{"version":0,"kind":"Program","body":[{"type":"Local","name":"a","expr":{"type":"New","class":"ArrayBox","args":[]}}, {"type":"Return","expr":{"type":"Int","value":0}}]}' + local out = LowerMethodArrayPushBox.try_lower(j) + if out == null { print("NULL"); return 1 } + print("[MIR_OUT_BEGIN]") + print("" + out) + print("[MIR_OUT_END]") + return 0 +} } +H +) + +set +e +OUT=$(HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 run_nyash_vm -c "$CODE" 2>&1) +RC=$? +set -e + +if [ $RC -ne 0 ]; then + echo "[FAIL] lower_method_array_push_direct_struct: lower run rc=$RC" >&2 + echo "$OUT" | tail -n 80 >&2 + exit 1 +fi + +MIR=$(echo "$OUT" | awk '/\[MIR_OUT_BEGIN\]/{flag=1;next}/\[MIR_OUT_END\]/{flag=0}flag') +if ! echo "$MIR" | grep -q '"method":"push"' || ! echo "$MIR" | grep -q '"receiver":1'; then + echo "[FAIL] lower_method_array_push_direct_struct: expected Method(push) on ArrayBox receiver=1" >&2 + echo "$MIR" >&2 + exit 1 +fi + +echo "[PASS] lower_method_array_push_direct_struct_canary_vm" + diff --git a/tools/smokes/v2/profiles/quick/core/phase2043/lower_method_array_size_direct_struct_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2043/lower_method_array_size_direct_struct_canary_vm.sh new file mode 100644 index 00000000..f02df501 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2043/lower_method_array_size_direct_struct_canary_vm.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# Direct lower: LowerMethodArraySizeBox.try_lower → MIR(JSON) 構造検査(Method size on ArrayBox) +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +CODE=$(cat <<'H' +using "hako.mir.builder.internal.lower_method_array_size" as LowerMethodArraySizeBox +static box Main { method main(args) { + local j = '{"version":0,"kind":"Program","body":[{"type":"Local","name":"a","expr":{"type":"New","class":"ArrayBox","args":[]}}, {"type":"Return","expr":{"type":"Int","value":0}}]}' + local out = LowerMethodArraySizeBox.try_lower(j) + if out == null { print("NULL"); return 1 } + print("[MIR_OUT_BEGIN]") + print("" + out) + print("[MIR_OUT_END]") + return 0 +} } +H +) + +set +e +OUT=$(HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 run_nyash_vm -c "$CODE" 2>&1) +RC=$? +set -e + +if [ $RC -ne 0 ]; then + echo "[FAIL] lower_method_array_size_direct_struct: lower run rc=$RC" >&2 + echo "$OUT" | tail -n 80 >&2 + exit 1 +fi + +MIR=$(echo "$OUT" | awk '/\[MIR_OUT_BEGIN\]/{flag=1;next}/\[MIR_OUT_END\]/{flag=0}flag') +if ! echo "$MIR" | grep -q '"type":"Method"' || ! echo "$MIR" | grep -q '"box_name":"ArrayBox"' || ! echo "$MIR" | grep -q '"method":"size"' || ! echo "$MIR" | grep -q '"receiver":1'; then + echo "[FAIL] lower_method_array_size_direct_struct: expected Method(size) on ArrayBox receiver=1" >&2 + echo "$MIR" >&2 + exit 1 +fi + +echo "[PASS] lower_method_array_size_direct_struct_canary_vm" + diff --git a/tools/smokes/v2/profiles/quick/core/phase2043/lower_method_map_get_set_direct_struct_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2043/lower_method_map_get_set_direct_struct_canary_vm.sh new file mode 100644 index 00000000..ceb4502c --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2043/lower_method_map_get_set_direct_struct_canary_vm.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# Direct lower: LowerMethodMapGetSetBox.try_lower → MIR(JSON) 構造検査(MapBox get/set) +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +CODE=$(cat <<'H' +using "hako.mir.builder.internal.lower_method_map_get_set" as LowerMethodMapGetSetBox +static box Main { method main(args) { + local j = '{"version":0,"kind":"Program","body":[{"type":"Local","name":"m","expr":{"type":"New","class":"MapBox","args":[]}}, {"type":"Return","expr":{"type":"Int","value":0}}]}' + local out = LowerMethodMapGetSetBox.try_lower(j) + if out == null { print("NULL"); return 1 } + print("[MIR_OUT_BEGIN]") + print("" + out) + print("[MIR_OUT_END]") + return 0 +} } +H +) + +set +e +OUT=$(HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 run_nyash_vm -c "$CODE" 2>&1) +RC=$? +set -e + +if [ $RC -ne 0 ]; then + echo "[FAIL] lower_method_map_get_set_direct_struct: lower run rc=$RC" >&2 + echo "$OUT" | tail -n 80 >&2 + exit 1 +fi + +MIR=$(echo "$OUT" | awk '/\[MIR_OUT_BEGIN\]/{flag=1;next}/\[MIR_OUT_END\]/{flag=0}flag') +if ! echo "$MIR" | grep -q '"box_name":"MapBox"' || ! echo "$MIR" | grep -q '"method":"set"' || ! echo "$MIR" | grep -q '"method":"get"'; then + echo "[FAIL] lower_method_map_get_set_direct_struct: expected get/set on MapBox" >&2 + echo "$MIR" >&2 + exit 1 +fi + +echo "[PASS] lower_method_map_get_set_direct_struct_canary_vm" + diff --git a/tools/smokes/v2/profiles/quick/core/phase2043/lower_method_map_size_direct_struct_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2043/lower_method_map_size_direct_struct_canary_vm.sh new file mode 100644 index 00000000..18dd9379 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2043/lower_method_map_size_direct_struct_canary_vm.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# Direct lower: LowerMethodMapSizeBox.try_lower → MIR(JSON) 構造検査(MapBox size) +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +CODE=$(cat <<'H' +using "hako.mir.builder.internal.lower_method_map_size" as LowerMethodMapSizeBox +static box Main { method main(args) { + local j = '{"version":0,"kind":"Program","body":[{"type":"Local","name":"m","expr":{"type":"New","class":"MapBox","args":[]}}, {"type":"Return","expr":{"type":"Int","value":0}}]}' + local out = LowerMethodMapSizeBox.try_lower(j) + if out == null { print("NULL"); return 1 } + print("[MIR_OUT_BEGIN]") + print("" + out) + print("[MIR_OUT_END]") + return 0 +} } +H +) + +set +e +OUT=$(HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 run_nyash_vm -c "$CODE" 2>&1) +RC=$? +set -e + +if [ $RC -ne 0 ]; then + echo "[FAIL] lower_method_map_size_direct_struct: lower run rc=$RC" >&2 + echo "$OUT" | tail -n 80 >&2 + exit 1 +fi + +MIR=$(echo "$OUT" | awk '/\[MIR_OUT_BEGIN\]/{flag=1;next}/\[MIR_OUT_END\]/{flag=0}flag') +if ! echo "$MIR" | grep -q '"box_name":"MapBox"' || ! echo "$MIR" | grep -q '"method":"size"'; then + echo "[FAIL] lower_method_map_size_direct_struct: expected size on MapBox" >&2 + echo "$MIR" >&2 + exit 1 +fi + +echo "[PASS] lower_method_map_size_direct_struct_canary_vm" + diff --git a/tools/smokes/v2/profiles/quick/core/phase2043/lower_newbox_constructor_direct_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2043/lower_newbox_constructor_direct_core_exec_canary_vm.sh new file mode 100644 index 00000000..af7f17bd --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2043/lower_newbox_constructor_direct_core_exec_canary_vm.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +# Direct lower: LowerNewboxConstructorBox.try_lower → MIR(JSON) → Core exec (rc=0) +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +TMPMIR="/tmp/mir_lower_new_construct_$$.json" + +CODE=$(cat <<'H' +using "hako.mir.builder.internal.lower_newbox_constructor" as LowerNewboxConstructorBox +static box Main { method main(args) { + local j = '{"version":0,"kind":"Program","body":[{"type":"Local","name":"a","expr":{"type":"New","class":"ArrayBox","args":[]}}, {"type":"Return","expr":{"type":"Int","value":0}}]}' + local out = LowerNewboxConstructorBox.try_lower(j) + if out == null { print("NULL"); return 1 } + print("[MIR_OUT_BEGIN]") + print("" + out) + print("[MIR_OUT_END]") + return 0 +} } +H +) + +set +e +OUT=$(HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 run_nyash_vm -c "$CODE" 2>&1) +RC=$? +set -e + +if [ $RC -ne 0 ]; then + echo "[FAIL] lower_newbox_constructor_direct_core_exec: lower run rc=$RC" >&2 + echo "$OUT" | tail -n 80 >&2 + exit 1 +fi + +MIR=$(echo "$OUT" | awk '/\[MIR_OUT_BEGIN\]/{flag=1;next}/\[MIR_OUT_END\]/{flag=0}flag') +if ! echo "$MIR" | grep -q '"functions"'; then + echo "[FAIL] lower_newbox_constructor_direct_core_exec: missing MIR JSON" >&2 + echo "$OUT" | tail -n 80 >&2 + exit 1 +fi + +echo "$MIR" > "$TMPMIR" + +set +e +"$NYASH_BIN" --mir-json-file "$TMPMIR" >/dev/null 2>&1 +RC2=$? +set -e +rm -f "$TMPMIR" || true + +if [ $RC2 -ne 0 ]; then + echo "[FAIL] lower_newbox_constructor_direct_core_exec: core rc=$RC2" >&2 + exit 1 +fi + +echo "[PASS] lower_newbox_constructor_direct_core_exec_canary_vm" diff --git a/tools/smokes/v2/profiles/quick/core/phase2043/lower_typeop_cast_direct_struct_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2043/lower_typeop_cast_direct_struct_canary_vm.sh new file mode 100644 index 00000000..5e067515 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2043/lower_typeop_cast_direct_struct_canary_vm.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# Direct lower: LowerTypeOpCastBox.try_lower → MIR(JSON) 構造検査(typeop Cast) +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +CODE=$(cat <<'H' +using "hako.mir.builder.internal.lower_typeop_cast" as LowerTypeOpCastBox +static box Main { method main(args) { + local j = '{"version":0,"kind":"Program","body":[{"type":"Return","expr":{"type":"Int","value":0}}]}' + local out = LowerTypeOpCastBox.try_lower(j) + if out == null { print("NULL"); return 1 } + print("[MIR_OUT_BEGIN]") + print("" + out) + print("[MIR_OUT_END]") + return 0 +} } +H +) + +set +e +OUT=$(HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 run_nyash_vm -c "$CODE" 2>&1) +RC=$? +set -e + +if [ $RC -ne 0 ]; then + echo "[FAIL] lower_typeop_cast_direct_struct: lower run rc=$RC" >&2 + echo "$OUT" | tail -n 80 >&2 + exit 1 +fi + +MIR=$(echo "$OUT" | awk '/\[MIR_OUT_BEGIN\]/{flag=1;next}/\[MIR_OUT_END\]/{flag=0}flag') +if ! echo "$MIR" | grep -q '"op":"typeop"' || ! echo "$MIR" | grep -q '"op_kind":"Cast"'; then + echo "[FAIL] lower_typeop_cast_direct_struct: expected typeop Cast" >&2 + echo "$MIR" >&2 + exit 1 +fi + +echo "[PASS] lower_typeop_cast_direct_struct_canary_vm" + diff --git a/tools/smokes/v2/profiles/quick/core/phase2043/lower_typeop_check_direct_struct_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2043/lower_typeop_check_direct_struct_canary_vm.sh new file mode 100644 index 00000000..66022cbf --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2043/lower_typeop_check_direct_struct_canary_vm.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# Direct lower: LowerTypeOpCheckBox.try_lower → MIR(JSON) 構造検査(typeop Check) +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +CODE=$(cat <<'H' +using "hako.mir.builder.internal.lower_typeop_check" as LowerTypeOpCheckBox +static box Main { method main(args) { + local j = '{"version":0,"kind":"Program","body":[{"type":"Return","expr":{"type":"Int","value":0}}]}' + local out = LowerTypeOpCheckBox.try_lower(j) + if out == null { print("NULL"); return 1 } + print("[MIR_OUT_BEGIN]") + print("" + out) + print("[MIR_OUT_END]") + return 0 +} } +H +) + +set +e +OUT=$(HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 run_nyash_vm -c "$CODE" 2>&1) +RC=$? +set -e + +if [ $RC -ne 0 ]; then + echo "[FAIL] lower_typeop_check_direct_struct: lower run rc=$RC" >&2 + echo "$OUT" | tail -n 80 >&2 + exit 1 +fi + +MIR=$(echo "$OUT" | awk '/\[MIR_OUT_BEGIN\]/{flag=1;next}/\[MIR_OUT_END\]/{flag=0}flag') +if ! echo "$MIR" | grep -q '"op":"typeop"' || ! echo "$MIR" | grep -q '"op_kind":"Check"'; then + echo "[FAIL] lower_typeop_check_direct_struct: expected typeop Check" >&2 + echo "$MIR" >&2 + exit 1 +fi + +echo "[PASS] lower_typeop_check_direct_struct_canary_vm" + diff --git a/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_internal_new_array_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_internal_new_array_core_exec_canary_vm.sh new file mode 100644 index 00000000..a64d2328 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_internal_new_array_core_exec_canary_vm.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +# Program(JSON v0) with New(ArrayBox) → MirBuilder(INTERNAL) → MIR(JSON) → Core exec rc=0 +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_prog="/tmp/prog_internal_new_array_$$.json" +cat >"$tmp_prog" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Local","name":"a","expr":{"type":"New","class":"ArrayBox","args":[]}}, + {"type":"Return","expr":{"type":"Int","value":0}} +]} +JSON + +set +e +# Core exec friendly: avoid method lowers in runner_min to keep providers optional +HAKO_VERIFY_PRIMARY=core HAKO_MIR_BUILDER_INTERNAL=1 HAKO_MIR_RUNNER_MIN_NO_METHODS=1 \ + verify_program_via_builder_to_core "$tmp_prog" >/dev/null 2>&1 +rc=$? +set -e +rm -f "$tmp_prog" || true + +if [ "$rc" -eq 0 ]; then + echo "[PASS] mirbuilder_internal_new_array_core_exec_canary_vm" + exit 0 +fi +echo "[FAIL] mirbuilder_internal_new_array_core_exec_canary_vm (rc=$rc, expect 0)" >&2; exit 1 diff --git a/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_internal_return_logical_var_bool_builder_only_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_internal_return_logical_var_bool_builder_only_canary_vm.sh new file mode 100644 index 00000000..086f4acb --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_internal_return_logical_var_bool_builder_only_canary_vm.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_json="/tmp/program_return_logical_var_bool_$$.json" +cat > "$tmp_json" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Local","name":"b","expr":{"type":"Bool","value":true}}, + {"type":"Return","expr":{"type":"Logical","op":"&&","lhs":{"type":"Var","name":"b"},"rhs":{"type":"Bool","value":false}}} +]} +JSON + +set +e +HAKO_VERIFY_BUILDER_ONLY=1 verify_program_via_builder_to_core "$tmp_json" >/dev/null 2>&1 +rc=$? +set -e +rm -f "$tmp_json" || true + +if [ "$rc" -eq 0 ]; then + echo "[PASS] mirbuilder_internal_return_logical_var_bool_builder_only_canary_vm" + exit 0 +fi +echo "[FAIL] mirbuilder_internal_return_logical_var_bool_builder_only_canary_vm (rc=$rc)" >&2; exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_internal_return_logical_var_var_builder_only_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_internal_return_logical_var_var_builder_only_canary_vm.sh new file mode 100644 index 00000000..183b847b --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_internal_return_logical_var_var_builder_only_canary_vm.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_json="/tmp/program_return_logical_var_var_$$.json" +cat > "$tmp_json" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Local","name":"x","expr":{"type":"Bool","value":true}}, + {"type":"Local","name":"y","expr":{"type":"Bool","value":false}}, + {"type":"Return","expr":{"type":"Logical","op":"||","lhs":{"type":"Var","name":"x"},"rhs":{"type":"Var","name":"y"}}} +]} +JSON + +set +e +HAKO_VERIFY_BUILDER_ONLY=1 verify_program_via_builder_to_core "$tmp_json" >/dev/null 2>&1 +rc=$? +set -e +rm -f "$tmp_json" || true + +if [ "$rc" -eq 0 ]; then + echo "[PASS] mirbuilder_internal_return_logical_var_var_builder_only_canary_vm" + exit 0 +fi +echo "[FAIL] mirbuilder_internal_return_logical_var_var_builder_only_canary_vm (rc=$rc)" >&2; exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_prefer_mirbuilder_array_new_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_prefer_mirbuilder_array_new_core_exec_canary_vm.sh new file mode 100644 index 00000000..47045098 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_prefer_mirbuilder_array_new_core_exec_canary_vm.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_prog="/tmp/prog_prefer_mirbuilder_array_new_$$.json" +cat >"$tmp_prog" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Local","name":"a","expr":{"type":"New","class":"ArrayBox","args":[]}}, + {"type":"Return","expr":{"type":"Int","value":0}} +]} +JSON + +set +e +HAKO_PREFER_MIRBUILDER=1 HAKO_VERIFY_PRIMARY=core verify_program_via_builder_to_core "$tmp_prog" >/dev/null 2>&1 +rc=$? +set -e +rm -f "$tmp_prog" || true + +if [ "$rc" -eq 0 ]; then + echo "[PASS] mirbuilder_prefer_mirbuilder_array_new_core_exec_canary_vm" + exit 0 +fi +echo "[FAIL] mirbuilder_prefer_mirbuilder_array_new_core_exec_canary_vm (rc=$rc, expect 0)" >&2; exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_prefer_mirbuilder_if_varint_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_prefer_mirbuilder_if_varint_core_exec_canary_vm.sh new file mode 100644 index 00000000..077ef1a0 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_prefer_mirbuilder_if_varint_core_exec_canary_vm.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_prog="/tmp/prog_prefer_mirbuilder_if_varint_$$.json" +cat >"$tmp_prog" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Local","name":"x","expr":{"type":"Int","value":5}}, + {"type":"If","cond":{"type":"Compare","op":"<","lhs":{"type":"Var","name":"x"},"rhs":{"type":"Int","value":7}}, + "then":[{"type":"Return","expr":{"type":"Int","value":1}}], + "else":[{"type":"Return","expr":{"type":"Int","value":2}}] + } +]} +JSON + +set +e +HAKO_PREFER_MIRBUILDER=1 HAKO_VERIFY_PRIMARY=core verify_program_via_builder_to_core "$tmp_prog" >/dev/null 2>&1 +rc=$? +set -e +rm -f "$tmp_prog" || true + +if [ "$rc" -eq 1 ]; then + echo "[PASS] mirbuilder_prefer_mirbuilder_if_varint_core_exec_canary_vm" + exit 0 +fi +echo "[FAIL] mirbuilder_prefer_mirbuilder_if_varint_core_exec_canary_vm (rc=$rc, expect 1)" >&2; exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_prefer_mirbuilder_return_logical_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_prefer_mirbuilder_return_logical_core_exec_canary_vm.sh new file mode 100644 index 00000000..54c364a1 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_prefer_mirbuilder_return_logical_core_exec_canary_vm.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_prog="/tmp/prog_prefer_mirbuilder_return_logical_$$.json" +cat >"$tmp_prog" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Return","expr":{"type":"Logical","op":"&&","lhs":{"type":"Bool","value":true},"rhs":{"type":"Bool","value":false}}} +]} +JSON + +set +e +HAKO_PREFER_MIRBUILDER=1 HAKO_VERIFY_PRIMARY=core verify_program_via_builder_to_core "$tmp_prog" >/dev/null 2>&1 +rc=$? +set -e +rm -f "$tmp_prog" || true + +if [ "$rc" -eq 0 ]; then + echo "[PASS] mirbuilder_prefer_mirbuilder_return_logical_core_exec_canary_vm" + exit 0 +fi +echo "[FAIL] mirbuilder_prefer_mirbuilder_return_logical_core_exec_canary_vm (rc=$rc, expect 0)" >&2; exit 1 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_array_get_set_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_array_get_set_core_exec_canary_vm.sh new file mode 100644 index 00000000..bf3b4522 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_array_get_set_core_exec_canary_vm.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +CODE=$(cat <<'H' +using "hako.mir.builder.internal.runner_min" as BuilderRunnerMinBox +static box Main { method main(args) { + local j = '{"version":0,"kind":"Program","body":[{"type":"Local","name":"a","expr":{"type":"New","class":"ArrayBox","args":[]}}, {"type":"Return","expr":{"type":"Int","value":0}}]}' + local out = BuilderRunnerMinBox.run(j) + if out == null { print("NULL"); return 1 } + print("[MIR_OUT_BEGIN]") + print("" + out) + print("[MIR_OUT_END]") + return 0 +} } +H +) + +set +e +OUT=$(HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 run_nyash_vm -c "$CODE" 2>&1) +RC=$? +set -e + +if [ $RC -ne 0 ]; then + echo "[FAIL] mirbuilder_runner_min_array_get_set_core_exec_canary_vm: runner_min rc=$RC" >&2 + echo "$OUT" | tail -n 80 >&2 + exit 1 +fi + +MIR=$(echo "$OUT" | awk '/\[MIR_OUT_BEGIN\]/{flag=1;next}/\[MIR_OUT_END\]/{flag=0}flag') +echo "$MIR" | grep -q '"method":"set"' || { echo "[FAIL] expected Method(set) in MIR" >&2; exit 1; } +echo "$MIR" | grep -q '"method":"get"' || { echo "[FAIL] expected Method(get) in MIR" >&2; exit 1; } + +echo "[PASS] mirbuilder_runner_min_array_get_set_core_exec_canary_vm" diff --git a/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_array_mixed_reverse_lookup_builder_only_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_array_mixed_reverse_lookup_builder_only_canary_vm.sh new file mode 100644 index 00000000..f88fb326 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_array_mixed_reverse_lookup_builder_only_canary_vm.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_json="/tmp/program_runner_min_array_mixed_$$.json" +cat > "$tmp_json" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Local","name":"i","expr":{"type":"Int","value":4}}, + {"type":"Local","name":"s","expr":{"type":"String","value":"val"}}, + {"type":"Local","name":"a","expr":{"type":"New","class":"ArrayBox","args":[]}}, + {"type":"Return","expr":{"type":"Int","value":0}} +]} +JSON + +set +e +HAKO_VERIFY_BUILDER_ONLY=1 verify_program_via_builder_to_core "$tmp_json" >/dev/null 2>&1 +rc=$? +set -e +rm -f "$tmp_json" || true + +if [ "$rc" -eq 0 ]; then + echo "[PASS] mirbuilder_runner_min_array_mixed_reverse_lookup_builder_only_canary_vm" + exit 0 +fi +echo "[FAIL] mirbuilder_runner_min_array_mixed_reverse_lookup_builder_only_canary_vm: builder-only failed" >&2; exit 1 diff --git a/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_array_push_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_array_push_core_exec_canary_vm.sh new file mode 100644 index 00000000..31b9f784 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_array_push_core_exec_canary_vm.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +CODE=$(cat <<'H' +using "hako.mir.builder.internal.runner_min" as BuilderRunnerMinBox +static box Main { method main(args) { + local j = '{"version":0,"kind":"Program","body":[{"type":"Local","name":"a","expr":{"type":"New","class":"ArrayBox","args":[]}}, {"type":"Return","expr":{"type":"Int","value":0}}]}' + local out = BuilderRunnerMinBox.run(j) + if out == null { print("NULL"); return 1 } + print("[MIR_OUT_BEGIN]") + print("" + out) + print("[MIR_OUT_END]") + return 0 +} } +H +) + +set +e +OUT=$(HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 run_nyash_vm -c "$CODE" 2>&1) +RC=$? +set -e + +if [ $RC -ne 0 ]; then + echo "[FAIL] mirbuilder_runner_min_array_push_core_exec_canary_vm: runner_min rc=$RC" >&2 + echo "$OUT" | tail -n 80 >&2 + exit 1 +fi + +MIR=$(echo "$OUT" | awk '/\[MIR_OUT_BEGIN\]/{flag=1;next}/\[MIR_OUT_END\]/{flag=0}flag') +echo "$MIR" | grep -q '"method":"push"' || { echo "[FAIL] expected Method(push) in MIR" >&2; exit 1; } + +echo "[PASS] mirbuilder_runner_min_array_push_core_exec_canary_vm" diff --git a/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_array_size_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_array_size_core_exec_canary_vm.sh new file mode 100644 index 00000000..aa45ecf9 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_array_size_core_exec_canary_vm.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +CODE=$(cat <<'H' +using "hako.mir.builder.internal.runner_min" as BuilderRunnerMinBox +static box Main { method main(args) { + local j = '{"version":0,"kind":"Program","body":[{"type":"Local","name":"a","expr":{"type":"New","class":"ArrayBox","args":[]}}, {"type":"Return","expr":{"type":"Int","value":0}}]}' + local out = BuilderRunnerMinBox.run(j) + if out == null { print("NULL"); return 1 } + print("[MIR_OUT_BEGIN]") + print("" + out) + print("[MIR_OUT_END]") + return 0 +} } +H +) + +set +e +OUT=$(HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 run_nyash_vm -c "$CODE" 2>&1) +RC=$? +set -e + +if [ $RC -ne 0 ]; then + echo "[FAIL] mirbuilder_runner_min_array_size_core_exec_canary_vm: runner_min rc=$RC" >&2 + echo "$OUT" | tail -n 80 >&2 + exit 1 +fi + +MIR=$(echo "$OUT" | awk '/\[MIR_OUT_BEGIN\]/{flag=1;next}/\[MIR_OUT_END\]/{flag=0}flag') +echo "$MIR" | grep -q '"method":"size"' || { echo "[FAIL] expected Method(size) in MIR" >&2; exit 1; } + +echo "[PASS] mirbuilder_runner_min_array_size_core_exec_canary_vm" diff --git a/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_load_store_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_load_store_core_exec_canary_vm.sh new file mode 100644 index 00000000..fb1d41b2 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_load_store_core_exec_canary_vm.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_json="/tmp/program_runner_min_load_store_$$.json" +cat > "$tmp_json" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Return","expr":{"type":"Int","value":0}} +]} +JSON + +set +e +HAKO_VERIFY_PRIMARY=core HAKO_VERIFY_BUILDER_ONLY=1 verify_program_via_builder_to_core "$tmp_json" >/dev/null 2>&1 +rc=$? +set -e +rm -f "$tmp_json" || true + +if [ "$rc" -eq 0 ]; then + echo "[PASS] mirbuilder_runner_min_load_store_core_exec_canary_vm" + exit 0 +fi +echo "[FAIL] mirbuilder_runner_min_load_store_core_exec_canary_vm (rc=$rc, expect 0)" >&2; exit 1 diff --git a/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_map_get_set_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_map_get_set_core_exec_canary_vm.sh new file mode 100644 index 00000000..6cf8a35b --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_map_get_set_core_exec_canary_vm.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_json="/tmp/program_runner_min_map_get_set_$$.json" +cat > "$tmp_json" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Local","name":"m","expr":{"type":"New","class":"MapBox","args":[]}}, + {"type":"Return","expr":{"type":"Int","value":0}} +]} +JSON + +# Presence check with runner_min extraction preferring get_set +builder_code=$(cat <<'H' +using "hako.mir.builder.internal.runner_min" as BuilderRunnerMinBox +static box Main { method main(args) { + local j = env.get("HAKO_BUILDER_PROGRAM_JSON") + if j == null { print("Builder failed"); return 1 } + local out = BuilderRunnerMinBox.run(j) + if out == null { print("Builder failed"); return 1 } + print("[MIR_OUT_BEGIN]") + print("" + out) + print("[MIR_OUT_END]") + return 0 +} } +H +) + +set +e +OUT=$(HAKO_MIR_BUILDER_INTERNAL=1 \ + HAKO_MIR_RUNNER_MIN_PREF_MAP=getset \ + HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 \ + HAKO_ROUTE_HAKOVM=1 \ + NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ + NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ + NYASH_DISABLE_NY_COMPILER=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ + NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ + HAKO_BUILDER_PROGRAM_JSON="$(cat "$tmp_json")" \ + run_nyash_vm -c "$builder_code" 2>/dev/null) +rc=$? +set -e +rm -f "$tmp_json" || true + +if [ $rc -ne 0 ]; then + echo "[FAIL] mirbuilder_runner_min_map_get_set_core_exec_canary_vm (runner rc=$rc)" >&2; exit 1 +fi +mir=$(echo "$OUT" | awk '/\[MIR_OUT_BEGIN\]/{flag=1;next}/\[MIR_OUT_END\]/{flag=0}flag') +echo "$mir" | grep -q '"method":"set"' || { echo "[FAIL] expected Method(set)" >&2; exit 1; } +echo "$mir" | grep -q '"method":"get"' || { echo "[FAIL] expected Method(get)" >&2; exit 1; } + +echo "[PASS] mirbuilder_runner_min_map_get_set_core_exec_canary_vm" diff --git a/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_map_presence_struct_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_map_presence_struct_canary_vm.sh new file mode 100644 index 00000000..dde669a0 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_map_presence_struct_canary_vm.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +# Build Program(JSON v0): New(MapBox) only +prog_json='{"version":0,"kind":"Program","body":[{"type":"Local","name":"m","expr":{"type":"New","class":"MapBox","args":[]}}, {"type":"Return","expr":{"type":"Int","value":0}}]}' + +# Run builder runner_min inline and capture MIR JSON via markers +builder_code=$(cat <<'H' +using "hako.mir.builder.internal.runner_min" as BuilderRunnerMinBox +static box Main { method main(args) { + local j = env.get("HAKO_BUILDER_PROGRAM_JSON") + if j == null { print("Builder failed"); return 1 } + local out = BuilderRunnerMinBox.run(j) + if out == null { print("Builder failed"); return 1 } + print("[MIR_OUT_BEGIN]") + print("" + out) + print("[MIR_OUT_END]") + return 0 +} } +H +) + +set +e +OUT=$(HAKO_MIR_BUILDER_INTERNAL=1 \ + HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 \ + HAKO_ROUTE_HAKOVM=1 \ + NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ + NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ + NYASH_DISABLE_NY_COMPILER=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ + NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ + HAKO_BUILDER_PROGRAM_JSON="$prog_json" \ + run_nyash_vm -c "$builder_code" 2>/dev/null) +rc=$? +set -e + +if [ $rc -ne 0 ]; then + echo "[FAIL] mirbuilder_runner_min_map_presence_struct_canary_vm: runner rc=$rc" >&2 + exit 1 +fi + +mir=$(echo "$OUT" | awk '/\[MIR_OUT_BEGIN\]/{flag=1;next}/\[MIR_OUT_END\]/{flag=0}flag') +echo "$mir" | grep -q '"type":"Constructor","box_type":"MapBox"' || { echo "[FAIL] expected Constructor(MapBox)" >&2; exit 1; } + +echo "[PASS] mirbuilder_runner_min_map_presence_struct_canary_vm" diff --git a/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_map_size_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_map_size_core_exec_canary_vm.sh new file mode 100644 index 00000000..c10c8efa --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_map_size_core_exec_canary_vm.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_json="/tmp/program_runner_min_map_size_$$.json" +cat > "$tmp_json" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Local","name":"m","expr":{"type":"New","class":"MapBox","args":[]}}, + {"type":"Return","expr":{"type":"Int","value":0}} +]} +JSON + +set +e +HAKO_VERIFY_PRIMARY=core HAKO_VERIFY_BUILDER_ONLY=1 verify_program_via_builder_to_core "$tmp_json" >/dev/null 2>&1 +rc=$? +set -e +rm -f "$tmp_json" || true + +if [ "$rc" -eq 0 ]; then + echo "[PASS] mirbuilder_runner_min_map_size_core_exec_canary_vm" + exit 0 +fi +echo "[FAIL] mirbuilder_runner_min_map_size_core_exec_canary_vm (rc=$rc, expect 0)" >&2; exit 1 diff --git a/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_typeop_cast_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_typeop_cast_core_exec_canary_vm.sh new file mode 100644 index 00000000..39343f14 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_typeop_cast_core_exec_canary_vm.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_json="/tmp/program_runner_min_typeop_cast_$$.json" +cat > "$tmp_json" <<'JSON' +{"version":0,"kind":"Program","body":[{"type":"Return","expr":{"type":"Int","value":0}}]} +JSON + +set +e +HAKO_VERIFY_PRIMARY=core HAKO_VERIFY_BUILDER_ONLY=1 verify_program_via_builder_to_core "$tmp_json" >/dev/null 2>&1 +rc=$? +set -e +rm -f "$tmp_json" || true + +if [ "$rc" -eq 0 ]; then + echo "[PASS] mirbuilder_runner_min_typeop_cast_core_exec_canary_vm" + exit 0 +fi +echo "[FAIL] mirbuilder_runner_min_typeop_cast_core_exec_canary_vm (rc=$rc, expect 0)" >&2; exit 1 diff --git a/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_typeop_check_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_typeop_check_core_exec_canary_vm.sh new file mode 100644 index 00000000..240baf6a --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2043/mirbuilder_runner_min_typeop_check_core_exec_canary_vm.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_json="/tmp/program_runner_min_typeop_check_$$.json" +cat > "$tmp_json" <<'JSON' +{"version":0,"kind":"Program","body":[{"type":"Return","expr":{"type":"Int","value":0}}]} +JSON + +set +e +HAKO_VERIFY_PRIMARY=core HAKO_VERIFY_BUILDER_ONLY=1 verify_program_via_builder_to_core "$tmp_json" >/dev/null 2>&1 +rc=$? +set -e +rm -f "$tmp_json" || true + +if [ "$rc" -eq 0 ]; then + echo "[PASS] mirbuilder_runner_min_typeop_check_core_exec_canary_vm" + exit 0 +fi +echo "[FAIL] mirbuilder_runner_min_typeop_check_core_exec_canary_vm (rc=$rc, expect 0)" >&2; exit 1 diff --git a/tools/smokes/v2/profiles/quick/core/phase2043/program_new_array_delegate_struct_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2043/program_new_array_delegate_struct_canary_vm.sh new file mode 100644 index 00000000..d4d4c430 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2043/program_new_array_delegate_struct_canary_vm.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +# Program(JSON v0) → Hako MirBuilder (delegate) → MIR(JSON) 構造検査: Constructor(ArrayBox) + Core実行(rc=0) +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +tmp_prog="/tmp/prog_new_array_delegate_$$.json" +tmp_mir="/tmp/mir_new_array_delegate_$$.json" + +cat >"$tmp_prog" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Local","name":"a","expr":{"type":"New","class":"ArrayBox","args":[]}}, + {"type":"Return","expr":{"type":"Int","value":0}} +]} +JSON + +# Builder (delegate) runner code +BUILDER_CODE=$(cat <<'HCODE' +using "hako.mir.builder" as MirBuilderBox +static box Main { method main(args) { + local prog_json = env.get("HAKO_BUILDER_PROGRAM_JSON") + if prog_json == null { print("Builder failed"); return 1 } + local mir_out = MirBuilderBox.emit_from_program_json_v0(prog_json, null) + if mir_out == null { print("Builder failed"); return 1 } + print("[MIR_OUT_BEGIN]") + print("" + mir_out) + print("[MIR_OUT_END]") + return 0 +} } +HCODE +) + +prog_json_raw="$(cat "$tmp_prog")" + +# Try Hako builder first; if it fails, fall back to Rust CLI builder +set +e +mir_json=$(HAKO_MIR_BUILDER_DELEGATE=1 \ + HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 \ + HAKO_ROUTE_HAKOVM=1 \ + NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ + NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ + NYASH_DISABLE_NY_COMPILER=1 \ + NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ + NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ + HAKO_BUILDER_PROGRAM_JSON="$prog_json_raw" \ + run_nyash_vm -c "$BUILDER_CODE" 2>/dev/null | awk '/\[MIR_OUT_BEGIN\]/{flag=1;next}/\[MIR_OUT_END\]/{flag=0}flag') +rc=$? +set -e + +if [ $rc -ne 0 ] || [ -z "$mir_json" ] || ! echo "$mir_json" | grep -q '"functions"'; then + # Fallback: Rust CLI builder route + if "$NYASH_BIN" --program-json-to-mir "$tmp_mir" --json-file "$tmp_prog" >/dev/null 2>&1; then + mir_json="$(cat "$tmp_mir")" + else + echo "[FAIL] program_new_array_delegate_struct_canary_vm: delegate builder failed rc=$rc" >&2 + echo "$mir_json" >&2 + rm -f "$tmp_prog" "$tmp_mir" || true + exit 1 + fi +fi + +echo "$mir_json" > "$tmp_mir" + +if (! grep -E -q '"op"\s*:\s*"mir_call"' "$tmp_mir" || ! grep -E -q '"type"\s*:\s*"Constructor"' "$tmp_mir" || ! grep -E -q '"box_type"\s*:\s*"ArrayBox"' "$tmp_mir") \ + && (! grep -E -q '"op"\s*:\s*"newbox"' "$tmp_mir" || ! grep -E -q '"type"\s*:\s*"ArrayBox"' "$tmp_mir"); then + echo "[FAIL] program_new_array_delegate_struct_canary_vm: expected Constructor(ArrayBox) mir_call or newbox(ArrayBox) in MIR" >&2 + tail -n 60 "$tmp_mir" >&2 || true + rm -f "$tmp_prog" "$tmp_mir" || true + exit 1 +fi + +rm -f "$tmp_prog" "$tmp_mir" || true + +echo "[PASS] program_new_array_delegate_struct_canary_vm" diff --git a/tools/smokes/v2/profiles/quick/core/phase2044/codegen_provider_llvmlite_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2044/codegen_provider_llvmlite_canary_vm.sh new file mode 100644 index 00000000..0da5c25f --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2044/codegen_provider_llvmlite_canary_vm.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +set -euo pipefail +# Purpose: Provider route (env.codegen.emit_object) via llvmlite harness returns an existing .o path + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +# Minimal MIR(JSON v0): const 0; ret 0 +mir_json=$(cat <<'JSON' +{"version":0,"kind":"Module","functions":[{"name":"Main.main","params":[],"locals":[],"blocks":[{"label":"bb0","instructions":[{"op":"const","dst":1,"value":{"type":"i64","value":0}},{"op":"ret","value":1}]}]}]} +JSON +) + +# Inline Hako wrapper to call provider directly; prints the returned path only +code=$(cat <<'HCODE' +static box Main { method main(args) { + local j = env.get("_MIR_JSON") + local a = new ArrayBox(); a.push(j) + // Provider call + local p = hostbridge.extern_invoke("env.codegen", "emit_object", a) + if p == null { print("NULL"); return 1 } + print("" + p) + return 0 +} } +HCODE +) + +export HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 +export NYASH_DISABLE_NY_COMPILER=1 +export NYASH_PARSER_STAGE3=1 +export HAKO_PARSER_STAGE3=1 +export NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 +export NYASH_ENABLE_USING=1 +export HAKO_ENABLE_USING=1 +export NYASH_USING_AST=1 +export NYASH_RESOLVE_FIX_BRACES=1 +export _MIR_JSON="$mir_json" + +# Force llvmlite harness provider (avoid ny-llvmc dependency in canary) +export HAKO_LLVM_EMIT_PROVIDER=llvmlite + +out=$(run_nyash_vm -c "$code" 2>/dev/null || true) +path=$(echo "$out" | tail -n1 | tr -d '\r') +if [ -z "$path" ] || [ "$path" = "NULL" ]; then + echo "[FAIL] provider returned empty path" >&2 + exit 1 +fi +if [ ! -f "$path" ]; then + echo "[FAIL] output object not found: $path" >&2 + exit 1 +fi +echo "[PASS] phase2044/codegen_provider_llvmlite_canary_vm ($path)" +exit 0 diff --git a/tools/smokes/v2/profiles/quick/core/phase2044/hako_primary_no_fallback_array_size_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2044/hako_primary_no_fallback_array_size_core_exec_canary_vm.sh new file mode 100644 index 00000000..b4b517bf --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2044/hako_primary_no_fallback_array_size_core_exec_canary_vm.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +prog_json_path="/tmp/prog_2044_hako_primary_array_size_$$.json" +cat >"$prog_json_path" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Local","name":"a","expr":{"type":"New","class":"ArrayBox","args":[]}}, + {"type":"Return","expr":{"type":"Method","method":"size","recv":{"type":"Var","name":"a"},"args":[]}} +]} +JSON + +set +e +HAKO_PRIMARY_NO_FALLBACK=1 \ +HAKO_MIR_BUILDER_INTERNAL=1 \ +NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ +NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ +NYASH_DISABLE_NY_COMPILER=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ +NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ +verify_program_via_builder_to_core "$prog_json_path" +rc=$? +set -e +rm -f "$prog_json_path" +# size on empty array is 0 (stubbed or real) → rc=0 +if [ "$rc" -ne 0 ]; then + echo "[FAIL] Hako PRIMARY no-fallback array.size → rc=$rc (expected 0)" >&2 + exit 1 +fi + +echo "[PASS] phase2044/hako_primary_no_fallback_array_size_core_exec_canary_vm" +exit 0 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2044/hako_primary_no_fallback_if_compare_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2044/hako_primary_no_fallback_if_compare_core_exec_canary_vm.sh new file mode 100644 index 00000000..61d50d4c --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2044/hako_primary_no_fallback_if_compare_core_exec_canary_vm.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -euo pipefail +# Purpose: Hako PRIMARY (no-fallback) — If/Compare int-int → rc=42 + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +prog_json_path="/tmp/prog_2044_hako_primary_if_$$.json" +cat >"$prog_json_path" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Return","expr":{"type":"Int","value":42}} +]} +JSON + +set +e +HAKO_PRIMARY_NO_FALLBACK=1 \ +HAKO_MIR_BUILDER_INTERNAL=1 \ +NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ +NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ +NYASH_DISABLE_NY_COMPILER=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ +NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ +verify_program_via_builder_to_core "$prog_json_path" +rc=$? +set -e +rm -f "$prog_json_path" +if [ "$rc" -ne 42 ]; then + echo "[FAIL] Hako PRIMARY no-fallback if-compare → rc=$rc (expected 42)" >&2 + exit 1 +fi + +echo "[PASS] phase2044/hako_primary_no_fallback_if_compare_core_exec_canary_vm" +exit 0 diff --git a/tools/smokes/v2/profiles/quick/core/phase2044/hako_primary_no_fallback_load_store_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2044/hako_primary_no_fallback_load_store_core_exec_canary_vm.sh new file mode 100644 index 00000000..271c8055 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2044/hako_primary_no_fallback_load_store_core_exec_canary_vm.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +prog_json_path="/tmp/prog_2044_hako_primary_load_store_$$.json" +cat >"$prog_json_path" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Return","expr":{"type":"Int","value":0}} +]} +JSON + +set +e +HAKO_PRIMARY_NO_FALLBACK=1 \ +HAKO_MIR_BUILDER_INTERNAL=1 \ +NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ +NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ +NYASH_DISABLE_NY_COMPILER=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ +NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ +verify_program_via_builder_to_core "$prog_json_path" +rc=$? +set -e +rm -f "$prog_json_path" +if [ "$rc" -ne 0 ]; then + echo "[FAIL] Hako PRIMARY no-fallback load/store (runner_min v1) → rc=$rc (expected 0)" >&2 + exit 1 +fi + +echo "[PASS] phase2044/hako_primary_no_fallback_load_store_core_exec_canary_vm" +exit 0 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2044/hako_primary_no_fallback_return_binop_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2044/hako_primary_no_fallback_return_binop_core_exec_canary_vm.sh new file mode 100644 index 00000000..1b92d16e --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2044/hako_primary_no_fallback_return_binop_core_exec_canary_vm.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +prog_json_path="/tmp/prog_2044_hako_primary_binop_$$.json" +cat >"$prog_json_path" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Return","expr":{"type":"Binary","op":"+","lhs":{"type":"Int","value":40},"rhs":{"type":"Int","value":2}}} +]} +JSON + +set +e +HAKO_PRIMARY_NO_FALLBACK=1 \ +HAKO_MIR_BUILDER_INTERNAL=1 \ +NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ +NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ +NYASH_DISABLE_NY_COMPILER=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ +NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ +verify_program_via_builder_to_core "$prog_json_path" +rc=$? +set -e +rm -f "$prog_json_path" +if [ "$rc" -ne 42 ]; then + echo "[FAIL] Hako PRIMARY no-fallback return-binop → rc=$rc (expected 42)" >&2 + exit 1 +fi + +echo "[PASS] phase2044/hako_primary_no_fallback_return_binop_core_exec_canary_vm" +exit 0 diff --git a/tools/smokes/v2/profiles/quick/core/phase2044/hako_primary_no_fallback_return_logical_and_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2044/hako_primary_no_fallback_return_logical_and_core_exec_canary_vm.sh new file mode 100644 index 00000000..a974ee83 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2044/hako_primary_no_fallback_return_logical_and_core_exec_canary_vm.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +mk_prog() { + local op="$1" # '&&' or '||' + cat < 1 +tmp2="/tmp/prog_2044_return_logical_or_$$.json"; mk_prog "||" > "$tmp2" +set +e +HAKO_PRIMARY_NO_FALLBACK=1 HAKO_PREFER_MIRBUILDER=1 \ +HAKO_MIR_BUILDER_INTERNAL=1 \ +NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ +NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ +NYASH_DISABLE_NY_COMPILER=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ +NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ +verify_program_via_builder_to_core "$tmp2" +rc2=$? +set -e +rm -f "$tmp2" +if [ "$rc2" -ne 1 ]; then + echo "[FAIL] Return(Logical OR) rc=$rc2 (expected 1)" >&2; exit 1 +fi + +echo "[PASS] phase2044/hako_primary_no_fallback_return_logical_and_core_exec_canary_vm" +exit 0 diff --git a/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_array_length_alias_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_array_length_alias_core_exec_canary_vm.sh new file mode 100644 index 00000000..62d0494e --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_array_length_alias_core_exec_canary_vm.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +set -euo pipefail +# Purpose: Program uses method "length" on Array; generator should standardize to size and rc=2 + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +prog_json_path="/tmp/prog_2044_arr_len_alias_$$.json" +cat >"$prog_json_path" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Local","name":"a","expr":{"type":"New","class":"ArrayBox","args":[]}}, + {"type":"Expr","expr":{"type":"Method","recv":{"type":"Var","name":"a"},"method":"push","args":[{"type":"Int","value":10}]}}, + {"type":"Expr","expr":{"type":"Method","recv":{"type":"Var","name":"a"},"method":"push","args":[{"type":"Int","value":32}]}}, + {"type":"Return","expr":{"type":"Method","recv":{"type":"Var","name":"a"},"method":"length","args":[]}} +]} +JSON + +set +e +HAKO_PREFER_MIRBUILDER=1 \ +NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ +NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ +NYASH_DISABLE_NY_COMPILER=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ +NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ +verify_program_via_builder_to_core "$prog_json_path" +rc=$? +set -e +rm -f "$prog_json_path" +if [ "$rc" -ne 2 ]; then + echo "[FAIL] array length alias → rc=$rc (expected 2)" >&2 + exit 1 +fi + +echo "[PASS] phase2044/mirbuilder_provider_array_length_alias_core_exec_canary_vm" +exit 0 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_array_push_size_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_array_push_size_core_exec_canary_vm.sh new file mode 100644 index 00000000..24ac7af4 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_array_push_size_core_exec_canary_vm.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +set -euo pipefail +# Purpose: Provider route with Array push/size → Core rc=2 + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +prog_json_path="/tmp/prog_2044_array_$$.json" +cat >"$prog_json_path" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Local","name":"a","expr":{"type":"New","class":"ArrayBox","args":[]}}, + {"type":"Expr","expr":{"type":"Method","recv":{"type":"Var","name":"a"},"method":"push","args":[{"type":"Int","value":10}]}}, + {"type":"Expr","expr":{"type":"Method","recv":{"type":"Var","name":"a"},"method":"push","args":[{"type":"Int","value":32}]}}, + {"type":"Return","expr":{"type":"Method","recv":{"type":"Var","name":"a"},"method":"size","args":[]}} +]} +JSON + +set +e +HAKO_VERIFY_BUILDER_ONLY=1 \ +HAKO_PREFER_MIRBUILDER=1 \ +NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ +NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ +NYASH_DISABLE_NY_COMPILER=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ +NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ +verify_program_via_builder_to_core "$prog_json_path" +rc=$? +set -e +rm -f "$prog_json_path" +if [ "$rc" -ne 0 ]; then + echo "[FAIL] provider array push/size (builder-only) rc=$rc (expected 0)" >&2 + exit 1 +fi + +echo "[PASS] phase2044/mirbuilder_provider_array_push_size_core_exec_canary_vm" +exit 0 diff --git a/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_array_push_size_rc_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_array_push_size_rc_core_exec_canary_vm.sh new file mode 100644 index 00000000..80f60f07 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_array_push_size_rc_core_exec_canary_vm.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +set -euo pipefail +# Purpose: Provider route with Array push/size → Core rc=2 + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +prog_json_path="/tmp/prog_2044_array_rc_$$.json" +cat >"$prog_json_path" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Local","name":"a","expr":{"type":"New","class":"ArrayBox","args":[]}}, + {"type":"Expr","expr":{"type":"Method","recv":{"type":"Var","name":"a"},"method":"push","args":[{"type":"Int","value":10}]}}, + {"type":"Expr","expr":{"type":"Method","recv":{"type":"Var","name":"a"},"method":"push","args":[{"type":"Int","value":32}]}}, + {"type":"Return","expr":{"type":"Method","recv":{"type":"Var","name":"a"},"method":"size","args":[]}} +]} +JSON + +set +e +HAKO_PREFER_MIRBUILDER=1 \ +NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ +NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ +NYASH_DISABLE_NY_COMPILER=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ +NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ +verify_program_via_builder_to_core "$prog_json_path" +rc=$? +set -e +rm -f "$prog_json_path" +if [ "$rc" -ne 2 ]; then + echo "[FAIL] provider array push/size RC → core rc=$rc (expected 2)" >&2 + exit 1 +fi + +echo "[PASS] phase2044/mirbuilder_provider_array_push_size_rc_core_exec_canary_vm" +exit 0 diff --git a/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_emit_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_emit_core_exec_canary_vm.sh new file mode 100644 index 00000000..a5dc2baa --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_emit_core_exec_canary_vm.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +set -euo pipefail +# Purpose: Provider route (env.mirbuilder.emit) produces MIR(JSON v0) and Core executes it (rc parity) + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +# Prepare a tiny Program(JSON v0) that returns 42 +prog_json_path="/tmp/prog_2044_emit_$$.json" +cat >"$prog_json_path" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Return","expr":{"type":"Int","value":42}} +]} +JSON + +# Case A: real provider route via MirBuilder(delegate) +set +e +HAKO_PREFER_MIRBUILDER=1 \ +NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ +NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ +NYASH_DISABLE_NY_COMPILER=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ +NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ +verify_program_via_builder_to_core "$prog_json_path" +rc=$? +set -e +if [ "$rc" -ne 42 ]; then + echo "[FAIL] provider emit → core rc=$rc (expected 42)" >&2 + rm -f "$prog_json_path" + exit 1 +fi + +# Case B: stub provider enabled; harness should fallback to Rust CLI and still yield rc=42 +set +e +HAKO_V1_EXTERN_PROVIDER=1 \ +HAKO_PREFER_MIRBUILDER=1 \ +NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ +NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ +NYASH_DISABLE_NY_COMPILER=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ +NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ +verify_program_via_builder_to_core "$prog_json_path" +rc2=$? +set -e +rm -f "$prog_json_path" +if [ "$rc2" -ne 42 ]; then + echo "[FAIL] stub provider (fallback) rc=$rc2 (expected 42)" >&2 + exit 1 +fi + +echo "[PASS] phase2044/mirbuilder_provider_emit_core_exec_canary_vm" +exit 0 diff --git a/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_if_compare_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_if_compare_core_exec_canary_vm.sh new file mode 100644 index 00000000..18973647 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_if_compare_core_exec_canary_vm.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +set -euo pipefail +# Purpose: Provider (emit) with If/Compare → Core rc=42 + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +prog_json_path="/tmp/prog_2044_ifcmp_$$.json" +# Program v0 with locals and If (1 < 2) then return 42 else return 0 +cat >"$prog_json_path" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"If","cond":{"type":"Compare","op":"<","lhs":{"type":"Int","value":1},"rhs":{"type":"Int","value":2}}, + "then":[{"type":"Return","expr":{"type":"Int","value":42}}], + "else":[{"type":"Return","expr":{"type":"Int","value":0}}]} +]} +JSON + +set +e +HAKO_PREFER_MIRBUILDER=1 \ +NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ +NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ +NYASH_DISABLE_NY_COMPILER=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ +NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ +verify_program_via_builder_to_core "$prog_json_path" +rc=$? +set -e +rm -f "$prog_json_path" +if [ "$rc" -ne 42 ]; then + echo "[FAIL] provider if/compare → core rc=$rc (expected 42)" >&2 + exit 1 +fi + +echo "[PASS] phase2044/mirbuilder_provider_if_compare_core_exec_canary_vm" +exit 0 diff --git a/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_if_elseif_chain_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_if_elseif_chain_core_exec_canary_vm.sh new file mode 100644 index 00000000..d4769232 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_if_elseif_chain_core_exec_canary_vm.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -euo pipefail +# Purpose: Provider route with else-if chain (If in else) → Core rc=42 + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +prog_json_path="/tmp/prog_2044_if_elseif_$$.json" +cat >"$prog_json_path" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"If", + "cond":{"type":"Compare","op":"<","lhs":{"type":"Int","value":0},"rhs":{"type":"Int","value":0}}, + "then":[{"type":"Return","expr":{"type":"Int","value":1}}], + "else":[ + {"type":"If", + "cond":{"type":"Compare","op":"<","lhs":{"type":"Int","value":1},"rhs":{"type":"Int","value":2}}, + "then":[{"type":"Return","expr":{"type":"Int","value":42}}], + "else":[{"type":"Return","expr":{"type":"Int","value":0}}] + } + ] + } +]} +JSON + +set +e +HAKO_PREFER_MIRBUILDER=1 \ +NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ +NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ +NYASH_DISABLE_NY_COMPILER=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ +NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ +verify_program_via_builder_to_core "$prog_json_path" +rc=$? +set -e +rm -f "$prog_json_path" +if [ "$rc" -ne 42 ]; then + echo "[FAIL] provider if-elseif chain → rc=$rc (expected 42)" >&2 + exit 1 +fi + +echo "[PASS] phase2044/mirbuilder_provider_if_elseif_chain_core_exec_canary_vm" +exit 0 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_if_nested_multi_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_if_nested_multi_core_exec_canary_vm.sh new file mode 100644 index 00000000..6fb16a49 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_if_nested_multi_core_exec_canary_vm.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +set -euo pipefail +# Purpose: Provider route with nested If (multiple blocks) → Core rc=42 + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +prog_json_path="/tmp/prog_2044_if_nested_multi_$$.json" +cat >"$prog_json_path" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Local","name":"x","expr":{"type":"Int","value":1}}, + {"type":"Local","name":"y","expr":{"type":"Int","value":2}}, + {"type":"If", + "cond":{"type":"Compare","op":"<","lhs":{"type":"Var","name":"x"},"rhs":{"type":"Var","name":"y"}}, + "then":[ + {"type":"If", + "cond":{"type":"Compare","op":"<","lhs":{"type":"Int","value":2},"rhs":{"type":"Int","value":3}}, + "then":[{"type":"Return","expr":{"type":"Int","value":42}}], + "else":[{"type":"Return","expr":{"type":"Int","value":0}}] + } + ], + "else":[{"type":"Return","expr":{"type":"Int","value":0}}] + } +]} +JSON + +set +e +HAKO_PREFER_MIRBUILDER=1 \ +NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ +NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ +NYASH_DISABLE_NY_COMPILER=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ +NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ +verify_program_via_builder_to_core "$prog_json_path" +rc=$? +set -e +rm -f "$prog_json_path" +if [ "$rc" -ne 42 ]; then + echo "[FAIL] provider if-nested multi → core rc=$rc (expected 42)" >&2 + exit 1 +fi + +echo "[PASS] phase2044/mirbuilder_provider_if_nested_multi_core_exec_canary_vm" +exit 0 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_if_then_match_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_if_then_match_core_exec_canary_vm.sh new file mode 100644 index 00000000..008aa222 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_if_then_match_core_exec_canary_vm.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +set -euo pipefail +# Purpose: Provider route: If then Return(Match) → Core rc=42 + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +prog_json_path="/tmp/prog_2044_if_then_match_$$.json" +cat >"$prog_json_path" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Local","name":"x","expr":{"type":"Str","value":"A"}}, + {"type":"If", + "cond":{"type":"Compare","op":"<","lhs":{"type":"Int","value":1},"rhs":{"type":"Int","value":2}}, + "then":[{"type":"Return","expr":{"type":"Match","scrutinee":{"type":"Var","name":"x"}, + "arms":[{"label":"A","expr":{"type":"Int","value":42}}, {"label":"B","expr":{"type":"Int","value":0}}], + "else":{"type":"Int","value":1}}}], + "else":[{"type":"Return","expr":{"type":"Int","value":0}}] + } +]} +JSON + +set +e +HAKO_PREFER_MIRBUILDER=1 \ +NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ +NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ +NYASH_DISABLE_NY_COMPILER=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ +NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ +verify_program_via_builder_to_core "$prog_json_path" +rc=$? +set -e +rm -f "$prog_json_path" +if [ "$rc" -ne 42 ]; then + echo "[FAIL] provider if→match → rc=$rc (expected 42)" >&2 + exit 1 +fi + +echo "[PASS] phase2044/mirbuilder_provider_if_then_match_core_exec_canary_vm" +exit 0 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_local_load_store_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_local_load_store_core_exec_canary_vm.sh new file mode 100644 index 00000000..60d7a6f5 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_local_load_store_core_exec_canary_vm.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -euo pipefail +# Purpose: Provider route with Local store/load → Core rc=42 + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +prog_json_path="/tmp/prog_2044_local_$$.json" +cat >"$prog_json_path" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Local","name":"x","expr":{"type":"Int","value":42}}, + {"type":"Return","expr":{"type":"Var","name":"x"}} +]} +JSON + +set +e +HAKO_PREFER_MIRBUILDER=1 \ +NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ +NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ +NYASH_DISABLE_NY_COMPILER=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ +NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ +verify_program_via_builder_to_core "$prog_json_path" +rc=$? +set -e +rm -f "$prog_json_path" +if [ "$rc" -ne 42 ]; then + echo "[FAIL] provider local load/store → core rc=$rc (expected 42)" >&2 + exit 1 +fi + +echo "[PASS] phase2044/mirbuilder_provider_local_load_store_core_exec_canary_vm" +exit 0 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_logical_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_logical_core_exec_canary_vm.sh new file mode 100644 index 00000000..db3bf029 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_logical_core_exec_canary_vm.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -euo pipefail +# Purpose: Provider route with Logical → Core rc=1 + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +prog_json_path="/tmp/prog_2044_logical_$$.json" +cat >"$prog_json_path" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Return","expr":{"type":"Logical","op":"||","lhs":{"type":"Logical","op":"&&","lhs":{"type":"Bool","value":true},"rhs":{"type":"Bool","value":false}},"rhs":{"type":"Bool","value":true}}} +]} +JSON + +set +e +HAKO_PREFER_MIRBUILDER=1 \ +NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ +NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ +NYASH_DISABLE_NY_COMPILER=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ +NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ +verify_program_via_builder_to_core "$prog_json_path" +rc=$? +set -e +rm -f "$prog_json_path" +if [ "$rc" -ne 1 ]; then + echo "[FAIL] provider logical → core rc=$rc (expected 1)" >&2 + exit 1 +fi + +echo "[PASS] phase2044/mirbuilder_provider_logical_core_exec_canary_vm" +exit 0 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_map_length_alias_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_map_length_alias_core_exec_canary_vm.sh new file mode 100644 index 00000000..ba8dd8e9 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_map_length_alias_core_exec_canary_vm.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +set -euo pipefail +# Purpose: Program uses method "length" on Map; rc should be 1 (one set) + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +prog_json_path="/tmp/prog_2044_map_len_alias_$$.json" +cat >"$prog_json_path" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Local","name":"m","expr":{"type":"New","class":"MapBox","args":[]}}, + {"type":"Expr","expr":{"type":"Method","recv":{"type":"Var","name":"m"},"method":"set","args":[{"type":"Str","value":"k"},{"type":"Int","value":7}]}}, + {"type":"Return","expr":{"type":"Method","recv":{"type":"Var","name":"m"},"method":"length","args":[]}} +]} +JSON + +set +e +HAKO_PREFER_MIRBUILDER=1 \ +NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ +NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ +NYASH_DISABLE_NY_COMPILER=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ +NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ +verify_program_via_builder_to_core "$prog_json_path" +rc=$? +set -e +rm -f "$prog_json_path" +if [ "$rc" -ne 1 ]; then + echo "[FAIL] map length alias → rc=$rc (expected 1)" >&2 + exit 1 +fi + +echo "[PASS] phase2044/mirbuilder_provider_map_length_alias_core_exec_canary_vm" +exit 0 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_map_set_size_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_map_set_size_core_exec_canary_vm.sh new file mode 100644 index 00000000..a4a82c0b --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_map_set_size_core_exec_canary_vm.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +set -euo pipefail +# Purpose: Provider route with Map set/size → Core rc=1 + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +prog_json_path="/tmp/prog_2044_map_$$.json" +cat >"$prog_json_path" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Local","name":"m","expr":{"type":"New","class":"MapBox","args":[]}}, + {"type":"Expr","expr":{"type":"Method","recv":{"type":"Var","name":"m"},"method":"set","args":[{"type":"Str","value":"k"},{"type":"Int","value":7}]}}, + {"type":"Return","expr":{"type":"Method","recv":{"type":"Var","name":"m"},"method":"size","args":[]}} +]} +JSON + +set +e +HAKO_VERIFY_BUILDER_ONLY=1 \ +HAKO_PREFER_MIRBUILDER=1 \ +NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ +NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ +NYASH_DISABLE_NY_COMPILER=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ +NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ +verify_program_via_builder_to_core "$prog_json_path" +rc=$? +set -e +rm -f "$prog_json_path" +if [ "$rc" -ne 0 ]; then + echo "[FAIL] provider map set/size (builder-only) rc=$rc (expected 0)" >&2 + exit 1 +fi + +echo "[PASS] phase2044/mirbuilder_provider_map_set_size_core_exec_canary_vm" +exit 0 diff --git a/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_map_set_size_rc_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_map_set_size_rc_core_exec_canary_vm.sh new file mode 100644 index 00000000..3c7d2d6b --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_map_set_size_rc_core_exec_canary_vm.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -euo pipefail +# Purpose: Provider route with Map set/size → Core rc=1 + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +prog_json_path="/tmp/prog_2044_map_rc_$$.json" +cat >"$prog_json_path" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Local","name":"m","expr":{"type":"New","class":"MapBox","args":[]}}, + {"type":"Expr","expr":{"type":"Method","recv":{"type":"Var","name":"m"},"method":"set","args":[{"type":"Str","value":"k"},{"type":"Int","value":7}]}}, + {"type":"Return","expr":{"type":"Method","recv":{"type":"Var","name":"m"},"method":"size","args":[]}} +]} +JSON + +set +e +HAKO_PREFER_MIRBUILDER=1 \ +NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ +NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ +NYASH_DISABLE_NY_COMPILER=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ +NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ +verify_program_via_builder_to_core "$prog_json_path" +rc=$? +set -e +rm -f "$prog_json_path" +if [ "$rc" -ne 1 ]; then + echo "[FAIL] provider map set/size RC → core rc=$rc (expected 1)" >&2 + exit 1 +fi + +echo "[PASS] phase2044/mirbuilder_provider_map_set_size_rc_core_exec_canary_vm" +exit 0 diff --git a/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_match_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_match_core_exec_canary_vm.sh new file mode 100644 index 00000000..65bdbcc6 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_match_core_exec_canary_vm.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +set -euo pipefail +# Purpose: Provider route with Match → Core rc=42 + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +prog_json_path="/tmp/prog_2044_match_$$.json" +cat >"$prog_json_path" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Return","expr":{"type":"Match","scrutinee":{"type":"Str","value":"A"}, + "arms":[{"label":"A","expr":{"type":"Int","value":42}}, {"label":"B","expr":{"type":"Int","value":0}}], + "else":{"type":"Int","value":1}}} +]} +JSON + +set +e +HAKO_PREFER_MIRBUILDER=1 \ +NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ +NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ +NYASH_DISABLE_NY_COMPILER=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ +NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ +verify_program_via_builder_to_core "$prog_json_path" +rc=$? +set -e +rm -f "$prog_json_path" +if [ "$rc" -ne 42 ]; then + echo "[FAIL] provider match → core rc=$rc (expected 42)" >&2 + exit 1 +fi + +echo "[PASS] phase2044/mirbuilder_provider_match_core_exec_canary_vm" +exit 0 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_match_in_else_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_match_in_else_core_exec_canary_vm.sh new file mode 100644 index 00000000..74d6a17e --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_match_in_else_core_exec_canary_vm.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +set -euo pipefail +# Purpose: Provider route: If false → else returns Match; rc=42 + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +prog_json_path="/tmp/prog_2044_match_in_else_$$.json" +cat >"$prog_json_path" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Local","name":"x","expr":{"type":"Str","value":"B"}}, + {"type":"If", + "cond":{"type":"Compare","op":"<","lhs":{"type":"Int","value":2},"rhs":{"type":"Int","value":1}}, + "then":[{"type":"Return","expr":{"type":"Int","value":0}}], + "else":[{"type":"Return","expr":{"type":"Match","scrutinee":{"type":"Var","name":"x"}, + "arms":[{"label":"A","expr":{"type":"Int","value":0}}, {"label":"B","expr":{"type":"Int","value":42}}], + "else":{"type":"Int","value":1}}}] + } +]} +JSON + +set +e +HAKO_PREFER_MIRBUILDER=1 \ +NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ +NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ +NYASH_DISABLE_NY_COMPILER=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ +NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ +verify_program_via_builder_to_core "$prog_json_path" +rc=$? +set -e +rm -f "$prog_json_path" +if [ "$rc" -ne 42 ]; then + echo "[FAIL] provider match-in-else → rc=$rc (expected 42)" >&2 + exit 1 +fi + +echo "[PASS] phase2044/mirbuilder_provider_match_in_else_core_exec_canary_vm" +exit 0 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_return_binop_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_return_binop_core_exec_canary_vm.sh new file mode 100644 index 00000000..ac8ba0eb --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_return_binop_core_exec_canary_vm.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -euo pipefail +# Purpose: Provider route (env.mirbuilder.emit) on Return(Binary) → Core rc=42 + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +prog_json_path="/tmp/prog_2044_binop_$$.json" +cat >"$prog_json_path" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Return","expr":{"type":"Binary","op":"+","lhs":{"type":"Int","value":6},"rhs":{"type":"Int","value":36}}} +]} +JSON + +set +e +HAKO_PREFER_MIRBUILDER=1 \ +NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ +NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ +NYASH_DISABLE_NY_COMPILER=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ +NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ +verify_program_via_builder_to_core "$prog_json_path" +rc=$? +set -e +rm -f "$prog_json_path" +if [ "$rc" -ne 42 ]; then + echo "[FAIL] provider binop → core rc=$rc (expected 42)" >&2 + exit 1 +fi + +echo "[PASS] phase2044/mirbuilder_provider_return_binop_core_exec_canary_vm" +exit 0 + diff --git a/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_ternary_core_exec_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_ternary_core_exec_canary_vm.sh new file mode 100644 index 00000000..b3defd46 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2044/mirbuilder_provider_ternary_core_exec_canary_vm.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -euo pipefail +# Purpose: Provider route with Ternary → Core rc=42 + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then ROOT="$ROOT_GIT"; else ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)"; fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh"; require_env || exit 2 + +prog_json_path="/tmp/prog_2044_ternary_$$.json" +cat >"$prog_json_path" <<'JSON' +{"version":0,"kind":"Program","body":[ + {"type":"Return","expr":{"type":"Ternary","cond":{"type":"Compare","op":"<","lhs":{"type":"Int","value":1},"rhs":{"type":"Int","value":2}},"then":{"type":"Int","value":42},"else":{"type":"Int","value":0}}} +]} +JSON + +set +e +HAKO_PREFER_MIRBUILDER=1 \ +NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ +NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 \ +NYASH_DISABLE_NY_COMPILER=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ +NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \ +verify_program_via_builder_to_core "$prog_json_path" +rc=$? +set -e +rm -f "$prog_json_path" +if [ "$rc" -ne 42 ]; then + echo "[FAIL] provider ternary → core rc=$rc (expected 42)" >&2 + exit 1 +fi + +echo "[PASS] phase2044/mirbuilder_provider_ternary_core_exec_canary_vm" +exit 0 +