diff --git a/lib/lua/test.sh b/lib/lua/test.sh index 96a2e495..f644888a 100755 --- a/lib/lua/test.sh +++ b/lib/lua/test.sh @@ -409,6 +409,57 @@ cat > "$TMPFILE" << 'EPOCHS' (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)\")") + EPOCHS OUTPUT=$(timeout 60 "$SX_SERVER" < "$TMPFILE" 2>/dev/null) @@ -633,6 +684,32 @@ 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' + 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 9ae8fe61..8f1d8c17 100644 --- a/plans/lua-on-sx.md +++ b/plans/lua-on-sx.md @@ -51,7 +51,7 @@ Each item: implement → tests → tick box → update progress log. - [x] 30+ eval tests in `lib/lua/tests/eval.sx` ### Phase 3 — tables + functions + first PUC-Rio slice -- [ ] `function` (anon, local, top-level), closures +- [x] `function` (anon, local, top-level), closures - [ ] Multi-return: return as list, unpack at call sites - [ ] Table constructors (array + hash + computed keys) - [ ] Raw table access `t.k` / `t[k]` (no metatables yet) @@ -82,6 +82,7 @@ Each item: implement → tests → tick box → update progress log. _Newest first. Agent appends on every commit._ +- 2026-04-24: lua: phase 3 — functions (anon/local/top-level) + closures verified (lexical capture, mutation-through-closure, recursion, HOFs). 175 total tests. - 2026-04-24: lua: phase 2 transpile — arithmetic, comparison, short-circuit logical, `..` concat, if/while/repeat/for-num/local/assign. 157 total tests green. - 2026-04-24: lua: parser (exprs with precedence, all phase-1 statements, funcbody, table ctors, method/chained calls) — 112 total tokenizer+parser tests - 2026-04-24: lua: tokenizer (numbers/strings/long-brackets/keywords/ops/comments) + 56 tests