Commit | Line | Data |
---|---|---|
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 | ||
8 | functor Switch (S: SWITCH_STRUCTS): SWITCH = | |
9 | struct | |
10 | ||
11 | open S | |
12 | ||
13 | fun 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 | ||
33 | datatype t = | |
34 | T of {cases: (WordX.t * Label.t) vector, | |
35 | default: Label.t option, | |
36 | size: WordSize.t, | |
37 | test: Use.t} | |
38 | ||
39 | fun 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 | ||
51 | fun 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 | ||
79 | fun 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 | ||
89 | fun foreachLabel (s, f) = | |
90 | foldLabelUse (s, (), {label = f o #1, | |
91 | use = fn _ => ()}) | |
92 | ||
93 | end |