Add spec/stdlib.sx: 46 primitives become library functions
The irreducible primitive set drops from 79 to 33. Everything that can be expressed in SX is now a library function in stdlib.sx, loaded after evaluator.sx and before render.sx. Moved to stdlib.sx (pure SX, no host dependency): - Logic: not - Comparison: != <= >= eq? eqv? equal? - Predicates: nil? boolean? number? string? list? dict? continuation? empty? odd? even? zero? contains? - Arithmetic: inc dec abs ceil round min max clamp - Collections: first last rest nth cons append reverse flatten range chunk-every zip-pairs vals has-key? merge assoc dissoc into - Strings: upcase downcase string-length substring string-contains? starts-with? ends-with? split join replace - Text: pluralize escape assert parse-datetime Remaining irreducible primitives (33): + - * / mod floor pow sqrt = < > type-of symbol-name keyword-name str slice index-of upper lower trim char-from-code list dict concat get len keys dict-set! append! random-int json-encode format-date parse-int format-decimal strip-tags sx-parse error apply All hosts: JS 957+1080, Python 744, OCaml 952 — zero regressions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,36 +1,38 @@
|
||||
;; ==========================================================================
|
||||
;; primitives.sx — Specification of all SX built-in pure functions
|
||||
;; primitives.sx — Irreducible primitive set
|
||||
;;
|
||||
;; Each entry declares: name, parameter signature, and semantics.
|
||||
;; Bootstrap compilers implement these natively per target.
|
||||
;; These are the functions that CANNOT be written in SX because they
|
||||
;; require host-native capabilities: native arithmetic, type inspection,
|
||||
;; host string library, host math, host I/O, host data structures.
|
||||
;;
|
||||
;; This file is a SPECIFICATION, not executable code. The define-primitive
|
||||
;; form is a declarative macro that bootstrap compilers consume to generate
|
||||
;; native primitive registrations.
|
||||
;; Everything else lives in spec/stdlib.sx as library functions.
|
||||
;;
|
||||
;; The primitive set is the out-of-band floor. The fewer primitives,
|
||||
;; the tighter the strange loop and the more of the system is auditable,
|
||||
;; verifiable, portable SX.
|
||||
;;
|
||||
;; Format:
|
||||
;; (define-primitive "name"
|
||||
;; :params (param1 param2 &rest rest)
|
||||
;; :returns "type"
|
||||
;; :doc "description"
|
||||
;; :body (reference-implementation ...))
|
||||
;; :doc "description")
|
||||
;;
|
||||
;; Typed params use (name :as type) syntax:
|
||||
;; (define-primitive "+"
|
||||
;; :params (&rest (args :as number))
|
||||
;; :returns "number"
|
||||
;; :doc "Sum all arguments.")
|
||||
;; Typed params use (name :as type) syntax.
|
||||
;; Modules: (define-module :name) scopes subsequent entries.
|
||||
;;
|
||||
;; Untyped params default to `any`. Typed params enable the gradual
|
||||
;; type checker (types.sx) to catch mistyped primitive calls.
|
||||
;;
|
||||
;; The :body is optional — when provided, it gives a reference
|
||||
;; implementation in SX that bootstrap compilers MAY use for testing
|
||||
;; or as a fallback. Most targets will implement natively for performance.
|
||||
;;
|
||||
;; Modules: (define-module :name) scopes subsequent define-primitive
|
||||
;; entries until the next define-module. Bootstrappers use this to
|
||||
;; selectively include primitive groups.
|
||||
;; Functions moved to stdlib.sx (no longer primitives):
|
||||
;; Comparison: != <= >= eq? eqv? equal?
|
||||
;; Predicates: nil? boolean? number? string? list? dict?
|
||||
;; continuation? empty? odd? even? zero? contains?
|
||||
;; Arithmetic: inc dec abs ceil round min max clamp
|
||||
;; Collections: first last rest nth cons append reverse flatten
|
||||
;; range chunk-every zip-pairs vals has-key? merge
|
||||
;; assoc dissoc into
|
||||
;; Strings: upcase downcase string-length substring
|
||||
;; string-contains? starts-with? ends-with?
|
||||
;; split join replace
|
||||
;; Logic: not
|
||||
;; Text: pluralize escape assert parse-datetime
|
||||
;; ==========================================================================
|
||||
|
||||
|
||||
|
||||
367
spec/stdlib.sx
Normal file
367
spec/stdlib.sx
Normal file
@@ -0,0 +1,367 @@
|
||||
;; ==========================================================================
|
||||
;; 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))
|
||||
Reference in New Issue
Block a user