Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
5be4823
Sketch the `NewDesugarer`
chengluyu Aug 15, 2025
f8d040d
Prevent duplicate terms using `Label` in normalization
chengluyu Sep 3, 2025
0f9be9d
Merge branch 'origin/hkmc2'
chengluyu Sep 5, 2025
18b9b7f
Fix that `NewDesugarer` cannot handle `let` bindings
chengluyu Sep 5, 2025
5a27c9e
Check if errors from new and old desugarers are consistent
chengluyu Sep 5, 2025
0c15ac2
Fix spacing after `while` and line break before `break`
chengluyu Sep 16, 2025
a079bd9
Desugar splits using `NaiveCompiler` and fix numerous issues
chengluyu Sep 16, 2025
8d77887
Deprecate `Desugarer` and fix related issues
chengluyu Sep 16, 2025
1b8617b
Add the test from today's stand-up meeting
chengluyu Sep 17, 2025
defdc53
Deduplicate throw blocks that raise match errors
chengluyu Sep 17, 2025
e661386
Improve shorthands that were not sufficiently tested
chengluyu Sep 17, 2025
24e3f73
Comment on a test which worked before
chengluyu Sep 17, 2025
ff24d0b
Separate symbols in patterns and terms to fix `where` clauses
chengluyu Sep 18, 2025
0030549
Find dead splits after else & treat `_` as else only in splits
chengluyu Sep 20, 2025
0fb7066
Document a possible future work
chengluyu Sep 20, 2025
3ca6d55
Avoid generating unnecessary`break` in the outermost `Label`
chengluyu Sep 20, 2025
b80d4bc
Add locations to the keyword of `InfixApp`
chengluyu Sep 22, 2025
28336d7
Document the reason why we need two sets of symbols
chengluyu Sep 22, 2025
63e521d
Merge branch 'hkmc2'
chengluyu Sep 22, 2025
c58b4fd
Support annotation in the desugarer
chengluyu Sep 22, 2025
69ceb31
Remove the uses of keyword escape
chengluyu Sep 22, 2025
55da3fe
Revert the treatment of `_` in splits
chengluyu Sep 22, 2025
012da18
Revise several test files
chengluyu Sep 24, 2025
fa35be0
Remove a temporary test command
chengluyu Sep 24, 2025
719570c
Revise several comments
chengluyu Sep 24, 2025
eb6babd
Use names instead of underscores in several patterns.
chengluyu Sep 24, 2025
bfd7dc7
Move `isInvalidStringBounds`
chengluyu Sep 24, 2025
ed97e31
Partially implement `mkClone` for `SynthIf`
chengluyu Sep 24, 2025
dce1cd3
Deduplicate `SpreadKind`'s `toString` methods
chengluyu Sep 24, 2025
f57588f
Minor code cleanup
chengluyu Sep 24, 2025
ccc115b
Remove a useless file
chengluyu Sep 24, 2025
22b79b1
Fix the location of wildcard patterns
chengluyu Sep 24, 2025
dacd443
Fix inconsistent empty record patterns in shorthands
chengluyu Sep 24, 2025
659db36
Correct the typo in a file name
chengluyu Sep 24, 2025
8970563
Attach location information to error splits
chengluyu Sep 25, 2025
00466f2
Attach locations to error annotations
chengluyu Sep 25, 2025
992b36b
Revert commented code in split pretty printing
chengluyu Sep 25, 2025
7a530a0
Add tests for string patterns and `@compile` in UCS
chengluyu Sep 25, 2025
4e25640
Merge branch 'origin/hkmc2'
chengluyu Sep 27, 2025
8e0fd16
Validate arguments when expanding splits
chengluyu Sep 27, 2025
7696956
Further separate the duties of `SplitCompiler` and `Normalization`
chengluyu Oct 1, 2025
cc8a9be
Continue decluttering `FlatPattern`
chengluyu Oct 1, 2025
bdf27c0
Continue decluttering `Normalization`
chengluyu Oct 2, 2025
8ce2d07
No need to clone `Pattern` anymore
chengluyu Oct 2, 2025
d60fd0b
Fix the output of string patterns
chengluyu Oct 2, 2025
7e97a94
Add tests for cross compilation of patterns
chengluyu Oct 2, 2025
a4e9acd
Add tests for wrongly applied pattern arguments
chengluyu Oct 2, 2025
9af8eaf
Amend test changes
chengluyu Oct 2, 2025
bbee7c0
Fix that the same error messages were raised twice
chengluyu Oct 2, 2025
1f9d671
Amend test changes
chengluyu Oct 3, 2025
d6f27b9
Merge `SplitCompiler` and `NaiveCompiler` and deduplicate
chengluyu Oct 3, 2025
9f29e6b
Bring back a newline
chengluyu Oct 3, 2025
b6cad7c
Merge branch 'origin/hkmc2'
chengluyu Oct 3, 2025
a58ca96
Merge branch 'origin/hkmc2'
chengluyu Oct 21, 2025
09316dd
Keep `name` field in the lockfile stable
chengluyu Oct 21, 2025
2ca4acc
Use precise locations when reporting mixed use of `do` and `then`
chengluyu Oct 21, 2025
d5d89fa
Merge branch 'origin/hkmc2'
chengluyu Oct 27, 2025
54ce910
Represent call-by-value evaluation contexts using patterns
chengluyu Oct 28, 2025
739f4ea
Mark a problem of inconsistent origins
chengluyu Oct 28, 2025
dfead57
Add the Hindley Milner example
chengluyu Oct 31, 2025
25fca5f
Implement Hindley Milner unification using patterns
chengluyu Oct 31, 2025
a139ef7
Clean up TODOs
chengluyu Nov 2, 2025
6e53e92
A change during the standup meeting
chengluyu Nov 3, 2025
687b3b2
Document mixed parameters
chengluyu Nov 3, 2025
56289ea
Implement call-by-name evaluation context using patterns
chengluyu Nov 3, 2025
83906b4
Merge branch 'origin/hkmc2'
chengluyu Nov 5, 2025
bcf7ae8
Add a few tests
LPTK Nov 6, 2025
f49721a
Update a comment
chengluyu Nov 7, 2025
4074ce0
Merge branch 'luyu/refactoring-desugarer'
chengluyu Nov 7, 2025
0182701
Fix parentheses in a test
chengluyu Nov 7, 2025
17a201c
Document a precedence problem
chengluyu Nov 7, 2025
571f84e
Use `MutMap`
chengluyu Nov 7, 2025
274b5f9
Add changes missing in the previous commit
chengluyu Nov 7, 2025
29d221d
Update a comment
chengluyu Nov 7, 2025
ca8a1e7
Add tests & fix a couple of things
LPTK Nov 7, 2025
cab0586
Update a comment
chengluyu Nov 7, 2025
e94246e
Update a comment
chengluyu Nov 7, 2025
3af4454
Update a comment
chengluyu Nov 7, 2025
2dde445
Fix a few minor issues
chengluyu Nov 7, 2025
3e58e5f
Update a comment.
chengluyu Nov 7, 2025
8f8f656
Update a comment
chengluyu Nov 7, 2025
62a116c
Polish a warning
chengluyu Nov 7, 2025
ed8744a
Remove an overload
chengluyu Nov 7, 2025
64dad63
Rename `MatchResult` to `MatchSuccess`
chengluyu Nov 7, 2025
679d8b0
Add a comment for class `SimpleSplit`
chengluyu Nov 7, 2025
8f51cd1
Add a test
chengluyu Nov 7, 2025
20ff59c
Remove an outdated comment an unused method
chengluyu Nov 7, 2025
caabab8
Properly document a test
chengluyu Nov 7, 2025
5ae5df4
Merge branch 'hkmc2' into refactoring-desugarer
LPTK Nov 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1431,9 +1431,19 @@ extends Importer with ucs.SplitElaborator:
* variables we found in `p`. */
def arrow(lhs: Tree, rhs: Tree): Ctxl[Pattern] =
val pattern = go(lhs)
val termCtx = ctx ++ pattern.variables.allocate
val variables = pattern.variables.allocate
// - `contextEntries` will be added to the context
Comment thread
chengluyu marked this conversation as resolved.
// - `correspondence` is mapping from symbols representing variables
// in the pattern to symbols for parameters to be used in the `term`.
val (contextEntries, correspondence) = variables.iterator.map:
case (name, symbol) =>
// We must create a symbol specifically for `Param` to avoid
// repetitively declare symbols in `Scope` during code generation.
val parameterSymbol = VarSymbol(new Ident(symbol.name))
(name -> parameterSymbol, symbol -> parameterSymbol)
.toList.unzip
pattern.variables.report // Report all invalid variables we found in `pattern`.
Transform(pattern, term(rhs)(using termCtx))
Transform(pattern, correspondence, term(rhs)(using ctx ++ contextEntries))
/** Elaborate tuple patterns like `[p1, p2, ...ps, pn]`. */
def tuple(ts: Ls[Tree]): Ctxl[Pattern.Tuple] =
// We are accumulating two components: the leading patterns, the spred
Comment thread
chengluyu marked this conversation as resolved.
Outdated
Expand Down
16 changes: 10 additions & 6 deletions hkmc2/shared/src/main/scala/hkmc2/semantics/Pattern.scala
Original file line number Diff line number Diff line change
Expand Up @@ -238,9 +238,13 @@ enum Pattern extends AutoLocated:
case Alias(pattern: Pattern, id: Ident) extends Pattern with AliasImpl

