phase-20.39 step3 (partial): concat-safety in vm helpers – add StrCast, refactor MiniMap, ValueManager, MiniArray/MiniMap2, mir_call_v1_handler, extern provider/call; keep behavior; canaries PASS
This commit is contained in:
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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) }
|
||||
}
|
||||
|
||||
@ -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) } }
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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" {
|
||||
|
||||
14
lang/src/vm/hakorune-vm/str_cast.hako
Normal file
14
lang/src/vm/hakorune-vm/str_cast.hako
Normal file
@ -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 } }
|
||||
|
||||
@ -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)
|
||||
|
||||
Reference in New Issue
Block a user