From 5098a8f015c4b4ea8c967dbd97486ec21bc5e1fe Mon Sep 17 00:00:00 2001 From: giles Date: Sat, 6 Jun 2026 08:04:45 +0000 Subject: [PATCH] erlang: atom_to_list/integer_to_list return Erlang charlists; list_to_* accept both (+9 net eval, 759/759) --- lib/erlang/scoreboard.json | 6 ++--- lib/erlang/scoreboard.md | 4 ++-- lib/erlang/tests/eval.sx | 32 +++++++++++++++++++++---- lib/erlang/transpile.sx | 48 +++++++++++++++++++++++++------------- 4 files changed, 64 insertions(+), 26 deletions(-) diff --git a/lib/erlang/scoreboard.json b/lib/erlang/scoreboard.json index 8b2827f2..97d6f589 100644 --- a/lib/erlang/scoreboard.json +++ b/lib/erlang/scoreboard.json @@ -1,11 +1,11 @@ { "language": "erlang", - "total_pass": 750, - "total": 750, + "total_pass": 759, + "total": 759, "suites": [ {"name":"tokenize","pass":62,"total":62,"status":"ok"}, {"name":"parse","pass":52,"total":52,"status":"ok"}, - {"name":"eval","pass":397,"total":397,"status":"ok"}, + {"name":"eval","pass":406,"total":406,"status":"ok"}, {"name":"runtime","pass":93,"total":93,"status":"ok"}, {"name":"ring","pass":4,"total":4,"status":"ok"}, {"name":"ping-pong","pass":4,"total":4,"status":"ok"}, diff --git a/lib/erlang/scoreboard.md b/lib/erlang/scoreboard.md index 13ad1a7c..6487bf21 100644 --- a/lib/erlang/scoreboard.md +++ b/lib/erlang/scoreboard.md @@ -1,12 +1,12 @@ # Erlang-on-SX Scoreboard -**Total: 750 / 750 tests passing** +**Total: 759 / 759 tests passing** | | Suite | Pass | Total | |---|---|---|---| | ✅ | tokenize | 62 | 62 | | ✅ | parse | 52 | 52 | -| ✅ | eval | 397 | 397 | +| ✅ | eval | 406 | 406 | | ✅ | runtime | 93 | 93 | | ✅ | ring | 4 | 4 | | ✅ | ping-pong | 4 | 4 | diff --git a/lib/erlang/tests/eval.sx b/lib/erlang/tests/eval.sx index 7ff48aed..dca0765d 100644 --- a/lib/erlang/tests/eval.sx +++ b/lib/erlang/tests/eval.sx @@ -228,9 +228,10 @@ (er-eval-test "tuple_size 0" (ev "tuple_size({})") 0) ;; ── BIFs: atom / list conversions ─────────────────────────────── -(er-eval-test "atom_to_list" (ev "atom_to_list(hello)") "hello") +(er-eval-test "atom_to_list -> charlist length" (ev "length(atom_to_list(hello))") 5) +(er-eval-test "atom_to_list -> head $h" (ev "hd(atom_to_list(hello))") 104) (er-eval-test "list_to_atom roundtrip" - (nm (ev "list_to_atom(atom_to_list(foo))")) "foo") + (nm (ev "list_to_atom(atom_to_list(foo))")) "foo") ;; round-trip via charlist (er-eval-test "list_to_atom fresh" (nm (ev "list_to_atom(\"bar\")")) "bar") @@ -1060,11 +1061,13 @@ (er-eval-test "list_to_tuple roundtrip" (ev "tuple_size(list_to_tuple([10, 20, 30]))") 3) -(er-eval-test "integer_to_list" (ev "integer_to_list(42)") "42") -(er-eval-test "integer_to_list neg" (ev "integer_to_list(-99)") "-99") +(er-eval-test "integer_to_list -> charlist length" (ev "length(integer_to_list(42))") 2) +(er-eval-test "integer_to_list 42 head $4" (ev "hd(integer_to_list(42))") 52) +(er-eval-test "integer_to_list neg -> charlist length" (ev "length(integer_to_list(-99))") 3) +(er-eval-test "integer_to_list -99 head $-" (ev "hd(integer_to_list(-99))") 45) (er-eval-test "list_to_integer" (ev "list_to_integer(\"123\")") 123) (er-eval-test "list_to_integer roundtrip" - (ev "list_to_integer(integer_to_list(7))") 7) + (ev "list_to_integer(integer_to_list(7))") 7) ;; round-trip via charlist (er-eval-test "is_function fun" (nm (ev "F = fun (X) -> X end, is_function(F)")) "true") @@ -1358,6 +1361,25 @@ (er-eval-test "list_to_binary char-list round-trip" (nm (ev "list_to_binary([$h, $i]) =:= <<104, 105>>")) "true") + +;; ── atom_to_list / integer_to_list charlist semantics (Step 3b substrate fix #3) ── +(er-eval-test "atom_to_list hd is char code" + (ev "hd(atom_to_list(hi))") 104) +(er-eval-test "atom_to_list maps to bytes via list_to_binary" + (ev "byte_size(list_to_binary(atom_to_list(hello)))") 5) +(er-eval-test "atom_to_list -> list_to_binary -> bytes content" + (nm (ev "list_to_binary(atom_to_list(ok)) =:= <<111, 107>>")) "true") +(er-eval-test "integer_to_list 12345 -> 5 chars" + (ev "length(integer_to_list(12345))") 5) +(er-eval-test "integer_to_list -> bytes -> back" + (ev "list_to_integer(integer_to_list(99999))") 99999) +(er-eval-test "list_to_atom from charlist" + (nm (ev "list_to_atom([$f, $o, $o])")) "foo") +(er-eval-test "list_to_atom from SX-string back-compat" + (nm (ev "list_to_atom(\"bar\")")) "bar") +(er-eval-test "list_to_integer from charlist" + (ev "list_to_integer([$1, $0, $0])") 100) + (define er-eval-test-summary (str "eval " er-eval-test-pass "/" er-eval-test-count)) diff --git a/lib/erlang/transpile.sx b/lib/erlang/transpile.sx index 915d31b6..c72d9298 100644 --- a/lib/erlang/transpile.sx +++ b/lib/erlang/transpile.sx @@ -821,16 +821,30 @@ (len (get v :elements)) (error "Erlang: tuple_size: not a tuple"))))) +(define er-string->charlist + (fn (s) + (let ((cs (string->list s)) (out (er-mk-nil))) + (for-each + (fn (i) + (set! out (er-mk-cons + (char->integer (nth cs (- (- (len cs) 1) i))) + out))) + (range 0 (len cs))) + out))) + (define er-bif-atom-to-list (fn (vs) (let ((v (er-bif-arg1 vs "atom_to_list"))) + ;; Standard Erlang: atom_to_list/1 returns an Erlang charlist + ;; (list of integer char codes). Was: SX string of :name — + ;; unusable from Erlang-land for [Char|T] / ++ / binary segments. (if (er-atom? v) - (get v :name) - (error "Erlang: atom_to_list: not an atom"))))) + (er-string->charlist (get v :name)) + (raise (er-mk-error-marker (er-mk-atom "badarg"))))))) (define er-bif-list-to-atom @@ -838,10 +852,11 @@ (vs) (let ((v (er-bif-arg1 vs "list_to_atom"))) - (if - (= (type-of v) "string") - (er-mk-atom v) - (error "Erlang: list_to_atom: not a string"))))) + ;; Accept Erlang charlist (cons of ints) or SX string. + (let ((s (er-source-to-string v))) + (cond + (= s nil) (raise (er-mk-error-marker (er-mk-atom "badarg"))) + :else (er-mk-atom s)))))) ;; ── lists module ───────────────────────────────────────────────── (define @@ -1597,10 +1612,12 @@ (vs) (let ((v (er-bif-arg1 vs "integer_to_list"))) + ;; Standard Erlang: integer_to_list/1 returns an Erlang charlist + ;; (e.g. integer_to_list(42) -> [$4, $2] -> [52, 50]). (cond (not (= (type-of v) "number")) (raise (er-mk-error-marker (er-mk-atom "badarg"))) - :else (str v))))) + :else (er-string->charlist (str v)))))) (define er-bif-list-to-integer @@ -1608,15 +1625,14 @@ (vs) (let ((v (er-bif-arg1 vs "list_to_integer"))) - (cond - (not (= (type-of v) "string")) - (raise (er-mk-error-marker (er-mk-atom "badarg"))) - :else (let - ((n (parse-number v))) - (cond - (= n nil) - (raise (er-mk-error-marker (er-mk-atom "badarg"))) - :else n)))))) + ;; Accept Erlang charlist (cons of ints) or SX string. + (let ((s (er-source-to-string v))) + (cond + (= s nil) (raise (er-mk-error-marker (er-mk-atom "badarg"))) + :else (let ((n (parse-number s))) + (cond + (= n nil) (raise (er-mk-error-marker (er-mk-atom "badarg"))) + :else n))))))) (define er-bif-is-function