diff --git a/hosts/ocaml/lib/sx_runtime.ml b/hosts/ocaml/lib/sx_runtime.ml index d0239b84..c6e01921 100644 --- a/hosts/ocaml/lib/sx_runtime.ml +++ b/hosts/ocaml/lib/sx_runtime.ml @@ -155,29 +155,17 @@ let sort' a = _prim "sort" [a] let range' a = _prim "range" [a] let unique a = _prim "unique" [a] let zip a b = _prim "zip" [a; b] -let zip_pairs a = _prim "zip-pairs" [a] let take a b = _prim "take" [a; b] let drop a b = _prim "drop" [a; b] -let chunk_every a b = _prim "chunk-every" [a; b] (* Predicates *) let empty_p a = _prim "empty?" [a] -let nil_p a = _prim "nil?" [a] let number_p a = _prim "number?" [a] let string_p a = _prim "string?" [a] let boolean_p a = _prim "boolean?" [a] let list_p a = _prim "list?" [a] let dict_p a = _prim "dict?" [a] let symbol_p a = _prim "symbol?" [a] -let keyword_p a = _prim "keyword?" [a] -let contains_p a b = _prim "contains?" [a; b] -let has_key_p a b = _prim "has-key?" [a; b] -let starts_with_p a b = _prim "starts-with?" [a; b] -let ends_with_p a b = _prim "ends-with?" [a; b] -let string_contains_p a b = _prim "string-contains?" [a; b] -let odd_p a = _prim "odd?" [a] -let even_p a = _prim "even?" [a] -let zero_p a = _prim "zero?" [a] (* String ops *) let str' args = String (sx_str args) @@ -189,10 +177,7 @@ let trim a = _prim "trim" [a] let split a b = _prim "split" [a; b] let join a b = _prim "join" [a; b] let replace a b c = _prim "replace" [a; b; c] -let index_of a b = _prim "index-of" [a; b] let substring a b c = _prim "substring" [a; b; c] -let string_length a = _prim "string-length" [a] -let char_from_code a = _prim "char-from-code" [a] (* Dict ops *) let assoc d k v = _prim "assoc" [d; k; v] @@ -202,7 +187,6 @@ let keys a = _prim "keys" [a] let vals a = _prim "vals" [a] let dict_set a b c = _prim "dict-set!" [a; b; c] let dict_get a b = _prim "dict-get" [a; b] -let dict_has_p a b = _prim "dict-has?" [a; b] let dict_delete a b = _prim "dict-delete!" [a; b] (* Math *) @@ -215,8 +199,6 @@ let round' a = _prim "round" [a] let min' a b = _prim "min" [a; b] let max' a b = _prim "max" [a; b] let clamp a b c = _prim "clamp" [a; b; c] -let parse_int a = _prim "parse-int" [a] -let parse_float a = _prim "parse-float" [a] (* Misc *) let error msg = raise (Eval_error (value_to_str msg)) @@ -224,17 +206,8 @@ let error msg = raise (Eval_error (value_to_str msg)) (* inspect wrapper — returns String value instead of OCaml string *) let inspect v = String (Sx_types.inspect v) let apply' f args = sx_apply f args -let identical_p a b = _prim "identical?" [a; b] -let _is_spread_prim a = _prim "spread?" [a] let spread_attrs a = _prim "spread-attrs" [a] -let make_spread a = _prim "make-spread" [a] -(* Scope primitives — delegate to sx_ref.py's shared scope stacks *) -let sx_collect a b = prim_call "collect!" [a; b] -let sx_collected a = prim_call "collected" [a] -let sx_clear_collected a = prim_call "clear-collected!" [a] -let sx_emit a b = prim_call "emit!" [a; b] -let sx_emitted a = prim_call "emitted" [a] let sx_context a b = prim_call "context" [a; b] (* Trampoline — forward-declared in sx_ref.ml, delegates to CEK eval_expr *) @@ -280,10 +253,8 @@ let is_island v = Bool (Sx_types.is_island v) let is_macro v = Bool (Sx_types.is_macro v) let is_signal v = Bool (Sx_types.is_signal v) let is_callable v = Bool (Sx_types.is_callable v) -let is_identical a b = Bool (a == b) let is_primitive name = Bool (Sx_primitives.is_primitive (value_to_str name)) let get_primitive name = Sx_primitives.get_primitive (value_to_str name) -let is_spread v = match v with Spread _ -> Bool true | _ -> Bool false (* Stubs for functions defined in sx_ref.ml — resolved at link time *) (* These are forward-declared here; sx_ref.ml defines the actual implementations *) @@ -293,21 +264,6 @@ let is_spread v = match v with Spread _ -> Bool true | _ -> Bool false sometimes referenced before their definition via forward calls. These get overridden by the actual transpiled definitions. *) -let map_indexed fn coll = - List (List.mapi (fun i x -> sx_call fn [Number (float_of_int i); x]) (sx_to_list coll)) - -let map_dict fn d = - match d with - | Dict tbl -> - let result = Hashtbl.create (Hashtbl.length tbl) in - Hashtbl.iter (fun k v -> Hashtbl.replace result k (sx_call fn [String k; v])) tbl; - Dict result - | _ -> raise (Eval_error "map-dict: expected dict") - -let for_each fn coll = - List.iter (fun x -> ignore (sx_call fn [x])) (sx_to_list coll); - Nil - let for_each_indexed fn coll = List.iteri (fun i x -> ignore (sx_call fn [Number (float_of_int i); x])) (sx_to_list coll); Nil @@ -380,8 +336,6 @@ let signal_value s = match s with | Signal sig' -> sig'.s_value | Dict d -> (match Hashtbl.find_opt d "value" with Some v -> v | None -> Nil) | _ -> raise (Eval_error "not a signal") -let signal_set_value s v = match s with Signal sig' -> sig'.s_value <- v; v | _ -> raise (Eval_error "not a signal") -let signal_subscribers s = match s with Signal sig' -> List (List.map (fun _ -> Nil) sig'.s_subscribers) | _ -> List [] let signal_add_sub_b s f = match s with | Dict d -> @@ -400,29 +354,6 @@ let signal_remove_sub_b s f = | _ -> Nil) | _ -> Nil -let signal_deps s = - match s with - | Dict d -> (match Hashtbl.find_opt d "deps" with Some v -> v | None -> List []) - | _ -> List [] - -let signal_set_deps s d = - match s with - | Dict tbl -> Hashtbl.replace tbl "deps" d; Nil - | _ -> Nil - -let notify_subscribers s = - let subs = match s with - | Dict d -> (match Hashtbl.find_opt d "subscribers" with - | Some (ListRef { contents = items }) | Some (List items) -> items - | _ -> []) - | _ -> [] - in - List.iter (fun f -> ignore (sx_call f [])) subs; - Nil - -let flush_subscribers _s = Nil -let dispose_computed _s = Nil - (* Island scope stubs — accept both bare OCaml fns and NativeFn values from transpiled code (NativeFn wrapping for value-storable lambdas). *) let with_island_scope _register_fn body_fn = @@ -444,20 +375,14 @@ let parse_keyword_args _raw_args _env = (* Stub — the real implementation is transpiled from evaluator.sx *) List [Dict (Hashtbl.create 0); List []] -(* Make handler/query/action/page def stubs *) +(* Make handler def — used by custom_special_forms *) let make_handler_def name params body _env = Dict (let d = Hashtbl.create 4 in Hashtbl.replace d "type" (String "handler"); Hashtbl.replace d "name" name; Hashtbl.replace d "params" params; Hashtbl.replace d "body" body; d) -let make_query_def name params body _env = make_handler_def name params body _env -let make_action_def name params body _env = make_handler_def name params body _env let make_page_def name _opts = Dict (let d = Hashtbl.create 4 in Hashtbl.replace d "type" (String "page"); Hashtbl.replace d "name" name; d) -(* sf-def* stubs — platform-specific def-forms, not in the SX spec *) +(* sf_defhandler — used by custom_special_forms *) let sf_defhandler args env = let name = first args in let rest_args = rest args in make_handler_def name (first rest_args) (nth rest_args (Number 1.0)) env -let sf_defquery args env = sf_defhandler args env -let sf_defaction args env = sf_defhandler args env -let sf_defpage args _env = - let name = first args in make_page_def name (rest args) let strip_prefix s prefix = match s, prefix with diff --git a/spec/primitives.sx b/spec/primitives.sx index bc938308..23bce392 100644 --- a/spec/primitives.sx +++ b/spec/primitives.sx @@ -34,576 +34,650 @@ ;; Logic: not ;; Text: pluralize escape assert parse-datetime ;; ========================================================================== - - ;; -------------------------------------------------------------------------- ;; Core — Arithmetic ;; -------------------------------------------------------------------------- - (define-module :core.arithmetic) -(define-primitive "+" +(define-primitive + "+" :params (&rest (args :as number)) :returns "number" :doc "Sum all arguments." :body (reduce (fn (a b) (native-add a b)) 0 args)) -(define-primitive "-" +(define-primitive + "-" :params ((a :as number) &rest (b :as number)) :returns "number" :doc "Subtract. Unary: negate. Binary: a - b." :body (if (empty? b) (native-neg a) (native-sub a (first b)))) -(define-primitive "*" +(define-primitive + "*" :params (&rest (args :as number)) :returns "number" :doc "Multiply all arguments." :body (reduce (fn (a b) (native-mul a b)) 1 args)) -(define-primitive "/" +(define-primitive + "/" :params ((a :as number) (b :as number)) :returns "number" :doc "Divide a by b." :body (native-div a b)) -(define-primitive "mod" +(define-primitive + "mod" :params ((a :as number) (b :as number)) :returns "number" :doc "Modulo a % b." :body (native-mod a b)) -(define-primitive "random-int" +(define-primitive + "random-int" :params ((low :as number) (high :as number)) :returns "number" :doc "Random integer in [low, high] inclusive." :body (native-random-int low high)) -(define-primitive "json-encode" +(define-primitive + "json-encode" :params (value) :returns "string" :doc "Encode value as JSON string with indentation.") -(define-primitive "sqrt" +(define-primitive + "sqrt" :params ((x :as number)) :returns "number" :doc "Square root.") -(define-primitive "pow" +(define-primitive + "pow" :params ((x :as number) (n :as number)) :returns "number" :doc "x raised to power n.") -(define-primitive "abs" +(define-primitive + "abs" :params ((x :as number)) :returns "number" :doc "Absolute value.") -(define-primitive "floor" +(define-primitive + "floor" :params ((x :as number)) :returns "number" :doc "Floor to integer.") -(define-primitive "ceil" +(define-primitive + "ceil" :params ((x :as number)) :returns "number" :doc "Ceiling to integer.") -(define-primitive "round" +(define-primitive + "round" :params ((x :as number) &rest (ndigits :as number)) :returns "number" :doc "Round to ndigits decimal places (default 0).") -(define-primitive "min" +(define-primitive + "min" :params (&rest (args :as number)) :returns "number" :doc "Minimum. Single list arg or variadic.") -(define-primitive "max" +(define-primitive + "max" :params (&rest (args :as number)) :returns "number" :doc "Maximum. Single list arg or variadic.") -(define-primitive "clamp" +(define-primitive + "clamp" :params ((x :as number) (lo :as number) (hi :as number)) :returns "number" :doc "Clamp x to range [lo, hi]." :body (max lo (min hi x))) -(define-primitive "inc" +(define-primitive + "inc" :params ((n :as number)) :returns "number" :doc "Increment by 1." :body (+ n 1)) -(define-primitive "dec" +(define-primitive + "dec" :params ((n :as number)) :returns "number" :doc "Decrement by 1." :body (- n 1)) - ;; -------------------------------------------------------------------------- ;; Core — Comparison ;; -------------------------------------------------------------------------- - (define-module :core.comparison) -(define-primitive "=" +(define-primitive + "=" :params (a b) :returns "boolean" :doc "Deep structural equality. Alias for equal?.") -(define-primitive "!=" +(define-primitive + "!=" :params (a b) :returns "boolean" :doc "Inequality." :body (not (= a b))) -(define-primitive "eq?" +(define-primitive + "eq?" :params (a b) :returns "boolean" - :doc "Identity equality. True only if a and b are the exact same object. - For immutable atoms (numbers, strings, booleans, nil) this may or - may not match — use eqv? for reliable atom comparison.") + :doc "Identity equality. True only if a and b are the same object." + :body (identical? a b)) -(define-primitive "eqv?" +(define-primitive + "eqv?" :params (a b) :returns "boolean" - :doc "Equivalent value for atoms, identity for compound objects. - Returns true for identical objects (eq?), and also for numbers, - strings, booleans, and nil with the same value. For lists, dicts, - lambdas, and components, only true if same identity.") + :doc "Equivalent value for atoms, identity for compound objects.\n Returns true for identical objects (eq?), and also for numbers,\n strings, booleans, and nil with the same value. For lists, dicts,\n lambdas, and components, only true if same identity.") -(define-primitive "equal?" +(define-primitive + "equal?" :params (a b) :returns "boolean" - :doc "Deep structural equality. Recursively compares lists and dicts. - Same semantics as = but explicit Scheme name.") + :doc "Deep structural equality. Recursively compares collections." + :body (= a b)) -(define-primitive "<" +(define-primitive + "<" :params ((a :as number) (b :as number)) :returns "boolean" :doc "Less than.") -(define-primitive ">" +(define-primitive + ">" :params ((a :as number) (b :as number)) :returns "boolean" :doc "Greater than.") -(define-primitive "<=" +(define-primitive + "<=" :params ((a :as number) (b :as number)) :returns "boolean" - :doc "Less than or equal.") + :doc "Less than or equal." + :body (or (< a b) (= a b))) -(define-primitive ">=" +(define-primitive + ">=" :params ((a :as number) (b :as number)) :returns "boolean" - :doc "Greater than or equal.") - + :doc "Greater than or equal." + :body (or (> a b) (= a b))) ;; -------------------------------------------------------------------------- ;; Core — Predicates ;; -------------------------------------------------------------------------- - (define-module :core.predicates) -(define-primitive "odd?" +(define-primitive + "odd?" :params ((n :as number)) :returns "boolean" :doc "True if n is odd." :body (= (mod n 2) 1)) -(define-primitive "even?" +(define-primitive + "even?" :params ((n :as number)) :returns "boolean" :doc "True if n is even." :body (= (mod n 2) 0)) -(define-primitive "zero?" +(define-primitive + "zero?" :params ((n :as number)) :returns "boolean" :doc "True if n is zero." :body (= n 0)) -(define-primitive "nil?" +(define-primitive + "nil?" :params (x) :returns "boolean" - :doc "True if x is nil/null/None.") + :doc "True if x is nil/null/None." + :body (= (type-of x) "nil")) -(define-primitive "boolean?" +(define-primitive + "boolean?" :params (x) :returns "boolean" - :doc "True if x is a boolean (true or false). Must be checked before - number? on platforms where booleans are numeric subtypes.") + :doc "True if x is a boolean (true or false)." + :body (= (type-of x) "boolean")) -(define-primitive "number?" +(define-primitive + "number?" :params (x) :returns "boolean" - :doc "True if x is a number (int or float). Excludes booleans.") + :doc "True if x is a number (int or float)." + :body (= (type-of x) "number")) -(define-primitive "string?" +(define-primitive + "string?" :params (x) :returns "boolean" - :doc "True if x is a string.") + :doc "True if x is a string." + :body (= (type-of x) "string")) -(define-primitive "list?" +(define-primitive + "list?" :params (x) :returns "boolean" - :doc "True if x is a list/array.") + :doc "True if x is a list/array." + :body (= (type-of x) "list")) -(define-primitive "dict?" +(define-primitive + "dict?" :params (x) :returns "boolean" - :doc "True if x is a dict/map.") + :doc "True if x is a dict/map." + :body (= (type-of x) "dict")) -(define-primitive "continuation?" +(define-primitive + "continuation?" :params (x) :returns "boolean" - :doc "True if x is a captured continuation.") + :doc "True if x is a captured continuation." + :body (= (type-of x) "continuation")) -(define-primitive "empty?" +(define-primitive + "empty?" :params (coll) :returns "boolean" - :doc "True if coll is nil or has length 0.") + :doc "True if coll is nil or has length 0." + :body (or (nil? coll) (= (len coll) 0))) -(define-primitive "contains?" +(define-primitive + "contains?" :params (coll key) :returns "boolean" :doc "True if coll contains key. Strings: substring check. Dicts: key check. Lists: membership.") - ;; -------------------------------------------------------------------------- ;; Core — Logic ;; -------------------------------------------------------------------------- - (define-module :core.logic) -(define-primitive "not" +(define-primitive + "not" :params (x) :returns "boolean" - :doc "Logical negation. Note: and/or are special forms (short-circuit).") - + :doc "Logical negation. Note: and/or are special forms, not primitives." + :body (if x false true)) ;; -------------------------------------------------------------------------- ;; Core — Strings ;; -------------------------------------------------------------------------- - (define-module :core.strings) -(define-primitive "str" +(define-primitive + "str" :params (&rest args) :returns "string" :doc "Concatenate all args as strings. nil → empty string, bool → true/false.") -(define-primitive "concat" +(define-primitive + "concat" :params (&rest (colls :as list)) :returns "list" :doc "Concatenate multiple lists into one. Skips nil values.") -(define-primitive "upper" +(define-primitive + "upper" :params ((s :as string)) :returns "string" :doc "Uppercase string.") -(define-primitive "upcase" +(define-primitive + "upcase" :params ((s :as string)) :returns "string" :doc "Alias for upper. Uppercase string.") -(define-primitive "lower" +(define-primitive + "lower" :params ((s :as string)) :returns "string" :doc "Lowercase string.") -(define-primitive "downcase" +(define-primitive + "downcase" :params ((s :as string)) :returns "string" :doc "Alias for lower. Lowercase string.") -(define-primitive "string-length" +(define-primitive + "string-length" :params ((s :as string)) :returns "number" :doc "Length of string in characters.") -(define-primitive "char-from-code" +(define-primitive + "char-from-code" :params ((n :as number)) :returns "string" :doc "Convert Unicode code point to single-character string.") -(define-primitive "substring" +(define-primitive + "substring" :params ((s :as string) (start :as number) (end :as number)) :returns "string" :doc "Extract substring from start (inclusive) to end (exclusive).") -(define-primitive "string-contains?" +(define-primitive + "string-contains?" :params ((s :as string) (needle :as string)) :returns "boolean" :doc "True if string s contains substring needle.") -(define-primitive "trim" +(define-primitive + "trim" :params ((s :as string)) :returns "string" :doc "Strip leading/trailing whitespace.") -(define-primitive "split" +(define-primitive + "split" :params ((s :as string) &rest (sep :as string)) :returns "list" :doc "Split string by separator (default space).") -(define-primitive "join" +(define-primitive + "join" :params ((sep :as string) (coll :as list)) :returns "string" :doc "Join collection items with separator string.") -(define-primitive "replace" +(define-primitive + "replace" :params ((s :as string) (old :as string) (new :as string)) :returns "string" :doc "Replace all occurrences of old with new in s.") -(define-primitive "slice" +(define-primitive + "slice" :params (coll (start :as number) &rest (end :as number)) :returns "any" :doc "Slice a string or list from start to end (exclusive). End is optional.") -(define-primitive "index-of" +(define-primitive + "index-of" :params ((s :as string) (needle :as string) &rest (from :as number)) :returns "number" :doc "Index of first occurrence of needle in s, or -1 if not found. Optional start index.") -(define-primitive "starts-with?" +(define-primitive + "starts-with?" :params ((s :as string) (prefix :as string)) :returns "boolean" :doc "True if string s starts with prefix.") -(define-primitive "ends-with?" +(define-primitive + "ends-with?" :params ((s :as string) (suffix :as string)) :returns "boolean" :doc "True if string s ends with suffix.") - ;; -------------------------------------------------------------------------- ;; Core — Collections ;; -------------------------------------------------------------------------- - (define-module :core.collections) -(define-primitive "list" +(define-primitive + "list" :params (&rest args) :returns "list" :doc "Create a list from arguments.") -(define-primitive "dict" +(define-primitive + "dict" :params (&rest pairs) :returns "dict" :doc "Create a dict from key/value pairs: (dict :a 1 :b 2).") -(define-primitive "range" +(define-primitive + "range" :params ((start :as number) (end :as number) &rest (step :as number)) :returns "list" :doc "Integer range [start, end) with optional step.") -(define-primitive "get" +(define-primitive + "get" :params (coll key &rest default) :returns "any" :doc "Get value from dict by key, or list by index. Optional default.") -(define-primitive "len" +(define-primitive + "len" :params (coll) :returns "number" :doc "Length of string, list, or dict.") -(define-primitive "first" +(define-primitive + "first" :params ((coll :as list)) :returns "any" :doc "First element, or nil if empty.") -(define-primitive "last" +(define-primitive + "last" :params ((coll :as list)) :returns "any" :doc "Last element, or nil if empty.") -(define-primitive "rest" +(define-primitive + "rest" :params ((coll :as list)) :returns "list" :doc "All elements except the first.") -(define-primitive "nth" +(define-primitive + "nth" :params ((coll :as list) (n :as number)) :returns "any" :doc "Element at index n, or nil if out of bounds.") -(define-primitive "cons" +(define-primitive + "cons" :params (x (coll :as list)) :returns "list" :doc "Prepend x to coll.") -(define-primitive "append" +(define-primitive + "append" :params ((coll :as list) x) :returns "list" :doc "If x is a list, concatenate. Otherwise append x as single element.") -(define-primitive "append!" +(define-primitive + "append!" :params ((coll :as list) x) :returns "list" :doc "Mutate coll by appending x in-place. Returns coll.") -(define-primitive "reverse" +(define-primitive + "reverse" :params ((coll :as list)) :returns "list" :doc "Return coll in reverse order.") -(define-primitive "flatten" +(define-primitive + "flatten" :params ((coll :as list)) :returns "list" :doc "Flatten one level of nesting. Nested lists become top-level elements.") -(define-primitive "chunk-every" +(define-primitive + "chunk-every" :params ((coll :as list) (n :as number)) :returns "list" :doc "Split coll into sub-lists of size n.") -(define-primitive "zip-pairs" +(define-primitive + "zip-pairs" :params ((coll :as list)) :returns "list" :doc "Consecutive pairs: (1 2 3 4) → ((1 2) (2 3) (3 4)).") - ;; -------------------------------------------------------------------------- ;; Core — Dict operations ;; -------------------------------------------------------------------------- - (define-module :core.dict) -(define-primitive "keys" +(define-primitive + "keys" :params ((d :as dict)) :returns "list" :doc "List of dict keys.") -(define-primitive "vals" +(define-primitive + "vals" :params ((d :as dict)) :returns "list" :doc "List of dict values.") -(define-primitive "merge" +(define-primitive + "merge" :params (&rest (dicts :as dict)) :returns "dict" :doc "Merge dicts left to right. Later keys win. Skips nil.") -(define-primitive "has-key?" +(define-primitive + "has-key?" :params ((d :as dict) key) :returns "boolean" :doc "True if dict d contains key.") -(define-primitive "assoc" +(define-primitive + "assoc" :params ((d :as dict) &rest pairs) :returns "dict" :doc "Return new dict with key/value pairs added/overwritten.") -(define-primitive "dissoc" +(define-primitive + "dissoc" :params ((d :as dict) &rest keys) :returns "dict" :doc "Return new dict with keys removed.") -(define-primitive "dict-set!" +(define-primitive + "dict-set!" :params ((d :as dict) key val) :returns "any" :doc "Mutate dict d by setting key to val in-place. Returns val.") -(define-primitive "into" +(define-primitive + "into" :params (target coll) :returns "any" :doc "Pour coll into target. List target: convert to list. Dict target: convert pairs to dict.") - ;; -------------------------------------------------------------------------- ;; Stdlib — Format ;; -------------------------------------------------------------------------- - (define-module :stdlib.format) -(define-primitive "format-date" +(define-primitive + "format-date" :params ((date-str :as string) (fmt :as string)) :returns "string" :doc "Parse ISO date string and format with strftime-style format.") -(define-primitive "format-decimal" +(define-primitive + "format-decimal" :params ((val :as number) &rest (places :as number)) :returns "string" :doc "Format number with fixed decimal places (default 2).") -(define-primitive "parse-int" +(define-primitive + "parse-int" :params (val &rest default) :returns "number" :doc "Parse string to integer with optional default on failure.") -(define-primitive "parse-datetime" +(define-primitive + "parse-datetime" :params ((s :as string)) :returns "string" :doc "Parse datetime string — identity passthrough (returns string or nil).") - ;; -------------------------------------------------------------------------- ;; Stdlib — Text ;; -------------------------------------------------------------------------- - (define-module :stdlib.text) -(define-primitive "pluralize" +(define-primitive + "pluralize" :params ((count :as number) &rest (forms :as string)) :returns "string" :doc "Pluralize: (pluralize 1) → \"\", (pluralize 2) → \"s\". Or (pluralize n \"item\" \"items\").") -(define-primitive "escape" +(define-primitive + "escape" :params ((s :as string)) :returns "string" :doc "HTML-escape a string (&, <, >, \", ').") -(define-primitive "strip-tags" +(define-primitive + "strip-tags" :params ((s :as string)) :returns "string" :doc "Remove HTML tags from string.") - ;; -------------------------------------------------------------------------- ;; Stdlib — Style ;; -------------------------------------------------------------------------- - - - ;; -------------------------------------------------------------------------- ;; Stdlib — Debug ;; -------------------------------------------------------------------------- - (define-module :stdlib.debug) -(define-primitive "assert" +(define-primitive + "assert" :params (condition &rest message) :returns "boolean" :doc "Assert condition is truthy; raise error with message if not.") - ;; -------------------------------------------------------------------------- ;; Type introspection — platform primitives ;; -------------------------------------------------------------------------- - (define-module :stdlib.types) -(define-primitive "type-of" +(define-primitive + "type-of" :params (x) :returns "string" :doc "Return type name: number, string, boolean, nil, symbol, keyword, list, dict, lambda, component, island, macro.") -(define-primitive "symbol-name" +(define-primitive + "symbol-name" :params ((sym :as symbol)) :returns "string" :doc "Return the name string of a symbol.") -(define-primitive "keyword-name" +(define-primitive + "keyword-name" :params ((kw :as keyword)) :returns "string" :doc "Return the name string of a keyword.") -(define-primitive "sx-parse" +(define-primitive + "sx-parse" :params ((source :as string)) :returns "list" :doc "Parse SX source string into a list of AST expressions.")