/** A pattern that matches the same value as other pattern, with an additional
* function applied to the bound variables in the pattern.
* function applied to the bound variables in the pattern.
*
* @param pattern The pattern to be matched against.
* @param parameters A map from the variable symbols to parameter symbols.
* @param transform The term that should be applied to the extracted values.
*/
case Transform(pattern: Pattern, transform: Term)
case Transform(pattern: Pattern, parameters: Ls[(VarSymbol, VarSymbol)], transform: Term)

case Annotated(pattern: Pattern, annotations: Vector[Term])

Expand Down Expand Up @@ -295,7 +299,7 @@ enum Pattern extends AutoLocated:
case (name, pattern) => name :: pattern.children
case Chain(first, second) => first :: second :: Nil
case Alias(pattern, alias) => pattern :: alias :: Nil
case Transform(pattern, transform) => pattern :: transform :: Nil
case Transform(pattern, _, transform) => pattern :: transform :: Nil
case Annotated(pattern, annotations) => pattern :: annotations.toList
case Guarded(pattern, guard) => pattern.children :+ guard

Expand All @@ -311,7 +315,7 @@ enum Pattern extends AutoLocated:
case Record(fields) => fields.flatMap(_._2.subTerms)
case Chain(first, second) => first.subTerms ::: second.subTerms
case Alias(pattern, _) => pattern.subTerms
case Transform(pattern, transform) => pattern.subTerms :+ transform
case Transform(pattern, _, transform) => pattern.subTerms :+ transform
case Annotated(pattern, annotations) => pattern.subTerms ::: annotations.toList
case Guarded(pattern, guard) => pattern.subTerms :+ guard

