From 418a0dc1203908b48bb9c520a126eac3b73d0089 Mon Sep 17 00:00:00 2001 From: giles Date: Fri, 24 Apr 2026 17:23:39 +0000 Subject: [PATCH] =?UTF-8?q?lua:=20raw=20table=20access=20=E2=80=94=20mutat?= =?UTF-8?q?ing=20set!,=20len=20via=20has-key=3F,=20+19=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/lua/runtime.sx | 4 +-- lib/lua/test.sh | 76 ++++++++++++++++++++++++++++++++++++++++++++++ plans/lua-on-sx.md | 3 +- 3 files changed, 80 insertions(+), 3 deletions(-) diff --git a/lib/lua/runtime.sx b/lib/lua/runtime.sx index d21b92bb..83eeb2d0 100644 --- a/lib/lua/runtime.sx +++ b/lib/lua/runtime.sx @@ -123,7 +123,7 @@ (fn (i) (if - (has? a (str i)) + (has-key? a (str i)) (begin (set! n i) (count-loop (+ i 1))) n))) (count-loop 1)))) @@ -168,7 +168,7 @@ (t k) (if (= t nil) nil (let ((v (get t (str k)))) (if (= v nil) nil v))))) -(define lua-set! (fn (t k v) (assoc t (str k) v))) +(define lua-set! (fn (t k v) (dict-set! t (str k) v))) (define lua-multi? diff --git a/lib/lua/test.sh b/lib/lua/test.sh index 0b473fd2..5bb5d6b5 100755 --- a/lib/lua/test.sh +++ b/lib/lua/test.sh @@ -539,6 +539,61 @@ cat > "$TMPFILE" << 'EPOCHS' (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\")") + EPOCHS OUTPUT=$(timeout 60 "$SX_SERVER" < "$TMPFILE" 2>/dev/null) @@ -823,6 +878,27 @@ 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' + TOTAL=$((PASS + FAIL)) if [ $FAIL -eq 0 ]; then echo "ok $PASS/$TOTAL Lua-on-SX tests passed" diff --git a/plans/lua-on-sx.md b/plans/lua-on-sx.md index 7fb07cf0..8c369897 100644 --- a/plans/lua-on-sx.md +++ b/plans/lua-on-sx.md @@ -54,7 +54,7 @@ Each item: implement → tests → tick box → update progress log. - [x] `function` (anon, local, top-level), closures - [x] Multi-return: return as list, unpack at call sites - [x] Table constructors (array + hash + computed keys) -- [ ] Raw table access `t.k` / `t[k]` (no metatables yet) +- [x] Raw table access `t.k` / `t[k]` (no metatables yet) - [ ] Vendor PUC-Rio 5.1.5 suite to `lib/lua/lua-tests/` (just `.lua` files) - [ ] `lib/lua/conformance.sh` + Python runner (model on `lib/js/test262-runner.py`) - [ ] `scoreboard.json` + `scoreboard.md` baseline @@ -82,6 +82,7 @@ Each item: implement → tests → tick box → update progress log. _Newest first. Agent appends on every commit._ +- 2026-04-24: lua: raw table access — fix `lua-set!` to use `dict-set!` (mutating), fix `lua-len` `has?`→`has-key?`, `#t` works, mutation/chained/computed-key writes + reference semantics. 224 total tests. - 2026-04-24: lua: phase 3 — table constructors verified (array, hash, computed keys, mixed, nested, dynamic values, fn values, sep variants). 205 total tests. - 2026-04-24: lua: multi-return — `lua-multi` tagged value, `lua-first`/`lua-nth-ret`/`lua-pack-return` runtime, tail-position spread in return/local/assign. 185 total tests. - 2026-04-24: lua: phase 3 — functions (anon/local/top-level) + closures verified (lexical capture, mutation-through-closure, recursion, HOFs). 175 total tests.