2025-09-24 09:30:42 +09:00
|
|
|
|
#!/bin/bash
|
|
|
|
|
|
# test_runner.sh - 中核実行器(強制使用)
|
|
|
|
|
|
# スモークテストv2の核心ライブラリ
|
|
|
|
|
|
|
|
|
|
|
|
# set -eは使わない(個々のテストが失敗しても全体を続行するため)
|
|
|
|
|
|
set -uo pipefail
|
|
|
|
|
|
|
2025-09-24 21:45:27 +09:00
|
|
|
|
# ルート/バイナリ検出(CWDに依存しない実行を保証)
|
|
|
|
|
|
if [ -z "${NYASH_ROOT:-}" ]; then
|
|
|
|
|
|
export NYASH_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)"
|
|
|
|
|
|
fi
|
2025-11-02 17:50:06 +09:00
|
|
|
|
# Prefer hakorune binary if exists; fallback to nyash for compatibility
|
|
|
|
|
|
if [ -z "${NYASH_BIN:-}" ]; then
|
|
|
|
|
|
if [ -x "$NYASH_ROOT/target/release/hakorune" ]; then
|
|
|
|
|
|
export NYASH_BIN="$NYASH_ROOT/target/release/hakorune"
|
|
|
|
|
|
else
|
|
|
|
|
|
export NYASH_BIN="$NYASH_ROOT/target/release/nyash"
|
|
|
|
|
|
fi
|
|
|
|
|
|
fi
|
2025-09-24 21:45:27 +09:00
|
|
|
|
|
2025-09-24 09:30:42 +09:00
|
|
|
|
# グローバル変数
|
|
|
|
|
|
export SMOKES_V2_LIB_LOADED=1
|
|
|
|
|
|
export SMOKES_START_TIME=$(date +%s.%N)
|
|
|
|
|
|
export SMOKES_TEST_COUNT=0
|
|
|
|
|
|
export SMOKES_PASS_COUNT=0
|
|
|
|
|
|
export SMOKES_FAIL_COUNT=0
|
2025-11-03 23:21:48 +09:00
|
|
|
|
export SMOKES_INCLUDE_SKIP_COUNT=0
|
|
|
|
|
|
declare -a SMOKES_INCLUDE_SKIP_LIST=()
|
2025-09-24 09:30:42 +09:00
|
|
|
|
|
|
|
|
|
|
# 色定義(重複回避)
|
|
|
|
|
|
if [ -z "${RED:-}" ]; then
|
|
|
|
|
|
readonly RED='\033[0;31m'
|
|
|
|
|
|
readonly GREEN='\033[0;32m'
|
|
|
|
|
|
readonly YELLOW='\033[1;33m'
|
|
|
|
|
|
readonly BLUE='\033[0;34m'
|
|
|
|
|
|
readonly NC='\033[0m' # No Color
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# ログ関数
|
|
|
|
|
|
log_info() {
|
|
|
|
|
|
echo -e "${BLUE}[INFO]${NC} $*" >&2
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
log_success() {
|
|
|
|
|
|
echo -e "${GREEN}[PASS]${NC} $*" >&2
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
log_warn() {
|
|
|
|
|
|
echo -e "${YELLOW}[WARN]${NC} $*" >&2
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
log_error() {
|
|
|
|
|
|
echo -e "${RED}[FAIL]${NC} $*" >&2
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-25 06:15:22 +09:00
|
|
|
|
# 共通ノイズフィルタ(VM実行時の出力整形)
|
|
|
|
|
|
filter_noise() {
|
|
|
|
|
|
# プラグイン初期化やメタログ、動的ローダの案内等を除去
|
|
|
|
|
|
grep -v "^\[UnifiedBoxRegistry\]" \
|
|
|
|
|
|
| grep -v "^\[FileBox\]" \
|
|
|
|
|
|
| grep -v "^Net plugin:" \
|
2025-09-26 03:30:59 +09:00
|
|
|
|
| grep -v "^\[.*\] Plugin" \
|
2025-09-25 06:15:22 +09:00
|
|
|
|
| grep -v "Using builtin StringBox" \
|
2025-09-26 03:30:59 +09:00
|
|
|
|
| grep -v "Using builtin ArrayBox" \
|
|
|
|
|
|
| grep -v "Using builtin MapBox" \
|
2025-09-26 14:34:42 +09:00
|
|
|
|
| grep -v "^\[using\]" \
|
|
|
|
|
|
| grep -v "^\[using/resolve\]" \
|
|
|
|
|
|
| grep -v "^\[builder\]" \
|
2025-09-27 08:45:25 +09:00
|
|
|
|
| grep -v "^\\[vm-trace\\]" \
|
2025-11-01 17:39:36 +09:00
|
|
|
|
| grep -v "^\[DEBUG\]" \
|
2025-09-27 08:45:25 +09:00
|
|
|
|
| grep -v '^\{"ev":' \
|
2025-09-28 01:33:58 +09:00
|
|
|
|
| grep -v '^\[warn\] dev fallback: user instance BoxCall' \
|
2025-09-27 08:45:25 +09:00
|
|
|
|
| sed -E 's/^❌ VM fallback error: *//' \
|
2025-09-28 01:33:58 +09:00
|
|
|
|
| grep -v '^\[warn\] dev verify: NewBox ' \
|
|
|
|
|
|
| grep -v '^\[warn\] dev verify: NewBox→birth invariant warnings:' \
|
2025-11-02 15:43:43 +09:00
|
|
|
|
| grep -v '^\[ny-compiler\]' \
|
|
|
|
|
|
| grep -v '^\[using/cache\]' \
|
2025-09-26 03:30:59 +09:00
|
|
|
|
| grep -v "plugins/nyash-array-plugin" \
|
|
|
|
|
|
| grep -v "plugins/nyash-map-plugin" \
|
2025-09-25 06:15:22 +09:00
|
|
|
|
| grep -v "Phase 15.5: Everything is Plugin" \
|
|
|
|
|
|
| grep -v "cargo build -p nyash-string-plugin" \
|
|
|
|
|
|
| grep -v "^\[plugin-loader\] backend=" \
|
|
|
|
|
|
| grep -v "^\[using\] ctx:" \
|
|
|
|
|
|
| grep -v "^🔌 plugin host initialized" \
|
|
|
|
|
|
| grep -v "^✅ plugin host fully configured" \
|
|
|
|
|
|
| grep -v "Failed to load nyash.toml - plugins disabled" \
|
2025-11-02 17:50:06 +09:00
|
|
|
|
| grep -v "^🚀 Nyash VM Backend - Executing file:" \
|
|
|
|
|
|
| grep -v "^🚀 Hakorune VM Backend - Executing file:"
|
2025-09-25 06:15:22 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-24 09:30:42 +09:00
|
|
|
|
# 環境チェック(必須)
|
|
|
|
|
|
require_env() {
|
|
|
|
|
|
local required_tools=("cargo" "grep" "jq")
|
|
|
|
|
|
local missing_tools=()
|
|
|
|
|
|
|
|
|
|
|
|
for tool in "${required_tools[@]}"; do
|
|
|
|
|
|
if ! command -v "$tool" &> /dev/null; then
|
|
|
|
|
|
missing_tools+=("$tool")
|
|
|
|
|
|
fi
|
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
|
|
if [ ${#missing_tools[@]} -ne 0 ]; then
|
|
|
|
|
|
log_error "Required tools missing: ${missing_tools[*]}"
|
|
|
|
|
|
log_error "Please install missing tools and try again"
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Nyash実行ファイル確認
|
2025-09-24 21:45:27 +09:00
|
|
|
|
if [ ! -f "$NYASH_BIN" ]; then
|
|
|
|
|
|
log_error "Nyash executable not found at $NYASH_BIN"
|
|
|
|
|
|
log_error "Please run 'cargo build --release' first (in $NYASH_ROOT)"
|
2025-09-24 09:30:42 +09:00
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
log_info "Environment check passed"
|
|
|
|
|
|
return 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# プラグイン整合性チェック(必須)
|
|
|
|
|
|
preflight_plugins() {
|
|
|
|
|
|
# プラグインマネージャーが存在する場合は実行
|
|
|
|
|
|
if [ -f "$(dirname "${BASH_SOURCE[0]}")/plugin_manager.sh" ]; then
|
|
|
|
|
|
source "$(dirname "${BASH_SOURCE[0]}")/plugin_manager.sh"
|
|
|
|
|
|
check_plugin_integrity || return 1
|
|
|
|
|
|
else
|
|
|
|
|
|
log_warn "Plugin manager not found, skipping plugin checks"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
return 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# テスト実行関数
|
|
|
|
|
|
run_test() {
|
|
|
|
|
|
local test_name="$1"
|
|
|
|
|
|
local test_func="$2"
|
|
|
|
|
|
|
|
|
|
|
|
((SMOKES_TEST_COUNT++))
|
|
|
|
|
|
local start_time=$(date +%s.%N)
|
|
|
|
|
|
|
|
|
|
|
|
log_info "Running test: $test_name"
|
|
|
|
|
|
|
|
|
|
|
|
if $test_func; then
|
|
|
|
|
|
local end_time=$(date +%s.%N)
|
|
|
|
|
|
local duration=$(echo "$end_time - $start_time" | bc -l)
|
|
|
|
|
|
log_success "$test_name (${duration}s)"
|
|
|
|
|
|
((SMOKES_PASS_COUNT++))
|
|
|
|
|
|
return 0
|
|
|
|
|
|
else
|
|
|
|
|
|
local end_time=$(date +%s.%N)
|
|
|
|
|
|
local duration=$(echo "$end_time - $start_time" | bc -l)
|
|
|
|
|
|
log_error "$test_name (${duration}s)"
|
|
|
|
|
|
((SMOKES_FAIL_COUNT++))
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Nyash実行ヘルパー(Rust VM)
|
|
|
|
|
|
run_nyash_vm() {
|
|
|
|
|
|
local program="$1"
|
|
|
|
|
|
shift
|
2025-09-24 21:45:27 +09:00
|
|
|
|
local USE_PYVM="${SMOKES_USE_PYVM:-0}"
|
2025-09-27 08:45:25 +09:00
|
|
|
|
local EXTRA_ARGS=()
|
|
|
|
|
|
if [ "${SMOKES_USE_DEV:-0}" = "1" ]; then
|
|
|
|
|
|
EXTRA_ARGS+=("--dev")
|
|
|
|
|
|
fi
|
2025-09-28 01:33:58 +09:00
|
|
|
|
# Optional env sanitization between rapid invocations (default OFF)
|
|
|
|
|
|
# Enable with: SMOKES_CLEAN_ENV=1
|
|
|
|
|
|
local ENV_PREFIX=( )
|
|
|
|
|
|
if [ "${SMOKES_CLEAN_ENV:-0}" = "1" ]; then
|
|
|
|
|
|
ENV_PREFIX=(env -u NYASH_DEBUG_ENABLE -u NYASH_DEBUG_KINDS -u NYASH_DEBUG_SINK \
|
|
|
|
|
|
-u NYASH_RESOLVE_FIX_BRACES -u NYASH_USING_AST \
|
|
|
|
|
|
-u NYASH_VM_TRACE -u NYASH_VM_VERIFY_MIR -u NYASH_VM_TOLERATE_VOID \
|
|
|
|
|
|
-u NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN)
|
|
|
|
|
|
fi
|
2025-09-24 09:30:42 +09:00
|
|
|
|
# -c オプションの場合は一時ファイル経由で実行
|
|
|
|
|
|
if [ "$program" = "-c" ]; then
|
|
|
|
|
|
local code="$1"
|
|
|
|
|
|
shift
|
|
|
|
|
|
local tmpfile="/tmp/nyash_test_$$.nyash"
|
|
|
|
|
|
echo "$code" > "$tmpfile"
|
2025-09-28 12:19:49 +09:00
|
|
|
|
# 軽量ASIFix(テスト用): ブロック終端の余剰セミコロンを寛容に除去
|
|
|
|
|
|
if [ "${SMOKES_ASI_STRIP_SEMI:-1}" = "1" ]; then
|
|
|
|
|
|
sed -i -E 's/;([[:space:]]*)(\}|$)/\1\2/g' "$tmpfile" || true
|
|
|
|
|
|
fi
|
2025-09-24 09:30:42 +09:00
|
|
|
|
# プラグイン初期化メッセージを除外
|
2025-11-03 16:09:19 +09:00
|
|
|
|
# Optional preinclude for include-based code
|
|
|
|
|
|
local runfile="$tmpfile"
|
|
|
|
|
|
if [ "${NYASH_PREINCLUDE:-0}" = "1" ] || [ "${HAKO_PREINCLUDE:-0}" = "1" ]; then
|
|
|
|
|
|
local prefile="/tmp/nyash_pre_$$.nyash"
|
|
|
|
|
|
"$NYASH_ROOT/tools/dev/hako_preinclude.sh" "$tmpfile" "$prefile" >/dev/null || true
|
|
|
|
|
|
runfile="$prefile"
|
|
|
|
|
|
fi
|
|
|
|
|
|
# Optional hint for include lines when preinclude is OFF
|
|
|
|
|
|
if grep -q '^include\s\"' "$tmpfile" 2>/dev/null && [ "${NYASH_PREINCLUDE:-0}" != "1" ] && [ "${HAKO_PREINCLUDE:-0}" != "1" ]; then
|
|
|
|
|
|
echo "[WARN] VM backend does not support include. Prefer using+alias, or set NYASH_PREINCLUDE=1 for dev." >&2
|
|
|
|
|
|
fi
|
2025-11-02 07:12:52 +09:00
|
|
|
|
NYASH_VM_USE_PY="$USE_PYVM" NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \
|
2025-11-02 15:43:43 +09:00
|
|
|
|
NYASH_DISABLE_NY_COMPILER=1 HAKO_DISABLE_NY_COMPILER=1 \
|
2025-11-02 07:12:52 +09:00
|
|
|
|
NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 NYASH_PARSER_ALLOW_SEMICOLON=1 \
|
|
|
|
|
|
"${ENV_PREFIX[@]}" \
|
2025-11-03 16:09:19 +09:00
|
|
|
|
"$NYASH_BIN" --backend vm "$runfile" "${EXTRA_ARGS[@]}" "$@" 2>&1 | filter_noise
|
2025-09-24 09:30:42 +09:00
|
|
|
|
local exit_code=${PIPESTATUS[0]}
|
2025-11-03 16:09:19 +09:00
|
|
|
|
# prefile may be unset when preinclude is OFF; use default expansion to avoid set -u errors
|
|
|
|
|
|
rm -f "$tmpfile" "${prefile:-}" 2>/dev/null || true
|
2025-09-24 09:30:42 +09:00
|
|
|
|
return $exit_code
|
|
|
|
|
|
else
|
2025-09-26 14:34:42 +09:00
|
|
|
|
# 軽量ASIFix(テスト用): ブロック終端の余剰セミコロンを寛容に除去
|
|
|
|
|
|
if [ "${SMOKES_ASI_STRIP_SEMI:-1}" = "1" ] && [ -f "$program" ]; then
|
|
|
|
|
|
sed -i -E 's/;([[:space:]]*)(\}|$)/\1\2/g' "$program" || true
|
|
|
|
|
|
fi
|
2025-09-24 09:30:42 +09:00
|
|
|
|
# プラグイン初期化メッセージを除外
|
2025-11-03 16:09:19 +09:00
|
|
|
|
# Optional preinclude
|
|
|
|
|
|
local runfile2="$program"
|
|
|
|
|
|
if [ "${NYASH_PREINCLUDE:-0}" = "1" ] || [ "${HAKO_PREINCLUDE:-0}" = "1" ]; then
|
|
|
|
|
|
local prefile2="/tmp/nyash_pre_$$.nyash"
|
|
|
|
|
|
"$NYASH_ROOT/tools/dev/hako_preinclude.sh" "$program" "$prefile2" >/dev/null || true
|
|
|
|
|
|
runfile2="$prefile2"
|
|
|
|
|
|
fi
|
|
|
|
|
|
# Optional hint for include lines when preinclude is OFF
|
|
|
|
|
|
if [ -f "$program" ] && grep -q '^include\s\"' "$program" 2>/dev/null && [ "${NYASH_PREINCLUDE:-0}" != "1" ] && [ "${HAKO_PREINCLUDE:-0}" != "1" ]; then
|
2025-11-03 23:21:48 +09:00
|
|
|
|
# Policy: quick は SKIP 既定。それ以外は WARN(SMOKES_INCLUDE_POLICY で上書き可能)。
|
|
|
|
|
|
local policy="${SMOKES_INCLUDE_POLICY:-}"
|
|
|
|
|
|
if [ -z "$policy" ]; then
|
|
|
|
|
|
case "$program" in
|
|
|
|
|
|
*/profiles/quick/*) policy="skip" ;;
|
|
|
|
|
|
*) policy="warn" ;;
|
|
|
|
|
|
esac
|
|
|
|
|
|
fi
|
|
|
|
|
|
if [ "$policy" = "skip" ]; then
|
|
|
|
|
|
SMOKES_INCLUDE_SKIP_COUNT=$((SMOKES_INCLUDE_SKIP_COUNT + 1))
|
|
|
|
|
|
local rel_path="$program"
|
|
|
|
|
|
if [[ "$program" == "$NYASH_ROOT/"* ]]; then
|
|
|
|
|
|
rel_path="${program#$NYASH_ROOT/}"
|
|
|
|
|
|
fi
|
|
|
|
|
|
SMOKES_INCLUDE_SKIP_LIST+=("$rel_path")
|
|
|
|
|
|
echo "[SKIP] include is deprecated in 20.36+ (quick). Prefer using+alias." >&2
|
|
|
|
|
|
return 0
|
|
|
|
|
|
elif [ "$policy" = "error" ]; then
|
|
|
|
|
|
echo "[ERROR] include is deprecated in 20.36+. Prefer using+alias." >&2
|
|
|
|
|
|
return 2
|
|
|
|
|
|
else
|
|
|
|
|
|
echo "[WARN] include is deprecated in 20.36+. Prefer using+alias. Preinclude is dev-only (NYASH_PREINCLUDE=1)." >&2
|
|
|
|
|
|
fi
|
2025-11-03 16:09:19 +09:00
|
|
|
|
fi
|
2025-11-02 07:12:52 +09:00
|
|
|
|
NYASH_VM_USE_PY="$USE_PYVM" NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 \
|
2025-11-02 15:43:43 +09:00
|
|
|
|
NYASH_DISABLE_NY_COMPILER=1 HAKO_DISABLE_NY_COMPILER=1 \
|
2025-11-02 07:12:52 +09:00
|
|
|
|
NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 NYASH_PARSER_ALLOW_SEMICOLON=1 \
|
|
|
|
|
|
"${ENV_PREFIX[@]}" \
|
2025-11-03 16:09:19 +09:00
|
|
|
|
"$NYASH_BIN" --backend vm "$runfile2" "${EXTRA_ARGS[@]}" "$@" 2>&1 | filter_noise
|
|
|
|
|
|
local exit_code=${PIPESTATUS[0]}
|
|
|
|
|
|
# prefile2 may be unset when preinclude is OFF
|
|
|
|
|
|
rm -f "${prefile2:-}" 2>/dev/null || true
|
|
|
|
|
|
return $exit_code
|
|
|
|
|
|
fi
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Verify MIR JSON rc using selected primary (Core or Hakorune VM)
|
|
|
|
|
|
verify_mir_rc() {
|
|
|
|
|
|
local json_path="$1"
|
2025-11-03 23:21:48 +09:00
|
|
|
|
# 20.36: hakovm を primary 既定へ(Core は診断 fallback)
|
|
|
|
|
|
local primary="${HAKO_VERIFY_PRIMARY:-hakovm}"
|
2025-11-03 16:09:19 +09:00
|
|
|
|
if [ "$primary" = "hakovm" ]; then
|
2025-11-03 23:21:48 +09:00
|
|
|
|
# If the payload is MIR JSON v1 (schema_version present), Mini-VM cannot execute it yet.
|
|
|
|
|
|
# Route to Core fallback directly to keep canaries meaningful while Mini-VM gains v1 support.
|
|
|
|
|
|
if grep -q '"schema_version"' "$json_path" 2>/dev/null; then
|
|
|
|
|
|
# Optional: hakovm v1 verify (flagged). Default remains Core.
|
|
|
|
|
|
if [ "${HAKO_VERIFY_V1_HAKOVM:-0}" = "1" ]; then
|
|
|
|
|
|
local json_literal_v1
|
|
|
|
|
|
json_literal_v1="$(jq -Rs . < "$json_path")"
|
|
|
|
|
|
local code_v1=$(cat <<'HCODE'
|
|
|
|
|
|
using selfhost.vm.hv1.dispatch as NyVmDispatcherV1Box
|
|
|
|
|
|
static box Main { method main(args) {
|
|
|
|
|
|
local j = __MIR_JSON__
|
|
|
|
|
|
local rc = NyVmDispatcherV1Box.run(j)
|
|
|
|
|
|
print("" + rc)
|
|
|
|
|
|
return rc
|
|
|
|
|
|
} }
|
|
|
|
|
|
HCODE
|
|
|
|
|
|
)
|
|
|
|
|
|
code_v1="${code_v1/__MIR_JSON__/$json_literal_v1}"
|
|
|
|
|
|
local out_v1; out_v1=$(NYASH_USING_AST=1 run_nyash_vm -c "$code_v1" 2>/dev/null | tr -d '\r' | tail -n 1)
|
|
|
|
|
|
if [[ "$out_v1" =~ ^-?[0-9]+$ ]]; then
|
|
|
|
|
|
local n=$out_v1; if [ $n -lt 0 ]; then n=$(( (n % 256 + 256) % 256 )); else n=$(( n % 256 )); fi; return $n
|
|
|
|
|
|
fi
|
|
|
|
|
|
# fallback to Core when hakovm v1 path not ready
|
|
|
|
|
|
fi
|
|
|
|
|
|
"$NYASH_BIN" --mir-json-file "$json_path" >/dev/null 2>&1
|
|
|
|
|
|
return $?
|
|
|
|
|
|
fi
|
2025-11-03 16:09:19 +09:00
|
|
|
|
# Build a tiny driver to call MiniVmEntryBox.run_min with JSON literal embedded
|
|
|
|
|
|
if [ ! -f "$json_path" ]; then
|
|
|
|
|
|
echo "[FAIL] verify_mir_rc: json not found: $json_path" >&2
|
|
|
|
|
|
return 2
|
|
|
|
|
|
fi
|
|
|
|
|
|
# Escape JSON as a single string literal via jq -Rs (preserves newlines)
|
|
|
|
|
|
local json_literal
|
|
|
|
|
|
json_literal="$(jq -Rs . < "$json_path")"
|
|
|
|
|
|
build_and_run_driver_alias() {
|
|
|
|
|
|
local header="$1"
|
|
|
|
|
|
local code=$(cat <<HCODE
|
|
|
|
|
|
$header
|
|
|
|
|
|
static box Main { method main(args) {
|
|
|
|
|
|
local j = __MIR_JSON__;
|
|
|
|
|
|
local rc = MiniVmEntryBox.run_min(j)
|
|
|
|
|
|
print(MiniVmEntryBox.int_to_str(rc))
|
|
|
|
|
|
return rc
|
|
|
|
|
|
} }
|
|
|
|
|
|
HCODE
|
|
|
|
|
|
)
|
|
|
|
|
|
code="${code/__MIR_JSON__/$json_literal}"
|
2025-11-03 23:21:48 +09:00
|
|
|
|
NYASH_USING_AST=1 NYASH_RESOLVE_FIX_BRACES=1 run_nyash_vm -c "$code" 2>/dev/null | tr -d '\r' | tail -n 1
|
2025-11-03 16:09:19 +09:00
|
|
|
|
}
|
|
|
|
|
|
build_and_run_driver_include() {
|
|
|
|
|
|
local inc_path="$1"
|
|
|
|
|
|
local code=$(cat <<HCODE
|
|
|
|
|
|
include "$inc_path"
|
|
|
|
|
|
static box Main { method main(args) {
|
|
|
|
|
|
local j = __MIR_JSON__;
|
|
|
|
|
|
local rc = MiniVmEntryBox.run_min(j)
|
|
|
|
|
|
print(MiniVmEntryBox.int_to_str(rc))
|
|
|
|
|
|
return rc
|
|
|
|
|
|
} }
|
|
|
|
|
|
HCODE
|
|
|
|
|
|
)
|
|
|
|
|
|
code="${code/__MIR_JSON__/$json_literal}"
|
2025-11-03 23:21:48 +09:00
|
|
|
|
NYASH_PREINCLUDE=1 NYASH_RESOLVE_FIX_BRACES=1 run_nyash_vm -c "$code" 2>/dev/null | tr -d '\r' | tail -n 1
|
2025-11-03 16:09:19 +09:00
|
|
|
|
}
|
|
|
|
|
|
# Try alias header first; fallback to dev-file header; final fallback: include+preinclude
|
|
|
|
|
|
local out
|
|
|
|
|
|
out="$(build_and_run_driver_alias 'using selfhost.vm.entry as MiniVmEntryBox')"
|
|
|
|
|
|
if ! [[ "$out" =~ ^-?[0-9]+$ ]]; then
|
|
|
|
|
|
out="$(build_and_run_driver_alias 'using "lang/src/vm/boxes/mini_vm_entry.hako" as MiniVmEntryBox')"
|
|
|
|
|
|
fi
|
|
|
|
|
|
if ! [[ "$out" =~ ^-?[0-9]+$ ]]; then
|
|
|
|
|
|
out="$(build_and_run_driver_include 'lang/src/vm/boxes/mini_vm_entry.hako')"
|
|
|
|
|
|
fi
|
|
|
|
|
|
if [[ "$out" =~ ^-?[0-9]+$ ]]; then
|
|
|
|
|
|
local n=$out
|
|
|
|
|
|
# normalize into [0,255]
|
|
|
|
|
|
if [ $n -lt 0 ]; then n=$(( (n % 256 + 256) % 256 )); else n=$(( n % 256 )); fi
|
|
|
|
|
|
return $n
|
|
|
|
|
|
fi
|
|
|
|
|
|
# Fallback: core primary when MiniVM resolution is unavailable
|
2025-11-03 23:21:48 +09:00
|
|
|
|
if grep -q '"functions"' "$json_path" 2>/dev/null && grep -q '"blocks"' "$json_path" 2>/dev/null; then
|
|
|
|
|
|
local json_literal3; json_literal3="$(jq -Rs . < "$json_path")"
|
|
|
|
|
|
local code=$(cat <<HCODE
|
|
|
|
|
|
include "lang/src/vm/core/dispatcher.hako"
|
|
|
|
|
|
static box Main { method main(args) {
|
|
|
|
|
|
local j = __MIR_JSON__
|
|
|
|
|
|
local r = NyVmDispatcher.run(j)
|
|
|
|
|
|
print("" + r)
|
|
|
|
|
|
return r
|
|
|
|
|
|
} }
|
|
|
|
|
|
HCODE
|
|
|
|
|
|
)
|
|
|
|
|
|
code="${code/__MIR_JSON__/$json_literal3}"
|
|
|
|
|
|
local tmpwrap="/tmp/hako_core_wrap_$$.nyash"
|
|
|
|
|
|
echo "$code" > "$tmpwrap"
|
|
|
|
|
|
NYASH_PREINCLUDE=1 run_nyash_vm "$tmpwrap" >/dev/null 2>&1; local r=$?; rm -f "$tmpwrap"; return $r
|
|
|
|
|
|
fi
|
|
|
|
|
|
NYASH_GATE_C_CORE=1 HAKO_GATE_C_CORE=1 "$NYASH_BIN" --json-file "$json_path" >/dev/null 2>&1; return $?
|
2025-11-03 16:09:19 +09:00
|
|
|
|
else
|
2025-11-03 23:21:48 +09:00
|
|
|
|
# Core primary: detect MIR(JSON) vs Program(JSON v0)
|
|
|
|
|
|
if grep -q '"functions"' "$json_path" 2>/dev/null && grep -q '"blocks"' "$json_path" 2>/dev/null; then
|
|
|
|
|
|
"$NYASH_BIN" --mir-json-file "$json_path" >/dev/null 2>&1; return $?
|
|
|
|
|
|
fi
|
|
|
|
|
|
NYASH_GATE_C_CORE=1 HAKO_GATE_C_CORE=1 "$NYASH_BIN" --json-file "$json_path" >/dev/null 2>&1; return $?
|
2025-09-24 09:30:42 +09:00
|
|
|
|
fi
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Nyash実行ヘルパー(LLVM)
|
|
|
|
|
|
run_nyash_llvm() {
|
|
|
|
|
|
local program="$1"
|
|
|
|
|
|
shift
|
2025-09-28 12:19:49 +09:00
|
|
|
|
# Allow developer to force LLVM run (env guarantees availability)
|
|
|
|
|
|
if [ "${SMOKES_FORCE_LLVM:-0}" != "1" ]; then
|
|
|
|
|
|
# Skip gracefully when LLVM backend is not available in this build
|
|
|
|
|
|
# Primary check: version string advertises features
|
|
|
|
|
|
if ! "$NYASH_BIN" --version 2>/dev/null | grep -q "features.*llvm"; then
|
|
|
|
|
|
# Fallback check: binary contains LLVM harness symbols (ny-llvmc / NYASH_LLVM_USE_HARNESS)
|
|
|
|
|
|
if ! strings "$NYASH_BIN" 2>/dev/null | grep -E -q 'ny-llvmc|NYASH_LLVM_USE_HARNESS'; then
|
|
|
|
|
|
log_warn "LLVM backend not available in this build; skipping LLVM run"
|
|
|
|
|
|
log_info "Hint: build ny-llvmc + enable harness: cargo build --release -p nyash-llvm-compiler && cargo build --release --features llvm"
|
|
|
|
|
|
return 0
|
|
|
|
|
|
fi
|
|
|
|
|
|
fi
|
2025-09-27 08:45:25 +09:00
|
|
|
|
fi
|
2025-09-24 09:30:42 +09:00
|
|
|
|
# -c オプションの場合は一時ファイル経由で実行
|
|
|
|
|
|
if [ "$program" = "-c" ]; then
|
|
|
|
|
|
local code="$1"
|
|
|
|
|
|
shift
|
|
|
|
|
|
local tmpfile="/tmp/nyash_test_$$.nyash"
|
|
|
|
|
|
echo "$code" > "$tmpfile"
|
2025-09-28 12:19:49 +09:00
|
|
|
|
# 軽量ASIFix(テスト用): ブロック終端の余剰セミコロンを寛容に除去
|
|
|
|
|
|
if [ "${SMOKES_ASI_STRIP_SEMI:-1}" = "1" ]; then
|
|
|
|
|
|
sed -i -E 's/;([[:space:]]*)(\}|$)/\1\2/g' "$tmpfile" || true
|
|
|
|
|
|
fi
|
|
|
|
|
|
# 軽量ASIFix(テスト用): ブロック終端の余剰セミコロンを寛容に除去
|
|
|
|
|
|
if [ "${SMOKES_ASI_STRIP_SEMI:-1}" = "1" ] && [ -f "$program" ]; then
|
|
|
|
|
|
sed -i -E 's/;([[:space:]]*)(\}|$)/\1\2/g' "$program" || true
|
|
|
|
|
|
fi
|
2025-09-24 09:30:42 +09:00
|
|
|
|
# プラグイン初期化メッセージを除外
|
2025-11-02 17:50:06 +09:00
|
|
|
|
PYTHONPATH="${PYTHONPATH:-$NYASH_ROOT}" NYASH_NY_LLVM_COMPILER="$NYASH_ROOT/target/release/ny-llvmc" NYASH_LLVM_USE_HARNESS=1 NYASH_EMIT_EXE_NYRT="$NYASH_ROOT/target/release" NYASH_VM_USE_PY=0 NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 NYASH_PARSER_ALLOW_SEMICOLON=1 NYASH_DISABLE_NY_COMPILER=1 HAKO_DISABLE_NY_COMPILER=1 "$NYASH_BIN" --backend llvm "$tmpfile" "$@" 2>&1 | \
|
2025-09-28 12:19:49 +09:00
|
|
|
|
grep -v "^\[UnifiedBoxRegistry\]" | grep -v "^\[FileBox\]" | grep -v "^Net plugin:" | grep -v "^\[.*\] Plugin" | \
|
2025-11-02 17:50:06 +09:00
|
|
|
|
grep -v '^\[plugin-loader\] backend=' | \
|
|
|
|
|
|
grep -v '^🔌 plugin host initialized' | grep -v '^✅ plugin host fully configured' | \
|
|
|
|
|
|
grep -v '^⚡ Hakorune LLVM Backend' | \
|
2025-09-28 12:19:49 +09:00
|
|
|
|
grep -v '^✅ LLVM (harness) execution completed' | grep -v '^📊 MIR Module compiled successfully' | grep -v '^📊 Functions:' | grep -v 'JSON Parse Errors:' | grep -v 'Parsing errors' | grep -v 'No parsing errors' | grep -v 'Error at line ' | \
|
2025-11-02 17:50:06 +09:00
|
|
|
|
grep -v '^\[using\]' | grep -v '^\[using/resolve\]' | grep -v '^\[using/cache\]' | \
|
2025-09-28 12:19:49 +09:00
|
|
|
|
grep -v '^\[ny-llvmc\]' | grep -v '^\[harness\]' | grep -v '^Compiled to ' | grep -v '^/usr/bin/ld:'
|
2025-09-24 09:30:42 +09:00
|
|
|
|
local exit_code=${PIPESTATUS[0]}
|
|
|
|
|
|
rm -f "$tmpfile"
|
|
|
|
|
|
return $exit_code
|
|
|
|
|
|
else
|
2025-09-28 12:19:49 +09:00
|
|
|
|
# 軽量ASIFix(テスト用): ブロック終端の余剰セミコロンを寛容に除去
|
|
|
|
|
|
if [ "${SMOKES_ASI_STRIP_SEMI:-1}" = "1" ] && [ -f "$program" ]; then
|
|
|
|
|
|
sed -i -E 's/;([[:space:]]*)(\}|$)/\1\2/g' "$program" || true
|
|
|
|
|
|
fi
|
2025-09-24 09:30:42 +09:00
|
|
|
|
# プラグイン初期化メッセージを除外
|
2025-11-02 17:50:06 +09:00
|
|
|
|
PYTHONPATH="${PYTHONPATH:-$NYASH_ROOT}" NYASH_NY_LLVM_COMPILER="$NYASH_ROOT/target/release/ny-llvmc" NYASH_LLVM_USE_HARNESS=1 NYASH_EMIT_EXE_NYRT="$NYASH_ROOT/target/release" NYASH_VM_USE_PY=0 NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 NYASH_PARSER_ALLOW_SEMICOLON=1 NYASH_DISABLE_NY_COMPILER=1 HAKO_DISABLE_NY_COMPILER=1 "$NYASH_BIN" --backend llvm "$program" "$@" 2>&1 | \
|
2025-09-28 12:19:49 +09:00
|
|
|
|
grep -v "^\[UnifiedBoxRegistry\]" | grep -v "^\[FileBox\]" | grep -v "^Net plugin:" | grep -v "^\[.*\] Plugin" | \
|
2025-11-02 17:50:06 +09:00
|
|
|
|
grep -v '^\[plugin-loader\] backend=' | \
|
|
|
|
|
|
grep -v '^🔌 plugin host initialized' | grep -v '^✅ plugin host fully configured' | \
|
|
|
|
|
|
grep -v '^⚡ Hakorune LLVM Backend' | \
|
2025-09-28 12:19:49 +09:00
|
|
|
|
grep -v '^✅ LLVM (harness) execution completed' | grep -v '^📊 MIR Module compiled successfully' | grep -v '^📊 Functions:' | grep -v 'JSON Parse Errors:' | grep -v 'Parsing errors' | grep -v 'No parsing errors' | grep -v 'Error at line ' | \
|
2025-11-02 17:50:06 +09:00
|
|
|
|
grep -v '^\[using\]' | grep -v '^\[using/resolve\]' | grep -v '^\[using/cache\]' | \
|
2025-09-28 12:19:49 +09:00
|
|
|
|
grep -v '^\[ny-llvmc\]' | grep -v '^\[harness\]' | grep -v '^Compiled to ' | grep -v '^/usr/bin/ld:'
|
2025-09-24 09:30:42 +09:00
|
|
|
|
return ${PIPESTATUS[0]}
|
|
|
|
|
|
fi
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-24 21:45:27 +09:00
|
|
|
|
# シンプルテスト補助(スクリプト互換)
|
|
|
|
|
|
test_pass() { log_success "$1"; return 0; }
|
|
|
|
|
|
test_fail() { log_error "$1 ${2:-}"; return 1; }
|
|
|
|
|
|
test_skip() { log_warn "SKIP $1 ${2:-}"; return 0; }
|
|
|
|
|
|
|
2025-09-24 09:30:42 +09:00
|
|
|
|
# 出力比較ヘルパー
|
|
|
|
|
|
compare_outputs() {
|
|
|
|
|
|
local expected="$1"
|
|
|
|
|
|
local actual="$2"
|
|
|
|
|
|
local test_name="$3"
|
|
|
|
|
|
|
|
|
|
|
|
if [ "$expected" = "$actual" ]; then
|
|
|
|
|
|
return 0
|
|
|
|
|
|
else
|
|
|
|
|
|
log_error "$test_name output mismatch:"
|
|
|
|
|
|
log_error " Expected: $expected"
|
|
|
|
|
|
log_error " Actual: $actual"
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# 結果サマリー出力
|
|
|
|
|
|
print_summary() {
|
|
|
|
|
|
local end_time=$(date +%s.%N)
|
|
|
|
|
|
local total_duration=$(echo "$end_time - $SMOKES_START_TIME" | bc -l)
|
|
|
|
|
|
|
|
|
|
|
|
echo ""
|
|
|
|
|
|
echo "==============================================="
|
|
|
|
|
|
echo "Smoke Test Summary"
|
|
|
|
|
|
echo "==============================================="
|
|
|
|
|
|
echo "Total tests: $SMOKES_TEST_COUNT"
|
|
|
|
|
|
echo "Passed: $SMOKES_PASS_COUNT"
|
|
|
|
|
|
echo "Failed: $SMOKES_FAIL_COUNT"
|
|
|
|
|
|
echo "Duration: ${total_duration}s"
|
|
|
|
|
|
echo ""
|
|
|
|
|
|
|
2025-11-03 23:21:48 +09:00
|
|
|
|
if [ "${SMOKES_INCLUDE_SKIP_COUNT:-0}" -gt 0 ]; then
|
|
|
|
|
|
echo "Include SKIPs: $SMOKES_INCLUDE_SKIP_COUNT"
|
|
|
|
|
|
for entry in "${SMOKES_INCLUDE_SKIP_LIST[@]}"; do
|
|
|
|
|
|
echo " - $entry"
|
|
|
|
|
|
done
|
|
|
|
|
|
echo ""
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
2025-09-24 09:30:42 +09:00
|
|
|
|
if [ $SMOKES_FAIL_COUNT -eq 0 ]; then
|
|
|
|
|
|
log_success "All tests passed! ✨"
|
|
|
|
|
|
return 0
|
|
|
|
|
|
else
|
|
|
|
|
|
log_error "$SMOKES_FAIL_COUNT test(s) failed"
|
|
|
|
|
|
return 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# JSON出力関数
|
|
|
|
|
|
output_json() {
|
|
|
|
|
|
local profile="${1:-unknown}"
|
|
|
|
|
|
local end_time=$(date +%s.%N)
|
|
|
|
|
|
local total_duration=$(echo "$end_time - $SMOKES_START_TIME" | bc -l)
|
|
|
|
|
|
|
|
|
|
|
|
cat << EOF
|
|
|
|
|
|
{
|
|
|
|
|
|
"profile": "$profile",
|
|
|
|
|
|
"total": $SMOKES_TEST_COUNT,
|
|
|
|
|
|
"passed": $SMOKES_PASS_COUNT,
|
|
|
|
|
|
"failed": $SMOKES_FAIL_COUNT,
|
|
|
|
|
|
"duration": $total_duration,
|
|
|
|
|
|
"timestamp": "$(date -Iseconds)",
|
|
|
|
|
|
"success": $([ $SMOKES_FAIL_COUNT -eq 0 ] && echo "true" || echo "false")
|
|
|
|
|
|
}
|
|
|
|
|
|
EOF
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# JUnit XML出力関数
|
|
|
|
|
|
output_junit() {
|
|
|
|
|
|
local profile="${1:-unknown}"
|
|
|
|
|
|
local end_time=$(date +%s.%N)
|
|
|
|
|
|
local total_duration=$(echo "$end_time - $SMOKES_START_TIME" | bc -l)
|
|
|
|
|
|
|
|
|
|
|
|
cat << EOF
|
|
|
|
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
|
|
|
|
<testsuite name="smokes_$profile" tests="$SMOKES_TEST_COUNT" failures="$SMOKES_FAIL_COUNT" time="$total_duration">
|
|
|
|
|
|
<!-- Individual test cases would be added by specific test scripts -->
|
|
|
|
|
|
</testsuite>
|
|
|
|
|
|
EOF
|
2025-09-24 21:45:27 +09:00
|
|
|
|
}
|