Import Upstream version 20180207
[hcoop/debian/mlton.git] / mlton / backend / switch.fun
CommitLineData
7f918cf1
CE
1(* Copyright (C) 2002-2007 Henry Cejtin, Matthew Fluet, Suresh
2 * Jagannathan, and Stephen Weeks.
3 *
4 * MLton is released under a BSD-style license.
5 * See the file MLton-LICENSE for details.
6 *)
7
8functor Switch (S: SWITCH_STRUCTS): SWITCH =
9struct
10
11open S
12
13fun isRedundant {cases: 'a vector,
14 equals: 'a * 'a -> bool}: bool =
15 let
16 val nCases = Vector.length cases
17 in
18 0 < nCases
19 andalso let
20 fun loop (i: int, prev: 'a): bool =
21 i < nCases
22 andalso let
23 val cur = Vector.sub (cases, i)
24 in
25 equals (cur, prev)
26 orelse loop (i + 1, cur)
27 end
28 in
29 loop (1, Vector.first cases)
30 end
31 end
32
33datatype t =
34 T of {cases: (WordX.t * Label.t) vector,
35 default: Label.t option,
36 size: WordSize.t,
37 test: Use.t}
38
39fun layout (T {cases, default, test, ...})=
40 let
41 open Layout
42 in
43 seq [str "switch ",
44 record [("test", Use.layout test),
45 ("default", Option.layout Label.layout default),
46 ("cases",
47 Vector.layout (Layout.tuple2 (WordX.layout, Label.layout))
48 cases)]]
49 end
50
51fun isOk (T {cases, default, size = _, test}, {checkUse, labelIsOk}): bool =
52 let
53 val () = checkUse test
54 val ty = Use.ty test
55 in
56 Vector.forall (cases, labelIsOk o #2)
57 andalso (case default of
58 NONE => true
59 | SOME l => labelIsOk l)
60 andalso Vector.isSorted (cases, fn ((w, _), (w', _)) =>
61 WordX.le (w, w', {signed = false}))
62 andalso not (isRedundant
63 {cases = cases,
64 equals = fn ((w, _), (w', _)) => WordX.equals (w, w')})
65 andalso
66 if Vector.isEmpty cases
67 then isSome default
68 else
69 let
70 val casesTy =
71 Type.sum (Vector.map (cases, fn (w, _) => Type.ofWordX w))
72 in
73 Bits.equals (Type.width ty, Type.width casesTy)
74 andalso not (Type.isObjptr ty)
75 andalso (isSome default orelse Type.isSubtype (ty, casesTy))
76 end
77 end
78
79fun foldLabelUse (T {cases, default, test, ...}, a: 'a, {label, use}): 'a =
80 let
81 val a = use (test, a)
82 val a = Option.fold (default, a, label)
83 val a = Vector.fold (cases, a, fn ((_, l), a) =>
84 label (l, a))
85 in
86 a
87 end
88
89fun foreachLabel (s, f) =
90 foldLabelUse (s, (), {label = f o #1,
91 use = fn _ => ()})
92
93end