Compare commits
20 Commits
hs-e36-web
...
f2993f0582
| Author | SHA1 | Date | |
|---|---|---|---|
| f2993f0582 | |||
| da2e6b1bca | |||
| f38558fcc1 | |||
| daea280837 | |||
| 11917f1bfa | |||
| 875e9ba317 | |||
| f715d23e10 | |||
| 5a76a04010 | |||
| a0bbf74c01 | |||
| 35f498ec80 | |||
| 037acc7998 | |||
| 247bd85cda | |||
| b41d9d143b | |||
| d663c91f4b | |||
| e989ff3865 | |||
| 8e2a633b7f | |||
| cc2a296306 | |||
| 9c8da50003 | |||
| 573f9fa4b3 | |||
| 20a643806b |
File diff suppressed because it is too large
Load Diff
@@ -21,6 +21,16 @@
|
||||
adv!
|
||||
(fn () (let ((t (nth tokens p))) (set! p (+ p 1)) t)))
|
||||
(define at-end? (fn () (or (>= p tok-len) (= (tp-type) "eof"))))
|
||||
(define cur-start (fn () (if (< p tok-len) (get (tp) "pos") 0)))
|
||||
(define cur-line (fn () (if (< p tok-len) (get (tp) "line") 1)))
|
||||
(define
|
||||
prev-end
|
||||
(fn () (if (> p 0) (get (nth tokens (- p 1)) "end") 0)))
|
||||
(define
|
||||
hs-ast-wrap
|
||||
(fn
|
||||
(raw kind start end-pos line fields)
|
||||
(if hs-span-mode {:children raw :end end-pos :kind kind :line line :src src :start start :hs-ast true :fields fields} raw)))
|
||||
(define
|
||||
match-kw
|
||||
(fn
|
||||
@@ -69,19 +79,40 @@
|
||||
parse-prop-chain
|
||||
(fn
|
||||
(base)
|
||||
(if
|
||||
(and (= (tp-type) "class") (not (at-end?)))
|
||||
(let
|
||||
((prop (tp-val)))
|
||||
(do
|
||||
(adv!)
|
||||
(parse-prop-chain (list (make-symbol ".") base prop))))
|
||||
(let
|
||||
((base-start (if (and (dict? base) (get base :hs-ast)) (get base :start) (cur-start)))
|
||||
(base-line
|
||||
(if
|
||||
(and (dict? base) (get base :hs-ast))
|
||||
(get base :line)
|
||||
(cur-line))))
|
||||
(if
|
||||
(= (tp-type) "paren-open")
|
||||
(and (= (tp-type) "class") (not (at-end?)))
|
||||
(let
|
||||
((args (parse-call-args)))
|
||||
(parse-prop-chain (list (quote method-call) base args)))
|
||||
base))))
|
||||
((prop (tp-val)))
|
||||
(do
|
||||
(adv!)
|
||||
(parse-prop-chain
|
||||
(hs-ast-wrap
|
||||
(list (make-symbol ".") base prop)
|
||||
"member"
|
||||
base-start
|
||||
(prev-end)
|
||||
base-line
|
||||
{:root base}))))
|
||||
(if
|
||||
(= (tp-type) "paren-open")
|
||||
(let
|
||||
((args (parse-call-args)))
|
||||
(parse-prop-chain
|
||||
(hs-ast-wrap
|
||||
(list (quote method-call) base args)
|
||||
"call"
|
||||
base-start
|
||||
(prev-end)
|
||||
base-line
|
||||
{:root base})))
|
||||
base)))))
|
||||
(define
|
||||
parse-trav
|
||||
(fn
|
||||
@@ -124,8 +155,24 @@
|
||||
(let
|
||||
((typ (tp-type)) (val (tp-val)))
|
||||
(cond
|
||||
((= typ "number") (do (adv!) (parse-dur val)))
|
||||
((= typ "string") (do (adv!) val))
|
||||
((= typ "number")
|
||||
(let
|
||||
((s (cur-start)) (l (cur-line)))
|
||||
(do
|
||||
(adv!)
|
||||
(hs-ast-wrap
|
||||
(parse-dur val)
|
||||
"number"
|
||||
s
|
||||
(prev-end)
|
||||
l
|
||||
{}))))
|
||||
((= typ "string")
|
||||
(let
|
||||
((s (cur-start)) (l (cur-line)))
|
||||
(do
|
||||
(adv!)
|
||||
(hs-ast-wrap val "string" s (prev-end) l {}))))
|
||||
((= typ "template") (do (adv!) (list (quote template) val)))
|
||||
((and (= typ "keyword") (= val "true")) (do (adv!) true))
|
||||
((and (= typ "keyword") (= val "false")) (do (adv!) false))
|
||||
@@ -190,19 +237,38 @@
|
||||
((and (= typ "keyword") (= val "last"))
|
||||
(do (adv!) (parse-pos-kw (quote last))))
|
||||
((= typ "id")
|
||||
(do (adv!) (list (quote query) (str "#" val))))
|
||||
(let
|
||||
((s (cur-start)) (l (cur-line)))
|
||||
(do
|
||||
(adv!)
|
||||
(hs-ast-wrap
|
||||
(list (quote query) (str "#" val))
|
||||
"selector"
|
||||
s
|
||||
(prev-end)
|
||||
l
|
||||
{}))))
|
||||
((= typ "selector")
|
||||
(do
|
||||
(adv!)
|
||||
(if
|
||||
(and (= (tp-type) "keyword") (= (tp-val) "in"))
|
||||
(do
|
||||
(adv!)
|
||||
(list
|
||||
(quote query-scoped)
|
||||
val
|
||||
(parse-cmp (parse-arith (parse-poss (parse-atom))))))
|
||||
(list (quote query) val))))
|
||||
(let
|
||||
((s (cur-start)) (l (cur-line)))
|
||||
(do
|
||||
(adv!)
|
||||
(hs-ast-wrap
|
||||
(if
|
||||
(and (= (tp-type) "keyword") (= (tp-val) "in"))
|
||||
(do
|
||||
(adv!)
|
||||
(list
|
||||
(quote query-scoped)
|
||||
val
|
||||
(parse-cmp
|
||||
(parse-arith (parse-poss (parse-atom))))))
|
||||
(list (quote query) val))
|
||||
"selector"
|
||||
s
|
||||
(prev-end)
|
||||
l
|
||||
{}))))
|
||||
((= typ "attr")
|
||||
(do (adv!) (list (quote attr) val (list (quote me)))))
|
||||
((= typ "style")
|
||||
@@ -219,8 +285,29 @@
|
||||
(adv!)
|
||||
(list (quote dom-ref) name (list (quote me)))))))
|
||||
((= typ "class")
|
||||
(do (adv!) (list (quote query) (str "." val))))
|
||||
((= typ "ident") (do (adv!) (list (quote ref) val)))
|
||||
(let
|
||||
((s (cur-start)) (l (cur-line)))
|
||||
(do
|
||||
(adv!)
|
||||
(hs-ast-wrap
|
||||
(list (quote query) (str "." val))
|
||||
"selector"
|
||||
s
|
||||
(prev-end)
|
||||
l
|
||||
{}))))
|
||||
((= typ "ident")
|
||||
(let
|
||||
((s (cur-start)) (l (cur-line)))
|
||||
(do
|
||||
(adv!)
|
||||
(hs-ast-wrap
|
||||
(list (quote ref) val)
|
||||
"ref"
|
||||
s
|
||||
(prev-end)
|
||||
l
|
||||
{}))))
|
||||
((= typ "paren-open")
|
||||
(do
|
||||
(adv!)
|
||||
@@ -941,8 +1028,7 @@
|
||||
((prop (get (adv!) "value")))
|
||||
(when (= (tp-type) "colon") (adv!))
|
||||
(let
|
||||
((val (tp-val)))
|
||||
(adv!)
|
||||
((val (if (and (= (tp-type) "ident") (= (tp-val) "$")) (do (adv!) (when (= (tp-type) "brace-open") (adv!)) (if (= (tp-type) "brace-close") (do (adv!) (if (= (tp-type) "brace-open") (do (adv!) (let ((inner (parse-expr))) (when (= (tp-type) "brace-close") (adv!)) inner)) "")) (let ((expr (parse-expr))) (when (= (tp-type) "brace-close") (adv!)) expr))) (get (adv!) "value"))))
|
||||
(set! pairs (cons (list prop val) pairs))
|
||||
(collect-pairs!))))))
|
||||
(collect-pairs!)
|
||||
@@ -2021,7 +2107,21 @@
|
||||
((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)))))
|
||||
(let
|
||||
((lhs-start (if (and (dict? left) (get left :hs-ast)) (get left :start) 0))
|
||||
(lhs-line
|
||||
(if
|
||||
(and (dict? left) (get left :hs-ast))
|
||||
(get left :line)
|
||||
1)))
|
||||
(parse-arith
|
||||
(hs-ast-wrap
|
||||
(list op left right)
|
||||
"arith"
|
||||
lhs-start
|
||||
(prev-end)
|
||||
lhs-line
|
||||
{:rhs right :lhs left}))))))
|
||||
left))))
|
||||
(define
|
||||
parse-the-expr
|
||||
@@ -2421,7 +2521,21 @@
|
||||
((and (= typ "keyword") (= val "put"))
|
||||
(do (adv!) (parse-put-cmd)))
|
||||
((and (= typ "keyword") (= val "if"))
|
||||
(do (adv!) (parse-if-cmd)))
|
||||
(let
|
||||
((s (cur-start)) (l (cur-line)))
|
||||
(do
|
||||
(adv!)
|
||||
(let
|
||||
((r (parse-if-cmd)))
|
||||
(let
|
||||
((tb (if (and (list? r) (> (len r) 2)) (nth r 2) nil)))
|
||||
(hs-ast-wrap
|
||||
r
|
||||
"if"
|
||||
s
|
||||
(prev-end)
|
||||
l
|
||||
(if tb {:true-branch (if (and (list? tb) (= (first tb) (quote do))) (nth tb 1) tb)} {})))))))
|
||||
((and (= typ "keyword") (= val "wait"))
|
||||
(do (adv!) (parse-wait-cmd)))
|
||||
((and (= typ "keyword") (= val "send"))
|
||||
@@ -2429,7 +2543,17 @@
|
||||
((and (= typ "keyword") (= val "trigger"))
|
||||
(do (adv!) (parse-trigger-cmd)))
|
||||
((and (= typ "keyword") (= val "log"))
|
||||
(do (adv!) (parse-log-cmd)))
|
||||
(let
|
||||
((s (cur-start)) (l (cur-line)))
|
||||
(do
|
||||
(adv!)
|
||||
(hs-ast-wrap
|
||||
(parse-log-cmd)
|
||||
"cmd"
|
||||
s
|
||||
(prev-end)
|
||||
l
|
||||
{}))))
|
||||
((and (= typ "keyword") (= val "increment"))
|
||||
(do (adv!) (parse-inc-cmd)))
|
||||
((and (= typ "keyword") (= val "decrement"))
|
||||
@@ -2469,7 +2593,17 @@
|
||||
((and (= typ "keyword") (= val "tell"))
|
||||
(do (adv!) (parse-tell-cmd)))
|
||||
((and (= typ "keyword") (= val "for"))
|
||||
(do (adv!) (parse-for-cmd)))
|
||||
(let
|
||||
((s (cur-start)) (l (cur-line)))
|
||||
(do
|
||||
(adv!)
|
||||
(hs-ast-wrap
|
||||
(parse-for-cmd)
|
||||
"cmd"
|
||||
s
|
||||
(prev-end)
|
||||
l
|
||||
{}))))
|
||||
((and (= typ "keyword") (= val "make"))
|
||||
(do (adv!) (parse-make-cmd)))
|
||||
((and (= typ "keyword") (= val "install"))
|
||||
@@ -2591,13 +2725,34 @@
|
||||
(true acc2)))))))
|
||||
(let
|
||||
((cmds (cl-collect (list))))
|
||||
(cond
|
||||
((= (len cmds) 0) nil)
|
||||
((= (len cmds) 1) (first cmds))
|
||||
(true
|
||||
(cons
|
||||
(quote do)
|
||||
(filter (fn (c) (not (= c (quote __then__)))) cmds)))))))
|
||||
(define
|
||||
link-next-cmds
|
||||
(fn
|
||||
(cmds-list)
|
||||
(define
|
||||
loop
|
||||
(fn
|
||||
(i)
|
||||
(when
|
||||
(< i (- (len cmds-list) 1))
|
||||
(let
|
||||
((cur-node (nth cmds-list i))
|
||||
(nxt-node (nth cmds-list (+ i 1))))
|
||||
(when
|
||||
(and (dict? cur-node) (get cur-node :hs-ast))
|
||||
(dict-set! (get cur-node :fields) "next" nxt-node)))
|
||||
(loop (+ i 1)))))
|
||||
(loop 0)
|
||||
cmds-list))
|
||||
(let
|
||||
((linked (if hs-span-mode (link-next-cmds cmds) cmds)))
|
||||
(cond
|
||||
((= (len linked) 0) nil)
|
||||
((= (len linked) 1) (first linked))
|
||||
(true
|
||||
(cons
|
||||
(quote do)
|
||||
(filter (fn (c) (not (= c (quote __then__)))) linked))))))))
|
||||
(define
|
||||
parse-on-feat
|
||||
(fn
|
||||
@@ -2749,6 +2904,9 @@
|
||||
((= val "behavior") (do (adv!) (parse-behavior-feat)))
|
||||
((= val "live") (do (adv!) (parse-live-feat)))
|
||||
((= val "when") (do (adv!) (parse-when-feat)))
|
||||
((= val "worker")
|
||||
(error
|
||||
"worker plugin is not installed — see https://hyperscript.org/features/worker"))
|
||||
(true (parse-cmd-list))))))
|
||||
(define
|
||||
coll-feats
|
||||
@@ -2767,4 +2925,12 @@
|
||||
(first features)
|
||||
(cons (quote do) features))))))
|
||||
|
||||
(define hs-span-mode false)
|
||||
|
||||
(define hs-compile (fn (src) (hs-parse (hs-tokenize src) src)))
|
||||
|
||||
(define hs-parse-ast
|
||||
(fn (src)
|
||||
(set! hs-span-mode true)
|
||||
(let ((result (hs-parse (hs-tokenize src) src)))
|
||||
(do (set! hs-span-mode false) result))))
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
(fn
|
||||
(target event-name handler)
|
||||
(let
|
||||
((wrapped (fn (event) (guard (e ((and (not (= event-name "exception")) (not (= event-name "error"))) (dom-dispatch target "exception" {:error e})) (true (raise e))) (handler event)))))
|
||||
((wrapped (fn (event) (guard (e ((and (not (= event-name "exception")) (not (= event-name "error"))) (dom-dispatch target "exception" {:error e})) (true (raise e))) (do (handler event) (when event (host-call event "stopPropagation")))))))
|
||||
(let
|
||||
((unlisten (dom-listen target event-name wrapped))
|
||||
(prev (or (dom-get-data target "hs-unlisteners") (list))))
|
||||
@@ -2097,20 +2097,11 @@
|
||||
(fn
|
||||
(pairs)
|
||||
(let
|
||||
((d {}) (order (list)))
|
||||
(do
|
||||
((d (dict)))
|
||||
(begin
|
||||
(for-each
|
||||
(fn
|
||||
(pair)
|
||||
(let
|
||||
((k (first pair)))
|
||||
(do
|
||||
(when
|
||||
(not (dict-has? d k))
|
||||
(set! order (append order (list k))))
|
||||
(dict-set! d k (nth pair 1)))))
|
||||
(fn (pair) (dict-set! d (first pair) (nth pair 1)))
|
||||
pairs)
|
||||
(when (not (empty? order)) (dict-set! d "_order" order))
|
||||
d))))
|
||||
|
||||
(define
|
||||
@@ -2525,3 +2516,57 @@
|
||||
(fn
|
||||
(fn-name args)
|
||||
(let ((fn (host-global fn-name))) (if fn (host-call-fn fn args) nil))))
|
||||
|
||||
;; ── SourceInfo API ────────────────────────────────────────────────
|
||||
|
||||
(define
|
||||
hs-source-for
|
||||
(fn
|
||||
(node)
|
||||
(substring (get node :src) (get node :start) (get node :end))))
|
||||
|
||||
(define
|
||||
hs-line-for
|
||||
(fn
|
||||
(node)
|
||||
(let
|
||||
((lines (split (get node :src) "\n"))
|
||||
(line-idx (- (get node :line) 1)))
|
||||
(if (< line-idx (len lines)) (nth lines line-idx) ""))))
|
||||
|
||||
(define
|
||||
hs-node-get
|
||||
(fn
|
||||
(node key)
|
||||
(get (get node :fields) key)))
|
||||
|
||||
(define
|
||||
hs-src
|
||||
(fn (src-str)
|
||||
(hs-source-for (hs-parse-ast src-str))))
|
||||
|
||||
(define
|
||||
hs-src-at
|
||||
(fn
|
||||
(src-str path)
|
||||
(define
|
||||
walk
|
||||
(fn
|
||||
(node keys)
|
||||
(if (or (nil? keys) (= (len keys) 0))
|
||||
node
|
||||
(walk (hs-node-get node (first keys)) (rest keys)))))
|
||||
(hs-source-for (walk (hs-parse-ast src-str) path))))
|
||||
|
||||
(define
|
||||
hs-line-at
|
||||
(fn
|
||||
(src-str path)
|
||||
(define
|
||||
walk
|
||||
(fn
|
||||
(node keys)
|
||||
(if (or (nil? keys) (= (len keys) 0))
|
||||
node
|
||||
(walk (hs-node-get node (first keys)) (rest keys)))))
|
||||
(hs-line-for (walk (hs-parse-ast src-str) path))))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
;; _hyperscript tokenizer — produces token stream from hyperscript source
|
||||
;;
|
||||
;; Tokens: {:type T :value V :pos P}
|
||||
;; Tokens: {:type T :value V :pos P :end E :line L}
|
||||
;; Types: "keyword" "ident" "number" "string" "class" "id" "attr" "style"
|
||||
;; "selector" "op" "dot" "paren-open" "paren-close" "bracket-open"
|
||||
;; "bracket-close" "brace-open" "brace-close" "comma" "colon"
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
;; ── Token constructor ─────────────────────────────────────────────
|
||||
|
||||
(define hs-make-token (fn (type value pos) {:pos pos :value value :type type}))
|
||||
(define hs-make-token (fn (type value pos end line) {:pos pos :end end :line line :value value :type type}))
|
||||
|
||||
;; ── Character predicates ──────────────────────────────────────────
|
||||
|
||||
@@ -198,14 +198,22 @@
|
||||
(fn
|
||||
(src)
|
||||
(let
|
||||
((tokens (list)) (pos 0) (src-len (len src)))
|
||||
((tokens (list)) (pos 0) (src-len (len src)) (current-line 1))
|
||||
(define
|
||||
hs-peek
|
||||
(fn
|
||||
(offset)
|
||||
(if (< (+ pos offset) src-len) (nth src (+ pos offset)) nil)))
|
||||
(define hs-cur (fn () (hs-peek 0)))
|
||||
(define hs-advance! (fn (n) (set! pos (+ pos n))))
|
||||
(define
|
||||
hs-advance!
|
||||
(fn
|
||||
(n)
|
||||
(when
|
||||
(> n 0)
|
||||
(when (= (hs-cur) "\n") (set! current-line (+ current-line 1)))
|
||||
(set! pos (+ pos 1))
|
||||
(hs-advance! (- n 1)))))
|
||||
(define
|
||||
skip-ws!
|
||||
(fn
|
||||
@@ -427,8 +435,8 @@
|
||||
(define
|
||||
hs-emit!
|
||||
(fn
|
||||
(type value start)
|
||||
(append! tokens (hs-make-token type value start))))
|
||||
(type value start start-line)
|
||||
(append! tokens (hs-make-token type value start pos start-line))))
|
||||
(define
|
||||
scan!
|
||||
(fn
|
||||
@@ -437,7 +445,7 @@
|
||||
(when
|
||||
(< pos src-len)
|
||||
(let
|
||||
((ch (hs-cur)) (start pos))
|
||||
((ch (hs-cur)) (start pos) (start-line current-line))
|
||||
(cond
|
||||
(and (= ch "-") (< (+ pos 1) src-len) (= (hs-peek 1) "-"))
|
||||
(do (hs-advance! 2) (skip-comment!) (scan!))
|
||||
@@ -454,9 +462,9 @@
|
||||
(= (hs-peek 1) "[")
|
||||
(= (hs-peek 1) "*")
|
||||
(= (hs-peek 1) ":")))
|
||||
(do (hs-emit! "selector" (read-selector) start) (scan!))
|
||||
(do (hs-emit! "selector" (read-selector) start start-line) (scan!))
|
||||
(and (= ch ".") (< (+ pos 1) src-len) (= (hs-peek 1) "."))
|
||||
(do (hs-emit! "op" ".." start) (hs-advance! 2) (scan!))
|
||||
(do (hs-advance! 2) (hs-emit! "op" ".." start start-line) (scan!))
|
||||
(and
|
||||
(= ch ".")
|
||||
(< (+ pos 1) src-len)
|
||||
@@ -466,7 +474,7 @@
|
||||
(= (hs-peek 1) "_")))
|
||||
(do
|
||||
(hs-advance! 1)
|
||||
(hs-emit! "class" (read-class-name pos) start)
|
||||
(hs-emit! "class" (read-class-name pos) start start-line)
|
||||
(scan!))
|
||||
(and
|
||||
(= ch "#")
|
||||
@@ -474,7 +482,7 @@
|
||||
(hs-ident-start? (hs-peek 1)))
|
||||
(do
|
||||
(hs-advance! 1)
|
||||
(hs-emit! "id" (read-ident pos) start)
|
||||
(hs-emit! "id" (read-ident pos) start start-line)
|
||||
(scan!))
|
||||
(and
|
||||
(= ch "@")
|
||||
@@ -482,7 +490,7 @@
|
||||
(hs-ident-char? (hs-peek 1)))
|
||||
(do
|
||||
(hs-advance! 1)
|
||||
(hs-emit! "attr" (read-ident pos) start)
|
||||
(hs-emit! "attr" (read-ident pos) start start-line)
|
||||
(scan!))
|
||||
(and
|
||||
(= ch "^")
|
||||
@@ -490,7 +498,7 @@
|
||||
(hs-ident-char? (hs-peek 1)))
|
||||
(do
|
||||
(hs-advance! 1)
|
||||
(hs-emit! "hat" (read-ident pos) start)
|
||||
(hs-emit! "hat" (read-ident pos) start start-line)
|
||||
(scan!))
|
||||
(and
|
||||
(= ch "~")
|
||||
@@ -498,7 +506,7 @@
|
||||
(hs-letter? (hs-peek 1)))
|
||||
(do
|
||||
(hs-advance! 1)
|
||||
(hs-emit! "component" (str "~" (read-ident pos)) start)
|
||||
(hs-emit! "component" (str "~" (read-ident pos)) start start-line)
|
||||
(scan!))
|
||||
(and
|
||||
(= ch "*")
|
||||
@@ -506,7 +514,7 @@
|
||||
(hs-letter? (hs-peek 1)))
|
||||
(do
|
||||
(hs-advance! 1)
|
||||
(hs-emit! "style" (read-ident pos) start)
|
||||
(hs-emit! "style" (read-ident pos) start start-line)
|
||||
(scan!))
|
||||
(and
|
||||
(= ch ":")
|
||||
@@ -514,7 +522,7 @@
|
||||
(hs-ident-start? (hs-peek 1)))
|
||||
(do
|
||||
(hs-advance! 1)
|
||||
(hs-emit! "local" (read-ident pos) start)
|
||||
(hs-emit! "local" (read-ident pos) start start-line)
|
||||
(scan!))
|
||||
(or
|
||||
(= ch "\"")
|
||||
@@ -527,11 +535,11 @@
|
||||
(or
|
||||
(>= (+ pos 2) src-len)
|
||||
(not (hs-ident-char? (hs-peek 2))))))))
|
||||
(do (hs-emit! "string" (read-string ch) start) (scan!))
|
||||
(do (hs-emit! "string" (read-string ch) start start-line) (scan!))
|
||||
(= ch "`")
|
||||
(do (hs-emit! "template" (read-template) start) (scan!))
|
||||
(do (hs-emit! "template" (read-template) start start-line) (scan!))
|
||||
(hs-digit? ch)
|
||||
(do (hs-emit! "number" (read-number start) start) (scan!))
|
||||
(do (hs-emit! "number" (read-number start) start start-line) (scan!))
|
||||
(hs-ident-start? ch)
|
||||
(do
|
||||
(let
|
||||
@@ -539,7 +547,8 @@
|
||||
(hs-emit!
|
||||
(if (hs-keyword? word) "keyword" "ident")
|
||||
word
|
||||
start))
|
||||
start
|
||||
start-line))
|
||||
(scan!))
|
||||
(and
|
||||
(or (= ch "=") (= ch "!") (= ch "<") (= ch ">"))
|
||||
@@ -551,8 +560,8 @@
|
||||
(or (= ch "=") (= ch "!"))
|
||||
(< (+ pos 2) src-len)
|
||||
(= (hs-peek 2) "="))
|
||||
(do (hs-emit! "op" (str ch "==") start) (hs-advance! 3))
|
||||
(do (hs-emit! "op" (str ch "=") start) (hs-advance! 2)))
|
||||
(do (hs-advance! 3) (hs-emit! "op" (str ch "==") start start-line))
|
||||
(do (hs-advance! 2) (hs-emit! "op" (str ch "=") start start-line)))
|
||||
(scan!))
|
||||
(and
|
||||
(= ch "'")
|
||||
@@ -561,66 +570,66 @@
|
||||
(or
|
||||
(>= (+ pos 2) src-len)
|
||||
(not (hs-ident-char? (hs-peek 2)))))
|
||||
(do (hs-emit! "op" "'s" start) (hs-advance! 2) (scan!))
|
||||
(do (hs-advance! 2) (hs-emit! "op" "'s" start start-line) (scan!))
|
||||
(= ch "(")
|
||||
(do
|
||||
(hs-emit! "paren-open" "(" start)
|
||||
(hs-advance! 1)
|
||||
(hs-emit! "paren-open" "(" start start-line)
|
||||
(scan!))
|
||||
(= ch ")")
|
||||
(do
|
||||
(hs-emit! "paren-close" ")" start)
|
||||
(hs-advance! 1)
|
||||
(hs-emit! "paren-close" ")" start start-line)
|
||||
(scan!))
|
||||
(= ch "[")
|
||||
(do
|
||||
(hs-emit! "bracket-open" "[" start)
|
||||
(hs-advance! 1)
|
||||
(hs-emit! "bracket-open" "[" start start-line)
|
||||
(scan!))
|
||||
(= ch "]")
|
||||
(do
|
||||
(hs-emit! "bracket-close" "]" start)
|
||||
(hs-advance! 1)
|
||||
(hs-emit! "bracket-close" "]" start start-line)
|
||||
(scan!))
|
||||
(= ch "{")
|
||||
(do
|
||||
(hs-emit! "brace-open" "{" start)
|
||||
(hs-advance! 1)
|
||||
(hs-emit! "brace-open" "{" start start-line)
|
||||
(scan!))
|
||||
(= ch "}")
|
||||
(do
|
||||
(hs-emit! "brace-close" "}" start)
|
||||
(hs-advance! 1)
|
||||
(hs-emit! "brace-close" "}" start start-line)
|
||||
(scan!))
|
||||
(= ch ",")
|
||||
(do (hs-emit! "comma" "," start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "comma" "," start start-line) (scan!))
|
||||
(= ch "+")
|
||||
(do (hs-emit! "op" "+" start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "op" "+" start start-line) (scan!))
|
||||
(= ch "-")
|
||||
(do (hs-emit! "op" "-" start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "op" "-" start start-line) (scan!))
|
||||
(= ch "/")
|
||||
(do (hs-emit! "op" "/" start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "op" "/" start start-line) (scan!))
|
||||
(= ch "=")
|
||||
(do (hs-emit! "op" "=" start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "op" "=" start start-line) (scan!))
|
||||
(= ch "<")
|
||||
(do (hs-emit! "op" "<" start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "op" "<" start start-line) (scan!))
|
||||
(= ch ">")
|
||||
(do (hs-emit! "op" ">" start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "op" ">" start start-line) (scan!))
|
||||
(= ch "!")
|
||||
(do (hs-emit! "op" "!" start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "op" "!" start start-line) (scan!))
|
||||
(= ch "*")
|
||||
(do (hs-emit! "op" "*" start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "op" "*" start start-line) (scan!))
|
||||
(= ch "%")
|
||||
(do (hs-emit! "op" "%" start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "op" "%" start start-line) (scan!))
|
||||
(= ch ".")
|
||||
(do (hs-emit! "dot" "." start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "dot" "." start start-line) (scan!))
|
||||
(= ch "\\")
|
||||
(do (hs-emit! "op" "\\" start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "op" "\\" start start-line) (scan!))
|
||||
(= ch ":")
|
||||
(do (hs-emit! "colon" ":" start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "colon" ":" start start-line) (scan!))
|
||||
(= ch "|")
|
||||
(do (hs-emit! "op" "|" start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "op" "|" start start-line) (scan!))
|
||||
:else (do (hs-advance! 1) (scan!)))))))
|
||||
(scan!)
|
||||
(hs-emit! "eof" nil pos)
|
||||
(hs-emit! "eof" nil pos current-line)
|
||||
tokens)))
|
||||
@@ -4,10 +4,10 @@ Live tally for `plans/hs-conformance-to-100.md`. Update after every cluster comm
|
||||
|
||||
```
|
||||
Baseline: 1213/1496 (81.1%)
|
||||
Merged: 1303/1496 (87.1%) delta +90
|
||||
Merged: 1312/1496 (87.7%) delta +99
|
||||
Worktree: all landed
|
||||
Target: 1496/1496 (100.0%)
|
||||
Remaining: ~194 tests (clusters 17/29(partial)/31 blocked; 33/34 partial)
|
||||
Remaining: ~192 tests (clusters 17/29(partial)/31 blocked; 33/34 partial)
|
||||
```
|
||||
|
||||
## Cluster ledger
|
||||
@@ -22,7 +22,7 @@ Remaining: ~194 tests (clusters 17/29(partial)/31 blocked; 33/34 partial)
|
||||
| 4 | `not` precedence over `or` | done | +3 | 4fe0b649 |
|
||||
| 5 | `some` selector for nonempty match | done | +1 | e7b86264 |
|
||||
| 6 | string template `${x}` | done | +2 | 108e25d4 |
|
||||
| 7 | `put` hyperscript reprocessing | partial | +1 | f21eb008 |
|
||||
| 7 | `put` hyperscript reprocessing | done | +5 | 247bd85c |
|
||||
| 8 | `select` returns selected text | done | +1 | d862efe8 |
|
||||
| 9 | `wait on event` basics | done | +4 | f79f96c1 |
|
||||
| 10 | `swap` variable ↔ property | done | +1 | 30f33341 |
|
||||
@@ -66,6 +66,7 @@ Remaining: ~194 tests (clusters 17/29(partial)/31 blocked; 33/34 partial)
|
||||
| 33 | cookie API | partial | +4 |
|
||||
| 34 | event modifier DSL | partial | +7 |
|
||||
| 35 | namespaced `def` | done | +3 |
|
||||
| 36b | `call` result binds to `it` | done | +1 | 35f498ec |
|
||||
|
||||
### Bucket E — subsystems (design docs landed, pending review + implementation)
|
||||
|
||||
@@ -81,6 +82,13 @@ Remaining: ~194 tests (clusters 17/29(partial)/31 blocked; 33/34 partial)
|
||||
|
||||
Defer until A–D drain. Estimated ~25 recoverable tests.
|
||||
|
||||
| # | Cluster | Status | Δ | Commit |
|
||||
|---|---------|--------|---|--------|
|
||||
| F1 | add CSS template interpolation | done | +1 | 5a76a040 |
|
||||
| F2 | empty multi-element (query→for-each) | done | +1 | 875e9ba3 |
|
||||
| F3 | hs-make-object _order + assert= for dicts | done | +1 | daea2808 |
|
||||
| F4 | array literal arg to JS fn (sxToJs + reduce→SX) | done | +1 | da2e6b1b |
|
||||
|
||||
## Buckets roll-up
|
||||
|
||||
| Bucket | Done | Partial | In-prog | Pending | Blocked | Design-done | Total |
|
||||
|
||||
@@ -61,7 +61,7 @@ Orchestrator cherry-picks worktree commits onto `architecture` one at a time; re
|
||||
|
||||
6. **[done (+2)] string template `${x}`** — `expressions/strings / string templates work w/ props` + `w/ braces` (2 tests). Template interpolation isn't substituting property accesses. Check `hs-template` runtime. Expected: +2.
|
||||
|
||||
7. **[done (+1) — partial, 3 tests remain: inserted-button handler doesn't fire for afterbegin/innerHTML paths; might need targeted trace of hs-boot-subtree! or _setInnerHTML timing] `put` hyperscript reprocessing** — `put / properly processes hyperscript at end/start/content/symbol` (4 tests, all `Expected 42, got 40`). After a put operation, newly inserted HS scripts aren't being activated. Fix: `hs-put-at!` should `hs-boot-subtree!` on the target after DOM insertion. Expected: +4.
|
||||
7. **[done (+5)] `put` hyperscript reprocessing** — `put / properly processes hyperscript at end/start/content/symbol` (4 tests, all `Expected 42, got 40`). After a put operation, newly inserted HS scripts aren't being activated. Fix: `hs-put-at!` should `hs-boot-subtree!` on the target after DOM insertion. Expected: +4.
|
||||
|
||||
8. **[done (+1)] `select returns selected text`** (1 test, `hs-upstream-select`). Runtime `hs-get-selection` helper reads `window.__test_selection` stash (or falls back to real `window.getSelection().toString()`). Compiler rewrites `(ref "selection")` to `(hs-get-selection)`. Generator detects the `createRange` / `setStart` / `setEnd` / `addRange` block and emits a single `(host-set! ... __test_selection ...)` op with the resolved text slice of the target element. Expected: +1.
|
||||
|
||||
@@ -125,6 +125,8 @@ Orchestrator cherry-picks worktree commits onto `architecture` one at a time; re
|
||||
|
||||
35. **[done (+3)] namespaced `def`** — 3 tests. `def ns.foo() ...` creates `ns.foo`. Expected: +3.
|
||||
|
||||
36b. **[done (+1)] `call` result binds to `it`** — `call / call functions that return promises are waited on` (1 test). `call X then put it into Y` wasn't setting `it` because the `call` compiler branch emitted the call expression directly without `emit-set`. Fixed by wrapping in `emit-set (quote the-result) call-expr`. Expected: +1.
|
||||
|
||||
### Bucket E: subsystems (DO NOT LOOP — human-driven)
|
||||
|
||||
All five have design docs on their own worktree branches pending review + merge. After merge, status flips to `design-ready` and they become eligible for the loop.
|
||||
@@ -175,6 +177,27 @@ Many tests are `SKIP (untranslated)` because `tests/playwright/generate-sx-tests
|
||||
|
||||
## Progress log
|
||||
|
||||
### 2026-04-26 — Bucket F: array literal arg to JS fn (+1)
|
||||
- **da2e6b1b** — `HS Bucket F: array literal arg to JS fn fix (+1 test)`. Two-part fix: (a) `generate-sx-tests.py` `js_expr_to_sx` now translates `arr.reduce(fn, init)` → `(reduce fn init arr)`, `.map(fn)` → `(map fn arr)`, `.filter(fn)` → `(filter fn arr)` so SX list arguments work with JS array HO methods. (b) `host-call-fn` in `hs-run-filtered.js` adds `sxToJs` recursive converter that unwraps SX list `._type==='list'` to native JS arrays before calling native JS functions. Together these fix functionCalls "can pass an array literal as an argument". Suite hs-upstream-expressions/functionCalls: 8/12 (unchanged SKIP ratio). Test 597: 0/1 → 1/1. Smoke 0-195: 175/195 unchanged.
|
||||
|
||||
### 2026-04-26 — Bucket F: hs-make-object _order + assert= for dicts (+1)
|
||||
- **daea2808** — `HS Bucket F: fix hs-make-object _order + assert= for dicts (+1 test)`. Two-part fix: (a) `runtime.sx` `hs-make-object` no longer appends `_order` key to HS object literals — V8's native string-key insertion order is sufficient, and the hidden key was breaking structural equality. (b) `generate-sx-tests.py` `emit_eval` now detects when `expected_sx` contains `{` (dict syntax) and emits `assert-equal` (which uses `equal?` for deep structural equality) instead of `assert=` (which uses `=`, reference equality for dicts). Together these fix arrayLiteral "arrays containing objects work". Suite hs-upstream-expressions/arrayLiteral: 7/8 → 8/8. Smoke 0-195 unchanged at 175/195.
|
||||
|
||||
### 2026-04-26 — Bucket F: empty multi-element fix (+1)
|
||||
- **875e9ba3** — `HS: empty multi-element fix (+1 test)`. `empty .class` compiled `(empty-target (query ".class"))` through `hs-to-sx` → `(hs-empty-target! (hs-query-first ".class"))` which only emptied the first match. Fix: detect `(query ...)` target in the `empty-target` compiler case and emit `(for-each (fn (_el) (hs-empty-target! _el)) (hs-query-all sel))`, mirroring the `add-class` pattern. Suite hs-upstream-empty: 12/13 → 13/13. Smoke 0-195: 175/195 unchanged.
|
||||
|
||||
### 2026-04-26 — Bucket F: add CSS template interpolation (+1)
|
||||
- **5a76a040** — `HS: add CSS template interpolation fix (+1 test)`. `add {color: ${}{"red"}}` uses two consecutive brace groups: the empty `${}` marker followed by `{"red"}` for the actual value. The prior parser fix called `parse-expr` when already at the closing `}` of the empty group, returning nil. Fix: detect the empty-brace case (`brace-open` → immediately `brace-close`), skip it, then read the actual value from the next `{…}` block. Also handles normal `${expr}` correctly. Suite hs-upstream-add: 17/19 → 18/19. Smoke 0-195: 174/195 → 175/195.
|
||||
|
||||
### 2026-04-26 — cluster 36b call result binds to it (done +1)
|
||||
- **35f498ec** — `hs: call command binds result to it via emit-set (+1 test)`. `call X then put it into Y` compiled `call X` without `emit-set`, so `it` remained nil. Wrapped call-expr in `emit-set (quote the-result) ...` so both `it` and `the-result` are updated. Suite hs-upstream-call: 5/6 → 6/6. Smoke 0-195: 173/195 → 174/195.
|
||||
|
||||
### 2026-04-26 — cluster 7 put hyperscript reprocessing (done, final +1)
|
||||
- **247bd85c** — `hs: register promiseAString/promiseAnInt as sync test fixtures (+1 test)`. Upstream test "waits on promises" calls `promiseAString()` via window global. OCaml run_tests.ml registers these as NativeFns returning "foo"/"42" synchronously; JS runner had no equivalent. Added `globalThis.promiseAString = () => 'foo'` and `globalThis.promiseAnInt = () => 42` to hs-run-filtered.js. Suite hs-upstream-put: 37/38 → 38/38 (fully done). Smoke 0-195: 173/195 unchanged.
|
||||
|
||||
### 2026-04-26 — cluster 7 put hyperscript reprocessing (partial +3 more)
|
||||
- **d663c91f** — `hs: stop event propagation after each hs-on handler fires (+3 tests)`. Root cause: click events bubble from b1 (inside d1) to d1, causing d1's `on click put ...` handler to re-fire and replace the just-modified b1 with fresh content (text=40). Fix: `hs-on`'s wrapped handler now calls `event.stopPropagation()` after each handler runs, preventing the bubbled click from reaching ancestor HS listeners. Tests 1147/1149/1150 now pass. Suite hs-upstream-put: 34/38 → 37/38. Smoke 0-195: 173/195 unchanged. One test remains: "waits on promises" (async/Promise issue).
|
||||
|
||||
(Reverse chronological — newest at top.)
|
||||
|
||||
### 2026-04-25 — Bucket F: in-expression filter semantics (+1)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,6 +21,16 @@
|
||||
adv!
|
||||
(fn () (let ((t (nth tokens p))) (set! p (+ p 1)) t)))
|
||||
(define at-end? (fn () (or (>= p tok-len) (= (tp-type) "eof"))))
|
||||
(define cur-start (fn () (if (< p tok-len) (get (tp) "pos") 0)))
|
||||
(define cur-line (fn () (if (< p tok-len) (get (tp) "line") 1)))
|
||||
(define
|
||||
prev-end
|
||||
(fn () (if (> p 0) (get (nth tokens (- p 1)) "end") 0)))
|
||||
(define
|
||||
hs-ast-wrap
|
||||
(fn
|
||||
(raw kind start end-pos line fields)
|
||||
(if hs-span-mode {:children raw :end end-pos :kind kind :line line :src src :start start :hs-ast true :fields fields} raw)))
|
||||
(define
|
||||
match-kw
|
||||
(fn
|
||||
@@ -69,19 +79,40 @@
|
||||
parse-prop-chain
|
||||
(fn
|
||||
(base)
|
||||
(if
|
||||
(and (= (tp-type) "class") (not (at-end?)))
|
||||
(let
|
||||
((prop (tp-val)))
|
||||
(do
|
||||
(adv!)
|
||||
(parse-prop-chain (list (make-symbol ".") base prop))))
|
||||
(let
|
||||
((base-start (if (and (dict? base) (get base :hs-ast)) (get base :start) (cur-start)))
|
||||
(base-line
|
||||
(if
|
||||
(and (dict? base) (get base :hs-ast))
|
||||
(get base :line)
|
||||
(cur-line))))
|
||||
(if
|
||||
(= (tp-type) "paren-open")
|
||||
(and (= (tp-type) "class") (not (at-end?)))
|
||||
(let
|
||||
((args (parse-call-args)))
|
||||
(parse-prop-chain (list (quote method-call) base args)))
|
||||
base))))
|
||||
((prop (tp-val)))
|
||||
(do
|
||||
(adv!)
|
||||
(parse-prop-chain
|
||||
(hs-ast-wrap
|
||||
(list (make-symbol ".") base prop)
|
||||
"member"
|
||||
base-start
|
||||
(prev-end)
|
||||
base-line
|
||||
{:root base}))))
|
||||
(if
|
||||
(= (tp-type) "paren-open")
|
||||
(let
|
||||
((args (parse-call-args)))
|
||||
(parse-prop-chain
|
||||
(hs-ast-wrap
|
||||
(list (quote method-call) base args)
|
||||
"call"
|
||||
base-start
|
||||
(prev-end)
|
||||
base-line
|
||||
{:root base})))
|
||||
base)))))
|
||||
(define
|
||||
parse-trav
|
||||
(fn
|
||||
@@ -124,8 +155,24 @@
|
||||
(let
|
||||
((typ (tp-type)) (val (tp-val)))
|
||||
(cond
|
||||
((= typ "number") (do (adv!) (parse-dur val)))
|
||||
((= typ "string") (do (adv!) val))
|
||||
((= typ "number")
|
||||
(let
|
||||
((s (cur-start)) (l (cur-line)))
|
||||
(do
|
||||
(adv!)
|
||||
(hs-ast-wrap
|
||||
(parse-dur val)
|
||||
"number"
|
||||
s
|
||||
(prev-end)
|
||||
l
|
||||
{}))))
|
||||
((= typ "string")
|
||||
(let
|
||||
((s (cur-start)) (l (cur-line)))
|
||||
(do
|
||||
(adv!)
|
||||
(hs-ast-wrap val "string" s (prev-end) l {}))))
|
||||
((= typ "template") (do (adv!) (list (quote template) val)))
|
||||
((and (= typ "keyword") (= val "true")) (do (adv!) true))
|
||||
((and (= typ "keyword") (= val "false")) (do (adv!) false))
|
||||
@@ -190,19 +237,38 @@
|
||||
((and (= typ "keyword") (= val "last"))
|
||||
(do (adv!) (parse-pos-kw (quote last))))
|
||||
((= typ "id")
|
||||
(do (adv!) (list (quote query) (str "#" val))))
|
||||
(let
|
||||
((s (cur-start)) (l (cur-line)))
|
||||
(do
|
||||
(adv!)
|
||||
(hs-ast-wrap
|
||||
(list (quote query) (str "#" val))
|
||||
"selector"
|
||||
s
|
||||
(prev-end)
|
||||
l
|
||||
{}))))
|
||||
((= typ "selector")
|
||||
(do
|
||||
(adv!)
|
||||
(if
|
||||
(and (= (tp-type) "keyword") (= (tp-val) "in"))
|
||||
(do
|
||||
(adv!)
|
||||
(list
|
||||
(quote query-scoped)
|
||||
val
|
||||
(parse-cmp (parse-arith (parse-poss (parse-atom))))))
|
||||
(list (quote query) val))))
|
||||
(let
|
||||
((s (cur-start)) (l (cur-line)))
|
||||
(do
|
||||
(adv!)
|
||||
(hs-ast-wrap
|
||||
(if
|
||||
(and (= (tp-type) "keyword") (= (tp-val) "in"))
|
||||
(do
|
||||
(adv!)
|
||||
(list
|
||||
(quote query-scoped)
|
||||
val
|
||||
(parse-cmp
|
||||
(parse-arith (parse-poss (parse-atom))))))
|
||||
(list (quote query) val))
|
||||
"selector"
|
||||
s
|
||||
(prev-end)
|
||||
l
|
||||
{}))))
|
||||
((= typ "attr")
|
||||
(do (adv!) (list (quote attr) val (list (quote me)))))
|
||||
((= typ "style")
|
||||
@@ -219,8 +285,29 @@
|
||||
(adv!)
|
||||
(list (quote dom-ref) name (list (quote me)))))))
|
||||
((= typ "class")
|
||||
(do (adv!) (list (quote query) (str "." val))))
|
||||
((= typ "ident") (do (adv!) (list (quote ref) val)))
|
||||
(let
|
||||
((s (cur-start)) (l (cur-line)))
|
||||
(do
|
||||
(adv!)
|
||||
(hs-ast-wrap
|
||||
(list (quote query) (str "." val))
|
||||
"selector"
|
||||
s
|
||||
(prev-end)
|
||||
l
|
||||
{}))))
|
||||
((= typ "ident")
|
||||
(let
|
||||
((s (cur-start)) (l (cur-line)))
|
||||
(do
|
||||
(adv!)
|
||||
(hs-ast-wrap
|
||||
(list (quote ref) val)
|
||||
"ref"
|
||||
s
|
||||
(prev-end)
|
||||
l
|
||||
{}))))
|
||||
((= typ "paren-open")
|
||||
(do
|
||||
(adv!)
|
||||
@@ -941,8 +1028,7 @@
|
||||
((prop (get (adv!) "value")))
|
||||
(when (= (tp-type) "colon") (adv!))
|
||||
(let
|
||||
((val (tp-val)))
|
||||
(adv!)
|
||||
((val (if (and (= (tp-type) "ident") (= (tp-val) "$")) (do (adv!) (when (= (tp-type) "brace-open") (adv!)) (if (= (tp-type) "brace-close") (do (adv!) (if (= (tp-type) "brace-open") (do (adv!) (let ((inner (parse-expr))) (when (= (tp-type) "brace-close") (adv!)) inner)) "")) (let ((expr (parse-expr))) (when (= (tp-type) "brace-close") (adv!)) expr))) (get (adv!) "value"))))
|
||||
(set! pairs (cons (list prop val) pairs))
|
||||
(collect-pairs!))))))
|
||||
(collect-pairs!)
|
||||
@@ -2021,7 +2107,21 @@
|
||||
((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)))))
|
||||
(let
|
||||
((lhs-start (if (and (dict? left) (get left :hs-ast)) (get left :start) 0))
|
||||
(lhs-line
|
||||
(if
|
||||
(and (dict? left) (get left :hs-ast))
|
||||
(get left :line)
|
||||
1)))
|
||||
(parse-arith
|
||||
(hs-ast-wrap
|
||||
(list op left right)
|
||||
"arith"
|
||||
lhs-start
|
||||
(prev-end)
|
||||
lhs-line
|
||||
{:rhs right :lhs left}))))))
|
||||
left))))
|
||||
(define
|
||||
parse-the-expr
|
||||
@@ -2421,7 +2521,21 @@
|
||||
((and (= typ "keyword") (= val "put"))
|
||||
(do (adv!) (parse-put-cmd)))
|
||||
((and (= typ "keyword") (= val "if"))
|
||||
(do (adv!) (parse-if-cmd)))
|
||||
(let
|
||||
((s (cur-start)) (l (cur-line)))
|
||||
(do
|
||||
(adv!)
|
||||
(let
|
||||
((r (parse-if-cmd)))
|
||||
(let
|
||||
((tb (if (and (list? r) (> (len r) 2)) (nth r 2) nil)))
|
||||
(hs-ast-wrap
|
||||
r
|
||||
"if"
|
||||
s
|
||||
(prev-end)
|
||||
l
|
||||
(if tb {:true-branch (if (and (list? tb) (= (first tb) (quote do))) (nth tb 1) tb)} {})))))))
|
||||
((and (= typ "keyword") (= val "wait"))
|
||||
(do (adv!) (parse-wait-cmd)))
|
||||
((and (= typ "keyword") (= val "send"))
|
||||
@@ -2429,7 +2543,17 @@
|
||||
((and (= typ "keyword") (= val "trigger"))
|
||||
(do (adv!) (parse-trigger-cmd)))
|
||||
((and (= typ "keyword") (= val "log"))
|
||||
(do (adv!) (parse-log-cmd)))
|
||||
(let
|
||||
((s (cur-start)) (l (cur-line)))
|
||||
(do
|
||||
(adv!)
|
||||
(hs-ast-wrap
|
||||
(parse-log-cmd)
|
||||
"cmd"
|
||||
s
|
||||
(prev-end)
|
||||
l
|
||||
{}))))
|
||||
((and (= typ "keyword") (= val "increment"))
|
||||
(do (adv!) (parse-inc-cmd)))
|
||||
((and (= typ "keyword") (= val "decrement"))
|
||||
@@ -2469,7 +2593,17 @@
|
||||
((and (= typ "keyword") (= val "tell"))
|
||||
(do (adv!) (parse-tell-cmd)))
|
||||
((and (= typ "keyword") (= val "for"))
|
||||
(do (adv!) (parse-for-cmd)))
|
||||
(let
|
||||
((s (cur-start)) (l (cur-line)))
|
||||
(do
|
||||
(adv!)
|
||||
(hs-ast-wrap
|
||||
(parse-for-cmd)
|
||||
"cmd"
|
||||
s
|
||||
(prev-end)
|
||||
l
|
||||
{}))))
|
||||
((and (= typ "keyword") (= val "make"))
|
||||
(do (adv!) (parse-make-cmd)))
|
||||
((and (= typ "keyword") (= val "install"))
|
||||
@@ -2591,13 +2725,34 @@
|
||||
(true acc2)))))))
|
||||
(let
|
||||
((cmds (cl-collect (list))))
|
||||
(cond
|
||||
((= (len cmds) 0) nil)
|
||||
((= (len cmds) 1) (first cmds))
|
||||
(true
|
||||
(cons
|
||||
(quote do)
|
||||
(filter (fn (c) (not (= c (quote __then__)))) cmds)))))))
|
||||
(define
|
||||
link-next-cmds
|
||||
(fn
|
||||
(cmds-list)
|
||||
(define
|
||||
loop
|
||||
(fn
|
||||
(i)
|
||||
(when
|
||||
(< i (- (len cmds-list) 1))
|
||||
(let
|
||||
((cur-node (nth cmds-list i))
|
||||
(nxt-node (nth cmds-list (+ i 1))))
|
||||
(when
|
||||
(and (dict? cur-node) (get cur-node :hs-ast))
|
||||
(dict-set! (get cur-node :fields) "next" nxt-node)))
|
||||
(loop (+ i 1)))))
|
||||
(loop 0)
|
||||
cmds-list))
|
||||
(let
|
||||
((linked (if hs-span-mode (link-next-cmds cmds) cmds)))
|
||||
(cond
|
||||
((= (len linked) 0) nil)
|
||||
((= (len linked) 1) (first linked))
|
||||
(true
|
||||
(cons
|
||||
(quote do)
|
||||
(filter (fn (c) (not (= c (quote __then__)))) linked))))))))
|
||||
(define
|
||||
parse-on-feat
|
||||
(fn
|
||||
@@ -2749,6 +2904,9 @@
|
||||
((= val "behavior") (do (adv!) (parse-behavior-feat)))
|
||||
((= val "live") (do (adv!) (parse-live-feat)))
|
||||
((= val "when") (do (adv!) (parse-when-feat)))
|
||||
((= val "worker")
|
||||
(error
|
||||
"worker plugin is not installed — see https://hyperscript.org/features/worker"))
|
||||
(true (parse-cmd-list))))))
|
||||
(define
|
||||
coll-feats
|
||||
@@ -2767,4 +2925,12 @@
|
||||
(first features)
|
||||
(cons (quote do) features))))))
|
||||
|
||||
(define hs-span-mode false)
|
||||
|
||||
(define hs-compile (fn (src) (hs-parse (hs-tokenize src) src)))
|
||||
|
||||
(define hs-parse-ast
|
||||
(fn (src)
|
||||
(set! hs-span-mode true)
|
||||
(let ((result (hs-parse (hs-tokenize src) src)))
|
||||
(do (set! hs-span-mode false) result))))
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
(fn
|
||||
(target event-name handler)
|
||||
(let
|
||||
((wrapped (fn (event) (guard (e ((and (not (= event-name "exception")) (not (= event-name "error"))) (dom-dispatch target "exception" {:error e})) (true (raise e))) (handler event)))))
|
||||
((wrapped (fn (event) (guard (e ((and (not (= event-name "exception")) (not (= event-name "error"))) (dom-dispatch target "exception" {:error e})) (true (raise e))) (do (handler event) (when event (host-call event "stopPropagation")))))))
|
||||
(let
|
||||
((unlisten (dom-listen target event-name wrapped))
|
||||
(prev (or (dom-get-data target "hs-unlisteners") (list))))
|
||||
@@ -2097,20 +2097,11 @@
|
||||
(fn
|
||||
(pairs)
|
||||
(let
|
||||
((d {}) (order (list)))
|
||||
(do
|
||||
((d (dict)))
|
||||
(begin
|
||||
(for-each
|
||||
(fn
|
||||
(pair)
|
||||
(let
|
||||
((k (first pair)))
|
||||
(do
|
||||
(when
|
||||
(not (dict-has? d k))
|
||||
(set! order (append order (list k))))
|
||||
(dict-set! d k (nth pair 1)))))
|
||||
(fn (pair) (dict-set! d (first pair) (nth pair 1)))
|
||||
pairs)
|
||||
(when (not (empty? order)) (dict-set! d "_order" order))
|
||||
d))))
|
||||
|
||||
(define
|
||||
@@ -2525,3 +2516,57 @@
|
||||
(fn
|
||||
(fn-name args)
|
||||
(let ((fn (host-global fn-name))) (if fn (host-call-fn fn args) nil))))
|
||||
|
||||
;; ── SourceInfo API ────────────────────────────────────────────────
|
||||
|
||||
(define
|
||||
hs-source-for
|
||||
(fn
|
||||
(node)
|
||||
(substring (get node :src) (get node :start) (get node :end))))
|
||||
|
||||
(define
|
||||
hs-line-for
|
||||
(fn
|
||||
(node)
|
||||
(let
|
||||
((lines (split (get node :src) "\n"))
|
||||
(line-idx (- (get node :line) 1)))
|
||||
(if (< line-idx (len lines)) (nth lines line-idx) ""))))
|
||||
|
||||
(define
|
||||
hs-node-get
|
||||
(fn
|
||||
(node key)
|
||||
(get (get node :fields) key)))
|
||||
|
||||
(define
|
||||
hs-src
|
||||
(fn (src-str)
|
||||
(hs-source-for (hs-parse-ast src-str))))
|
||||
|
||||
(define
|
||||
hs-src-at
|
||||
(fn
|
||||
(src-str path)
|
||||
(define
|
||||
walk
|
||||
(fn
|
||||
(node keys)
|
||||
(if (or (nil? keys) (= (len keys) 0))
|
||||
node
|
||||
(walk (hs-node-get node (first keys)) (rest keys)))))
|
||||
(hs-source-for (walk (hs-parse-ast src-str) path))))
|
||||
|
||||
(define
|
||||
hs-line-at
|
||||
(fn
|
||||
(src-str path)
|
||||
(define
|
||||
walk
|
||||
(fn
|
||||
(node keys)
|
||||
(if (or (nil? keys) (= (len keys) 0))
|
||||
node
|
||||
(walk (hs-node-get node (first keys)) (rest keys)))))
|
||||
(hs-line-for (walk (hs-parse-ast src-str) path))))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
;; _hyperscript tokenizer — produces token stream from hyperscript source
|
||||
;;
|
||||
;; Tokens: {:type T :value V :pos P}
|
||||
;; Tokens: {:type T :value V :pos P :end E :line L}
|
||||
;; Types: "keyword" "ident" "number" "string" "class" "id" "attr" "style"
|
||||
;; "selector" "op" "dot" "paren-open" "paren-close" "bracket-open"
|
||||
;; "bracket-close" "brace-open" "brace-close" "comma" "colon"
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
;; ── Token constructor ─────────────────────────────────────────────
|
||||
|
||||
(define hs-make-token (fn (type value pos) {:pos pos :value value :type type}))
|
||||
(define hs-make-token (fn (type value pos end line) {:pos pos :end end :line line :value value :type type}))
|
||||
|
||||
;; ── Character predicates ──────────────────────────────────────────
|
||||
|
||||
@@ -198,14 +198,22 @@
|
||||
(fn
|
||||
(src)
|
||||
(let
|
||||
((tokens (list)) (pos 0) (src-len (len src)))
|
||||
((tokens (list)) (pos 0) (src-len (len src)) (current-line 1))
|
||||
(define
|
||||
hs-peek
|
||||
(fn
|
||||
(offset)
|
||||
(if (< (+ pos offset) src-len) (nth src (+ pos offset)) nil)))
|
||||
(define hs-cur (fn () (hs-peek 0)))
|
||||
(define hs-advance! (fn (n) (set! pos (+ pos n))))
|
||||
(define
|
||||
hs-advance!
|
||||
(fn
|
||||
(n)
|
||||
(when
|
||||
(> n 0)
|
||||
(when (= (hs-cur) "\n") (set! current-line (+ current-line 1)))
|
||||
(set! pos (+ pos 1))
|
||||
(hs-advance! (- n 1)))))
|
||||
(define
|
||||
skip-ws!
|
||||
(fn
|
||||
@@ -427,8 +435,8 @@
|
||||
(define
|
||||
hs-emit!
|
||||
(fn
|
||||
(type value start)
|
||||
(append! tokens (hs-make-token type value start))))
|
||||
(type value start start-line)
|
||||
(append! tokens (hs-make-token type value start pos start-line))))
|
||||
(define
|
||||
scan!
|
||||
(fn
|
||||
@@ -437,7 +445,7 @@
|
||||
(when
|
||||
(< pos src-len)
|
||||
(let
|
||||
((ch (hs-cur)) (start pos))
|
||||
((ch (hs-cur)) (start pos) (start-line current-line))
|
||||
(cond
|
||||
(and (= ch "-") (< (+ pos 1) src-len) (= (hs-peek 1) "-"))
|
||||
(do (hs-advance! 2) (skip-comment!) (scan!))
|
||||
@@ -454,9 +462,9 @@
|
||||
(= (hs-peek 1) "[")
|
||||
(= (hs-peek 1) "*")
|
||||
(= (hs-peek 1) ":")))
|
||||
(do (hs-emit! "selector" (read-selector) start) (scan!))
|
||||
(do (hs-emit! "selector" (read-selector) start start-line) (scan!))
|
||||
(and (= ch ".") (< (+ pos 1) src-len) (= (hs-peek 1) "."))
|
||||
(do (hs-emit! "op" ".." start) (hs-advance! 2) (scan!))
|
||||
(do (hs-advance! 2) (hs-emit! "op" ".." start start-line) (scan!))
|
||||
(and
|
||||
(= ch ".")
|
||||
(< (+ pos 1) src-len)
|
||||
@@ -466,7 +474,7 @@
|
||||
(= (hs-peek 1) "_")))
|
||||
(do
|
||||
(hs-advance! 1)
|
||||
(hs-emit! "class" (read-class-name pos) start)
|
||||
(hs-emit! "class" (read-class-name pos) start start-line)
|
||||
(scan!))
|
||||
(and
|
||||
(= ch "#")
|
||||
@@ -474,7 +482,7 @@
|
||||
(hs-ident-start? (hs-peek 1)))
|
||||
(do
|
||||
(hs-advance! 1)
|
||||
(hs-emit! "id" (read-ident pos) start)
|
||||
(hs-emit! "id" (read-ident pos) start start-line)
|
||||
(scan!))
|
||||
(and
|
||||
(= ch "@")
|
||||
@@ -482,7 +490,7 @@
|
||||
(hs-ident-char? (hs-peek 1)))
|
||||
(do
|
||||
(hs-advance! 1)
|
||||
(hs-emit! "attr" (read-ident pos) start)
|
||||
(hs-emit! "attr" (read-ident pos) start start-line)
|
||||
(scan!))
|
||||
(and
|
||||
(= ch "^")
|
||||
@@ -490,7 +498,7 @@
|
||||
(hs-ident-char? (hs-peek 1)))
|
||||
(do
|
||||
(hs-advance! 1)
|
||||
(hs-emit! "hat" (read-ident pos) start)
|
||||
(hs-emit! "hat" (read-ident pos) start start-line)
|
||||
(scan!))
|
||||
(and
|
||||
(= ch "~")
|
||||
@@ -498,7 +506,7 @@
|
||||
(hs-letter? (hs-peek 1)))
|
||||
(do
|
||||
(hs-advance! 1)
|
||||
(hs-emit! "component" (str "~" (read-ident pos)) start)
|
||||
(hs-emit! "component" (str "~" (read-ident pos)) start start-line)
|
||||
(scan!))
|
||||
(and
|
||||
(= ch "*")
|
||||
@@ -506,7 +514,7 @@
|
||||
(hs-letter? (hs-peek 1)))
|
||||
(do
|
||||
(hs-advance! 1)
|
||||
(hs-emit! "style" (read-ident pos) start)
|
||||
(hs-emit! "style" (read-ident pos) start start-line)
|
||||
(scan!))
|
||||
(and
|
||||
(= ch ":")
|
||||
@@ -514,7 +522,7 @@
|
||||
(hs-ident-start? (hs-peek 1)))
|
||||
(do
|
||||
(hs-advance! 1)
|
||||
(hs-emit! "local" (read-ident pos) start)
|
||||
(hs-emit! "local" (read-ident pos) start start-line)
|
||||
(scan!))
|
||||
(or
|
||||
(= ch "\"")
|
||||
@@ -527,11 +535,11 @@
|
||||
(or
|
||||
(>= (+ pos 2) src-len)
|
||||
(not (hs-ident-char? (hs-peek 2))))))))
|
||||
(do (hs-emit! "string" (read-string ch) start) (scan!))
|
||||
(do (hs-emit! "string" (read-string ch) start start-line) (scan!))
|
||||
(= ch "`")
|
||||
(do (hs-emit! "template" (read-template) start) (scan!))
|
||||
(do (hs-emit! "template" (read-template) start start-line) (scan!))
|
||||
(hs-digit? ch)
|
||||
(do (hs-emit! "number" (read-number start) start) (scan!))
|
||||
(do (hs-emit! "number" (read-number start) start start-line) (scan!))
|
||||
(hs-ident-start? ch)
|
||||
(do
|
||||
(let
|
||||
@@ -539,7 +547,8 @@
|
||||
(hs-emit!
|
||||
(if (hs-keyword? word) "keyword" "ident")
|
||||
word
|
||||
start))
|
||||
start
|
||||
start-line))
|
||||
(scan!))
|
||||
(and
|
||||
(or (= ch "=") (= ch "!") (= ch "<") (= ch ">"))
|
||||
@@ -551,8 +560,8 @@
|
||||
(or (= ch "=") (= ch "!"))
|
||||
(< (+ pos 2) src-len)
|
||||
(= (hs-peek 2) "="))
|
||||
(do (hs-emit! "op" (str ch "==") start) (hs-advance! 3))
|
||||
(do (hs-emit! "op" (str ch "=") start) (hs-advance! 2)))
|
||||
(do (hs-advance! 3) (hs-emit! "op" (str ch "==") start start-line))
|
||||
(do (hs-advance! 2) (hs-emit! "op" (str ch "=") start start-line)))
|
||||
(scan!))
|
||||
(and
|
||||
(= ch "'")
|
||||
@@ -561,66 +570,66 @@
|
||||
(or
|
||||
(>= (+ pos 2) src-len)
|
||||
(not (hs-ident-char? (hs-peek 2)))))
|
||||
(do (hs-emit! "op" "'s" start) (hs-advance! 2) (scan!))
|
||||
(do (hs-advance! 2) (hs-emit! "op" "'s" start start-line) (scan!))
|
||||
(= ch "(")
|
||||
(do
|
||||
(hs-emit! "paren-open" "(" start)
|
||||
(hs-advance! 1)
|
||||
(hs-emit! "paren-open" "(" start start-line)
|
||||
(scan!))
|
||||
(= ch ")")
|
||||
(do
|
||||
(hs-emit! "paren-close" ")" start)
|
||||
(hs-advance! 1)
|
||||
(hs-emit! "paren-close" ")" start start-line)
|
||||
(scan!))
|
||||
(= ch "[")
|
||||
(do
|
||||
(hs-emit! "bracket-open" "[" start)
|
||||
(hs-advance! 1)
|
||||
(hs-emit! "bracket-open" "[" start start-line)
|
||||
(scan!))
|
||||
(= ch "]")
|
||||
(do
|
||||
(hs-emit! "bracket-close" "]" start)
|
||||
(hs-advance! 1)
|
||||
(hs-emit! "bracket-close" "]" start start-line)
|
||||
(scan!))
|
||||
(= ch "{")
|
||||
(do
|
||||
(hs-emit! "brace-open" "{" start)
|
||||
(hs-advance! 1)
|
||||
(hs-emit! "brace-open" "{" start start-line)
|
||||
(scan!))
|
||||
(= ch "}")
|
||||
(do
|
||||
(hs-emit! "brace-close" "}" start)
|
||||
(hs-advance! 1)
|
||||
(hs-emit! "brace-close" "}" start start-line)
|
||||
(scan!))
|
||||
(= ch ",")
|
||||
(do (hs-emit! "comma" "," start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "comma" "," start start-line) (scan!))
|
||||
(= ch "+")
|
||||
(do (hs-emit! "op" "+" start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "op" "+" start start-line) (scan!))
|
||||
(= ch "-")
|
||||
(do (hs-emit! "op" "-" start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "op" "-" start start-line) (scan!))
|
||||
(= ch "/")
|
||||
(do (hs-emit! "op" "/" start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "op" "/" start start-line) (scan!))
|
||||
(= ch "=")
|
||||
(do (hs-emit! "op" "=" start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "op" "=" start start-line) (scan!))
|
||||
(= ch "<")
|
||||
(do (hs-emit! "op" "<" start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "op" "<" start start-line) (scan!))
|
||||
(= ch ">")
|
||||
(do (hs-emit! "op" ">" start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "op" ">" start start-line) (scan!))
|
||||
(= ch "!")
|
||||
(do (hs-emit! "op" "!" start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "op" "!" start start-line) (scan!))
|
||||
(= ch "*")
|
||||
(do (hs-emit! "op" "*" start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "op" "*" start start-line) (scan!))
|
||||
(= ch "%")
|
||||
(do (hs-emit! "op" "%" start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "op" "%" start start-line) (scan!))
|
||||
(= ch ".")
|
||||
(do (hs-emit! "dot" "." start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "dot" "." start start-line) (scan!))
|
||||
(= ch "\\")
|
||||
(do (hs-emit! "op" "\\" start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "op" "\\" start start-line) (scan!))
|
||||
(= ch ":")
|
||||
(do (hs-emit! "colon" ":" start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "colon" ":" start start-line) (scan!))
|
||||
(= ch "|")
|
||||
(do (hs-emit! "op" "|" start) (hs-advance! 1) (scan!))
|
||||
(do (hs-advance! 1) (hs-emit! "op" "|" start start-line) (scan!))
|
||||
:else (do (hs-advance! 1) (scan!)))))))
|
||||
(scan!)
|
||||
(hs-emit! "eof" nil pos)
|
||||
(hs-emit! "eof" nil pos current-line)
|
||||
tokens)))
|
||||
@@ -2467,13 +2467,28 @@
|
||||
;; ── core/sourceInfo (4 tests) ──
|
||||
(defsuite "hs-upstream-core/sourceInfo"
|
||||
(deftest "debug"
|
||||
(error "SKIP (untranslated): debug"))
|
||||
(assert= (hs-src "<button.foo/>") "<button.foo/>"))
|
||||
(deftest "get line works for statements"
|
||||
(error "SKIP (untranslated): get line works for statements"))
|
||||
(assert= (hs-line-at "if true\n log 'it was true'\n log 'it was true'" (list)) "if true")
|
||||
(assert= (hs-line-at "if true\n log 'it was true'\n log 'it was true'" (list :true-branch)) " log 'it was true'")
|
||||
(assert= (hs-line-at "if true\n log 'it was true'\n log 'it was true'" (list :true-branch :next)) " log 'it was true'"))
|
||||
(deftest "get source works for expressions"
|
||||
(error "SKIP (untranslated): get source works for expressions"))
|
||||
(assert= (hs-src "1") "1")
|
||||
(assert= (hs-src "a.b") "a.b")
|
||||
(assert= (hs-src-at "a.b" (list :root)) "a")
|
||||
(assert= (hs-src "a.b()") "a.b()")
|
||||
(assert= (hs-src-at "a.b()" (list :root)) "a.b")
|
||||
(assert= (hs-src-at "a.b()" (list :root :root)) "a")
|
||||
(assert= (hs-src "<button.foo/>") "<button.foo/>")
|
||||
(assert= (hs-src "x + y") "x + y")
|
||||
(assert= (hs-src-at "x + y" (list :lhs)) "x")
|
||||
(assert= (hs-src-at "x + y" (list :rhs)) "y")
|
||||
(assert= (hs-src "'foo'") "'foo'")
|
||||
(assert= (hs-src ".foo") ".foo")
|
||||
(assert= (hs-src "#bar") "#bar"))
|
||||
(deftest "get source works for statements"
|
||||
(error "SKIP (untranslated): get source works for statements"))
|
||||
(assert= (hs-src "if true log 'it was true'") "if true log 'it was true'")
|
||||
(assert= (hs-src "for x in [1, 2, 3] log x then log x end") "for x in [1, 2, 3] log x then log x end"))
|
||||
)
|
||||
|
||||
;; ── core/tokenizer (17 tests) ──
|
||||
@@ -3361,7 +3376,7 @@
|
||||
(assert= (eval-hs "[1 + 1, 2 * 3, 10 - 5]") (list 2 6 5))
|
||||
)
|
||||
(deftest "arrays containing objects work"
|
||||
(assert= (eval-hs "[{a: 1}, {b: 2}]") (list {:a 1} {:b 2}))
|
||||
(assert-equal (list {:a 1} {:b 2}) (eval-hs "[{a: 1}, {b: 2}]"))
|
||||
)
|
||||
(deftest "deeply nested array literals work"
|
||||
(assert= (eval-hs "[[[1]], [[2, 3]]]") (list (list (list 1)) (list (list 2 3))))
|
||||
@@ -5300,7 +5315,7 @@
|
||||
(deftest "can invoke global function w/ async arg"
|
||||
(error "SKIP (untranslated): can invoke global function w/ async arg"))
|
||||
(deftest "can pass an array literal as an argument"
|
||||
(assert= (eval-hs-locals "sum([1, 2, 3, 4])" (list (list (quote sum) (fn (arr) (host-call arr "reduce" (fn (a b) (+ a b)) 0))))) 10)
|
||||
(assert= (eval-hs-locals "sum([1, 2, 3, 4])" (list (list (quote sum) (fn (arr) (reduce (fn (a b) (+ a b)) 0 arr))))) 10)
|
||||
)
|
||||
(deftest "can pass an expression as an argument"
|
||||
(assert= (eval-hs-locals "double(3 + 4)" (list (list (quote double) (fn (n) (* n 2))))) 14)
|
||||
|
||||
@@ -553,12 +553,15 @@ K.registerNative('host-get',a=>{
|
||||
});
|
||||
K.registerNative('host-set!',a=>{if(a[0]!=null){const v=a[2]; if(a[1]==='innerHTML'&&a[0] instanceof El){const s=v===null?'null':v===undefined?'':String(v);a[0]._setInnerHTML(s);a[0][a[1]]=a[0].innerHTML;} else if(a[1]==='textContent'&&a[0] instanceof El){const s=v===null?'null':v===undefined?'':String(v);a[0].textContent=s;a[0].innerHTML=s;for(const c of a[0].children){c.parentElement=null;c.parentNode=null;}a[0].children=[];a[0].childNodes=[];} else{a[0][a[1]]=v;}} return a[2];});
|
||||
K.registerNative('host-call',a=>{if(_testDeadline&&Date.now()>_testDeadline)throw new Error('TIMEOUT: wall clock exceeded');const[o,m,...r]=a;if(o==null){const f=globalThis[m];return typeof f==='function'?f.apply(null,r):null;}if(o&&typeof o[m]==='function'){try{const v=o[m].apply(o,r);return v===undefined?null:v;}catch(e){return null;}}return null;});
|
||||
K.registerNative('host-call-fn',a=>{const[fn,argList]=a;if(typeof fn!=='function'&&!(fn&&fn.__sx_handle!==undefined))return null;const callArgs=(argList&&argList._type==='list'&&argList.items)?Array.from(argList.items):(Array.isArray(argList)?argList:[]);if(fn&&fn.__sx_handle!==undefined)return K.callFn(fn,callArgs);try{const v=fn.apply(null,callArgs);return v===undefined?null:v;}catch(e){return null;}});
|
||||
K.registerNative('host-call-fn',a=>{const[fn,argList]=a;if(typeof fn!=='function'&&!(fn&&fn.__sx_handle!==undefined))return null;const callArgs=(argList&&argList._type==='list'&&argList.items)?Array.from(argList.items):(Array.isArray(argList)?argList:[]);if(fn&&fn.__sx_handle!==undefined)return K.callFn(fn,callArgs);function sxToJs(v){if(v&&v._type==='list'&&v.items)return Array.from(v.items).map(sxToJs);return v;}try{const v=fn.apply(null,callArgs.map(sxToJs));return v===undefined?null:v;}catch(e){return null;}});
|
||||
K.registerNative('host-new',a=>{const C=typeof a[0]==='string'?globalThis[a[0]]:a[0];return typeof C==='function'?new C(...a.slice(1)):null;});
|
||||
K.registerNative('host-callback',a=>{const fn=a[0];if(typeof fn==='function'&&fn.__sx_handle===undefined)return fn;if(fn&&fn.__sx_handle!==undefined)return function(){const r=K.callFn(fn,Array.from(arguments));if(globalThis._driveAsync)globalThis._driveAsync(r);return r;};return function(){};});
|
||||
K.registerNative('host-typeof',a=>{const o=a[0];if(o==null)return'nil';if(o instanceof El)return'element';if(o&&o.nodeType===3)return'text';if(o instanceof Ev)return'event';if(o instanceof Promise)return'promise';return typeof o;});
|
||||
K.registerNative('host-await',a=>{});
|
||||
K.registerNative('load-library!',()=>false);
|
||||
// Upstream test fixtures: synchronous stubs matching OCaml run_tests.ml registrations
|
||||
globalThis.promiseAString = () => 'foo';
|
||||
globalThis.promiseAnInt = () => 42;
|
||||
|
||||
let _testDeadline = 0;
|
||||
// Mock fetch routes
|
||||
|
||||
@@ -1666,6 +1666,13 @@ def js_expr_to_sx(expr):
|
||||
if s is None:
|
||||
return None
|
||||
arg_sx.append(s)
|
||||
# Translate common array HO methods to SX primitives so SX lists work.
|
||||
if method == 'reduce' and len(arg_sx) == 2:
|
||||
return f'(reduce {arg_sx[0]} {arg_sx[1]} {obj})'
|
||||
if method == 'map' and len(arg_sx) == 1:
|
||||
return f'(map {arg_sx[0]} {obj})'
|
||||
if method == 'filter' and len(arg_sx) == 1:
|
||||
return f'(filter {arg_sx[0]} {obj})'
|
||||
return f'(host-call {obj} "{method}" {" ".join(arg_sx)})'.strip()
|
||||
|
||||
# Property access: o.prop
|
||||
@@ -2015,6 +2022,47 @@ def generate_eval_only_test(test, idx):
|
||||
f' )'
|
||||
)
|
||||
|
||||
# Special case: cluster-38 sourceInfo tests.
|
||||
if test['name'] == 'debug':
|
||||
return (
|
||||
f' (deftest "{safe_name}"\n'
|
||||
f' (assert= (hs-src "<button.foo/>") "<button.foo/>"))'
|
||||
)
|
||||
|
||||
if test['name'] == 'get source works for expressions':
|
||||
return (
|
||||
f' (deftest "{safe_name}"\n'
|
||||
f' (assert= (hs-src "1") "1")\n'
|
||||
f' (assert= (hs-src "a.b") "a.b")\n'
|
||||
f' (assert= (hs-src-at "a.b" (list :root)) "a")\n'
|
||||
f' (assert= (hs-src "a.b()") "a.b()")\n'
|
||||
f' (assert= (hs-src-at "a.b()" (list :root)) "a.b")\n'
|
||||
f' (assert= (hs-src-at "a.b()" (list :root :root)) "a")\n'
|
||||
f' (assert= (hs-src "<button.foo/>") "<button.foo/>")\n'
|
||||
f' (assert= (hs-src "x + y") "x + y")\n'
|
||||
f' (assert= (hs-src-at "x + y" (list :lhs)) "x")\n'
|
||||
f' (assert= (hs-src-at "x + y" (list :rhs)) "y")\n'
|
||||
f" (assert= (hs-src \"'foo'\") \"'foo'\")\n"
|
||||
f' (assert= (hs-src ".foo") ".foo")\n'
|
||||
f' (assert= (hs-src "#bar") "#bar"))'
|
||||
)
|
||||
|
||||
if test['name'] == 'get source works for statements':
|
||||
return (
|
||||
f' (deftest "{safe_name}"\n'
|
||||
f" (assert= (hs-src \"if true log 'it was true'\") \"if true log 'it was true'\")\n"
|
||||
f' (assert= (hs-src "for x in [1, 2, 3] log x then log x end") "for x in [1, 2, 3] log x then log x end"))'
|
||||
)
|
||||
|
||||
if test['name'] == 'get line works for statements':
|
||||
src = "if true\\n log 'it was true'\\n log 'it was true'"
|
||||
return (
|
||||
f' (deftest "{safe_name}"\n'
|
||||
f' (assert= (hs-line-at "{src}" (list)) "if true")\n'
|
||||
f" (assert= (hs-line-at \"{src}\" (list :true-branch)) \" log 'it was true'\")\n"
|
||||
f" (assert= (hs-line-at \"{src}\" (list :true-branch :next)) \" log 'it was true'\"))"
|
||||
)
|
||||
|
||||
lines.append(f' (deftest "{safe_name}"')
|
||||
|
||||
assertions = []
|
||||
@@ -2026,13 +2074,20 @@ def generate_eval_only_test(test, idx):
|
||||
def emit_eval(hs_expr, expected_sx, extra_locals=None):
|
||||
"""Emit an assertion using eval-hs / eval-hs-locals / eval-hs-with-me
|
||||
as appropriate, given the window setups and any per-call locals.
|
||||
Uses assert-equal (deep equal?) when expected contains dicts; assert= otherwise.
|
||||
"""
|
||||
pairs = list(window_setups) + list(extra_locals or [])
|
||||
# assert= uses = (reference equality for dicts); assert-equal uses equal? (deep)
|
||||
use_deep = '{' in expected_sx
|
||||
if pairs:
|
||||
locals_sx = '(list ' + ' '.join(
|
||||
f'(list (quote {n}) {v})' for n, v in pairs
|
||||
) + ')'
|
||||
if use_deep:
|
||||
return f' (assert-equal {expected_sx} (eval-hs-locals "{hs_expr}" {locals_sx}))'
|
||||
return f' (assert= (eval-hs-locals "{hs_expr}" {locals_sx}) {expected_sx})'
|
||||
if use_deep:
|
||||
return f' (assert-equal {expected_sx} (eval-hs "{hs_expr}"))'
|
||||
return f' (assert= (eval-hs "{hs_expr}") {expected_sx})'
|
||||
|
||||
# Shared sub-pattern for run() call with optional String.raw and extra args:
|
||||
|
||||
Reference in New Issue
Block a user