Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
1414 lines
61 KiB
Bash
Executable File
1414 lines
61 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\")")
|
||
|
||
;; ── Phase 3: functions + closures ─────────────────────────────
|
||
;; Anonymous
|
||
(epoch 500)
|
||
(eval "(lua-eval-ast \"local f = function(x) return x + 1 end return f(5)\")")
|
||
(epoch 501)
|
||
(eval "(lua-eval-ast \"local f = function() return 42 end return f()\")")
|
||
(epoch 502)
|
||
(eval "(lua-eval-ast \"return (function(a, b) return a * b end)(3, 4)\")")
|
||
|
||
;; Local function
|
||
(epoch 510)
|
||
(eval "(lua-eval-ast \"local function double(x) return x * 2 end return double(7)\")")
|
||
(epoch 511)
|
||
(eval "(lua-eval-ast \"local function sum3(a, b, c) return a + b + c end return sum3(1, 2, 3)\")")
|
||
(epoch 512)
|
||
(eval "(lua-eval-ast \"local function greet() return \\\"hi\\\" end return greet()\")")
|
||
|
||
;; Top-level function decl
|
||
(epoch 520)
|
||
(eval "(lua-eval-ast \"function add(a, b) return a + b end return add(3, 4)\")")
|
||
(epoch 521)
|
||
(eval "(lua-eval-ast \"function id(x) return x end return id(\\\"abc\\\")\")")
|
||
|
||
;; Closures — lexical capture
|
||
(epoch 530)
|
||
(eval "(lua-eval-ast \"local x = 10 local function getx() return x end return getx()\")")
|
||
(epoch 531)
|
||
(eval "(lua-eval-ast \"local function make_adder(n) return function(x) return x + n end end local add5 = make_adder(5) return add5(10)\")")
|
||
(epoch 532)
|
||
(eval "(lua-eval-ast \"local function counter() local n = 0 return function() n = n + 1 return n end end local c = counter() c() c() return c()\")")
|
||
(epoch 533)
|
||
(eval "(lua-eval-ast \"local a = 1 local b = 2 local function f() return a + b end a = 10 return f()\")")
|
||
|
||
;; Recursion
|
||
(epoch 540)
|
||
(eval "(lua-eval-ast \"local function fact(n) if n <= 1 then return 1 else return n * fact(n - 1) end end return fact(5)\")")
|
||
(epoch 541)
|
||
(eval "(lua-eval-ast \"function fib(n) if n < 2 then return n else return fib(n-1) + fib(n-2) end end return fib(10)\")")
|
||
|
||
;; Higher-order
|
||
(epoch 550)
|
||
(eval "(lua-eval-ast \"local function apply(f, x) return f(x) end local function sq(n) return n * n end return apply(sq, 4)\")")
|
||
(epoch 551)
|
||
(eval "(lua-eval-ast \"local function twice(f, x) return f(f(x)) end return twice(function(n) return n + 1 end, 5)\")")
|
||
|
||
;; Mixed with control flow
|
||
(epoch 560)
|
||
(eval "(lua-eval-ast \"local function max(a, b) if a > b then return a else return b end end return max(7, 3)\")")
|
||
(epoch 561)
|
||
(eval "(lua-eval-ast \"local function sum_to(n) local s = 0 for i = 1, n do s = s + i end return s end return sum_to(10)\")")
|
||
|
||
;; ── Phase 3: multi-return + unpack ────────────────────────────
|
||
(epoch 570)
|
||
(eval "(lua-eval-ast \"local a, b = (function() return 1, 2 end)() return a + b\")")
|
||
(epoch 571)
|
||
(eval "(lua-eval-ast \"local function two() return 10, 20 end local a, b = two() return b - a\")")
|
||
(epoch 572)
|
||
(eval "(lua-eval-ast \"function swap(a, b) return b, a end local x, y = swap(1, 2) return x * 10 + y\")")
|
||
(epoch 573)
|
||
(eval "(lua-eval-ast \"local function three() return 1, 2, 3 end local a, b = three() return a * 10 + b\")")
|
||
(epoch 574)
|
||
(eval "(lua-eval-ast \"local function two() return 1, 2 end local a, b, c = two() if c == nil then return a + b else return 0 end\")")
|
||
(epoch 575)
|
||
(eval "(lua-eval-ast \"local function two() return 5, 7 end local function outer() return two() end local a, b = outer() return a + b\")")
|
||
(epoch 576)
|
||
(eval "(lua-eval-ast \"local function two() return 9, 9 end local a, b = two(), 5 return a * 10 + b\")")
|
||
(epoch 577)
|
||
(eval "(lua-eval-ast \"local function pair() return 4, 5 end local x = pair() return x + 1\")")
|
||
(epoch 578)
|
||
(eval "(lua-eval-ast \"local function none() return end local a, b = none() if a == nil and b == nil then return 99 else return 0 end\")")
|
||
(epoch 579)
|
||
(eval "(lua-eval-ast \"local a = 0 local b = 0 local function m() return 7, 11 end a, b = m() return a + b\")")
|
||
|
||
;; ── Phase 3: table constructors ────────────────────────────────
|
||
;; Array part
|
||
(epoch 600)
|
||
(eval "(lua-eval-ast \"local t = {10, 20, 30} return t[1]\")")
|
||
(epoch 601)
|
||
(eval "(lua-eval-ast \"local t = {10, 20, 30} return t[3]\")")
|
||
(epoch 602)
|
||
(eval "(lua-eval-ast \"local t = {10, 20, 30} if t[4] == nil then return 1 else return 0 end\")")
|
||
|
||
;; Hash part
|
||
(epoch 610)
|
||
(eval "(lua-eval-ast \"local t = {x = 1, y = 2} return t.x + t.y\")")
|
||
(epoch 611)
|
||
(eval "(lua-eval-ast \"local t = {name = \\\"bob\\\", age = 30} return t.name\")")
|
||
(epoch 612)
|
||
(eval "(lua-eval-ast \"local t = {name = \\\"bob\\\", age = 30} return t.age\")")
|
||
|
||
;; Computed keys
|
||
(epoch 620)
|
||
(eval "(lua-eval-ast \"local k = \\\"answer\\\" local t = {[k] = 42} return t.answer\")")
|
||
(epoch 621)
|
||
(eval "(lua-eval-ast \"local t = {[1+1] = \\\"two\\\"} return t[2]\")")
|
||
(epoch 622)
|
||
(eval "(lua-eval-ast \"local t = {[\\\"a\\\" .. \\\"b\\\"] = 99} return t.ab\")")
|
||
(epoch 623)
|
||
(eval "(lua-eval-ast \"local t = {[true] = \\\"yes\\\", [false] = \\\"no\\\"} return t[true]\")")
|
||
|
||
;; Mixed array + hash
|
||
(epoch 630)
|
||
(eval "(lua-eval-ast \"local t = {1, 2, 3, key = \\\"v\\\"} return t[2]\")")
|
||
(epoch 631)
|
||
(eval "(lua-eval-ast \"local t = {1, 2, 3, key = \\\"v\\\"} return t.key\")")
|
||
|
||
;; Separators
|
||
(epoch 640)
|
||
(eval "(lua-eval-ast \"local t = {1, 2, 3,} return t[3]\")")
|
||
(epoch 641)
|
||
(eval "(lua-eval-ast \"local t = {1; 2; 3} return t[2]\")")
|
||
(epoch 642)
|
||
(eval "(lua-eval-ast \"local t = {1, 2; 3, 4} return t[4]\")")
|
||
|
||
;; Nested
|
||
(epoch 650)
|
||
(eval "(lua-eval-ast \"local t = {{1, 2}, {3, 4}} return t[2][1]\")")
|
||
(epoch 651)
|
||
(eval "(lua-eval-ast \"local t = {inner = {a = 1, b = 2}} return t.inner.b\")")
|
||
|
||
;; Dynamic values
|
||
(epoch 660)
|
||
(eval "(lua-eval-ast \"local x = 7 local t = {x, x * 2, x * 3} return t[2]\")")
|
||
(epoch 661)
|
||
(eval "(lua-eval-ast \"local function f(n) return n + 1 end local t = {f(1), f(2), f(3)} return t[3]\")")
|
||
|
||
;; Functions as values
|
||
(epoch 670)
|
||
(eval "(lua-eval-ast \"local t = {fn = function(x) return x * 2 end} return t.fn(5)\")")
|
||
|
||
;; ── Phase 3: raw table access (read + write + #) ───────────────
|
||
;; Write then read array index
|
||
(epoch 700)
|
||
(eval "(lua-eval-ast \"local t = {} t[1] = \\\"a\\\" t[2] = \\\"b\\\" return t[1]\")")
|
||
(epoch 701)
|
||
(eval "(lua-eval-ast \"local t = {} t[1] = 10 t[2] = 20 return t[1] + t[2]\")")
|
||
|
||
;; Write then read field
|
||
(epoch 710)
|
||
(eval "(lua-eval-ast \"local t = {} t.x = 100 return t.x\")")
|
||
(epoch 711)
|
||
(eval "(lua-eval-ast \"local t = {} t.name = \\\"alice\\\" t.age = 30 return t.name\")")
|
||
(epoch 712)
|
||
(eval "(lua-eval-ast \"local t = {x = 1} t.x = 99 return t.x\")")
|
||
|
||
;; Missing key is nil
|
||
(epoch 720)
|
||
(eval "(lua-eval-ast \"local t = {x = 1} if t.y == nil then return 99 else return 0 end\")")
|
||
(epoch 721)
|
||
(eval "(lua-eval-ast \"local t = {} if t[1] == nil then return 1 else return 0 end\")")
|
||
|
||
;; Length operator
|
||
(epoch 730)
|
||
(eval "(lua-eval-ast \"local t = {10, 20, 30, 40, 50} return #t\")")
|
||
(epoch 731)
|
||
(eval "(lua-eval-ast \"local t = {} return #t\")")
|
||
(epoch 732)
|
||
(eval "(lua-eval-ast \"local t = {} t[1] = 5 t[2] = 10 return #t\")")
|
||
(epoch 733)
|
||
(eval "(lua-eval-ast \"return #\\\"hello\\\"\")")
|
||
|
||
;; Mixed read/write
|
||
(epoch 740)
|
||
(eval "(lua-eval-ast \"local t = {count = 0} t.count = t.count + 1 t.count = t.count + 1 return t.count\")")
|
||
(epoch 741)
|
||
(eval "(lua-eval-ast \"local t = {} for i = 1, 5 do t[i] = i * i end return t[3]\")")
|
||
(epoch 742)
|
||
(eval "(lua-eval-ast \"local t = {} for i = 1, 10 do t[i] = i end return #t\")")
|
||
|
||
;; Chained field read/write
|
||
(epoch 750)
|
||
(eval "(lua-eval-ast \"local t = {a = {b = {c = 42}}} return t.a.b.c\")")
|
||
(epoch 751)
|
||
(eval "(lua-eval-ast \"local t = {a = {}} t.a.x = 7 return t.a.x\")")
|
||
|
||
;; Computed key read/write
|
||
(epoch 760)
|
||
(eval "(lua-eval-ast \"local k = \\\"foo\\\" local t = {} t[k] = 88 return t.foo\")")
|
||
(epoch 761)
|
||
(eval "(lua-eval-ast \"local t = {} t[\\\"x\\\" .. \\\"y\\\"] = 7 return t.xy\")")
|
||
|
||
;; Reference semantics
|
||
(epoch 770)
|
||
(eval "(lua-eval-ast \"local t = {} local s = t s.x = 42 return t.x\")")
|
||
|
||
;; ── Phase 4: metatables ────────────────────────────────────────
|
||
;; setmetatable / getmetatable
|
||
(epoch 800)
|
||
(eval "(lua-eval-ast \"local t = {} local r = setmetatable(t, {}) if r == t then return 1 else return 0 end\")")
|
||
(epoch 801)
|
||
(eval "(lua-eval-ast \"local mt = {} local t = setmetatable({}, mt) if getmetatable(t) == mt then return 1 else return 0 end\")")
|
||
|
||
;; type()
|
||
(epoch 810)
|
||
(eval "(lua-eval-ast \"return type(1)\")")
|
||
(epoch 811)
|
||
(eval "(lua-eval-ast \"return type(\\\"s\\\")\")")
|
||
(epoch 812)
|
||
(eval "(lua-eval-ast \"return type({})\")")
|
||
(epoch 813)
|
||
(eval "(lua-eval-ast \"return type(nil)\")")
|
||
(epoch 814)
|
||
(eval "(lua-eval-ast \"return type(true)\")")
|
||
(epoch 815)
|
||
(eval "(lua-eval-ast \"return type(function() end)\")")
|
||
|
||
;; __index
|
||
(epoch 820)
|
||
(eval "(lua-eval-ast \"local base = {x = 10} local t = setmetatable({}, {__index = base}) return t.x\")")
|
||
(epoch 821)
|
||
(eval "(lua-eval-ast \"local base = {x = 10} local t = setmetatable({y = 20}, {__index = base}) return t.x + t.y\")")
|
||
(epoch 822)
|
||
(eval "(lua-eval-ast \"local t = setmetatable({}, {__index = function(tbl, k) return k .. \\\"!\\\" end}) return t.hi\")")
|
||
|
||
;; __newindex
|
||
(epoch 830)
|
||
(eval "(lua-eval-ast \"local log = {} local t = setmetatable({}, {__newindex = function(tbl, k, v) log[1] = k end}) t.foo = 1 return log[1]\")")
|
||
|
||
;; Arithmetic metamethods
|
||
(epoch 840)
|
||
(eval "(lua-eval-ast \"local mt = {__add = function(a, b) return 99 end} local x = setmetatable({}, mt) return x + 1\")")
|
||
(epoch 841)
|
||
(eval "(lua-eval-ast \"local mt = {__add = function(a, b) return a.v + b.v end} local x = setmetatable({v = 3}, mt) local y = setmetatable({v = 4}, mt) return x + y\")")
|
||
(epoch 842)
|
||
(eval "(lua-eval-ast \"local mt = {__sub = function(a, b) return 7 end, __mul = function(a, b) return 11 end} local t = setmetatable({}, mt) return t - t + (t * t)\")")
|
||
(epoch 843)
|
||
(eval "(lua-eval-ast \"local mt = {__unm = function(a) return 42 end} local t = setmetatable({}, mt) return -t\")")
|
||
(epoch 844)
|
||
(eval "(lua-eval-ast \"local mt = {__concat = function(a, b) return \\\"cat\\\" end} local t = setmetatable({}, mt) return t .. \\\"x\\\"\")")
|
||
|
||
;; Comparison metamethods
|
||
(epoch 850)
|
||
(eval "(lua-eval-ast \"local mt = {__eq = function(a, b) return true end} local x = setmetatable({}, mt) local y = setmetatable({}, mt) if x == y then return 1 else return 0 end\")")
|
||
(epoch 851)
|
||
(eval "(lua-eval-ast \"local mt = {__lt = function(a, b) return true end} local x = setmetatable({}, mt) local y = setmetatable({}, mt) if x < y then return 1 else return 0 end\")")
|
||
(epoch 852)
|
||
(eval "(lua-eval-ast \"local mt = {__le = function(a, b) return true end} local x = setmetatable({}, mt) local y = setmetatable({}, mt) if x <= y then return 1 else return 0 end\")")
|
||
|
||
;; __call
|
||
(epoch 860)
|
||
(eval "(lua-eval-ast \"local mt = {__call = function(t, x) return x + 100 end} local obj = setmetatable({}, mt) return obj(5)\")")
|
||
|
||
;; __len
|
||
(epoch 870)
|
||
(eval "(lua-eval-ast \"local mt = {__len = function(t) return 99 end} local t = setmetatable({}, mt) return #t\")")
|
||
|
||
;; Classic OO pattern
|
||
(epoch 880)
|
||
(eval "(lua-eval-ast \"local Animal = {} Animal.__index = Animal function Animal:new(name) local o = setmetatable({name = name}, self) return o end function Animal:getName() return self.name end local a = Animal:new(\\\"Rex\\\") return a:getName()\")")
|
||
|
||
;; ── Phase 4: pcall / xpcall / error ────────────────────────────
|
||
(epoch 900)
|
||
(eval "(lua-eval-ast \"local ok, err = pcall(function() error(\\\"boom\\\") end) if ok then return 0 else return err end\")")
|
||
(epoch 901)
|
||
(eval "(lua-eval-ast \"local ok, v = pcall(function() return 42 end) if ok then return v else return -1 end\")")
|
||
(epoch 902)
|
||
(eval "(lua-eval-ast \"local ok, a, b = pcall(function() return 1, 2 end) return (ok and a + b) or 0\")")
|
||
(epoch 903)
|
||
(eval "(lua-eval-ast \"local function div(a, b) if b == 0 then error(\\\"div by zero\\\") end return a / b end local ok, r = pcall(div, 10, 2) if ok then return r else return -1 end\")")
|
||
(epoch 904)
|
||
(eval "(lua-eval-ast \"local function div(a, b) if b == 0 then error(\\\"div by zero\\\") end return a / b end local ok, e = pcall(div, 10, 0) if ok then return \\\"no\\\" else return e end\")")
|
||
(epoch 905)
|
||
(eval "(lua-eval-ast \"local function f() error({code = 42}) end local ok, err = pcall(f) return err.code\")")
|
||
(epoch 906)
|
||
(eval "(lua-eval-ast \"local ok1, e1 = pcall(function() local ok2, e2 = pcall(function() error(\\\"inner\\\") end) if not ok2 then error(\\\"outer:\\\" .. e2) end end) return e1\")")
|
||
|
||
;; xpcall
|
||
(epoch 910)
|
||
(eval "(lua-eval-ast \"local function f() error(\\\"raw\\\") end local function handler(e) return \\\"H:\\\" .. e end local ok, v = xpcall(f, handler) if ok then return \\\"no\\\" else return v end\")")
|
||
(epoch 911)
|
||
(eval "(lua-eval-ast \"local function f() return 99 end local function handler(e) return e end local ok, v = xpcall(f, handler) return v\")")
|
||
|
||
;; ── Phase 4: generic `for … in …` ──────────────────────────────
|
||
;; ipairs over array
|
||
(epoch 950)
|
||
(eval "(lua-eval-ast \"local t = {10, 20, 30} local sum = 0 for i, v in ipairs(t) do sum = sum + v end return sum\")")
|
||
(epoch 951)
|
||
(eval "(lua-eval-ast \"local t = {10, 20, 30} local last = 0 for i, v in ipairs(t) do last = i end return last\")")
|
||
(epoch 952)
|
||
(eval "(lua-eval-ast \"local t = {} local count = 0 for i, v in ipairs(t) do count = count + 1 end return count\")")
|
||
(epoch 953)
|
||
(eval "(lua-eval-ast \"local t = {1, 2, nil, 4} local c = 0 for i, v in ipairs(t) do c = c + 1 end return c\")")
|
||
|
||
;; pairs over hash
|
||
(epoch 960)
|
||
(eval "(lua-eval-ast \"local t = {a = 1, b = 2, c = 3} local sum = 0 for k, v in pairs(t) do sum = sum + v end return sum\")")
|
||
(epoch 961)
|
||
(eval "(lua-eval-ast \"local t = {x = 1, y = 2, z = 3} local n = 0 for k, v in pairs(t) do n = n + 1 end return n\")")
|
||
|
||
;; custom stateful iterator (if-else-return, works around early-return limit)
|
||
(epoch 970)
|
||
(eval "(lua-eval-ast \"local function range(n) local i = 0 return function() i = i + 1 if i > n then return nil else return i end end end local c = 0 for x in range(5) do c = c + x end return c\")")
|
||
|
||
;; 3-value iterator form (f, s, var)
|
||
(epoch 971)
|
||
(eval "(lua-eval-ast \"local function step(max, i) if i >= max then return nil else return i + 1, (i + 1) * (i + 1) end end local sum = 0 for i, v in step, 4, 0 do sum = sum + v end return sum\")")
|
||
|
||
;; pairs ignores __meta key
|
||
(epoch 980)
|
||
(eval "(lua-eval-ast \"local t = setmetatable({x = 1, y = 2}, {}) local n = 0 for k in pairs(t) do n = n + 1 end return n\")")
|
||
|
||
;; ── Phase 5: coroutines ────────────────────────────────────────
|
||
(epoch 1000)
|
||
(eval "(lua-eval-ast \"local co = coroutine.create(function() end) return coroutine.status(co)\")")
|
||
(epoch 1001)
|
||
(eval "(lua-eval-ast \"local co = coroutine.create(function() return 42 end) coroutine.resume(co) return coroutine.status(co)\")")
|
||
(epoch 1010)
|
||
(eval "(lua-eval-ast \"local co = coroutine.create(function() coroutine.yield(1) coroutine.yield(2) return 3 end) local ok1, v1 = coroutine.resume(co) local ok2, v2 = coroutine.resume(co) local ok3, v3 = coroutine.resume(co) return v1 * 100 + v2 * 10 + v3\")")
|
||
(epoch 1011)
|
||
(eval "(lua-eval-ast \"local co = coroutine.create(function(a, b) return a + b end) local ok, v = coroutine.resume(co, 10, 20) return v\")")
|
||
(epoch 1012)
|
||
(eval "(lua-eval-ast \"local co = coroutine.create(function() local x = coroutine.yield() return x + 100 end) coroutine.resume(co) local ok, v = coroutine.resume(co, 42) return v\")")
|
||
(epoch 1020)
|
||
(eval "(lua-eval-ast \"local co = coroutine.create(function() return 42 end) coroutine.resume(co) local ok, err = coroutine.resume(co) if ok then return \\\"no\\\" else return err end\")")
|
||
(epoch 1030)
|
||
(eval "(lua-eval-ast \"local gen = coroutine.wrap(function() coroutine.yield(1) coroutine.yield(2) coroutine.yield(3) end) return gen() + gen() + gen()\")")
|
||
(epoch 1040)
|
||
(eval "(lua-eval-ast \"local function iter() coroutine.yield(10) coroutine.yield(20) coroutine.yield(30) end local co = coroutine.create(iter) local sum = 0 for i = 1, 3 do local ok, v = coroutine.resume(co) sum = sum + v end return sum\")")
|
||
|
||
;; ── Phase 6: string library ───────────────────────────────────
|
||
(epoch 1100)
|
||
(eval "(lua-eval-ast \"return string.len(\\\"hello\\\")\")")
|
||
(epoch 1101)
|
||
(eval "(lua-eval-ast \"return string.upper(\\\"hi\\\")\")")
|
||
(epoch 1102)
|
||
(eval "(lua-eval-ast \"return string.lower(\\\"HI\\\")\")")
|
||
(epoch 1103)
|
||
(eval "(lua-eval-ast \"return string.rep(\\\"ab\\\", 3)\")")
|
||
(epoch 1110)
|
||
(eval "(lua-eval-ast \"return string.sub(\\\"hello\\\", 2, 4)\")")
|
||
(epoch 1111)
|
||
(eval "(lua-eval-ast \"return string.sub(\\\"hello\\\", -3)\")")
|
||
(epoch 1112)
|
||
(eval "(lua-eval-ast \"return string.sub(\\\"hello\\\", 1, -2)\")")
|
||
(epoch 1120)
|
||
(eval "(lua-eval-ast \"return string.byte(\\\"A\\\")\")")
|
||
(epoch 1121)
|
||
(eval "(lua-eval-ast \"return string.byte(\\\"ABC\\\", 2)\")")
|
||
(epoch 1130)
|
||
(eval "(lua-eval-ast \"return string.char(72, 105)\")")
|
||
(epoch 1131)
|
||
(eval "(lua-eval-ast \"return string.char(97, 98, 99)\")")
|
||
(epoch 1140)
|
||
(eval "(lua-eval-ast \"local s, e = string.find(\\\"hello world\\\", \\\"wor\\\") return s * 100 + e\")")
|
||
(epoch 1141)
|
||
(eval "(lua-eval-ast \"if string.find(\\\"abc\\\", \\\"z\\\") == nil then return 1 else return 0 end\")")
|
||
(epoch 1150)
|
||
(eval "(lua-eval-ast \"return string.match(\\\"hello\\\", \\\"ell\\\")\")")
|
||
(epoch 1160)
|
||
(eval "(lua-eval-ast \"local r, n = string.gsub(\\\"abcabc\\\", \\\"a\\\", \\\"X\\\") return r .. \\\":\\\" .. n\")")
|
||
(epoch 1161)
|
||
(eval "(lua-eval-ast \"local r, n = string.gsub(\\\"aaaa\\\", \\\"a\\\", \\\"b\\\", 2) return r .. \\\":\\\" .. n\")")
|
||
(epoch 1170)
|
||
(eval "(lua-eval-ast \"local c = 0 for w in string.gmatch(\\\"aa aa aa\\\", \\\"aa\\\") do c = c + 1 end return c\")")
|
||
(epoch 1180)
|
||
(eval "(lua-eval-ast \"return string.format(\\\"%s=%d\\\", \\\"x\\\", 42)\")")
|
||
(epoch 1181)
|
||
(eval "(lua-eval-ast \"return string.format(\\\"%d%%\\\", 50)\")")
|
||
|
||
;; ── Phase 6: math library ─────────────────────────────────────
|
||
(epoch 1200)
|
||
(eval "(lua-eval-ast \"return math.pi > 3.14 and math.pi < 3.15\")")
|
||
(epoch 1201)
|
||
(eval "(lua-eval-ast \"return math.huge > 1000000\")")
|
||
(epoch 1210)
|
||
(eval "(lua-eval-ast \"return math.abs(-7)\")")
|
||
(epoch 1211)
|
||
(eval "(lua-eval-ast \"return math.sqrt(16)\")")
|
||
(epoch 1212)
|
||
(eval "(lua-eval-ast \"return math.floor(3.7)\")")
|
||
(epoch 1213)
|
||
(eval "(lua-eval-ast \"return math.ceil(3.2)\")")
|
||
(epoch 1220)
|
||
(eval "(lua-eval-ast \"return math.max(3, 7, 1, 4)\")")
|
||
(epoch 1221)
|
||
(eval "(lua-eval-ast \"return math.min(3, 7, 1, 4)\")")
|
||
(epoch 1230)
|
||
(eval "(lua-eval-ast \"return math.pow(2, 8)\")")
|
||
(epoch 1231)
|
||
(eval "(lua-eval-ast \"return math.exp(0)\")")
|
||
(epoch 1232)
|
||
(eval "(lua-eval-ast \"return math.log(1)\")")
|
||
(epoch 1233)
|
||
(eval "(lua-eval-ast \"return math.log10(100)\")")
|
||
(epoch 1240)
|
||
(eval "(lua-eval-ast \"return math.sin(0) + math.cos(0)\")")
|
||
(epoch 1250)
|
||
(eval "(lua-eval-ast \"return math.fmod(10, 3)\")")
|
||
(epoch 1251)
|
||
(eval "(lua-eval-ast \"local i, f = math.modf(3.5) return i\")")
|
||
(epoch 1260)
|
||
(eval "(lua-eval-ast \"local r = math.random(100) return r >= 1 and r <= 100\")")
|
||
(epoch 1261)
|
||
(eval "(lua-eval-ast \"local r = math.random(5, 10) return r >= 5 and r <= 10\")")
|
||
|
||
;; ── Phase 6: table library ────────────────────────────────────
|
||
(epoch 1300)
|
||
(eval "(lua-eval-ast \"local t = {1, 2, 3} table.insert(t, 4) return #t\")")
|
||
(epoch 1301)
|
||
(eval "(lua-eval-ast \"local t = {1, 2, 3} table.insert(t, 4) return t[4]\")")
|
||
(epoch 1302)
|
||
(eval "(lua-eval-ast \"local t = {10, 30} table.insert(t, 2, 20) return t[2]\")")
|
||
(epoch 1303)
|
||
(eval "(lua-eval-ast \"local t = {10, 20, 30} table.insert(t, 1, 5) return t[1] * 100 + t[2]\")")
|
||
(epoch 1310)
|
||
(eval "(lua-eval-ast \"local t = {1, 2, 3} local v = table.remove(t) return v * 10 + #t\")")
|
||
(epoch 1311)
|
||
(eval "(lua-eval-ast \"local t = {10, 20, 30} table.remove(t, 1) return t[1] * 10 + t[2]\")")
|
||
(epoch 1320)
|
||
(eval "(lua-eval-ast \"local t = {\\\"a\\\", \\\"b\\\", \\\"c\\\"} return table.concat(t)\")")
|
||
(epoch 1321)
|
||
(eval "(lua-eval-ast \"local t = {\\\"a\\\", \\\"b\\\", \\\"c\\\"} return table.concat(t, \\\"-\\\")\")")
|
||
(epoch 1322)
|
||
(eval "(lua-eval-ast \"local t = {1, 2, 3, 4} return table.concat(t, \\\",\\\", 2, 3)\")")
|
||
(epoch 1330)
|
||
(eval "(lua-eval-ast \"local t = {3, 1, 4, 1, 5, 9, 2, 6} table.sort(t) return t[1] * 100 + t[8]\")")
|
||
(epoch 1331)
|
||
(eval "(lua-eval-ast \"local t = {3, 1, 2} table.sort(t, function(a, b) return a > b end) return t[1] * 100 + t[3]\")")
|
||
(epoch 1340)
|
||
(eval "(lua-eval-ast \"local t = {10, 20, 30} local a, b, c = unpack(t) return a + b + c\")")
|
||
(epoch 1341)
|
||
(eval "(lua-eval-ast \"local t = {10, 20, 30, 40} local a, b = table.unpack(t, 2, 3) return a + b\")")
|
||
|
||
;; ── Phase 6: io stub + print/tostring/tonumber ────────────────
|
||
(epoch 1400)
|
||
(eval "(lua-eval-ast \"io.write(\\\"hello\\\") return io.__buffer()\")")
|
||
(epoch 1401)
|
||
(eval "(lua-eval-ast \"io.write(\\\"a\\\", \\\"b\\\", \\\"c\\\") return io.__buffer()\")")
|
||
(epoch 1402)
|
||
(eval "(lua-eval-ast \"io.write(1, \\\" \\\", 2) return io.__buffer()\")")
|
||
(epoch 1410)
|
||
(eval "(lua-eval-ast \"print(\\\"x\\\", \\\"y\\\") return io.__buffer()\")")
|
||
(epoch 1411)
|
||
(eval "(lua-eval-ast \"print(1, 2, 3) return io.__buffer()\")")
|
||
(epoch 1420)
|
||
(eval "(lua-eval-ast \"return tostring(42)\")")
|
||
(epoch 1421)
|
||
(eval "(lua-eval-ast \"return tostring(nil)\")")
|
||
(epoch 1422)
|
||
(eval "(lua-eval-ast \"return tostring({})\")")
|
||
(epoch 1430)
|
||
(eval "(lua-eval-ast \"return tonumber(\\\"42\\\")\")")
|
||
(epoch 1431)
|
||
(eval "(lua-eval-ast \"if tonumber(\\\"abc\\\") == nil then return 1 else return 0 end\")")
|
||
(epoch 1440)
|
||
(eval "(lua-eval-ast \"if io.read() == nil then return 1 else return 0 end\")")
|
||
(epoch 1441)
|
||
(eval "(lua-eval-ast \"if io.open(\\\"x\\\") == nil then return 1 else return 0 end\")")
|
||
|
||
;; ── Phase 6: os stub ──────────────────────────────────────────
|
||
(epoch 1500)
|
||
(eval "(lua-eval-ast \"return type(os.time())\")")
|
||
(epoch 1501)
|
||
(eval "(lua-eval-ast \"local t1 = os.time() local t2 = os.time() return t2 > t1\")")
|
||
(epoch 1502)
|
||
(eval "(lua-eval-ast \"return os.difftime(100, 60)\")")
|
||
(epoch 1503)
|
||
(eval "(lua-eval-ast \"return type(os.clock())\")")
|
||
(epoch 1504)
|
||
(eval "(lua-eval-ast \"return type(os.date())\")")
|
||
(epoch 1505)
|
||
(eval "(lua-eval-ast \"local d = os.date(\\\"*t\\\") return d.year\")")
|
||
(epoch 1506)
|
||
(eval "(lua-eval-ast \"if os.getenv(\\\"HOME\\\") == nil then return 1 else return 0 end\")")
|
||
(epoch 1507)
|
||
(eval "(lua-eval-ast \"return type(os.tmpname())\")")
|
||
|
||
;; ── Phase 7: require / package ────────────────────────────────
|
||
(epoch 1600)
|
||
(eval "(lua-eval-ast \"package.preload.mymath = function() local m = {} m.add = function(a, b) return a + b end return m end local mm = require(\\\"mymath\\\") return mm.add(3, 4)\")")
|
||
(epoch 1601)
|
||
(eval "(lua-eval-ast \"package.preload.counter = function() local n = 0 local m = {} m.inc = function() n = n + 1 return n end return m end local c1 = require(\\\"counter\\\") local c2 = require(\\\"counter\\\") c1.inc() c1.inc() return c2.inc()\")")
|
||
(epoch 1602)
|
||
(eval "(lua-eval-ast \"local ok, err = pcall(require, \\\"nope\\\") if ok then return 0 else return 1 end\")")
|
||
(epoch 1603)
|
||
(eval "(lua-eval-ast \"package.preload.x = function() return {val = 42} end require(\\\"x\\\") return package.loaded.x.val\")")
|
||
(epoch 1604)
|
||
(eval "(lua-eval-ast \"package.preload.noret = function() end local r = require(\\\"noret\\\") return type(r)\")")
|
||
|
||
;; ── Phase 7: vararg `...` (scoreboard iteration) ──────────────
|
||
(epoch 1700)
|
||
(eval "(lua-eval-ast \"local function f(...) return ... end local a, b, c = f(1, 2, 3) return a + b + c\")")
|
||
(epoch 1701)
|
||
(eval "(lua-eval-ast \"local function f(...) local t = {...} return t[2] end return f(10, 20, 30)\")")
|
||
(epoch 1702)
|
||
(eval "(lua-eval-ast \"local function f(a, ...) return a + select(\\\"#\\\", ...) end return f(10, 1, 2, 3)\")")
|
||
(epoch 1703)
|
||
(eval "(lua-eval-ast \"local function f(...) return select(2, ...) end local a, b = f(10, 20, 30) return a + b\")")
|
||
(epoch 1704)
|
||
(eval "(lua-eval-ast \"local function sum(...) local s = 0 for _, v in ipairs({...}) do s = s + v end return s end return sum(1, 2, 3, 4, 5)\")")
|
||
(epoch 1705)
|
||
(eval "(lua-eval-ast \"local function f(a, b, ...) return a * 100 + b * 10 + select(\\\"#\\\", ...) end return f(7, 8, 1, 2, 3)\")")
|
||
|
||
;; ── Phase 7: do-block proper scoping ──────────────────────────
|
||
(epoch 1800)
|
||
(eval "(lua-eval-ast \"local i = 10 do local i = 100 end return i\")")
|
||
(epoch 1801)
|
||
(eval "(lua-eval-ast \"do local i = 10 do local i = 100 assert(i == 100) end assert(i == 10) end return \\\"ok\\\"\")")
|
||
|
||
;; ── if/else/elseif body scoping ──────────────────────────────
|
||
(epoch 1810)
|
||
(eval "(lua-eval-ast \"local x = 10 if true then local x = 99 end return x\")")
|
||
(epoch 1811)
|
||
(eval "(lua-eval-ast \"local x = 10 if false then else local x = 99 end return x\")")
|
||
(epoch 1812)
|
||
(eval "(lua-eval-ast \"local x = 10 if false then elseif true then local x = 99 end return x\")")
|
||
|
||
;; ── Lua 5.0-style `arg` table in vararg functions ─────────────
|
||
(epoch 1820)
|
||
(eval "(lua-eval-ast \"function f(a, ...) return arg.n end return f({}, 1, 2, 3)\")")
|
||
(epoch 1821)
|
||
(eval "(lua-eval-ast \"function f(a, ...) return arg[1] + arg[2] + arg[3] end return f({}, 10, 20, 30)\")")
|
||
|
||
;; ── Decimal-escape strings ────────────────────────────────────
|
||
(epoch 1830)
|
||
(eval "(lua-eval-ast \"return \\\"\\\\65\\\"\")")
|
||
(epoch 1831)
|
||
(eval "(lua-eval-ast \"if \\\"\\\\09912\\\" == \\\"c12\\\" then return 1 else return 0 end\")")
|
||
|
||
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'
|
||
|
||
# ── Phase 3: functions + closures ─────────────────────────────
|
||
check 500 "anon fn call" '6'
|
||
check 501 "anon fn no args" '42'
|
||
check 502 "iife" '12'
|
||
|
||
check 510 "local function double" '14'
|
||
check 511 "local function sum3" '6'
|
||
check 512 "local function greet" '"hi"'
|
||
|
||
check 520 "top-level function decl" '7'
|
||
check 521 "top-level id string" '"abc"'
|
||
|
||
check 530 "closure reads outer" '10'
|
||
check 531 "closure factory add5(10)" '15'
|
||
check 532 "closure with mutable counter" '3'
|
||
check 533 "closure sees later mutation" '12'
|
||
|
||
check 540 "recursive local fact(5)" '120'
|
||
check 541 "recursive top-level fib(10)" '55'
|
||
|
||
check 550 "apply(sq,4)" '16'
|
||
check 551 "twice(+1, 5)" '7'
|
||
|
||
check 560 "max with if" '7'
|
||
check 561 "sum_to(10) with for" '55'
|
||
|
||
# ── Phase 3: multi-return + unpack ────────────────────────────
|
||
check 570 "anon-fn returns 2, unpack" '3'
|
||
check 571 "local fn returns 2, unpack" '10'
|
||
check 572 "swap via multi-return" '21'
|
||
check 573 "extra returns discarded" '12'
|
||
check 574 "missing returns nil-padded" '3'
|
||
check 575 "tail-return passthrough" '12'
|
||
check 576 "non-last call truncated to 1st" '95'
|
||
check 577 "single-assign truncates to 1st" '5'
|
||
check 578 "empty return → all nil" '99'
|
||
check 579 "multi-assign (non-local)" '18'
|
||
|
||
# ── Phase 3: table constructors ────────────────────────────────
|
||
check 600 "array t[1]" '10'
|
||
check 601 "array t[3]" '30'
|
||
check 602 "array out-of-range is nil" '1'
|
||
check 610 "hash t.x+t.y" '3'
|
||
check 611 "hash name lookup" '"bob"'
|
||
check 612 "hash age lookup" '30'
|
||
check 620 "computed [k]=v" '42'
|
||
check 621 "computed [1+1]" '"two"'
|
||
check 622 "computed [concat]" '99'
|
||
check 623 "boolean key [true]" '"yes"'
|
||
check 630 "mixed array part" '2'
|
||
check 631 "mixed hash part" '"v"'
|
||
check 640 "trailing comma" '3'
|
||
check 641 "semicolon separators" '2'
|
||
check 642 "mixed separators" '4'
|
||
check 650 "nested array" '3'
|
||
check 651 "nested hash" '2'
|
||
check 660 "dynamic pos values" '14'
|
||
check 661 "function calls as values" '4'
|
||
check 670 "function-valued field + call" '10'
|
||
|
||
# ── Phase 3: raw table access ─────────────────────────────────
|
||
check 700 "t[1]=v then read" '"a"'
|
||
check 701 "t[1]+t[2] after writes" '30'
|
||
check 710 "t.x=100 persists" '100'
|
||
check 711 "t.name=... persists" '"alice"'
|
||
check 712 "overwrite existing field" '99'
|
||
check 720 "missing field is nil" '99'
|
||
check 721 "missing index is nil" '1'
|
||
check 730 "#t on 5-element array" '5'
|
||
check 731 "#t on empty" '0'
|
||
check 732 "#t after inserts" '2'
|
||
check 733 "#\"hello\"" '5'
|
||
check 740 "t.count mutate chain" '2'
|
||
check 741 "fill via for-num then read" '9'
|
||
check 742 "#t after 10 inserts" '10'
|
||
check 750 "chained t.a.b.c read" '42'
|
||
check 751 "chained t.a.x write" '7'
|
||
check 760 "t[k]=v reads via t.foo" '88'
|
||
check 761 "t[concat]=v reads via t.xy" '7'
|
||
check 770 "reference semantics t=s" '42'
|
||
|
||
# ── Phase 4: metatables ───────────────────────────────────────
|
||
check 800 "setmetatable returns t" '1'
|
||
check 801 "getmetatable roundtrip" '1'
|
||
check 810 "type(1)" '"number"'
|
||
check 811 "type(string)" '"string"'
|
||
check 812 "type({})" '"table"'
|
||
check 813 "type(nil)" '"nil"'
|
||
check 814 "type(true)" '"boolean"'
|
||
check 815 "type(function)" '"function"'
|
||
check 820 "__index table lookup" '10'
|
||
check 821 "__index chain + self" '30'
|
||
check 822 "__index as function" '"hi!"'
|
||
check 830 "__newindex fires" '"foo"'
|
||
check 840 "__add table+number" '99'
|
||
check 841 "__add two tables" '7'
|
||
check 842 "__sub + __mul chain" '18'
|
||
check 843 "__unm" '42'
|
||
check 844 "__concat" '"cat"'
|
||
check 850 "__eq" '1'
|
||
check 851 "__lt" '1'
|
||
check 852 "__le" '1'
|
||
check 860 "__call" '105'
|
||
check 870 "__len" '99'
|
||
check 880 "OO pattern self:m()" '"Rex"'
|
||
|
||
# ── Phase 4: pcall / xpcall / error ───────────────────────────
|
||
check 900 "pcall catches error(msg)" '"boom"'
|
||
check 901 "pcall ok path single val" '42'
|
||
check 902 "pcall ok path multi val" '3'
|
||
check 903 "pcall with args, ok" '5'
|
||
check 904 "pcall with args, err" '"div by zero"'
|
||
check 905 "error(table) preserved" '42'
|
||
check 906 "nested pcall" '"outer:inner"'
|
||
check 910 "xpcall invokes handler" '"H:raw"'
|
||
check 911 "xpcall ok path" '99'
|
||
|
||
# ── Phase 4: generic `for … in …` ─────────────────────────────
|
||
check 950 "ipairs sum" '60'
|
||
check 951 "ipairs last index" '3'
|
||
check 952 "ipairs empty → 0" '0'
|
||
check 953 "ipairs stops at nil" '2'
|
||
check 960 "pairs hash sum" '6'
|
||
check 961 "pairs hash count" '3'
|
||
check 970 "stateful closure iter" '15'
|
||
check 971 "3-value iterator form" '30'
|
||
check 980 "pairs skips __meta" '2'
|
||
|
||
# ── Phase 5: coroutines ────────────────────────────────────────
|
||
check 1000 "coroutine.status initial" '"suspended"'
|
||
check 1001 "coroutine.status after done" '"dead"'
|
||
check 1010 "yield/resume × 3 sequence" '123'
|
||
check 1011 "resume passes args to body" '30'
|
||
check 1012 "resume passes args via yield" '142'
|
||
check 1020 "resume dead returns error" '"cannot resume dead coroutine"'
|
||
check 1030 "coroutine.wrap" '6'
|
||
check 1040 "iterator via coroutine" '60'
|
||
|
||
# ── Phase 6: string library ───────────────────────────────────
|
||
check 1100 "string.len" '5'
|
||
check 1101 "string.upper" '"HI"'
|
||
check 1102 "string.lower" '"hi"'
|
||
check 1103 "string.rep" '"ababab"'
|
||
check 1110 "string.sub(s,i,j)" '"ell"'
|
||
check 1111 "string.sub(s,-3)" '"llo"'
|
||
check 1112 "string.sub(s,1,-2)" '"hell"'
|
||
check 1120 "string.byte" '65'
|
||
check 1121 "string.byte(s,i)" '66'
|
||
check 1130 "string.char(72,105)" '"Hi"'
|
||
check 1131 "string.char(97,98,99)" '"abc"'
|
||
check 1140 "string.find literal hit" '709'
|
||
check 1141 "string.find literal miss" '1'
|
||
check 1150 "string.match literal" '"ell"'
|
||
check 1160 "string.gsub replace all" '"XbcXbc:2"'
|
||
check 1161 "string.gsub with limit" '"bbaa:2"'
|
||
check 1170 "string.gmatch iterator" '3'
|
||
check 1180 "string.format %s=%d" '"x=42"'
|
||
check 1181 "string.format %d%%" '"50%"'
|
||
|
||
# ── Phase 6: math library ─────────────────────────────────────
|
||
check 1200 "math.pi in range" 'true'
|
||
check 1201 "math.huge big" 'true'
|
||
check 1210 "math.abs(-7)" '7'
|
||
check 1211 "math.sqrt(16)" '4'
|
||
check 1212 "math.floor(3.7)" '3'
|
||
check 1213 "math.ceil(3.2)" '4'
|
||
check 1220 "math.max(3,7,1,4)" '7'
|
||
check 1221 "math.min(3,7,1,4)" '1'
|
||
check 1230 "math.pow(2,8)" '256'
|
||
check 1231 "math.exp(0)" '1'
|
||
check 1232 "math.log(1)" '0'
|
||
check 1233 "math.log10(100)" '2'
|
||
check 1240 "math.sin(0)+math.cos(0)" '1'
|
||
check 1250 "math.fmod(10,3)" '1'
|
||
check 1251 "math.modf(3.5) int part" '3'
|
||
check 1260 "math.random(n) in range" 'true'
|
||
check 1261 "math.random(m,n) in range" 'true'
|
||
|
||
# ── Phase 6: table library ────────────────────────────────────
|
||
check 1300 "table.insert append → #t" '4'
|
||
check 1301 "table.insert value" '4'
|
||
check 1302 "table.insert(t,pos,v) mid" '20'
|
||
check 1303 "table.insert(t,1,v) prepend" '510'
|
||
check 1310 "table.remove() last" '33'
|
||
check 1311 "table.remove(t,1) shift" '230'
|
||
check 1320 "table.concat no sep" '"abc"'
|
||
check 1321 "table.concat with sep" '"a-b-c"'
|
||
check 1322 "table.concat range" '"2,3"'
|
||
check 1330 "table.sort asc" '109'
|
||
check 1331 "table.sort desc via cmp" '301'
|
||
check 1340 "unpack global" '60'
|
||
check 1341 "table.unpack(t,i,j)" '50'
|
||
|
||
# ── Phase 6: io stub + print/tostring/tonumber ────────────────
|
||
check 1400 "io.write single" '"hello"'
|
||
check 1401 "io.write multi strings" '"abc"'
|
||
check 1402 "io.write numbers + spaces" '"1 2"'
|
||
check 1410 "print two args tab-sep + NL" '"x\ty\n"'
|
||
check 1411 "print three ints" '"1\t2\t3\n"'
|
||
check 1420 "tostring(42)" '"42"'
|
||
check 1421 "tostring(nil)" '"nil"'
|
||
check 1422 "tostring({})" '"table"'
|
||
check 1430 "tonumber(\"42\")" '42'
|
||
check 1431 "tonumber(\"abc\") → nil" '1'
|
||
check 1440 "io.read() → nil" '1'
|
||
check 1441 "io.open(x) → nil" '1'
|
||
|
||
# ── Phase 6: os stub ──────────────────────────────────────────
|
||
check 1500 "os.time → number" '"number"'
|
||
check 1501 "os.time monotonic" 'true'
|
||
check 1502 "os.difftime" '40'
|
||
check 1503 "os.clock → number" '"number"'
|
||
check 1504 "os.date() default" '"string"'
|
||
check 1505 "os.date(*t).year" '1970'
|
||
check 1506 "os.getenv → nil" '1'
|
||
check 1507 "os.tmpname → string" '"string"'
|
||
|
||
# ── Phase 7: require / package ────────────────────────────────
|
||
check 1600 "require(preload) + call" '7'
|
||
check 1601 "require returns cached" '3'
|
||
check 1602 "require unknown module errors" '1'
|
||
check 1603 "package.loaded populated" '42'
|
||
check 1604 "nil return caches as true" '"boolean"'
|
||
|
||
# ── Phase 7: vararg `...` (scoreboard iteration) ──────────────
|
||
check 1700 "f(...) return ... unpack" '6'
|
||
check 1701 "{...} table from vararg" '20'
|
||
check 1702 "f(a, ...) + select(#,...)" '13'
|
||
check 1703 "select(2, ...) unpack" '50'
|
||
check 1704 "sum via ipairs({...})" '15'
|
||
check 1705 "f(a, b, ...) mixed" '783'
|
||
|
||
# ── Phase 7: do-block proper scoping ──────────────────────────
|
||
check 1800 "inner do local shadows" '10'
|
||
check 1801 "nested do scopes" '"ok"'
|
||
|
||
# ── if/else/elseif body scoping ──────────────────────────────
|
||
check 1810 "if then local shadows" '10'
|
||
check 1811 "else local shadows" '10'
|
||
check 1812 "elseif local shadows" '10'
|
||
|
||
# ── Lua 5.0-style `arg` table in vararg functions ─────────────
|
||
check 1820 "arg.n in vararg fn" '3'
|
||
check 1821 "arg[i] access" '60'
|
||
|
||
# ── Decimal-escape strings ───────────────────────────────────
|
||
check 1830 "\\65 → A" '"A"'
|
||
check 1831 "\\099 + 12 → c12" '1'
|
||
|
||
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 ]
|