Refactor SX primitives: modular, isomorphic, general-purpose
Spec modularization: - Add (define-module :name) markers to primitives.sx creating 11 modules (7 core, 4 stdlib). Bootstrappers can now selectively include modules. - Add parse_primitives_by_module() to boundary_parser.py. - Remove split-ids primitive; inline at 4 call sites in blog/market queries. Python file split: - primitives.py: slimmed to registry + core primitives only (~350 lines) - primitives_stdlib.py: NEW — stdlib primitives (format, text, style, debug) - primitives_ctx.py: NEW — extracted 12 page context builders from IO - primitives_io.py: add register_io_handler decorator, auto-derive IO_PRIMITIVES from registry, move sync IO bridges here JS parity fixes: - = uses === (strict equality), != uses !== - round supports optional ndigits parameter - concat uses nil-check not falsy-check (preserves 0, "", false) - escape adds single quote entity (') matching Python/markupsafe - assert added (was missing from JS entirely) Bootstrapper modularization: - PRIMITIVES_JS_MODULES / PRIMITIVES_PY_MODULES dicts keyed by module - --modules CLI flag for selective inclusion (core.* always included) - Regenerated sx-ref.js and sx_ref.py with all fixes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -42,17 +42,44 @@ def _extract_keyword_arg(expr: list, key: str) -> Any:
|
||||
|
||||
def parse_primitives_sx() -> frozenset[str]:
|
||||
"""Parse primitives.sx and return frozenset of declared pure primitive names."""
|
||||
by_module = parse_primitives_by_module()
|
||||
all_names: set[str] = set()
|
||||
for names in by_module.values():
|
||||
all_names.update(names)
|
||||
return frozenset(all_names)
|
||||
|
||||
|
||||
def parse_primitives_by_module() -> dict[str, frozenset[str]]:
|
||||
"""Parse primitives.sx and return primitives grouped by module.
|
||||
|
||||
Returns:
|
||||
Dict mapping module name (e.g. "core.arithmetic") to frozenset of
|
||||
primitive names declared under that module.
|
||||
"""
|
||||
source = _read_file("primitives.sx")
|
||||
exprs = parse_all(source)
|
||||
names: set[str] = set()
|
||||
modules: dict[str, set[str]] = {}
|
||||
current_module = "_unscoped"
|
||||
|
||||
for expr in exprs:
|
||||
if (isinstance(expr, list) and len(expr) >= 2
|
||||
and isinstance(expr[0], Symbol)
|
||||
and expr[0].name == "define-primitive"):
|
||||
if not isinstance(expr, list) or len(expr) < 2:
|
||||
continue
|
||||
if not isinstance(expr[0], Symbol):
|
||||
continue
|
||||
|
||||
if expr[0].name == "define-module":
|
||||
mod_name = expr[1]
|
||||
if isinstance(mod_name, Keyword):
|
||||
current_module = mod_name.name
|
||||
elif isinstance(mod_name, str):
|
||||
current_module = mod_name
|
||||
|
||||
elif expr[0].name == "define-primitive":
|
||||
name = expr[1]
|
||||
if isinstance(name, str):
|
||||
names.add(name)
|
||||
return frozenset(names)
|
||||
modules.setdefault(current_module, set()).add(name)
|
||||
|
||||
return {mod: frozenset(names) for mod, names in modules.items()}
|
||||
|
||||
|
||||
def parse_boundary_sx() -> tuple[frozenset[str], dict[str, frozenset[str]]]:
|
||||
|
||||
Reference in New Issue
Block a user