Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 52s
Idents, ctors, 51 keywords, numbers (int/float/hex/exp/underscored), strings + chars with escapes, type variables, 26 op/punct tokens, and nested (* ... *) block comments. Tests via epoch protocol against sx_server.exe.
291 lines
9.4 KiB
Bash
Executable File
291 lines
9.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Fast OCaml-on-SX test runner — epoch protocol direct to sx_server.exe.
|
|
# Mirrors lib/lua/test.sh.
|
|
#
|
|
# Usage:
|
|
# bash lib/ocaml/test.sh # run all tests
|
|
# bash lib/ocaml/test.sh -v # verbose
|
|
|
|
set -uo pipefail
|
|
cd "$(git rev-parse --show-toplevel)"
|
|
|
|
SX_SERVER="${SX_SERVER:-hosts/ocaml/_build/default/bin/sx_server.exe}"
|
|
if [ ! -x "$SX_SERVER" ]; then
|
|
SX_SERVER="/root/rose-ash/hosts/ocaml/_build/default/bin/sx_server.exe"
|
|
fi
|
|
if [ ! -x "$SX_SERVER" ]; then
|
|
echo "ERROR: sx_server.exe not found. Run: cd hosts/ocaml && dune build"
|
|
exit 1
|
|
fi
|
|
|
|
VERBOSE="${1:-}"
|
|
PASS=0
|
|
FAIL=0
|
|
ERRORS=""
|
|
TMPFILE=$(mktemp)
|
|
trap "rm -f $TMPFILE" EXIT
|
|
|
|
cat > "$TMPFILE" << 'EPOCHS'
|
|
(epoch 1)
|
|
(load "lib/guest/lex.sx")
|
|
(load "lib/guest/prefix.sx")
|
|
(load "lib/ocaml/tokenizer.sx")
|
|
(load "lib/ocaml/tests/tokenize.sx")
|
|
|
|
;; ── empty / eof ────────────────────────────────────────────────
|
|
(epoch 100)
|
|
(eval "(ocaml-test-tok-count \"\")")
|
|
(epoch 101)
|
|
(eval "(ocaml-test-tok-type \"\" 0)")
|
|
|
|
;; ── numbers ────────────────────────────────────────────────────
|
|
(epoch 110)
|
|
(eval "(ocaml-test-tok-type \"42\" 0)")
|
|
(epoch 111)
|
|
(eval "(ocaml-test-tok-value \"42\" 0)")
|
|
(epoch 112)
|
|
(eval "(ocaml-test-tok-value \"3.14\" 0)")
|
|
(epoch 113)
|
|
(eval "(ocaml-test-tok-value \"0xff\" 0)")
|
|
(epoch 114)
|
|
(eval "(ocaml-test-tok-value \"1e3\" 0)")
|
|
(epoch 115)
|
|
(eval "(ocaml-test-tok-value \"1_000_000\" 0)")
|
|
(epoch 116)
|
|
(eval "(ocaml-test-tok-value \"3.14e-2\" 0)")
|
|
|
|
;; ── identifiers / constructors / keywords ─────────────────────
|
|
(epoch 120)
|
|
(eval "(ocaml-test-tok-type \"foo\" 0)")
|
|
(epoch 121)
|
|
(eval "(ocaml-test-tok-value \"foo_bar1\" 0)")
|
|
(epoch 122)
|
|
(eval "(ocaml-test-tok-type \"Some\" 0)")
|
|
(epoch 123)
|
|
(eval "(ocaml-test-tok-value \"Some\" 0)")
|
|
(epoch 124)
|
|
(eval "(ocaml-test-tok-type \"let\" 0)")
|
|
(epoch 125)
|
|
(eval "(ocaml-test-tok-value \"match\" 0)")
|
|
(epoch 126)
|
|
(eval "(ocaml-test-tok-type \"true\" 0)")
|
|
(epoch 127)
|
|
(eval "(ocaml-test-tok-value \"false\" 0)")
|
|
(epoch 128)
|
|
(eval "(ocaml-test-tok-value \"name'\" 0)")
|
|
|
|
;; ── strings ────────────────────────────────────────────────────
|
|
(epoch 130)
|
|
(eval "(ocaml-test-tok-type \"\\\"hi\\\"\" 0)")
|
|
(epoch 131)
|
|
(eval "(ocaml-test-tok-value \"\\\"hi\\\"\" 0)")
|
|
(epoch 132)
|
|
(eval "(ocaml-test-tok-value \"\\\"a\\\\nb\\\"\" 0)")
|
|
|
|
;; ── chars ──────────────────────────────────────────────────────
|
|
(epoch 140)
|
|
(eval "(ocaml-test-tok-type \"'a'\" 0)")
|
|
(epoch 141)
|
|
(eval "(ocaml-test-tok-value \"'a'\" 0)")
|
|
(epoch 142)
|
|
(eval "(ocaml-test-tok-value \"'\\\\n'\" 0)")
|
|
|
|
;; ── type variables ─────────────────────────────────────────────
|
|
(epoch 145)
|
|
(eval "(ocaml-test-tok-type \"'a\" 0)")
|
|
(epoch 146)
|
|
(eval "(ocaml-test-tok-value \"'a\" 0)")
|
|
|
|
;; ── multi-char operators ───────────────────────────────────────
|
|
(epoch 150)
|
|
(eval "(ocaml-test-tok-value \"->\" 0)")
|
|
(epoch 151)
|
|
(eval "(ocaml-test-tok-value \"|>\" 0)")
|
|
(epoch 152)
|
|
(eval "(ocaml-test-tok-value \"<-\" 0)")
|
|
(epoch 153)
|
|
(eval "(ocaml-test-tok-value \":=\" 0)")
|
|
(epoch 154)
|
|
(eval "(ocaml-test-tok-value \"::\" 0)")
|
|
(epoch 155)
|
|
(eval "(ocaml-test-tok-value \";;\" 0)")
|
|
(epoch 156)
|
|
(eval "(ocaml-test-tok-value \"@@\" 0)")
|
|
(epoch 157)
|
|
(eval "(ocaml-test-tok-value \"<>\" 0)")
|
|
(epoch 158)
|
|
(eval "(ocaml-test-tok-value \"&&\" 0)")
|
|
(epoch 159)
|
|
(eval "(ocaml-test-tok-value \"||\" 0)")
|
|
|
|
;; ── single-char punctuation ────────────────────────────────────
|
|
(epoch 160)
|
|
(eval "(ocaml-test-tok-value \"+\" 0)")
|
|
(epoch 161)
|
|
(eval "(ocaml-test-tok-value \"|\" 0)")
|
|
(epoch 162)
|
|
(eval "(ocaml-test-tok-value \";\" 0)")
|
|
(epoch 163)
|
|
(eval "(ocaml-test-tok-value \"(\" 0)")
|
|
(epoch 164)
|
|
(eval "(ocaml-test-tok-value \"!\" 0)")
|
|
(epoch 165)
|
|
(eval "(ocaml-test-tok-value \"@\" 0)")
|
|
|
|
;; ── comments ───────────────────────────────────────────────────
|
|
(epoch 170)
|
|
(eval "(ocaml-test-tok-count \"(* hi *)\")")
|
|
(epoch 171)
|
|
(eval "(ocaml-test-tok-value \"(* c *) 42\" 0)")
|
|
(epoch 172)
|
|
(eval "(ocaml-test-tok-count \"(* outer (* inner *) end *) 1\")")
|
|
(epoch 173)
|
|
(eval "(ocaml-test-tok-value \"(* outer (* inner *) end *) 1\" 0)")
|
|
|
|
;; ── compound expressions ───────────────────────────────────────
|
|
(epoch 180)
|
|
(eval "(ocaml-test-tok-count \"let x = 1\")")
|
|
(epoch 181)
|
|
(eval "(ocaml-test-tok-type \"let x = 1\" 0)")
|
|
(epoch 182)
|
|
(eval "(ocaml-test-tok-value \"let x = 1\" 0)")
|
|
(epoch 183)
|
|
(eval "(ocaml-test-tok-type \"let x = 1\" 1)")
|
|
(epoch 184)
|
|
(eval "(ocaml-test-tok-value \"let x = 1\" 2)")
|
|
(epoch 185)
|
|
(eval "(ocaml-test-tok-value \"let x = 1\" 3)")
|
|
|
|
(epoch 190)
|
|
(eval "(ocaml-test-tok-count \"match x with | None -> 0 | Some y -> y\")")
|
|
(epoch 191)
|
|
(eval "(ocaml-test-tok-value \"fun x -> x + 1\" 2)")
|
|
(epoch 192)
|
|
(eval "(ocaml-test-tok-type \"fun x -> x + 1\" 2)")
|
|
(epoch 193)
|
|
(eval "(ocaml-test-tok-type \"Some 42\" 0)")
|
|
(epoch 194)
|
|
(eval "(ocaml-test-tok-value \"a |> f |> g\" 1)")
|
|
(epoch 195)
|
|
(eval "(ocaml-test-tok-value \"x := !y\" 1)")
|
|
|
|
EPOCHS
|
|
|
|
OUTPUT=$(timeout 60 "$SX_SERVER" < "$TMPFILE" 2>/dev/null)
|
|
|
|
check() {
|
|
local epoch="$1" desc="$2" expected="$3"
|
|
local actual
|
|
actual=$(echo "$OUTPUT" | grep -A1 "^(ok-len $epoch " | tail -1)
|
|
if [ -z "$actual" ]; then
|
|
actual=$(echo "$OUTPUT" | grep "^(ok $epoch " || true)
|
|
fi
|
|
if [ -z "$actual" ]; then
|
|
actual=$(echo "$OUTPUT" | grep "^(error $epoch " || true)
|
|
fi
|
|
if [ -z "$actual" ]; then
|
|
actual="<no output for epoch $epoch>"
|
|
fi
|
|
|
|
if echo "$actual" | grep -qF -- "$expected"; then
|
|
PASS=$((PASS + 1))
|
|
[ "$VERBOSE" = "-v" ] && echo " ok $desc"
|
|
else
|
|
FAIL=$((FAIL + 1))
|
|
ERRORS+=" FAIL $desc (epoch $epoch)
|
|
expected: $expected
|
|
actual: $actual
|
|
"
|
|
fi
|
|
}
|
|
|
|
# empty / eof
|
|
check 100 "empty tokens length" '1'
|
|
check 101 "empty first is eof" '"eof"'
|
|
|
|
# numbers
|
|
check 110 "int type" '"number"'
|
|
check 111 "int value" '42'
|
|
check 112 "float value" '3.14'
|
|
check 113 "hex value" '255'
|
|
check 114 "exponent" '1000'
|
|
check 115 "underscored int" '1000000'
|
|
check 116 "neg exponent" '0.0314'
|
|
|
|
# idents / ctors / keywords
|
|
check 120 "ident type" '"ident"'
|
|
check 121 "ident value" '"foo_bar1"'
|
|
check 122 "ctor type" '"ctor"'
|
|
check 123 "ctor value" '"Some"'
|
|
check 124 "let keyword type" '"keyword"'
|
|
check 125 "match keyword value" '"match"'
|
|
check 126 "true is keyword" '"keyword"'
|
|
check 127 "false value" '"false"'
|
|
check 128 "primed ident" "\"name'\""
|
|
|
|
# strings
|
|
check 130 "string type" '"string"'
|
|
check 131 "string value" '"hi"'
|
|
check 132 "escape sequence" '"a'
|
|
|
|
# chars
|
|
check 140 "char type" '"char"'
|
|
check 141 "char value" '"a"'
|
|
check 142 "char escape" '"'
|
|
|
|
# tyvars
|
|
check 145 "tyvar type" '"tyvar"'
|
|
check 146 "tyvar value" '"a"'
|
|
|
|
# multi-char ops
|
|
check 150 "->" '"->"'
|
|
check 151 "|>" '"|>"'
|
|
check 152 "<-" '"<-"'
|
|
check 153 ":=" '":="'
|
|
check 154 "::" '"::"'
|
|
check 155 ";;" '";;"'
|
|
check 156 "@@" '"@@"'
|
|
check 157 "<>" '"<>"'
|
|
check 158 "&&" '"&&"'
|
|
check 159 "||" '"||"'
|
|
|
|
# single ops
|
|
check 160 "+" '"+"'
|
|
check 161 "|" '"|"'
|
|
check 162 ";" '";"'
|
|
check 163 "(" '"("'
|
|
check 164 "!" '"!"'
|
|
check 165 "@" '"@"'
|
|
|
|
# comments
|
|
check 170 "block comment alone -> eof" '1'
|
|
check 171 "num after block comment" '42'
|
|
check 172 "nested comment count" '2'
|
|
check 173 "nested comment value" '1'
|
|
|
|
# compound
|
|
check 180 "let x = 1 count" '5'
|
|
check 181 "let is keyword" '"keyword"'
|
|
check 182 "let value" '"let"'
|
|
check 183 "x is ident" '"ident"'
|
|
check 184 "= value" '"="'
|
|
check 185 "1 value" '1'
|
|
|
|
check 190 "match expr count" '13'
|
|
check 191 "fun -> arrow value" '"->"'
|
|
check 192 "fun -> arrow type" '"op"'
|
|
check 193 "Some is ctor" '"ctor"'
|
|
check 194 "first |> value" '"|>"'
|
|
check 195 "ref assign :=" '":="'
|
|
|
|
TOTAL=$((PASS + FAIL))
|
|
if [ $FAIL -eq 0 ]; then
|
|
echo "ok $PASS/$TOTAL OCaml-on-SX tokenizer tests passed"
|
|
else
|
|
echo "FAIL $PASS/$TOTAL passed, $FAIL failed:"
|
|
echo ""
|
|
echo "$ERRORS"
|
|
fi
|
|
|
|
[ $FAIL -eq 0 ]
|