merge: architecture into loops/haskell — Phases 7-16 complete + Phases 17-19 planned
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 53s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 53s
Brings the architecture branch (559 commits ahead — R7RS step 4-6, JIT expansion, host_error wrapping, bytecode compiler, etc.) into the loops/haskell line of work. Conflict in lib/haskell/conformance.sh: architecture replaced the inline driver with a thin wrapper delegating to lib/guest/conformance.sh + a config file. Resolved by taking the wrapper and extending lib/haskell/conformance.conf with all programs added under loops/haskell (caesar, runlength-str, showadt, showio, partial, statistics, newton, wordfreq, mapgraph, uniquewords, setops, shapes, person, config, counter, accumulate, safediv, trycatch) plus adding map.sx and set.sx to PRELOADS. plans/haskell-completeness.md gains three new follow-up phases: - Phase 17 — parser polish (`(x :: Int)` annotations, mid-file imports) - Phase 18 — one ambitious conformance program (lambda-calc / Dijkstra / JSON parser candidate list) - Phase 19 — conformance speed (batch all suites in one sx_server process to compress the 25-min run to single-digit minutes) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
96
lib/haskell/conformance.conf
Normal file
96
lib/haskell/conformance.conf
Normal file
@@ -0,0 +1,96 @@
|
||||
# Haskell-on-SX conformance config — sourced by lib/guest/conformance.sh.
|
||||
|
||||
LANG_NAME=haskell
|
||||
MODE=counters
|
||||
COUNTERS_PASS=hk-test-pass
|
||||
COUNTERS_FAIL=hk-test-fail
|
||||
TIMEOUT_PER_SUITE=120
|
||||
|
||||
PRELOADS=(
|
||||
lib/haskell/tokenizer.sx
|
||||
lib/haskell/layout.sx
|
||||
lib/haskell/parser.sx
|
||||
lib/haskell/desugar.sx
|
||||
lib/haskell/runtime.sx
|
||||
lib/haskell/match.sx
|
||||
lib/haskell/eval.sx
|
||||
lib/haskell/map.sx
|
||||
lib/haskell/set.sx
|
||||
lib/haskell/testlib.sx
|
||||
)
|
||||
|
||||
SUITES=(
|
||||
"fib:lib/haskell/tests/program-fib.sx"
|
||||
"sieve:lib/haskell/tests/program-sieve.sx"
|
||||
"quicksort:lib/haskell/tests/program-quicksort.sx"
|
||||
"nqueens:lib/haskell/tests/program-nqueens.sx"
|
||||
"calculator:lib/haskell/tests/program-calculator.sx"
|
||||
"collatz:lib/haskell/tests/program-collatz.sx"
|
||||
"palindrome:lib/haskell/tests/program-palindrome.sx"
|
||||
"maybe:lib/haskell/tests/program-maybe.sx"
|
||||
"fizzbuzz:lib/haskell/tests/program-fizzbuzz.sx"
|
||||
"anagram:lib/haskell/tests/program-anagram.sx"
|
||||
"roman:lib/haskell/tests/program-roman.sx"
|
||||
"binary:lib/haskell/tests/program-binary.sx"
|
||||
"either:lib/haskell/tests/program-either.sx"
|
||||
"primes:lib/haskell/tests/program-primes.sx"
|
||||
"zipwith:lib/haskell/tests/program-zipwith.sx"
|
||||
"matrix:lib/haskell/tests/program-matrix.sx"
|
||||
"wordcount:lib/haskell/tests/program-wordcount.sx"
|
||||
"powers:lib/haskell/tests/program-powers.sx"
|
||||
"caesar:lib/haskell/tests/program-caesar.sx"
|
||||
"runlength-str:lib/haskell/tests/program-runlength-str.sx"
|
||||
"showadt:lib/haskell/tests/program-showadt.sx"
|
||||
"showio:lib/haskell/tests/program-showio.sx"
|
||||
"partial:lib/haskell/tests/program-partial.sx"
|
||||
"statistics:lib/haskell/tests/program-statistics.sx"
|
||||
"newton:lib/haskell/tests/program-newton.sx"
|
||||
"wordfreq:lib/haskell/tests/program-wordfreq.sx"
|
||||
"mapgraph:lib/haskell/tests/program-mapgraph.sx"
|
||||
"uniquewords:lib/haskell/tests/program-uniquewords.sx"
|
||||
"setops:lib/haskell/tests/program-setops.sx"
|
||||
"shapes:lib/haskell/tests/program-shapes.sx"
|
||||
"person:lib/haskell/tests/program-person.sx"
|
||||
"config:lib/haskell/tests/program-config.sx"
|
||||
"counter:lib/haskell/tests/program-counter.sx"
|
||||
"accumulate:lib/haskell/tests/program-accumulate.sx"
|
||||
"safediv:lib/haskell/tests/program-safediv.sx"
|
||||
"trycatch:lib/haskell/tests/program-trycatch.sx"
|
||||
)
|
||||
|
||||
emit_scoreboard_json() {
|
||||
local n=${#GC_NAMES[@]} i sep date_only
|
||||
date_only=$(date '+%Y-%m-%d')
|
||||
printf '{\n'
|
||||
printf ' "date": "%s",\n' "$date_only"
|
||||
printf ' "total_pass": %d,\n' "$GC_TOTAL_PASS"
|
||||
printf ' "total_fail": %d,\n' "$GC_TOTAL_FAIL"
|
||||
printf ' "programs": {\n'
|
||||
for ((i=0; i<n; i++)); do
|
||||
sep=","; [ $i -eq $((n-1)) ] && sep=""
|
||||
printf ' "%s": {"pass": %d, "fail": %d}%s\n' \
|
||||
"${GC_NAMES[$i]}" "${GC_PASS[$i]}" "${GC_FAIL[$i]}" "$sep"
|
||||
done
|
||||
printf ' }\n'
|
||||
printf '}\n'
|
||||
}
|
||||
|
||||
emit_scoreboard_md() {
|
||||
local n=${#GC_NAMES[@]}
|
||||
local i status p f t prog_pass=0 prog_total=$n date_only
|
||||
date_only=$(date '+%Y-%m-%d')
|
||||
for ((i=0; i<n; i++)); do
|
||||
[ "${GC_FAIL[$i]}" -eq 0 ] && prog_pass=$((prog_pass + 1))
|
||||
done
|
||||
printf '# Haskell-on-SX Scoreboard\n\n'
|
||||
printf 'Updated %s · Phase 6 (prelude extras + 18 programs)\n\n' "$date_only"
|
||||
printf '| Program | Tests | Status |\n'
|
||||
printf '|---------|-------|--------|\n'
|
||||
for ((i=0; i<n; i++)); do
|
||||
p=${GC_PASS[$i]}; f=${GC_FAIL[$i]}; t=${GC_TOTAL_S[$i]}
|
||||
[ "$f" -eq 0 ] && status="✓" || status="✗"
|
||||
printf '| %s.hs | %d/%d | %s |\n' "${GC_NAMES[$i]}" "$p" "$t" "$status"
|
||||
done
|
||||
printf '| **Total** | **%d/%d** | **%d/%d programs** |\n' \
|
||||
"$GC_TOTAL_PASS" "$GC_TOTAL" "$prog_pass" "$prog_total"
|
||||
}
|
||||
@@ -1,142 +1,3 @@
|
||||
#!/usr/bin/env bash
|
||||
# lib/haskell/conformance.sh — run the classic-program test suites.
|
||||
# Writes lib/haskell/scoreboard.json and lib/haskell/scoreboard.md.
|
||||
#
|
||||
# Usage:
|
||||
# bash lib/haskell/conformance.sh # run + write scoreboards
|
||||
# bash lib/haskell/conformance.sh --check # run only, exit 1 on failure
|
||||
|
||||
set -euo pipefail
|
||||
cd "$(git rev-parse --show-toplevel)"
|
||||
|
||||
SX_SERVER="hosts/ocaml/_build/default/bin/sx_server.exe"
|
||||
if [ ! -x "$SX_SERVER" ]; then
|
||||
MAIN_ROOT=$(git worktree list | head -1 | awk '{print $1}')
|
||||
if [ -x "$MAIN_ROOT/$SX_SERVER" ]; then
|
||||
SX_SERVER="$MAIN_ROOT/$SX_SERVER"
|
||||
else
|
||||
echo "ERROR: sx_server.exe not found. Run: cd hosts/ocaml && dune build"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
PROGRAMS=(fib sieve quicksort nqueens calculator collatz palindrome maybe fizzbuzz anagram roman binary either primes zipwith matrix wordcount powers caesar runlength-str showadt showio partial statistics newton wordfreq mapgraph uniquewords setops shapes person config counter accumulate safediv trycatch)
|
||||
PASS_COUNTS=()
|
||||
FAIL_COUNTS=()
|
||||
|
||||
run_suite() {
|
||||
local prog="$1"
|
||||
local FILE="lib/haskell/tests/program-${prog}.sx"
|
||||
local TMPFILE
|
||||
TMPFILE=$(mktemp)
|
||||
cat > "$TMPFILE" <<EPOCHS
|
||||
(epoch 1)
|
||||
(load "lib/haskell/tokenizer.sx")
|
||||
(load "lib/haskell/layout.sx")
|
||||
(load "lib/haskell/parser.sx")
|
||||
(load "lib/haskell/desugar.sx")
|
||||
(load "lib/haskell/runtime.sx")
|
||||
(load "lib/haskell/match.sx")
|
||||
(load "lib/haskell/eval.sx")
|
||||
(load "lib/haskell/map.sx")
|
||||
(load "lib/haskell/set.sx")
|
||||
(load "lib/haskell/testlib.sx")
|
||||
(epoch 2)
|
||||
(load "$FILE")
|
||||
(epoch 3)
|
||||
(eval "(list hk-test-pass hk-test-fail)")
|
||||
EPOCHS
|
||||
local OUTPUT
|
||||
OUTPUT=$(timeout 120 "$SX_SERVER" < "$TMPFILE" 2>&1 || true)
|
||||
rm -f "$TMPFILE"
|
||||
|
||||
local LINE
|
||||
LINE=$(echo "$OUTPUT" | awk '/^\(ok-len 3 / {getline; print; exit}')
|
||||
if [ -z "$LINE" ]; then
|
||||
LINE=$(echo "$OUTPUT" | grep -E '^\(ok 3 \([0-9]+ [0-9]+\)\)' | tail -1 \
|
||||
| sed -E 's/^\(ok 3 //; s/\)$//' || true)
|
||||
fi
|
||||
if [ -z "$LINE" ]; then
|
||||
echo "0 1"
|
||||
else
|
||||
local P F
|
||||
P=$(echo "$LINE" | sed -E 's/^\(([0-9]+) ([0-9]+)\).*/\1/' || echo "0")
|
||||
F=$(echo "$LINE" | sed -E 's/^\(([0-9]+) ([0-9]+)\).*/\2/' || echo "1")
|
||||
echo "$P $F"
|
||||
fi
|
||||
}
|
||||
|
||||
for prog in "${PROGRAMS[@]}"; do
|
||||
RESULT=$(run_suite "$prog")
|
||||
P=$(echo "$RESULT" | cut -d' ' -f1)
|
||||
F=$(echo "$RESULT" | cut -d' ' -f2)
|
||||
PASS_COUNTS+=("$P")
|
||||
FAIL_COUNTS+=("$F")
|
||||
T=$((P + F))
|
||||
if [ "$F" -eq 0 ]; then
|
||||
printf '✓ %-14s %d/%d\n' "${prog}.hs" "$P" "$T"
|
||||
else
|
||||
printf '✗ %-14s %d/%d\n' "${prog}.hs" "$P" "$T"
|
||||
fi
|
||||
done
|
||||
|
||||
TOTAL_PASS=0
|
||||
TOTAL_FAIL=0
|
||||
PROG_PASS=0
|
||||
for i in "${!PROGRAMS[@]}"; do
|
||||
TOTAL_PASS=$((TOTAL_PASS + PASS_COUNTS[i]))
|
||||
TOTAL_FAIL=$((TOTAL_FAIL + FAIL_COUNTS[i]))
|
||||
[ "${FAIL_COUNTS[$i]}" -eq 0 ] && PROG_PASS=$((PROG_PASS + 1))
|
||||
done
|
||||
PROG_TOTAL=${#PROGRAMS[@]}
|
||||
|
||||
echo ""
|
||||
echo "Classic programs: ${TOTAL_PASS}/$((TOTAL_PASS + TOTAL_FAIL)) tests | ${PROG_PASS}/${PROG_TOTAL} programs passing"
|
||||
|
||||
if [[ "${1:-}" == "--check" ]]; then
|
||||
[ $TOTAL_FAIL -eq 0 ]
|
||||
exit $?
|
||||
fi
|
||||
|
||||
DATE=$(date '+%Y-%m-%d')
|
||||
|
||||
# scoreboard.json
|
||||
{
|
||||
printf '{\n'
|
||||
printf ' "date": "%s",\n' "$DATE"
|
||||
printf ' "total_pass": %d,\n' "$TOTAL_PASS"
|
||||
printf ' "total_fail": %d,\n' "$TOTAL_FAIL"
|
||||
printf ' "programs": {\n'
|
||||
last=$((${#PROGRAMS[@]} - 1))
|
||||
for i in "${!PROGRAMS[@]}"; do
|
||||
prog="${PROGRAMS[$i]}"
|
||||
if [ $i -lt $last ]; then
|
||||
printf ' "%s": {"pass": %d, "fail": %d},\n' "$prog" "${PASS_COUNTS[$i]}" "${FAIL_COUNTS[$i]}"
|
||||
else
|
||||
printf ' "%s": {"pass": %d, "fail": %d}\n' "$prog" "${PASS_COUNTS[$i]}" "${FAIL_COUNTS[$i]}"
|
||||
fi
|
||||
done
|
||||
printf ' }\n'
|
||||
printf '}\n'
|
||||
} > lib/haskell/scoreboard.json
|
||||
|
||||
# scoreboard.md
|
||||
{
|
||||
printf '# Haskell-on-SX Scoreboard\n\n'
|
||||
printf 'Updated %s · Phase 6 (prelude extras + 18 programs)\n\n' "$DATE"
|
||||
printf '| Program | Tests | Status |\n'
|
||||
printf '|---------|-------|--------|\n'
|
||||
for i in "${!PROGRAMS[@]}"; do
|
||||
prog="${PROGRAMS[$i]}"
|
||||
P=${PASS_COUNTS[$i]}
|
||||
F=${FAIL_COUNTS[$i]}
|
||||
T=$((P + F))
|
||||
[ "$F" -eq 0 ] && STATUS="✓" || STATUS="✗"
|
||||
printf '| %s | %d/%d | %s |\n' "${prog}.hs" "$P" "$T" "$STATUS"
|
||||
done
|
||||
printf '| **Total** | **%d/%d** | **%d/%d programs** |\n' \
|
||||
"$TOTAL_PASS" "$((TOTAL_PASS + TOTAL_FAIL))" "$PROG_PASS" "$PROG_TOTAL"
|
||||
} > lib/haskell/scoreboard.md
|
||||
|
||||
echo "Wrote lib/haskell/scoreboard.json and lib/haskell/scoreboard.md"
|
||||
[ $TOTAL_FAIL -eq 0 ]
|
||||
# Thin wrapper — see lib/guest/conformance.sh and lib/haskell/conformance.conf.
|
||||
exec bash "$(dirname "$0")/../guest/conformance.sh" "$(dirname "$0")/conformance.conf" "$@"
|
||||
|
||||
Reference in New Issue
Block a user