Skip to content

Conversation

@disconcision
Copy link
Member

@disconcision disconcision commented Jan 21, 2026

This implemented sort-dependent expansion. Multi-delimiter forms now only expand when inserted in an appropriate sort context. This is a slightly subtle notion; it currently means that the nearest leftward non-secondary piece has a nib of the appropriate sort. This has a complex but well-tested special case around case rules.

The new functionality is demonstrated below by creating four new forms of pattern sort. They are patterns because I didn't want to bother creating a new sort, but are intended to be representative of what we'd need to implement module syntax. The let and type forms below reuse Exp keywords, but now in a pattern context they expand different. ; is an infix operator below, not a trailing delimiter. AFAICT this suffices to implement module syntax; see appendix below.

Screenshot 2026-01-21 at 12 47 14 AM

Appendix:

Example of module syntax which the above enables:

	let M : {
	  type T = Int;
	  let a: T
	} = {
	  type T = Int;
	  let a = 4;
	  let b = a
	}

Required for modules: 2 new sorts: Mod and Sig and 8 new forms:

Typ:= ...
  | "{" Sig "}"
Exp ::= ... 
  | "{" Mod "}"
Mod ::=
  | Mod ";" Mod
  | "type" TPat "=" Typ
  | "let" Pat "=" Exp
Sig ::=
  | Sig ";" Sig
  | "type" TPat "=" Typ
  | "let" Pat

Remaining issues:

  • If you copy an expanded form to a new sort context, or deconstruct its parent sort context, it will not remold or disintegrate; i.e. to turn a module let into a regular let or vice versa you'll need to delete all delimiters. Getting this to work is a larger change; I'm not sure on a good approach. Copy-paste could be hacked to work somewhat straightforwardly though (just skip the clipboard cache for segments containing forms with multiple expansions)
  • Probably want an error for reserved words (expanding delimiters used out-of-sort-context)
  • Much more functional testing needed; implementing modules should handle this though.

disconcision and others added 3 commits January 20, 2026 21:49
When inserting a tile, select a mold appropriate for the local sort
context rather than just taking the first available mold. This prevents
wrong-sort molds (e.g., Exp mold for `-` in a Pat context) from being
assigned during insertion.

- Form.Molds: split into get_base, try_get (strict), try_get_permissive,
  and get (with fallback). Strict filtering for remolding, permissive
  for insertion (allows wrong-sort multi-delimiter forms to expand)
- Relatives.sort: compute local sort at insertion point from left
  sibling's right nib (handles heterogeneous infix like `:`)
- Insert.re: use sort-aware Form.Molds.get
- Segment.remold_tile: use strict try_get
- Ancestor.re: remove unused functions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Expansion now considers sort context when deciding how to expand
delimiters. This prevents wrong-sort expansions (e.g., `let` expanding
in Pat context) and enables sort-specific forms (e.g., `[` expanding
to ListLitPat vs ListLitExp based on context).

Key changes:
- Form.re: Register expansions using nib sort (the context you're
  typing in) rather than mold.out (what the form produces). Rul
  context is permissive and falls back to any expansion since rules
  contain Exp/Pat operands but have no operand forms of their own.
- Insert.re: Handle `|` entirely here when inside case expressions,
  bypassing sort-specific lookup. This is needed because ascriptions
  (expr : Type) have Typ right nib even though they produce Exp.
- TyDiForms.re: Pass sort to Form.Expansion.get.

See plans/sort-specific-expansion.md for detailed analysis of the
case/rule structure and known limitations.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@disconcision disconcision changed the title Sort-dependent expansion Sort-dependent expansion for Modules Jan 21, 2026
@disconcision disconcision changed the base branch from dev to probe-III January 21, 2026 06:27
@disconcision disconcision marked this pull request as ready for review January 21, 2026 06:27
@codecov
Copy link

codecov bot commented Jan 21, 2026

Codecov Report

❌ Patch coverage is 94.20290% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 47.72%. Comparing base (bb290a6) to head (745ee4d).

Files with missing lines Patch % Lines
src/haz3lcore/lang/Form.re 94.44% 2 Missing ⚠️
src/haz3lcore/TyDi/TyDiForms.re 87.50% 1 Missing ⚠️
src/haz3lcore/zipper/action/Insert.re 85.71% 1 Missing ⚠️
Additional details and impacted files
@@              Coverage Diff              @@
##           probe-III    #2075      +/-   ##
=============================================
+ Coverage      47.55%   47.72%   +0.17%     
=============================================
  Files            229      229              
  Lines          24937    24955      +18     
=============================================
+ Hits           11860    11911      +51     
+ Misses         13077    13044      -33     
Files with missing lines Coverage Δ
src/haz3lcore/tiles/Segment.re 66.17% <100.00%> (ø)
src/haz3lcore/zipper/Ancestor.re 75.00% <ø> (+26.61%) ⬆️
src/haz3lcore/zipper/Relatives.re 78.78% <100.00%> (+2.38%) ⬆️
src/haz3lcore/TyDi/TyDiForms.re 53.16% <87.50%> (-0.69%) ⬇️
src/haz3lcore/zipper/action/Insert.re 91.40% <85.71%> (+0.06%) ⬆️
src/haz3lcore/lang/Form.re 93.08% <94.44%> (+0.49%) ⬆️

... and 13 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

2 participants