lumbda/tests/portal-cross-test.sh
russell@unturf.com 57f3c9fab1 asm/c/py: add (load), ports, write-file/file->string — full cross-impl parity
Asm gains the file I/O surface Python and C already had, unlocking
9/9 cells of the portal producer×consumer matrix (previously 6/9).

asm:
- (load "path") — mmaps file, swaps input source, loops scheme_read+eval,
  restores on exit. Nestable. Uses SYS_LSEEK + SYS_MUNMAP.
- Output ports: (open-output-file), (close-port), (port?). Encoded as
  SPECIAL values ≥ 1000 (fd = (val>>3) − PORT_SPECIAL_BASE), no tag-bit
  expansion needed.
- (display), (write), (newline) accept optional port arg; printer
  writes via output_fd global, swapped by port-aware builtins.
- (write-file path content) / (file->string path) — bytes in/out.

c, py: (write-file) / (file->string) added for parity.

tests: 131 asm (up 23), 189 functional (up 8, shared py+c),
tests/portal-cross-test.sh exercises 3×3 save×load matrix.
2026-04-16 16:37:40 -04:00

73 lines
2.5 KiB
Bash
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# portal-cross-test.sh — Exercise the full save×load matrix
# across Python, C, and asm using the S-expression portal.
#
# Each implementation must be able to:
# 1. Write a portable .sexp file
# 2. Read a .sexp file written by any other implementation
#
# Result: 3x3 = 9 combinations. 7 are tested here (Python and C
# have built-in (load); asm gained (load) in commit on 2026-04-16,
# so it participates as both producer and consumer).
set -e
cd "$(dirname "$0")/.."
PY="python3 uncommonlisp.py --fast"
C="./c/uncommonlisp"
ASM="./asm/uncommonlisp"
SEXP=/tmp/portal-xtest.sexp
PASS=0
FAIL=0
verify() {
local label="$1" output="$2"
if echo "$output" | grep -q "PASS:"; then
PASS=$((PASS + 1))
printf " %-30s OK\n" "$label"
else
FAIL=$((FAIL + 1))
printf " %-30s FAIL\n" "$label"
echo "----- output:"
echo "$output"
echo "-----"
fi
}
echo "═══════════════════════════════════════════════════════"
echo "Portal cross-impl exchange (S-expression format)"
echo "═══════════════════════════════════════════════════════"
for PRODUCER in "Python|$PY tests/portal-cross-save.lsp" \
"C|$C tests/portal-cross-save.lsp" \
"Asm|$ASM < tests/portal-cross-save.lsp"; do
P_NAME="${PRODUCER%%|*}"
P_CMD="${PRODUCER#*|}"
echo
echo "── producer: $P_NAME ──"
rm -f "$SEXP"
# portal-cross-save writes to /tmp/cross.sexp; copy out to our slot
eval "$P_CMD" >/dev/null 2>&1
cp /tmp/cross.sexp "$SEXP"
for CONSUMER in "Python|$PY tests/portal-cross-load.lsp" \
"C|$C tests/portal-cross-load.lsp" \
"Asm|$ASM < tests/portal-cross-load.lsp"; do
C_NAME="${CONSUMER%%|*}"
C_CMD="${CONSUMER#*|}"
# Regenerate /tmp/cross.sexp from our slot (portal-cross-load reads it)
cp "$SEXP" /tmp/cross.sexp
OUTPUT=$(eval "$C_CMD" 2>&1)
verify "$P_NAME$C_NAME" "$OUTPUT"
done
done
rm -f "$SEXP" /tmp/cross.sexp
echo
echo "═══════════════════════════════════════════════════════"
echo "Cross-impl portal: $PASS passed, $FAIL failed"
if [ $FAIL -ne 0 ]; then
exit 1
fi