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

- 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:
2026-04-26 09:55:48 +00:00
parent c2dcc94ce2
commit a20c9c4625
15 changed files with 291 additions and 65 deletions

View File

@@ -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)))))