Add typed params to 67 primitives, implement check-primitive-call
Annotate all primitives in primitives.sx with (:as type) param types where meaningful (67/80 — 13 polymorphic ops stay untyped). Add parse_primitive_param_types() to boundary_parser.py for extraction. Implement check-primitive-call in types.sx with full positional + rest param validation, thread prim-param-types through check-body-walk, check-component, and check-all. 10 new tests (438 total, all pass). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -793,8 +793,95 @@ def _load_types(env):
|
||||
}
|
||||
|
||||
env["test-prim-types"] = _test_prim_types
|
||||
|
||||
# test-prim-param-types: param type signatures for primitive call checking
|
||||
def _test_prim_param_types():
|
||||
# Each entry: {"positional": [["name", "type"|None], ...], "rest-type": "type"|None}
|
||||
return {
|
||||
"+": {"positional": [], "rest-type": "number"},
|
||||
"-": {"positional": [["a", "number"]], "rest-type": "number"},
|
||||
"*": {"positional": [], "rest-type": "number"},
|
||||
"/": {"positional": [["a", "number"], ["b", "number"]], "rest-type": None},
|
||||
"mod": {"positional": [["a", "number"], ["b", "number"]], "rest-type": None},
|
||||
"sqrt": {"positional": [["x", "number"]], "rest-type": None},
|
||||
"pow": {"positional": [["x", "number"], ["n", "number"]], "rest-type": None},
|
||||
"abs": {"positional": [["x", "number"]], "rest-type": None},
|
||||
"floor": {"positional": [["x", "number"]], "rest-type": None},
|
||||
"ceil": {"positional": [["x", "number"]], "rest-type": None},
|
||||
"round": {"positional": [["x", "number"]], "rest-type": "number"},
|
||||
"min": {"positional": [], "rest-type": "number"},
|
||||
"max": {"positional": [], "rest-type": "number"},
|
||||
"clamp": {"positional": [["x", "number"], ["lo", "number"], ["hi", "number"]], "rest-type": None},
|
||||
"inc": {"positional": [["n", "number"]], "rest-type": None},
|
||||
"dec": {"positional": [["n", "number"]], "rest-type": None},
|
||||
"<": {"positional": [["a", "number"], ["b", "number"]], "rest-type": None},
|
||||
">": {"positional": [["a", "number"], ["b", "number"]], "rest-type": None},
|
||||
"<=": {"positional": [["a", "number"], ["b", "number"]], "rest-type": None},
|
||||
">=": {"positional": [["a", "number"], ["b", "number"]], "rest-type": None},
|
||||
"odd?": {"positional": [["n", "number"]], "rest-type": None},
|
||||
"even?": {"positional": [["n", "number"]], "rest-type": None},
|
||||
"zero?": {"positional": [["n", "number"]], "rest-type": None},
|
||||
"upper": {"positional": [["s", "string"]], "rest-type": None},
|
||||
"upcase": {"positional": [["s", "string"]], "rest-type": None},
|
||||
"lower": {"positional": [["s", "string"]], "rest-type": None},
|
||||
"downcase": {"positional": [["s", "string"]], "rest-type": None},
|
||||
"string-length": {"positional": [["s", "string"]], "rest-type": None},
|
||||
"substring": {"positional": [["s", "string"], ["start", "number"], ["end", "number"]], "rest-type": None},
|
||||
"string-contains?": {"positional": [["s", "string"], ["needle", "string"]], "rest-type": None},
|
||||
"trim": {"positional": [["s", "string"]], "rest-type": None},
|
||||
"split": {"positional": [["s", "string"]], "rest-type": "string"},
|
||||
"join": {"positional": [["sep", "string"], ["coll", "list"]], "rest-type": None},
|
||||
"replace": {"positional": [["s", "string"], ["old", "string"], ["new", "string"]], "rest-type": None},
|
||||
"index-of": {"positional": [["s", "string"], ["needle", "string"]], "rest-type": "number"},
|
||||
"starts-with?": {"positional": [["s", "string"], ["prefix", "string"]], "rest-type": None},
|
||||
"ends-with?": {"positional": [["s", "string"], ["suffix", "string"]], "rest-type": None},
|
||||
"concat": {"positional": [], "rest-type": "list"},
|
||||
"range": {"positional": [["start", "number"], ["end", "number"]], "rest-type": "number"},
|
||||
"first": {"positional": [["coll", "list"]], "rest-type": None},
|
||||
"last": {"positional": [["coll", "list"]], "rest-type": None},
|
||||
"rest": {"positional": [["coll", "list"]], "rest-type": None},
|
||||
"nth": {"positional": [["coll", "list"], ["n", "number"]], "rest-type": None},
|
||||
"cons": {"positional": [["x", None], ["coll", "list"]], "rest-type": None},
|
||||
"append": {"positional": [["coll", "list"]], "rest-type": None},
|
||||
"append!": {"positional": [["coll", "list"]], "rest-type": None},
|
||||
"reverse": {"positional": [["coll", "list"]], "rest-type": None},
|
||||
"flatten": {"positional": [["coll", "list"]], "rest-type": None},
|
||||
"chunk-every": {"positional": [["coll", "list"], ["n", "number"]], "rest-type": None},
|
||||
"zip-pairs": {"positional": [["coll", "list"]], "rest-type": None},
|
||||
"keys": {"positional": [["d", "dict"]], "rest-type": None},
|
||||
"vals": {"positional": [["d", "dict"]], "rest-type": None},
|
||||
"merge": {"positional": [], "rest-type": "dict"},
|
||||
"has-key?": {"positional": [["d", "dict"]], "rest-type": None},
|
||||
"assoc": {"positional": [["d", "dict"]], "rest-type": None},
|
||||
"dissoc": {"positional": [["d", "dict"]], "rest-type": None},
|
||||
"dict-set!": {"positional": [["d", "dict"]], "rest-type": None},
|
||||
"format-date": {"positional": [["date-str", "string"], ["fmt", "string"]], "rest-type": None},
|
||||
"format-decimal": {"positional": [["val", "number"]], "rest-type": "number"},
|
||||
"parse-datetime": {"positional": [["s", "string"]], "rest-type": None},
|
||||
"pluralize": {"positional": [["count", "number"]], "rest-type": "string"},
|
||||
"escape": {"positional": [["s", "string"]], "rest-type": None},
|
||||
"strip-tags": {"positional": [["s", "string"]], "rest-type": None},
|
||||
"symbol-name": {"positional": [["sym", "symbol"]], "rest-type": None},
|
||||
"keyword-name": {"positional": [["kw", "keyword"]], "rest-type": None},
|
||||
"sx-parse": {"positional": [["source", "string"]], "rest-type": None},
|
||||
}
|
||||
|
||||
env["test-prim-param-types"] = _test_prim_param_types
|
||||
env["test-env"] = lambda: env
|
||||
|
||||
# Platform functions needed by types.sx check-body-walk
|
||||
if "env-get" not in env:
|
||||
env["env-get"] = lambda e, k: e.get(k) if hasattr(e, 'get') else None
|
||||
if "env-has?" not in env:
|
||||
env["env-has?"] = lambda e, k: k in e
|
||||
if "dict-has?" not in env:
|
||||
env["dict-has?"] = lambda d, k: k in d if isinstance(d, dict) else False
|
||||
if "dict-get" not in env:
|
||||
env["dict-get"] = lambda d, k, *default: d.get(k, default[0] if default else None) if isinstance(d, dict) else (default[0] if default else None)
|
||||
# types.sx uses component-has-children (no ?), test runner has component-has-children?
|
||||
if "component-has-children" not in env:
|
||||
env["component-has-children"] = lambda c: getattr(c, 'has_children', False)
|
||||
|
||||
# Try bootstrapped types first, fall back to eval
|
||||
try:
|
||||
from shared.sx.ref.sx_ref import (
|
||||
|
||||
Reference in New Issue
Block a user