;; ========================================================================== ;; stdlib.sx — Standard library functions ;; ;; Every function here CAN be expressed in SX using the irreducible ;; primitive set. They are library functions, not primitives. ;; ;; These were previously platform-provided primitives. Moving them to ;; SX tightens the strange loop — less out-of-band, more auditable, ;; portable, and verifiable. ;; ;; Depends on: evaluator.sx (special forms) ;; Must load before: render.sx, freeze.sx, types.sx, user code ;; ;; Irreducible primitives (the ones that CANNOT be written in SX): ;; Arithmetic: + - * / mod floor pow sqrt ;; Comparison: = < > ;; Types: type-of symbol-name keyword-name ;; Strings: str slice index-of upper lower trim char-from-code ;; Collections: list dict concat get len keys dict-set! append! ;; I/O & host: random-int json-encode format-date parse-int ;; format-decimal strip-tags sx-parse error apply ;; ========================================================================== ;; -------------------------------------------------------------------------- ;; Logic ;; -------------------------------------------------------------------------- (define not (fn (x) (if x false true))) ;; -------------------------------------------------------------------------- ;; Comparison ;; -------------------------------------------------------------------------- (define != (fn (a b) (not (= a b)))) (define <= (fn (a b) (or (< a b) (= a b)))) (define >= (fn (a b) (or (> a b) (= a b)))) ;; Aliases — SX uses structural equality for all three (define eq? =) (define eqv? =) (define equal? =) ;; -------------------------------------------------------------------------- ;; Type predicates ;; -------------------------------------------------------------------------- (define nil? (fn (x) (= (type-of x) "nil"))) (define boolean? (fn (x) (= (type-of x) "boolean"))) (define number? (fn (x) (= (type-of x) "number"))) (define string? (fn (x) (= (type-of x) "string"))) (define list? (fn (x) (= (type-of x) "list"))) (define dict? (fn (x) (= (type-of x) "dict"))) (define continuation? (fn (x) (= (type-of x) "continuation"))) ;; -------------------------------------------------------------------------- ;; Numeric predicates ;; -------------------------------------------------------------------------- (define zero? (fn (n) (= n 0))) (define odd? (fn (n) (= (mod n 2) 1))) (define even? (fn (n) (= (mod n 2) 0))) ;; -------------------------------------------------------------------------- ;; Arithmetic ;; -------------------------------------------------------------------------- (define inc (fn (n) (+ n 1))) (define dec (fn (n) (- n 1))) (define abs (fn (x) (if (< x 0) (- x) x))) (define ceil (fn (x) (let ((f (floor x))) (if (= x f) f (+ f 1))))) (define round (fn (x ndigits) (if (nil? ndigits) (floor (+ x 0.5)) (let ((f (pow 10 ndigits))) (/ (floor (+ (* x f) 0.5)) f))))) (define min (fn (a b) (if (< a b) a b))) (define max (fn (a b) (if (> a b) a b))) (define clamp (fn (x lo hi) (max lo (min hi x)))) ;; -------------------------------------------------------------------------- ;; Collection accessors ;; -------------------------------------------------------------------------- (define first (fn (coll) (if (and coll (> (len coll) 0)) (get coll 0) nil))) (define last (fn (coll) (if (and coll (> (len coll) 0)) (get coll (- (len coll) 1)) nil))) (define rest (fn (coll) (if coll (slice coll 1) (list)))) (define nth (fn (coll n) (if (and coll (>= n 0) (< n (len coll))) (get coll n) nil))) (define empty? (fn (coll) (or (nil? coll) (= (len coll) 0)))) (define cons (fn (x coll) (concat (list x) (or coll (list))))) (define append (fn (coll x) (if (list? x) (concat coll x) (concat coll (list x))))) ;; -------------------------------------------------------------------------- ;; Collection transforms ;; -------------------------------------------------------------------------- (define reverse (fn (coll) (let ((result (list)) (i (- (len coll) 1))) (let loop ((i i)) (when (>= i 0) (append! result (get coll i)) (loop (- i 1)))) result))) (define flatten (fn (coll) (let ((result (list))) (for-each (fn (x) (if (list? x) (for-each (fn (y) (append! result y)) x) (append! result x))) coll) result))) (define range (fn (start end step) (let ((s (if (nil? step) 1 step)) (result (list))) (let loop ((i start)) (when (< i end) (append! result i) (loop (+ i s)))) result))) (define chunk-every (fn (coll n) (let ((result (list)) (clen (len coll))) (let loop ((i 0)) (when (< i clen) (append! result (slice coll i (min (+ i n) clen))) (loop (+ i n)))) result))) (define zip-pairs (fn (coll) (let ((result (list)) (clen (len coll))) (let loop ((i 0)) (when (< i (- clen 1)) (append! result (list (get coll i) (get coll (+ i 1)))) (loop (+ i 1)))) result))) ;; -------------------------------------------------------------------------- ;; Dict operations ;; -------------------------------------------------------------------------- (define vals (fn (d) (let ((result (list))) (for-each (fn (k) (append! result (get d k))) (keys d)) result))) (define has-key? (fn (d key) (some (fn (k) (= k key)) (keys d)))) (define merge (fn (a b) (let ((result (dict))) (when a (for-each (fn (k) (dict-set! result k (get a k))) (keys a))) (when b (for-each (fn (k) (dict-set! result k (get b k))) (keys b))) result))) (define assoc (fn (d key val) (let ((result (dict))) (when d (for-each (fn (k) (dict-set! result k (get d k))) (keys d))) (dict-set! result key val) result))) (define dissoc (fn (d key) (let ((result (dict))) (for-each (fn (k) (when (!= k key) (dict-set! result k (get d k)))) (keys d)) result))) (define into (fn (target coll) (cond (list? target) (if (list? coll) (concat coll (list)) (let ((result (list))) (for-each (fn (k) (append! result (list k (get coll k)))) (keys coll)) result)) (dict? target) (let ((result (dict))) (for-each (fn (pair) (when (and (list? pair) (>= (len pair) 2)) (dict-set! result (get pair 0) (get pair 1)))) coll) result) :else target))) ;; -------------------------------------------------------------------------- ;; String operations ;; -------------------------------------------------------------------------- (define upcase upper) (define downcase lower) (define string-length (fn (s) (len s))) (define substring (fn (s start end) (slice s start end))) (define string-contains? (fn (s needle) (!= (index-of s needle) -1))) (define starts-with? (fn (s prefix) (= (index-of s prefix) 0))) (define ends-with? (fn (s suffix) (let ((slen (len s)) (plen (len suffix))) (if (< slen plen) false (= (slice s (- slen plen)) suffix))))) (define split (fn (s sep) (let ((separator (if (nil? sep) " " sep)) (result (list)) (slen (len s)) (seplen (len separator))) (let loop ((start 0)) (let ((idx (index-of s separator start))) (if (= idx -1) (do (append! result (slice s start)) result) (do (append! result (slice s start idx)) (loop (+ idx seplen))))))))) (define join (fn (sep coll) (let ((result "")) (for-each (fn (x) (set! result (if (= result "") (str x) (str result sep x)))) coll) result))) (define replace (fn (s old new) (join new (split s old)))) (define contains? (fn (coll key) (cond (string? coll) (!= (index-of coll (str key)) -1) (dict? coll) (has-key? coll key) (list? coll) (some (fn (x) (= x key)) coll) :else false))) ;; -------------------------------------------------------------------------- ;; Text utilities ;; -------------------------------------------------------------------------- (define pluralize (fn (count singular plural) (if (= count 1) (or singular "") (or plural "s")))) (define escape (fn (s) (-> (str s) (replace "&" "&") (replace "<" "<") (replace ">" ">") (replace "\"" """) (replace "'" "'")))) (define parse-datetime (fn (s) (if s (str s) nil))) (define assert (fn (condition message) (when (not condition) (error (or message "Assertion failed"))) true))