Skip to content

feat: Python bridge via ISC generation - #774

Merged
ronaldtse merged 2 commits into
mainfrom
feat/python-bridge-isc-generator
Sep 29, 2026
Merged

ronaldtse merged 2 commits into
mainfrom
feat/python-bridge-isc-generator

Conversation

@ronaldtse

Copy link
Copy Markdown
Contributor

Fixes 15 of the remaining rake failures (53 dsl_stage Python legs → 18, reversibility 6 → 0, round_trip 9 → 0) — requires interscript/interscript-py#6 to merge first (CI's monorepo bootstrap clones interscript-python main).

The break

The python runtime was rewritten to execute ISC sources from configured load paths. The bridge still targeted the pre-rewrite contract: it wrote generated .py modules into the python package tree and called load_map(name) on them — every Compiler::Python spec leg failed with map 'example-N' not found in load paths (none configured), and the write violated the no-side-effects rule for library packages.

The fix

  • Isc::Generator — serializes a Node::Document back to ISC source (the inverse of Parser + DocumentBuilder + NodeAdapter). Pinned by spec/interscript/isc/generator_spec.rb: every construct round-trips with identical Interpreter behavior (sub with all four constraints, to upcase, parallel, any() sets/ranges, capture+ref, document aliases, multi-stage with same-map runs). Astral code points pass through as raw UTF-8 — surrogate-pair \u escapes are not re-joined by either parser.
  • Bridge — writes the generated ISC to a per-process temp dir registered once via add_load_path, then load_map. No more writes into the python tree. The engine cache is keyed by document identity with eviction on name reuse (synthetic example-N docs would otherwise serve stale engines). sys.path.insert(0, …) so an editable install can't shadow the monorepo checkout; INTERSCRIPT_PYTHON_SRC overrides the path.
  • spec_helper — $compiler resets per example; dsl_stage_spec leaked Compiler::Python into every later file (reversibility's plain .calls were silently rerouted to the python runtime).

The 18 that remain (python engine vocabulary, tracked separately)

capture groups in patterns, aliased captures, non_word_boundary, local/remote alias resolution semantics, any() multi-version replacement (the Ruby any-of-outputs feature), parallel any ordering, title_case/separate with kwargs (no ISC syntax yet).

Verification (local, live PyCall against the rewritten runtime)

  • construct matrix through the real bridge: 10/10 byte-identical with the Interpreter
  • dsl_stage_spec: 159 examples, 18 failures (was 53)
  • reversibility + round_trip + gallery + corpus: all green in combined order (194 examples)

The rewritten python runtime executes ISC sources from configured load
paths; the bridge still wrote generated .py modules into the python
package tree and called load_map on them — every Compiler::Python spec
leg failed with 'map not found in load paths (none configured)'.

In-memory documents now cross the boundary as generated ISC text: a
new Isc::Generator serializes a Node::Document back to ISC source
(the inverse of Parser + DocumentBuilder + NodeAdapter, pinned by
round-trip behavior specs), the bridge writes it to a per-process temp
dir registered once via add_load_path, and load_map compiles it. The
generated-into-the-package-tree write is gone.

Notes:
- The engine cache is keyed by document identity, not name: synthetic
  spec documents reuse example-N names and a stale engine would serve
  the previous document; a reused name now evicts via unload_map.
- sys.path is inserted at 0: an editable install of the python package
  otherwise shadows the monorepo checkout.
- INTERSCRIPT_PYTHON_SRC overrides the python source path for
  out-of-monorepo setups.
- spec_helper resets the $compiler global per example; dsl_stage_spec
  leaked Compiler::Python into every later file, silently rerouting
  suites that never opted in.

With interscript-py#6 (to-position case functions, same-map stage
runs): dsl_stage python legs 53 -> 18 failures, reversibility 6 -> 0,
round_trip 9 -> 0.
PyCall builds against whichever libpython it finds, which is not the
python that bare pip targets on the runners — the python compiler legs
then fail every load_map with ModuleNotFoundError. Resolve the bound
version and pip-install into that interpreter.
@ronaldtse
ronaldtse merged commit 6a27046 into main Sep 29, 2026
4 of 10 checks passed
@ronaldtse
ronaldtse deleted the feat/python-bridge-isc-generator branch September 29, 2026 08:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant