1 (* Copyright (C) 2015,2017 Matthew Fluet.
2 * Copyright (C) 1999-2007 Henry Cejtin, Matthew Fluet, Suresh
3 * Jagannathan, and Stephen Weeks.
4 * Copyright (C) 1997-2000 NEC Research Institute.
6 * MLton is released under a BSD-style license.
7 * See the file MLton-LICENSE for details.
10 functor MatchCompile (S: MATCH_COMPILE_STRUCTS): MATCH_COMPILE =
18 ConApp of {arg: t option, con: Con.t}
19 | ConstRange of {lo: Const.t option, hi: Const.t option, isChar: bool, isInt: bool}
22 | Record of t SortedRecord.t
23 | Vector of t vector * {dots: bool}
26 fun layout (ex, isDelimited) =
29 fun delimit t = if isDelimited then t else paren t
32 fun loop (n: int, c: IntInf.t, ac: char list) =
37 val (q, r) = IntInf.quotRem (c, 0x10)
39 loop (n - 1, q, Char.fromHexDigit (Int.fromIntInf r) :: ac)
41 fun doit (n, esc) = str (concat ["\\", esc, loop (n, c, [])])
44 then str (Char.escapeSML (Char.fromInt (Int.fromIntInf c)))
49 fun layoutConst (c, isChar, isInt) =
55 layoutChar (WordX.toIntInf w),
57 | _ => Error.bug (concat
58 ["MatchCompile.Example.layout.layoutConst: ",
60 Layout.toString (Const.layout c)])
64 Const.IntInf i => IntInf.layout i
65 | Const.Word w => IntInf.layout (WordX.toIntInfX w)
66 | _ => Error.bug (concat
67 ["MatchCompile.Example.layout.layoutConst: ",
69 Layout.toString (Const.layout c)])
73 seq [str "0wx", str (IntInf.format (WordX.toIntInf w, StringCvt.HEX))]
74 | Const.WordVector ws =>
76 seq (WordXVector.toListMap (ws, layoutChar o WordX.toIntInf)),
78 | _ => Error.bug (concat
79 ["MatchCompile.Example.layout.layoutConst: ",
81 Layout.toString (Const.layout c)])
86 NONE => str (Con.originalName con)
89 [str (Con.originalName con),
92 | ConstRange {lo, hi, isChar, isInt} =>
94 (NONE, NONE) => str "..."
96 delimit (seq [str "... ", layoutConst (hi, isChar, isInt)])
98 delimit (seq [layoutConst (lo, isChar, isInt), str " ..."])
99 | (SOME lo, SOME hi) =>
100 if Const.equals (lo, hi)
101 then layoutConst (lo, isChar, isInt)
102 else delimit (seq [layoutConst (lo, isChar, isInt),
104 layoutConst (hi, isChar, isInt)]))
105 | Exn => delimit (str "_ : exn")
107 (delimit o mayAlign o separateLeft)
108 (Vector.toListMap (exs, layoutT), "| ")
113 layoutTuple = fn exs => tuple (Vector.toListMap (exs, layoutT)),
116 | Vector (exs, {dots}) =>
118 val exs = Vector.map (exs, layoutT)
121 then Vector.concat [exs, Vector.new1 (str "...")]
126 and layoutF ex = layout (ex, false)
127 and layoutT ex = layout (ex, true)
136 fun const {const, isChar, isInt} =
137 ConstRange {lo = SOME const, hi = SOME const,
138 isChar = isChar, isInt = isInt}
139 fun constRange {lo, hi, isChar, isInt} =
140 ConstRange {lo = lo, hi = hi,
141 isChar = isChar, isInt = isInt}
144 if SortedRecord.forall (rexs, isWild)
148 fun vector exs = Vector (exs, {dots = false})
149 fun vectorDots exs = Vector (exs, {dots = true})
151 fun compare (ex1, ex2) =
153 (* Wild sorts last *)
154 (Wild, Wild) => EQUAL
156 | (Wild, _) => GREATER
158 | (Exn, Exn) => EQUAL
160 | (Exn, _) => GREATER
161 | (ConstRange {lo = lo1, hi = hi1, isInt, ...},
162 ConstRange {lo = lo2, hi = hi2, ...}) =>
164 fun cmp (x, y, b, k) =
166 (NONE, NONE) => k EQUAL
167 | (NONE, SOME _) => if b then LESS else GREATER
168 | (SOME _, NONE) => if b then GREATER else LESS
169 | (SOME (Const.Word w1), SOME (Const.Word w2)) =>
170 k (WordX.compare (w1, w2, {signed = isInt}))
171 | (SOME (Const.IntInf ii1), SOME (Const.IntInf ii2)) =>
172 k (IntInf.compare (ii1, ii2))
173 | (SOME (Const.WordVector ws1), SOME (Const.WordVector ws2)) =>
174 k (WordXVector.compare (ws1, ws2))
175 | _ => Error.bug "MatchCompile.Example.compare: ConstRange/ConstRange"
177 cmp (lo1, lo2, true, fn order =>
180 | EQUAL => cmp (hi1, hi2, false, fn order => order)
181 | GREATER => GREATER)
183 | (ConApp {con = con1, arg = arg1}, ConApp {con = con2, arg = arg2}) =>
184 (case String.compare (Con.toString con1, Con.toString con2) of
186 | EQUAL => (case (arg1, arg2) of
187 (SOME arg1, SOME arg2) => compare' (arg1, arg2)
188 | (NONE, NONE) => EQUAL
189 | _ => Error.bug "MatchCompile.Example.compare: ConApp/ConApp")
190 | GREATER => GREATER)
191 | (Vector (exs1, {dots = dots1}), Vector (exs2, {dots = dots2})) =>
192 (case (dots1, dots2) of
193 (false, true) => LESS
194 | (true, false) => GREATER
195 | _ => Vector.compare (exs1, exs2, compare'))
196 | (Record rexs1, Record rexs2) =>
197 Vector.compare (SortedRecord.range rexs1, SortedRecord.range rexs2, compare')
198 | _ => Error.bug "MatchCompile.Example.compare"
199 and compare' (ex1, ex2) =
201 (Or ex1s, Or ex2s) => compares (Vector.toList ex1s, Vector.toList ex2s)
202 | (Or ex1s, _) => compares (Vector.toList ex1s, [ex2])
203 | (_, Or ex2s) => compares ([ex1], Vector.toList ex2s)
204 | _ => compare (ex1, ex2)
205 and compares (exs1, exs2) =
206 List.compare (exs1, exs2, compare)
210 fun join (exs1, exs2) =
214 | ((ex1 as ConApp {con = con1, arg = arg1})::exs1',
215 (ex2 as ConApp {con = con2, arg = arg2})::exs2') =>
216 (case String.compare (Con.toString con1, Con.toString con2) of
217 LESS => ex1::(join (exs1', exs2))
222 (SOME arg1, SOME arg2) => or [arg1, arg2]
223 | (NONE, NONE) => NONE
224 | _ => Error.bug "MatchCompile.Example.or.join"
226 (ConApp {con = con1, arg = arg})::
227 (join (exs1', exs2'))
229 | GREATER => ex2::(join (exs1, exs2')))
230 | (ex1::exs1', ex2::exs2') =>
231 (case compare (ex1, ex2) of
232 LESS => ex1::(join (exs1', exs2))
233 | EQUAL => ex1::(join (exs1', exs2'))
234 | GREATER => ex2::(join (exs1, exs2')))
236 List.map (exs, fn Or exs => Vector.toList exs | ex => [ex])
238 List.fold (exss, [], join)
243 | _ => SOME (Or (Vector.fromList exs))
248 structure Env = MonoEnv (structure Domain = Var
249 structure Range = Var)
254 Con of {arg: Var.t option,
256 | Record of Var.t SortedRecord.t
257 | Vector of Var.t vector
259 fun layout (f: t): Layout.t =
268 | SOME x => seq [str " ", Var.layout x]]
272 layoutElt = Var.layout,
273 layoutTuple = fn xs => tuple (Vector.toListMap (xs, Var.layout)),
276 | Vector xs => vector (Vector.map (xs, Var.layout))
282 datatype t = T of {exs: (Var.t * Example.t) list,
285 fun layout (T {exs, ...}) =
286 List.layout (Layout.tuple2 (Var.layout, Example.layout)) exs
288 val empty = T {exs = [], isOnlyExns = true}
290 fun add (T {exs, isOnlyExns = is}, x, ex, {isOnlyExns: bool}) =
291 T {exs = (x, ex) :: exs,
292 isOnlyExns = is andalso isOnlyExns}
297 datatype t = T of {fact: Fact.t,
304 List.layout (fn {fact, var} =>
305 seq [Var.layout var, str " = ", Fact.layout fact])
311 fun add (T fs, x, f) = T ({fact = f, var = x} :: fs)
313 fun bind (T facts, x: Var.t, p: NestedPat.t): Env.t =
315 val {destroy, get = fact: Var.t -> Fact.t, set = setFact, ...} =
316 Property.destGetSetOnce
317 (Var.plist, Property.initRaise ("fact", Var.layout))
318 val () = List.foreach (facts, fn {fact, var} => setFact (var, fact))
319 fun loop (p: NestedPat.t, x: Var.t, env: Env.t): Env.t =
321 datatype z = datatype NestedPat.node
323 case NestedPat.node p of
329 Fact.Con {arg = SOME x, ...} =>
331 | _ => Error.bug "MatchCompile.Facts.bind: Con:wrong fact"))
333 | Layered (y, p) => loop (p, x, Env.extend (env, y, x))
334 | Or _ => Error.bug "MatchCompile.factbind: or pattern shouldn't be here"
338 Vector.fold2 (SortedRecord.range rp, SortedRecord.range rx, env, loop)
339 | _ => Error.bug "MatchCompile.Facts.bind: Record:wrong fact")
340 | Var y => Env.extend (env, y, x)
344 Vector.fold2 (ps, xs, env, loop)
345 | _ => Error.bug "MatchCompile.Facts.bind: Vector:wrong fact")
348 val env = loop (p, x, Env.empty)
355 Trace.trace3 ("MatchCompile.Facts.bind",
356 layout, Var.layout, NestedPat.layout, Env.layout)
359 fun example (T facts, Examples.T {exs, ...}, x: Var.t): Example.t =
362 get = fact: Var.t -> Fact.t option,
363 set = setFact, ...} =
364 Property.destGetSetOnce (Var.plist, Property.initConst NONE)
365 val () = List.foreach (facts, fn {fact, var} =>
366 setFact (var, SOME fact))
367 fun loop (x: Var.t): Example.t =
370 (case List.peek (exs, fn (x', _) => Var.equals (x, x')) of
372 | SOME (_, ex) => ex)
375 Fact.Con {arg, con} =>
376 Example.ConApp {con = con, arg = Option.map (arg, loop)}
378 Example.record (SortedRecord.map (rxs, loop))
380 Example.vector (Vector.map (xs, loop)))
389 ("MatchCompile.Facts.example",
390 layout, Examples.layout, Var.layout, Example.layout)
397 Const of {const: Const.t,
400 | Con of {arg: (t * Type.t) option,
402 targs: Type.t vector}
403 | Record of t SortedRecord.t
407 fun layout (p: t): Layout.t =
412 Const {const, ...} => Const.layout const
413 | Con {arg, con, ...} =>
417 | SOME (p, _) => seq [str " ", layout p]]
422 layoutTuple = fn ps => tuple (Vector.toListMap (ps, layout)),
425 | Vector ps => vector (Vector.map (ps, layout))
429 val isWild: t -> bool =
433 val fromNestedPat: NestedPat.t -> t =
435 fun loop (p: NestedPat.t): t =
436 case NestedPat.node p of
437 NestedPat.Con {arg, con, targs} =>
440 Option.map (arg, fn p => (loop p, NestedPat.ty p))
442 Con {arg = arg, con = con, targs = targs}
444 | NestedPat.Const r => Const r
445 | NestedPat.Layered (_, p) => loop p
446 | NestedPat.Or _ => Error.bug "MatchCompile.fromNestedPat: or pattern shouldn't be here"
447 | NestedPat.Record rps => Record (SortedRecord.map (rps, loop))
448 | NestedPat.Var _ => Wild
449 | NestedPat.Vector ps => Vector (Vector.map (ps, loop))
450 | NestedPat.Wild => Wild
460 fun dropNth (v: 'a t, n: int): 'a t =
461 keepAllMapi (v, fn (i, a) => if i = n then NONE else SOME a)
467 T of {pats: Pat.t vector,
468 rest: {examples: (Example.t * {isOnlyExns: bool}) list ref option,
469 finish: (Var.t -> Var.t) -> Exp.t,
470 nestedPat: NestedPat.t}}
473 fun layout (T {pats, ...}) =
474 Layout.tuple (Vector.toListMap (pats, Pat.layout))
476 fun allWild (T {pats, ...}) = Vector.forall (pats, Pat.isWild)
478 fun dropNth (T {pats, rest}, n) =
479 T {pats = Vector.dropNth (pats, n),
485 type t = Rule.t vector
487 fun layout (rs: t) = Layout.align (Vector.toListMap (rs, Rule.layout))
489 fun dropNth (rs: t, n: int): t =
490 Vector.map (rs, fn r => Rule.dropNth (r, n))
495 type t = (Var.t * Type.t) vector
497 val layout = Vector.layout (Layout.tuple2 (Var.layout, Type.layout))
501 List.keepAllMap (WordSize.all, fn s =>
502 if WordSize.equals (s, WordSize.fromBits (Bits.fromInt 64))
504 else SOME {size = s, ty = Type.word s})
506 fun unhandledConsts {consts = cs: Const.t vector, isChar, isInt}: Example.t option =
508 fun search {<= : 'a * 'a -> bool,
509 equals: 'a * 'a -> bool,
510 extract: Const.t -> 'a,
517 fun exampleConstRange (lo, hi) =
519 {lo = Option.map (lo, make),
520 hi = Option.map (hi, make),
521 isChar = isChar, isInt = isInt}
522 fun mkExampleConstRange (lo, hi) =
524 then if equals (lo, hi)
525 then [exampleConstRange (SOME lo, SOME hi)]
531 then [exampleConstRange (SOME lo, SOME lo),
532 exampleConstRange (SOME hi, SOME hi)]
533 else if equals (lo', hi')
534 then [exampleConstRange (SOME lo, SOME lo),
535 exampleConstRange (SOME lo', SOME hi'),
536 exampleConstRange (SOME hi, SOME hi)]
537 else [exampleConstRange (SOME lo, SOME hi)]
540 val cs = QuickSort.sortVector (Vector.map (cs, extract), op <=)
541 val cs = Vector.toList cs
547 NONE => [exampleConstRange (SOME (next cMax), NONE)]
549 if equals (cMax, max')
551 else mkExampleConstRange (next cMax, max'))
553 (mkExampleConstRange (next c1, prev c2)) @ (loop (c2::cs))
557 NONE => [exampleConstRange (NONE, SOME (prev cMin))] @ (loop cs)
559 if equals (cMin, min')
561 else (mkExampleConstRange (min', prev cMin)) @ (loop cs)
565 datatype z = datatype Const.t
567 case Vector.first cs of
573 | _ => Error.bug "MatchCompile.unhandledConsts: expected IntInf"
581 next = fn i => i + 1,
582 prev = fn i => i - 1}
584 | Null => Error.bug "MatchCompile.unhandledConsts: Null"
585 | Real _ => Error.bug "MatchCompile.unhandledConsts: Real"
589 val signed = {signed = isInt}
593 | _ => Error.bug "MatchCompile.unhandledConsts: expected Word"
595 search {<= = fn (w1, w2) => WordX.le (w1, w2, signed),
596 equals = WordX.equals,
599 max = SOME (WordX.max (s, signed)),
600 min = SOME (WordX.min (s, signed)),
601 next = fn w => WordX.add (w, WordX.one s),
602 prev = fn w => WordX.sub (w, WordX.one s)}
606 val s = WordXVector.elementSize ws
607 val signed = {signed = false}
611 | _ => Error.bug "MatchCompile.unhandledConsts: expected Word"
614 val wsOrig = List.rev (WordXVector.toListMap (ws, fn w => w))
619 [] => [WordX.min (s, signed)]
621 if WordX.isMax (w, signed)
622 then (WordX.min (s, signed))::(loop ws)
623 else (WordX.add (w, WordX.one s))::ws
628 WordXVector.fromListRev ({elementSize = s}, wsNext)
632 val wsOrig = List.rev (WordXVector.toListMap (ws, fn w => w))
637 [] => Error.bug "MatchCompile.unhandledConst: WordXVector.prev"
639 if WordX.isMin (w, signed)
641 else [WordX.sub (w, WordX.one s)]
643 if WordX.isMin (w, signed)
644 then (WordX.max (s, signed))::(loop ws)
645 else (WordX.sub (w, WordX.one s))::ws
650 WordXVector.fromListRev ({elementSize = s}, wsPrev)
653 search {<= = WordXVector.le,
654 equals = WordXVector.equals,
656 make = Const.wordVector,
658 min = SOME (WordXVector.fromVector ({elementSize = s}, Vector.new0 ())),
668 fun layout (_: t) = Layout.str "<exp>"
672 Trace.trace ("MatchCompile.match",
673 fn (vars, rules, facts, es) =>
674 Layout.record [("vars", Vars.layout vars),
675 ("rules", Rules.layout rules),
676 ("facts", Facts.layout facts),
677 ("examples", Examples.layout es)],
680 Trace.trace ("MatchCompile.const",
681 fn (vars, rules, facts, es, i: Int.t, test: Exp.t) =>
682 Layout.record [("vars", Vars.layout vars),
683 ("rules", Rules.layout rules),
684 ("facts", Facts.layout facts),
685 ("examples", Examples.layout es),
686 ("index", Int.layout i),
687 ("test", Exp.layout test)],
690 Trace.trace ("MatchCompile.sum",
691 fn (vars, rules, facts, es, i: Int.t, test: Exp.t, _: Tycon.t) =>
692 Layout.record [("vars", Vars.layout vars),
693 ("rules", Rules.layout rules),
694 ("facts", Facts.layout facts),
695 ("examples", Examples.layout es),
696 ("index", Int.layout i),
697 ("test", Exp.layout test)],
700 Trace.trace ("MatchCompile.record",
701 fn (vars, rules, facts, es, i: Int.t, test: Exp.t, _: Field.t vector) =>
702 Layout.record [("vars", Vars.layout vars),
703 ("rules", Rules.layout rules),
704 ("facts", Facts.layout facts),
705 ("examples", Examples.layout es),
706 ("index", Int.layout i),
707 ("test", Exp.layout test)],
710 Trace.trace ("MatchCompile.vector",
711 fn (vars, rules, facts, es, i: Int.t, test: Exp.t) =>
712 Layout.record [("vars", Vars.layout vars),
713 ("rules", Rules.layout rules),
714 ("facts", Facts.layout facts),
715 ("examples", Examples.layout es),
716 ("index", Int.layout i),
717 ("test", Exp.layout test)],
720 (*---------------------------------------------------*)
722 (*---------------------------------------------------*)
724 fun matchCompile {caseType: Type.t,
725 cases: (NestedPat.t * ((Var.t -> Var.t) -> Exp.t)) vector,
726 conTycon: Con.t -> Tycon.t,
730 tyconCons: Tycon.t -> {con: Con.t,
731 hasArg: bool} vector} =
733 fun chooseColumn _ = 0
734 fun match arg : Exp.t =
736 (fn (vars: Vars.t, rules: Rules.t, facts: Facts.t, es) =>
737 if Vector.isEmpty rules
738 then Error.bug "MatchCompile.match: no rules"
739 else if Rule.allWild (Vector.first rules)
740 then (* The first rule matches. *)
742 val Rule.T {rest = {examples, finish, nestedPat, ...}, ...} =
744 val env = Facts.bind (facts, test, nestedPat)
745 val Examples.T {isOnlyExns, ...} = es
748 (examples, fn examples =>
750 (Facts.example (facts, es, test),
751 {isOnlyExns = isOnlyExns})))
753 finish (fn x => Env.lookup (env, x))
757 val i = chooseColumn rules
759 case Vector.peek (rules, fn Rule.T {pats, ...} =>
760 not (Pat.isWild (Vector.sub (pats, i)))) of
761 NONE => match (Vector.dropNth (vars, i),
762 Rules.dropNth (rules, i),
764 | SOME (Rule.T {pats, ...}) =>
766 datatype z = datatype Pat.t
767 val test = Exp.var (Vector.sub (vars, i))
769 case Vector.sub (pats, i) of
770 Const _ => const (vars, rules, facts, es, i, test)
772 sum (vars, rules, facts, es, i, test, conTycon con)
774 record (vars, rules, facts, es, i, test, SortedRecord.domain rps)
775 | Vector _ => vector (vars, rules, facts, es, i, test)
776 | Wild => Error.bug "MatchCompile.match: Wild"
781 (fn (vars, rules, facts, es, i, test) =>
783 val (var, ty) = Vector.sub (vars, i)
784 val {isChar, isInt} =
785 case Vector.peekMap (rules, fn Rule.T {pats, ...} =>
786 case Vector.sub (pats, i) of
787 Pat.Const {isChar, isInt, ...} =>
788 SOME {isChar = isChar, isInt = isInt}
790 NONE => {isChar = false, isInt = false}
791 | SOME {isChar, isInt} => {isChar = isChar, isInt = isInt}
793 Example.const {const = c, isChar = isChar, isInt = isInt}
794 val (cases, defaults) =
797 fn (rule as Rule.T {pats, ...}, (cases, defaults)) =>
799 val rule = Rule.dropNth (rule, i)
801 case Vector.sub (pats, i) of
802 Pat.Const {const = c, ...} =>
804 fun insert (cases, ac) =
807 {const = c, rules = rule :: defaults} :: ac
808 | (casee as {const, rules}) :: cases =>
809 if Const.equals (c, const)
811 {const = c, rules = rule :: rules}
812 :: List.appendRev (ac, cases)
813 else insert (cases, casee :: ac)
815 (insert (cases, []), defaults)
818 (List.map (cases, fn {const, rules} =>
819 {const = const, rules = rule :: rules}),
821 | _ => Error.bug "MatchCompile.const: expected Const pat"
823 val cases = Vector.fromListMap (cases, fn {const, rules} =>
825 rules = Vector.fromList rules})
826 val defaults = Vector.fromList defaults
827 val vars = Vector.dropNth (vars, i)
828 fun finish (rules: Rule.t vector, e): Exp.t =
829 match (vars, rules, facts,
830 Examples.add (es, var, e, {isOnlyExns = false}))
831 val default: Exp.t option =
833 (unhandledConsts {consts = Vector.map (cases, #const),
834 isChar = isChar, isInt = isInt},
835 fn e => finish (defaults, e))
837 case List.peek (directCases, fn {ty = ty', ...} =>
838 Type.equals (ty, ty')) of
841 val (cases, default) =
843 SOME default => (cases, default)
845 (Vector.dropSuffix (cases, 1),
846 let val {const, rules} = Vector.last cases
847 in finish (rules, exampleConst const)
851 (cases, default, fn ({const, rules}, rest) =>
852 Exp.iff {test = Exp.equal (test, Exp.const const),
853 thenn = finish (rules, exampleConst const),
857 | SOME {size, ...} =>
861 (default, fn default =>
865 (cases, fn {const, rules} =>
870 | _ => Error.bug "MatchCompile.const: caseWord type error"
872 (w, finish (rules, exampleConst const))
875 Exp.casee {cases = Cases.word (size, cases),
883 (fn (vars: Vars.t, rules: Rules.t, facts: Facts.t, es,
886 val (var, _) = Vector.sub (vars, i)
887 val (cases, defaults) =
890 fn (rule as Rule.T {pats, ...}, (cases, defaults)) =>
891 case Vector.sub (pats, i) of
892 Pat.Con {arg, con, targs} =>
902 if i = i' then NONE else SOME x))
905 val arg = Var.newNoname ()
910 if i = i' then (arg, ty) else x))
917 rules = rule :: defaults}
919 fun insert (cases, ac) =
921 [] => oneCase () :: ac
922 | ((casee as {rest as {con = con', ...}, rules})
924 if Con.equals (con, con')
926 {rest = rest, rules = rule :: rules}
927 :: List.appendRev (ac, cases)
928 else insert (cases, casee :: ac)
930 (insert (cases, []), defaults)
933 (List.map (cases, fn {rest, rules} =>
934 {rest = rest, rules = rule :: rules}),
936 | _ => Error.bug "MatchCompile.sum: expected Con pat")
939 (cases, fn {rest = {arg, con, targs, vars}, rules} =>
943 (rules, fn Rule.T {pats, rest} =>
947 (pats, fn (i', p') =>
948 if i <> i' then SOME p'
951 Pat.Con {arg, ...} => Option.map (arg, #1)
953 Option.map (arg, fn _ => Pat.Wild)
954 | _ => Error.bug "MatchCompile.sum: decon got strange pattern")
956 Rule.T {pats = pats, rest = rest}
961 Fact.Con {arg = Option.map (arg, #1), con = con})
965 rhs = match (vars, rules, facts, es),
968 fun done (e, isOnlyExns) =
969 SOME (match (Vector.dropNth (vars, i),
970 Rules.dropNth (Vector.fromList defaults, i),
972 Examples.add (es, var, e,
973 {isOnlyExns = isOnlyExns})))
975 if Vector.isEmpty cases
976 then done (Example.Wild, true)
977 else if Tycon.equals (tycon, Tycon.exn)
978 then done (Example.Exn, true)
981 val cons = tyconCons tycon
984 (Vector.toList cons, fn {con, hasArg, ...} =>
985 if Vector.exists (cases, fn {con = con', ...} =>
986 Con.equals (con, con'))
988 else SOME (Example.ConApp
991 then SOME Example.Wild
995 (Example.or unhandled, NONE, fn (e, _) => done (e, false))
998 Exp.casee {cases = Cases.con cases,
999 default = Option.map (default, fn e => (e, region)),
1003 if 1 <> Vector.length cases
1007 val {arg, con, rhs, ...} = Vector.first cases
1009 if not (Con.equals (con, Con.reff))
1013 NONE => Error.bug "MatchCompile.sum: ref missing arg"
1015 Exp.lett {body = rhs,
1016 exp = Exp.deref test,
1022 (fn (vars: Vars.t, rules: Rules.t, facts: Facts.t, es, i, test, fs) =>
1024 val (var, varTy) = Vector.sub (vars, i)
1027 val n = Vector.length vars'
1031 (vars, fn (i', x) =>
1034 else Vector.new1 x))
1037 (rules, fn Rule.T {pats, rest} =>
1042 (pats, fn (i', p) =>
1046 Pat.Record rps => SortedRecord.range rps
1048 Vector.tabulate (n, fn _ => Pat.Wild)
1049 | _ => Error.bug "MatchCompile.record: derecord")))
1051 Rule.T {pats = pats, rest = rest}
1056 Fact.Record (SortedRecord.zip (fs, Vector.map (vars', #1))))
1058 match (vars, rules, facts, es)
1061 if Vector.length fs = 1
1062 then let val var' = Var.newNoname ()
1064 (* Although 'test' is likely a variable,
1065 * must bind to a fresh variable to maintain
1066 * a unique Fact.t per variable in Facts.t.
1068 Exp.lett {var = var', exp = test,
1069 body = body (Vector.new1 (var', varTy))}
1071 else Exp.detuple {body = body, tuple = test}
1075 (fn (vars: Vars.t, rules: Rules.t, facts: Facts.t, es, i, test) =>
1077 val (var, _) = Vector.sub (vars, i)
1078 val (cases, defaults) =
1081 fn (rule as Rule.T {pats, ...}, (cases, defaults)) =>
1082 case Vector.sub (pats, i) of
1086 {len = Vector.length args,
1087 rules = rule :: defaults}
1088 fun insert (cases, ac) =
1090 [] => oneCase () :: ac
1091 | ((casee as {len, rules})::cases) =>
1092 if Vector.length args = len
1094 {len = len, rules = rule :: rules}
1095 :: List.appendRev (ac, cases)
1096 else insert (cases, casee :: ac)
1098 (insert (cases, []), defaults)
1101 (List.map (cases, fn {len, rules} =>
1102 {len = len, rules = rule :: rules}),
1104 | _ => Error.bug "MatchCompile.vector: expected Vector pat")
1109 (cases, ~1, fn ({len, ...}, max) =>
1112 Example.vectorDots (Vector.new (maxLen + 1, Example.Wild))
1115 (0, maxLen, [unhandled], fn (i, unhandled) =>
1116 if List.exists (cases, fn {len, ...} => i = len)
1118 else (Example.vector (Vector.new (i, Example.Wild))) :: unhandled)
1120 Example.or unhandled
1122 match (Vector.dropNth (vars, i),
1123 Rules.dropNth (Vector.fromList defaults, i),
1126 (unhandled, es, fn (unhandled, es) =>
1127 Examples.add (es, var, unhandled, {isOnlyExns = false})))
1131 (cases, fn {len, rules} =>
1138 (vars, fn (i', x) =>
1141 else Vector.new1 x))
1144 (rules, fn Rule.T {pats, rest} =>
1149 (pats, fn (i', p) =>
1154 | Pat.Wild => Vector.new (len, Pat.Wild)
1155 | _ => Error.bug "MatchCompile.vector: devector")))
1157 Rule.T {pats = pats, rest = rest}
1161 Facts.add (facts, var,
1162 Fact.Vector (Vector.map (vars', #1))),
1166 (WordX.fromIntInf (IntInf.fromInt len, WordSize.seqIndex ()),
1167 Exp.devector {vector = test, length = len, body = body})
1171 {cases = Cases.word (WordSize.seqIndex (), cases),
1172 default = SOME (default, region),
1173 test = Exp.vectorLength test,
1176 val examples = ref []
1178 match (Vector.new1 (test, testType),
1179 Vector.mapi (cases, fn (i, (p, f)) =>
1180 Rule.T {pats = Vector.new1 (Pat.fromNestedPat p),
1181 rest = {examples = if i = Vector.length cases - 1
1189 fn {dropOnlyExns} =>
1192 (Example.or o List.keepAllMap)
1193 (!examples, fn (ex, {isOnlyExns}) =>
1194 if dropOnlyExns andalso isOnlyExns
1198 Option.map (example, Example.layout)
1205 fn {caseType: Type.t,
1206 cases: (NestedPat.t * (int -> (Var.t -> Var.t) -> Exp.t)) vector,
1207 conTycon: Con.t -> Tycon.t,
1211 tyconCons: Tycon.t -> {con: Con.t,
1212 hasArg: bool} vector} =>
1216 (cases, fn (pat, mk) =>
1218 val pats = NestedPat.flatten pat
1219 val mk = mk (Vector.length pats)
1221 Vector.map (pats, fn pat => (pat, mk))
1223 val cases = Vector.concatV cases
1225 matchCompile {caseType = caseType,
1227 conTycon = conTycon,
1230 testType = testType,
1231 tyconCons = tyconCons}
1236 ("MatchCompile.matchCompile",
1237 fn {caseType, cases, test, testType, ...} =>
1238 Layout.record [("caseType", Type.layout caseType),
1239 ("cases", Vector.layout (NestedPat.layout o #1) cases),
1240 ("test", Var.layout test),
1241 ("testType", Type.layout testType)],