Previously defhandler routed to sf-define which tried to evaluate (&key ...) params as expressions. Now each form has its own spec with parse-key-params and platform constructors. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
119 lines
4.7 KiB
Plaintext
119 lines
4.7 KiB
Plaintext
;; ==========================================================================
|
|
;; forms.sx — Server-side definition forms
|
|
;;
|
|
;; Platform-specific special forms for declaring handlers, pages, queries,
|
|
;; and actions. These parse &key parameter lists and create typed definition
|
|
;; objects that the server runtime uses for routing and execution.
|
|
;;
|
|
;; When SX moves to isomorphic execution, these forms will have different
|
|
;; platform bindings on client vs server. The spec stays the same — only
|
|
;; the constructors (make-handler-def, make-query-def, etc.) change.
|
|
;;
|
|
;; Platform functions required:
|
|
;; make-handler-def(name, params, body, env) → HandlerDef
|
|
;; make-query-def(name, params, doc, body, env) → QueryDef
|
|
;; make-action-def(name, params, doc, body, env) → ActionDef
|
|
;; make-page-def(name, slots, env) → PageDef
|
|
;; ==========================================================================
|
|
|
|
|
|
;; --------------------------------------------------------------------------
|
|
;; Shared: parse (&key param1 param2 ...) → list of param name strings
|
|
;; --------------------------------------------------------------------------
|
|
|
|
(define parse-key-params
|
|
(fn (params-expr)
|
|
(let ((params (list))
|
|
(in-key false))
|
|
(for-each
|
|
(fn (p)
|
|
(when (= (type-of p) "symbol")
|
|
(let ((name (symbol-name p)))
|
|
(cond
|
|
(= name "&key") (set! in-key true)
|
|
in-key (append! params name)
|
|
:else (append! params name)))))
|
|
params-expr)
|
|
params)))
|
|
|
|
|
|
;; --------------------------------------------------------------------------
|
|
;; defhandler — (defhandler name (&key param...) body)
|
|
;; --------------------------------------------------------------------------
|
|
|
|
(define sf-defhandler
|
|
(fn (args env)
|
|
(let ((name-sym (first args))
|
|
(params-raw (nth args 1))
|
|
(body (nth args 2))
|
|
(name (symbol-name name-sym))
|
|
(params (parse-key-params params-raw)))
|
|
(let ((hdef (make-handler-def name params body env)))
|
|
(env-set! env (str "handler:" name) hdef)
|
|
hdef))))
|
|
|
|
|
|
;; --------------------------------------------------------------------------
|
|
;; defquery — (defquery name (&key param...) "docstring" body)
|
|
;; --------------------------------------------------------------------------
|
|
|
|
(define sf-defquery
|
|
(fn (args env)
|
|
(let ((name-sym (first args))
|
|
(params-raw (nth args 1))
|
|
(name (symbol-name name-sym))
|
|
(params (parse-key-params params-raw))
|
|
;; Optional docstring before body
|
|
(has-doc (and (>= (len args) 4) (= (type-of (nth args 2)) "string")))
|
|
(doc (if has-doc (nth args 2) ""))
|
|
(body (if has-doc (nth args 3) (nth args 2))))
|
|
(let ((qdef (make-query-def name params doc body env)))
|
|
(env-set! env (str "query:" name) qdef)
|
|
qdef))))
|
|
|
|
|
|
;; --------------------------------------------------------------------------
|
|
;; defaction — (defaction name (&key param...) "docstring" body)
|
|
;; --------------------------------------------------------------------------
|
|
|
|
(define sf-defaction
|
|
(fn (args env)
|
|
(let ((name-sym (first args))
|
|
(params-raw (nth args 1))
|
|
(name (symbol-name name-sym))
|
|
(params (parse-key-params params-raw))
|
|
(has-doc (and (>= (len args) 4) (= (type-of (nth args 2)) "string")))
|
|
(doc (if has-doc (nth args 2) ""))
|
|
(body (if has-doc (nth args 3) (nth args 2))))
|
|
(let ((adef (make-action-def name params doc body env)))
|
|
(env-set! env (str "action:" name) adef)
|
|
adef))))
|
|
|
|
|
|
;; --------------------------------------------------------------------------
|
|
;; defpage — (defpage name :path "/..." :auth :public :content expr ...)
|
|
;;
|
|
;; Keyword-slot form: all values after the name are :key value pairs.
|
|
;; Values are stored as unevaluated AST — resolved at request time.
|
|
;; --------------------------------------------------------------------------
|
|
|
|
(define sf-defpage
|
|
(fn (args env)
|
|
(let ((name-sym (first args))
|
|
(name (symbol-name name-sym))
|
|
(slots {}))
|
|
;; Parse keyword slots from remaining args
|
|
(let ((i 1)
|
|
(max-i (len args)))
|
|
(for-each
|
|
(fn (idx)
|
|
(when (and (< idx max-i)
|
|
(= (type-of (nth args idx)) "keyword"))
|
|
(when (< (+ idx 1) max-i)
|
|
(dict-set! slots (keyword-name (nth args idx))
|
|
(nth args (+ idx 1))))))
|
|
(range 1 max-i 2)))
|
|
(let ((pdef (make-page-def name slots env)))
|
|
(env-set! env (str "page:" name) pdef)
|
|
pdef))))
|