lua: io stub (buffered) + print/tostring/tonumber +12 tests
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
This commit is contained in:
@@ -1129,3 +1129,112 @@
|
|||||||
(dict-set! table "maxn" lua-table-maxn)
|
(dict-set! table "maxn" lua-table-maxn)
|
||||||
|
|
||||||
(define unpack lua-unpack)
|
(define unpack lua-unpack)
|
||||||
|
|
||||||
|
;; ── io library (minimal stub — buffered; no real stdio) ───────
|
||||||
|
(define io {})
|
||||||
|
(define __io-buffer "")
|
||||||
|
|
||||||
|
(define
|
||||||
|
lua-io-write
|
||||||
|
(fn (&rest args)
|
||||||
|
(begin
|
||||||
|
(define
|
||||||
|
loop
|
||||||
|
(fn (i)
|
||||||
|
(when (< i (len args))
|
||||||
|
(begin
|
||||||
|
(set! __io-buffer (str __io-buffer (lua-concat-coerce (nth args i))))
|
||||||
|
(loop (+ i 1))))))
|
||||||
|
(loop 0)
|
||||||
|
io)))
|
||||||
|
|
||||||
|
(define
|
||||||
|
lua-io-read
|
||||||
|
(fn (&rest args) nil))
|
||||||
|
|
||||||
|
(define
|
||||||
|
lua-io-open
|
||||||
|
(fn (&rest args) nil))
|
||||||
|
|
||||||
|
(define
|
||||||
|
lua-io-lines
|
||||||
|
(fn (&rest args) (fn (&rest __) nil)))
|
||||||
|
|
||||||
|
(define
|
||||||
|
lua-io-close
|
||||||
|
(fn (&rest args) true))
|
||||||
|
|
||||||
|
(define
|
||||||
|
lua-io-flush
|
||||||
|
(fn (&rest args) nil))
|
||||||
|
|
||||||
|
(define
|
||||||
|
lua-io-buffer
|
||||||
|
(fn ()
|
||||||
|
(let ((out __io-buffer))
|
||||||
|
(begin
|
||||||
|
(set! __io-buffer "")
|
||||||
|
out))))
|
||||||
|
|
||||||
|
;; print(a, b, c) — args joined by tab, trailing newline
|
||||||
|
(define
|
||||||
|
lua-print
|
||||||
|
(fn (&rest args)
|
||||||
|
(begin
|
||||||
|
(define
|
||||||
|
loop
|
||||||
|
(fn (i)
|
||||||
|
(when (< i (len args))
|
||||||
|
(begin
|
||||||
|
(when (> i 0) (set! __io-buffer (str __io-buffer "\t")))
|
||||||
|
(set! __io-buffer (str __io-buffer (lua-to-display (nth args i))))
|
||||||
|
(loop (+ i 1))))))
|
||||||
|
(loop 0)
|
||||||
|
(set! __io-buffer (str __io-buffer "\n"))
|
||||||
|
nil)))
|
||||||
|
|
||||||
|
(define
|
||||||
|
lua-to-display
|
||||||
|
(fn (v)
|
||||||
|
(cond
|
||||||
|
((= v nil) "nil")
|
||||||
|
((= v true) "true")
|
||||||
|
((= v false) "false")
|
||||||
|
((= (type-of v) "string") v)
|
||||||
|
((= (type-of v) "number") (str v))
|
||||||
|
((= (type-of v) "dict") (str "table"))
|
||||||
|
((or (= (type-of v) "function") (= (type-of v) "lambda")) "function")
|
||||||
|
(else (str v)))))
|
||||||
|
|
||||||
|
(define
|
||||||
|
lua-tostring
|
||||||
|
(fn (v)
|
||||||
|
(cond
|
||||||
|
((= (type-of v) "dict")
|
||||||
|
(let ((m (lua-get-mm v "__tostring")))
|
||||||
|
(cond
|
||||||
|
((not (= m nil)) (lua-first (m v)))
|
||||||
|
(else (lua-to-display v)))))
|
||||||
|
(else (lua-to-display v)))))
|
||||||
|
|
||||||
|
(define
|
||||||
|
lua-tonumber
|
||||||
|
(fn (&rest args)
|
||||||
|
(let ((v (first args))
|
||||||
|
(base (if (> (len args) 1) (nth args 1) nil)))
|
||||||
|
(cond
|
||||||
|
((= (type-of v) "number") v)
|
||||||
|
((= (type-of v) "string") (lua-to-number v))
|
||||||
|
(else nil)))))
|
||||||
|
|
||||||
|
(dict-set! io "write" lua-io-write)
|
||||||
|
(dict-set! io "read" lua-io-read)
|
||||||
|
(dict-set! io "open" lua-io-open)
|
||||||
|
(dict-set! io "lines" lua-io-lines)
|
||||||
|
(dict-set! io "close" lua-io-close)
|
||||||
|
(dict-set! io "flush" lua-io-flush)
|
||||||
|
(dict-set! io "__buffer" lua-io-buffer)
|
||||||
|
|
||||||
|
(define print lua-print)
|
||||||
|
(define tostring lua-tostring)
|
||||||
|
(define tonumber lua-tonumber)
|
||||||
|
|||||||
@@ -832,6 +832,32 @@ cat > "$TMPFILE" << 'EPOCHS'
|
|||||||
(epoch 1341)
|
(epoch 1341)
|
||||||
(eval "(lua-eval-ast \"local t = {10, 20, 30, 40} local a, b = table.unpack(t, 2, 3) return a + b\")")
|
(eval "(lua-eval-ast \"local t = {10, 20, 30, 40} local a, b = table.unpack(t, 2, 3) return a + b\")")
|
||||||
|
|
||||||
|
;; ── Phase 6: io stub + print/tostring/tonumber ────────────────
|
||||||
|
(epoch 1400)
|
||||||
|
(eval "(lua-eval-ast \"io.write(\\\"hello\\\") return io.__buffer()\")")
|
||||||
|
(epoch 1401)
|
||||||
|
(eval "(lua-eval-ast \"io.write(\\\"a\\\", \\\"b\\\", \\\"c\\\") return io.__buffer()\")")
|
||||||
|
(epoch 1402)
|
||||||
|
(eval "(lua-eval-ast \"io.write(1, \\\" \\\", 2) return io.__buffer()\")")
|
||||||
|
(epoch 1410)
|
||||||
|
(eval "(lua-eval-ast \"print(\\\"x\\\", \\\"y\\\") return io.__buffer()\")")
|
||||||
|
(epoch 1411)
|
||||||
|
(eval "(lua-eval-ast \"print(1, 2, 3) return io.__buffer()\")")
|
||||||
|
(epoch 1420)
|
||||||
|
(eval "(lua-eval-ast \"return tostring(42)\")")
|
||||||
|
(epoch 1421)
|
||||||
|
(eval "(lua-eval-ast \"return tostring(nil)\")")
|
||||||
|
(epoch 1422)
|
||||||
|
(eval "(lua-eval-ast \"return tostring({})\")")
|
||||||
|
(epoch 1430)
|
||||||
|
(eval "(lua-eval-ast \"return tonumber(\\\"42\\\")\")")
|
||||||
|
(epoch 1431)
|
||||||
|
(eval "(lua-eval-ast \"if tonumber(\\\"abc\\\") == nil then return 1 else return 0 end\")")
|
||||||
|
(epoch 1440)
|
||||||
|
(eval "(lua-eval-ast \"if io.read() == nil then return 1 else return 0 end\")")
|
||||||
|
(epoch 1441)
|
||||||
|
(eval "(lua-eval-ast \"if io.open(\\\"x\\\") == nil then return 1 else return 0 end\")")
|
||||||
|
|
||||||
EPOCHS
|
EPOCHS
|
||||||
|
|
||||||
OUTPUT=$(timeout 60 "$SX_SERVER" < "$TMPFILE" 2>/dev/null)
|
OUTPUT=$(timeout 60 "$SX_SERVER" < "$TMPFILE" 2>/dev/null)
|
||||||
@@ -1249,6 +1275,20 @@ check 1331 "table.sort desc via cmp" '301'
|
|||||||
check 1340 "unpack global" '60'
|
check 1340 "unpack global" '60'
|
||||||
check 1341 "table.unpack(t,i,j)" '50'
|
check 1341 "table.unpack(t,i,j)" '50'
|
||||||
|
|
||||||
|
# ── Phase 6: io stub + print/tostring/tonumber ────────────────
|
||||||
|
check 1400 "io.write single" '"hello"'
|
||||||
|
check 1401 "io.write multi strings" '"abc"'
|
||||||
|
check 1402 "io.write numbers + spaces" '"1 2"'
|
||||||
|
check 1410 "print two args tab-sep + NL" '"x\ty\n"'
|
||||||
|
check 1411 "print three ints" '"1\t2\t3\n"'
|
||||||
|
check 1420 "tostring(42)" '"42"'
|
||||||
|
check 1421 "tostring(nil)" '"nil"'
|
||||||
|
check 1422 "tostring({})" '"table"'
|
||||||
|
check 1430 "tonumber(\"42\")" '42'
|
||||||
|
check 1431 "tonumber(\"abc\") → nil" '1'
|
||||||
|
check 1440 "io.read() → nil" '1'
|
||||||
|
check 1441 "io.open(x) → nil" '1'
|
||||||
|
|
||||||
TOTAL=$((PASS + FAIL))
|
TOTAL=$((PASS + FAIL))
|
||||||
if [ $FAIL -eq 0 ]; then
|
if [ $FAIL -eq 0 ]; then
|
||||||
echo "ok $PASS/$TOTAL Lua-on-SX tests passed"
|
echo "ok $PASS/$TOTAL Lua-on-SX tests passed"
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ Each item: implement → tests → tick box → update progress log.
|
|||||||
- [x] `string` — `format`, `sub`, `find`, `match`, `gmatch`, `gsub`, `len`, `rep`, `upper`, `lower`, `byte`, `char`
|
- [x] `string` — `format`, `sub`, `find`, `match`, `gmatch`, `gsub`, `len`, `rep`, `upper`, `lower`, `byte`, `char`
|
||||||
- [x] `math` — full surface
|
- [x] `math` — full surface
|
||||||
- [x] `table` — `insert`, `remove`, `concat`, `sort`, `unpack`
|
- [x] `table` — `insert`, `remove`, `concat`, `sort`, `unpack`
|
||||||
- [ ] `io` — minimal stub (read/write to SX IO surface)
|
- [x] `io` — minimal stub (read/write to SX IO surface)
|
||||||
- [ ] `os` — time/date subset
|
- [ ] `os` — time/date subset
|
||||||
|
|
||||||
### Phase 7 — modules + full conformance
|
### Phase 7 — modules + full conformance
|
||||||
@@ -82,6 +82,7 @@ Each item: implement → tests → tick box → update progress log.
|
|||||||
|
|
||||||
_Newest first. Agent appends on every commit._
|
_Newest first. Agent appends on every commit._
|
||||||
|
|
||||||
|
- 2026-04-24: lua: `io` stub + `print`/`tostring`/`tonumber` globals. io buffers to internal `__io-buffer` (tests drain it via `io.__buffer()`). print: tab-sep + NL. tostring respects `__tostring` metamethod. 334 tests.
|
||||||
- 2026-04-24: lua: `table` lib — insert (append / at pos, shifts up), remove (last / at pos, shifts down), concat (sep, i, j), sort (insertion sort, optional cmp), unpack + table.unpack, maxn. Caught trap: local helper named `shift` collides with SX's `shift` special form → renamed to `tbl-shift-up`/`tbl-shift-down`. 322 tests.
|
- 2026-04-24: lua: `table` lib — insert (append / at pos, shifts up), remove (last / at pos, shifts down), concat (sep, i, j), sort (insertion sort, optional cmp), unpack + table.unpack, maxn. Caught trap: local helper named `shift` collides with SX's `shift` special form → renamed to `tbl-shift-up`/`tbl-shift-down`. 322 tests.
|
||||||
- 2026-04-24: lua: `math` lib — pi/huge + abs/ceil/floor/sqrt/exp/log/log10/pow/trig (sin/cos/tan/asin/acos/atan/atan2)/deg/rad/min/max (&rest)/fmod/modf/random (0/1/2 arg)/randomseed. Most ops delegate to SX primitives; log w/ base via change-of-base. 309 tests.
|
- 2026-04-24: lua: `math` lib — pi/huge + abs/ceil/floor/sqrt/exp/log/log10/pow/trig (sin/cos/tan/asin/acos/atan/atan2)/deg/rad/min/max (&rest)/fmod/modf/random (0/1/2 arg)/randomseed. Most ops delegate to SX primitives; log w/ base via change-of-base. 309 tests.
|
||||||
- 2026-04-24: lua: `string` lib — len/upper/lower/rep/sub (1-idx + neg)/byte/char/find/match/gmatch/gsub/format. Patterns are literal-only (no `%d`/etc.); format is `%s`/`%d`/`%f`/`%%` only. `string.char` uses printable-ASCII lookup + tab/nl/cr. 292 tests.
|
- 2026-04-24: lua: `string` lib — len/upper/lower/rep/sub (1-idx + neg)/byte/char/find/match/gmatch/gsub/format. Patterns are literal-only (no `%d`/etc.); format is `%s`/`%d`/`%f`/`%%` only. `string.char` uses printable-ASCII lookup + tab/nl/cr. 292 tests.
|
||||||
@@ -108,6 +109,7 @@ _Shared-file issues that need someone else to fix. Minimal repro only._
|
|||||||
|
|
||||||
## Known limitations (own code, not shared)
|
## Known limitations (own code, not shared)
|
||||||
|
|
||||||
|
- **`io` library is a stub** — `io.write`/`print` append to an internal `__io-buffer` (accessible via `io.__buffer()` which returns + clears it) instead of real stdout. `io.read`/`open`/`lines` return nil. Suitable for tests that inspect output; no actual stdio.
|
||||||
- **`string.find`/`match`/`gmatch`/`gsub` patterns are LITERAL only** — no `%d`/`%a`/`.`/`*`/`+`/etc. Implementing Lua patterns is a separate work item; literal search covers the common case.
|
- **`string.find`/`match`/`gmatch`/`gsub` patterns are LITERAL only** — no `%d`/`%a`/`.`/`*`/`+`/etc. Implementing Lua patterns is a separate work item; literal search covers the common case.
|
||||||
- **`string.format`** supports only `%s`, `%d`, `%f`, `%%`. No width/precision flags (`%.2f`, `%5d`).
|
- **`string.format`** supports only `%s`, `%d`, `%f`, `%%`. No width/precision flags (`%.2f`, `%5d`).
|
||||||
- **`string.char`** supports printable ASCII 32–126 plus `\t`/`\n`/`\r`; other codes error.
|
- **`string.char`** supports printable ASCII 32–126 plus `\t`/`\n`/`\r`; other codes error.
|
||||||
|
|||||||
Reference in New Issue
Block a user