HS E36: socket URL parsing + hs-socket-register! runtime (+3 tests)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 15s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 15s
- parser.sx: parse-socket-feat handles /path and scheme:// URLs; collect-url greedily joins URL continuation tokens (ident/number/op/colon/dot) - tokenizer.sx: fix :// not treated as line comment (lookback check) - compiler.sx: emit-socket compiles socket AST to hs-socket-register! call - runtime.sx: hs-socket-register! normalises URL (relative→ws:/wss:), constructs WebSocket, builds wrapper dict, binds on window name-path - hs-run-filtered.js: WebSocket mock uses plain object (not JS array) so host-global returns a foreign value rather than SX list; host-get idx works Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -787,6 +787,31 @@
|
||||
(quote fn)
|
||||
(cons (quote me) (map make-symbol params))
|
||||
(cons (quote do) (map hs-to-sx body)))))))
|
||||
(define
|
||||
emit-socket
|
||||
(fn
|
||||
(ast)
|
||||
(let
|
||||
((name-path (nth ast 1))
|
||||
(url (nth ast 2))
|
||||
(timeout-ms (nth ast 3))
|
||||
(on-msg (nth ast 4)))
|
||||
(let
|
||||
((handler
|
||||
(if
|
||||
(nil? on-msg)
|
||||
nil
|
||||
(let
|
||||
((body (hs-to-sx (nth on-msg 2))))
|
||||
(list (quote fn) (list (quote event)) body))))
|
||||
(json?-val (if (nil? on-msg) false (nth on-msg 1))))
|
||||
(list
|
||||
(quote hs-socket-register!)
|
||||
(cons (quote list) name-path)
|
||||
url
|
||||
(if (nil? timeout-ms) nil (hs-to-sx timeout-ms))
|
||||
handler
|
||||
json?-val)))))
|
||||
(fn
|
||||
(ast)
|
||||
(cond
|
||||
@@ -2075,6 +2100,7 @@
|
||||
(quote _hs-def-val))
|
||||
(quote _hs-def-val))))))
|
||||
((= head (quote behavior)) (emit-behavior ast))
|
||||
((= head (quote socket)) (emit-socket ast))
|
||||
((= head (quote sx-eval))
|
||||
(let
|
||||
((src (nth ast 1)))
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -2729,6 +2729,63 @@
|
||||
(match-kw "end")
|
||||
(list (quote when-feat-no-op)))))
|
||||
(do (pwf-skip) (match-kw "end") (list (quote when-feat-no-op))))))
|
||||
(define
|
||||
parse-socket-feat
|
||||
(fn
|
||||
()
|
||||
(let
|
||||
((seg0 (tp-val)))
|
||||
(adv!)
|
||||
(define
|
||||
collect-segs
|
||||
(fn
|
||||
(acc)
|
||||
(if
|
||||
(= (tp-type) "class")
|
||||
(let
|
||||
((seg (tp-val)))
|
||||
(adv!)
|
||||
(collect-segs (append acc (list seg))))
|
||||
acc)))
|
||||
(let
|
||||
((name-path (collect-segs (list seg0))))
|
||||
(define
|
||||
url-cont?
|
||||
(fn
|
||||
()
|
||||
(or
|
||||
(= (tp-type) "ident")
|
||||
(= (tp-type) "number")
|
||||
(= (tp-type) "op")
|
||||
(= (tp-type) "colon")
|
||||
(= (tp-type) "dot")
|
||||
(and
|
||||
(= (tp-type) "keyword")
|
||||
(not
|
||||
(or
|
||||
(= (tp-val) "end")
|
||||
(= (tp-val) "with")
|
||||
(= (tp-val) "on")
|
||||
(= (tp-val) "as")))))))
|
||||
(define
|
||||
collect-url
|
||||
(fn
|
||||
(parts)
|
||||
(if
|
||||
(and (not (at-end?)) (url-cont?))
|
||||
(let
|
||||
((v (tp-val)))
|
||||
(adv!)
|
||||
(collect-url (append parts (list v))))
|
||||
(join "" parts))))
|
||||
(let
|
||||
((url (cond ((and (= (tp-type) "op") (= (tp-val) "/")) (do (adv!) (collect-url (list "/")))) ((= (tp-type) "ident") (let ((scheme (tp-val))) (adv!) (if (= (tp-type) "colon") (collect-url (list scheme)) (parse-arith (parse-poss (list (quote ref) scheme)))))) (true (parse-atom)))))
|
||||
(let
|
||||
((timeout-ms (if (match-kw "with") (do (adv!) (parse-expr)) nil)))
|
||||
(let
|
||||
((on-msg (if (match-kw "on") (do (adv!) (let ((json? (if (match-kw "as") (do (adv!) true) false))) (let ((body (parse-cmd-list))) (list (quote on-message) json? body)))) nil)))
|
||||
(match-kw "end")
|
||||
(list (quote socket) name-path url timeout-ms on-msg))))))))
|
||||
(define
|
||||
parse-feat
|
||||
(fn
|
||||
@@ -2749,6 +2806,7 @@
|
||||
((= val "behavior") (do (adv!) (parse-behavior-feat)))
|
||||
((= val "live") (do (adv!) (parse-live-feat)))
|
||||
((= val "when") (do (adv!) (parse-when-feat)))
|
||||
((= val "socket") (do (adv!) (parse-socket-feat)))
|
||||
(true (parse-cmd-list))))))
|
||||
(define
|
||||
coll-feats
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -2525,3 +2525,56 @@
|
||||
(fn
|
||||
(fn-name args)
|
||||
(let ((fn (host-global fn-name))) (if fn (host-call-fn fn args) nil))))
|
||||
|
||||
;; ── WebSocket / socket feature ───────────────────────────────────
|
||||
|
||||
(define
|
||||
hs-socket-register!
|
||||
(fn
|
||||
(name-path url timeout-ms handler json?)
|
||||
;; 1. Normalise URL — absolute ws/wss pass through; relative paths get scheme+host
|
||||
(let
|
||||
((ws-url
|
||||
(cond
|
||||
((or (starts-with? url "ws://") (starts-with? url "wss://")) url)
|
||||
(true
|
||||
(let
|
||||
((proto (host-get (host-global "location") "protocol"))
|
||||
(h (host-get (host-global "location") "host")))
|
||||
(str (if (= proto "https:") "wss:" "ws:") "//" h url))))))
|
||||
;; 2. Construct WebSocket
|
||||
(let
|
||||
((ws (host-new "WebSocket" ws-url)))
|
||||
;; 3. Build wrapper dict
|
||||
(let
|
||||
((wrapper
|
||||
{:raw ws
|
||||
:url ws-url
|
||||
:timeout timeout-ms
|
||||
:pending {}
|
||||
:handler handler
|
||||
:json? json?
|
||||
:closed? false}))
|
||||
;; 4. Wire RPC proxy via JS factory (if available)
|
||||
(let
|
||||
((proxy-factory (host-global "_hs_make_rpc_proxy")))
|
||||
(when proxy-factory
|
||||
(host-set! wrapper "rpc"
|
||||
(host-call proxy-factory "call" nil wrapper))))
|
||||
;; 5. Bind wrapper on window, walking name-path
|
||||
(define
|
||||
bind-path!
|
||||
(fn
|
||||
(obj path)
|
||||
(if
|
||||
(= (len path) 1)
|
||||
(host-set! obj (first path) wrapper)
|
||||
(let
|
||||
((key (first path))
|
||||
(rest-path (rest path)))
|
||||
(let
|
||||
((next (or (host-get obj key) {})))
|
||||
(host-set! obj key next)
|
||||
(bind-path! next rest-path))))))
|
||||
(bind-path! (host-global "window") name-path)
|
||||
wrapper)))))
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -441,7 +441,11 @@
|
||||
(cond
|
||||
(and (= ch "-") (< (+ pos 1) src-len) (= (hs-peek 1) "-"))
|
||||
(do (hs-advance! 2) (skip-comment!) (scan!))
|
||||
(and (= ch "/") (< (+ pos 1) src-len) (= (hs-peek 1) "/"))
|
||||
(and
|
||||
(= ch "/")
|
||||
(< (+ pos 1) src-len)
|
||||
(= (hs-peek 1) "/")
|
||||
(not (and (> pos 0) (= (hs-peek -1) ":"))))
|
||||
(do (hs-advance! 2) (skip-comment!) (scan!))
|
||||
(and
|
||||
(= ch "<")
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user