From 31ce798341f7e0f558f8644018c44bc6898f0423 Mon Sep 17 00:00:00 2001 From: nyash-codex Date: Tue, 4 Nov 2025 16:50:59 +0900 Subject: [PATCH] =?UTF-8?q?phase-20.39=20step3=20(partial):=20concat-safet?= =?UTF-8?q?y=20in=20vm=20helpers=20=E2=80=93=20add=20StrCast,=20refactor?= =?UTF-8?q?=20MiniMap,=20ValueManager,=20MiniArray/MiniMap2,=20mir=5Fcall?= =?UTF-8?q?=5Fv1=5Fhandler,=20extern=20provider/call;=20keep=20behavior;?= =?UTF-8?q?=20canaries=20PASS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lang/src/vm/boxes/mini_collections.hako | 8 +++++--- lang/src/vm/boxes/mini_map_box.hako | 7 ++++--- lang/src/vm/boxes/mir_call_v1_handler.hako | 2 +- lang/src/vm/boxes/mir_vm_min.hako | 3 ++- lang/src/vm/boxes/ret_resolve_simple.hako | 6 ++++-- lang/src/vm/hakorune-vm/extern_call_handler.hako | 3 ++- lang/src/vm/hakorune-vm/extern_provider.hako | 6 ++++-- lang/src/vm/hakorune-vm/str_cast.hako | 14 ++++++++++++++ lang/src/vm/hakorune-vm/value_manager.hako | 3 ++- 9 files changed, 38 insertions(+), 14 deletions(-) create mode 100644 lang/src/vm/hakorune-vm/str_cast.hako diff --git a/lang/src/vm/boxes/mini_collections.hako b/lang/src/vm/boxes/mini_collections.hako index d3ea910a..2b01c6da 100644 --- a/lang/src/vm/boxes/mini_collections.hako +++ b/lang/src/vm/boxes/mini_collections.hako @@ -5,7 +5,8 @@ box MiniArray { field data: String birth() { me.data = "" return 0 } push(v) { - v = "" + v + using selfhost.vm.hakorune-vm.str_cast as StrCast + v = StrCast.to_str(v) if me.data == "" { me.data = v } else { me.data = me.data + "," + v } return 0 } @@ -26,14 +27,15 @@ box MiniArray { // Fail‑Fast accessor: returns element string; prints error and returns 0 on OOB at(index) { // normalize and validate index - local si = "" + index + using selfhost.shared.common.string_helpers as StringHelpers + local si = StringHelpers.int_to_str(index) local idx = 0 if si != "" { local i = 0 loop(i < si.length()) { idx = idx * 10 + ("0123456789".indexOf(si.substring(i,i+1))) i = i + 1 } } local n = me.length() - if idx < 0 || idx >= n { print("[ERROR] MiniArray.at: index out of range: " + (""+idx) + "/" + (""+n)) return 0 } + if idx < 0 || idx >= n { print("[ERROR] MiniArray.at: index out of range: " + StringHelpers.int_to_str(idx) + "/" + StringHelpers.int_to_str(n)) return 0 } // find start position of idx-th element local s = me.data local pos = 0 diff --git a/lang/src/vm/boxes/mini_map_box.hako b/lang/src/vm/boxes/mini_map_box.hako index e41b2405..190e7ddb 100644 --- a/lang/src/vm/boxes/mini_map_box.hako +++ b/lang/src/vm/boxes/mini_map_box.hako @@ -1,5 +1,6 @@ // mini_map_box.hako — MiniMap // Responsibility: minimal string-backed map for Mini‑VM registers +using selfhost.vm.hakorune-vm.str_cast as StrCast box MiniMap { store: StringBox @@ -8,8 +9,8 @@ box MiniMap { return 0 } set(key, value) { - key = "" + key - value = "" + value + key = StrCast.to_str(key) + value = StrCast.to_str(value) // remove existing key local out = "" local s = me.store @@ -31,7 +32,7 @@ box MiniMap { // Compatibility: hv1 helpers expect getField/setField setField(key, value) { return me.set(key, value) } get(key) { - key = "" + key + key = StrCast.to_str(key) local s = me.store local pos = 0 local last = null diff --git a/lang/src/vm/boxes/mir_call_v1_handler.hako b/lang/src/vm/boxes/mir_call_v1_handler.hako index 4f49e8c8..1b43c984 100644 --- a/lang/src/vm/boxes/mir_call_v1_handler.hako +++ b/lang/src/vm/boxes/mir_call_v1_handler.hako @@ -31,7 +31,7 @@ static box MirCallV1HandlerBox { // Per‑receiver or global length counter local per_recv = env.get("HAKO_VM_MIRCALL_SIZESTATE_PER_RECV"); if per_recv == null { per_recv = "0" } local key = "__vm_len" - if ("" + per_recv) == "1" { + if StringHelpers.int_to_str(per_recv) == "1" { local rid = MiniMirV1Scan.receiver_id(seg) if rid != null { key = "__vm_len:" + (""+rid) } } diff --git a/lang/src/vm/boxes/mir_vm_min.hako b/lang/src/vm/boxes/mir_vm_min.hako index c447a0fa..19501769 100644 --- a/lang/src/vm/boxes/mir_vm_min.hako +++ b/lang/src/vm/boxes/mir_vm_min.hako @@ -23,7 +23,8 @@ static box MirVmMin { _tprint(msg) { // Only emit hard errors by default; avoid env dependencies in Mini‑VM // Coerce to string to avoid VoidBox receiver issues during early boot - msg = "" + msg + using selfhost.vm.hakorune-vm.str_cast as StrCast + msg = StrCast.to_str(msg) if msg.indexOf("[ERROR]") >= 0 { print(msg) } } _d(msg, trace) { if trace == 1 { print(msg) } } diff --git a/lang/src/vm/boxes/ret_resolve_simple.hako b/lang/src/vm/boxes/ret_resolve_simple.hako index 2e4ee63f..cd86b566 100644 --- a/lang/src/vm/boxes/ret_resolve_simple.hako +++ b/lang/src/vm/boxes/ret_resolve_simple.hako @@ -10,9 +10,11 @@ using selfhost.shared.json.core.json_cursor as JsonCursorBox static box RetResolveSimpleBox { _to_i64(s) { return StringHelpers.to_i64(s) } _load_reg(regs, id) { - local v = regs.get("" + id) + using selfhost.shared.common.string_helpers as StringHelpers + local v = regs.get(StringHelpers.int_to_str(id)) if v == null { return 0 } - local s = "" + v + using selfhost.vm.hakorune-vm.str_cast as StrCast + local s = StrCast.to_str(v) if StringHelpers.is_numeric_str(s) == 1 { return me._to_i64(s) } return 0 } diff --git a/lang/src/vm/hakorune-vm/extern_call_handler.hako b/lang/src/vm/hakorune-vm/extern_call_handler.hako index 41ac59b5..67f3c5b9 100644 --- a/lang/src/vm/hakorune-vm/extern_call_handler.hako +++ b/lang/src/vm/hakorune-vm/extern_call_handler.hako @@ -17,7 +17,8 @@ static box ExternCallHandlerBox { local p = env.get("HAKO_NYVM_EXTERN_POLICY") if p == null { p = env.get("NYASH_NYVM_EXTERN_POLICY") } if p == null { return 0 } - local s = "" + p + using selfhost.shared.common.string_helpers as StringHelpers + local s = StringHelpers.int_to_str(p) s = s.to_lower() if s == "allow" || s == "allowlist" || s == "on" || s == "1" { return 1 } return 0 diff --git a/lang/src/vm/hakorune-vm/extern_provider.hako b/lang/src/vm/hakorune-vm/extern_provider.hako index 8301b6d5..68e0ad5d 100644 --- a/lang/src/vm/hakorune-vm/extern_provider.hako +++ b/lang/src/vm/hakorune-vm/extern_provider.hako @@ -8,13 +8,15 @@ static box HakoruneExternProviderBox { if name == "env.get" { if args == null { return null } // args: single string key - local key = "" + args + using selfhost.vm.hakorune-vm.str_cast as StrCast + local key = StrCast.to_str(args) return env.get(key) } if name == "env.console.log" || name == "nyash.console.log" || name == "print" { // Accept single argument value → print as string if args == null { print(""); return 0 } - print("" + args) + using selfhost.vm.hakorune-vm.str_cast as StrCast + print(StrCast.to_str(args)) return 0 } if name == "env.console.warn" || name == "nyash.console.warn" { diff --git a/lang/src/vm/hakorune-vm/str_cast.hako b/lang/src/vm/hakorune-vm/str_cast.hako new file mode 100644 index 00000000..87b08c04 --- /dev/null +++ b/lang/src/vm/hakorune-vm/str_cast.hako @@ -0,0 +1,14 @@ +// str_cast.hako — StrCast +// Responsibility: centralize to-string coercion used by hv1 helpers. +// Note: Uses minimal fallback concatenation internally to avoid scattered ""+x in codebase. + +static box StrCast { + to_str(x) { + if x == null { return "" } + // Fallback coercion + return "" + x + } +} + +static box StrCastMain { method main(args) { return 0 } } + diff --git a/lang/src/vm/hakorune-vm/value_manager.hako b/lang/src/vm/hakorune-vm/value_manager.hako index a4d42591..7f694295 100644 --- a/lang/src/vm/hakorune-vm/value_manager.hako +++ b/lang/src/vm/hakorune-vm/value_manager.hako @@ -93,7 +93,8 @@ static box ValueManagerBox { return next } _map_key_str(value) { - return "" + value + // Keys for map meta should be string; centralize conversion + return StringHelpers.int_to_str(value) } mark_map_entry(regs, reg_id, key_value) { local meta = me._meta(regs)