lua: string metatable, high-byte chars, multi-return truthy, perf

This commit is contained in:
2026-04-25 11:15:12 +00:00
parent dd47fa8a0b
commit 8ca5c8052d
7 changed files with 196 additions and 121 deletions

View File

@@ -1,4 +1,4 @@
(define lua-truthy? (fn (v) (and (not (= v nil)) (not (= v false)))))
(define lua-truthy? (fn (v) (let ((v1 (if (and (= (type-of v) "list") (> (len v) 0) (= (first v) (quote lua-multi))) (if (> (len v) 1) (nth v 1) nil) v))) (and (not (= v1 nil)) (not (= v1 false))))))
(define
lua-to-number
@@ -151,18 +151,19 @@
lua-eq
(fn
(a b)
(cond
((and (= a nil) (= b nil)) true)
((or (= a nil) (= b nil)) false)
((and (= (type-of a) (type-of b)) (= a b)) true)
((and (= (type-of a) "dict") (= (type-of b) "dict"))
(let
((m (lua-get-mm a "__eq")))
(cond
((not (= m nil))
(let ((r (lua-first (m a b)))) (and (not (= r nil)) (not (= r false)))))
(else false))))
(else false))))
(let ((a (lua-first a)) (b (lua-first b)))
(cond
((and (= a nil) (= b nil)) true)
((or (= a nil) (= b nil)) false)
((and (= (type-of a) (type-of b)) (= a b)) true)
((and (= (type-of a) "dict") (= (type-of b) "dict"))
(let
((m (lua-get-mm a "__eq")))
(cond
((not (= m nil))
(let ((r (lua-first (m a b)))) (and (not (= r nil)) (not (= r false)))))
(else false))))
(else false)))))
(define lua-neq (fn (a b) (not (lua-eq a b))))
@@ -170,44 +171,46 @@
lua-lt
(fn
(a b)
(cond
((and (= (type-of a) "number") (= (type-of b) "number")) (< a b))
((and (= (type-of a) "string") (= (type-of b) "string")) (< a b))
(else
(let
((m (lua-get-mm a "__lt")))
(cond
((not (= m nil))
(let ((r (lua-first (m a b)))) (and (not (= r nil)) (not (= r false)))))
(else
(let
((m2 (lua-get-mm b "__lt")))
(cond
((not (= m2 nil))
(let ((r (lua-first (m2 a b)))) (and (not (= r nil)) (not (= r false)))))
(else (error "lua: attempt to compare incompatible types")))))))))))
(let ((a (lua-first a)) (b (lua-first b)))
(cond
((and (= (type-of a) "number") (= (type-of b) "number")) (< a b))
((and (= (type-of a) "string") (= (type-of b) "string")) (< a b))
(else
(let
((m (lua-get-mm a "__lt")))
(cond
((not (= m nil))
(let ((r (lua-first (m a b)))) (and (not (= r nil)) (not (= r false)))))
(else
(let
((m2 (lua-get-mm b "__lt")))
(cond
((not (= m2 nil))
(let ((r (lua-first (m2 a b)))) (and (not (= r nil)) (not (= r false)))))
(else (error "lua: attempt to compare incompatible types"))))))))))))
(define
lua-le
(fn
(a b)
(cond
((and (= (type-of a) "number") (= (type-of b) "number")) (<= a b))
((and (= (type-of a) "string") (= (type-of b) "string"))
(or (< a b) (= a b)))
(else
(let
((m (lua-get-mm a "__le")))
(cond
((not (= m nil))
(let ((r (lua-first (m a b)))) (and (not (= r nil)) (not (= r false)))))
(else
(let
((m2 (lua-get-mm b "__le")))
(cond
((not (= m2 nil))
(let ((r (lua-first (m2 a b)))) (and (not (= r nil)) (not (= r false)))))
(else (not (lua-lt b a))))))))))))
(let ((a (lua-first a)) (b (lua-first b)))
(cond
((and (= (type-of a) "number") (= (type-of b) "number")) (<= a b))
((and (= (type-of a) "string") (= (type-of b) "string"))
(or (< a b) (= a b)))
(else
(let
((m (lua-get-mm a "__le")))
(cond
((not (= m nil))
(let ((r (lua-first (m a b)))) (and (not (= r nil)) (not (= r false)))))
(else
(let
((m2 (lua-get-mm b "__le")))
(cond
((not (= m2 nil))
(let ((r (lua-first (m2 a b)))) (and (not (= r nil)) (not (= r false)))))
(else (not (lua-lt b a)))))))))))))
(define lua-gt (fn (a b) (lua-lt b a)))
@@ -271,14 +274,16 @@
(fn (i)
(when (< i (len v))
(begin
(set! t (assoc t (str array-idx) (nth v i)))
(when (not (= (nth v i) nil))
(set! t (assoc t (str array-idx) (nth v i))))
(set! array-idx (+ array-idx 1))
(spread-loop (+ i 1))))))
(spread-loop 1)))
(else
(let ((val (if (lua-multi? v) (lua-first v) v)))
(begin
(set! t (assoc t (str array-idx) val))
(when (not (= val nil))
(set! t (assoc t (str array-idx) val)))
(set! array-idx (+ array-idx 1))))))))
((= (first f) "kv")
(let
@@ -294,6 +299,7 @@
(t k)
(cond
((= t nil) nil)
((= (type-of t) "string") (lua-get string k))
((not (= (type-of t) "dict")) nil)
(else
(let
@@ -315,6 +321,8 @@
(let
((key (str k)))
(cond
((= v nil)
(when (has-key? t key) (dict-delete! t key)))
((has-key? t key) (dict-set! t key v))
(else
(let
@@ -1015,14 +1023,21 @@
(b-loop ni)
out)))))))))))
(define __lua-ctrl-32 "
")
(define __lua-127-255 "<7F>ƒ„…†‡ˆ‰ŠŒ<E280B9>Ž<EFBFBD><C5BD>“”•˜™šœ<E280BA>žŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ")
(define
lua-char-one
(fn (n)
((= n 9) "\t")
(cond
((= n 9) "\t")
((= n 10) "\n")
((= n 13) "\r")
((and (>= n 0) (< n 32)) (char-at __lua-ctrl-32 n))
((and (>= n 32) (<= n 126)) (char-at __ascii-32-126 (- n 32)))
((and (>= n 127) (<= n 255)) (char-at __lua-127-255 (- n 127)))
(else (error (str "lua: string.char out of range: " n))))))
@@ -1999,7 +2014,14 @@
(list
(list (make-symbol "lua-return-sentinel?") (make-symbol "e"))
(list (make-symbol "lua-return-value") (make-symbol "e"))))
(let ((wrapped (list (make-symbol "fn") (list (make-symbol "&rest") (make-symbol "__args")) guarded)))
(list (make-symbol "let") (list) compiled))))
(let ((wrapped (list
(make-symbol "fn")
(list (make-symbol "&rest") (make-symbol "__args"))
(list (make-symbol "let")
(list (list (make-symbol "__varargs")
(list (make-symbol "lua-varargs")
(make-symbol "__args") 0)))
guarded))))
(eval-expr wrapped)))))))
@@ -2015,7 +2037,9 @@
(let ((n (first args)) (rest-args (rest args)))
(cond
((= n "#") (len rest-args))
(let ((i (- n 1)))
((= (type-of n) "number")
(let ((i (if (< n 0)
(+ (len rest-args) 1 n -1)
(- n 1))))
(cond
((< i 0) (error "lua: bad argument to select"))
@@ -2075,7 +2099,7 @@
(dict-set! __package-loaded "coroutine" coroutine)
(dict-set! __package-loaded "package" package)
(dict-set! __package-loaded "_G" _G)
(define arg {})
(define arg nil)
;; preload debug stub
@@ -2141,3 +2165,44 @@
(fn (e) (and (= (type-of e) "list") (> (len e) 0) (= (first e) (quote lua-brk)))))
(define dofile (fn (&rest args) nil))
(define loadfile (fn (&rest args) nil))
;; Populate _G with the standard Lua 5.1 global environment.
;; _G must be non-empty so that next(_G) returns a key-value pair.
(dict-set! _G "assert" assert)
(dict-set! _G "collectgarbage" collectgarbage)
(dict-set! _G "dofile" dofile)
(dict-set! _G "error" error)
(dict-set! _G "getfenv" getfenv)
(dict-set! _G "getmetatable" getmetatable)
(dict-set! _G "ipairs" ipairs)
(dict-set! _G "load" load)
(dict-set! _G "loadfile" loadfile)
(dict-set! _G "loadstring" loadstring)
(dict-set! _G "next" next)
(dict-set! _G "pairs" pairs)
(dict-set! _G "pcall" pcall)
(dict-set! _G "print" print)
(dict-set! _G "rawequal" rawequal)
(dict-set! _G "rawget" rawget)
(dict-set! _G "rawset" rawset)
(dict-set! _G "require" require)
(dict-set! _G "select" select)
(dict-set! _G "setfenv" setfenv)
(dict-set! _G "setmetatable" setmetatable)
(dict-set! _G "tonumber" tonumber)
(dict-set! _G "tostring" tostring)
(dict-set! _G "type" type)
(dict-set! _G "unpack" unpack)
(dict-set! _G "xpcall" xpcall)
(dict-set! _G "string" string)
(dict-set! _G "table" table)
(dict-set! _G "math" math)
(dict-set! _G "io" io)
(dict-set! _G "os" os)
(dict-set! _G "coroutine" coroutine)
(dict-set! _G "package" package)
(dict-set! _G "debug" debug)
(dict-set! _G "_VERSION" _VERSION)
(dict-set! _G "_G" _G)
;; Soft mode: skip tests that require io/os/C facilities

View File

@@ -1,33 +1,25 @@
{
"totals": {
"pass": 1,
"fail": 9,
"timeout": 6,
"pass": 3,
"fail": 8,
"timeout": 5,
"skip": 8,
"total": 24,
"runnable": 16,
"pass_rate": 6.2
"pass_rate": 18.8
},
"top_failure_modes": [
[
"timeout",
6
"other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"assertion failed!\\\\\\\"\\",
7
],
[
"other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"assertion failed!\\\\\\\"\\",
"timeout",
5
],
[
"other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"lua: attempt to call non-functio",
2
],
[
"other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"lua: module 'C' not found\\\\\\\"\\",
1
],
[
"undefined symbol: fat\\",
1
]
],
"results": [
@@ -47,19 +39,19 @@
"name": "attrib.lua",
"status": "fail",
"reason": "other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"lua: module 'C' not found\\\\\\\"\\",
"ms": 6174
"ms": 6616
},
{
"name": "big.lua",
"status": "timeout",
"reason": "per-test timeout",
"ms": 8007
"ms": 8008
},
{
"name": "calls.lua",
"status": "fail",
"reason": "undefined symbol: fat\\",
"ms": 5270
"status": "timeout",
"reason": "per-test timeout",
"ms": 8006
},
{
"name": "checktable.lua",
@@ -71,7 +63,7 @@
"name": "closure.lua",
"status": "timeout",
"reason": "per-test timeout",
"ms": 8006
"ms": 8000
},
{
"name": "code.lua",
@@ -81,9 +73,9 @@
},
{
"name": "constructs.lua",
"status": "timeout",
"reason": "per-test timeout",
"ms": 8007
"status": "fail",
"reason": "other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"assertion failed!\\\\\\\"\\",
"ms": 7429
},
{
"name": "db.lua",
@@ -95,13 +87,13 @@
"name": "errors.lua",
"status": "fail",
"reason": "other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"assertion failed!\\\\\\\"\\",
"ms": 4731
"ms": 3517
},
{
"name": "events.lua",
"status": "timeout",
"reason": "per-test timeout",
"ms": 8007
"status": "fail",
"reason": "other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"assertion failed!\\\\\\\"\\",
"ms": 7893
},
{
"name": "files.lua",
@@ -119,13 +111,13 @@
"name": "literals.lua",
"status": "fail",
"reason": "other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"assertion failed!\\\\\\\"\\",
"ms": 1996
"ms": 5676
},
{
"name": "locals.lua",
"status": "fail",
"reason": "other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"lua: attempt to call non-functio",
"ms": 1785
"reason": "other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"assertion failed!\\\\\\\"\\",
"ms": 1829
},
{
"name": "main.lua",
@@ -135,9 +127,9 @@
},
{
"name": "math.lua",
"status": "fail",
"reason": "other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"lua: attempt to call non-functio",
"ms": 4610
"status": "pass",
"reason": "",
"ms": 4512
},
{
"name": "nextvar.lua",
@@ -149,31 +141,31 @@
"name": "pm.lua",
"status": "fail",
"reason": "other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"assertion failed!\\\\\\\"\\",
"ms": 7860
"ms": 6665
},
{
"name": "sort.lua",
"status": "timeout",
"reason": "per-test timeout",
"ms": 8003
"ms": 8007
},
{
"name": "strings.lua",
"status": "fail",
"reason": "other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"assertion failed!\\\\\\\"\\",
"ms": 4636
"ms": 4488
},
{
"name": "vararg.lua",
"status": "fail",
"reason": "other: Unhandled exception: \\\"Unhandled exception: \\\\\\\"assertion failed!\\\\\\\"\\",
"ms": 2770
"status": "pass",
"reason": "",
"ms": 2734
},
{
"name": "verybig.lua",
"status": "pass",
"reason": "",
"ms": 1319
"ms": 612
}
]
}

View File

@@ -1,15 +1,13 @@
# Lua-on-SX conformance scoreboard
**Pass rate:** 1/16 runnable (6.2%)
fail=9 timeout=6 skip=8 total=24
**Pass rate:** 3/16 runnable (18.8%)
fail=8 timeout=5 skip=8 total=24
## Top failure modes
- **6x** timeout
- **5x** other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\
- **2x** other: Unhandled exception: \"Unhandled exception: \\\"lua: attempt to call non-functio
- **7x** other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\
- **5x** timeout
- **1x** other: Unhandled exception: \"Unhandled exception: \\\"lua: module 'C' not found\\\"\
- **1x** undefined symbol: fat\
## Per-test results
@@ -17,25 +15,25 @@ fail=9 timeout=6 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: \\\"lua: module 'C' not found\\\"\ | 6174 |
| big.lua | timeout | per-test timeout | 8007 |
| calls.lua | fail | undefined symbol: fat\ | 5270 |
| attrib.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"lua: module 'C' not found\\\"\ | 6616 |
| big.lua | timeout | per-test timeout | 8008 |
| calls.lua | timeout | per-test timeout | 8006 |
| checktable.lua | skip | internal debug helpers | 0 |
| closure.lua | timeout | per-test timeout | 8006 |
| closure.lua | timeout | per-test timeout | 8000 |
| code.lua | skip | bytecode inspection via debug library | 0 |
| constructs.lua | timeout | per-test timeout | 8007 |
| constructs.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 7429 |
| db.lua | skip | debug library | 0 |
| errors.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 4731 |
| events.lua | timeout | per-test timeout | 8007 |
| errors.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 3517 |
| events.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 7893 |
| files.lua | skip | io library | 0 |
| gc.lua | skip | collectgarbage / finalisers | 0 |
| literals.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 1996 |
| locals.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"lua: attempt to call non-functio | 1785 |
| literals.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 5676 |
| locals.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 1829 |
| main.lua | skip | standalone interpreter driver | 0 |
| math.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"lua: attempt to call non-functio | 4610 |
| math.lua | pass | - | 4512 |
| nextvar.lua | timeout | per-test timeout | 8007 |
| pm.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 7860 |
| sort.lua | timeout | per-test timeout | 8003 |
| strings.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 4636 |
| vararg.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 2770 |
| verybig.lua | pass | - | 1319 |
| pm.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 6665 |
| sort.lua | timeout | per-test timeout | 8007 |
| strings.lua | fail | other: Unhandled exception: \"Unhandled exception: \\\"assertion failed!\\\"\ | 4488 |
| vararg.lua | pass | - | 2734 |
| verybig.lua | pass | - | 612 |

View File

@@ -1008,6 +1008,12 @@ cat > "$TMPFILE" << 'EPOCHS'
(epoch 1925)
(eval "(lua-eval-ast \"return string.format('%.3s', 'hello')\")")
;; ── New-style vararg: arg is nil when ... used in body ──────
(epoch 1930)
(eval "(lua-eval-ast \"function f(...) local x = {...} return arg == nil and 1 or 0 end return f(1,2,3)\")")
(epoch 1931)
(eval "(lua-eval-ast \"function f(...) return select('#', ...) end return f(10,20,30)\")")
EPOCHS
OUTPUT=$(timeout 60 "$SX_SERVER" < "$TMPFILE" 2>/dev/null)
@@ -1530,6 +1536,10 @@ check 1923 "%X HEX" '"FF"'
check 1924 "%c char" '"A"'
check 1925 "%.3s precision" '"hel"'
# ── New-style vararg: arg is nil when ... used in body ───────
check 1930 "new-style vararg arg==nil" '1'
check 1931 "select # vararg count" '3'
TOTAL=$((PASS + FAIL))
if [ $FAIL -eq 0 ]; then
echo "ok $PASS/$TOTAL Lua-on-SX tests passed"

Binary file not shown.

View File

@@ -204,6 +204,16 @@
(make-symbol "arg")
(list (make-symbol "lua-varargs-arg-table") (make-symbol "__args") n))))
(define
lua-body-uses-vararg?
(fn
(node)
(cond
((not (= (type-of node) "list")) false)
((= (first node) (quote lua-vararg)) true)
((= (first node) (quote lua-function)) false)
(else (some lua-body-uses-vararg? node)))))
(define
lua-tx-function-guard
(fn (body-sx)
@@ -236,9 +246,10 @@
((all-bindings
(if is-vararg
(append bindings
(list
(lua-tx-function-varargs-binding (len params))
(lua-tx-function-arg-binding (len params))))
(list (lua-tx-function-varargs-binding (len params)))
(if (lua-body-uses-vararg? body)
(list)
(list (lua-tx-function-arg-binding (len params)))))
bindings)))
(list
(make-symbol "fn")
@@ -518,10 +529,8 @@
((target (nth node 1)) (func (nth node 2)))
(cond
((= (first target) (quote lua-name))
(list
(make-symbol "define")
(make-symbol (nth target 1))
(lua-tx func)))
(let ((nm (nth target 1)))
(list (make-symbol "set!") (make-symbol nm) (lua-tx func))))
((= (first target) (quote lua-field))
(list
(make-symbol "lua-set!")