Commit Graph

3 Commits

Author SHA1 Message Date
d75c61d408 GUEST: step 7 — lib/guest/layout.sx off-side / layout-sensitive lexer
Configurable layout pass that inserts virtual open / close / separator
tokens based on indentation. Supports both styles the brief calls out:

  • Haskell-flavour: layout opens AFTER a reserved keyword
    (let/where/do/of) and resolves to the next token's column. Module
    prelude wraps the whole input in an implicit block. Explicit `{`
    after the keyword suppresses virtual layout.

  • Python-flavour: layout opens via an :open-trailing-fn predicate
    fired AFTER the trigger token (e.g. trailing `:`) — and resolves
    to the column of the next token, which in real source is on a
    fresh line. No module prelude.

Public entry: (layout-pass cfg tokens). Token shape: dict with at
least :type :value :line :col; everything else passes through. Newline
filler tokens are NOT used — line-break detection is via :line.

lib/guest/tests/layout.sx — 6 tests covering both flavours:
  haskell-do-block / haskell-explicit-brace / haskell-do-inline /
  haskell-module-prelude / python-if-block / python-nested.

Per the brief's gotcha note ("Don't ship lib/guest/layout.sx unless
the haskell scoreboard equals baseline") — haskell/layout.sx is left
UNTOUCHED. The kit isn't yet a drop-in replacement for the full
Haskell 98 algorithm (Note 5, multi-stage pre-pass, etc.) and forcing
a port would risk the 156 currently passing programs. Haskell
scoreboard remains at 156/156 baseline because no haskell file
changed. The synthetic Python-ish fixture is the second consumer per
the brief's wording.

PARTIAL — kit + synthetic fixture shipped; haskell port deferred until
the kit grows the missing Haskell-98 wrinkles.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 18:55:38 +00:00
863e9d93a4 GUEST: step 6 — lib/guest/match.sx pure unify + match kit
Pure-functional pattern-match + unification, shipped for miniKanren
(minikraken) / Datalog and any other logic-flavoured guest that wants
immutable unification without writing it from scratch.

Canonical wire format (config callbacks let other shapes plug in):
  var          (:var NAME)
  constructor  (:ctor HEAD ARGS)
  literal      number / string / boolean / nil

Public API:
  empty-subst  walk  walk*  extend  occurs?
  unify        (symmetric, with occurs check)
  unify-with   (cfg-driven for non-canonical term shapes)
  match-pat    (asymmetric pattern→value, vars only in pattern)
  match-pat-with (cfg-driven)

lib/guest/tests/match.sx — 25 tests covering walk chains, occurs,
unify (literal/var/ctor, head + arity mismatch, transitive vars),
match-pat. All passing.

The brief flagged this as the highest-risk step ("revert and redesign
on any regression"). The two existing engines — haskell/match.sx
(pure asymmetric, lazy, returns env-or-nil) and prolog runtime.sx
pl-unify! (mutating symmetric, trail-based, returns bool) — are
structurally divergent and forcing a shared core under either of their
contracts would risk the 746 tests they currently pass. Both are
untouched; they remain at baseline (haskell 156/156, prolog 590/590)
because none of their source files were modified.

PARTIAL — kit shipped, prolog/haskell ports deferred until a guest
chooses to migrate or until a third consumer (minikraken / datalog)
provides a less risky migration path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 18:41:29 +00:00
a774cd26c1 GUEST: step 5 — lib/guest/ast.sx canonical AST shapes (kit + tests)
Defines the 10 canonical node kinds called out in the brief — literal,
var, app, lambda, let, letrec, if, match-clause, module, import — plus
predicates, ast-kind dispatch, and per-field accessors. Each node is a
tagged keyword-headed list: (:literal V), (:var N), (:app FN ARGS), …

Also lib/guest/tests/ast.sx — 33 tests exercising every constructor +
predicate + accessor, runnable via (gast-tests-run!) which returns the
{:passed :failed :total} dict the shared conformance driver expects.

PARTIAL — pending real consumers. The brief calls Step 5 "Optional —
guests may keep their own AST" and forcing lua/prolog to switch their
internal AST shape risks regressing 775 passing tests for tooling that
nothing yet calls. Both internal ASTs are untouched; lua still 185/185,
prolog still 590/590. Datalog-on-sx (in flight, see plans/datalog-on-sx.md)
will be the natural first real consumer; lua/prolog converters can land
when a cross-language tool wants them.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 17:35:49 +00:00