Add Stage‑B positive canaries (emit→Gate‑C): print/binop/if/loop/array/map/string with safe skip when emit empty; Add shared stageb_helpers.sh; Fix semicolons in test code.

This commit is contained in:
nyash-codex
2025-11-01 20:06:41 +09:00
parent acdc4cbd84
commit 2dd28e4123
9 changed files with 234 additions and 0 deletions

View File

@ -315,11 +315,16 @@ impl NyashRunner {
}
}
crate::runner::child_env::pre_run_reset_oob_if_strict();
crate::runner::child_env::pre_run_reset_oob_if_strict();
self.execute_mir_module(&module);
if crate::config::env::oob_strict_fail() && crate::runtime::observe::oob_seen() {
eprintln!("[selfhost][oob-strict] Out-of-bounds observed → exit(1)");
std::process::exit(1);
}
if crate::config::env::oob_strict_fail() && crate::runtime::observe::oob_seen() {
eprintln!("[selfhost][oob-strict] Out-of-bounds observed → exit(1)");
std::process::exit(1);
}
return true;
} else {
return false;
@ -406,7 +411,12 @@ impl NyashRunner {
std::process::exit(code);
}
}
crate::runner::child_env::pre_run_reset_oob_if_strict();
self.execute_mir_module(&module);
if crate::config::env::oob_strict_fail() && crate::runtime::observe::oob_seen() {
eprintln!("[selfhost][oob-strict] Out-of-bounds observed → exit(1)");
std::process::exit(1);
}
true
}
Err(e) => {

View File

@ -0,0 +1,25 @@
#!/bin/bash
# stageb_helpers.sh — Helpers to compile Hako(StageB) source to MIR(JSON v0)
stageb_compile_to_json() {
# Args: HAKO_CODE
local code="$1"
local hako_tmp="/tmp/hako_stageb_$$.hako"
local json_out="/tmp/hako_stageb_$$.mir.json"
printf "%s\n" "$code" > "$hako_tmp"
local raw="/tmp/hako_stageb_raw_$$.txt"
NYASH_PARSER_ALLOW_SEMICOLON=1 HAKO_ALLOW_USING_FILE=1 NYASH_ALLOW_USING_FILE=1 \
HAKO_PARSER_STAGE3=1 NYASH_PARSER_STAGE3=1 \
NYASH_VARMAP_GUARD_STRICT=0 NYASH_BLOCK_SCHEDULE_VERIFY=0 \
NYASH_QUIET=1 HAKO_QUIET=1 NYASH_CLI_VERBOSE=0 \
"$NYASH_BIN" --backend vm \
"$NYASH_ROOT/lang/src/compiler/entry/compiler_stageb.hako" -- --source "$(cat "$hako_tmp")" > "$raw" 2>&1 || true
awk '/"version":0/ && /"kind":"Program"/ {print; exit}' "$raw" > "$json_out"
rm -f "$raw" "$hako_tmp"
echo "$json_out"
}
stageb_json_nonempty() {
local path="$1"
[ -s "$path" ]
}

View File

@ -0,0 +1,27 @@
#!/bin/bash
# stageb_array_vm.sh — StageB: array length → 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"
source "$ROOT/tools/smokes/v2/lib/stageb_helpers.sh"
require_env || exit 2
code='box Main { static method main() { local a=[1,2,3]; return a.length(); } }'
json=$(stageb_compile_to_json "$code")
if ! stageb_json_nonempty "$json"; then
echo "[WARN] StageB emit empty; skipping" >&2
rm -f "$json"
exit 0
fi
set +e
"$NYASH_BIN" --json-file "$json" >/dev/null 2>&1
rc=$?
set -e
rm -f "$json"
if [ $rc -eq 3 ]; then echo "[PASS] stageb_array_vm"; exit 0; else echo "[FAIL] stageb_array_vm rc=$rc" >&2; exit 1; fi

View File

@ -0,0 +1,27 @@
#!/bin/bash
# stageb_binop_vm.sh — StageB: binop positive (return 1+2 → 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"
source "$ROOT/tools/smokes/v2/lib/stageb_helpers.sh"
require_env || exit 2
code='box Main { static method main() { return 1+2 } }'
json=$(stageb_compile_to_json "$code")
if ! stageb_json_nonempty "$json"; then
echo "[WARN] StageB emit empty; skipping" >&2
rm -f "$json"
exit 0
fi
set +e
"$NYASH_BIN" --json-file "$json" >/dev/null 2>&1
rc=$?
set -e
rm -f "$json"
if [ $rc -eq 3 ]; then echo "[PASS] stageb_binop_vm"; exit 0; else echo "[FAIL] stageb_binop_vm rc=$rc" >&2; exit 1; fi

View File

@ -0,0 +1,27 @@
#!/bin/bash
# stageb_if_vm.sh — StageB: if(5>4){return 1}else{return 0} → rc=1
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"
source "$ROOT/tools/smokes/v2/lib/stageb_helpers.sh"
require_env || exit 2
code='box Main { static method main() { if(5>4){ return 1 } else { return 0 } } }'
json=$(stageb_compile_to_json "$code")
if ! stageb_json_nonempty "$json"; then
echo "[WARN] StageB emit empty; skipping" >&2
rm -f "$json"
exit 0
fi
set +e
"$NYASH_BIN" --json-file "$json" >/dev/null 2>&1
rc=$?
set -e
rm -f "$json"
if [ $rc -eq 1 ]; then echo "[PASS] stageb_if_vm"; exit 0; else echo "[FAIL] stageb_if_vm rc=$rc" >&2; exit 1; fi

View File

@ -0,0 +1,27 @@
#!/bin/bash
# stageb_loop_vm.sh — StageB: sum 1..3 → rc=6
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"
source "$ROOT/tools/smokes/v2/lib/stageb_helpers.sh"
require_env || exit 2
code='box Main { static method main() { local i=1; local s=0; loop(i<=3){ s=s+i; i=i+1; } return s; } }'
json=$(stageb_compile_to_json "$code")
if ! stageb_json_nonempty "$json"; then
echo "[WARN] StageB emit empty; skipping" >&2
rm -f "$json"
exit 0
fi
set +e
"$NYASH_BIN" --json-file "$json" >/dev/null 2>&1
rc=$?
set -e
rm -f "$json"
if [ $rc -eq 6 ]; then echo "[PASS] stageb_loop_vm"; exit 0; else echo "[FAIL] stageb_loop_vm rc=$rc" >&2; exit 1; fi

View File

@ -0,0 +1,27 @@
#!/bin/bash
# stageb_map_vm.sh — StageB: map size → rc=1
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"
source "$ROOT/tools/smokes/v2/lib/stageb_helpers.sh"
require_env || exit 2
code='box Main { static method main() { local m=new MapBox(); m.set("a",1); return m.size(); } }'
json=$(stageb_compile_to_json "$code")
if ! stageb_json_nonempty "$json"; then
echo "[WARN] StageB emit empty; skipping" >&2
rm -f "$json"
exit 0
fi
set +e
"$NYASH_BIN" --json-file "$json" >/dev/null 2>&1
rc=$?
set -e
rm -f "$json"
if [ $rc -eq 1 ]; then echo "[PASS] stageb_map_vm"; exit 0; else echo "[FAIL] stageb_map_vm rc=$rc" >&2; exit 1; fi

View File

@ -0,0 +1,37 @@
#!/bin/bash
# stageb_print_vm.sh — StageB: print positive case (emit→GateC direct)
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"
source "$ROOT/tools/smokes/v2/lib/stageb_helpers.sh"
require_env || exit 2
code='box Main { static method main() { print(3); return 0; } }'
json=$(stageb_compile_to_json "$code") || { echo "[WARN] StageB emit failed; skipping" >&2; exit 0; }
if ! stageb_json_nonempty "$json"; then
echo "[WARN] StageB emit empty; skipping" >&2
rm -f "$json"
exit 0
fi
set +e
output=$("$NYASH_BIN" --json-file "$json")
rc=$?
set -e
rm -f "$json"
if [ "$output" = "3" ] && [ $rc -eq 0 ]; then
echo "[PASS] stageb_print_vm"
exit 0
else
echo "[FAIL] stageb_print_vm (rc=$rc)" >&2
echo "--- output ---" >&2
echo "$output" >&2
exit 1
fi

View File

@ -0,0 +1,27 @@
#!/bin/bash
# stageb_string_vm.sh — StageB: string length → 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"
source "$ROOT/tools/smokes/v2/lib/stageb_helpers.sh"
require_env || exit 2
code='box Main { static method main() { local s="ab"; return s.length(); } }'
json=$(stageb_compile_to_json "$code")
if ! stageb_json_nonempty "$json"; then
echo "[WARN] StageB emit empty; skipping" >&2
rm -f "$json"
exit 0
fi
set +e
"$NYASH_BIN" --json-file "$json" >/dev/null 2>&1
rc=$?
set -e
rm -f "$json"
if [ $rc -eq 2 ]; then echo "[PASS] stageb_string_vm"; exit 0; else echo "[FAIL] stageb_string_vm rc=$rc" >&2; exit 1; fi