Add (param :as type) annotations to all fn/lambda params across SX spec

Extend the type annotation system from defcomp-only to fn/lambda params:
- Infrastructure: sf-lambda, py/js-collect-params-loop, and bootstrap_py.py
  now recognize (name :as type) in param lists, extracting just the name
- bootstrap_py.py: add _extract_param_name() helper, fix _emit_for_each_stmt
- 521 type annotations across 22 .sx spec files (eval, types, adapters,
  transpilers, engine, orchestration, deps, signals, router, prove, etc.)
- Zero behavioral change: annotations are metadata for static analysis only
- All bootstrappers (Python, JS, G1) pass, 81/81 spec tests pass

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-11 20:27:36 +00:00
parent c82941d93c
commit b99e69d1bb
23 changed files with 532 additions and 498 deletions

View File

@@ -253,7 +253,7 @@
;; --------------------------------------------------------------------------
(define py-mangle
(fn (name)
(fn ((name :as string))
(let ((renamed (get py-renames name)))
(if (not (nil? renamed))
renamed
@@ -279,7 +279,7 @@
;; --------------------------------------------------------------------------
(define py-quote-string
(fn (s)
(fn ((s :as string))
;; Produce a Python repr-style string literal
(str "'" (replace (replace (replace (replace s "\\" "\\\\") "'" "\\'") "\n" "\\n") "\t" "\\t") "'")))
@@ -292,11 +292,11 @@
(list "+" "-" "*" "/" "=" "!=" "<" ">" "<=" ">=" "mod"))
(define py-infix?
(fn (op)
(fn ((op :as string))
(some (fn (x) (= x op)) py-infix-ops)))
(define py-op-symbol
(fn (op)
(fn ((op :as string))
(case op
"=" "=="
"!=" "!="
@@ -309,7 +309,7 @@
;; --------------------------------------------------------------------------
(define py-find-nested-set-vars
(fn (body)
(fn ((body :as list))
;; Returns a list of mangled variable names that are set! from within
;; nested fn/lambda bodies
(let ((result (list)))
@@ -318,7 +318,7 @@
result))))
(define py-scan-set-vars
(fn (node in-nested result)
(fn (node (in-nested :as boolean) (result :as list))
(when (and (list? node) (not (empty? node)))
(let ((head (first node)))
(cond
@@ -353,7 +353,7 @@
(py-has-set? body))))
(define py-has-set?
(fn (nodes)
(fn ((nodes :as list))
(some (fn (node)
(and (list? node)
(not (empty? node))
@@ -372,7 +372,7 @@
(py-expr-with-cells expr (list))))
(define py-expr-with-cells
(fn (expr cell-vars)
(fn (expr (cell-vars :as list))
(cond
;; Bool MUST come before number check (Python: bool is subclass of int)
(= (type-of expr) "boolean")
@@ -417,7 +417,7 @@
;; --------------------------------------------------------------------------
(define py-emit-native-dict
(fn (d cell-vars)
(fn ((d :as dict) (cell-vars :as list))
(let ((items (keys d)))
(str "{" (join ", " (map (fn (k)
(str (py-quote-string k) ": " (py-expr-with-cells (get d k) cell-vars)))
@@ -429,7 +429,7 @@
;; --------------------------------------------------------------------------
(define py-emit-list
(fn (expr cell-vars)
(fn (expr (cell-vars :as list))
(let ((head (first expr))
(args (rest expr)))
(if (not (= (type-of head) "symbol"))
@@ -548,7 +548,7 @@
;; --------------------------------------------------------------------------
(define py-emit-fn
(fn (expr cell-vars)
(fn (expr (cell-vars :as list))
(let ((params (nth expr 1))
(body (rest (rest expr)))
(param-strs (py-collect-params params)))
@@ -562,11 +562,11 @@
"\n)[-1])"))))))
(define py-collect-params
(fn (params)
(fn ((params :as list))
(py-collect-params-loop params 0 (list))))
(define py-collect-params-loop
(fn (params i result)
(fn ((params :as list) (i :as number) (result :as list))
(if (>= i (len params))
result
(let ((p (nth params i)))
@@ -574,13 +574,25 @@
;; &rest marker
(and (= (type-of p) "symbol") (= (symbol-name p) "&rest"))
(if (< (+ i 1) (len params))
(py-collect-params-loop params (+ i 2)
(append result (str "*" (py-mangle (symbol-name (nth params (+ i 1)))))))
(let ((rp (nth params (+ i 1))))
(py-collect-params-loop params (+ i 2)
(append result (str "*" (py-mangle
(if (and (= (type-of rp) "list") (= (len rp) 3)
(= (type-of (nth rp 1)) "keyword")
(= (keyword-name (nth rp 1)) "as"))
(symbol-name (first rp))
(if (= (type-of rp) "symbol") (symbol-name rp) (str rp))))))))
(py-collect-params-loop params (+ i 1) result))
;; Normal param
(= (type-of p) "symbol")
(py-collect-params-loop params (+ i 1)
(append result (py-mangle (symbol-name p))))
;; Annotated param: (name :as type) → extract name
(and (= (type-of p) "list") (= (len p) 3)
(= (type-of (nth p 1)) "keyword")
(= (keyword-name (nth p 1)) "as"))
(py-collect-params-loop params (+ i 1)
(append result (py-mangle (symbol-name (first p)))))
;; Something else
:else
(py-collect-params-loop params (+ i 1)
@@ -592,7 +604,7 @@
;; --------------------------------------------------------------------------
(define py-emit-let
(fn (expr cell-vars)
(fn (expr (cell-vars :as list))
(let ((bindings (nth expr 1))
(body (rest (rest expr))))
(let ((assignments (py-parse-bindings bindings cell-vars)))
@@ -603,7 +615,7 @@
(py-wrap-let-bindings assignments body-str cell-vars))))))
(define py-parse-bindings
(fn (bindings cell-vars)
(fn (bindings (cell-vars :as list))
(if (and (list? bindings) (not (empty? bindings)))
(if (list? (first bindings))
;; Scheme-style: ((name val) ...)
@@ -618,7 +630,7 @@
(list))))
(define py-parse-clojure-bindings
(fn (bindings i result cell-vars)
(fn (bindings (i :as number) (result :as list) (cell-vars :as list))
(if (>= i (- (len bindings) 1))
result
(let ((vname (if (= (type-of (nth bindings i)) "symbol")
@@ -629,7 +641,7 @@
cell-vars)))))
(define py-wrap-let-bindings
(fn (assignments body-str cell-vars)
(fn ((assignments :as list) (body-str :as string) (cell-vars :as list))
(if (empty? assignments)
body-str
(let ((binding (last assignments))
@@ -649,7 +661,7 @@
;; --------------------------------------------------------------------------
(define py-emit-when
(fn (expr cell-vars)
(fn (expr (cell-vars :as list))
(let ((cond-e (py-expr-with-cells (nth expr 1) cell-vars))
(body-parts (rest (rest expr))))
(if (= (len body-parts) 1)
@@ -663,7 +675,7 @@
;; --------------------------------------------------------------------------
(define py-emit-cond
(fn (clauses cell-vars)
(fn ((clauses :as list) (cell-vars :as list))
(if (empty? clauses)
"NIL"
;; Detect scheme vs clojure style
@@ -681,7 +693,7 @@
(and (= (type-of test) "keyword") (= (keyword-name test) "else")))))
(define py-cond-scheme
(fn (clauses cell-vars)
(fn ((clauses :as list) (cell-vars :as list))
(if (empty? clauses)
"NIL"
(let ((clause (first clauses))
@@ -694,7 +706,7 @@
") else " (py-cond-scheme (rest clauses) cell-vars) ")"))))))
(define py-cond-clojure
(fn (clauses cell-vars)
(fn ((clauses :as list) (cell-vars :as list))
(if (< (len clauses) 2)
"NIL"
(let ((test (first clauses))
@@ -711,17 +723,17 @@
;; --------------------------------------------------------------------------
(define py-emit-case
(fn (args cell-vars)
(fn ((args :as list) (cell-vars :as list))
(let ((match-expr (py-expr-with-cells (first args) cell-vars))
(clauses (rest args)))
(str "_sx_case(" match-expr ", [" (py-case-pairs clauses cell-vars) "])"))))
(define py-case-pairs
(fn (clauses cell-vars)
(fn ((clauses :as list) (cell-vars :as list))
(py-case-pairs-loop clauses 0 (list) cell-vars)))
(define py-case-pairs-loop
(fn (clauses i result cell-vars)
(fn ((clauses :as list) (i :as number) (result :as list) (cell-vars :as list))
(if (>= i (- (len clauses) 1))
(join ", " result)
(let ((test (nth clauses i))
@@ -738,28 +750,28 @@
;; --------------------------------------------------------------------------
(define py-emit-and
(fn (args cell-vars)
(fn ((args :as list) (cell-vars :as list))
(let ((parts (map (fn (x) (py-expr-with-cells x cell-vars)) args)))
(if (= (len parts) 1)
(first parts)
(py-and-chain parts)))))
(define py-and-chain
(fn (parts)
(fn ((parts :as list))
(if (= (len parts) 1)
(first parts)
(let ((p (first parts)))
(str "(" p " if not sx_truthy(" p ") else " (py-and-chain (rest parts)) ")")))))
(define py-emit-or
(fn (args cell-vars)
(fn ((args :as list) (cell-vars :as list))
(if (= (len args) 1)
(py-expr-with-cells (first args) cell-vars)
(let ((parts (map (fn (x) (py-expr-with-cells x cell-vars)) args)))
(py-or-chain parts)))))
(define py-or-chain
(fn (parts)
(fn ((parts :as list))
(if (= (len parts) 1)
(first parts)
(let ((p (first parts)))
@@ -771,7 +783,7 @@
;; --------------------------------------------------------------------------
(define py-emit-do
(fn (args cell-vars)
(fn ((args :as list) (cell-vars :as list))
(if (= (len args) 1)
(py-expr-with-cells (first args) cell-vars)
(str "_sx_begin(" (join ", " (map (fn (e) (py-expr-with-cells e cell-vars)) args)) ")"))))
@@ -782,11 +794,11 @@
;; --------------------------------------------------------------------------
(define py-emit-dict-literal
(fn (pairs cell-vars)
(fn ((pairs :as list) (cell-vars :as list))
(str "{" (py-dict-pairs-str pairs 0 (list) cell-vars) "}")))
(define py-dict-pairs-str
(fn (pairs i result cell-vars)
(fn ((pairs :as list) (i :as number) (result :as list) (cell-vars :as list))
(if (>= i (- (len pairs) 1))
(join ", " result)
(let ((key (nth pairs i))
@@ -805,7 +817,7 @@
;; --------------------------------------------------------------------------
(define py-emit-infix
(fn (op args cell-vars)
(fn ((op :as string) (args :as list) (cell-vars :as list))
(let ((py-op (py-op-symbol op)))
(if (and (= (len args) 1) (= op "-"))
(str "(-" (py-expr-with-cells (first args) cell-vars) ")")
@@ -839,15 +851,15 @@
;; --------------------------------------------------------------------------
(define py-pad
(fn (indent)
(fn ((indent :as number))
(join "" (map (fn (i) " ") (range 0 indent)))))
(define py-statement
(fn (expr indent)
(fn (expr (indent :as number))
(py-statement-with-cells expr indent (list))))
(define py-statement-with-cells
(fn (expr indent cell-vars)
(fn (expr (indent :as number) (cell-vars :as list))
(let ((pad (py-pad indent)))
(if (and (list? expr) (not (empty? expr))
(= (type-of (first expr)) "symbol"))
@@ -889,7 +901,7 @@
;; --------------------------------------------------------------------------
(define py-emit-define
(fn (expr indent cell-vars)
(fn (expr (indent :as number) (cell-vars :as list))
(let ((pad (py-pad indent))
(name (if (= (type-of (nth expr 1)) "symbol")
(symbol-name (nth expr 1))
@@ -911,7 +923,7 @@
;; --------------------------------------------------------------------------
(define py-emit-define-as-def
(fn (name fn-expr indent)
(fn ((name :as string) fn-expr (indent :as number))
(let ((pad (py-pad indent))
(params (nth fn-expr 1))
(body (rest (rest fn-expr)))
@@ -932,13 +944,13 @@
;; --------------------------------------------------------------------------
(define py-emit-body-stmts
(fn (body lines indent cell-vars)
(fn ((body :as list) (lines :as list) (indent :as number) (cell-vars :as list))
(let ((pad (py-pad indent))
(total (len body)))
(py-emit-body-stmts-loop body lines indent cell-vars 0 total pad))))
(define py-emit-body-stmts-loop
(fn (body lines indent cell-vars i total pad)
(fn ((body :as list) (lines :as list) (indent :as number) (cell-vars :as list) (i :as number) (total :as number) (pad :as string))
(when (< i total)
(let ((expr (nth body i))
(is-last (= i (- total 1))))
@@ -968,7 +980,7 @@
;; --------------------------------------------------------------------------
(define py-emit-let-as-stmts
(fn (expr lines indent is-last cell-vars)
(fn (expr (lines :as list) (indent :as number) (is-last :as boolean) (cell-vars :as list))
(let ((pad (py-pad indent))
(bindings (nth expr 1))
(body (rest (rest expr))))
@@ -981,7 +993,7 @@
(for-each (fn (b) (py-emit-stmt-recursive b lines indent cell-vars)) body))))))
(define py-emit-binding-assignments
(fn (bindings lines indent cell-vars)
(fn (bindings (lines :as list) (indent :as number) (cell-vars :as list))
(let ((pad (py-pad indent)))
(when (and (list? bindings) (not (empty? bindings)))
(if (list? (first bindings))
@@ -1002,7 +1014,7 @@
(py-emit-clojure-binding-assignments bindings lines indent 0 cell-vars))))))
(define py-emit-clojure-binding-assignments
(fn (bindings lines indent i cell-vars)
(fn (bindings (lines :as list) (indent :as number) (i :as number) (cell-vars :as list))
(let ((pad (py-pad indent)))
(when (< i (- (len bindings) 1))
(let ((vname (if (= (type-of (nth bindings i)) "symbol")
@@ -1024,7 +1036,7 @@
;; --------------------------------------------------------------------------
(define py-emit-stmt-recursive
(fn (expr lines indent cell-vars)
(fn (expr (lines :as list) (indent :as number) (cell-vars :as list))
(let ((pad (py-pad indent)))
(if (not (and (list? expr) (not (empty? expr))))
(append! lines (py-statement-with-cells expr indent cell-vars))
@@ -1082,7 +1094,7 @@
;; --------------------------------------------------------------------------
(define py-emit-cond-stmt
(fn (expr lines indent cell-vars)
(fn (expr (lines :as list) (indent :as number) (cell-vars :as list))
(let ((pad (py-pad indent))
(clauses (rest expr)))
;; Detect scheme vs clojure
@@ -1094,7 +1106,7 @@
(py-cond-stmt-clojure clauses lines indent 0 true cell-vars))))))
(define py-cond-stmt-scheme
(fn (clauses lines indent first-clause cell-vars)
(fn ((clauses :as list) (lines :as list) (indent :as number) (first-clause :as boolean) (cell-vars :as list))
(let ((pad (py-pad indent)))
(when (not (empty? clauses))
(let ((clause (first clauses))
@@ -1111,7 +1123,7 @@
(py-cond-stmt-scheme (rest clauses) lines indent false cell-vars)))))))
(define py-cond-stmt-clojure
(fn (clauses lines indent i first-clause cell-vars)
(fn ((clauses :as list) (lines :as list) (indent :as number) (i :as number) (first-clause :as boolean) (cell-vars :as list))
(let ((pad (py-pad indent)))
(when (< i (- (len clauses) 1))
(let ((test (nth clauses i))
@@ -1132,7 +1144,7 @@
;; --------------------------------------------------------------------------
(define py-emit-when-stmt
(fn (expr indent cell-vars)
(fn (expr (indent :as number) (cell-vars :as list))
(let ((pad (py-pad indent))
(cond-e (py-expr-with-cells (nth expr 1) cell-vars))
(body-parts (rest (rest expr))))
@@ -1146,7 +1158,7 @@
;; --------------------------------------------------------------------------
(define py-emit-for-each-stmt
(fn (expr indent cell-vars)
(fn (expr (indent :as number) (cell-vars :as list))
(let ((pad (py-pad indent))
(fn-expr (nth expr 1))
(coll-expr (nth expr 2))
@@ -1175,7 +1187,7 @@
;; --------------------------------------------------------------------------
(define py-translate-file
(fn (defines)
(fn ((defines :as list))
(join "\n" (map (fn (pair)
(let ((name (first pair))
(expr (nth pair 1)))