Expand All @@ -328,7 +332,7 @@ enum Pattern extends AutoLocated:
case Record(_) => "record"
case Chain(_, _) => "chain"
case Alias(_, _) => "alias"
case Transform(_, _) => "transform"
case Transform(_, _, _) => "transform"
case Annotated(_, _) => "annotated pattern"
case Guarded(_, _) => "guarded pattern"

Expand Down Expand Up @@ -365,7 +369,7 @@ enum Pattern extends AutoLocated:
case Chain(first, second) => s"${first.showDbgWithPar} as ${second.showDbgWithPar}"
case Alias(Wildcard(), alias) => alias.name
case Alias(pattern, alias) => s"${pattern.showDbgWithPar} as ${alias.name}"
case Transform(pattern, transform) => s"${pattern.showDbgWithPar} => ${transform.showDbg}"
case Transform(pattern, _, transform) => s"${pattern.showDbgWithPar} => ${transform.showDbg}"
case Annotated(pattern, annotations) =>
annotations.iterator.map(_.showDbg).mkString("@", " @", " ") + pattern.showDbgWithPar
case Guarded(pattern, guard) => pattern.showDbg + " where " + guard.showDbg
86 changes: 52 additions & 34 deletions hkmc2/shared/src/main/scala/hkmc2/semantics/ucs/Normalization.scala
Original file line number Diff line number Diff line change
Expand Up @@ -603,38 +603,41 @@ class Normalization(lowering: Lowering)(using tl: TL)(using Raise, Ctx, State) e

/** Collect terms that appear in multiple `Split.Else` branches. We will share
* the corresponding blocks to avoid code duplication. */
private def collectSharedConsequents(split: Split): List[(Term, TempSymbol)] =
val counts: MutMap[Term, (Int, Int)] = MutMap.empty
private def createLabelsForDuplicatedBranches(split: Split): Labels =
val counts: MutMap[Term, (order: Int, count: Int)] = MutMap.empty
var throwCount = 0
def rec(s: Split): Unit = s match
case Split.End => ()
case Split.End => throwCount += 1
case Split.Else(els) => counts.updateWith(els):
case S((n, count)) => S((n, count + 1))
case N => S((counts.size + 1, 1))
case Split.Let(_, _, tail) => rec(tail)
case Split.Cons(Branch(_, _, cons), tail) => rec(cons); rec(tail)
rec(split)
counts.iterator.filter(_._2._2 > 1).toSeq.sortBy(_._2._1).zipWithIndex.map:
case ((term, _), i) => (term, new TempSymbol(S(term), s"split_${i + 1}$$"))
.toList
val consequents =
counts.iterator.filter(_._2.count > 1).toSeq.sortBy(_._2.order).zipWithIndex.map:
case ((term, _), i) => (term, TempSymbol(S(term), s"split_${i + 1}$$"))
.toList
val default = if throwCount > 1 then S(TempSymbol(N, s"split_default$$")) else N
Labels(consequents, default)

