Skip to content

Commit 94345cb

Browse files
chengluyuChronarakLPTKFlandiaYingman
authored
The Ultimate Pattern Syntax (#316)
Co-authored-by: Florent Ferrari <[email protected]> Co-authored-by: Lionel Parreaux <[email protected]> Co-authored-by: Flandia <[email protected]>
1 parent 4c8591d commit 94345cb

File tree

109 files changed

+6103
-1785
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

109 files changed

+6103
-1785
lines changed

hkmc2/shared/src/main/scala/hkmc2/Message.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ object Message:
2929
sealed abstract class Bit
3030
final case class Text(str: Str) extends Bit
3131
final case class Code(ty: TypeLike) extends Bit
32-
implicit def fromType(ty: TypeLike): Message = Message(Code(ty)::Nil)
33-
implicit def fromStr(str: Str): Message = Message(Text(str)::Nil)
32+
implicit def fromType(ty: TypeLike): Message = Message(Code(ty) :: Nil)
33+
implicit def fromStr(str: Str): Message = Message(Text(str) :: Nil)
34+
implicit def fromInt(int: Int): Message = Message(Text(int.toString) :: Nil)
3435

3536
implicit class MessageContext(private val ctx: StringContext):
3637
def msg(inserted: Message*): Message =

hkmc2/shared/src/main/scala/hkmc2/bbml/bbML.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import mlscript.utils.*, shorthands.*
99
import utils.*
1010

1111
import Message.MessageContext
12-
import semantics.*, semantics.Term.*
12+
import semantics.*, Term.*, ucs.FlatPattern
1313
import Elaborator.Ctx
1414
import syntax.*
1515
import Tree.*
@@ -258,7 +258,7 @@ class BBTyper(using elState: Elaborator.State, tl: TL):
258258
val res = freshVar(new TempSymbol(S(blk), "ctx"))(using ctx)
259259
constrain(bodyCtx, sk | res)
260260
(bodyTy, rhsCtx | res, rhsEff | bodyEff)
261-
case Term.IfLike(Keyword.`if`, Split.Let(_, cond, Split.Cons(Branch(_, Pattern.Lit(BoolLit(true)), Split.Else(cons)), Split.Else(alts)))) =>
261+
case Term.IfLike(Keyword.`if`, Split.Let(_, cond, Split.Cons(Branch(_, FlatPattern.Lit(BoolLit(true)), Split.Else(cons)), Split.Else(alts)))) =>
262262
val (condTy, condCtx, condEff) = typeCode(cond)
263263
val (consTy, consCtx, consEff) = typeCode(cons)
264264
val (altsTy, altsCtx, altsEff) = typeCode(alts)
@@ -295,7 +295,7 @@ class BBTyper(using elState: Elaborator.State, tl: TL):
295295
val nestCtx1 = ctx.nest
296296
val nestCtx2 = ctx.nest
297297
val patTy = pattern match
298-
case pat: Pattern.ClassLike =>
298+
case pat: FlatPattern.ClassLike =>
299299
pat.constructor.symbol.flatMap(_.asCls) match
300300
case S(sym) =>
301301
val (clsTy, tv, emptyTy) = sym.defn.map(sym -> _) match
@@ -313,7 +313,7 @@ class BBTyper(using elState: Elaborator.State, tl: TL):
313313
case N =>
314314
error(msg"Not a valid class: ${pat.constructor.describe}" -> pat.constructor.toLoc :: Nil)
315315
Bot
316-
case Pattern.Lit(lit) => lit match
316+
case FlatPattern.Lit(lit) => lit match
317317
case _: Tree.BoolLit => BbCtx.boolTy
318318
case _: Tree.IntLit => BbCtx.intTy
319319
case _: Tree.DecLit => BbCtx.numTy

hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import utils.*
1010

1111
import hkmc2.Message.MessageContext
1212

13-
import semantics.*
13+
import semantics.*, ucs.FlatPattern
1414
import hkmc2.{semantics => sem}
1515
import semantics.{Term => st}
1616
import semantics.Term.{Throw => _, *}
@@ -184,7 +184,9 @@ class Lowering()(using Config, TL, Raise, State, Ctx):
184184
blockImpl(stats, res)(k)
185185
case cls: ClassLikeDef =>
186186
reportAnnotations(cls, cls.extraAnnotations)
187-
val (mtds, publicFlds, privateFlds, ctor) = gatherMembers(cls.body)
187+
val (mtds, publicFlds, privateFlds, ctor) = cls match
188+
case pd: PatternDef => compilePatternMethods(pd)
189+
case _ => gatherMembers(cls.body)
188190
cls.ext match
189191
case N =>
190192
Define(ClsLikeDefn(cls.owner, cls.sym, cls.bsym, cls.kind, cls.paramsOpt, cls.auxParams, N,
@@ -341,7 +343,9 @@ class Lowering()(using Config, TL, Raise, State, Ctx):
341343
case _: sem.BuiltinSymbol => true
342344
case sym: sem.BlockMemberSymbol =>
343345
sym.trmImplTree.fold(sym.clsTree.isDefined)(_.k is syntax.Fun)
344-
case _ => false
346+
// Do not perform safety check on `MatchResult` and `MatchFailure`.
347+
case sym => (sym is State.matchResultClsSymbol) ||
348+
(sym is State.matchFailureClsSymbol)
345349
def conclude(fr: Path) =
346350
arg match
347351
case Tup(fs) =>
@@ -506,8 +510,8 @@ class Lowering()(using Config, TL, Raise, State, Ctx):
506510
End()
507511
)
508512
pat match
509-
case Pattern.Lit(lit) => mkMatch(Case.Lit(lit) -> go(tail, topLevel = false))
510-
case Pattern.ClassLike(ctor, argsOpt, _mode, _refined) =>
513+
case FlatPattern.Lit(lit) => mkMatch(Case.Lit(lit) -> go(tail, topLevel = false))
514+
case FlatPattern.ClassLike(ctor, argsOpt, _mode, _refined) =>
511515
/** Make a continuation that creates the match. */
512516
def k(ctorSym: ClassLikeSymbol, clsParams: Ls[TermSymbol])(st: Path): Block =
513517
val args = argsOpt.map(_.map(_.scrutinee)).getOrElse(Nil)
@@ -537,8 +541,8 @@ class Lowering()(using Config, TL, Raise, State, Ctx):
537541
// resolves to a class or module. Branches with unresolved
538542
// constructors should have been removed.
539543
lastWords("Pattern.ClassLike: constructor is neither a class nor a module")
540-
case Pattern.Tuple(len, inf) => mkMatch(Case.Tup(len, inf) -> go(tail, topLevel = false))
541-
case Pattern.Record(entries) =>
544+
case FlatPattern.Tuple(len, inf) => mkMatch(Case.Tup(len, inf) -> go(tail, topLevel = false))
545+
case FlatPattern.Record(entries) =>
542546
val objectSym = ctx.builtins.Object
543547
mkMatch( // checking that we have an object
544548
Case.Cls(objectSym, Value.Ref(BuiltinSymbol(objectSym.nme, false, false, true, false))),
@@ -565,7 +569,7 @@ class Lowering()(using Config, TL, Raise, State, Ctx):
565569
val normalized = tl.scoped("ucs:normalize"):
566570
normalize(iftrm.desugared)
567571
tl.scoped("ucs:normalized"):
568-
tl.log(s"Normalized:\n${Split.display(normalized)}")
572+
tl.log(s"Normalized:\n${normalized.prettyPrint}")
569573

570574
if k.isInstanceOf[TailOp] && isIf then go(normalized, topLevel = true)
571575
else
@@ -683,8 +687,8 @@ class Lowering()(using Config, TL, Raise, State, Ctx):
683687
def setupSymbol(symbol: Local)(k: Result => Block)(using Subst): Block =
684688
k(Instantiate(mut = false, Value.Ref(State.termSymbol).selSN("Symbol"), Value.Lit(Tree.StrLit(symbol.nme)) :: Nil))
685689

686-
def quotePattern(p: Pattern)(k: Result => Block)(using Subst): Block = p match
687-
case Pattern.Lit(lit) => setupTerm("LitPattern", Value.Lit(lit) :: Nil)(k)
690+
def quotePattern(p: FlatPattern)(k: Result => Block)(using Subst): Block = p match
691+
case FlatPattern.Lit(lit) => setupTerm("LitPattern", Value.Lit(lit) :: Nil)(k)
688692
case _ => // TODO
689693
fail:
690694
ErrorReport(
@@ -819,6 +823,21 @@ class Lowering()(using Config, TL, Raise, State, Ctx):
819823
case t => t
820824
(mtds, publicFlds, privateFlds, ctor)
821825

826+
/** Compile the pattern definition into `unapply` and `unapplyStringPrefix`
827+
* methods using the `NaiveCompiler`, which transliterate the pattern into
828+
* UCS splits that backtrack without any optimizations. */
829+
def compilePatternMethods(defn: PatternDef)(using Subst):
830+
// The return type is intended to be consistent with `gatherMembers`
831+
(Ls[FunDefn], Ls[BlockMemberSymbol -> TermSymbol], Ls[TermSymbol], Block) =
832+
val compiler = new ups.NaiveCompiler
833+
val methods = compiler.compilePattern(defn)
834+
val mtds = methods
835+
.flatMap: td =>
836+
td.body.map: bod =>
837+
val (paramLists, bodyBlock) = setupFunctionDef(td.params, bod, S(td.sym.nme))
838+
FunDefn(td.owner, td.sym, paramLists, bodyBlock)
839+
(mtds, Nil, Nil, End())
840+
822841
def args(elems: Ls[Elem])(k: Ls[Arg] => Block)(using Subst): Block =
823842
val as = elems.map:
824843
case sem.Fld(sem.FldFlags.benign(), value, N) => R(N -> value)

hkmc2/shared/src/main/scala/hkmc2/codegen/js/JSBuilder.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ class JSBuilder(using TL, State, Ctx) extends CodeBuilder:
169169
then doc"$runtimeVar.Tuple.lazyConcat(${es.map(argument).mkDocument(doc", ")})"
170170
else doc"[ #{ # ${es.map(argument).mkDocument(doc", # ")} #} # ]"
171171
if mut then inner else s"$freeze(${inner})"
172+
case Value.Rcd(mut, Nil) =>
173+
if mut then "{}" else s"$freeze({})"
172174
case Value.Rcd(mut, flds) =>
173175
val inner = doc"{ # #{ ${
174176
flds.map:

hkmc2/shared/src/main/scala/hkmc2/semantics/BlockImpl.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ trait BlockImpl(using Elaborator.State):
1313
val desugStmts =
1414
def desug(stmts: Ls[Tree]): Ls[Tree] =
1515
stmts match
16-
case PossiblyAnnotated(anns, syntax.Desugared(td: TypeDef)) :: stmts =>
16+
case syntax.Desugared(PossiblyAnnotated(anns, td: TypeDef)) :: stmts =>
1717
val ctors = td.withPart.toList.flatMap:
1818
case Block(sts) => sts.flatMap:
1919
case Constructor(Block(ctors)) => ctors

0 commit comments

Comments
 (0)