lua: pcall/xpcall/error via guard+raise; arity-dispatch lua-apply +9 tests
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled

This commit is contained in:
2026-04-24 18:05:35 +00:00
parent 43c13c4eb1
commit e224fb2db0
3 changed files with 85 additions and 3 deletions

View File

@@ -384,6 +384,24 @@
(define sx-apply-ref apply)
(define
lua-apply
(fn
(f rargs)
(let
((n (len rargs)))
(cond
((= n 0) (f))
((= n 1) (f (nth rargs 0)))
((= n 2) (f (nth rargs 0) (nth rargs 1)))
((= n 3) (f (nth rargs 0) (nth rargs 1) (nth rargs 2)))
((= n 4) (f (nth rargs 0) (nth rargs 1) (nth rargs 2) (nth rargs 3)))
((= n 5) (f (nth rargs 0) (nth rargs 1) (nth rargs 2) (nth rargs 3) (nth rargs 4)))
((= n 6) (f (nth rargs 0) (nth rargs 1) (nth rargs 2) (nth rargs 3) (nth rargs 4) (nth rargs 5)))
((= n 7) (f (nth rargs 0) (nth rargs 1) (nth rargs 2) (nth rargs 3) (nth rargs 4) (nth rargs 5) (nth rargs 6)))
((= n 8) (f (nth rargs 0) (nth rargs 1) (nth rargs 2) (nth rargs 3) (nth rargs 4) (nth rargs 5) (nth rargs 6) (nth rargs 7)))
(else (sx-apply-ref f rargs))))))
(define
lua-call
(fn
@@ -392,11 +410,41 @@
((f (first args)) (rargs (rest args)))
(cond
((or (= (type-of f) "function") (= (type-of f) "lambda"))
(sx-apply-ref f rargs))
(lua-apply f rargs))
((= (type-of f) "dict")
(let
((m (lua-get-mm f "__call")))
(cond
((= m nil) (error "lua: attempt to call non-function"))
(else (sx-apply-ref m (cons f rargs))))))
(else (lua-apply m (cons f rargs))))))
(else (error "lua: attempt to call non-function"))))))
(define lua-error (fn (&rest args) (raise (first args))))
(define error lua-error)
(define
pcall
(fn
(&rest args)
(let
((f (first args)) (rargs (rest args)))
(guard
(e (true (list (quote lua-multi) false e)))
(let
((r (lua-apply f rargs)))
(cond
((lua-multi? r) (cons (quote lua-multi) (cons true (rest r))))
(else (list (quote lua-multi) true r))))))))
(define
xpcall
(fn
(f msgh)
(guard
(e (true (list (quote lua-multi) false (lua-first (lua-apply msgh (list e))))))
(let
((r (lua-apply f (list))))
(cond
((lua-multi? r) (cons (quote lua-multi) (cons true (rest r))))
(else (list (quote lua-multi) true r)))))))

View File

@@ -659,6 +659,28 @@ cat > "$TMPFILE" << 'EPOCHS'
(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\")")
EPOCHS
OUTPUT=$(timeout 60 "$SX_SERVER" < "$TMPFILE" 2>/dev/null)
@@ -989,6 +1011,17 @@ 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'
TOTAL=$((PASS + FAIL))
if [ $FAIL -eq 0 ]; then
echo "ok $PASS/$TOTAL Lua-on-SX tests passed"

View File

@@ -61,7 +61,7 @@ Each item: implement → tests → tick box → update progress log.
### Phase 4 — metatables + error handling (next run)
- [x] Metatable dispatch: `__index`, `__newindex`, `__add`/`__sub`/…, `__eq`, `__lt`, `__call`, `__tostring`, `__len`
- [ ] `pcall`/`xpcall`/`error` via handler-bind
- [x] `pcall`/`xpcall`/`error` via handler-bind
- [ ] Generic `for … in …`
### Phase 5 — coroutines (the showcase)
@@ -82,6 +82,7 @@ Each item: implement → tests → tick box → update progress log.
_Newest first. Agent appends on every commit._
- 2026-04-24: lua: `pcall`/`xpcall`/`error` via SX `guard` + `raise`. Added `lua-apply` (arity-dispatch 0-8, apply fallback) because SX `apply` re-wraps raises as "Unhandled exception". Table payloads preserved (`error({code = 42})`). 256 total tests.
- 2026-04-24: lua: phase 4 — metatable dispatch (`__index`/`__newindex`/arith/compare/`__call`/`__len`), `setmetatable`/`getmetatable`/`type` globals, OO `self:method` pattern. Transpile routes all calls through `lua-call` (stashed `sx-apply-ref` to dodge user-shadowing of SX `apply`). Skipped `__tostring` (needs `tostring()` builtin). 247 total tests.
- 2026-04-24: lua: PUC-Rio scoreboard baseline — 0/16 runnable pass (0.0%). Top modes: 14× parse error, 1× `print` undef, 1× vararg transpile. Phase 3 complete.
- 2026-04-24: lua: conformance runner — `conformance.sh` shim + `conformance.py` (long-lived sx_server, epoch protocol, classify_error, writes scoreboard.{json,md}). 24 files classified in full run: 8 skip / 16 fail / 0 timeout.