Files
rose-ash/lib/erlang/runtime.sx
giles 3c0a963229 erlang-runtime: add lib/erlang/runtime.sx + test.sh (55/55 pass)
Numeric tower (is-integer?/float?/number?, float/trunc/round/abs/max/min),
div/rem (quotient/remainder), bitwise (band/bor/bxor/bnot/bsl/bsr),
sets module (new/add/member/union/intersection/subtract/size/to-list/from-list),
re module (run/replace/replace-all/match-groups/split),
list BIFs (hd/tl/length/member/reverse/nth/foldl/foldr/seq/flatten/zip),
type conversions (integer-to-list, list-to-integer, atom-to-list, etc.),
ok/error tuple helpers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 21:21:39 +00:00

231 lines
7.2 KiB
Plaintext

;; lib/erlang/runtime.sx — Erlang BIFs and stdlib wrappers on SX primitives
;;
;; Provides Erlang-idiomatic wrappers. Thin where spec primitives match;
;; inline where Erlang semantics differ (e.g. rem sign, integer division).
;;
;; Primitives used from spec:
;; integer?/float? (Phase 2)
;; remainder/quotient (Phase 2 / Phase 15)
;; bitwise-and/or/xor/not (Phase 7)
;; arithmetic-shift (Phase 7)
;; make-set/set-add!/etc (Phase 18)
;; make-regexp/regexp-match/etc (Phase 20)
;; gcd (Phase 15)
;; ---------------------------------------------------------------------------
;; 1. Numeric tower — type predicates + conversions
;; ---------------------------------------------------------------------------
(define er-is-integer? integer?)
(define er-is-float? float?)
(define (er-is-number? x) (or (integer? x) (float? x)))
(define (er-is-atom? x) (= (type-of x) "symbol"))
(define er-is-list? list?)
(define er-is-binary? bytevector?)
;; Erlang float/1 coerces an integer to float
(define (er-float x) (* 1 x))
;; Erlang trunc/1 — truncate toward zero
(define er-trunc truncate)
;; Erlang round/1 — round to nearest integer
(define er-round round)
;; Erlang abs/1
(define er-abs abs)
;; Erlang max/min (BIFs in OTP 26)
(define (er-max a b) (if (>= a b) a b))
(define (er-min a b) (if (<= a b) a b))
;; ---------------------------------------------------------------------------
;; 2. Integer arithmetic — div + rem (Erlang semantics)
;; ---------------------------------------------------------------------------
;; Erlang div: integer division truncating toward zero
(define er-div quotient)
;; Erlang rem: remainder with sign of dividend (matches remainder primitive)
(define er-rem remainder)
;; Erlang gcd (non-standard BIF but useful)
(define er-gcd gcd)
;; ---------------------------------------------------------------------------
;; 3. Bitwise ops — band / bor / bxor / bnot / bsl / bsr
;; ---------------------------------------------------------------------------
(define er-band bitwise-and)
(define er-bor bitwise-or)
(define er-bxor bitwise-xor)
(define er-bnot bitwise-not)
;; bsl: bit shift left by N positions
(define (er-bsl x n) (arithmetic-shift x n))
;; bsr: bit shift right by N positions
(define (er-bsr x n) (arithmetic-shift x (- 0 n)))
;; ---------------------------------------------------------------------------
;; 4. Sets module — thin wrappers matching Erlang sets API
;; ---------------------------------------------------------------------------
(define er-sets-new make-set)
(define er-sets-add-element set-add!)
(define er-sets-is-element set-member?)
(define er-sets-del-element set-remove!)
(define er-sets-union set-union)
(define er-sets-intersection set-intersection)
(define er-sets-subtract set-difference)
(define er-sets-to-list set->list)
(define er-sets-from-list list->set)
(define (er-sets-size s) (len (set->list s)))
(define (er-sets-is-set? x) (set? x))
;; ---------------------------------------------------------------------------
;; 5. Regexp — re module wrappers
;; ---------------------------------------------------------------------------
;; er-re-run: returns match dict or nil (no match)
(define
(er-re-run subject pattern)
(regexp-match (make-regexp pattern) subject))
;; er-re-replace: replace first match
(define
(er-re-replace subject pattern replacement)
(regexp-replace (make-regexp pattern) subject replacement))
;; er-re-replace-all: global replace
(define
(er-re-replace-all subject pattern replacement)
(regexp-replace-all (make-regexp pattern) subject replacement))
;; er-re-match-groups: extract capture groups from a match result
(define (er-re-match-groups m) (if (= m nil) nil (get m :groups)))
;; er-re-split: split string on regexp delimiter
(define
(er-re-split subject pattern)
(let
((re (make-regexp pattern))
(ms (regexp-match-all (make-regexp pattern) subject)))
(if
(= (len ms) 0)
(list subject)
(letrec
((go (fn (matches pos acc) (if (= (len matches) 0) (append acc (list (substring subject pos (len subject)))) (let ((m (first matches)) (start (get (first matches) :start)) (end (get (first matches) :end))) (go (rest matches) end (append acc (list (substring subject pos start)))))))))
(go ms 0 (list))))))
;; ---------------------------------------------------------------------------
;; 6. List BIFs — hd/tl/length + lists module
;; ---------------------------------------------------------------------------
(define (er-hd lst) (first lst))
(define (er-tl lst) (rest lst))
(define (er-length lst) (len lst))
;; lists:member/2
(define
(er-lists-member elem lst)
(cond
((= (len lst) 0) false)
((= elem (first lst)) true)
(else (er-lists-member elem (rest lst)))))
;; lists:reverse/1
(define er-lists-reverse reverse)
;; lists:append/2
(define er-lists-append append)
;; lists:flatten/1
(define
(er-lists-flatten lst)
(cond
((= (len lst) 0) (list))
((list? (first lst))
(append (er-lists-flatten (first lst)) (er-lists-flatten (rest lst))))
(else (cons (first lst) (er-lists-flatten (rest lst))))))
;; lists:nth/2 — 1-indexed
(define (er-lists-nth n lst) (nth lst (- n 1)))
;; lists:map/2
(define er-lists-map map)
;; lists:filter/2
(define er-lists-filter filter)
;; lists:foldl/3 — (Fun, Acc0, List)
(define
(er-lists-foldl f acc lst)
(if
(= (len lst) 0)
acc
(er-lists-foldl f (f (first lst) acc) (rest lst))))
;; lists:foldr/3
(define
(er-lists-foldr f acc lst)
(if
(= (len lst) 0)
acc
(f (first lst) (er-lists-foldr f acc (rest lst)))))
;; lists:zip/2
(define
(er-lists-zip a b)
(if
(or (= (len a) 0) (= (len b) 0))
(list)
(cons (list (first a) (first b)) (er-lists-zip (rest a) (rest b)))))
;; lists:seq/2 — generate integer range (1-indexed like Erlang)
(define
(er-lists-seq from to)
(if
(> from to)
(list)
(cons from (er-lists-seq (+ from 1) to))))
;; ---------------------------------------------------------------------------
;; 7. Type conversion BIFs
;; ---------------------------------------------------------------------------
;; atom_to_list/1 — convert atom (symbol) to its name string
(define (er-atom-to-list a) (symbol->string a))
;; list_to_atom/1 — convert string to atom (symbol)
(define (er-list-to-atom s) (make-symbol s))
;; integer_to_list/1
(define (er-integer-to-list n) (str n))
;; list_to_integer/1
(define (er-list-to-integer s) (truncate (parse-number s)))
;; float_to_list/1
(define (er-float-to-list f) (str f))
;; list_to_float/1
(define (er-list-to-float s) (* 1 (parse-number s)))
;; integer_to_list/2 — with radix (e.g. 16 for hex)
(define (er-integer-to-list-radix n radix) (number->string n radix))
;; ---------------------------------------------------------------------------
;; 8. ok/error tuple helpers — Erlang idiom {ok, Val} / {error, Reason}
;; ---------------------------------------------------------------------------
(define (er-ok val) (list "ok" val))
(define (er-error reason) (list "error" reason))
(define
(er-is-ok? t)
(and (list? t) (= (len t) 2) (= (first t) "ok")))
(define
(er-is-error? t)
(and (list? t) (= (len t) 2) (= (first t) "error")))
(define (er-unwrap t) (nth t 1))