fed-sx-m1: Step 3b substrate fix #2 — $X char literals decode to char code in tokenizer (+12 eval, 750/750)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 31s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 31s
This commit is contained in:
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"language": "erlang",
|
"language": "erlang",
|
||||||
"total_pass": 738,
|
"total_pass": 750,
|
||||||
"total": 738,
|
"total": 750,
|
||||||
"suites": [
|
"suites": [
|
||||||
{"name":"tokenize","pass":62,"total":62,"status":"ok"},
|
{"name":"tokenize","pass":62,"total":62,"status":"ok"},
|
||||||
{"name":"parse","pass":52,"total":52,"status":"ok"},
|
{"name":"parse","pass":52,"total":52,"status":"ok"},
|
||||||
{"name":"eval","pass":385,"total":385,"status":"ok"},
|
{"name":"eval","pass":397,"total":397,"status":"ok"},
|
||||||
{"name":"runtime","pass":93,"total":93,"status":"ok"},
|
{"name":"runtime","pass":93,"total":93,"status":"ok"},
|
||||||
{"name":"ring","pass":4,"total":4,"status":"ok"},
|
{"name":"ring","pass":4,"total":4,"status":"ok"},
|
||||||
{"name":"ping-pong","pass":4,"total":4,"status":"ok"},
|
{"name":"ping-pong","pass":4,"total":4,"status":"ok"},
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Erlang-on-SX Scoreboard
|
# Erlang-on-SX Scoreboard
|
||||||
|
|
||||||
**Total: 738 / 738 tests passing**
|
**Total: 750 / 750 tests passing**
|
||||||
|
|
||||||
| | Suite | Pass | Total |
|
| | Suite | Pass | Total |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| ✅ | tokenize | 62 | 62 |
|
| ✅ | tokenize | 62 | 62 |
|
||||||
| ✅ | parse | 52 | 52 |
|
| ✅ | parse | 52 | 52 |
|
||||||
| ✅ | eval | 385 | 385 |
|
| ✅ | eval | 397 | 397 |
|
||||||
| ✅ | runtime | 93 | 93 |
|
| ✅ | runtime | 93 | 93 |
|
||||||
| ✅ | ring | 4 | 4 |
|
| ✅ | ring | 4 | 4 |
|
||||||
| ✅ | ping-pong | 4 | 4 |
|
| ✅ | ping-pong | 4 | 4 |
|
||||||
|
|||||||
@@ -1341,6 +1341,23 @@
|
|||||||
(get (nth (get er-rt-cap-result :elements) 4) :name) "true")
|
(get (nth (get er-rt-cap-result :elements) 4) :name) "true")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;; ── $X char literals (Step 3b substrate fix 2026-06-04) ──────────
|
||||||
|
(er-eval-test "char $A" (ev "$A") 65)
|
||||||
|
(er-eval-test "char $a" (ev "$a") 97)
|
||||||
|
(er-eval-test "char $0 is digit, not escape-NUL" (ev "$0") 48)
|
||||||
|
(er-eval-test "char $\\n is newline (10)" (ev "$\\n") 10)
|
||||||
|
(er-eval-test "char $\\t is tab (9)" (ev "$\\t") 9)
|
||||||
|
(er-eval-test "char $\\r is CR (13)" (ev "$\\r") 13)
|
||||||
|
(er-eval-test "char $\\s is space (32)" (ev "$\\s") 32)
|
||||||
|
(er-eval-test "char $\\0 is NUL (0)" (ev "$\\0") 0)
|
||||||
|
(er-eval-test "char $\\\\ is backslash (92)" (ev "$\\\\") 92)
|
||||||
|
(er-eval-test "[$h,$i] head is 104" (ev "hd([$h, $i])") 104)
|
||||||
|
(er-eval-test "list_to_binary char-list -> bytes"
|
||||||
|
(ev "byte_size(list_to_binary([$f, $e, $d]))") 3)
|
||||||
|
(er-eval-test "list_to_binary char-list round-trip"
|
||||||
|
(nm (ev "list_to_binary([$h, $i]) =:= <<104, 105>>")) "true")
|
||||||
|
|
||||||
(define
|
(define
|
||||||
er-eval-test-summary
|
er-eval-test-summary
|
||||||
(str "eval " er-eval-test-pass "/" er-eval-test-count))
|
(str "eval " er-eval-test-pass "/" er-eval-test-count))
|
||||||
|
|||||||
@@ -229,13 +229,37 @@
|
|||||||
(= ch "$")
|
(= ch "$")
|
||||||
(do
|
(do
|
||||||
(er-advance! 1)
|
(er-advance! 1)
|
||||||
(if
|
;; Emit the char's decimal code as the integer token value
|
||||||
(and (< pos src-len) (= (er-cur) "\\"))
|
;; (was: raw "$X" text — parse-number then returned nil).
|
||||||
(do
|
(let
|
||||||
(er-advance! 1)
|
((code (cond
|
||||||
(when (< pos src-len) (er-advance! 1)))
|
(>= pos src-len) 0
|
||||||
(when (< pos src-len) (er-advance! 1)))
|
(= (er-cur) "\\")
|
||||||
(er-emit! "integer" (slice src start pos) start)
|
(do
|
||||||
|
(er-advance! 1)
|
||||||
|
(let ((esc (if (< pos src-len) (er-cur) "")))
|
||||||
|
(when (< pos src-len) (er-advance! 1))
|
||||||
|
(cond
|
||||||
|
(= esc "n") 10
|
||||||
|
(= esc "t") 9
|
||||||
|
(= esc "r") 13
|
||||||
|
(= esc "s") 32
|
||||||
|
(= esc "b") 8
|
||||||
|
(= esc "e") 27
|
||||||
|
(= esc "f") 12
|
||||||
|
(= esc "v") 11
|
||||||
|
(= esc "d") 127
|
||||||
|
(= esc "0") 0
|
||||||
|
(= esc "\\") 92
|
||||||
|
(= esc "\"") 34
|
||||||
|
(= esc "'") 39
|
||||||
|
(= esc "") 0
|
||||||
|
:else (char->integer (nth (string->list esc) 0)))))
|
||||||
|
:else
|
||||||
|
(let ((c (er-cur)))
|
||||||
|
(er-advance! 1)
|
||||||
|
(char->integer (nth (string->list c) 0))))))
|
||||||
|
(er-emit! "integer" (str code) start))
|
||||||
(scan!))
|
(scan!))
|
||||||
(er-lower? ch)
|
(er-lower? ch)
|
||||||
(do
|
(do
|
||||||
|
|||||||
@@ -103,16 +103,16 @@ The kernel calls into these host primitives: `crypto:hash/2`,
|
|||||||
|
|
||||||
These three gaps block the remaining unchecked deliverables:
|
These three gaps block the remaining unchecked deliverables:
|
||||||
|
|
||||||
1. **Term codec** (`3b`/`3c`) — **byte-level path resolved 2026-06-04:**
|
1. **Term codec** (`3b`/`3c`) — **substrate fixes #1 + #2 done 2026-06-04:**
|
||||||
`erlang:binary_to_list/1` and `erlang:list_to_binary/1` are now registered
|
`erlang:binary_to_list/1` and `erlang:list_to_binary/1` are registered
|
||||||
in `lib/erlang/runtime.sx` (738/738 conformance, +9 ffi tests). `list_to_binary`
|
in `lib/erlang/runtime.sx` (`list_to_binary` is iolist-aware); the
|
||||||
is iolist-aware (`[1, <<2,3>>, [4, [5]]]` → `<<1,2,3,4,5>>`); round-trip
|
tokenizer's `$X` branch now emits the decimal char code, so `[$h, $i | T]`
|
||||||
`list_to_binary(binary_to_list(B)) =:= B` holds. Step 3b on-disk segment
|
patterns and `list_to_binary([$f,$e,$d])` work end-to-end. 750/750
|
||||||
writer is unblocked if it uses byte ints directly. Still parked:
|
conformance, +9 ffi + +12 eval tests. Step 3b on-disk segment writer
|
||||||
`atom_to_list`/`integer_to_list` return SX-strings (an opaque OCaml-string
|
has a complete byte-level term ↔ binary path. Still parked (low priority
|
||||||
type), not Erlang charlists; `$X` char literals decode to `nil` in
|
for Milestone 1): `atom_to_list`/`integer_to_list` return SX-strings
|
||||||
`parse-number`. Both still block code that wants Erlang-idiomatic
|
(an opaque OCaml-string type), not Erlang charlists — only blocks code
|
||||||
`[$h,$i | T]` patterns on atom/integer names.
|
that wants charlist arithmetic on atom/integer names.
|
||||||
|
|
||||||
2. **SX-source eval bridge** — There's no BIF that lets Erlang call into the
|
2. **SX-source eval bridge** — There's no BIF that lets Erlang call into the
|
||||||
SX evaluator on a parsed source string. Blocks evaluating the `:schema` /
|
SX evaluator on a parsed source string. Blocks evaluating the `:schema` /
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ verify_signature(Activity, ActorState) ->
|
|||||||
- [ ] **3b** — *Parked behind substrate gap (see Blockers below).* Term codec + on-disk persistence: serializer/parser writing each activity as a JSONL-style line; restart-resumes-tip from the segment file.
|
- [ ] **3b** — *Parked behind substrate gap (see Blockers below).* Term codec + on-disk persistence: serializer/parser writing each activity as a JSONL-style line; restart-resumes-tip from the segment file.
|
||||||
- [ ] **3c** — Segment rotation at size threshold + gen_server-mediated concurrent appends.
|
- [ ] **3c** — Segment rotation at size threshold + gen_server-mediated concurrent appends.
|
||||||
|
|
||||||
**Blockers (Step 3b) — byte-level path resolved 2026-06-04:** `binary_to_list/1` and `list_to_binary/1` are now registered Erlang BIFs in `lib/erlang/runtime.sx` (Step 3b substrate fix, +9 ffi tests, 738/738 conformance). `list_to_binary` is iolist-aware: accepts nested cons of integer bytes (0-255) and/or binaries; `binary_to_list` returns a proper Erlang charlist of integers. Round-trip verified: `list_to_binary(binary_to_list(B)) =:= B`. On-disk segment writer (3b) can now build segment bytes from `[Header, IoListPayload]` and reconstruct on read — option (c) of the original workaround menu is now cheap. Still parked: `atom_to_list/1`/`integer_to_list/1` return SX strings rather than Erlang charlists, and `$X` char literals decode to `nil` in `parse-number`. Neither blocks the on-disk format if the encoding uses byte ints directly (no string→list coercion); both still block code that wants to write Erlang-idiomatic `[$h,$i | T]` patterns. 3b on-disk implementation is unblocked; revisit the remaining two gaps if a downstream Step requires charlist arithmetic on atom/integer names.
|
**Blockers (Step 3b) — byte-level path resolved 2026-06-04:** `binary_to_list/1` and `list_to_binary/1` are now registered Erlang BIFs in `lib/erlang/runtime.sx` (Step 3b substrate fix, +9 ffi tests, 738/738 conformance). `list_to_binary` is iolist-aware: accepts nested cons of integer bytes (0-255) and/or binaries; `binary_to_list` returns a proper Erlang charlist of integers. Round-trip verified: `list_to_binary(binary_to_list(B)) =:= B`. On-disk segment writer (3b) can now build segment bytes from `[Header, IoListPayload]` and reconstruct on read — option (c) of the original workaround menu is now cheap. `$X` char literals now decode correctly **as of 2026-06-04**: the Erlang tokenizer's `(= ch "$")` branch (`lib/erlang/tokenizer.sx`) now emits the decimal char code as the token value instead of the raw `$X` text (which `parse-number` couldn't decode → nil). Plain chars use `char->integer` of the first char; the standard escape table (`\n=10 \t=9 \r=13 \s=32 \b=8 \e=27 \f=12 \v=11 \d=127 \0=0 \\=92 \"=34 \'=39`) handles `$\X` forms. So `[$h, $i | T]` patterns and `list_to_binary([$f,$e,$d])` both work end-to-end. +12 eval tests, 750/750. Combined with 3b's `binary_to_list`/`list_to_binary`, Erlang code can now read/write byte sequences and string-shaped char lists fluently. Still parked: `atom_to_list/1`/`integer_to_list/1` return SX strings rather than Erlang charlists — only blocks code that wants to do `[$0+N | _]` arithmetic on integer-to-string output or `[Lower | _]` on atom names; downstream Steps in this milestone don't need it.
|
||||||
|
|
||||||
**Deliverables:**
|
**Deliverables:**
|
||||||
|
|
||||||
@@ -1003,6 +1003,7 @@ A few things still under-specified; resolve as work begins.
|
|||||||
Newest first. One line per sub-deliverable commit. Erlang conformance gate
|
Newest first. One line per sub-deliverable commit. Erlang conformance gate
|
||||||
(`bash lib/erlang/conformance.sh`) must remain 729/729 on every entry.
|
(`bash lib/erlang/conformance.sh`) must remain 729/729 on every entry.
|
||||||
|
|
||||||
|
- **2026-06-04** — Step 3b substrate fix #2: `$X` char-literal decoding. Patched the Erlang tokenizer's `(= ch "$")` branch in `lib/erlang/tokenizer.sx` to emit the decimal char code as the integer token value instead of the raw `$X` source text (which `parse-number` couldn't decode → nil). Plain `$c` uses `char->integer` of the first char; `$\C` consults the standard Erlang escape table (`\n=10 \t=9 \r=13 \s=32 \b=8 \e=27 \f=12 \v=11 \d=127 \0=0 \\=92 \"=34 \'=39`). End-of-file after `$` decodes to 0 defensively. Probes: `$A→65`, `$0→48`, `$\n→10`, `$\\→92`, `[$h,$i]` → cons of 104/105, `list_to_binary([$f,$e,$d])` → `<<102,101,100>>`. +12 eval tests (single chars, each escape, list/binary composition with previous BIFs). Combined with substrate fix #1, Erlang code in fed-sx-m1 can now write `[$h, $i | T]` patterns AND construct/deconstruct binaries — a full term-codec primitive set. Erlang conformance **750/750** (eval 385→397). Plan Blockers note updated; remaining `atom_to_list`/`integer_to_list` charlist gap noted as low-priority for Milestone 1.
|
||||||
- **2026-06-04** — Step 3b substrate fix: registered `erlang:binary_to_list/1` and `erlang:list_to_binary/1` in `lib/erlang/runtime.sx` — the byte-level half of the term-codec gap. `binary_to_list` returns a proper Erlang charlist (`er-mk-cons` chain of byte ints). `list_to_binary` is iolist-aware via a recursive `er-iolist-walk!` that accepts nil / cons / binary / integer 0-255 and flattens nested iolists (e.g. `[1, <<2,3>>, [4, [5]]]` → `<<1,2,3,4,5>>`); out-of-range bytes or non-iolist elements raise `error:badarg`. Round-trip verified: `list_to_binary(binary_to_list(B)) =:= B`. +9 ffi tests (length, hd, empty→[], flat byte_size, nested-iolist, round-trip, 3 badarg paths). On-disk segment writer (3b) now has a complete `[Header | IoListPayload] → Binary` path; the remaining two substrate gaps (`atom_to_list`/`integer_to_list` as Erlang charlists, `$X` char-literal decoding) are still parked but no longer block 3b implementation if the encoding uses byte ints directly. Erlang conformance **738/738** (ffi 28→37). Plan Blockers note for Step 3b updated to reflect the partial resolution.
|
- **2026-06-04** — Step 3b substrate fix: registered `erlang:binary_to_list/1` and `erlang:list_to_binary/1` in `lib/erlang/runtime.sx` — the byte-level half of the term-codec gap. `binary_to_list` returns a proper Erlang charlist (`er-mk-cons` chain of byte ints). `list_to_binary` is iolist-aware via a recursive `er-iolist-walk!` that accepts nil / cons / binary / integer 0-255 and flattens nested iolists (e.g. `[1, <<2,3>>, [4, [5]]]` → `<<1,2,3,4,5>>`); out-of-range bytes or non-iolist elements raise `error:badarg`. Round-trip verified: `list_to_binary(binary_to_list(B)) =:= B`. +9 ffi tests (length, hd, empty→[], flat byte_size, nested-iolist, round-trip, 3 badarg paths). On-disk segment writer (3b) now has a complete `[Header | IoListPayload] → Binary` path; the remaining two substrate gaps (`atom_to_list`/`integer_to_list` as Erlang charlists, `$X` char-literal decoding) are still parked but no longer block 3b implementation if the encoding uses byte ints directly. Erlang conformance **738/738** (ffi 28→37). Plan Blockers note for Step 3b updated to reflect the partial resolution.
|
||||||
- **2026-05-28** — Step 4f-consolidate: `bootstrap:start/3(ActorId, KeySpec, ActorState)` brings up the full kernel substrate in one call — starts the registry gen_server, populates it from the canonical genesis bundle (31 entries across 7 kinds), then starts nx_kernel. Returns the kernel Pid (gen_server convention in this port returns raw Pid not `{ok, Pid}`). Tests verify whereis(nx_kernel), per-kind counts (3/10/7/3/3/2/3), registry lookup of a known entry (`create`), publish + log_tip advance. `next/tests/bootstrap_start.sh` 10/10. Erlang conformance 729/729.
|
- **2026-05-28** — Step 4f-consolidate: `bootstrap:start/3(ActorId, KeySpec, ActorState)` brings up the full kernel substrate in one call — starts the registry gen_server, populates it from the canonical genesis bundle (31 entries across 7 kinds), then starts nx_kernel. Returns the kernel Pid (gen_server convention in this port returns raw Pid not `{ok, Pid}`). Tests verify whereis(nx_kernel), per-kind counts (3/10/7/3/3/2/3), registry lookup of a known entry (`create`), publish + log_tip advance. `next/tests/bootstrap_start.sh` 10/10. Erlang conformance 729/729.
|
||||||
- **2026-05-28** — Step 7d-pure: `next/kernel/sandbox.erl` — `eval_pure/2(Fun, Arg)` and `eval_pure/3(Fun, Activity, State)`. try/catch envelope returns `{ok, Result}` on success and `{error, {Class, Reason}}` for each of the three exception classes (throw, error, exit). The 3-arity variant matches the projection-fold shape so the scheduler can wrap fold bodies. Port note: this Erlang implementation catches by explicit class names rather than the open `Class:Reason` pattern — wrappers enumerate `throw:Reason / error:Reason / exit:Reason` explicitly. Real gas budget + IO denial + env-stripping lands with SX-source eval; the wrapper API doesn't change. `next/tests/sandbox_eval.sh` 13/13. Erlang conformance 729/729.
|
- **2026-05-28** — Step 7d-pure: `next/kernel/sandbox.erl` — `eval_pure/2(Fun, Arg)` and `eval_pure/3(Fun, Activity, State)`. try/catch envelope returns `{ok, Result}` on success and `{error, {Class, Reason}}` for each of the three exception classes (throw, error, exit). The 3-arity variant matches the projection-fold shape so the scheduler can wrap fold bodies. Port note: this Erlang implementation catches by explicit class names rather than the open `Class:Reason` pattern — wrappers enumerate `throw:Reason / error:Reason / exit:Reason` explicitly. Real gas budget + IO denial + env-stripping lands with SX-source eval; the wrapper API doesn't change. `next/tests/sandbox_eval.sh` 13/13. Erlang conformance 729/729.
|
||||||
|
|||||||
Reference in New Issue
Block a user