You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nudt-compiler-cpp/scripts/lab1_build_test.sh

194 lines
4.7 KiB

#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
COMPILER="$REPO_ROOT/build/bin/compiler"
ANTLR_JAR="$REPO_ROOT/third_party/antlr-4.13.2-complete.jar"
RUN_ROOT="$REPO_ROOT/output/logs/lab1"
RUN_NAME="lab1_$(date +%Y%m%d_%H%M%S)"
RUN_DIR="$RUN_ROOT/$RUN_NAME"
WHOLE_LOG="$RUN_DIR/whole.log"
FAIL_DIR="$RUN_DIR/failures"
LEGACY_SAVE_TREE=false
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
TEST_DIRS=()
while [[ $# -gt 0 ]]; do
case "$1" in
--save-tree)
LEGACY_SAVE_TREE=true
;;
*)
TEST_DIRS+=("$1")
;;
esac
shift
done
mkdir -p "$RUN_DIR"
: > "$WHOLE_LOG"
log_plain() {
printf '%s\n' "$*"
printf '%s\n' "$*" >> "$WHOLE_LOG"
}
log_color() {
local color="$1"
shift
local message="$*"
printf '%b%s%b\n' "$color" "$message" "$NC"
printf '%s\n' "$message" >> "$WHOLE_LOG"
}
append_file_to_whole_log() {
local title="$1"
local file="$2"
{
printf '\n===== %s =====\n' "$title"
cat "$file"
printf '\n'
} >> "$WHOLE_LOG"
}
cleanup_tmp_dir() {
local dir="$1"
if [[ -d "$dir" ]]; then
rm -rf "$dir"
fi
}
discover_default_test_dirs() {
local roots=(
"$REPO_ROOT/test/test_case"
"$REPO_ROOT/test/class_test_case"
)
local root
for root in "${roots[@]}"; do
[[ -d "$root" ]] || continue
find "$root" -mindepth 1 -maxdepth 1 -type d -print0
done | sort -z
}
prune_empty_run_dirs() {
if [[ -d "$RUN_DIR/.tmp" ]]; then
rmdir "$RUN_DIR/.tmp" 2>/dev/null || true
fi
if [[ -d "$FAIL_DIR" ]]; then
rmdir "$FAIL_DIR" 2>/dev/null || true
fi
}
if [[ ${#TEST_DIRS[@]} -eq 0 ]]; then
while IFS= read -r -d '' test_dir; do
TEST_DIRS+=("$test_dir")
done < <(discover_default_test_dirs)
fi
log_plain "Run directory: $RUN_DIR"
log_plain "Whole log: $WHOLE_LOG"
if [[ "$LEGACY_SAVE_TREE" == true ]]; then
log_color "$YELLOW" "Warning: --save-tree is deprecated; successful case artifacts will still be deleted."
fi
log_plain "==> [1/3] Generate ANTLR Lexer/Parser"
mkdir -p "$REPO_ROOT/build/generated/antlr4"
if ! java -jar "$ANTLR_JAR" \
-Dlanguage=Cpp \
-visitor -no-listener \
-Xexact-output-dir \
-o "$REPO_ROOT/build/generated/antlr4" \
"$REPO_ROOT/src/antlr4/SysY.g4" >> "$WHOLE_LOG" 2>&1; then
log_color "$RED" "ANTLR generation failed. See $WHOLE_LOG"
exit 1
fi
log_plain "==> [2/3] Configure and build parse-only compiler"
if ! cmake -S "$REPO_ROOT" -B "$REPO_ROOT/build" -DCMAKE_BUILD_TYPE=Release -DCOMPILER_PARSE_ONLY=ON >> "$WHOLE_LOG" 2>&1; then
log_color "$RED" "CMake configure failed. See $WHOLE_LOG"
exit 1
fi
if ! cmake --build "$REPO_ROOT/build" -j "$(nproc)" >> "$WHOLE_LOG" 2>&1; then
log_color "$RED" "Compiler build failed. See $WHOLE_LOG"
exit 1
fi
log_plain "==> [3/3] Run parse validation suite"
PASS=0
FAIL=0
FAIL_LIST=()
test_one() {
local sy_file="$1"
local rel="$2"
local safe_name="${rel//\//_}"
local case_key="${safe_name%.sy}"
local tmp_dir="$RUN_DIR/.tmp/$case_key"
local fail_case_dir="$FAIL_DIR/$case_key"
local tree_file="$tmp_dir/parse.tree"
local case_log="$tmp_dir/error.log"
cleanup_tmp_dir "$tmp_dir"
cleanup_tmp_dir "$fail_case_dir"
mkdir -p "$tmp_dir"
if "$COMPILER" --emit-parse-tree "$sy_file" > "$tree_file" 2> "$case_log"; then
cleanup_tmp_dir "$tmp_dir"
return 0
fi
mkdir -p "$FAIL_DIR"
{
printf 'Command: %s --emit-parse-tree %s\n' "$COMPILER" "$sy_file"
if [[ -s "$case_log" ]]; then
printf '\n'
cat "$case_log"
fi
} > "$tmp_dir/error.log.tmp"
mv "$tmp_dir/error.log.tmp" "$case_log"
mv "$tmp_dir" "$fail_case_dir"
append_file_to_whole_log "$rel" "$fail_case_dir/error.log"
return 1
}
for test_dir in "${TEST_DIRS[@]}"; do
if [[ ! -d "$test_dir" ]]; then
log_color "$YELLOW" "skip missing dir: $test_dir"
continue
fi
while IFS= read -r -d '' sy_file; do
rel="$(realpath --relative-to="$REPO_ROOT" "$sy_file")"
if test_one "$sy_file" "$rel"; then
log_color "$GREEN" "PASS $rel"
PASS=$((PASS + 1))
else
log_color "$RED" "FAIL $rel"
FAIL=$((FAIL + 1))
FAIL_LIST+=("$rel")
fi
done < <(find "$test_dir" -maxdepth 1 -type f -name '*.sy' -print0 | sort -z)
done
prune_empty_run_dirs
log_plain ""
log_plain "summary: ${PASS} PASS / ${FAIL} FAIL / total $((PASS + FAIL))"
if [[ ${#FAIL_LIST[@]} -gt 0 ]]; then
log_plain "failed cases:"
for f in "${FAIL_LIST[@]}"; do
safe_name="${f//\//_}"
log_plain "- $f"
log_plain " artifacts: $FAIL_DIR/${safe_name%.sy}"
done
else
log_plain "all successful case artifacts have been deleted automatically."
fi
log_plain "whole log saved to: $WHOLE_LOG"
[[ $FAIL -eq 0 ]]