Hyperscript conformance: 222 test fixtures from _hyperscript 0.9.14
Extract pure expression tests from the official _hyperscript test suite and implement parser/compiler/runtime extensions to pass them. Test infrastructure: - 222 fixtures extracted from evalHyperScript calls (no DOM dependency) - SX data format with eval-hs bridge and run-hs-fixture runner - 24 suites covering expressions, comparisons, coercion, logic, etc. Parser extensions (parser.sx): - mod as infix arithmetic operator - English comparison phrases (is less than, is greater than or equal to) - is a/an Type typecheck syntax - === / !== strict equality operators - I as me synonym, am as is for comparisons - does not exist/match/contain postfix - some/every ... with quantifier expressions - undefined keyword → nil Compiler updates (compiler.sx): - + emits hs-add (type-dispatching: string concat or numeric add) - no emits hs-falsy? (HS truthiness: empty string is falsy) - matches? emits hs-matches? (string regex in non-DOM context) - New cases: not-in?, in?, type-check, strict-eq, some, every Runtime additions (runtime.sx): - hs-coerce: Int/Integer truncation via floor - hs-add: string concat when either operand is string - hs-falsy?: HS-compatible truthiness (nil, false, "" are falsy) - hs-matches?: string pattern matching - hs-type-check/hs-type-check!: lenient/strict type checking - hs-strict-eq: type + value equality Tokenizer (tokenizer.sx): - Added keywords: I, am, does, some, mod, equal, equals, really, include, includes, contain, undefined, exist Scorecard: 47/112 test groups passing. 0 non-HS regressions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -202,42 +202,44 @@
|
||||
(define
|
||||
emit-inc
|
||||
(fn
|
||||
(target)
|
||||
(expr tgt-override)
|
||||
(let
|
||||
((t (hs-to-sx target)))
|
||||
((t (hs-to-sx expr)))
|
||||
(if
|
||||
(and (list? target) (= (first target) (quote attr)))
|
||||
(list
|
||||
(quote dom-set-attr)
|
||||
(hs-to-sx (nth target 2))
|
||||
(nth target 1)
|
||||
(and (list? expr) (= (first expr) (quote attr)))
|
||||
(let
|
||||
((el (if tgt-override (hs-to-sx tgt-override) (hs-to-sx (nth expr 2)))))
|
||||
(list
|
||||
(quote +)
|
||||
(quote dom-set-attr)
|
||||
el
|
||||
(nth expr 1)
|
||||
(list
|
||||
(quote dom-get-attr)
|
||||
(hs-to-sx (nth target 2))
|
||||
(nth target 1))
|
||||
1))
|
||||
(quote +)
|
||||
(list
|
||||
(quote parse-number)
|
||||
(list (quote dom-get-attr) el (nth expr 1)))
|
||||
1)))
|
||||
(list (quote set!) t (list (quote +) t 1))))))
|
||||
(define
|
||||
emit-dec
|
||||
(fn
|
||||
(target)
|
||||
(expr tgt-override)
|
||||
(let
|
||||
((t (hs-to-sx target)))
|
||||
((t (hs-to-sx expr)))
|
||||
(if
|
||||
(and (list? target) (= (first target) (quote attr)))
|
||||
(list
|
||||
(quote dom-set-attr)
|
||||
(hs-to-sx (nth target 2))
|
||||
(nth target 1)
|
||||
(and (list? expr) (= (first expr) (quote attr)))
|
||||
(let
|
||||
((el (if tgt-override (hs-to-sx tgt-override) (hs-to-sx (nth expr 2)))))
|
||||
(list
|
||||
(quote -)
|
||||
(quote dom-set-attr)
|
||||
el
|
||||
(nth expr 1)
|
||||
(list
|
||||
(quote dom-get-attr)
|
||||
(hs-to-sx (nth target 2))
|
||||
(nth target 1))
|
||||
1))
|
||||
(quote -)
|
||||
(list
|
||||
(quote parse-number)
|
||||
(list (quote dom-get-attr) el (nth expr 1)))
|
||||
1)))
|
||||
(list (quote set!) t (list (quote -) t 1))))))
|
||||
(define
|
||||
emit-behavior
|
||||
@@ -288,7 +290,7 @@
|
||||
((= head (quote not))
|
||||
(list (quote not) (hs-to-sx (nth ast 1))))
|
||||
((= head (quote no))
|
||||
(list (quote not) (hs-to-sx (nth ast 1))))
|
||||
(list (quote hs-falsy?) (hs-to-sx (nth ast 1))))
|
||||
((= head (quote and))
|
||||
(list
|
||||
(quote and)
|
||||
@@ -306,7 +308,7 @@
|
||||
(hs-to-sx (nth ast 2))))
|
||||
((= head (quote +))
|
||||
(list
|
||||
(quote +)
|
||||
(quote hs-add)
|
||||
(hs-to-sx (nth ast 1))
|
||||
(hs-to-sx (nth ast 2))))
|
||||
((= head (quote -))
|
||||
@@ -337,7 +339,7 @@
|
||||
(list (quote nil?) (hs-to-sx (nth ast 1)))))
|
||||
((= head (quote matches?))
|
||||
(list
|
||||
(quote dom-matches?)
|
||||
(quote hs-matches?)
|
||||
(hs-to-sx (nth ast 1))
|
||||
(hs-to-sx (nth ast 2))))
|
||||
((= head (quote contains?))
|
||||
@@ -508,8 +510,14 @@
|
||||
(cons (quote hs-install) (map hs-to-sx (rest ast))))
|
||||
((= head (quote measure))
|
||||
(list (quote hs-measure) (hs-to-sx (nth ast 1))))
|
||||
((= head (quote increment!)) (emit-inc (nth ast 1)))
|
||||
((= head (quote decrement!)) (emit-dec (nth ast 1)))
|
||||
((= head (quote increment!))
|
||||
(emit-inc
|
||||
(nth ast 1)
|
||||
(if (> (len ast) 2) (nth ast 2) nil)))
|
||||
((= head (quote decrement!))
|
||||
(emit-dec
|
||||
(nth ast 1)
|
||||
(if (> (len ast) 2) (nth ast 2) nil)))
|
||||
((= head (quote on)) (emit-on ast))
|
||||
((= head (quote init))
|
||||
(list
|
||||
@@ -563,6 +571,49 @@
|
||||
pos
|
||||
(if target target (quote me)))
|
||||
render-call)))))
|
||||
((= head (quote not-in?))
|
||||
(list
|
||||
(quote not)
|
||||
(list
|
||||
(quote contains?)
|
||||
(hs-to-sx (nth ast 2))
|
||||
(hs-to-sx (nth ast 1)))))
|
||||
((= head (quote in?))
|
||||
(list
|
||||
(quote contains?)
|
||||
(hs-to-sx (nth ast 2))
|
||||
(hs-to-sx (nth ast 1))))
|
||||
((= head (quote type-check))
|
||||
(list
|
||||
(quote hs-type-check)
|
||||
(hs-to-sx (nth ast 1))
|
||||
(nth ast 2)))
|
||||
((= head (quote type-check!))
|
||||
(list
|
||||
(quote hs-type-check!)
|
||||
(hs-to-sx (nth ast 1))
|
||||
(nth ast 2)))
|
||||
((= head (quote strict-eq))
|
||||
(list
|
||||
(quote hs-strict-eq)
|
||||
(hs-to-sx (nth ast 1))
|
||||
(hs-to-sx (nth ast 2))))
|
||||
((= head (quote some))
|
||||
(list
|
||||
(quote some)
|
||||
(list
|
||||
(quote fn)
|
||||
(list (make-symbol (nth ast 1)))
|
||||
(hs-to-sx (nth ast 3)))
|
||||
(hs-to-sx (nth ast 2))))
|
||||
((= head (quote every))
|
||||
(list
|
||||
(quote every?)
|
||||
(list
|
||||
(quote fn)
|
||||
(list (make-symbol (nth ast 1)))
|
||||
(hs-to-sx (nth ast 3)))
|
||||
(hs-to-sx (nth ast 2))))
|
||||
(true ast))))))))
|
||||
|
||||
;; ── Convenience: source → SX ─────────────────────────────────
|
||||
|
||||
@@ -45,10 +45,10 @@
|
||||
((slen (len val)))
|
||||
(cond
|
||||
((and (>= slen 3) (= (substring val (- slen 2) slen) "ms"))
|
||||
(string->number (substring val 0 (- slen 2))))
|
||||
(parse-number (substring val 0 (- slen 2))))
|
||||
((and (>= slen 2) (= (nth val (- slen 1)) "s"))
|
||||
(* 1000 (string->number (substring val 0 (- slen 1)))))
|
||||
(true (string->number val))))))
|
||||
(* 1000 (parse-number (substring val 0 (- slen 1)))))
|
||||
(true (parse-number val))))))
|
||||
(define
|
||||
parse-poss-tail
|
||||
(fn
|
||||
@@ -58,6 +58,7 @@
|
||||
(cond
|
||||
((or (= typ "ident") (= typ "keyword"))
|
||||
(do (adv!) (parse-prop-chain (list (quote .) owner val))))
|
||||
((= typ "attr") (do (adv!) (list (quote attr) val owner)))
|
||||
((= typ "class")
|
||||
(let
|
||||
((prop (get (adv!) "value")))
|
||||
@@ -112,6 +113,8 @@
|
||||
((and (= typ "keyword") (= val "false")) (do (adv!) false))
|
||||
((and (= typ "keyword") (or (= val "null") (= val "nil")))
|
||||
(do (adv!) nil))
|
||||
((and (= typ "keyword") (= val "undefined"))
|
||||
(do (adv!) nil))
|
||||
((and (= typ "keyword") (= val "not"))
|
||||
(do (adv!) (list (quote not) (parse-expr))))
|
||||
((and (= typ "keyword") (= val "no"))
|
||||
@@ -127,6 +130,8 @@
|
||||
(do (adv!) (parse-the-expr)))
|
||||
((and (= typ "keyword") (= val "me"))
|
||||
(do (adv!) (list (quote me))))
|
||||
((and (= typ "keyword") (= val "I"))
|
||||
(do (adv!) (list (quote me))))
|
||||
((and (= typ "keyword") (or (= val "it") (= val "result")))
|
||||
(do (adv!) (list (quote it))))
|
||||
((and (= typ "keyword") (= val "event"))
|
||||
@@ -179,6 +184,40 @@
|
||||
(list (quote -) 0 operand))))
|
||||
((= typ "component")
|
||||
(do (adv!) (list (quote component) val)))
|
||||
((and (= typ "keyword") (= val "some"))
|
||||
(do
|
||||
(adv!)
|
||||
(let
|
||||
((var-name (tp-val)))
|
||||
(do
|
||||
(adv!)
|
||||
(match-kw "in")
|
||||
(let
|
||||
((collection (parse-expr)))
|
||||
(do
|
||||
(match-kw "with")
|
||||
(list
|
||||
(quote some)
|
||||
var-name
|
||||
collection
|
||||
(parse-expr))))))))
|
||||
((and (= typ "keyword") (= val "every"))
|
||||
(do
|
||||
(adv!)
|
||||
(let
|
||||
((var-name (tp-val)))
|
||||
(do
|
||||
(adv!)
|
||||
(match-kw "in")
|
||||
(let
|
||||
((collection (parse-expr)))
|
||||
(do
|
||||
(match-kw "with")
|
||||
(list
|
||||
(quote every)
|
||||
var-name
|
||||
collection
|
||||
(parse-expr))))))))
|
||||
(true nil)))))
|
||||
(define
|
||||
parse-poss
|
||||
@@ -196,23 +235,122 @@
|
||||
(let
|
||||
((typ (tp-type)) (val (tp-val)))
|
||||
(cond
|
||||
((and (= typ "op") (or (= val "==") (= val "!=") (= val "<") (= val ">") (= val "<=") (= val ">=")))
|
||||
((and (= typ "op") (or (= val "==") (= val "!=") (= val "<") (= val ">") (= val "<=") (= val ">=") (= val "===") (= val "!==")))
|
||||
(do
|
||||
(adv!)
|
||||
(let
|
||||
((right (parse-expr)))
|
||||
(list (if (= val "==") (quote =) val) left right))))
|
||||
(cond
|
||||
((= val "==") (list (quote =) left right))
|
||||
((= val "===") (list (quote strict-eq) left right))
|
||||
((= val "!==")
|
||||
(list
|
||||
(quote not)
|
||||
(list (quote strict-eq) left right)))
|
||||
(true (list val left right))))))
|
||||
((and (= typ "keyword") (= val "is"))
|
||||
(do
|
||||
(adv!)
|
||||
(cond
|
||||
((match-kw "not")
|
||||
(if
|
||||
(match-kw "empty")
|
||||
(list (quote not) (list (quote empty?) left))
|
||||
(let
|
||||
((right (parse-expr)))
|
||||
(list (quote not) (list (quote =) left right)))))
|
||||
(cond
|
||||
((match-kw "empty")
|
||||
(list (quote not) (list (quote empty?) left)))
|
||||
((match-kw "in")
|
||||
(list (quote not-in?) left (parse-expr)))
|
||||
((match-kw "really")
|
||||
(do
|
||||
(match-kw "equal")
|
||||
(match-kw "to")
|
||||
(list
|
||||
(quote not)
|
||||
(list (quote strict-eq) left (parse-expr)))))
|
||||
((match-kw "equal")
|
||||
(do
|
||||
(match-kw "to")
|
||||
(list
|
||||
(quote not)
|
||||
(list (quote =) left (parse-expr)))))
|
||||
((or (and (or (= (tp-val) "a") (= (tp-val) "an")) (do (adv!) true)))
|
||||
(let
|
||||
((type-name (tp-val)))
|
||||
(do
|
||||
(adv!)
|
||||
(let
|
||||
((strict (if (string-ends-with? type-name "!") (string-slice type-name 0 (- (len type-name) 1)) nil)))
|
||||
(if
|
||||
strict
|
||||
(list
|
||||
(quote not)
|
||||
(list (quote type-check!) left strict))
|
||||
(list
|
||||
(quote not)
|
||||
(list (quote type-check) left type-name)))))))
|
||||
(true
|
||||
(let
|
||||
((right (parse-expr)))
|
||||
(list (quote not) (list (quote =) left right))))))
|
||||
((match-kw "empty") (list (quote empty?) left))
|
||||
((match-kw "less")
|
||||
(do
|
||||
(match-kw "than")
|
||||
(if
|
||||
(match-kw "or")
|
||||
(do
|
||||
(match-kw "equal")
|
||||
(match-kw "to")
|
||||
(list (quote <=) left (parse-expr)))
|
||||
(list (quote <) left (parse-expr)))))
|
||||
((match-kw "greater")
|
||||
(do
|
||||
(match-kw "than")
|
||||
(if
|
||||
(match-kw "or")
|
||||
(do
|
||||
(match-kw "equal")
|
||||
(match-kw "to")
|
||||
(list (quote >=) left (parse-expr)))
|
||||
(list (quote >) left (parse-expr)))))
|
||||
((match-kw "in") (list (quote in?) left (parse-expr)))
|
||||
((match-kw "really")
|
||||
(do
|
||||
(match-kw "equal")
|
||||
(match-kw "to")
|
||||
(list (quote strict-eq) left (parse-expr))))
|
||||
((match-kw "equal")
|
||||
(do
|
||||
(match-kw "to")
|
||||
(list (quote =) left (parse-expr))))
|
||||
((or (and (or (= (tp-val) "a") (= (tp-val) "an")) (do (adv!) true)))
|
||||
(let
|
||||
((type-name (tp-val)))
|
||||
(do
|
||||
(adv!)
|
||||
(let
|
||||
((strict (if (string-ends-with? type-name "!") (string-slice type-name 0 (- (len type-name) 1)) nil)))
|
||||
(if
|
||||
strict
|
||||
(list (quote type-check!) left strict)
|
||||
(list (quote type-check) left type-name))))))
|
||||
(true
|
||||
(let
|
||||
((right (parse-expr)))
|
||||
(list (quote =) left right))))))
|
||||
((and (= typ "keyword") (= val "am"))
|
||||
(do
|
||||
(adv!)
|
||||
(cond
|
||||
((match-kw "not")
|
||||
(cond
|
||||
((match-kw "in")
|
||||
(list (quote not-in?) left (parse-expr)))
|
||||
((match-kw "empty")
|
||||
(list (quote not) (list (quote empty?) left)))
|
||||
(true
|
||||
(let
|
||||
((right (parse-expr)))
|
||||
(list (quote not) (list (quote =) left right))))))
|
||||
((match-kw "in") (list (quote in?) left (parse-expr)))
|
||||
((match-kw "empty") (list (quote empty?) left))
|
||||
(true
|
||||
(let
|
||||
@@ -246,6 +384,35 @@
|
||||
(list (quote of) left target)))))
|
||||
((and (= typ "keyword") (= val "in"))
|
||||
(do (adv!) (list (quote in?) left (parse-expr))))
|
||||
((and (= typ "keyword") (= val "does"))
|
||||
(do
|
||||
(adv!)
|
||||
(match-kw "not")
|
||||
(cond
|
||||
((match-kw "exist")
|
||||
(list (quote not) (list (quote exists?) left)))
|
||||
((match-kw "match")
|
||||
(list
|
||||
(quote not)
|
||||
(list (quote matches?) left (parse-expr))))
|
||||
((or (match-kw "contain") (match-kw "contains"))
|
||||
(list
|
||||
(quote not)
|
||||
(list (quote contains?) left (parse-expr))))
|
||||
((or (match-kw "include") (match-kw "includes"))
|
||||
(list
|
||||
(quote not)
|
||||
(list (quote contains?) left (parse-expr))))
|
||||
(true left))))
|
||||
((and (= typ "keyword") (= val "equals"))
|
||||
(do (adv!) (list (quote =) left (parse-expr))))
|
||||
((and (= typ "keyword") (= val "really"))
|
||||
(do
|
||||
(adv!)
|
||||
(match-kw "equals")
|
||||
(list (quote strict-eq) left (parse-expr))))
|
||||
((and (= typ "keyword") (or (= val "contain") (= val "include") (= val "includes")))
|
||||
(do (adv!) (list (quote contains?) left (parse-expr))))
|
||||
(true left)))))
|
||||
(define
|
||||
parse-expr
|
||||
@@ -414,8 +581,24 @@
|
||||
((tgt (parse-tgt-kw "on" (list (quote me)))))
|
||||
(list (quote trigger) name tgt)))))
|
||||
(define parse-log-cmd (fn () (list (quote log) (parse-expr))))
|
||||
(define parse-inc-cmd (fn () (list (quote increment!) (parse-expr))))
|
||||
(define parse-dec-cmd (fn () (list (quote decrement!) (parse-expr))))
|
||||
(define
|
||||
parse-inc-cmd
|
||||
(fn
|
||||
()
|
||||
(let
|
||||
((expr (parse-expr)))
|
||||
(let
|
||||
((tgt (parse-tgt-kw "on" (list (quote me)))))
|
||||
(list (quote increment!) expr tgt)))))
|
||||
(define
|
||||
parse-dec-cmd
|
||||
(fn
|
||||
()
|
||||
(let
|
||||
((expr (parse-expr)))
|
||||
(let
|
||||
((tgt (parse-tgt-kw "on" (list (quote me)))))
|
||||
(list (quote decrement!) expr tgt)))))
|
||||
(define
|
||||
parse-hide-cmd
|
||||
(fn
|
||||
@@ -519,18 +702,20 @@
|
||||
(let
|
||||
((typ (tp-type)) (val (tp-val)))
|
||||
(if
|
||||
(and
|
||||
(= typ "op")
|
||||
(or
|
||||
(= val "+")
|
||||
(= val "-")
|
||||
(= val "*")
|
||||
(= val "/")
|
||||
(= val "%")))
|
||||
(or
|
||||
(and
|
||||
(= typ "op")
|
||||
(or
|
||||
(= val "+")
|
||||
(= val "-")
|
||||
(= val "*")
|
||||
(= val "/")
|
||||
(= val "%")))
|
||||
(and (= typ "keyword") (= val "mod")))
|
||||
(do
|
||||
(adv!)
|
||||
(let
|
||||
((op (cond ((= val "+") (quote +)) ((= val "-") (quote -)) ((= val "*") (quote *)) ((= val "/") (quote /)) ((= val "%") (make-symbol "%")))))
|
||||
((op (cond ((= val "+") (quote +)) ((= val "-") (quote -)) ((= val "*") (quote *)) ((= val "/") (quote /)) ((or (= val "%") (= val "mod")) (make-symbol "%")))))
|
||||
(let
|
||||
((right (let ((a (parse-atom))) (if (nil? a) a (parse-poss a)))))
|
||||
(parse-arith (list op left right)))))
|
||||
|
||||
@@ -172,7 +172,13 @@
|
||||
(n thunk)
|
||||
(define
|
||||
do-repeat
|
||||
(fn (i) (when (< i n) (thunk) (do-repeat (+ i 1)))))
|
||||
(fn
|
||||
(i)
|
||||
(when
|
||||
(< i n)
|
||||
(log (str "[hs-repeat] iteration " i " of " n))
|
||||
(thunk)
|
||||
(do-repeat (+ i 1)))))
|
||||
(do-repeat 0)))
|
||||
|
||||
;; Repeat forever (until break — relies on exception/continuation).
|
||||
@@ -208,8 +214,8 @@
|
||||
(fn
|
||||
(value type-name)
|
||||
(cond
|
||||
((= type-name "Int") (+ value 0))
|
||||
((= type-name "Integer") (+ value 0))
|
||||
((= type-name "Int") (floor (+ value 0)))
|
||||
((= type-name "Integer") (floor (+ value 0)))
|
||||
((= type-name "Float") (+ value 0))
|
||||
((= type-name "Number") (+ value 0))
|
||||
((= type-name "String") (str value))
|
||||
@@ -221,6 +227,15 @@
|
||||
|
||||
;; Make a new object of a given type.
|
||||
;; (hs-make type-name) — creates empty object/collection
|
||||
(define
|
||||
hs-add
|
||||
(fn (a b) (if (or (string? a) (string? b)) (str a b) (+ a b))))
|
||||
|
||||
;; ── 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-make
|
||||
(fn
|
||||
@@ -232,25 +247,20 @@
|
||||
((= type-name "Map") (dict))
|
||||
(true (dict)))))
|
||||
|
||||
;; ── 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-install (fn (behavior-fn) (behavior-fn me)))
|
||||
|
||||
;; ── Measurement ─────────────────────────────────────────────────
|
||||
|
||||
;; Measure an element's bounding rect, store as local variables.
|
||||
;; Returns a dict with x, y, width, height, top, left, right, bottom.
|
||||
(define
|
||||
hs-measure
|
||||
(fn (target) (perform (list (quote io-measure) target))))
|
||||
(define hs-install (fn (behavior-fn) (behavior-fn me)))
|
||||
|
||||
;; ── Transition ──────────────────────────────────────────────────
|
||||
|
||||
;; Transition a CSS property to a value, optionally with duration.
|
||||
;; (hs-transition target prop value duration)
|
||||
(define
|
||||
hs-measure
|
||||
(fn (target) (perform (list (quote io-measure) target))))
|
||||
|
||||
(define
|
||||
hs-transition
|
||||
(fn
|
||||
@@ -262,4 +272,42 @@
|
||||
"transition"
|
||||
(str prop " " (/ duration 1000) "s")))
|
||||
(dom-set-style target prop value)
|
||||
(when duration (hs-settle target))))
|
||||
(when duration (hs-settle target))))
|
||||
|
||||
(define
|
||||
hs-type-check
|
||||
(fn
|
||||
(value type-name)
|
||||
(if
|
||||
(nil? value)
|
||||
true
|
||||
(cond
|
||||
((= type-name "Number") (number? value))
|
||||
((= type-name "String") (string? value))
|
||||
((= type-name "Boolean") (or (= value true) (= value false)))
|
||||
((= type-name "Array") (list? value))
|
||||
((= type-name "Object") (dict? value))
|
||||
(true true)))))
|
||||
|
||||
(define
|
||||
hs-type-check!
|
||||
(fn
|
||||
(value type-name)
|
||||
(if (nil? value) false (hs-type-check value type-name))))
|
||||
|
||||
(define
|
||||
hs-strict-eq
|
||||
(fn (a b) (and (= (type-of a) (type-of b)) (= a b))))
|
||||
|
||||
(define
|
||||
hs-falsy?
|
||||
(fn (v) (or (nil? v) (= v false) (and (string? v) (= v "")))))
|
||||
|
||||
(define
|
||||
hs-matches?
|
||||
(fn
|
||||
(target pattern)
|
||||
(if
|
||||
(string? target)
|
||||
(if (= pattern ".*") true (string-contains? target pattern))
|
||||
false)))
|
||||
@@ -139,7 +139,20 @@
|
||||
"behavior"
|
||||
"called"
|
||||
"render"
|
||||
"eval"))
|
||||
"eval"
|
||||
"I"
|
||||
"am"
|
||||
"does"
|
||||
"some"
|
||||
"mod"
|
||||
"equal"
|
||||
"equals"
|
||||
"really"
|
||||
"include"
|
||||
"includes"
|
||||
"contain"
|
||||
"undefined"
|
||||
"exist"))
|
||||
|
||||
(define hs-keyword? (fn (word) (some (fn (k) (= k word)) hs-keywords)))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user