Add Special Forms docs page at /docs/special-forms
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 3m54s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 3m54s
Parses special-forms.sx spec into categorized form cards with syntax, description, tail-position info, and highlighted examples. Follows the same pattern as the Primitives page: Python helper returns structured data, .sx components render it. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -293,6 +293,11 @@
|
|||||||
:returns "dict"
|
:returns "dict"
|
||||||
:service "sx")
|
:service "sx")
|
||||||
|
|
||||||
|
(define-page-helper "special-forms-data"
|
||||||
|
:params ()
|
||||||
|
:returns "dict"
|
||||||
|
:service "sx")
|
||||||
|
|
||||||
(define-page-helper "reference-data"
|
(define-page-helper "reference-data"
|
||||||
:params (slug)
|
:params (slug)
|
||||||
:returns "dict"
|
:returns "dict"
|
||||||
|
|||||||
@@ -76,6 +76,15 @@
|
|||||||
"sx provides ~80 built-in pure functions. They work identically on server (Python) and client (JavaScript).")
|
"sx provides ~80 built-in pure functions. They work identically on server (Python) and client (JavaScript).")
|
||||||
(div :class "space-y-6" prims))))
|
(div :class "space-y-6" prims))))
|
||||||
|
|
||||||
|
(defcomp ~docs-special-forms-content (&key forms)
|
||||||
|
(~doc-page :title "Special Forms"
|
||||||
|
(~doc-section :title "Syntactic constructs" :id "special-forms"
|
||||||
|
(p :class "text-stone-600"
|
||||||
|
"Special forms are syntactic constructs whose arguments are NOT evaluated before dispatch. Each form has its own evaluation rules — unlike primitives, which receive pre-evaluated values. Together with primitives, special forms define the complete language surface.")
|
||||||
|
(p :class "text-stone-600"
|
||||||
|
"Forms marked with a tail position enable " (a :href "/essays/tco" :class "text-violet-600 hover:underline" "tail-call optimization") " — recursive calls in tail position use constant stack space.")
|
||||||
|
(div :class "space-y-10" forms))))
|
||||||
|
|
||||||
(defcomp ~docs-css-content ()
|
(defcomp ~docs-css-content ()
|
||||||
(~doc-page :title "On-Demand CSS"
|
(~doc-page :title "On-Demand CSS"
|
||||||
(~doc-section :title "How it works" :id "how"
|
(~doc-section :title "How it works" :id "how"
|
||||||
|
|||||||
@@ -123,3 +123,40 @@
|
|||||||
:category cat
|
:category cat
|
||||||
:primitives (get primitives cat)))
|
:primitives (get primitives cat)))
|
||||||
(keys primitives))))
|
(keys primitives))))
|
||||||
|
|
||||||
|
;; Build all special form category sections from a {category: [form, ...]} dict.
|
||||||
|
(defcomp ~doc-special-forms-tables (&key forms)
|
||||||
|
(<> (map (fn (cat)
|
||||||
|
(~doc-special-forms-category
|
||||||
|
:category cat
|
||||||
|
:forms (get forms cat)))
|
||||||
|
(keys forms))))
|
||||||
|
|
||||||
|
(defcomp ~doc-special-forms-category (&key category forms)
|
||||||
|
(div :class "space-y-4"
|
||||||
|
(h3 :class "text-xl font-semibold text-stone-800 border-b border-stone-200 pb-2" category)
|
||||||
|
(div :class "space-y-4"
|
||||||
|
(map (fn (f)
|
||||||
|
(~doc-special-form-card
|
||||||
|
:name (get f "name")
|
||||||
|
:syntax (get f "syntax")
|
||||||
|
:doc (get f "doc")
|
||||||
|
:tail-position (get f "tail-position")
|
||||||
|
:example (get f "example")))
|
||||||
|
forms))))
|
||||||
|
|
||||||
|
(defcomp ~doc-special-form-card (&key name syntax doc tail-position example)
|
||||||
|
(div :class "border border-stone-200 rounded-lg p-4 space-y-3"
|
||||||
|
(div :class "flex items-baseline gap-3"
|
||||||
|
(code :class "text-lg font-bold text-violet-700" name)
|
||||||
|
(when (not (= tail-position "none"))
|
||||||
|
(span :class "text-xs px-2 py-0.5 rounded-full bg-green-100 text-green-700" "TCO")))
|
||||||
|
(when (not (= syntax ""))
|
||||||
|
(pre :class "bg-stone-50 rounded px-3 py-2 text-sm font-mono text-stone-700 overflow-x-auto"
|
||||||
|
syntax))
|
||||||
|
(p :class "text-stone-600 text-sm whitespace-pre-line" doc)
|
||||||
|
(when (not (= tail-position ""))
|
||||||
|
(p :class "text-xs text-stone-500"
|
||||||
|
(span :class "font-semibold" "Tail position: ") tail-position))
|
||||||
|
(when (not (= example ""))
|
||||||
|
(~doc-code :code (highlight example "lisp")))))
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
(dict :label "Components" :href "/docs/components")
|
(dict :label "Components" :href "/docs/components")
|
||||||
(dict :label "Evaluator" :href "/docs/evaluator")
|
(dict :label "Evaluator" :href "/docs/evaluator")
|
||||||
(dict :label "Primitives" :href "/docs/primitives")
|
(dict :label "Primitives" :href "/docs/primitives")
|
||||||
|
(dict :label "Special Forms" :href "/docs/special-forms")
|
||||||
(dict :label "CSS" :href "/docs/css")
|
(dict :label "CSS" :href "/docs/css")
|
||||||
(dict :label "Server Rendering" :href "/docs/server-rendering")))
|
(dict :label "Server Rendering" :href "/docs/server-rendering")))
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,8 @@
|
|||||||
"evaluator" (~docs-evaluator-content)
|
"evaluator" (~docs-evaluator-content)
|
||||||
"primitives" (~docs-primitives-content
|
"primitives" (~docs-primitives-content
|
||||||
:prims (~doc-primitives-tables :primitives (primitives-data)))
|
:prims (~doc-primitives-tables :primitives (primitives-data)))
|
||||||
|
"special-forms" (~docs-special-forms-content
|
||||||
|
:forms (~doc-special-forms-tables :forms (special-forms-data)))
|
||||||
"css" (~docs-css-content)
|
"css" (~docs-css-content)
|
||||||
"server-rendering" (~docs-server-rendering-content)
|
"server-rendering" (~docs-server-rendering-content)
|
||||||
:else (~docs-introduction-content)))
|
:else (~docs-introduction-content)))
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ def _register_sx_helpers() -> None:
|
|||||||
register_page_helpers("sx", {
|
register_page_helpers("sx", {
|
||||||
"highlight": _highlight,
|
"highlight": _highlight,
|
||||||
"primitives-data": _primitives_data,
|
"primitives-data": _primitives_data,
|
||||||
|
"special-forms-data": _special_forms_data,
|
||||||
"reference-data": _reference_data,
|
"reference-data": _reference_data,
|
||||||
"attr-detail-data": _attr_detail_data,
|
"attr-detail-data": _attr_detail_data,
|
||||||
"header-detail-data": _header_detail_data,
|
"header-detail-data": _header_detail_data,
|
||||||
@@ -29,6 +30,89 @@ def _primitives_data() -> dict:
|
|||||||
return PRIMITIVES
|
return PRIMITIVES
|
||||||
|
|
||||||
|
|
||||||
|
def _special_forms_data() -> dict:
|
||||||
|
"""Parse special-forms.sx and return categorized form data.
|
||||||
|
|
||||||
|
Returns a dict of category → list of form dicts, each with:
|
||||||
|
name, syntax, doc, tail_position, example
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
from shared.sx.parser import parse_all, serialize
|
||||||
|
from shared.sx.types import Symbol, Keyword
|
||||||
|
|
||||||
|
spec_path = os.path.join(
|
||||||
|
os.path.dirname(os.path.abspath(__file__)),
|
||||||
|
"..", "..", "..", "shared", "sx", "ref", "special-forms.sx",
|
||||||
|
)
|
||||||
|
with open(spec_path) as f:
|
||||||
|
exprs = parse_all(f.read())
|
||||||
|
|
||||||
|
# Categories inferred from comment sections in the file.
|
||||||
|
# We assign forms to categories based on their order in the spec.
|
||||||
|
categories: dict[str, list[dict]] = {}
|
||||||
|
current_category = "Other"
|
||||||
|
|
||||||
|
# Map form names to categories
|
||||||
|
category_map = {
|
||||||
|
"if": "Control Flow", "when": "Control Flow", "cond": "Control Flow",
|
||||||
|
"case": "Control Flow", "and": "Control Flow", "or": "Control Flow",
|
||||||
|
"let": "Binding", "let*": "Binding", "letrec": "Binding",
|
||||||
|
"define": "Binding", "set!": "Binding",
|
||||||
|
"lambda": "Functions & Components", "fn": "Functions & Components",
|
||||||
|
"defcomp": "Functions & Components", "defmacro": "Functions & Components",
|
||||||
|
"begin": "Sequencing & Threading", "do": "Sequencing & Threading",
|
||||||
|
"->": "Sequencing & Threading",
|
||||||
|
"quote": "Quoting", "quasiquote": "Quoting",
|
||||||
|
"reset": "Continuations", "shift": "Continuations",
|
||||||
|
"dynamic-wind": "Guards",
|
||||||
|
"map": "Higher-Order Forms", "map-indexed": "Higher-Order Forms",
|
||||||
|
"filter": "Higher-Order Forms", "reduce": "Higher-Order Forms",
|
||||||
|
"some": "Higher-Order Forms", "every?": "Higher-Order Forms",
|
||||||
|
"for-each": "Higher-Order Forms",
|
||||||
|
"defstyle": "Domain Definitions", "defkeyframes": "Domain Definitions",
|
||||||
|
"defhandler": "Domain Definitions", "defpage": "Domain Definitions",
|
||||||
|
"defquery": "Domain Definitions", "defaction": "Domain Definitions",
|
||||||
|
}
|
||||||
|
|
||||||
|
for expr in exprs:
|
||||||
|
if not isinstance(expr, list) or len(expr) < 2:
|
||||||
|
continue
|
||||||
|
head = expr[0]
|
||||||
|
if not isinstance(head, Symbol) or head.name != "define-special-form":
|
||||||
|
continue
|
||||||
|
|
||||||
|
name = expr[1]
|
||||||
|
# Extract keyword args
|
||||||
|
kwargs: dict[str, str] = {}
|
||||||
|
i = 2
|
||||||
|
while i < len(expr) - 1:
|
||||||
|
if isinstance(expr[i], Keyword):
|
||||||
|
key = expr[i].name
|
||||||
|
val = expr[i + 1]
|
||||||
|
if isinstance(val, list):
|
||||||
|
# For :syntax, avoid quote sugar (quasiquote → `x)
|
||||||
|
items = [serialize(item) for item in val]
|
||||||
|
kwargs[key] = "(" + " ".join(items) + ")"
|
||||||
|
else:
|
||||||
|
kwargs[key] = str(val)
|
||||||
|
i += 2
|
||||||
|
else:
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
category = category_map.get(name, "Other")
|
||||||
|
if category not in categories:
|
||||||
|
categories[category] = []
|
||||||
|
categories[category].append({
|
||||||
|
"name": name,
|
||||||
|
"syntax": kwargs.get("syntax", ""),
|
||||||
|
"doc": kwargs.get("doc", ""),
|
||||||
|
"tail-position": kwargs.get("tail-position", ""),
|
||||||
|
"example": kwargs.get("example", ""),
|
||||||
|
})
|
||||||
|
|
||||||
|
return categories
|
||||||
|
|
||||||
|
|
||||||
def _reference_data(slug: str) -> dict:
|
def _reference_data(slug: str) -> dict:
|
||||||
"""Return reference table data for a given slug.
|
"""Return reference table data for a given slug.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user