Salvaged from worktree-agent-* branches killed during sx-tree MCP outage: - lua: tokenizer + parser + phase-2 transpile (~157 tests) - prolog: tokenizer + parser + unification (72 tests, plan update lost to WIP) - forth: phase-1 reader/interpreter + phase-2 colon/VARIABLE (134 tests) - erlang: tokenizer + parser (114 tests) - haskell: tokenizer + parse tests (43 tests) Cherry-picked file contents only, not branch history, to avoid pulling in unrelated ocaml-vm merge commits that were in those branches' bases.
646 lines
23 KiB
Bash
Executable File
646 lines
23 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Fast Lua-on-SX test runner — epoch protocol direct to sx_server.exe.
|
|
# Mirrors lib/js/test.sh.
|
|
#
|
|
# Usage:
|
|
# bash lib/lua/test.sh # run all tests
|
|
# bash lib/lua/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
|
|
# fallback to main repo binary when running from a worktree without _build
|
|
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/lua/tokenizer.sx")
|
|
(epoch 2)
|
|
(load "lib/lua/parser.sx")
|
|
(epoch 3)
|
|
(load "lib/lua/runtime.sx")
|
|
(epoch 4)
|
|
(load "lib/lua/transpile.sx")
|
|
|
|
;; ── Phase 1: tokenizer ──────────────────────────────────────────
|
|
(epoch 100)
|
|
(eval "(len (lua-tokenize \"\"))")
|
|
(epoch 101)
|
|
(eval "(get (nth (lua-tokenize \"\") 0) :type)")
|
|
|
|
;; Numbers
|
|
(epoch 110)
|
|
(eval "(get (nth (lua-tokenize \"42\") 0) :type)")
|
|
(epoch 111)
|
|
(eval "(get (nth (lua-tokenize \"42\") 0) :value)")
|
|
(epoch 112)
|
|
(eval "(get (nth (lua-tokenize \"3.14\") 0) :value)")
|
|
(epoch 113)
|
|
(eval "(get (nth (lua-tokenize \"0xff\") 0) :value)")
|
|
(epoch 114)
|
|
(eval "(get (nth (lua-tokenize \"1e3\") 0) :value)")
|
|
(epoch 115)
|
|
(eval "(get (nth (lua-tokenize \"1.5e-2\") 0) :value)")
|
|
(epoch 116)
|
|
(eval "(get (nth (lua-tokenize \".5\") 0) :value)")
|
|
|
|
;; Identifiers and keywords
|
|
(epoch 120)
|
|
(eval "(get (nth (lua-tokenize \"foo\") 0) :type)")
|
|
(epoch 121)
|
|
(eval "(get (nth (lua-tokenize \"foo\") 0) :value)")
|
|
(epoch 122)
|
|
(eval "(get (nth (lua-tokenize \"_bar1\") 0) :value)")
|
|
(epoch 123)
|
|
(eval "(get (nth (lua-tokenize \"local\") 0) :type)")
|
|
(epoch 124)
|
|
(eval "(get (nth (lua-tokenize \"function\") 0) :value)")
|
|
(epoch 125)
|
|
(eval "(get (nth (lua-tokenize \"nil\") 0) :type)")
|
|
(epoch 126)
|
|
(eval "(get (nth (lua-tokenize \"true\") 0) :value)")
|
|
(epoch 127)
|
|
(eval "(get (nth (lua-tokenize \"false\") 0) :type)")
|
|
|
|
;; Short strings
|
|
(epoch 130)
|
|
(eval "(get (nth (lua-tokenize \"\\\"hi\\\"\") 0) :type)")
|
|
(epoch 131)
|
|
(eval "(get (nth (lua-tokenize \"\\\"hi\\\"\") 0) :value)")
|
|
(epoch 132)
|
|
(eval "(get (nth (lua-tokenize \"'ab'\") 0) :value)")
|
|
(epoch 133)
|
|
(eval "(get (nth (lua-tokenize \"\\\"a\\\\nb\\\"\") 0) :value)")
|
|
|
|
;; Long strings
|
|
(epoch 140)
|
|
(eval "(get (nth (lua-tokenize \"[[hello]]\") 0) :type)")
|
|
(epoch 141)
|
|
(eval "(get (nth (lua-tokenize \"[[hello]]\") 0) :value)")
|
|
(epoch 142)
|
|
(eval "(get (nth (lua-tokenize \"[==[level 2]==]\") 0) :value)")
|
|
|
|
;; Operators (multi-char)
|
|
(epoch 150)
|
|
(eval "(get (nth (lua-tokenize \"==\") 0) :value)")
|
|
(epoch 151)
|
|
(eval "(get (nth (lua-tokenize \"~=\") 0) :value)")
|
|
(epoch 152)
|
|
(eval "(get (nth (lua-tokenize \"<=\") 0) :value)")
|
|
(epoch 153)
|
|
(eval "(get (nth (lua-tokenize \">=\") 0) :value)")
|
|
(epoch 154)
|
|
(eval "(get (nth (lua-tokenize \"..\") 0) :value)")
|
|
(epoch 155)
|
|
(eval "(get (nth (lua-tokenize \"...\") 0) :value)")
|
|
(epoch 156)
|
|
(eval "(get (nth (lua-tokenize \"::\") 0) :value)")
|
|
|
|
;; Single-char operators / punctuation
|
|
(epoch 160)
|
|
(eval "(get (nth (lua-tokenize \"+\") 0) :value)")
|
|
(epoch 161)
|
|
(eval "(get (nth (lua-tokenize \"-\") 0) :value)")
|
|
(epoch 162)
|
|
(eval "(get (nth (lua-tokenize \"*\") 0) :value)")
|
|
(epoch 163)
|
|
(eval "(get (nth (lua-tokenize \"/\") 0) :value)")
|
|
(epoch 164)
|
|
(eval "(get (nth (lua-tokenize \"%\") 0) :value)")
|
|
(epoch 165)
|
|
(eval "(get (nth (lua-tokenize \"^\") 0) :value)")
|
|
(epoch 166)
|
|
(eval "(get (nth (lua-tokenize \"#\") 0) :value)")
|
|
(epoch 167)
|
|
(eval "(get (nth (lua-tokenize \"(\") 0) :value)")
|
|
(epoch 168)
|
|
(eval "(get (nth (lua-tokenize \"{\") 0) :value)")
|
|
(epoch 169)
|
|
(eval "(get (nth (lua-tokenize \";\") 0) :value)")
|
|
|
|
;; Comments are stripped
|
|
(epoch 170)
|
|
(eval "(len (lua-tokenize \"-- comment\\n\"))")
|
|
(epoch 171)
|
|
(eval "(len (lua-tokenize \"-- comment\\n1\"))")
|
|
(epoch 172)
|
|
(eval "(get (nth (lua-tokenize \"-- c\\n42\") 0) :value)")
|
|
(epoch 173)
|
|
(eval "(len (lua-tokenize \"--[[ block ]] 1\"))")
|
|
(epoch 174)
|
|
(eval "(get (nth (lua-tokenize \"--[[ c ]] 42\") 0) :value)")
|
|
(epoch 175)
|
|
(eval "(get (nth (lua-tokenize \"--[==[ x ]==] 7\") 0) :value)")
|
|
|
|
;; Compound expressions
|
|
(epoch 180)
|
|
(eval "(len (lua-tokenize \"local x = 1\"))")
|
|
(epoch 181)
|
|
(eval "(get (nth (lua-tokenize \"local x = 1\") 0) :type)")
|
|
(epoch 182)
|
|
(eval "(get (nth (lua-tokenize \"local x = 1\") 0) :value)")
|
|
(epoch 183)
|
|
(eval "(get (nth (lua-tokenize \"local x = 1\") 1) :type)")
|
|
(epoch 184)
|
|
(eval "(get (nth (lua-tokenize \"local x = 1\") 2) :value)")
|
|
(epoch 185)
|
|
(eval "(get (nth (lua-tokenize \"local x = 1\") 3) :value)")
|
|
|
|
(epoch 190)
|
|
(eval "(len (lua-tokenize \"a.b:c()\"))")
|
|
(epoch 191)
|
|
(eval "(get (nth (lua-tokenize \"a.b:c()\") 1) :value)")
|
|
(epoch 192)
|
|
(eval "(get (nth (lua-tokenize \"a.b:c()\") 3) :value)")
|
|
|
|
;; ── Phase 1.parse: parser ────────────────────────────────────
|
|
;; Literals
|
|
(epoch 200)
|
|
(eval "(lua-parse-expr \"42\")")
|
|
(epoch 201)
|
|
(eval "(lua-parse-expr \"3.14\")")
|
|
(epoch 202)
|
|
(eval "(lua-parse-expr \"\\\"hi\\\"\")")
|
|
(epoch 203)
|
|
(eval "(lua-parse-expr \"true\")")
|
|
(epoch 204)
|
|
(eval "(lua-parse-expr \"false\")")
|
|
(epoch 205)
|
|
(eval "(lua-parse-expr \"nil\")")
|
|
(epoch 206)
|
|
(eval "(lua-parse-expr \"foo\")")
|
|
(epoch 207)
|
|
(eval "(lua-parse-expr \"...\")")
|
|
|
|
;; Binops with precedence
|
|
(epoch 210)
|
|
(eval "(lua-parse-expr \"1+2\")")
|
|
(epoch 211)
|
|
(eval "(lua-parse-expr \"a+b*c\")")
|
|
(epoch 212)
|
|
(eval "(lua-parse-expr \"a*b+c\")")
|
|
(epoch 213)
|
|
(eval "(lua-parse-expr \"a and b or c\")")
|
|
(epoch 214)
|
|
(eval "(lua-parse-expr \"a==b\")")
|
|
(epoch 215)
|
|
(eval "(lua-parse-expr \"a..b..c\")")
|
|
(epoch 216)
|
|
(eval "(lua-parse-expr \"a^b^c\")")
|
|
(epoch 217)
|
|
(eval "(lua-parse-expr \"(a+b)*c\")")
|
|
|
|
;; Unary
|
|
(epoch 220)
|
|
(eval "(lua-parse-expr \"-x\")")
|
|
(epoch 221)
|
|
(eval "(lua-parse-expr \"not x\")")
|
|
(epoch 222)
|
|
(eval "(lua-parse-expr \"#a\")")
|
|
|
|
;; Member/index/call
|
|
(epoch 230)
|
|
(eval "(lua-parse-expr \"a.b\")")
|
|
(epoch 231)
|
|
(eval "(lua-parse-expr \"a.b.c\")")
|
|
(epoch 232)
|
|
(eval "(lua-parse-expr \"a[0]\")")
|
|
(epoch 233)
|
|
(eval "(lua-parse-expr \"f()\")")
|
|
(epoch 234)
|
|
(eval "(lua-parse-expr \"f(1,2)\")")
|
|
(epoch 235)
|
|
(eval "(lua-parse-expr \"a:b()\")")
|
|
|
|
;; Table constructors
|
|
(epoch 240)
|
|
(eval "(lua-parse-expr \"{1,2,3}\")")
|
|
(epoch 241)
|
|
(eval "(lua-parse-expr \"{x=1,y=2}\")")
|
|
(epoch 242)
|
|
(eval "(lua-parse-expr \"{[1+1]=\\\"a\\\"}\")")
|
|
(epoch 243)
|
|
(eval "(lua-parse-expr \"{}\")")
|
|
|
|
;; Anonymous function
|
|
(epoch 250)
|
|
(eval "(lua-parse-expr \"function() return 1 end\")")
|
|
(epoch 251)
|
|
(eval "(lua-parse-expr \"function(a,b) return a+b end\")")
|
|
(epoch 252)
|
|
(eval "(lua-parse-expr \"function(...) return 1 end\")")
|
|
|
|
;; Statements
|
|
(epoch 260)
|
|
(eval "(lua-parse \"local x = 1\")")
|
|
(epoch 261)
|
|
(eval "(lua-parse \"local a, b = 1, 2\")")
|
|
(epoch 262)
|
|
(eval "(lua-parse \"x = 1\")")
|
|
(epoch 263)
|
|
(eval "(lua-parse \"a, b = 1, 2\")")
|
|
(epoch 264)
|
|
(eval "(lua-parse \"if x then y = 1 end\")")
|
|
(epoch 265)
|
|
(eval "(lua-parse \"if x then y = 1 else y = 2 end\")")
|
|
(epoch 266)
|
|
(eval "(lua-parse \"if x then y = 1 elseif z then y = 2 else y = 3 end\")")
|
|
(epoch 267)
|
|
(eval "(lua-parse \"while x < 10 do x = x + 1 end\")")
|
|
(epoch 268)
|
|
(eval "(lua-parse \"repeat x = x + 1 until x > 10\")")
|
|
(epoch 269)
|
|
(eval "(lua-parse \"for i = 1, 10 do x = i end\")")
|
|
(epoch 270)
|
|
(eval "(lua-parse \"for i = 1, 10, 2 do x = i end\")")
|
|
(epoch 271)
|
|
(eval "(lua-parse \"do local x = 1 end\")")
|
|
(epoch 272)
|
|
(eval "(lua-parse \"break\")")
|
|
(epoch 273)
|
|
(eval "(lua-parse \"return 42\")")
|
|
(epoch 274)
|
|
(eval "(lua-parse \"return 1, 2\")")
|
|
(epoch 275)
|
|
(eval "(lua-parse \"return\")")
|
|
|
|
;; Function declarations
|
|
(epoch 280)
|
|
(eval "(lua-parse \"function f() return 1 end\")")
|
|
(epoch 281)
|
|
(eval "(lua-parse \"local function f(x) return x * 2 end\")")
|
|
(epoch 282)
|
|
(eval "(lua-parse \"function t.m(x) return x end\")")
|
|
(epoch 283)
|
|
(eval "(lua-parse \"function t:m(x) return self end\")")
|
|
|
|
;; Calls as statements
|
|
(epoch 290)
|
|
(eval "(lua-parse \"print(42)\")")
|
|
(epoch 291)
|
|
(eval "(lua-parse \"a:b()\")")
|
|
(epoch 292)
|
|
(eval "(lua-parse \"t.f()\")")
|
|
|
|
;; Multi-statement chunks
|
|
(epoch 300)
|
|
(eval "(len (lua-parse \"local x = 1 x = x + 1 return x\"))")
|
|
|
|
;; ── Phase 2: transpile + eval ─────────────────────────────────
|
|
;; Literals via return
|
|
(epoch 400)
|
|
(eval "(lua-eval-ast \"return 1\")")
|
|
(epoch 401)
|
|
(eval "(lua-eval-ast \"return true\")")
|
|
(epoch 402)
|
|
(eval "(lua-eval-ast \"return false\")")
|
|
(epoch 403)
|
|
(eval "(lua-eval-ast \"return nil\")")
|
|
(epoch 404)
|
|
(eval "(lua-eval-ast \"return \\\"hi\\\"\")")
|
|
|
|
;; Arithmetic
|
|
(epoch 410)
|
|
(eval "(lua-eval-ast \"return 1 + 2\")")
|
|
(epoch 411)
|
|
(eval "(lua-eval-ast \"return 10 - 3\")")
|
|
(epoch 412)
|
|
(eval "(lua-eval-ast \"return 4 * 5\")")
|
|
(epoch 413)
|
|
(eval "(lua-eval-ast \"return 10 / 4\")")
|
|
(epoch 414)
|
|
(eval "(lua-eval-ast \"return 10 % 3\")")
|
|
(epoch 415)
|
|
(eval "(lua-eval-ast \"return 2 ^ 10\")")
|
|
(epoch 416)
|
|
(eval "(lua-eval-ast \"return (1 + 2) * 3\")")
|
|
(epoch 417)
|
|
(eval "(lua-eval-ast \"return 1 + 2 * 3\")")
|
|
(epoch 418)
|
|
(eval "(lua-eval-ast \"return -5 + 10\")")
|
|
|
|
;; String
|
|
(epoch 420)
|
|
(eval "(lua-eval-ast \"return \\\"a\\\" .. \\\"b\\\"\")")
|
|
(epoch 421)
|
|
(eval "(lua-eval-ast \"return \\\"count: \\\" .. 42\")")
|
|
|
|
;; Comparison
|
|
(epoch 430)
|
|
(eval "(lua-eval-ast \"return 1 < 2\")")
|
|
(epoch 431)
|
|
(eval "(lua-eval-ast \"return 3 > 2\")")
|
|
(epoch 432)
|
|
(eval "(lua-eval-ast \"return 2 == 2\")")
|
|
(epoch 433)
|
|
(eval "(lua-eval-ast \"return 1 ~= 2\")")
|
|
(epoch 434)
|
|
(eval "(lua-eval-ast \"return 1 <= 1\")")
|
|
(epoch 435)
|
|
(eval "(lua-eval-ast \"return 3 >= 2\")")
|
|
|
|
;; Logical (short-circuit, return value)
|
|
(epoch 440)
|
|
(eval "(lua-eval-ast \"return true and 42\")")
|
|
(epoch 441)
|
|
(eval "(lua-eval-ast \"return false or 99\")")
|
|
(epoch 442)
|
|
(eval "(lua-eval-ast \"return nil or 7\")")
|
|
(epoch 443)
|
|
(eval "(lua-eval-ast \"return 1 and 2\")")
|
|
(epoch 444)
|
|
(eval "(lua-eval-ast \"return false and 999\")")
|
|
(epoch 445)
|
|
(eval "(lua-eval-ast \"return not true\")")
|
|
(epoch 446)
|
|
(eval "(lua-eval-ast \"return not nil\")")
|
|
(epoch 447)
|
|
(eval "(lua-eval-ast \"return not 0\")")
|
|
|
|
;; Truthy
|
|
(epoch 450)
|
|
(eval "(lua-truthy? 0)")
|
|
(epoch 451)
|
|
(eval "(lua-truthy? nil)")
|
|
(epoch 452)
|
|
(eval "(lua-truthy? false)")
|
|
(epoch 453)
|
|
(eval "(lua-truthy? \"\")")
|
|
|
|
;; Control flow
|
|
(epoch 460)
|
|
(eval "(lua-eval-ast \"if true then return 1 else return 2 end\")")
|
|
(epoch 461)
|
|
(eval "(lua-eval-ast \"if 1 > 2 then return 100 else return 200 end\")")
|
|
(epoch 462)
|
|
(eval "(lua-eval-ast \"local x = 1 if x > 0 then x = x * 10 elseif x < 0 then x = 999 else x = 42 end return x\")")
|
|
|
|
;; Local and assignment
|
|
(epoch 470)
|
|
(eval "(lua-eval-ast \"local x = 5 return x * 2\")")
|
|
(epoch 471)
|
|
(eval "(lua-eval-ast \"local x = 0 x = x + 1 x = x + 1 return x\")")
|
|
(epoch 472)
|
|
(eval "(lua-eval-ast \"local a, b = 1, 2 return a + b\")")
|
|
|
|
;; Loops
|
|
(epoch 480)
|
|
(eval "(lua-eval-ast \"local sum = 0 for i = 1, 5 do sum = sum + i end return sum\")")
|
|
(epoch 481)
|
|
(eval "(lua-eval-ast \"local n = 0 for i = 10, 1, -1 do n = n + 1 end return n\")")
|
|
(epoch 482)
|
|
(eval "(lua-eval-ast \"local i = 0 while i < 5 do i = i + 1 end return i\")")
|
|
(epoch 483)
|
|
(eval "(lua-eval-ast \"local i = 0 repeat i = i + 1 until i >= 3 return i\")")
|
|
(epoch 484)
|
|
(eval "(lua-eval-ast \"local s = 0 for i = 1, 100 do s = s + i end return s\")")
|
|
|
|
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 token is eof" '"eof"'
|
|
|
|
# ── Numbers ────────────────────────────────────────────────────
|
|
check 110 "int token type" '"number"'
|
|
check 111 "int value" '42'
|
|
check 112 "float value" '3.14'
|
|
check 113 "hex value" '255'
|
|
check 114 "exponent" '1000'
|
|
check 115 "neg exponent" '0.015'
|
|
check 116 "leading-dot" '0.5'
|
|
|
|
# ── Identifiers / keywords ─────────────────────────────────────
|
|
check 120 "ident type" '"ident"'
|
|
check 121 "ident value" '"foo"'
|
|
check 122 "underscore ident" '"_bar1"'
|
|
check 123 "local is keyword" '"keyword"'
|
|
check 124 "function keyword" '"function"'
|
|
check 125 "nil is keyword" '"keyword"'
|
|
check 126 "true value" '"true"'
|
|
check 127 "false type" '"keyword"'
|
|
|
|
# ── Strings ────────────────────────────────────────────────────
|
|
check 130 "string type" '"string"'
|
|
check 131 "string value" '"hi"'
|
|
check 132 "single-quote string" '"ab"'
|
|
check 133 "escape sequence" '"a'
|
|
check 140 "long string type" '"string"'
|
|
check 141 "long string value" '"hello"'
|
|
check 142 "level-2 long string" '"level 2"'
|
|
|
|
# ── Operators ──────────────────────────────────────────────────
|
|
check 150 "==" '"=="'
|
|
check 151 "~=" '"~="'
|
|
check 152 "<=" '"<="'
|
|
check 153 ">=" '">="'
|
|
check 154 ".." '".."'
|
|
check 155 "..." '"..."'
|
|
check 156 "::" '"::"'
|
|
|
|
check 160 "+" '"+"'
|
|
check 161 "-" '"-"'
|
|
check 162 "*" '"*"'
|
|
check 163 "/" '"/"'
|
|
check 164 "%" '"%"'
|
|
check 165 "^" '"^"'
|
|
check 166 "#" '"#"'
|
|
check 167 "(" '"("'
|
|
check 168 "{" '"{"'
|
|
check 169 ";" '";"'
|
|
|
|
# ── Comments ───────────────────────────────────────────────────
|
|
check 170 "line comment only → eof" '1'
|
|
check 171 "line comment + num" '2'
|
|
check 172 "num after line comment" '42'
|
|
check 173 "block comment → eof" '2'
|
|
check 174 "num after block comment" '42'
|
|
check 175 "num after level-2 block comment" '7'
|
|
|
|
# ── Compound ───────────────────────────────────────────────────
|
|
check 180 "local x = 1 token count" '5'
|
|
check 181 "local is keyword" '"keyword"'
|
|
check 182 "local value" '"local"'
|
|
check 183 "x is ident" '"ident"'
|
|
check 184 "= value" '"="'
|
|
check 185 "1 value" '1'
|
|
|
|
check 190 "a.b:c() token count" '8'
|
|
check 191 "dot after ident" '"."'
|
|
check 192 "colon after ident" '":"'
|
|
|
|
# ── Phase 1.parse: parser ────────────────────────────────────
|
|
check 200 "parse int" '(lua-num 42)'
|
|
check 201 "parse float" '(lua-num 3.14)'
|
|
check 202 "parse string" '(lua-str "hi")'
|
|
check 203 "parse true" '(lua-true)'
|
|
check 204 "parse false" '(lua-false)'
|
|
check 205 "parse nil" '(lua-nil)'
|
|
check 206 "parse ident" '(lua-name "foo")'
|
|
check 207 "parse vararg" '(lua-vararg)'
|
|
|
|
check 210 "parse 1+2" '(lua-binop "+" (lua-num 1) (lua-num 2))'
|
|
check 211 "parse a+b*c prec" '(lua-binop "+" (lua-name "a") (lua-binop "*"'
|
|
check 212 "parse a*b+c prec" '(lua-binop "+" (lua-binop "*"'
|
|
check 213 "parse and/or prec" '(lua-binop "or" (lua-binop "and"'
|
|
check 214 "parse ==" '(lua-binop "==" (lua-name "a") (lua-name "b"))'
|
|
check 215 "parse .. right-assoc" '(lua-binop ".." (lua-name "a") (lua-binop ".."'
|
|
check 216 "parse ^ right-assoc" '(lua-binop "^" (lua-name "a") (lua-binop "^"'
|
|
check 217 "parse paren override" '(lua-binop "*" (lua-binop "+"'
|
|
|
|
check 220 "parse -x" '(lua-unop "-" (lua-name "x"))'
|
|
check 221 "parse not x" '(lua-unop "not" (lua-name "x"))'
|
|
check 222 "parse #a" '(lua-unop "#" (lua-name "a"))'
|
|
|
|
check 230 "parse a.b" '(lua-field (lua-name "a") "b")'
|
|
check 231 "parse a.b.c" '(lua-field (lua-field (lua-name "a") "b") "c")'
|
|
check 232 "parse a[0]" '(lua-index (lua-name "a") (lua-num 0))'
|
|
check 233 "parse f()" '(lua-call (lua-name "f") ())'
|
|
check 234 "parse f(1,2)" '(lua-call (lua-name "f") ((lua-num 1) (lua-num 2)))'
|
|
check 235 "parse a:b()" '(lua-method-call (lua-name "a") "b" ())'
|
|
|
|
check 240 "parse {1,2,3}" '(lua-table (lua-pos (lua-num 1)) (lua-pos (lua-num 2))'
|
|
check 241 "parse {x=1,y=2}" '(lua-table (lua-kv (lua-str "x") (lua-num 1))'
|
|
check 242 "parse {[k]=v}" '(lua-table (lua-kv (lua-binop "+"'
|
|
check 243 "parse empty table" '(lua-table)'
|
|
|
|
check 250 "parse function() 1 end" '(lua-function () false'
|
|
check 251 "parse function(a,b)" '(lua-function ("a" "b") false'
|
|
check 252 "parse function(...)" '(lua-function () true'
|
|
|
|
check 260 "parse local x = 1" '(lua-block (lua-local ("x") ((lua-num 1))))'
|
|
check 261 "parse local a,b = 1,2" '(lua-block (lua-local ("a" "b") ((lua-num 1) (lua-num 2))))'
|
|
check 262 "parse x = 1" '(lua-assign ((lua-name "x")) ((lua-num 1)))'
|
|
check 263 "parse a,b = 1,2" '(lua-assign ((lua-name "a") (lua-name "b"))'
|
|
check 264 "parse if then end" '(lua-if (lua-name "x")'
|
|
check 265 "parse if-else" '(lua-if (lua-name "x") (lua-block (lua-assign ((lua-name "y")) ((lua-num 1)))) () (lua-block'
|
|
check 266 "parse if-elseif-else" '(((lua-name "z") (lua-block (lua-assign ((lua-name "y")) ((lua-num 2))))))'
|
|
check 267 "parse while" '(lua-while (lua-binop "<"'
|
|
check 268 "parse repeat" '(lua-repeat'
|
|
check 269 "parse for num" '(lua-for-num "i" (lua-num 1) (lua-num 10) nil'
|
|
check 270 "parse for num step" '(lua-for-num "i" (lua-num 1) (lua-num 10) (lua-num 2)'
|
|
check 271 "parse do block" '(lua-do (lua-block (lua-local ("x") ((lua-num 1))))'
|
|
check 272 "parse break" '(lua-break)'
|
|
check 273 "parse return" '(lua-return ((lua-num 42)))'
|
|
check 274 "parse return 1,2" '(lua-return ((lua-num 1) (lua-num 2)))'
|
|
check 275 "parse bare return" '(lua-return ())'
|
|
|
|
check 280 "parse function decl" '(lua-function-decl (lua-name "f")'
|
|
check 281 "parse local function" '(lua-local-function "f" (lua-function ("x") false'
|
|
check 282 "parse function t.m" '(lua-function-decl (lua-field (lua-name "t") "m")'
|
|
check 283 "parse method t:m" 'self'
|
|
|
|
check 290 "parse call stmt" '(lua-call-stmt (lua-call (lua-name "print")'
|
|
check 291 "parse method call stmt" '(lua-call-stmt (lua-method-call'
|
|
check 292 "parse chained call stmt" '(lua-call-stmt (lua-call (lua-field'
|
|
|
|
check 300 "parse multi-statement" '4'
|
|
|
|
# ── Phase 2: transpile + eval ────────────────────────────────
|
|
check 400 "eval return 1" '1'
|
|
check 401 "eval return true" 'true'
|
|
check 402 "eval return false" 'false'
|
|
check 403 "eval return nil" 'nil'
|
|
check 404 "eval return string" '"hi"'
|
|
|
|
check 410 "eval 1+2" '3'
|
|
check 411 "eval 10-3" '7'
|
|
check 412 "eval 4*5" '20'
|
|
check 413 "eval 10/4" '2.5'
|
|
check 414 "eval 10%3" '1'
|
|
check 415 "eval 2^10" '1024'
|
|
check 416 "eval (1+2)*3" '9'
|
|
check 417 "eval 1+2*3 prec" '7'
|
|
check 418 "eval -5+10" '5'
|
|
|
|
check 420 "eval \"a\"..\"b\"" '"ab"'
|
|
check 421 "eval str..num" '"count: 42"'
|
|
|
|
check 430 "eval 1<2" 'true'
|
|
check 431 "eval 3>2" 'true'
|
|
check 432 "eval 2==2" 'true'
|
|
check 433 "eval 1~=2" 'true'
|
|
check 434 "eval 1<=1" 'true'
|
|
check 435 "eval 3>=2" 'true'
|
|
|
|
check 440 "eval true and 42" '42'
|
|
check 441 "eval false or 99" '99'
|
|
check 442 "eval nil or 7" '7'
|
|
check 443 "eval 1 and 2" '2'
|
|
check 444 "eval false and 999" 'false'
|
|
check 445 "eval not true" 'false'
|
|
check 446 "eval not nil" 'true'
|
|
check 447 "eval not 0" 'false'
|
|
|
|
check 450 "truthy 0 (Lua truthy!)" 'true'
|
|
check 451 "truthy nil" 'false'
|
|
check 452 "truthy false" 'false'
|
|
check 453 "truthy empty string" 'true'
|
|
|
|
check 460 "if true then 1 else 2" '1'
|
|
check 461 "if 1>2 then 100 else 200" '200'
|
|
check 462 "if-elseif-else branching" '10'
|
|
|
|
check 470 "local x=5; x*2" '10'
|
|
check 471 "mutate x" '2'
|
|
check 472 "local a,b = 1,2; a+b" '3'
|
|
|
|
check 480 "for 1..5 sum" '15'
|
|
check 481 "for 10..1 step -1 count" '10'
|
|
check 482 "while i<5 count" '5'
|
|
check 483 "repeat until i>=3" '3'
|
|
check 484 "for 1..100 sum" '5050'
|
|
|
|
TOTAL=$((PASS + FAIL))
|
|
if [ $FAIL -eq 0 ]; then
|
|
echo "ok $PASS/$TOTAL Lua-on-SX tests passed"
|
|
else
|
|
echo "FAIL $PASS/$TOTAL passed, $FAIL failed:"
|
|
echo ""
|
|
echo "$ERRORS"
|
|
fi
|
|
|
|
[ $FAIL -eq 0 ]
|