;; 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))