private def lowerSplit(
split: Split,
sharedConsequents: Map[Term, TempSymbol],
cont: (Result => Block) \/ (Bool => Result => Block),
topLevel: Bool
)(using Subst): Block = split match
)(using labels: Labels)(using Subst): Block = split match
case Split.Let(sym, trm, tl) =>
term_nonTail(trm): r =>
Assign(sym, r, lowerSplit(tl, sharedConsequents, cont, topLevel))
Assign(sym, r, lowerSplit(tl, cont, topLevel))
case Split.Cons(Branch(scrut, pat, tail), restSplit) =>
subTerm_nonTail(scrut): sr =>
tl.log(s"Binding scrut $scrut to $sr (${summon[Subst].map})")
def mkMatch(cse: Case -> Block) = Match(sr, cse :: Nil,
S(lowerSplit(restSplit, sharedConsequents, cont, topLevel = true)),
S(lowerSplit(restSplit, cont, topLevel = true)),
End()
)
pat match
case FlatPattern.Lit(lit) => mkMatch(Case.Lit(lit) -> lowerSplit(tail, sharedConsequents, cont, topLevel = false))
case FlatPattern.Lit(lit) => mkMatch(Case.Lit(lit) -> lowerSplit(tail, cont, topLevel = false))
case FlatPattern.ClassLike(ctor, argsOpt, _mode, _refined) =>
/** Make a continuation that creates the match. */
def k(ctorSym: ClassLikeSymbol, clsParams: Ls[TermSymbol])(st: Path): Block =
Expand All @@ -644,7 +647,7 @@ class Normalization(lowering: Lowering)(using tl: TL)(using Raise, Ctx, State) e
assert(argsOpt.isEmpty || args.length <= clsParams.length, (argsOpt, clsParams))
def mkArgs(args: Ls[TermSymbol -> BlockLocalSymbol])(using Subst): Case -> Block = args match
case Nil =>
Case.Cls(ctorSym, st) -> lowerSplit(tail, sharedConsequents, cont, topLevel = false)
Case.Cls(ctorSym, st) -> lowerSplit(tail, cont, topLevel = false)
case (param, arg) :: args =>
val (cse, blk) = mkArgs(args)
(cse, Assign(arg, Select(sr, new Tree.Ident(param.id.name).withLocOf(arg))(S(param)), blk))
Expand All @@ -667,23 +670,25 @@ class Normalization(lowering: Lowering)(using tl: TL)(using Raise, Ctx, State) e
// resolves to a class or module. Branches with unresolved
// constructors should have been removed.
lastWords("Pattern.ClassLike: constructor is neither a class nor a module")
case FlatPattern.Tuple(len, inf) => mkMatch(Case.Tup(len, inf) -> lowerSplit(tail, sharedConsequents, cont, topLevel = false))
case FlatPattern.Tuple(len, inf) => mkMatch(Case.Tup(len, inf) -> lowerSplit(tail, cont, topLevel = false))
case FlatPattern.Record(entries) =>
val objectSym = ctx.builtins.Object
mkMatch( // checking that we have an object
Case.Cls(objectSym, Value.Ref(BuiltinSymbol(objectSym.nme, false, false, true, false))),
entries.foldRight(lowerSplit(tail, sharedConsequents, cont, topLevel = false)):
entries.foldRight(lowerSplit(tail, cont, topLevel = false)):
case ((fieldName, fieldSymbol), blk) =>
mkMatch(
Case.Field(fieldName, safe = true), // we know we have an object, no need to check again
Assign(fieldSymbol, Select(sr, fieldName)(N), blk)
)
)
case Split.Else(els) => sharedConsequents.get(els) match
case Split.Else(els) => labels.get(els) match
case S(label) => Break(label)
case N => term_nonTail(els)(cont.fold(identity, _(topLevel)))
case Split.End =>
Throw(Instantiate(mut = false, Select(Value.Ref(State.globalThisSymbol), Tree.Ident("Error"))(N),
case Split.End => labels.default.fold(throwMatchErrorBlock)(Break(_))

private def throwMatchErrorBlock =
Throw(Instantiate(mut = false, Select(Value.Ref(State.globalThisSymbol), Tree.Ident("Error"))(N),
Value.Lit(syntax.Tree.StrLit("match error")).asArg :: Nil)) // TODO add failed-match scrutinee info

import syntax.Keyword.{`if`, `while`}
Expand Down Expand Up @@ -723,15 +728,15 @@ class Normalization(lowering: Lowering)(using tl: TL)(using Raise, Ctx, State) e
tl.scoped("ucs:normalized"):
tl.log(s"Normalized:\n${normalized.prettyPrint}")
// Collect consequents that are shared in more than one branch.
val sharedConsequents = collectSharedConsequents(normalized)
given labels: Labels = createLabelsForDuplicatedBranches(normalized)
lazy val rootBreakLabel = new TempSymbol(N, "split_root$")
lazy val breakRoot = (r: Result) => Assign(l, r, Break(rootBreakLabel))
val cont =
if kw === `while` then
// If the term is a `while`, the action of `else` branches depends on
// whether the the enclosing split is at the top level or not.
R((topLevel: Bool) => (r: Result) => Assign(l, r, if topLevel then End() else Continue(loopLabel)))
else if sharedConsequents.isEmpty then
else if labels.isEmpty then
if k.isInstanceOf[TailOp] then
// If there are no shared consequents and the continuation is a tail
// operation, we can call it directly.
Expand All @@ -749,34 +754,47 @@ class Normalization(lowering: Lowering)(using tl: TL)(using Raise, Ctx, State) e
L(breakRoot)
// The main block contains the lowered split, where each shared consequent
// is replaced with a `Break` to the corresponding label.
val mainBlock = lowerSplit(normalized, sharedConsequents.toMap, cont, topLevel = true)
// Wrap the main block in a labelled block for each shared consequent. The
// `rest` of each `Label` is the lowered consequent plus a `Break` to the
// end of the entire `if` term. Otherwise, it will fall through to the outer
// consequent, which is the wrong semantics.
val wrappedBlock = if sharedConsequents.isEmpty then mainBlock else
sharedConsequents.foldRight(mainBlock):
case ((term, label), innerBlock) =>
Label(label, false, innerBlock, term_nonTail(term)(breakRoot))
val mainBlock =
val innermostBlock = lowerSplit(normalized, cont, topLevel = true)
// Wrap the main block in a labelled block for each shared consequent. The
// `rest` of each `Label` is the lowered consequent plus a `Break` to the
// end of the entire `if` term. Otherwise, it will fall through to the outer
// consequent, which is the wrong semantics.
val innerBlock: Block = if labels.consequents.isEmpty then innermostBlock else
labels.consequents.foldRight(innermostBlock):
case ((term, label), innerBlock) =>
Label(label, false, innerBlock, term_nonTail(term)(breakRoot))
labels.default match
case S(label) => Label(label, false, innerBlock, throwMatchErrorBlock)
case N => innerBlock
// If there are shared consequents, we need a wrap the entire block in a
// `Label` so that `Break`s in the shared consequents can jump to the end.
val body = if sharedConsequents.isEmpty then wrappedBlock else
Label(rootBreakLabel, false, wrappedBlock, End())
val body = if labels.isEmpty then mainBlock else
Label(rootBreakLabel, false, mainBlock, End())
// Embed the `body` into `Label` if the term is a `while`.
lazy val rest = if usesResTmp then k(Value.Ref(l)) else k(lowering.unit)
val resultBlock =
val block =
if kw === `while` then
Begin(Label(loopLabel, true, body, End()), rest)
else if sharedConsequents.isEmpty && k.isInstanceOf[TailOp] then
else if labels.isEmpty && k.isInstanceOf[TailOp] then
body
else
Begin(body, rest)
scoped("ucs:lowered"):
log(s"Lowered:\n${resultBlock.showAsTree}")
resultBlock
log(s"Lowered:\n${block.showAsTree}")
block
end Normalization

object Normalization:
/** This contains the labels for duplicated consequents and the default
* branch which throws match errors. */
private class Labels(val consequents: Ls[(Term, TempSymbol)], val default: Opt[TempSymbol]):
private val map = consequents.toMap

inline def isEmpty: Bool = consequents.isEmpty && default.isEmpty

inline def get(term: Term): Opt[TempSymbol] = map.get(term)

/**
* Hard-coded subtyping relations used in normalization and coverage checking.
* TODO use base classes and also handle modules
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,17 +74,19 @@ trait SplitElaborator:
/** Elaborate shorthand expressions. */
protected def shorthandSplit(tree: Tree)(using UnderCtx): Ctxl[SimpleSplit] =
val affirmative = Else(Term.Lit(BoolLit(true)))
val split = tree match
case lhs is rhs => subterm(lhs).reference: scrut =>
val (firstPatternTree, _) :: matches = disaggregate(rhs)
val firstPattern = self.pattern(firstPatternTree)
// firstPattern.variables.report
(ctx ++ firstPattern.variables.allocate).givenIn:
val split = expandMatches(matches)(affirmative)
Head.Match(scrut(), firstPattern, split) ~: End
case matches =>
expandMatches(disaggregate(matches))(affirmative)
split ~~: Else(Term.Lit(BoolLit(false)))
val negative = Else(Term.Lit(BoolLit(false)))
val (scrutinee, pattern) :: matches = disaggregate(tree)
subterm(scrutinee).reference: scrutinee =>
lazy val innerSplit: Ctxl[SimpleSplit] = expandMatches(matches)(affirmative)
pattern match
case Block(trees) => trees.foldRight(negative):
case (pattern, alternative) =>
Head.Match(scrutinee(), self.pattern(pattern), innerSplit) ~: alternative
case _ =>
val firstPattern = self.pattern(pattern)
firstPattern.variables.report
(ctx ++ firstPattern.variables.allocate).givenIn:
Head.Match(scrutinee(), firstPattern, innerSplit) ~: negative

/** Desugar a list of trees as a term split. The returned function takes a
* function, which takes a `Ctx` and returns a `SimpleSplit` representing
Expand Down
11 changes: 7 additions & 4 deletions hkmc2/shared/src/main/scala/hkmc2/semantics/ups/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -347,17 +347,20 @@ class Compiler(using Context)(using tl: TL)(using Ctx, State, Raise) extends Ter
case Rename(pattern, name) =>
// We should add those fields to a context.
completePattern(pattern, scrutinee, subScrutinees, name :: aliases)
case Extract(pattern, term) =>
case Extract(pattern, correspondence, term) =>
// The symbol representing the transform function, which should be
// declared at the outermost level.
val transformSymbol = TempSymbol(N, "transform")
// The transform function takes a single record as the argument.
val bindingsSymbol = VarSymbol(Ident("args"))
val params = paramList(param(bindingsSymbol))
// We then bind the variables to fields of the record.
// Because we pass the extracted values using recoreds. We need to bind
// each property to its corresponding variable which is accessible from
// then `term`.
val letBindings = pattern.symbols.flatMap: symbol =>
LetDecl(symbol, Nil) ::
DefineVar(symbol, sel(bindingsSymbol.safeRef, symbol.name)) :: Nil
val termSymbol = correspondence(symbol)
LetDecl(termSymbol, Nil) ::
DefineVar(termSymbol, sel(bindingsSymbol.safeRef, termSymbol.name)) :: Nil
val makeSplit = completePattern(pattern, scrutinee, subScrutinees, Nil)
(makeConsequent, alternative) => Split.Let(
sym = transformSymbol,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,10 @@ class Instantiator(using tl: TL)(using Ctx, State, Raise):
progress += (instantiation -> S(instantiated))
// Finally, return the synonym representing the entry point pattern and all
// instantiated pattern definitions.
Context:
progress.view.mapValues:
_.getOrElse(lastWords("The pattern is expected to be instantiated."))
.toMap
val definitions = progress.view.mapValues:
_.getOrElse(lastWords("The pattern is expected to be instantiated."))
.toMap
new Context(definitions)

/** Add the instantiation to the queue if it has not been instantiated yet. */
def schedule(instantiation: Instantiation): Instantiation =
Expand Down Expand Up @@ -159,4 +159,5 @@ class Instantiator(using tl: TL)(using Ctx, State, Raise):
case N => instantiate(pattern)
case S(symbol) => Rename(instantiate(pattern), symbol)
// Pattern arguments are accessible throughout the pattern.
case SP.Transform(pattern, transform) => Extract(instantiate(pattern), transform)
case SP.Transform(pattern, parameters, transform) =>
Extract(instantiate(pattern), parameters.toMap, transform)
Loading