adamc@315
|
1 (* Copyright (c) 2008, Adam Chlipala
|
adamc@315
|
2 * All rights reserved.
|
adamc@315
|
3 *
|
adamc@315
|
4 * Redistribution and use in source and binary forms, with or without
|
adamc@315
|
5 * modification, are permitted provided that the following conditions are met:
|
adamc@315
|
6 *
|
adamc@315
|
7 * - Redistributions of source code must retain the above copyright notice,
|
adamc@315
|
8 * this list of conditions and the following disclaimer.
|
adamc@315
|
9 * - Redistributions in binary form must reproduce the above copyright notice,
|
adamc@315
|
10 * this list of conditions and the following disclaimer in the documentation
|
adamc@315
|
11 * and/or other materials provided with the distribution.
|
adamc@315
|
12 * - The names of contributors may not be used to endorse or promote products
|
adamc@315
|
13 * derived from this software without specific prior written permission.
|
adamc@315
|
14 *
|
adamc@315
|
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
adamc@315
|
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
adamc@315
|
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
adamc@315
|
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
adamc@315
|
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
adamc@315
|
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
adamc@315
|
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
adamc@315
|
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
adamc@315
|
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
adamc@315
|
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
adamc@315
|
25 * POSSIBILITY OF SUCH DAMAGE.
|
adamc@315
|
26 *)
|
adamc@315
|
27
|
adamc@315
|
28 (* Simplify a Core program by repeating polymorphic function definitions *)
|
adamc@315
|
29
|
adamc@315
|
30 structure Unpoly :> UNPOLY = struct
|
adamc@315
|
31
|
adamc@315
|
32 open Core
|
adamc@315
|
33
|
adamc@315
|
34 structure E = CoreEnv
|
adamc@315
|
35 structure U = CoreUtil
|
adamc@315
|
36
|
adamc@315
|
37 structure IS = IntBinarySet
|
adamc@315
|
38 structure IM = IntBinaryMap
|
adamc@315
|
39
|
adamc@315
|
40
|
adamc@315
|
41 (** The actual specialization *)
|
adamc@315
|
42
|
adamc@315
|
43 val liftConInCon = E.liftConInCon
|
adamc@315
|
44 val subConInCon = E.subConInCon
|
adamc@315
|
45
|
adamc@315
|
46 val liftConInExp = E.liftConInExp
|
adamc@315
|
47 val subConInExp = E.subConInExp
|
adamc@315
|
48
|
adamc@399
|
49 val isOpen = U.Con.exists {kind = fn _ => false,
|
adamc@399
|
50 con = fn c =>
|
adamc@399
|
51 case c of
|
adamc@399
|
52 CRel _ => true
|
adamc@399
|
53 | _ => false}
|
adamc@399
|
54
|
adamc@316
|
55 fun unpolyNamed (xn, rep) =
|
adamc@316
|
56 U.Exp.map {kind = fn k => k,
|
adamc@316
|
57 con = fn c => c,
|
adamc@316
|
58 exp = fn e =>
|
adamc@316
|
59 case e of
|
adamc@399
|
60 ECApp (e', _) =>
|
adamc@325
|
61 let
|
adamc@325
|
62 fun isTheOne (e, _) =
|
adamc@325
|
63 case e of
|
adamc@325
|
64 ENamed xn' => xn' = xn
|
adamc@325
|
65 | ECApp (e, _) => isTheOne e
|
adamc@325
|
66 | _ => false
|
adamc@325
|
67 in
|
adamc@325
|
68 if isTheOne e' then
|
adamc@399
|
69 rep
|
adamc@325
|
70 else
|
adamc@325
|
71 e
|
adamc@325
|
72 end
|
adamc@316
|
73 | _ => e}
|
adamc@316
|
74
|
adamc@315
|
75 type state = {
|
adamc@315
|
76 funcs : (kind list * (string * int * con * exp * string) list) IM.map,
|
adamc@315
|
77 decls : decl list,
|
adamc@315
|
78 nextName : int
|
adamc@315
|
79 }
|
adamc@315
|
80
|
adamc@315
|
81 fun kind (k, st) = (k, st)
|
adamc@315
|
82
|
adamc@315
|
83 fun con (c, st) = (c, st)
|
adamc@315
|
84
|
adamc@315
|
85 fun exp (e, st : state) =
|
adamc@315
|
86 case e of
|
adamc@315
|
87 ECApp _ =>
|
adamc@315
|
88 let
|
adamc@315
|
89 (*val () = Print.prefaces "exp" [("e", CorePrint.p_exp CoreEnv.empty (e, ErrorMsg.dummySpan))]*)
|
adamc@315
|
90
|
adamc@315
|
91 fun unravel (e, cargs) =
|
adamc@315
|
92 case e of
|
adamc@315
|
93 ECApp ((e, _), c) => unravel (e, c :: cargs)
|
adamc@315
|
94 | ENamed n => SOME (n, rev cargs)
|
adamc@315
|
95 | _ => NONE
|
adamc@315
|
96 in
|
adamc@315
|
97 case unravel (e, []) of
|
adamc@315
|
98 NONE => (e, st)
|
adamc@315
|
99 | SOME (n, cargs) =>
|
adamc@399
|
100 if List.exists isOpen cargs then
|
adamc@399
|
101 (e, st)
|
adamc@399
|
102 else
|
adamc@399
|
103 case IM.find (#funcs st, n) of
|
adamc@399
|
104 NONE => (e, st)
|
adamc@399
|
105 | SOME (ks, vis) =>
|
adamc@399
|
106 let
|
adamc@399
|
107 val (vis, nextName) = ListUtil.foldlMap
|
adamc@399
|
108 (fn ((x, n, t, e, s), nextName) =>
|
adamc@399
|
109 ((x, nextName, n, t, e, s), nextName + 1))
|
adamc@399
|
110 (#nextName st) vis
|
adamc@315
|
111
|
adamc@399
|
112 fun specialize (x, n, n_old, t, e, s) =
|
adamc@399
|
113 let
|
adamc@399
|
114 fun trim (t, e, cargs) =
|
adamc@399
|
115 case (t, e, cargs) of
|
adamc@399
|
116 ((TCFun (_, _, t), _),
|
adamc@399
|
117 (ECAbs (_, _, e), _),
|
adamc@399
|
118 carg :: cargs) =>
|
adamc@399
|
119 let
|
adamc@399
|
120 val t = subConInCon (length cargs, carg) t
|
adamc@399
|
121 val e = subConInExp (length cargs, carg) e
|
adamc@399
|
122 in
|
adamc@399
|
123 trim (t, e, cargs)
|
adamc@399
|
124 end
|
adamc@399
|
125 | (_, _, []) =>
|
adamc@399
|
126 let
|
adamc@399
|
127 val e = foldl (fn ((_, n, n_old, _, _, _), e) =>
|
adamc@399
|
128 unpolyNamed (n_old, ENamed n) e)
|
adamc@399
|
129 e vis
|
adamc@399
|
130 in
|
adamc@399
|
131 SOME (t, e)
|
adamc@399
|
132 end
|
adamc@399
|
133 | _ => NONE
|
adamc@399
|
134 in
|
adamc@399
|
135 (*Print.prefaces "specialize"
|
adamc@399
|
136 [("t", CorePrint.p_con CoreEnv.empty t),
|
adamc@399
|
137 ("e", CorePrint.p_exp CoreEnv.empty e),
|
adamc@399
|
138 ("|cargs|", Print.PD.string (Int.toString (length cargs)))];*)
|
adamc@399
|
139 Option.map (fn (t, e) => (x, n, n_old, t, e, s))
|
adamc@399
|
140 (trim (t, e, cargs))
|
adamc@399
|
141 end
|
adamc@315
|
142
|
adamc@399
|
143 val vis = List.map specialize vis
|
adamc@399
|
144 in
|
adamc@399
|
145 if List.exists (not o Option.isSome) vis orelse length cargs > length ks then
|
adamc@399
|
146 (e, st)
|
adamc@399
|
147 else
|
adamc@399
|
148 let
|
adamc@399
|
149 val vis = List.mapPartial (fn x => x) vis
|
adamc@399
|
150 val vis = map (fn (x, n, n_old, t, e, s) =>
|
adamc@399
|
151 (x ^ "_unpoly", n, n_old, t, e, s)) vis
|
adamc@399
|
152 val vis' = map (fn (x, n, _, t, e, s) =>
|
adamc@399
|
153 (x, n, t, e, s)) vis
|
adamc@316
|
154
|
adamc@399
|
155 val ks' = List.drop (ks, length cargs)
|
adamc@399
|
156 in
|
adamc@399
|
157 case List.find (fn (_, _, n_old, _, _, _) => n_old = n) vis of
|
adamc@399
|
158 NONE => raise Fail "Unpoly: Inconsistent 'val rec' record"
|
adamc@399
|
159 | SOME (_, n, _, _, _, _) =>
|
adamc@399
|
160 (ENamed n,
|
adamc@399
|
161 {funcs = foldl (fn (vi, funcs) =>
|
adamc@399
|
162 IM.insert (funcs, #2 vi, (ks', vis')))
|
adamc@399
|
163 (#funcs st) vis',
|
adamc@399
|
164 decls = (DValRec vis', ErrorMsg.dummySpan) :: #decls st,
|
adamc@399
|
165 nextName = nextName})
|
adamc@399
|
166 end
|
adamc@399
|
167 end
|
adamc@315
|
168 end
|
adamc@315
|
169 | _ => (e, st)
|
adamc@315
|
170
|
adamc@315
|
171 fun decl (d, st : state) =
|
adamc@315
|
172 case d of
|
adamc@315
|
173 DValRec (vis as ((x, n, t, e, s) :: rest)) =>
|
adamc@315
|
174 let
|
adamc@315
|
175 fun unravel (e, cargs) =
|
adamc@315
|
176 case e of
|
adamc@315
|
177 (ECAbs (_, k, e), _) =>
|
adamc@315
|
178 unravel (e, k :: cargs)
|
adamc@315
|
179 | _ => rev cargs
|
adamc@315
|
180
|
adamc@315
|
181 val cargs = unravel (e, [])
|
adamc@315
|
182
|
adamc@315
|
183 fun unravel (e, cargs) =
|
adamc@315
|
184 case (e, cargs) of
|
adamc@315
|
185 ((ECAbs (_, k, e), _), k' :: cargs) =>
|
adamc@315
|
186 U.Kind.compare (k, k') = EQUAL
|
adamc@315
|
187 andalso unravel (e, cargs)
|
adamc@315
|
188 | (_, []) => true
|
adamc@315
|
189 | _ => false
|
adamc@315
|
190 in
|
adamc@315
|
191 if List.exists (fn vi => not (unravel (#4 vi, cargs))) rest then
|
adamc@315
|
192 (d, st)
|
adamc@315
|
193 else
|
adamc@315
|
194 let
|
adamc@315
|
195 val ns = IS.addList (IS.empty, map #2 vis)
|
adamc@315
|
196 val nargs = length cargs
|
adamc@315
|
197
|
adamc@315
|
198 fun deAbs (e, cargs) =
|
adamc@315
|
199 case (e, cargs) of
|
adamc@315
|
200 ((ECAbs (_, _, e), _), _ :: cargs) => deAbs (e, cargs)
|
adamc@315
|
201 | (_, []) => e
|
adamc@315
|
202 | _ => raise Fail "Unpoly: deAbs"
|
adamc@315
|
203
|
adamc@315
|
204 (** Verifying lack of polymorphic recursion *)
|
adamc@315
|
205
|
adamc@315
|
206 fun kind _ = false
|
adamc@315
|
207 fun con _ = false
|
adamc@315
|
208
|
adamc@315
|
209 fun exp e =
|
adamc@315
|
210 case e of
|
adamc@315
|
211 ECApp (e, c) =>
|
adamc@315
|
212 let
|
adamc@315
|
213 fun isIrregular (e, pos) =
|
adamc@315
|
214 case #1 e of
|
adamc@315
|
215 ENamed n =>
|
adamc@315
|
216 IS.member (ns, n)
|
adamc@315
|
217 andalso
|
adamc@315
|
218 (case #1 c of
|
adamc@315
|
219 CRel i => i <> nargs - pos
|
adamc@315
|
220 | _ => true)
|
adamc@315
|
221 | ECApp (e, _) => isIrregular (e, pos + 1)
|
adamc@315
|
222 | _ => false
|
adamc@315
|
223 in
|
adamc@315
|
224 isIrregular (e, 1)
|
adamc@315
|
225 end
|
adamc@315
|
226 | ECAbs _ => true
|
adamc@315
|
227 | _ => false
|
adamc@315
|
228
|
adamc@315
|
229 val irregular = U.Exp.exists {kind = kind, con = con, exp = exp}
|
adamc@315
|
230 in
|
adamc@315
|
231 if List.exists (fn x => irregular (deAbs (#4 x, cargs))) vis then
|
adamc@315
|
232 (d, st)
|
adamc@315
|
233 else
|
adamc@315
|
234 (d, {funcs = foldl (fn (vi, funcs) =>
|
adamc@315
|
235 IM.insert (funcs, #2 vi, (cargs, vis)))
|
adamc@315
|
236 (#funcs st) vis,
|
adamc@315
|
237 decls = #decls st,
|
adamc@315
|
238 nextName = #nextName st})
|
adamc@315
|
239 end
|
adamc@315
|
240 end
|
adamc@315
|
241
|
adamc@315
|
242 | _ => (d, st)
|
adamc@315
|
243
|
adamc@315
|
244 val polyDecl = U.Decl.foldMap {kind = kind, con = con, exp = exp, decl = decl}
|
adamc@315
|
245
|
adamc@315
|
246 fun unpoly file =
|
adamc@315
|
247 let
|
adamc@315
|
248 fun doDecl (d : decl, st : state) =
|
adamc@315
|
249 let
|
adamc@315
|
250 val (d, st) = polyDecl st d
|
adamc@315
|
251 in
|
adamc@315
|
252 (rev (d :: #decls st),
|
adamc@315
|
253 {funcs = #funcs st,
|
adamc@315
|
254 decls = [],
|
adamc@315
|
255 nextName = #nextName st})
|
adamc@315
|
256 end
|
adamc@315
|
257
|
adamc@315
|
258 val (ds, _) = ListUtil.foldlMapConcat doDecl
|
adamc@315
|
259 {funcs = IM.empty,
|
adamc@315
|
260 decls = [],
|
adamc@315
|
261 nextName = U.File.maxName file + 1} file
|
adamc@315
|
262 in
|
adamc@315
|
263 ds
|
adamc@315
|
264 end
|
adamc@315
|
265
|
adamc@315
|
266 end
|