diff --git a/lib/lua/runtime.sx b/lib/lua/runtime.sx index abd7a3d7..090415d3 100644 --- a/lib/lua/runtime.sx +++ b/lib/lua/runtime.sx @@ -1591,3 +1591,21 @@ ;; T — debug/testC placeholder for tests that check it conditionally (define T nil) + +;; Build Lua 5.0-style `arg` table: array + .n counter, skipping leading explicit params. +(define + lua-varargs-arg-table + (fn (args skip) + (let ((t {}) (n 0)) + (begin + (define + va-build + (fn (i) + (when (< i (len args)) + (begin + (set! n (+ n 1)) + (dict-set! t (str n) (nth args i)) + (va-build (+ i 1)))))) + (va-build skip) + (dict-set! t "n" n) + t)))) diff --git a/lib/lua/scoreboard.json b/lib/lua/scoreboard.json index 558f4eb2..314ffd65 100644 --- a/lib/lua/scoreboard.json +++ b/lib/lua/scoreboard.json @@ -39,7 +39,7 @@ "name": "attrib.lua", "status": "fail", "reason": "other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"assertion failed!\\\\\\\"\\", - "ms": 7069 + "ms": 7512 }, { "name": "big.lua", @@ -51,7 +51,7 @@ "name": "calls.lua", "status": "fail", "reason": "other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"assertion failed!\\\\\\\"\\", - "ms": 5059 + "ms": 5982 }, { "name": "checktable.lua", @@ -63,7 +63,7 @@ "name": "closure.lua", "status": "timeout", "reason": "per-test timeout", - "ms": 8008 + "ms": 8007 }, { "name": "code.lua", @@ -75,7 +75,7 @@ "name": "constructs.lua", "status": "fail", "reason": "other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"assertion failed!\\\\\\\"\\", - "ms": 4593 + "ms": 5319 }, { "name": "db.lua", @@ -87,13 +87,13 @@ "name": "errors.lua", "status": "fail", "reason": "other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"assertion failed!\\\\\\\"\\", - "ms": 3390 + "ms": 3803 }, { "name": "events.lua", "status": "fail", "reason": "other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"assertion failed!\\\\\\\"\\", - "ms": 7477 + "ms": 7620 }, { "name": "files.lua", @@ -111,13 +111,13 @@ "name": "literals.lua", "status": "fail", "reason": "other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"assertion failed!\\\\\\\"\\", - "ms": 1883 + "ms": 1927 }, { "name": "locals.lua", "status": "fail", "reason": "other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"lua: attempt to call non-functio", - "ms": 1642 + "ms": 1702 }, { "name": "main.lua", @@ -129,43 +129,43 @@ "name": "math.lua", "status": "fail", "reason": "other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"assertion failed!\\\\\\\"\\", - "ms": 4194 + "ms": 4183 }, { "name": "nextvar.lua", "status": "fail", "reason": "other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"assertion failed!\\\\\\\"\\", - "ms": 6779 + "ms": 7853 }, { "name": "pm.lua", "status": "fail", "reason": "other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"assertion failed!\\\\\\\"\\", - "ms": 5731 + "ms": 6268 }, { "name": "sort.lua", "status": "timeout", "reason": "per-test timeout", - "ms": 8008 + "ms": 8007 }, { "name": "strings.lua", "status": "fail", "reason": "other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"assertion failed!\\\\\\\"\\", - "ms": 3935 + "ms": 4020 }, { "name": "vararg.lua", "status": "fail", "reason": "other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"assertion failed!\\\\\\\"\\", - "ms": 2273 + "ms": 2349 }, { "name": "verybig.lua", "status": "fail", "reason": "other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"lua: attempt to call non-functio", - "ms": 564 + "ms": 579 } ] } \ No newline at end of file diff --git a/lib/lua/scoreboard.md b/lib/lua/scoreboard.md index b03a2697..db21961e 100644 --- a/lib/lua/scoreboard.md +++ b/lib/lua/scoreboard.md @@ -15,25 +15,25 @@ fail=13 timeout=3 skip=8 total=24 |---|---|---|---:| | all.lua | skip | driver uses dofile to chain other tests | 0 | | api.lua | skip | requires testC (C debug library) | 0 | -| attrib.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 7069 | +| attrib.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 7512 | | big.lua | timeout | per-test timeout | 8007 | -| calls.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 5059 | +| calls.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 5982 | | checktable.lua | skip | internal debug helpers | 0 | -| closure.lua | timeout | per-test timeout | 8008 | +| closure.lua | timeout | per-test timeout | 8007 | | code.lua | skip | bytecode inspection via debug library | 0 | -| constructs.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 4593 | +| constructs.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 5319 | | db.lua | skip | debug library | 0 | -| errors.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 3390 | -| events.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 7477 | +| errors.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 3803 | +| events.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 7620 | | files.lua | skip | io library | 0 | | gc.lua | skip | collectgarbage / finalisers | 0 | -| literals.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 1883 | -| locals.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"lua: attempt to call non-functio | 1642 | +| literals.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 1927 | +| locals.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"lua: attempt to call non-functio | 1702 | | main.lua | skip | standalone interpreter driver | 0 | -| math.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 4194 | -| nextvar.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 6779 | -| pm.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 5731 | -| sort.lua | timeout | per-test timeout | 8008 | -| strings.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 3935 | -| vararg.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 2273 | -| verybig.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"lua: attempt to call non-functio | 564 | +| math.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 4183 | +| nextvar.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 7853 | +| pm.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 6268 | +| sort.lua | timeout | per-test timeout | 8007 | +| strings.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 4020 | +| vararg.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 2349 | +| verybig.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"lua: attempt to call non-functio | 579 | diff --git a/lib/lua/test.sh b/lib/lua/test.sh index cadc2c3f..cd2b70a0 100755 --- a/lib/lua/test.sh +++ b/lib/lua/test.sh @@ -916,6 +916,12 @@ cat > "$TMPFILE" << 'EPOCHS' (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)\")") + EPOCHS OUTPUT=$(timeout 60 "$SX_SERVER" < "$TMPFILE" 2>/dev/null) @@ -1381,6 +1387,10 @@ 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' + TOTAL=$((PASS + FAIL)) if [ $FAIL -eq 0 ]; then echo "ok $PASS/$TOTAL Lua-on-SX tests passed" diff --git a/lib/lua/transpile.sx b/lib/lua/transpile.sx index f7feaefe..8c5e39a4 100644 --- a/lib/lua/transpile.sx +++ b/lib/lua/transpile.sx @@ -180,6 +180,13 @@ (make-symbol "__varargs") (list (make-symbol "lua-varargs") (make-symbol "__args") n)))) +(define + lua-tx-function-arg-binding + (fn (n) + (list + (make-symbol "arg") + (list (make-symbol "lua-varargs-arg-table") (make-symbol "__args") n)))) + (define lua-tx-function (fn @@ -200,7 +207,10 @@ (let ((all-bindings (if is-vararg - (append bindings (list (lua-tx-function-varargs-binding (len params)))) + (append bindings + (list + (lua-tx-function-varargs-binding (len params)) + (lua-tx-function-arg-binding (len params)))) bindings))) (list (make-symbol "fn") diff --git a/plans/lua-on-sx.md b/plans/lua-on-sx.md index feb0a92a..d4886605 100644 --- a/plans/lua-on-sx.md +++ b/plans/lua-on-sx.md @@ -82,6 +82,7 @@ Each item: implement → tests → tick box → update progress log. _Newest first. Agent appends on every commit._ +- 2026-04-24: lua: scoreboard iteration — Lua 5.0-style `arg` auto-binding inside vararg functions (some PUC-Rio tests still rely on it). `lua-varargs-arg-table` builds `{1=v1, 2=v2, …, n=count}`; transpile adds `arg` binding alongside `__varargs` when `is-vararg`. Diagnosis done with assert-counter instrumentation — literals.lua fails at #4 (long-string NL rule), vararg.lua was at #2 (arg table — FIXED), attrib.lua at #9, locals.lua now past asserts into call-non-fn. 360 tests. - 2026-04-24: lua: scoreboard iteration — **`loadstring` scoping**. Temporarily instrumented `lua-assert` with a counter, found `locals.lua` fails at assertion #5: `loadstring('local a = {}')() → assert(type(a) ~= 'table')`. The loadstring'd code's `local a` was leaking to outer scope because `lua-eval-ast` ran at top-level. Fixed by transpiling once and wrapping the AST in `(let () …)` before `eval-expr`. - 2026-04-24: lua: scoreboard iteration — **`if`/`else`/`elseif` body scoping** (latent bug). `else local x = 99` was leaking to enclosing scope. Wrap all three branches in `(let () …)` via `lua-tx-if-body`. 358 tests. - 2026-04-24: lua: scoreboard iteration — **`do`-block proper scoping**. Was transpiling `do ... end` to a raw `lua-tx` pass-through, so `define`s inside leaked to the enclosing scope (`do local i = 100 end` overwrote outer `i`). Now wraps in `(let () body)` for proper lexical isolation. 355 tests, +2 scoping tests.