comparison src/unpoly.sml @ 315:e21d0dddda09

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