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:
@@ -442,6 +442,15 @@ class PyEmitter:
|
||||
|
||||
# --- Special form emitters ---
|
||||
|
||||
@staticmethod
|
||||
def _extract_param_name(p):
|
||||
"""Extract the name from a param, handling (name :as type) annotations."""
|
||||
if isinstance(p, list) and len(p) == 3 and isinstance(p[1], Keyword) and p[1].name == "as":
|
||||
return p[0].name if isinstance(p[0], Symbol) else str(p[0])
|
||||
if isinstance(p, Symbol):
|
||||
return p.name
|
||||
return str(p)
|
||||
|
||||
def _emit_fn(self, expr) -> str:
|
||||
params = expr[1]
|
||||
body = expr[2:]
|
||||
@@ -453,16 +462,13 @@ class PyEmitter:
|
||||
if isinstance(p, Symbol) and p.name == "&rest":
|
||||
# Next param is the rest parameter
|
||||
if i + 1 < len(params):
|
||||
rest_name = self._mangle(params[i + 1].name if isinstance(params[i + 1], Symbol) else str(params[i + 1]))
|
||||
rest_name = self._mangle(self._extract_param_name(params[i + 1]))
|
||||
i += 2
|
||||
continue
|
||||
else:
|
||||
i += 1
|
||||
continue
|
||||
if isinstance(p, Symbol):
|
||||
param_names.append(self._mangle(p.name))
|
||||
else:
|
||||
param_names.append(str(p))
|
||||
param_names.append(self._mangle(self._extract_param_name(p)))
|
||||
i += 1
|
||||
if rest_name:
|
||||
param_names.append(f"*{rest_name}")
|
||||
@@ -708,17 +714,14 @@ class PyEmitter:
|
||||
p = params[i]
|
||||
if isinstance(p, Symbol) and p.name == "&rest":
|
||||
if i + 1 < len(params):
|
||||
rest_name = self._mangle(params[i + 1].name if isinstance(params[i + 1], Symbol) else str(params[i + 1]))
|
||||
rest_name = self._mangle(self._extract_param_name(params[i + 1]))
|
||||
param_names.append(f"*{rest_name}")
|
||||
i += 2
|
||||
continue
|
||||
else:
|
||||
i += 1
|
||||
continue
|
||||
if isinstance(p, Symbol):
|
||||
param_names.append(self._mangle(p.name))
|
||||
else:
|
||||
param_names.append(str(p))
|
||||
param_names.append(self._mangle(self._extract_param_name(p)))
|
||||
i += 1
|
||||
params_str = ", ".join(param_names)
|
||||
py_name = self._mangle(name)
|
||||
@@ -956,7 +959,7 @@ class PyEmitter:
|
||||
if isinstance(fn_expr, list) and isinstance(fn_expr[0], Symbol) and fn_expr[0].name == "fn":
|
||||
params = fn_expr[1]
|
||||
body = fn_expr[2:]
|
||||
p = params[0].name if isinstance(params[0], Symbol) else str(params[0])
|
||||
p = self._extract_param_name(params[0])
|
||||
p_py = self._mangle(p)
|
||||
lines = [f"{pad}for {p_py} in {coll}:"]
|
||||
# Emit body as statements with proper let/set! handling
|
||||
|
||||
Reference in New Issue
Block a user