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:
@@ -131,6 +131,7 @@ def compile_ref_to_js(
|
|||||||
# evaluator.sx = merged frames + eval utilities + CEK machine
|
# evaluator.sx = merged frames + eval utilities + CEK machine
|
||||||
sx_files = [
|
sx_files = [
|
||||||
("evaluator.sx", "evaluator (frames + eval + CEK)"),
|
("evaluator.sx", "evaluator (frames + eval + CEK)"),
|
||||||
|
("stdlib.sx", "stdlib (library functions from former primitives)"),
|
||||||
("freeze.sx", "freeze (serializable state boundaries)"),
|
("freeze.sx", "freeze (serializable state boundaries)"),
|
||||||
("content.sx", "content (content-addressed computation)"),
|
("content.sx", "content (content-addressed computation)"),
|
||||||
("render.sx", "render (core)"),
|
("render.sx", "render (core)"),
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ def compile_spec_to_ml(spec_dir: str | None = None) -> str:
|
|||||||
# Spec files to transpile (in dependency order)
|
# Spec files to transpile (in dependency order)
|
||||||
sx_files = [
|
sx_files = [
|
||||||
("evaluator.sx", "evaluator (frames + eval + CEK)"),
|
("evaluator.sx", "evaluator (frames + eval + CEK)"),
|
||||||
|
("stdlib.sx", "stdlib (library functions from former primitives)"),
|
||||||
]
|
]
|
||||||
|
|
||||||
parts = [PREAMBLE]
|
parts = [PREAMBLE]
|
||||||
|
|||||||
@@ -1640,6 +1640,7 @@ SPEC_MODULES = {
|
|||||||
"engine": ("engine.sx", "engine (fetch/swap/trigger pure logic)"),
|
"engine": ("engine.sx", "engine (fetch/swap/trigger pure logic)"),
|
||||||
"signals": ("signals.sx", "signals (reactive signal runtime)"),
|
"signals": ("signals.sx", "signals (reactive signal runtime)"),
|
||||||
"page-helpers": ("page-helpers.sx", "page-helpers (pure data transformation helpers)"),
|
"page-helpers": ("page-helpers.sx", "page-helpers (pure data transformation helpers)"),
|
||||||
|
"stdlib": ("stdlib.sx", "stdlib (library functions from former primitives)"),
|
||||||
"types": ("types.sx", "types (gradual type system)"),
|
"types": ("types.sx", "types (gradual type system)"),
|
||||||
"freeze": ("freeze.sx", "freeze (serializable state boundaries)"),
|
"freeze": ("freeze.sx", "freeze (serializable state boundaries)"),
|
||||||
"content": ("content.sx", "content (content-addressed computation)"),
|
"content": ("content.sx", "content (content-addressed computation)"),
|
||||||
@@ -1647,9 +1648,10 @@ SPEC_MODULES = {
|
|||||||
# Note: frames and cek are now part of evaluator.sx (always loaded as core)
|
# Note: frames and cek are now part of evaluator.sx (always loaded as core)
|
||||||
|
|
||||||
# Explicit ordering for spec modules with dependencies.
|
# Explicit ordering for spec modules with dependencies.
|
||||||
|
# stdlib must come first — other modules use its functions.
|
||||||
# freeze depends on signals; content depends on freeze.
|
# freeze depends on signals; content depends on freeze.
|
||||||
SPEC_MODULE_ORDER = [
|
SPEC_MODULE_ORDER = [
|
||||||
"deps", "engine", "page-helpers", "router", "signals", "types", "freeze", "content",
|
"stdlib", "deps", "engine", "page-helpers", "router", "signals", "types", "freeze", "content",
|
||||||
]
|
]
|
||||||
|
|
||||||
EXTENSION_NAMES = {"continuations"}
|
EXTENSION_NAMES = {"continuations"}
|
||||||
|
|||||||
@@ -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.
|
;; These are the functions that CANNOT be written in SX because they
|
||||||
;; Bootstrap compilers implement these natively per target.
|
;; 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
|
;; Everything else lives in spec/stdlib.sx as library functions.
|
||||||
;; form is a declarative macro that bootstrap compilers consume to generate
|
;;
|
||||||
;; native primitive registrations.
|
;; 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:
|
;; Format:
|
||||||
;; (define-primitive "name"
|
;; (define-primitive "name"
|
||||||
;; :params (param1 param2 &rest rest)
|
;; :params (param1 param2 &rest rest)
|
||||||
;; :returns "type"
|
;; :returns "type"
|
||||||
;; :doc "description"
|
;; :doc "description")
|
||||||
;; :body (reference-implementation ...))
|
|
||||||
;;
|
;;
|
||||||
;; Typed params use (name :as type) syntax:
|
;; Typed params use (name :as type) syntax.
|
||||||
;; (define-primitive "+"
|
;; Modules: (define-module :name) scopes subsequent entries.
|
||||||
;; :params (&rest (args :as number))
|
|
||||||
;; :returns "number"
|
|
||||||
;; :doc "Sum all arguments.")
|
|
||||||
;;
|
;;
|
||||||
;; Untyped params default to `any`. Typed params enable the gradual
|
;; Functions moved to stdlib.sx (no longer primitives):
|
||||||
;; type checker (types.sx) to catch mistyped primitive calls.
|
;; Comparison: != <= >= eq? eqv? equal?
|
||||||
;;
|
;; Predicates: nil? boolean? number? string? list? dict?
|
||||||
;; The :body is optional — when provided, it gives a reference
|
;; continuation? empty? odd? even? zero? contains?
|
||||||
;; implementation in SX that bootstrap compilers MAY use for testing
|
;; Arithmetic: inc dec abs ceil round min max clamp
|
||||||
;; or as a fallback. Most targets will implement natively for performance.
|
;; Collections: first last rest nth cons append reverse flatten
|
||||||
;;
|
;; range chunk-every zip-pairs vals has-key? merge
|
||||||
;; Modules: (define-module :name) scopes subsequent define-primitive
|
;; assoc dissoc into
|
||||||
;; entries until the next define-module. Bootstrappers use this to
|
;; Strings: upcase downcase string-length substring
|
||||||
;; selectively include primitive groups.
|
;; 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