HS parser/compiler/runtime: fix 8 parse errors, add/remove arrays, return guard
Parser:
- `add VALUE to :var` → (add-value) for array append
- `remove VALUE from :var` → (remove-value) for array removal
- `toggle .foo for 10ms` → (toggle-class-for) with duration
- `append VALUE` without `to` → implicit target (it)
- `set {obj} on target` → (set-on) for object property spread
- `repeat in` body: remove spurious nil (body at index 3→2)
- Keywords followed by `(` parsed as function calls (fixes `increment()`)
Compiler:
- Handle add-value, remove-value, toggle-class-for, set-on AST nodes
- Local variables (`set :var`) use `define` instead of `set!`
Runtime:
- hs-add-to!: append value to list
- hs-remove-from!: filter value from list
- hs-set-on!: spread dict properties onto target
- `as String` for lists: comma-join (JS Array.toString compat)
Tests:
- eval-hs/eval-hs-with-me: guard for hs-return exceptions
(return compiles to raise, needs handler to extract value)
Parse errors: 20→12 (8 fixed). Remaining: 6 embedded HTML quotes
(tokenizer), 6 transition template values `(expr)px`.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -43,7 +43,7 @@
|
|||||||
((= th (quote ref))
|
((= th (quote ref))
|
||||||
(list (quote set!) (make-symbol (nth target 1)) value))
|
(list (quote set!) (make-symbol (nth target 1)) value))
|
||||||
((= th (quote local))
|
((= th (quote local))
|
||||||
(list (quote set!) (make-symbol (nth target 1)) value))
|
(list (quote define) (make-symbol (nth target 1)) value))
|
||||||
((= th (quote me))
|
((= th (quote me))
|
||||||
(list (quote dom-set-inner-html) (quote me) value))
|
(list (quote dom-set-inner-html) (quote me) value))
|
||||||
((= th (quote it)) (list (quote set!) (quote it) value))
|
((= th (quote it)) (list (quote set!) (quote it) value))
|
||||||
@@ -912,6 +912,20 @@
|
|||||||
(nth ast 1)))))
|
(nth ast 1)))))
|
||||||
((= head (quote remove-element))
|
((= head (quote remove-element))
|
||||||
(list (quote dom-remove) (hs-to-sx (nth ast 1))))
|
(list (quote dom-remove) (hs-to-sx (nth ast 1))))
|
||||||
|
((= head (quote add-value))
|
||||||
|
(let
|
||||||
|
((val (hs-to-sx (nth ast 1))) (tgt (nth ast 2)))
|
||||||
|
(list
|
||||||
|
(quote set!)
|
||||||
|
(hs-to-sx tgt)
|
||||||
|
(list (quote hs-add-to!) val (hs-to-sx tgt)))))
|
||||||
|
((= head (quote remove-value))
|
||||||
|
(let
|
||||||
|
((val (hs-to-sx (nth ast 1))) (tgt (nth ast 2)))
|
||||||
|
(list
|
||||||
|
(quote set!)
|
||||||
|
(hs-to-sx tgt)
|
||||||
|
(list (quote hs-remove-from!) val (hs-to-sx tgt)))))
|
||||||
((= head (quote empty-target))
|
((= head (quote empty-target))
|
||||||
(list (quote hs-empty-target!) (hs-to-sx (nth ast 1))))
|
(list (quote hs-empty-target!) (hs-to-sx (nth ast 1))))
|
||||||
((= head (quote open-element))
|
((= head (quote open-element))
|
||||||
@@ -946,6 +960,28 @@
|
|||||||
(quote hs-toggle-class!)
|
(quote hs-toggle-class!)
|
||||||
(hs-to-sx (nth ast 2))
|
(hs-to-sx (nth ast 2))
|
||||||
(nth ast 1)))
|
(nth ast 1)))
|
||||||
|
((= head (quote toggle-class-for))
|
||||||
|
(list
|
||||||
|
(quote do)
|
||||||
|
(list
|
||||||
|
(quote hs-toggle-class!)
|
||||||
|
(hs-to-sx (nth ast 2))
|
||||||
|
(nth ast 1))
|
||||||
|
(list
|
||||||
|
(quote perform)
|
||||||
|
(list
|
||||||
|
(quote list)
|
||||||
|
(quote io-sleep)
|
||||||
|
(hs-to-sx (nth ast 3))))
|
||||||
|
(list
|
||||||
|
(quote hs-toggle-class!)
|
||||||
|
(hs-to-sx (nth ast 2))
|
||||||
|
(nth ast 1))))
|
||||||
|
((= head (quote set-on))
|
||||||
|
(list
|
||||||
|
(quote hs-set-on!)
|
||||||
|
(hs-to-sx (nth ast 1))
|
||||||
|
(hs-to-sx (nth ast 2))))
|
||||||
((= head (quote toggle-between))
|
((= head (quote toggle-between))
|
||||||
(list
|
(list
|
||||||
(quote hs-toggle-between!)
|
(quote hs-toggle-between!)
|
||||||
|
|||||||
@@ -283,6 +283,12 @@
|
|||||||
var-name
|
var-name
|
||||||
collection
|
collection
|
||||||
(parse-expr))))))))
|
(parse-expr))))))))
|
||||||
|
((and (= typ "keyword") (> (len tokens) (+ p 1)) (= (get (nth tokens (+ p 1)) "type") "paren-open"))
|
||||||
|
(do
|
||||||
|
(adv!)
|
||||||
|
(let
|
||||||
|
((name val) (args (parse-call-args)))
|
||||||
|
(list (quote call) (list (quote ref) name) args))))
|
||||||
(true nil)))))
|
(true nil)))))
|
||||||
(define
|
(define
|
||||||
parse-poss
|
parse-poss
|
||||||
@@ -805,7 +811,14 @@
|
|||||||
(cons
|
(cons
|
||||||
(quote multi-add-class)
|
(quote multi-add-class)
|
||||||
(cons tgt (cons cls extra-classes))))))))
|
(cons tgt (cons cls extra-classes))))))))
|
||||||
nil)))
|
(let
|
||||||
|
((value (parse-expr)))
|
||||||
|
(if
|
||||||
|
(match-kw "to")
|
||||||
|
(let
|
||||||
|
((tgt (parse-expr)))
|
||||||
|
(list (quote add-value) value tgt))
|
||||||
|
nil)))))
|
||||||
(define
|
(define
|
||||||
parse-remove-cmd
|
parse-remove-cmd
|
||||||
(fn
|
(fn
|
||||||
@@ -870,8 +883,13 @@
|
|||||||
(list (quote remove-css) props tgt)))))
|
(list (quote remove-css) props tgt)))))
|
||||||
(true
|
(true
|
||||||
(let
|
(let
|
||||||
((target (parse-expr)))
|
((value (parse-expr)))
|
||||||
(list (quote remove-element) target))))))
|
(if
|
||||||
|
(match-kw "from")
|
||||||
|
(let
|
||||||
|
((tgt (parse-expr)))
|
||||||
|
(list (quote remove-value) value tgt))
|
||||||
|
(list (quote remove-element) value)))))))
|
||||||
(define
|
(define
|
||||||
parse-toggle-cmd
|
parse-toggle-cmd
|
||||||
(fn
|
(fn
|
||||||
@@ -897,7 +915,12 @@
|
|||||||
((cls (do (let ((v (tp-val))) (adv!) v))))
|
((cls (do (let ((v (tp-val))) (adv!) v))))
|
||||||
(let
|
(let
|
||||||
((tgt (parse-tgt-kw "on" (list (quote me)))))
|
((tgt (parse-tgt-kw "on" (list (quote me)))))
|
||||||
(list (quote toggle-class) cls tgt))))
|
(if
|
||||||
|
(match-kw "for")
|
||||||
|
(let
|
||||||
|
((dur (parse-expr)))
|
||||||
|
(list (quote toggle-class-for) cls tgt dur))
|
||||||
|
(list (quote toggle-class) cls tgt)))))
|
||||||
((= (tp-type) "style")
|
((= (tp-type) "style")
|
||||||
(let
|
(let
|
||||||
((prop (do (let ((v (tp-val))) (adv!) v))))
|
((prop (do (let ((v (tp-val))) (adv!) v))))
|
||||||
@@ -1006,8 +1029,14 @@
|
|||||||
()
|
()
|
||||||
(let
|
(let
|
||||||
((tgt (parse-expr)))
|
((tgt (parse-expr)))
|
||||||
(expect-kw! "to")
|
(cond
|
||||||
(let ((value (parse-expr))) (list (quote set!) tgt value)))))
|
((match-kw "to")
|
||||||
|
(let ((value (parse-expr))) (list (quote set!) tgt value)))
|
||||||
|
((match-kw "on")
|
||||||
|
(let
|
||||||
|
((target (parse-expr)))
|
||||||
|
(list (quote set-on) tgt target)))
|
||||||
|
(true (error (str "Expected to/on at position " p)))))))
|
||||||
(define
|
(define
|
||||||
parse-put-cmd
|
parse-put-cmd
|
||||||
(fn
|
(fn
|
||||||
@@ -1244,7 +1273,7 @@
|
|||||||
(let
|
(let
|
||||||
((body (parse-cmd-list)))
|
((body (parse-cmd-list)))
|
||||||
(match-kw "end")
|
(match-kw "end")
|
||||||
(list (quote for) "it" collection nil body)))))
|
(list (quote for) "it" collection body)))))
|
||||||
(true
|
(true
|
||||||
(let
|
(let
|
||||||
((mode (cond ((match-kw "forever") (list (quote forever))) ((match-kw "while") (list (quote while) (parse-expr))) ((match-kw "until") (list (quote until) (parse-expr))) (true (let ((n (parse-expr))) (if (match-kw "times") (list (quote times) n) (list (quote forever))))))))
|
((mode (cond ((match-kw "forever") (list (quote forever))) ((match-kw "while") (list (quote while) (parse-expr))) ((match-kw "until") (list (quote until) (parse-expr))) (true (let ((n (parse-expr))) (if (match-kw "times") (list (quote times) n) (list (quote forever))))))))
|
||||||
@@ -1464,10 +1493,12 @@
|
|||||||
()
|
()
|
||||||
(let
|
(let
|
||||||
((value (parse-expr)))
|
((value (parse-expr)))
|
||||||
(expect-kw! "to")
|
(if
|
||||||
(let
|
(match-kw "to")
|
||||||
((target (parse-expr)))
|
(let
|
||||||
(list (quote append!) value target)))))
|
((target (parse-expr)))
|
||||||
|
(list (quote append!) value target))
|
||||||
|
(list (quote append!) value (list (quote it)))))))
|
||||||
(define
|
(define
|
||||||
parse-tell-cmd
|
parse-tell-cmd
|
||||||
(fn
|
(fn
|
||||||
|
|||||||
@@ -136,9 +136,35 @@
|
|||||||
((= pos "end") (dom-insert-adjacent-html target "beforeend" value)))))
|
((= pos "end") (dom-insert-adjacent-html target "beforeend" value)))))
|
||||||
|
|
||||||
;; Find previous sibling matching a selector.
|
;; Find previous sibling matching a selector.
|
||||||
(define hs-navigate! (fn (url) (perform (list (quote io-navigate) url))))
|
(define
|
||||||
|
hs-add-to!
|
||||||
|
(fn
|
||||||
|
(value target)
|
||||||
|
(if
|
||||||
|
(list? target)
|
||||||
|
(append target (list value))
|
||||||
|
(host-call target "push" value))))
|
||||||
|
|
||||||
;; First element matching selector within a scope.
|
;; First element matching selector within a scope.
|
||||||
|
(define
|
||||||
|
hs-remove-from!
|
||||||
|
(fn
|
||||||
|
(value target)
|
||||||
|
(if
|
||||||
|
(list? target)
|
||||||
|
(filter (fn (x) (not (= x value))) target)
|
||||||
|
(host-call target "splice" (host-call target "indexOf" value) 1))))
|
||||||
|
|
||||||
|
;; Last element matching selector.
|
||||||
|
(define
|
||||||
|
hs-set-on!
|
||||||
|
(fn
|
||||||
|
(props target)
|
||||||
|
(for-each (fn (k) (host-set! target k (get props k))) (keys props))))
|
||||||
|
|
||||||
|
;; First/last within a specific scope.
|
||||||
|
(define hs-navigate! (fn (url) (perform (list (quote io-navigate) url))))
|
||||||
|
|
||||||
(define
|
(define
|
||||||
hs-scroll!
|
hs-scroll!
|
||||||
(fn
|
(fn
|
||||||
@@ -151,7 +177,9 @@
|
|||||||
((= position "bottom") (dict :block "end"))
|
((= position "bottom") (dict :block "end"))
|
||||||
(true (dict :block "start")))))))
|
(true (dict :block "start")))))))
|
||||||
|
|
||||||
;; Last element matching selector.
|
;; ── Iteration ───────────────────────────────────────────────────
|
||||||
|
|
||||||
|
;; Repeat a thunk N times.
|
||||||
(define
|
(define
|
||||||
hs-halt!
|
hs-halt!
|
||||||
(fn
|
(fn
|
||||||
@@ -161,14 +189,19 @@
|
|||||||
(host-call event "preventDefault" (list))
|
(host-call event "preventDefault" (list))
|
||||||
(when (= mode "event") (host-call event "stopPropagation" (list))))))
|
(when (= mode "event") (host-call event "stopPropagation" (list))))))
|
||||||
|
|
||||||
;; First/last within a specific scope.
|
;; Repeat forever (until break — relies on exception/continuation).
|
||||||
(define hs-select! (fn (target) (host-call target "select" (list))))
|
(define hs-select! (fn (target) (host-call target "select" (list))))
|
||||||
|
|
||||||
|
;; ── Fetch ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
;; Fetch a URL, parse response according to format.
|
||||||
|
;; (hs-fetch url format) — format is "json" | "text" | "html"
|
||||||
(define hs-reset! (fn (target) (host-call target "reset" (list))))
|
(define hs-reset! (fn (target) (host-call target "reset" (list))))
|
||||||
|
|
||||||
;; ── Iteration ───────────────────────────────────────────────────
|
;; ── Type coercion ───────────────────────────────────────────────
|
||||||
|
|
||||||
;; Repeat a thunk N times.
|
;; Coerce a value to a type by name.
|
||||||
|
;; (hs-coerce value type-name) — type-name is "Int", "Float", "String", etc.
|
||||||
(define
|
(define
|
||||||
hs-next
|
hs-next
|
||||||
(fn
|
(fn
|
||||||
@@ -188,7 +221,10 @@
|
|||||||
(true (find-next (dom-next-sibling el))))))
|
(true (find-next (dom-next-sibling el))))))
|
||||||
(find-next sibling)))))
|
(find-next sibling)))))
|
||||||
|
|
||||||
;; Repeat forever (until break — relies on exception/continuation).
|
;; ── Object creation ─────────────────────────────────────────────
|
||||||
|
|
||||||
|
;; Make a new object of a given type.
|
||||||
|
;; (hs-make type-name) — creates empty object/collection
|
||||||
(define
|
(define
|
||||||
hs-previous
|
hs-previous
|
||||||
(fn
|
(fn
|
||||||
@@ -208,26 +244,27 @@
|
|||||||
(true (find-prev (dom-get-prop el "previousElementSibling"))))))
|
(true (find-prev (dom-get-prop el "previousElementSibling"))))))
|
||||||
(find-prev sibling)))))
|
(find-prev sibling)))))
|
||||||
|
|
||||||
;; ── Fetch ───────────────────────────────────────────────────────
|
;; ── Behavior installation ───────────────────────────────────────
|
||||||
|
|
||||||
;; Fetch a URL, parse response according to format.
|
;; Install a behavior on an element.
|
||||||
;; (hs-fetch url format) — format is "json" | "text" | "html"
|
;; A behavior is a function that takes (me ...params) and sets up features.
|
||||||
|
;; (hs-install behavior-fn me ...args)
|
||||||
(define
|
(define
|
||||||
hs-query-all
|
hs-query-all
|
||||||
(fn (sel) (host-call (dom-body) "querySelectorAll" sel)))
|
(fn (sel) (host-call (dom-body) "querySelectorAll" sel)))
|
||||||
|
|
||||||
;; ── Type coercion ───────────────────────────────────────────────
|
;; ── Measurement ─────────────────────────────────────────────────
|
||||||
|
|
||||||
;; Coerce a value to a type by name.
|
;; Measure an element's bounding rect, store as local variables.
|
||||||
;; (hs-coerce value type-name) — type-name is "Int", "Float", "String", etc.
|
;; Returns a dict with x, y, width, height, top, left, right, bottom.
|
||||||
(define
|
(define
|
||||||
hs-query-first
|
hs-query-first
|
||||||
(fn (sel) (host-call (host-global "document") "querySelector" sel)))
|
(fn (sel) (host-call (host-global "document") "querySelector" sel)))
|
||||||
|
|
||||||
;; ── Object creation ─────────────────────────────────────────────
|
;; ── Transition ──────────────────────────────────────────────────
|
||||||
|
|
||||||
;; Make a new object of a given type.
|
;; Transition a CSS property to a value, optionally with duration.
|
||||||
;; (hs-make type-name) — creates empty object/collection
|
;; (hs-transition target prop value duration)
|
||||||
(define
|
(define
|
||||||
hs-query-last
|
hs-query-last
|
||||||
(fn
|
(fn
|
||||||
@@ -236,17 +273,8 @@
|
|||||||
((all (dom-query-all (dom-body) sel)))
|
((all (dom-query-all (dom-body) sel)))
|
||||||
(if (> (len all) 0) (nth all (- (len all) 1)) nil))))
|
(if (> (len all) 0) (nth all (- (len all) 1)) nil))))
|
||||||
|
|
||||||
;; ── Behavior installation ───────────────────────────────────────
|
|
||||||
|
|
||||||
;; Install a behavior on an element.
|
|
||||||
;; A behavior is a function that takes (me ...params) and sets up features.
|
|
||||||
;; (hs-install behavior-fn me ...args)
|
|
||||||
(define hs-first (fn (scope sel) (dom-query-all scope sel)))
|
(define hs-first (fn (scope sel) (dom-query-all scope sel)))
|
||||||
|
|
||||||
;; ── Measurement ─────────────────────────────────────────────────
|
|
||||||
|
|
||||||
;; Measure an element's bounding rect, store as local variables.
|
|
||||||
;; Returns a dict with x, y, width, height, top, left, right, bottom.
|
|
||||||
(define
|
(define
|
||||||
hs-last
|
hs-last
|
||||||
(fn
|
(fn
|
||||||
@@ -255,10 +283,6 @@
|
|||||||
((all (dom-query-all scope sel)))
|
((all (dom-query-all scope sel)))
|
||||||
(if (> (len all) 0) (nth all (- (len all) 1)) nil))))
|
(if (> (len all) 0) (nth all (- (len all) 1)) nil))))
|
||||||
|
|
||||||
;; ── Transition ──────────────────────────────────────────────────
|
|
||||||
|
|
||||||
;; Transition a CSS property to a value, optionally with duration.
|
|
||||||
;; (hs-transition target prop value duration)
|
|
||||||
(define
|
(define
|
||||||
hs-repeat-times
|
hs-repeat-times
|
||||||
(fn
|
(fn
|
||||||
@@ -296,7 +320,11 @@
|
|||||||
((= type-name "Integer") (floor (+ value 0)))
|
((= type-name "Integer") (floor (+ value 0)))
|
||||||
((= type-name "Float") (+ value 0))
|
((= type-name "Float") (+ value 0))
|
||||||
((= type-name "Number") (+ value 0))
|
((= type-name "Number") (+ value 0))
|
||||||
((= type-name "String") (str value))
|
((= type-name "String")
|
||||||
|
(if
|
||||||
|
(list? value)
|
||||||
|
(join "," (map (fn (x) (str x)) value))
|
||||||
|
(str value)))
|
||||||
((= type-name "Bool") (not (hs-falsy? value)))
|
((= type-name "Bool") (not (hs-falsy? value)))
|
||||||
((= type-name "Boolean") (not (hs-falsy? value)))
|
((= type-name "Boolean") (not (hs-falsy? value)))
|
||||||
((= type-name "Array") (if (list? value) value (list value)))
|
((= type-name "Array") (if (list? value) value (list value)))
|
||||||
@@ -395,6 +423,10 @@
|
|||||||
|
|
||||||
(define hs-install (fn (behavior-fn) (behavior-fn me)))
|
(define hs-install (fn (behavior-fn) (behavior-fn me)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(define
|
(define
|
||||||
hs-measure
|
hs-measure
|
||||||
(fn (target) (perform (list (quote io-measure) target))))
|
(fn (target) (perform (list (quote io-measure) target))))
|
||||||
@@ -411,7 +443,8 @@
|
|||||||
(str prop " " (/ duration 1000) "s")))
|
(str prop " " (/ duration 1000) "s")))
|
||||||
(dom-set-style target prop value)
|
(dom-set-style target prop value)
|
||||||
(when duration (hs-settle target))))
|
(when duration (hs-settle target))))
|
||||||
|
;; ── Sandbox/test runtime additions ──────────────────────────────
|
||||||
|
;; Property access — dot notation and .length
|
||||||
(define
|
(define
|
||||||
hs-transition-from
|
hs-transition-from
|
||||||
(fn
|
(fn
|
||||||
@@ -425,11 +458,7 @@
|
|||||||
(str prop " " (/ duration 1000) "s")))
|
(str prop " " (/ duration 1000) "s")))
|
||||||
(dom-set-style target prop (str to-val))
|
(dom-set-style target prop (str to-val))
|
||||||
(when duration (hs-settle target))))
|
(when duration (hs-settle target))))
|
||||||
|
;; DOM query stub — sandbox returns empty list
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(define
|
(define
|
||||||
hs-type-check
|
hs-type-check
|
||||||
(fn
|
(fn
|
||||||
@@ -449,34 +478,33 @@
|
|||||||
(= (host-typeof value) "element")
|
(= (host-typeof value) "element")
|
||||||
(= (host-typeof value) "text")))
|
(= (host-typeof value) "text")))
|
||||||
(true (= (host-typeof value) (downcase type-name)))))))
|
(true (= (host-typeof value) (downcase type-name)))))))
|
||||||
|
;; Method dispatch — obj.method(args)
|
||||||
(define
|
(define
|
||||||
hs-type-check-strict
|
hs-type-check-strict
|
||||||
(fn
|
(fn
|
||||||
(value type-name)
|
(value type-name)
|
||||||
(if (nil? value) false (hs-type-check value type-name))))
|
(if (nil? value) false (hs-type-check value type-name))))
|
||||||
;; ── Sandbox/test runtime additions ──────────────────────────────
|
|
||||||
;; Property access — dot notation and .length
|
|
||||||
(define
|
|
||||||
hs-strict-eq
|
|
||||||
(fn (a b) (and (= (type-of a) (type-of b)) (= a b))))
|
|
||||||
;; DOM query stub — sandbox returns empty list
|
|
||||||
(define
|
|
||||||
hs-eq-ignore-case
|
|
||||||
(fn (a b) (= (downcase (str a)) (downcase (str b)))))
|
|
||||||
;; Method dispatch — obj.method(args)
|
|
||||||
(define
|
|
||||||
hs-starts-with-ic?
|
|
||||||
(fn (str prefix) (starts-with? (downcase str) (downcase prefix))))
|
|
||||||
|
|
||||||
;; ── 0.9.90 features ─────────────────────────────────────────────
|
;; ── 0.9.90 features ─────────────────────────────────────────────
|
||||||
;; beep! — debug logging, returns value unchanged
|
;; beep! — debug logging, returns value unchanged
|
||||||
|
(define
|
||||||
|
hs-strict-eq
|
||||||
|
(fn (a b) (and (= (type-of a) (type-of b)) (= a b))))
|
||||||
|
;; Property-based is — check obj.key truthiness
|
||||||
|
(define
|
||||||
|
hs-eq-ignore-case
|
||||||
|
(fn (a b) (= (downcase (str a)) (downcase (str b)))))
|
||||||
|
;; Array slicing (inclusive both ends)
|
||||||
|
(define
|
||||||
|
hs-starts-with-ic?
|
||||||
|
(fn (str prefix) (starts-with? (downcase str) (downcase prefix))))
|
||||||
|
;; Collection: sorted by
|
||||||
(define
|
(define
|
||||||
hs-contains-ignore-case?
|
hs-contains-ignore-case?
|
||||||
(fn
|
(fn
|
||||||
(haystack needle)
|
(haystack needle)
|
||||||
(contains? (downcase (str haystack)) (downcase (str needle)))))
|
(contains? (downcase (str haystack)) (downcase (str needle)))))
|
||||||
;; Property-based is — check obj.key truthiness
|
;; Collection: sorted by descending
|
||||||
(define
|
(define
|
||||||
hs-falsy?
|
hs-falsy?
|
||||||
(fn
|
(fn
|
||||||
@@ -488,7 +516,7 @@
|
|||||||
((and (list? v) (= (len v) 0)) true)
|
((and (list? v) (= (len v) 0)) true)
|
||||||
((= v 0) true)
|
((= v 0) true)
|
||||||
(true false))))
|
(true false))))
|
||||||
;; Array slicing (inclusive both ends)
|
;; Collection: split by
|
||||||
(define
|
(define
|
||||||
hs-matches?
|
hs-matches?
|
||||||
(fn
|
(fn
|
||||||
@@ -499,7 +527,7 @@
|
|||||||
((= (host-typeof target) "element")
|
((= (host-typeof target) "element")
|
||||||
(if (string? pattern) (host-call target "matches" pattern) false))
|
(if (string? pattern) (host-call target "matches" pattern) false))
|
||||||
(true false))))
|
(true false))))
|
||||||
;; Collection: sorted by
|
;; Collection: joined by
|
||||||
(define
|
(define
|
||||||
hs-contains?
|
hs-contains?
|
||||||
(fn
|
(fn
|
||||||
@@ -519,9 +547,9 @@
|
|||||||
true
|
true
|
||||||
(hs-contains? (rest collection) item)))))
|
(hs-contains? (rest collection) item)))))
|
||||||
(true false))))
|
(true false))))
|
||||||
;; Collection: sorted by descending
|
|
||||||
(define precedes? (fn (a b) (< (str a) (str b))))
|
(define precedes? (fn (a b) (< (str a) (str b))))
|
||||||
;; Collection: split by
|
|
||||||
(define
|
(define
|
||||||
hs-empty?
|
hs-empty?
|
||||||
(fn
|
(fn
|
||||||
@@ -532,7 +560,7 @@
|
|||||||
((list? v) (= (len v) 0))
|
((list? v) (= (len v) 0))
|
||||||
((dict? v) (= (len (keys v)) 0))
|
((dict? v) (= (len (keys v)) 0))
|
||||||
(true false))))
|
(true false))))
|
||||||
;; Collection: joined by
|
|
||||||
(define
|
(define
|
||||||
hs-empty-target!
|
hs-empty-target!
|
||||||
(fn
|
(fn
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
((= th (quote ref))
|
((= th (quote ref))
|
||||||
(list (quote set!) (make-symbol (nth target 1)) value))
|
(list (quote set!) (make-symbol (nth target 1)) value))
|
||||||
((= th (quote local))
|
((= th (quote local))
|
||||||
(list (quote set!) (make-symbol (nth target 1)) value))
|
(list (quote define) (make-symbol (nth target 1)) value))
|
||||||
((= th (quote me))
|
((= th (quote me))
|
||||||
(list (quote dom-set-inner-html) (quote me) value))
|
(list (quote dom-set-inner-html) (quote me) value))
|
||||||
((= th (quote it)) (list (quote set!) (quote it) value))
|
((= th (quote it)) (list (quote set!) (quote it) value))
|
||||||
@@ -912,6 +912,20 @@
|
|||||||
(nth ast 1)))))
|
(nth ast 1)))))
|
||||||
((= head (quote remove-element))
|
((= head (quote remove-element))
|
||||||
(list (quote dom-remove) (hs-to-sx (nth ast 1))))
|
(list (quote dom-remove) (hs-to-sx (nth ast 1))))
|
||||||
|
((= head (quote add-value))
|
||||||
|
(let
|
||||||
|
((val (hs-to-sx (nth ast 1))) (tgt (nth ast 2)))
|
||||||
|
(list
|
||||||
|
(quote set!)
|
||||||
|
(hs-to-sx tgt)
|
||||||
|
(list (quote hs-add-to!) val (hs-to-sx tgt)))))
|
||||||
|
((= head (quote remove-value))
|
||||||
|
(let
|
||||||
|
((val (hs-to-sx (nth ast 1))) (tgt (nth ast 2)))
|
||||||
|
(list
|
||||||
|
(quote set!)
|
||||||
|
(hs-to-sx tgt)
|
||||||
|
(list (quote hs-remove-from!) val (hs-to-sx tgt)))))
|
||||||
((= head (quote empty-target))
|
((= head (quote empty-target))
|
||||||
(list (quote hs-empty-target!) (hs-to-sx (nth ast 1))))
|
(list (quote hs-empty-target!) (hs-to-sx (nth ast 1))))
|
||||||
((= head (quote open-element))
|
((= head (quote open-element))
|
||||||
@@ -946,6 +960,28 @@
|
|||||||
(quote hs-toggle-class!)
|
(quote hs-toggle-class!)
|
||||||
(hs-to-sx (nth ast 2))
|
(hs-to-sx (nth ast 2))
|
||||||
(nth ast 1)))
|
(nth ast 1)))
|
||||||
|
((= head (quote toggle-class-for))
|
||||||
|
(list
|
||||||
|
(quote do)
|
||||||
|
(list
|
||||||
|
(quote hs-toggle-class!)
|
||||||
|
(hs-to-sx (nth ast 2))
|
||||||
|
(nth ast 1))
|
||||||
|
(list
|
||||||
|
(quote perform)
|
||||||
|
(list
|
||||||
|
(quote list)
|
||||||
|
(quote io-sleep)
|
||||||
|
(hs-to-sx (nth ast 3))))
|
||||||
|
(list
|
||||||
|
(quote hs-toggle-class!)
|
||||||
|
(hs-to-sx (nth ast 2))
|
||||||
|
(nth ast 1))))
|
||||||
|
((= head (quote set-on))
|
||||||
|
(list
|
||||||
|
(quote hs-set-on!)
|
||||||
|
(hs-to-sx (nth ast 1))
|
||||||
|
(hs-to-sx (nth ast 2))))
|
||||||
((= head (quote toggle-between))
|
((= head (quote toggle-between))
|
||||||
(list
|
(list
|
||||||
(quote hs-toggle-between!)
|
(quote hs-toggle-between!)
|
||||||
|
|||||||
@@ -283,6 +283,12 @@
|
|||||||
var-name
|
var-name
|
||||||
collection
|
collection
|
||||||
(parse-expr))))))))
|
(parse-expr))))))))
|
||||||
|
((and (= typ "keyword") (> (len tokens) (+ p 1)) (= (get (nth tokens (+ p 1)) "type") "paren-open"))
|
||||||
|
(do
|
||||||
|
(adv!)
|
||||||
|
(let
|
||||||
|
((name val) (args (parse-call-args)))
|
||||||
|
(list (quote call) (list (quote ref) name) args))))
|
||||||
(true nil)))))
|
(true nil)))))
|
||||||
(define
|
(define
|
||||||
parse-poss
|
parse-poss
|
||||||
@@ -805,7 +811,14 @@
|
|||||||
(cons
|
(cons
|
||||||
(quote multi-add-class)
|
(quote multi-add-class)
|
||||||
(cons tgt (cons cls extra-classes))))))))
|
(cons tgt (cons cls extra-classes))))))))
|
||||||
nil)))
|
(let
|
||||||
|
((value (parse-expr)))
|
||||||
|
(if
|
||||||
|
(match-kw "to")
|
||||||
|
(let
|
||||||
|
((tgt (parse-expr)))
|
||||||
|
(list (quote add-value) value tgt))
|
||||||
|
nil)))))
|
||||||
(define
|
(define
|
||||||
parse-remove-cmd
|
parse-remove-cmd
|
||||||
(fn
|
(fn
|
||||||
@@ -870,8 +883,13 @@
|
|||||||
(list (quote remove-css) props tgt)))))
|
(list (quote remove-css) props tgt)))))
|
||||||
(true
|
(true
|
||||||
(let
|
(let
|
||||||
((target (parse-expr)))
|
((value (parse-expr)))
|
||||||
(list (quote remove-element) target))))))
|
(if
|
||||||
|
(match-kw "from")
|
||||||
|
(let
|
||||||
|
((tgt (parse-expr)))
|
||||||
|
(list (quote remove-value) value tgt))
|
||||||
|
(list (quote remove-element) value)))))))
|
||||||
(define
|
(define
|
||||||
parse-toggle-cmd
|
parse-toggle-cmd
|
||||||
(fn
|
(fn
|
||||||
@@ -897,7 +915,12 @@
|
|||||||
((cls (do (let ((v (tp-val))) (adv!) v))))
|
((cls (do (let ((v (tp-val))) (adv!) v))))
|
||||||
(let
|
(let
|
||||||
((tgt (parse-tgt-kw "on" (list (quote me)))))
|
((tgt (parse-tgt-kw "on" (list (quote me)))))
|
||||||
(list (quote toggle-class) cls tgt))))
|
(if
|
||||||
|
(match-kw "for")
|
||||||
|
(let
|
||||||
|
((dur (parse-expr)))
|
||||||
|
(list (quote toggle-class-for) cls tgt dur))
|
||||||
|
(list (quote toggle-class) cls tgt)))))
|
||||||
((= (tp-type) "style")
|
((= (tp-type) "style")
|
||||||
(let
|
(let
|
||||||
((prop (do (let ((v (tp-val))) (adv!) v))))
|
((prop (do (let ((v (tp-val))) (adv!) v))))
|
||||||
@@ -1006,8 +1029,14 @@
|
|||||||
()
|
()
|
||||||
(let
|
(let
|
||||||
((tgt (parse-expr)))
|
((tgt (parse-expr)))
|
||||||
(expect-kw! "to")
|
(cond
|
||||||
(let ((value (parse-expr))) (list (quote set!) tgt value)))))
|
((match-kw "to")
|
||||||
|
(let ((value (parse-expr))) (list (quote set!) tgt value)))
|
||||||
|
((match-kw "on")
|
||||||
|
(let
|
||||||
|
((target (parse-expr)))
|
||||||
|
(list (quote set-on) tgt target)))
|
||||||
|
(true (error (str "Expected to/on at position " p)))))))
|
||||||
(define
|
(define
|
||||||
parse-put-cmd
|
parse-put-cmd
|
||||||
(fn
|
(fn
|
||||||
@@ -1244,7 +1273,7 @@
|
|||||||
(let
|
(let
|
||||||
((body (parse-cmd-list)))
|
((body (parse-cmd-list)))
|
||||||
(match-kw "end")
|
(match-kw "end")
|
||||||
(list (quote for) "it" collection nil body)))))
|
(list (quote for) "it" collection body)))))
|
||||||
(true
|
(true
|
||||||
(let
|
(let
|
||||||
((mode (cond ((match-kw "forever") (list (quote forever))) ((match-kw "while") (list (quote while) (parse-expr))) ((match-kw "until") (list (quote until) (parse-expr))) (true (let ((n (parse-expr))) (if (match-kw "times") (list (quote times) n) (list (quote forever))))))))
|
((mode (cond ((match-kw "forever") (list (quote forever))) ((match-kw "while") (list (quote while) (parse-expr))) ((match-kw "until") (list (quote until) (parse-expr))) (true (let ((n (parse-expr))) (if (match-kw "times") (list (quote times) n) (list (quote forever))))))))
|
||||||
@@ -1464,10 +1493,12 @@
|
|||||||
()
|
()
|
||||||
(let
|
(let
|
||||||
((value (parse-expr)))
|
((value (parse-expr)))
|
||||||
(expect-kw! "to")
|
(if
|
||||||
(let
|
(match-kw "to")
|
||||||
((target (parse-expr)))
|
(let
|
||||||
(list (quote append!) value target)))))
|
((target (parse-expr)))
|
||||||
|
(list (quote append!) value target))
|
||||||
|
(list (quote append!) value (list (quote it)))))))
|
||||||
(define
|
(define
|
||||||
parse-tell-cmd
|
parse-tell-cmd
|
||||||
(fn
|
(fn
|
||||||
|
|||||||
@@ -136,9 +136,35 @@
|
|||||||
((= pos "end") (dom-insert-adjacent-html target "beforeend" value)))))
|
((= pos "end") (dom-insert-adjacent-html target "beforeend" value)))))
|
||||||
|
|
||||||
;; Find previous sibling matching a selector.
|
;; Find previous sibling matching a selector.
|
||||||
(define hs-navigate! (fn (url) (perform (list (quote io-navigate) url))))
|
(define
|
||||||
|
hs-add-to!
|
||||||
|
(fn
|
||||||
|
(value target)
|
||||||
|
(if
|
||||||
|
(list? target)
|
||||||
|
(append target (list value))
|
||||||
|
(host-call target "push" value))))
|
||||||
|
|
||||||
;; First element matching selector within a scope.
|
;; First element matching selector within a scope.
|
||||||
|
(define
|
||||||
|
hs-remove-from!
|
||||||
|
(fn
|
||||||
|
(value target)
|
||||||
|
(if
|
||||||
|
(list? target)
|
||||||
|
(filter (fn (x) (not (= x value))) target)
|
||||||
|
(host-call target "splice" (host-call target "indexOf" value) 1))))
|
||||||
|
|
||||||
|
;; Last element matching selector.
|
||||||
|
(define
|
||||||
|
hs-set-on!
|
||||||
|
(fn
|
||||||
|
(props target)
|
||||||
|
(for-each (fn (k) (host-set! target k (get props k))) (keys props))))
|
||||||
|
|
||||||
|
;; First/last within a specific scope.
|
||||||
|
(define hs-navigate! (fn (url) (perform (list (quote io-navigate) url))))
|
||||||
|
|
||||||
(define
|
(define
|
||||||
hs-scroll!
|
hs-scroll!
|
||||||
(fn
|
(fn
|
||||||
@@ -151,7 +177,9 @@
|
|||||||
((= position "bottom") (dict :block "end"))
|
((= position "bottom") (dict :block "end"))
|
||||||
(true (dict :block "start")))))))
|
(true (dict :block "start")))))))
|
||||||
|
|
||||||
;; Last element matching selector.
|
;; ── Iteration ───────────────────────────────────────────────────
|
||||||
|
|
||||||
|
;; Repeat a thunk N times.
|
||||||
(define
|
(define
|
||||||
hs-halt!
|
hs-halt!
|
||||||
(fn
|
(fn
|
||||||
@@ -161,14 +189,19 @@
|
|||||||
(host-call event "preventDefault" (list))
|
(host-call event "preventDefault" (list))
|
||||||
(when (= mode "event") (host-call event "stopPropagation" (list))))))
|
(when (= mode "event") (host-call event "stopPropagation" (list))))))
|
||||||
|
|
||||||
;; First/last within a specific scope.
|
;; Repeat forever (until break — relies on exception/continuation).
|
||||||
(define hs-select! (fn (target) (host-call target "select" (list))))
|
(define hs-select! (fn (target) (host-call target "select" (list))))
|
||||||
|
|
||||||
|
;; ── Fetch ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
;; Fetch a URL, parse response according to format.
|
||||||
|
;; (hs-fetch url format) — format is "json" | "text" | "html"
|
||||||
(define hs-reset! (fn (target) (host-call target "reset" (list))))
|
(define hs-reset! (fn (target) (host-call target "reset" (list))))
|
||||||
|
|
||||||
;; ── Iteration ───────────────────────────────────────────────────
|
;; ── Type coercion ───────────────────────────────────────────────
|
||||||
|
|
||||||
;; Repeat a thunk N times.
|
;; Coerce a value to a type by name.
|
||||||
|
;; (hs-coerce value type-name) — type-name is "Int", "Float", "String", etc.
|
||||||
(define
|
(define
|
||||||
hs-next
|
hs-next
|
||||||
(fn
|
(fn
|
||||||
@@ -188,7 +221,10 @@
|
|||||||
(true (find-next (dom-next-sibling el))))))
|
(true (find-next (dom-next-sibling el))))))
|
||||||
(find-next sibling)))))
|
(find-next sibling)))))
|
||||||
|
|
||||||
;; Repeat forever (until break — relies on exception/continuation).
|
;; ── Object creation ─────────────────────────────────────────────
|
||||||
|
|
||||||
|
;; Make a new object of a given type.
|
||||||
|
;; (hs-make type-name) — creates empty object/collection
|
||||||
(define
|
(define
|
||||||
hs-previous
|
hs-previous
|
||||||
(fn
|
(fn
|
||||||
@@ -208,26 +244,27 @@
|
|||||||
(true (find-prev (dom-get-prop el "previousElementSibling"))))))
|
(true (find-prev (dom-get-prop el "previousElementSibling"))))))
|
||||||
(find-prev sibling)))))
|
(find-prev sibling)))))
|
||||||
|
|
||||||
;; ── Fetch ───────────────────────────────────────────────────────
|
;; ── Behavior installation ───────────────────────────────────────
|
||||||
|
|
||||||
;; Fetch a URL, parse response according to format.
|
;; Install a behavior on an element.
|
||||||
;; (hs-fetch url format) — format is "json" | "text" | "html"
|
;; A behavior is a function that takes (me ...params) and sets up features.
|
||||||
|
;; (hs-install behavior-fn me ...args)
|
||||||
(define
|
(define
|
||||||
hs-query-all
|
hs-query-all
|
||||||
(fn (sel) (host-call (dom-body) "querySelectorAll" sel)))
|
(fn (sel) (host-call (dom-body) "querySelectorAll" sel)))
|
||||||
|
|
||||||
;; ── Type coercion ───────────────────────────────────────────────
|
;; ── Measurement ─────────────────────────────────────────────────
|
||||||
|
|
||||||
;; Coerce a value to a type by name.
|
;; Measure an element's bounding rect, store as local variables.
|
||||||
;; (hs-coerce value type-name) — type-name is "Int", "Float", "String", etc.
|
;; Returns a dict with x, y, width, height, top, left, right, bottom.
|
||||||
(define
|
(define
|
||||||
hs-query-first
|
hs-query-first
|
||||||
(fn (sel) (host-call (host-global "document") "querySelector" sel)))
|
(fn (sel) (host-call (host-global "document") "querySelector" sel)))
|
||||||
|
|
||||||
;; ── Object creation ─────────────────────────────────────────────
|
;; ── Transition ──────────────────────────────────────────────────
|
||||||
|
|
||||||
;; Make a new object of a given type.
|
;; Transition a CSS property to a value, optionally with duration.
|
||||||
;; (hs-make type-name) — creates empty object/collection
|
;; (hs-transition target prop value duration)
|
||||||
(define
|
(define
|
||||||
hs-query-last
|
hs-query-last
|
||||||
(fn
|
(fn
|
||||||
@@ -236,17 +273,8 @@
|
|||||||
((all (dom-query-all (dom-body) sel)))
|
((all (dom-query-all (dom-body) sel)))
|
||||||
(if (> (len all) 0) (nth all (- (len all) 1)) nil))))
|
(if (> (len all) 0) (nth all (- (len all) 1)) nil))))
|
||||||
|
|
||||||
;; ── Behavior installation ───────────────────────────────────────
|
|
||||||
|
|
||||||
;; Install a behavior on an element.
|
|
||||||
;; A behavior is a function that takes (me ...params) and sets up features.
|
|
||||||
;; (hs-install behavior-fn me ...args)
|
|
||||||
(define hs-first (fn (scope sel) (dom-query-all scope sel)))
|
(define hs-first (fn (scope sel) (dom-query-all scope sel)))
|
||||||
|
|
||||||
;; ── Measurement ─────────────────────────────────────────────────
|
|
||||||
|
|
||||||
;; Measure an element's bounding rect, store as local variables.
|
|
||||||
;; Returns a dict with x, y, width, height, top, left, right, bottom.
|
|
||||||
(define
|
(define
|
||||||
hs-last
|
hs-last
|
||||||
(fn
|
(fn
|
||||||
@@ -255,10 +283,6 @@
|
|||||||
((all (dom-query-all scope sel)))
|
((all (dom-query-all scope sel)))
|
||||||
(if (> (len all) 0) (nth all (- (len all) 1)) nil))))
|
(if (> (len all) 0) (nth all (- (len all) 1)) nil))))
|
||||||
|
|
||||||
;; ── Transition ──────────────────────────────────────────────────
|
|
||||||
|
|
||||||
;; Transition a CSS property to a value, optionally with duration.
|
|
||||||
;; (hs-transition target prop value duration)
|
|
||||||
(define
|
(define
|
||||||
hs-repeat-times
|
hs-repeat-times
|
||||||
(fn
|
(fn
|
||||||
@@ -296,7 +320,11 @@
|
|||||||
((= type-name "Integer") (floor (+ value 0)))
|
((= type-name "Integer") (floor (+ value 0)))
|
||||||
((= type-name "Float") (+ value 0))
|
((= type-name "Float") (+ value 0))
|
||||||
((= type-name "Number") (+ value 0))
|
((= type-name "Number") (+ value 0))
|
||||||
((= type-name "String") (str value))
|
((= type-name "String")
|
||||||
|
(if
|
||||||
|
(list? value)
|
||||||
|
(join "," (map (fn (x) (str x)) value))
|
||||||
|
(str value)))
|
||||||
((= type-name "Bool") (not (hs-falsy? value)))
|
((= type-name "Bool") (not (hs-falsy? value)))
|
||||||
((= type-name "Boolean") (not (hs-falsy? value)))
|
((= type-name "Boolean") (not (hs-falsy? value)))
|
||||||
((= type-name "Array") (if (list? value) value (list value)))
|
((= type-name "Array") (if (list? value) value (list value)))
|
||||||
@@ -395,6 +423,10 @@
|
|||||||
|
|
||||||
(define hs-install (fn (behavior-fn) (behavior-fn me)))
|
(define hs-install (fn (behavior-fn) (behavior-fn me)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(define
|
(define
|
||||||
hs-measure
|
hs-measure
|
||||||
(fn (target) (perform (list (quote io-measure) target))))
|
(fn (target) (perform (list (quote io-measure) target))))
|
||||||
@@ -411,7 +443,8 @@
|
|||||||
(str prop " " (/ duration 1000) "s")))
|
(str prop " " (/ duration 1000) "s")))
|
||||||
(dom-set-style target prop value)
|
(dom-set-style target prop value)
|
||||||
(when duration (hs-settle target))))
|
(when duration (hs-settle target))))
|
||||||
|
;; ── Sandbox/test runtime additions ──────────────────────────────
|
||||||
|
;; Property access — dot notation and .length
|
||||||
(define
|
(define
|
||||||
hs-transition-from
|
hs-transition-from
|
||||||
(fn
|
(fn
|
||||||
@@ -425,11 +458,7 @@
|
|||||||
(str prop " " (/ duration 1000) "s")))
|
(str prop " " (/ duration 1000) "s")))
|
||||||
(dom-set-style target prop (str to-val))
|
(dom-set-style target prop (str to-val))
|
||||||
(when duration (hs-settle target))))
|
(when duration (hs-settle target))))
|
||||||
|
;; DOM query stub — sandbox returns empty list
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(define
|
(define
|
||||||
hs-type-check
|
hs-type-check
|
||||||
(fn
|
(fn
|
||||||
@@ -449,34 +478,33 @@
|
|||||||
(= (host-typeof value) "element")
|
(= (host-typeof value) "element")
|
||||||
(= (host-typeof value) "text")))
|
(= (host-typeof value) "text")))
|
||||||
(true (= (host-typeof value) (downcase type-name)))))))
|
(true (= (host-typeof value) (downcase type-name)))))))
|
||||||
|
;; Method dispatch — obj.method(args)
|
||||||
(define
|
(define
|
||||||
hs-type-check-strict
|
hs-type-check-strict
|
||||||
(fn
|
(fn
|
||||||
(value type-name)
|
(value type-name)
|
||||||
(if (nil? value) false (hs-type-check value type-name))))
|
(if (nil? value) false (hs-type-check value type-name))))
|
||||||
;; ── Sandbox/test runtime additions ──────────────────────────────
|
|
||||||
;; Property access — dot notation and .length
|
|
||||||
(define
|
|
||||||
hs-strict-eq
|
|
||||||
(fn (a b) (and (= (type-of a) (type-of b)) (= a b))))
|
|
||||||
;; DOM query stub — sandbox returns empty list
|
|
||||||
(define
|
|
||||||
hs-eq-ignore-case
|
|
||||||
(fn (a b) (= (downcase (str a)) (downcase (str b)))))
|
|
||||||
;; Method dispatch — obj.method(args)
|
|
||||||
(define
|
|
||||||
hs-starts-with-ic?
|
|
||||||
(fn (str prefix) (starts-with? (downcase str) (downcase prefix))))
|
|
||||||
|
|
||||||
;; ── 0.9.90 features ─────────────────────────────────────────────
|
;; ── 0.9.90 features ─────────────────────────────────────────────
|
||||||
;; beep! — debug logging, returns value unchanged
|
;; beep! — debug logging, returns value unchanged
|
||||||
|
(define
|
||||||
|
hs-strict-eq
|
||||||
|
(fn (a b) (and (= (type-of a) (type-of b)) (= a b))))
|
||||||
|
;; Property-based is — check obj.key truthiness
|
||||||
|
(define
|
||||||
|
hs-eq-ignore-case
|
||||||
|
(fn (a b) (= (downcase (str a)) (downcase (str b)))))
|
||||||
|
;; Array slicing (inclusive both ends)
|
||||||
|
(define
|
||||||
|
hs-starts-with-ic?
|
||||||
|
(fn (str prefix) (starts-with? (downcase str) (downcase prefix))))
|
||||||
|
;; Collection: sorted by
|
||||||
(define
|
(define
|
||||||
hs-contains-ignore-case?
|
hs-contains-ignore-case?
|
||||||
(fn
|
(fn
|
||||||
(haystack needle)
|
(haystack needle)
|
||||||
(contains? (downcase (str haystack)) (downcase (str needle)))))
|
(contains? (downcase (str haystack)) (downcase (str needle)))))
|
||||||
;; Property-based is — check obj.key truthiness
|
;; Collection: sorted by descending
|
||||||
(define
|
(define
|
||||||
hs-falsy?
|
hs-falsy?
|
||||||
(fn
|
(fn
|
||||||
@@ -488,7 +516,7 @@
|
|||||||
((and (list? v) (= (len v) 0)) true)
|
((and (list? v) (= (len v) 0)) true)
|
||||||
((= v 0) true)
|
((= v 0) true)
|
||||||
(true false))))
|
(true false))))
|
||||||
;; Array slicing (inclusive both ends)
|
;; Collection: split by
|
||||||
(define
|
(define
|
||||||
hs-matches?
|
hs-matches?
|
||||||
(fn
|
(fn
|
||||||
@@ -499,7 +527,7 @@
|
|||||||
((= (host-typeof target) "element")
|
((= (host-typeof target) "element")
|
||||||
(if (string? pattern) (host-call target "matches" pattern) false))
|
(if (string? pattern) (host-call target "matches" pattern) false))
|
||||||
(true false))))
|
(true false))))
|
||||||
;; Collection: sorted by
|
;; Collection: joined by
|
||||||
(define
|
(define
|
||||||
hs-contains?
|
hs-contains?
|
||||||
(fn
|
(fn
|
||||||
@@ -519,9 +547,9 @@
|
|||||||
true
|
true
|
||||||
(hs-contains? (rest collection) item)))))
|
(hs-contains? (rest collection) item)))))
|
||||||
(true false))))
|
(true false))))
|
||||||
;; Collection: sorted by descending
|
|
||||||
(define precedes? (fn (a b) (< (str a) (str b))))
|
(define precedes? (fn (a b) (< (str a) (str b))))
|
||||||
;; Collection: split by
|
|
||||||
(define
|
(define
|
||||||
hs-empty?
|
hs-empty?
|
||||||
(fn
|
(fn
|
||||||
@@ -532,7 +560,7 @@
|
|||||||
((list? v) (= (len v) 0))
|
((list? v) (= (len v) 0))
|
||||||
((dict? v) (= (len (keys v)) 0))
|
((dict? v) (= (len (keys v)) 0))
|
||||||
(true false))))
|
(true false))))
|
||||||
;; Collection: joined by
|
|
||||||
(define
|
(define
|
||||||
hs-empty-target!
|
hs-empty-target!
|
||||||
(fn
|
(fn
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user