@@ -6,8 +6,8 @@ import mlscript.utils.*, shorthands.*
6
6
import Message .MessageContext
7
7
import utils .TraceLogger
8
8
import hkmc2 .syntax .Literal
9
- import Keyword .{as , and , `else` , is , let , `then` }
10
- import collection .mutable .HashMap
9
+ import Keyword .{as , and , `do` , ` else` , is , let , `then` }
10
+ import collection .mutable .{ HashMap , SortedSet }
11
11
import Elaborator .{ctx , Ctxl }
12
12
import ucs .DesugaringBase
13
13
@@ -16,30 +16,52 @@ object Desugarer:
16
16
infix def unapply (tree : Tree ): Opt [(Tree , Tree )] = tree match
17
17
case InfixApp (lhs, `op`, rhs) => S ((lhs, rhs))
18
18
case _ => N
19
-
20
- /** An extractor that accepts either `A and B` or `A then B`. */
21
- object `~>` :
22
- infix def unapply (tree : Tree ): Opt [(Tree , Tree \/ Tree )] = tree match
23
- case lhs and rhs => S ((lhs, L (rhs)))
24
- case lhs `then` rhs => S ((lhs, R (rhs)))
25
- case _ => N
26
-
19
+
27
20
class ScrutineeData :
28
21
val classes : HashMap [ClassSymbol , List [BlockLocalSymbol ]] = HashMap .empty
29
22
val tupleLead : HashMap [Int , BlockLocalSymbol ] = HashMap .empty
30
23
val tupleLast : HashMap [Int , BlockLocalSymbol ] = HashMap .empty
31
24
end Desugarer
32
25
33
- class Desugarer (tl : TraceLogger , val elaborator : Elaborator )
26
+ class Desugarer (val elaborator : Elaborator )
34
27
(using raise : Raise , state : Elaborator .State , c : Elaborator .Ctx ) extends DesugaringBase :
35
28
import Desugarer .*
36
29
import Elaborator .Ctx
37
- import elaborator .term
38
- import tl .*
30
+ import elaborator .term , elaborator .tl .*
31
+
32
+ given Ordering [Loc ] = Ordering .by: loc =>
33
+ (loc.spanStart, loc.spanEnd)
34
+
35
+ /** Keep track of the locations where `do` and `then` are used as connectives. */
36
+ private val kwLocSets = (SortedSet .empty[Loc ], SortedSet .empty[Loc ])
37
+
38
+ private def reportInconsistentConnectives (kw : Keyword , kwLoc : Opt [Loc ]): Unit =
39
+ log(kwLocSets)
40
+ (kwLocSets._1.headOption, kwLocSets._2.headOption) match
41
+ case (Some (doLoc), Some (thenLoc)) =>
42
+ raise(ErrorReport (
43
+ msg " Mixed use of `do` and `then` in the ` ${kw.name}` expression. " -> kwLoc
44
+ :: msg " Keyword `then` is used here. " -> S (thenLoc)
45
+ :: msg " Keyword `do` is used here. " -> S (doLoc) :: Nil
46
+ ))
47
+ case _ => ()
48
+
49
+ private def topmostDefault : Split =
50
+ if kwLocSets._1.nonEmpty then Split .Else (Term .Lit (UnitLit (true ))) else Split .End
51
+
52
+ /** An extractor that accepts either `A and B`, `A then B`, and `A do B`. It
53
+ * also keeps track of the usage of `then` and `do`.
54
+ */
55
+ object `~>` :
56
+ infix def unapply (tree : Tree ): Opt [(Tree , Tree \/ Tree )] = tree match
57
+ case lhs and rhs => S ((lhs, L (rhs)))
58
+ case lhs `then` rhs => kwLocSets._2 ++= tree.toLoc; S ((lhs, R (rhs)))
59
+ case lhs `do` rhs => kwLocSets._1 ++= tree.toLoc; S ((lhs, R (rhs)))
60
+ case _ => N
39
61
40
62
// We're working on composing continuations in the UCS translation.
41
63
// The type of continuation is `Split => Ctx => Split`.
42
- // The first parameter represents the fallback split, which does not have
64
+ // The first parameter represents the "backup" split, which does not have
43
65
// access to the bindings in the current match. The second parameter
44
66
// represents the context with bindings in the current match.
45
67
@@ -82,10 +104,6 @@ class Desugarer(tl: TraceLogger, val elaborator: Elaborator)
82
104
83
105
def default : Split => Sequel = split => _ => split
84
106
85
- /** Desugar UCS shorthands. */
86
- def shorthands (tree : Tree ): Sequel = termSplitShorthands(tree, identity):
87
- Split .default(Term .Lit (Tree .BoolLit (false )))
88
-
89
107
private def termSplitShorthands (tree : Tree , finish : Term => Term ): Split => Sequel = tree match
90
108
case Block (branches) => branches match
91
109
case Nil => lastWords(" encountered empty block" )
@@ -166,6 +184,12 @@ class Desugarer(tl: TraceLogger, val elaborator: Elaborator)
166
184
val sym = VarSymbol (ident)
167
185
val fallbackCtx = ctx + (ident.name -> sym)
168
186
Split .Let (sym, term(termTree)(using ctx), elabFallback(fallback)(fallbackCtx)).withLocOf(t)
187
+ case Modified (Keyword .`do`, doLoc, computation) => fallback => ctx => trace(
188
+ pre = s " termSplit: do $computation" ,
189
+ post = (res : Split ) => s " termSplit: else >>> $res"
190
+ ):
191
+ val sym = TempSymbol (N , " doTemp" )
192
+ Split .Let (sym, term(computation)(using ctx), elabFallback(fallback)(ctx)).withLocOf(t)
169
193
case Modified (Keyword .`else`, elsLoc, default) => fallback => ctx => trace(
170
194
pre = s " termSplit: else $default" ,
171
195
post = (res : Split ) => s " termSplit: else >>> $res"
@@ -241,6 +265,12 @@ class Desugarer(tl: TraceLogger, val elaborator: Elaborator)
241
265
val sym = VarSymbol (ident)
242
266
val fallbackCtx = ctx + (ident.name -> sym)
243
267
Split .Let (sym, term(termTree)(using ctx), elabFallback(fallbackCtx))
268
+ case (Tree .Empty (), Modified (Keyword .`do`, doLoc, computation)) => ctx => trace(
269
+ pre = s " termSplit: do $computation" ,
270
+ post = (res : Split ) => s " termSplit: else >>> $res"
271
+ ):
272
+ val sym = TempSymbol (N , " doTemp" )
273
+ Split .Let (sym, term(computation)(using ctx), elabFallback(ctx))
244
274
case (Tree .Empty (), Modified (Keyword .`else`, elsLoc, default)) => ctx =>
245
275
// TODO: report `rest` as unreachable
246
276
Split .default(term(default)(using ctx))
@@ -322,6 +352,12 @@ class Desugarer(tl: TraceLogger, val elaborator: Elaborator)
322
352
val sym = VarSymbol (ident)
323
353
val fallbackCtx = ctx + (ident.name -> sym)
324
354
Split .Let (sym, term(termTree)(using ctx), elabFallback(backup)(fallbackCtx))
355
+ case Modified (Keyword .`do`, doLoc, computation) => fallback => ctx => trace(
356
+ pre = s " patternSplit (do) <<< $computation" ,
357
+ post = (res : Split ) => s " patternSplit: else >>> $res"
358
+ ):
359
+ val sym = TempSymbol (N , " doTemp" )
360
+ Split .Let (sym, term(computation)(using ctx), elabFallback(fallback)(ctx))
325
361
case Modified (Keyword .`else`, elsLoc, body) => backup => ctx => trace(
326
362
pre = s " patternSplit (else) <<< $tree" ,
327
363
post = (res : Split ) => s " patternSplit (else) >>> ${res.showDbg}"
@@ -499,4 +535,20 @@ class Desugarer(tl: TraceLogger, val elaborator: Elaborator)
499
535
):
500
536
val innermostSplit = subMatches(rest, sequel)(fallback)
501
537
expandMatch(scrutinee, pattern, innermostSplit)(fallback)
538
+
539
+ /** Desugar `case` expressions. */
540
+ def apply (tree : Case , scrut : VarSymbol )(using Ctx ): Split =
541
+ val topmost = patternSplit(tree.branches, scrut)(Split .End )(ctx)
542
+ reportInconsistentConnectives(Keyword .`case`, tree.kwLoc)
543
+ topmost ++ topmostDefault
544
+
545
+ /** Desugar `if` and `while` expressions. */
546
+ def apply (tree : IfLike )(using Ctx ): Split =
547
+ val topmost = termSplit(tree.split, identity)(Split .End )(ctx)
548
+ reportInconsistentConnectives(tree.kw, tree.kwLoc)
549
+ topmost ++ topmostDefault
550
+
551
+ /** Desugar `is` and `and` shorthands. */
552
+ def apply (tree : InfixApp )(using Ctx ): Split =
553
+ termSplitShorthands(tree, identity)(Split .default(Term .Lit (Tree .BoolLit (false ))))(ctx)
502
554
end Desugarer
0 commit comments