Skip to content

[Repo] res-to-affine partial-port mode: switch→match / function translation + module-qualified references #488

@hyperpolymath

Description

@hyperpolymath

Proposal

Successor to #57 (now closed — its goal, the .res.affine declaration translator, is delivered). This issue tracks the next translation model for tools/res-to-affine/: a partial-port mode that translates expression- and function-level constructs, plus module-qualified references.

Why a separate issue / model

--translate today guarantees that every emitted form type-checks standalone (main.exe checkType checking passed), which is exactly why it's bounded to self-contained top-level declarations: type aliases, sums, structs, generics, and literal letconst (slices delivered in #477 / #481 / #484). Two remaining forms cannot meet that guarantee by construction and need a different model:

1. switchmatch (+ function translation) — partial-port mode

A match is an expression, only meaningful inside a function body. Producing a type-checkable result means translating the whole enclosing function — but ReScript bindings are usually un-annotated (let f = x => …), while AffineScript fn requires parameter and return types, so the output won't compile.

The model this needs is translate-with-TODO-holes: render the structural skeleton of a function (signature stub + match arms with translated patterns) and leave un-inferable bodies / types as explicit // TODO islands. This drops the standalone-type-check guarantee — output is a partial port a human finishes, matching the README's original "~60–80% translation" vision. Scope to design:

  • function signature stubs from un-annotated params (TODO-typed params, inferred-where-possible)
  • switch e { | P => body, … }match e { P => body, … } (pattern translation; => kept; leading | dropped; commas added)
  • a small expression translator for the common, safe cases (literals, identifiers, constructor application, simple calls/operators), TODO for the rest

2. Module-qualified references

Belt.Map.t now parses (the #228 grammar gap closed — parser.mly:515 wires qualified_type_name into type_expr_primary) but Belt::Map::T won't resolve against a target module that doesn't exist yet. Needs a module-mapping story (ReScript stdlib module → AffineScript stdlib module, or an explicit "unresolved import" marker) before it can be emitted without breaking a build.

Acceptance / starting points

  • Decide the partial-port output contract (it is explicitly not required to type-check; document that distinction from the declaration translator).
  • Reuse the existing walker AST (tools/res-to-affine/walker.ml) and the conservative skip-don't-guess discipline.
  • Gate tests like the existing walker-phase3* suites (skip without the tree-sitter grammar).

Context


Filed as the successor to #57 at the owner's request.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions