P0-1: Map bad-key tags for get/set/delete + smokes; String substring clamp smoke; P0-2: Bridge no‑op(Method) + Gate‑C invalid header smokes; P1: v1 bridge Closure captures appended to argv
This commit is contained in:
@ -111,4 +111,8 @@ static box MinMirEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static box MinMirEmitterMain { main(args){ return 0 } }
|
using "lang/src/shared/common/entry_point_base.hako" as EntryPointBaseBox
|
||||||
|
|
||||||
|
static box MinMirEmitterMain {
|
||||||
|
main(args) { return EntryPointBaseBox.main(args) }
|
||||||
|
}
|
||||||
|
|||||||
18
lang/src/shared/common/common_imports.hako
Normal file
18
lang/src/shared/common/common_imports.hako
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// CommonImportsBox - Unified import utilities for string operations
|
||||||
|
// Consolidates frequently used StringHelpers and StringOps imports
|
||||||
|
|
||||||
|
using "lang/src/shared/common/string_helpers.hako" as StringHelpers
|
||||||
|
using selfhost.shared.common.string_ops as StringOps
|
||||||
|
|
||||||
|
static box CommonImportsBox {
|
||||||
|
// Provides access to common string utilities
|
||||||
|
// Boxes can import this instead of individual modules
|
||||||
|
static helpers() { return StringHelpers }
|
||||||
|
static ops() { return StringOps }
|
||||||
|
|
||||||
|
// Commonly used string operations
|
||||||
|
static read_digits(text, pos) { return StringHelpers.read_digits(text, pos) }
|
||||||
|
static to_i64(digits) { return StringHelpers.to_i64(digits) }
|
||||||
|
static index_of_from(text, pattern, start) { return StringOps.index_of_from(text, pattern, start) }
|
||||||
|
static substring(text, start, end) { return StringOps.substring(text, start, end) }
|
||||||
|
}
|
||||||
18
lang/src/shared/common/entry_point_base.hako
Normal file
18
lang/src/shared/common/entry_point_base.hako
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// EntryPointBaseBox - Common entry point for standalone boxes
|
||||||
|
// Eliminates repetitive main(args){ return 0 } boilerplate
|
||||||
|
|
||||||
|
static box EntryPointBaseBox {
|
||||||
|
// Standard entry point implementation
|
||||||
|
// Can be overridden by specific boxes if needed
|
||||||
|
static main(args) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entry point with validation
|
||||||
|
static safe_main(args) {
|
||||||
|
if args == null {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return EntryPointBaseBox.main(args)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -16,7 +16,7 @@ using "lang/src/vm/hakorune-vm/blocks_locator.hako" as BlocksLocatorBox
|
|||||||
using "lang/src/vm/hakorune-vm/instrs_locator.hako" as InstrsLocatorBox
|
using "lang/src/vm/hakorune-vm/instrs_locator.hako" as InstrsLocatorBox
|
||||||
using "lang/src/vm/hakorune-vm/backward_object_scanner.hako" as BackwardObjectScannerBox
|
using "lang/src/vm/hakorune-vm/backward_object_scanner.hako" as BackwardObjectScannerBox
|
||||||
using "lang/src/vm/hakorune-vm/block_iterator.hako" as BlockIteratorBox
|
using "lang/src/vm/hakorune-vm/block_iterator.hako" as BlockIteratorBox
|
||||||
using selfhost.shared.common.string_helpers as StringHelpers
|
using "lang/src/shared/common/common_imports.hako" as CommonImports
|
||||||
using selfhost.shared.common.box_helpers as BoxHelpers
|
using selfhost.shared.common.box_helpers as BoxHelpers
|
||||||
|
|
||||||
static box MirIoBox {
|
static box MirIoBox {
|
||||||
@ -144,7 +144,7 @@ static box MirIoBox {
|
|||||||
p = p + key_id.length()
|
p = p + key_id.length()
|
||||||
// skip ws
|
// skip ws
|
||||||
loop(p < obj.length()) { local ch = obj.substring(p,p+1) if ch == " " || ch == "\n" || ch == "\r" || ch == "\t" { p = p + 1 continue } break }
|
loop(p < obj.length()) { local ch = obj.substring(p,p+1) if ch == " " || ch == "\n" || ch == "\r" || ch == "\t" { p = p + 1 continue } break }
|
||||||
local digs = StringHelpers.read_digits(obj, p)
|
local digs = CommonImports.read_digits(obj, p)
|
||||||
if digs == "" { return Result.Err("invalid block id") }
|
if digs == "" { return Result.Err("invalid block id") }
|
||||||
ids.set(StringHelpers.int_to_str(StringHelpers.to_i64(digs)), 1)
|
ids.set(StringHelpers.int_to_str(StringHelpers.to_i64(digs)), 1)
|
||||||
// require terminator
|
// require terminator
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
using "lang/src/vm/boxes/result_box.hako" as Result
|
using "lang/src/vm/boxes/result_box.hako" as Result
|
||||||
using "lang/src/vm/hakorune-vm/json_field_extractor.hako" as JsonFieldExtractor
|
using "lang/src/vm/hakorune-vm/json_field_extractor.hako" as JsonFieldExtractor
|
||||||
|
using "lang/src/vm/hakorune-vm/inst_field_extractor.hako" as InstFieldExtractor
|
||||||
using "lang/src/vm/hakorune-vm/value_manager.hako" as ValueManagerBox
|
using "lang/src/vm/hakorune-vm/value_manager.hako" as ValueManagerBox
|
||||||
using "lang/src/vm/hakorune-vm/args_extractor.hako" as ArgsExtractorBox
|
using "lang/src/vm/hakorune-vm/args_extractor.hako" as ArgsExtractorBox
|
||||||
using "lang/src/shared/common/string_helpers.hako" as StringHelpers
|
using "lang/src/shared/common/string_helpers.hako" as StringHelpers
|
||||||
@ -36,8 +37,8 @@ static box CoreBridgeOps {
|
|||||||
local st = NyVmState.birth()
|
local st = NyVmState.birth()
|
||||||
local rc = NyVmOpConst.handle(inst_json, st)
|
local rc = NyVmOpConst.handle(inst_json, st)
|
||||||
if rc < 0 { return Result.Err("const: core failure") }
|
if rc < 0 { return Result.Err("const: core failure") }
|
||||||
// Reflect dst into hakorune-vm regs
|
// Reflect dst into hakorune-vm regs using unified extractor
|
||||||
local dst = JsonFieldExtractor.extract_int(inst_json, "dst")
|
local dst = InstFieldExtractor.extract_dst(inst_json)
|
||||||
if dst == null { return Result.Err("const: dst not found") }
|
if dst == null { return Result.Err("const: dst not found") }
|
||||||
local v = NyVmState.get_reg(st, dst)
|
local v = NyVmState.get_reg(st, dst)
|
||||||
ValueManagerBox.set(regs, dst, v)
|
ValueManagerBox.set(regs, dst, v)
|
||||||
@ -46,40 +47,30 @@ static box CoreBridgeOps {
|
|||||||
|
|
||||||
// Apply binop via Core
|
// Apply binop via Core
|
||||||
apply_binop(inst_json, regs) {
|
apply_binop(inst_json, regs) {
|
||||||
// Extract required fields
|
// Extract required fields using unified extractor
|
||||||
local dst = JsonFieldExtractor.extract_int(inst_json, "dst")
|
local dst = InstFieldExtractor.extract_dst(inst_json)
|
||||||
if dst == null { return Result.Err("binop: dst field not found") }
|
if dst == null { return Result.Err("binop: dst field not found") }
|
||||||
local lhs = JsonFieldExtractor.extract_int(inst_json, "lhs")
|
local binary_ops = InstFieldExtractor.extract_binary_ops(inst_json)
|
||||||
if lhs == null { return Result.Err("binop: lhs field not found") }
|
if binary_ops.lhs == null { return Result.Err("binop: lhs field not found") }
|
||||||
local rhs = JsonFieldExtractor.extract_int(inst_json, "rhs")
|
if binary_ops.rhs == null { return Result.Err("binop: rhs field not found") }
|
||||||
if rhs == null { return Result.Err("binop: rhs field not found") }
|
|
||||||
|
|
||||||
// Normalize operation: prefer symbolic 'operation', else map from 'op_kind'
|
// Use unified binary ops extractor (includes operation normalization)
|
||||||
local op = JsonFieldExtractor.extract_string(inst_json, "operation")
|
local op = binary_ops.operation
|
||||||
if op == null {
|
if op == null { return Result.Err("binop: operation/op_kind not found") }
|
||||||
local kind = JsonFieldExtractor.extract_string(inst_json, "op_kind")
|
|
||||||
if kind == null { return Result.Err("binop: operation/op_kind not found") }
|
|
||||||
if kind == "Add" { op = "+" }
|
|
||||||
else if kind == "Sub" { op = "-" }
|
|
||||||
else if kind == "Mul" { op = "*" }
|
|
||||||
else if kind == "Div" { op = "/" }
|
|
||||||
else if kind == "Mod" { op = "%" }
|
|
||||||
else { return Result.Err("binop: unsupported op_kind: " + kind) }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Guard: required src regs must be set
|
// Guard: required src regs must be set
|
||||||
local lhs_val = ValueManagerBox.get(regs, lhs)
|
local lhs_val = ValueManagerBox.get(regs, binary_ops.lhs)
|
||||||
if lhs_val == null { return Result.Err("binop: lhs v%" + lhs + " is unset") }
|
if lhs_val == null { return Result.Err("binop: lhs v%" + binary_ops.lhs + " is unset") }
|
||||||
local rhs_val = ValueManagerBox.get(regs, rhs)
|
local rhs_val = ValueManagerBox.get(regs, binary_ops.rhs)
|
||||||
if rhs_val == null { return Result.Err("binop: rhs v%" + rhs + " is unset") }
|
if rhs_val == null { return Result.Err("binop: rhs v%" + binary_ops.rhs + " is unset") }
|
||||||
|
|
||||||
// Rebuild minimal JSON acceptable to Core
|
// Rebuild minimal JSON acceptable to Core
|
||||||
local j = "{\"op\":\"binop\",\"dst\":" + dst + ",\"operation\":\"" + op + "\",\"lhs\":" + lhs + ",\"rhs\":" + rhs + "}"
|
local j = "{\"op\":\"binop\",\"dst\":" + dst + ",\"operation\":\"" + op + "\",\"lhs\":" + binary_ops.lhs + ",\"rhs\":" + binary_ops.rhs + "}"
|
||||||
|
|
||||||
// Execute via Core with a temporary state containing sources
|
// Execute via Core with a temporary state containing sources
|
||||||
local st = NyVmState.birth()
|
local st = NyVmState.birth()
|
||||||
NyVmState.set_reg(st, lhs, lhs_val)
|
NyVmState.set_reg(st, binary_ops.lhs, lhs_val)
|
||||||
NyVmState.set_reg(st, rhs, rhs_val)
|
NyVmState.set_reg(st, binary_ops.rhs, rhs_val)
|
||||||
local rc = NyVmOpBinOp.handle(j, st)
|
local rc = NyVmOpBinOp.handle(j, st)
|
||||||
if rc < 0 { return Result.Err("binop: core failure") }
|
if rc < 0 { return Result.Err("binop: core failure") }
|
||||||
local out = NyVmState.get_reg(st, dst)
|
local out = NyVmState.get_reg(st, dst)
|
||||||
@ -101,35 +92,24 @@ static box CoreBridgeOps {
|
|||||||
|
|
||||||
// Apply compare via Core
|
// Apply compare via Core
|
||||||
apply_compare(inst_json, regs) {
|
apply_compare(inst_json, regs) {
|
||||||
local dst = JsonFieldExtractor.extract_int(inst_json, "dst")
|
local dst = InstFieldExtractor.extract_dst(inst_json)
|
||||||
if dst == null { return Result.Err("compare: dst field not found") }
|
if dst == null { return Result.Err("compare: dst field not found") }
|
||||||
local lhs = JsonFieldExtractor.extract_int(inst_json, "lhs")
|
local compare_ops = InstFieldExtractor.extract_compare_ops(inst_json)
|
||||||
if lhs == null { return Result.Err("compare: lhs field not found") }
|
if compare_ops.lhs == null { return Result.Err("compare: lhs field not found") }
|
||||||
local rhs = JsonFieldExtractor.extract_int(inst_json, "rhs")
|
if compare_ops.rhs == null { return Result.Err("compare: rhs field not found") }
|
||||||
if rhs == null { return Result.Err("compare: rhs field not found") }
|
// Use unified compare ops extractor (includes operation normalization)
|
||||||
// Normalize kind -> operation
|
local op = compare_ops.operation
|
||||||
local op = JsonFieldExtractor.extract_string(inst_json, "operation")
|
if op == null { return Result.Err("compare: kind/operation not found") }
|
||||||
if op == null {
|
|
||||||
local kind = JsonFieldExtractor.extract_string(inst_json, "kind")
|
|
||||||
if kind == null { return Result.Err("compare: kind/operation not found") }
|
|
||||||
if kind == "Eq" { op = "==" }
|
|
||||||
else if kind == "Ne" { op = "!=" }
|
|
||||||
else if kind == "Lt" { op = "<" }
|
|
||||||
else if kind == "Le" { op = "<=" }
|
|
||||||
else if kind == "Gt" { op = ">" }
|
|
||||||
else if kind == "Ge" { op = ">=" }
|
|
||||||
else { return Result.Err("compare: unsupported kind: " + kind) }
|
|
||||||
}
|
|
||||||
// Guards
|
// Guards
|
||||||
local lv = ValueManagerBox.get(regs, lhs)
|
local lv = ValueManagerBox.get(regs, compare_ops.lhs)
|
||||||
if lv == null { return Result.Err("compare: lhs v%" + lhs + " is unset") }
|
if lv == null { return Result.Err("compare: lhs v%" + compare_ops.lhs + " is unset") }
|
||||||
local rv = ValueManagerBox.get(regs, rhs)
|
local rv = ValueManagerBox.get(regs, compare_ops.rhs)
|
||||||
if rv == null { return Result.Err("compare: rhs v%" + rhs + " is unset") }
|
if rv == null { return Result.Err("compare: rhs v%" + compare_ops.rhs + " is unset") }
|
||||||
// Build minimal JSON
|
// Build minimal JSON
|
||||||
local j = "{\"op\":\"compare\",\"dst\":" + dst + ",\"operation\":\"" + op + "\",\"lhs\":" + lhs + ",\"rhs\":" + rhs + "}"
|
local j = "{\"op\":\"compare\",\"dst\":" + dst + ",\"operation\":\"" + op + "\",\"lhs\":" + compare_ops.lhs + ",\"rhs\":" + compare_ops.rhs + "}"
|
||||||
local st = NyVmState.birth()
|
local st = NyVmState.birth()
|
||||||
NyVmState.set_reg(st, lhs, lv)
|
NyVmState.set_reg(st, compare_ops.lhs, lv)
|
||||||
NyVmState.set_reg(st, rhs, rv)
|
NyVmState.set_reg(st, compare_ops.rhs, rv)
|
||||||
local rc = NyVmOpCompare.handle(j, st)
|
local rc = NyVmOpCompare.handle(j, st)
|
||||||
if rc < 0 { return Result.Err("compare: core failure") }
|
if rc < 0 { return Result.Err("compare: core failure") }
|
||||||
ValueManagerBox.set(regs, dst, NyVmState.get_reg(st, dst))
|
ValueManagerBox.set(regs, dst, NyVmState.get_reg(st, dst))
|
||||||
|
|||||||
@ -23,12 +23,24 @@ static box InstFieldExtractorBox {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract comparison fields (lhs, rhs, kind)
|
// Extract comparison fields (lhs, rhs, kind) and normalize to operation
|
||||||
static extract_compare_ops(inst_json) {
|
static extract_compare_ops(inst_json) {
|
||||||
local result = {}
|
local result = {}
|
||||||
result.lhs = JsonFieldExtractor.extract_int(inst_json, "lhs")
|
result.lhs = JsonFieldExtractor.extract_int(inst_json, "lhs")
|
||||||
result.rhs = JsonFieldExtractor.extract_int(inst_json, "rhs")
|
result.rhs = JsonFieldExtractor.extract_int(inst_json, "rhs")
|
||||||
result.kind = JsonFieldExtractor.extract_string(inst_json, "kind")
|
result.kind = JsonFieldExtractor.extract_string(inst_json, "kind")
|
||||||
|
|
||||||
|
// Normalize kind -> operation
|
||||||
|
local op = JsonFieldExtractor.extract_string(inst_json, "operation")
|
||||||
|
if op == null && result.kind != null {
|
||||||
|
if result.kind == "Eq" { op = "==" }
|
||||||
|
else if result.kind == "Ne" { op = "!=" }
|
||||||
|
else if result.kind == "Lt" { op = "<" }
|
||||||
|
else if result.kind == "Le" { op = "<=" }
|
||||||
|
else if result.kind == "Gt" { op = ">" }
|
||||||
|
else if result.kind == "Ge" { op = ">=" }
|
||||||
|
}
|
||||||
|
result.operation = op
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -64,7 +64,12 @@ pub(super) fn try_handle_map_box(
|
|||||||
}
|
}
|
||||||
"set" => {
|
"set" => {
|
||||||
if args.len() != 2 { return Err(VMError::InvalidInstruction("MapBox.set expects 2 args".into())); }
|
if args.len() != 2 { return Err(VMError::InvalidInstruction("MapBox.set expects 2 args".into())); }
|
||||||
let k = this.reg_load(args[0])?.to_nyash_box();
|
let k_vm = this.reg_load(args[0])?;
|
||||||
|
if !matches!(k_vm, VMValue::String(_)) {
|
||||||
|
if let Some(d) = dst { this.regs.insert(d, VMValue::String("[map/bad-key] key must be string".to_string())); }
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
let k = k_vm.to_nyash_box();
|
||||||
let v = this.reg_load(args[1])?.to_nyash_box();
|
let v = this.reg_load(args[1])?.to_nyash_box();
|
||||||
let ret = mb.set(k, v);
|
let ret = mb.set(k, v);
|
||||||
if let Some(d) = dst { this.regs.insert(d, VMValue::from_nyash_box(ret)); }
|
if let Some(d) = dst { this.regs.insert(d, VMValue::from_nyash_box(ret)); }
|
||||||
@ -72,7 +77,12 @@ pub(super) fn try_handle_map_box(
|
|||||||
}
|
}
|
||||||
"get" => {
|
"get" => {
|
||||||
if args.len() != 1 { return Err(VMError::InvalidInstruction("MapBox.get expects 1 arg".into())); }
|
if args.len() != 1 { return Err(VMError::InvalidInstruction("MapBox.get expects 1 arg".into())); }
|
||||||
let k = this.reg_load(args[0])?.to_nyash_box();
|
let k_vm = this.reg_load(args[0])?;
|
||||||
|
if !matches!(k_vm, VMValue::String(_)) {
|
||||||
|
if let Some(d) = dst { this.regs.insert(d, VMValue::String("[map/bad-key] key must be string".to_string())); }
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
let k = k_vm.to_nyash_box();
|
||||||
let ret = mb.get(k);
|
let ret = mb.get(k);
|
||||||
if let Some(d) = dst { this.regs.insert(d, VMValue::from_nyash_box(ret)); }
|
if let Some(d) = dst { this.regs.insert(d, VMValue::from_nyash_box(ret)); }
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
@ -86,7 +96,12 @@ pub(super) fn try_handle_map_box(
|
|||||||
}
|
}
|
||||||
"delete" => {
|
"delete" => {
|
||||||
if args.len() != 1 { return Err(VMError::InvalidInstruction("MapBox.delete expects 1 arg".into())); }
|
if args.len() != 1 { return Err(VMError::InvalidInstruction("MapBox.delete expects 1 arg".into())); }
|
||||||
let k = this.reg_load(args[0])?.to_nyash_box();
|
let k_vm = this.reg_load(args[0])?;
|
||||||
|
if !matches!(k_vm, VMValue::String(_)) {
|
||||||
|
if let Some(d) = dst { this.regs.insert(d, VMValue::String("[map/bad-key] key must be string".to_string())); }
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
let k = k_vm.to_nyash_box();
|
||||||
let ret = mb.delete(k);
|
let ret = mb.delete(k);
|
||||||
if let Some(d) = dst { this.regs.insert(d, VMValue::from_nyash_box(ret)); }
|
if let Some(d) = dst { this.regs.insert(d, VMValue::from_nyash_box(ret)); }
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
|
|||||||
@ -467,6 +467,16 @@ pub fn try_parse_v1_to_module(json: &str) -> Result<Option<MirModule>, String> {
|
|||||||
"mir_call callee Closure missing func in function '{}'",
|
"mir_call callee Closure missing func in function '{}'",
|
||||||
func_name
|
func_name
|
||||||
))? as u32;
|
))? as u32;
|
||||||
|
// If captures exist, append them to argv (best-effort minimal semantics)
|
||||||
|
if let Some(caps) = callee_obj.get("captures").and_then(Value::as_array) {
|
||||||
|
for c in caps {
|
||||||
|
let id = c.as_u64().ok_or_else(|| format!(
|
||||||
|
"mir_call Closure capture must be integer in function '{}'",
|
||||||
|
func_name
|
||||||
|
))? as u32;
|
||||||
|
argv.push(ValueId::new(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
// Captures (if any) are currently ignored at this stage; captured values are
|
// Captures (if any) are currently ignored at this stage; captured values are
|
||||||
// expected to be materialized as arguments or handled by earlier lowering.
|
// expected to be materialized as arguments or handled by earlier lowering.
|
||||||
block_ref.add_instruction(MirInstruction::Call {
|
block_ref.add_instruction(MirInstruction::Call {
|
||||||
|
|||||||
@ -0,0 +1,35 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# canonicalize_noop_method_on_vm.sh — ONでもMethodは変異しない(dump-mut未生成)
|
||||||
|
|
||||||
|
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_path="/tmp/ny_v1_noop_method_$$.json"
|
||||||
|
mut_on="/tmp/ny_v1_noop_method_on_$$.json"
|
||||||
|
|
||||||
|
cat >"$json_path" <<'JSON'
|
||||||
|
{"schema_version":"1.0","functions":[{"name":"main","blocks":[{"id":0,"instructions":[{"op":"mir_call","mir_call":{"callee":{"type":"Method","box_name":"ArrayBox","method":"size","receiver":1},"args":[] }},{"op":"ret"}]}]}]}
|
||||||
|
JSON
|
||||||
|
|
||||||
|
set +e
|
||||||
|
HAKO_NYVM_V1_DOWNCONVERT=1 HAKO_BRIDGE_INJECT_SINGLETON=1 HAKO_DEBUG_NYVM_BRIDGE_DUMP_MUT="$mut_on" \
|
||||||
|
"$ROOT/target/release/nyash" --json-file "$json_path" >/dev/null 2>&1
|
||||||
|
set -e || true
|
||||||
|
|
||||||
|
if [ -f "$mut_on" ]; then
|
||||||
|
echo "[FAIL] canonicalize_noop_method_on_vm: mutated dump should not be created for Method" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[PASS] canonicalize_noop_method_on_vm"
|
||||||
|
rm -f "$json_path" "$mut_on"
|
||||||
|
exit 0
|
||||||
|
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# gate_c_invalid_header_vm.sh — Gate‑C(Core) invalid JSON header → 非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
|
||||||
|
|
||||||
|
bad="/tmp/gatec_bad_$$.json"
|
||||||
|
echo '{"bad":1}' > "$bad"
|
||||||
|
set +e
|
||||||
|
NYASH_GATE_C_CORE=1 "$NYASH_BIN" --nyvm-json-file "$bad" >/dev/null 2>&1
|
||||||
|
rc=$?
|
||||||
|
set -e
|
||||||
|
rm -f "$bad"
|
||||||
|
if [ $rc -ne 0 ]; then
|
||||||
|
echo "[PASS] gate_c_invalid_header_vm"
|
||||||
|
else
|
||||||
|
echo "[FAIL] gate_c_invalid_header_vm (rc=$rc)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# map_bad_key_delete_vm.sh — Map.delete with non-string key returns [map/bad-key]
|
||||||
|
|
||||||
|
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='static box Main { main() { local m=new MapBox(); print(m.delete(123)); return 0 } }'
|
||||||
|
out=$(run_nyash_vm -c "$code")
|
||||||
|
if echo "$out" | grep -q "\[map/bad-key\]"; then
|
||||||
|
echo "[PASS] map_bad_key_delete_vm"
|
||||||
|
else
|
||||||
|
echo "[FAIL] map_bad_key_delete_vm" >&2; echo "$out" >&2; exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# map_bad_key_get_vm.sh — Map.get with non-string key returns [map/bad-key]
|
||||||
|
|
||||||
|
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='static box Main { main() { local m=new MapBox(); print(m.get(123)); return 0 } }'
|
||||||
|
out=$(run_nyash_vm -c "$code")
|
||||||
|
if echo "$out" | grep -q "\[map/bad-key\]"; then
|
||||||
|
echo "[PASS] map_bad_key_get_vm"
|
||||||
|
else
|
||||||
|
echo "[FAIL] map_bad_key_get_vm" >&2; echo "$out" >&2; exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# map_bad_key_set_vm.sh — Map.set with non-string key returns [map/bad-key]
|
||||||
|
|
||||||
|
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='static box Main { main() { local m=new MapBox(); print(m.set(123, 1)); return 0 } }'
|
||||||
|
out=$(run_nyash_vm -c "$code")
|
||||||
|
if echo "$out" | grep -q "\[map/bad-key\]"; then
|
||||||
|
echo "[PASS] map_bad_key_set_vm"
|
||||||
|
else
|
||||||
|
echo "[FAIL] map_bad_key_set_vm" >&2; echo "$out" >&2; exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# substring_clamp_vm.sh — String.substring clamps to [0,size] and start<=end
|
||||||
|
|
||||||
|
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='static box Main { main() {
|
||||||
|
local s="abcd";
|
||||||
|
print(s.substring(-5, 2));
|
||||||
|
print(s.substring(2, 99));
|
||||||
|
print(s.substring(3, 1));
|
||||||
|
return 0
|
||||||
|
} }'
|
||||||
|
out=$(run_nyash_vm -c "$code")
|
||||||
|
expected=$(cat <<EOT
|
||||||
|
ab
|
||||||
|
cd
|
||||||
|
|
||||||
|
EOT
|
||||||
|
)
|
||||||
|
if [ "$out" = "$expected" ]; then
|
||||||
|
echo "[PASS] substring_clamp_vm"
|
||||||
|
else
|
||||||
|
echo "[FAIL] substring_clamp_vm" >&2; printf '--- expected ---\n%s--- got ---\n%s\n' "$expected" "$out" >&2; exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
Reference in New Issue
Block a user