|
|
#!/usr/bin/env bash
|
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
if [[ $# -lt 1 || $# -gt 2 ]]; then
|
|
|
echo "用法: $0 <test_dir> [output_dir]" >&2
|
|
|
exit 1
|
|
|
fi
|
|
|
|
|
|
test_dir=${1%/}
|
|
|
out_dir="test/test_result/function/asm"
|
|
|
|
|
|
shift
|
|
|
while [[ $# -gt 0 ]]; do
|
|
|
out_dir="$1"
|
|
|
shift
|
|
|
done
|
|
|
|
|
|
if [[ ! -d "$test_dir" ]]; then
|
|
|
echo "测试目录不存在: $test_dir" >&2
|
|
|
exit 1
|
|
|
fi
|
|
|
|
|
|
compiler="./build/bin/compiler"
|
|
|
if [[ ! -x "$compiler" ]]; then
|
|
|
echo "未找到编译器: $compiler ,请先构建。" >&2
|
|
|
exit 1
|
|
|
fi
|
|
|
|
|
|
if ! command -v aarch64-linux-gnu-gcc >/dev/null 2>&1; then
|
|
|
echo "未找到 aarch64-linux-gnu-gcc,无法汇编/链接。" >&2
|
|
|
exit 1
|
|
|
fi
|
|
|
|
|
|
if ! command -v qemu-aarch64 >/dev/null 2>&1; then
|
|
|
echo "未找到 qemu-aarch64,无法运行生成的可执行文件。" >&2
|
|
|
exit 1
|
|
|
fi
|
|
|
|
|
|
sylib_c="sylib/sylib.c"
|
|
|
if [[ ! -f "$sylib_c" ]]; then
|
|
|
echo "未找到 sylib: $sylib_c" >&2
|
|
|
exit 1
|
|
|
fi
|
|
|
|
|
|
mkdir -p "$out_dir"
|
|
|
|
|
|
sylib_obj="$out_dir/sylib.o"
|
|
|
aarch64-linux-gnu-gcc -c "$sylib_c" -I sylib -o "$sylib_obj"
|
|
|
|
|
|
mapfile -t inputs < <(find "$test_dir" -type f -name '*.sy' | sort)
|
|
|
if [[ ${#inputs[@]} -eq 0 ]]; then
|
|
|
echo "测试目录下未找到 .sy 文件: $test_dir" >&2
|
|
|
exit 1
|
|
|
fi
|
|
|
|
|
|
failures=0
|
|
|
|
|
|
normalize() {
|
|
|
# strip CR, then strip a single trailing newline so both files
|
|
|
# are comparable regardless of CRLF / trailing-newline differences
|
|
|
tr -d '\r' < "$1" | sed -e '${ /^$/d; }' | perl -pe 'chomp if eof'
|
|
|
}
|
|
|
|
|
|
run_case() {
|
|
|
local input=$1
|
|
|
local input_dir base stem rel_path rel_dir case_out_dir asm_file exe
|
|
|
local stdin_file expected_file stdout_file actual_file status
|
|
|
|
|
|
input_dir=$(dirname "$input")
|
|
|
base=$(basename "$input")
|
|
|
stem=${base%.sy}
|
|
|
rel_path=${input#"$test_dir"/}
|
|
|
rel_dir=$(dirname "$rel_path")
|
|
|
case_out_dir="$out_dir"
|
|
|
if [[ "$rel_dir" != "." ]]; then
|
|
|
case_out_dir="$out_dir/$rel_dir"
|
|
|
fi
|
|
|
|
|
|
mkdir -p "$case_out_dir"
|
|
|
|
|
|
asm_file="$case_out_dir/$stem.s"
|
|
|
exe="$case_out_dir/$stem"
|
|
|
stdin_file="$input_dir/$stem.in"
|
|
|
expected_file="$input_dir/$stem.out"
|
|
|
stdout_file="$case_out_dir/$stem.stdout"
|
|
|
actual_file="$case_out_dir/$stem.actual.out"
|
|
|
|
|
|
if ! "$compiler" --emit-asm "$input" > "$asm_file" 2>"$case_out_dir/$stem.err"; then
|
|
|
echo "$stem: 编译失败"
|
|
|
cat "$case_out_dir/$stem.err" >&2
|
|
|
return 1
|
|
|
fi
|
|
|
|
|
|
if ! aarch64-linux-gnu-gcc "$asm_file" "$sylib_obj" -o "$exe" 2>"$case_out_dir/$stem.link.err"; then
|
|
|
echo "$stem: 链接失败"
|
|
|
cat "$case_out_dir/$stem.link.err" >&2
|
|
|
return 1
|
|
|
fi
|
|
|
|
|
|
set +e
|
|
|
if [[ -f "$stdin_file" ]]; then
|
|
|
qemu-aarch64 -L /usr/aarch64-linux-gnu "$exe" < "$stdin_file" > "$stdout_file"
|
|
|
else
|
|
|
qemu-aarch64 -L /usr/aarch64-linux-gnu "$exe" > "$stdout_file"
|
|
|
fi
|
|
|
status=$?
|
|
|
set -e
|
|
|
|
|
|
{
|
|
|
cat "$stdout_file"
|
|
|
if [[ -s "$stdout_file" ]] && (( $(tail -c 1 "$stdout_file" | wc -l) == 0 )); then
|
|
|
printf '\n'
|
|
|
fi
|
|
|
printf '%s\n' "$status"
|
|
|
} > "$actual_file"
|
|
|
|
|
|
if [[ -f "$expected_file" ]]; then
|
|
|
if diff <(normalize "$expected_file") <(normalize "$actual_file") >/dev/null 2>&1; then
|
|
|
echo "$stem: PASS"
|
|
|
return 0
|
|
|
else
|
|
|
echo "$stem: FAIL (退出码: $status)"
|
|
|
diff -u --strip-trailing-cr "$expected_file" "$actual_file" >&2 || true
|
|
|
return 1
|
|
|
fi
|
|
|
else
|
|
|
echo "$stem: SKIP (无预期输出, 退出码: $status)"
|
|
|
return 0
|
|
|
fi
|
|
|
}
|
|
|
|
|
|
for input in "${inputs[@]}"; do
|
|
|
if ! run_case "$input"; then
|
|
|
((failures+=1))
|
|
|
fi
|
|
|
done
|
|
|
|
|
|
total=${#inputs[@]}
|
|
|
passed=$((total - failures))
|
|
|
echo "总计: $total, 通过: $passed, 失败: $failures"
|
|
|
|
|
|
if (( failures > 0 )); then
|
|
|
exit 1
|
|
|
fi
|