Mercurial > urweb
comparison src/mono_fooify.sml @ 2254:44ae2254f8fb
Factor out urlification.
author | Ziv Scully <ziv@mit.edu> |
---|---|
date | Mon, 21 Sep 2015 16:07:35 -0400 |
parents | |
children | 6f2ea4ed573a |
comparison
equal
deleted
inserted
replaced
2253:d665925acff8 | 2254:44ae2254f8fb |
---|---|
1 structure MonoFooify :> MONO_FOOIFY = struct | |
2 | |
3 open Mono | |
4 | |
5 datatype foo_kind = | |
6 Attr | |
7 | Url | |
8 | |
9 val nextPvar = ref 0 | |
10 val pvarDefs = ref ([] : (string * int * (string * int * typ option) list) list) | |
11 | |
12 structure Fm = struct | |
13 | |
14 type vr = string * int * typ * exp * string | |
15 | |
16 structure IM = IntBinaryMap | |
17 | |
18 structure M = BinaryMapFn(struct | |
19 type ord_key = foo_kind | |
20 fun compare x = | |
21 case x of | |
22 (Attr, Attr) => EQUAL | |
23 | (Attr, _) => LESS | |
24 | (_, Attr) => GREATER | |
25 | |
26 | (Url, Url) => EQUAL | |
27 end) | |
28 | |
29 structure TM = BinaryMapFn(struct | |
30 type ord_key = typ | |
31 val compare = MonoUtil.Typ.compare | |
32 end) | |
33 | |
34 type t = { | |
35 count : int, | |
36 map : int IM.map M.map, | |
37 listMap : int TM.map M.map, | |
38 decls : vr list | |
39 } | |
40 | |
41 fun empty count = { | |
42 count = count, | |
43 map = M.empty, | |
44 listMap = M.empty, | |
45 decls = [] | |
46 } | |
47 | |
48 fun chooseNext count = | |
49 let | |
50 val n = !nextPvar | |
51 in | |
52 if count < n then | |
53 (count, count+1) | |
54 else | |
55 (nextPvar := n + 1; | |
56 (n, n+1)) | |
57 end | |
58 | |
59 fun enter ({count, map, listMap, ...} : t) = {count = count, map = map, listMap = listMap, decls = []} | |
60 fun freshName {count, map, listMap, decls} = | |
61 let | |
62 val (next, count) = chooseNext count | |
63 in | |
64 (next, {count = count , map = map, listMap = listMap, decls = decls}) | |
65 end | |
66 fun decls ({decls, ...} : t) = | |
67 case decls of | |
68 [] => [] | |
69 | _ => [(DValRec decls, ErrorMsg.dummySpan)] | |
70 | |
71 fun lookup (t as {count, map, listMap, decls}) k n thunk = | |
72 let | |
73 val im = Option.getOpt (M.find (map, k), IM.empty) | |
74 in | |
75 case IM.find (im, n) of | |
76 NONE => | |
77 let | |
78 val n' = count | |
79 val (d, {count, map, listMap, decls}) = | |
80 thunk count {count = count + 1, | |
81 map = M.insert (map, k, IM.insert (im, n, n')), | |
82 listMap = listMap, | |
83 decls = decls} | |
84 in | |
85 ({count = count, | |
86 map = map, | |
87 listMap = listMap, | |
88 decls = d :: decls}, n') | |
89 end | |
90 | SOME n' => (t, n') | |
91 end | |
92 | |
93 fun lookupList (t as {count, map, listMap, decls}) k tp thunk = | |
94 let | |
95 val tm = Option.getOpt (M.find (listMap, k), TM.empty) | |
96 in | |
97 case TM.find (tm, tp) of | |
98 NONE => | |
99 let | |
100 val n' = count | |
101 val (d, {count, map, listMap, decls}) = | |
102 thunk count {count = count + 1, | |
103 map = map, | |
104 listMap = M.insert (listMap, k, TM.insert (tm, tp, n')), | |
105 decls = decls} | |
106 in | |
107 ({count = count, | |
108 map = map, | |
109 listMap = listMap, | |
110 decls = d :: decls}, n') | |
111 end | |
112 | SOME n' => (t, n') | |
113 end | |
114 | |
115 (* Has to be set at the end of [Monoize]. *) | |
116 val canonical = ref (empty 0 : t) | |
117 | |
118 end | |
119 | |
120 fun fk2s fk = | |
121 case fk of | |
122 Attr => "attr" | |
123 | Url => "url" | |
124 | |
125 fun capitalize s = | |
126 if s = "" then | |
127 s | |
128 else | |
129 str (Char.toUpper (String.sub (s, 0))) ^ String.extract (s, 1, NONE) | |
130 | |
131 structure E = ErrorMsg | |
132 | |
133 val dummyExp = (EPrim (Prim.Int 0), E.dummySpan) | |
134 | |
135 fun fooifyExp fk lookupENamed lookupDatatype = | |
136 let | |
137 fun fooify fm (e, tAll as (t, loc)) = | |
138 case #1 e of | |
139 EClosure (fnam, [(ERecord [], _)]) => | |
140 let | |
141 val (_, s) = lookupENamed fnam | |
142 in | |
143 ((EPrim (Prim.String (Prim.Normal, Settings.getUrlPrefix () ^ s)), loc), fm) | |
144 end | |
145 | EClosure (fnam, args) => | |
146 let | |
147 val (ft, s) = lookupENamed fnam | |
148 fun attrify (args, ft, e, fm) = | |
149 case (args, ft) of | |
150 ([], _) => (e, fm) | |
151 | (arg :: args, (TFun (t, ft), _)) => | |
152 let | |
153 val (arg', fm) = fooify fm (arg, t) | |
154 in | |
155 attrify (args, ft, | |
156 (EStrcat (e, | |
157 (EStrcat ((EPrim (Prim.String (Prim.Normal, "/")), loc), | |
158 arg'), loc)), loc), | |
159 fm) | |
160 end | |
161 | _ => (E.errorAt loc "Type mismatch encoding attribute"; | |
162 (e, fm)) | |
163 in | |
164 attrify (args, ft, (EPrim (Prim.String (Prim.Normal, Settings.getUrlPrefix () ^ s)), loc), fm) | |
165 end | |
166 | _ => | |
167 case t of | |
168 TFfi ("Basis", "unit") => ((EPrim (Prim.String (Prim.Normal, "")), loc), fm) | |
169 | TFfi (m, x) => ((EFfiApp (m, fk2s fk ^ "ify" ^ capitalize x, [(e, tAll)]), loc), fm) | |
170 | |
171 | TRecord [] => ((EPrim (Prim.String (Prim.Normal, "")), loc), fm) | |
172 | TRecord ((x, t) :: xts) => | |
173 let | |
174 val (se, fm) = fooify fm ((EField (e, x), loc), t) | |
175 in | |
176 foldl (fn ((x, t), (se, fm)) => | |
177 let | |
178 val (se', fm) = fooify fm ((EField (e, x), loc), t) | |
179 in | |
180 ((EStrcat (se, | |
181 (EStrcat ((EPrim (Prim.String (Prim.Normal, "/")), loc), | |
182 se'), loc)), loc), | |
183 fm) | |
184 end) (se, fm) xts | |
185 end | |
186 | |
187 | TDatatype (i, ref (dk, _)) => | |
188 let | |
189 fun makeDecl n fm = | |
190 let | |
191 val (x, xncs) = | |
192 case ListUtil.search (fn (x, i', xncs) => | |
193 if i' = i then | |
194 SOME (x, xncs) | |
195 else | |
196 NONE) (!pvarDefs) of | |
197 NONE => lookupDatatype i | |
198 | SOME v => v | |
199 | |
200 val (branches, fm) = | |
201 ListUtil.foldlMap | |
202 (fn ((x, n, to), fm) => | |
203 case to of | |
204 NONE => | |
205 (((PCon (dk, PConVar n, NONE), loc), | |
206 (EPrim (Prim.String (Prim.Normal, x)), loc)), | |
207 fm) | |
208 | SOME t => | |
209 let | |
210 val (arg, fm) = fooify fm ((ERel 0, loc), t) | |
211 in | |
212 (((PCon (dk, PConVar n, SOME (PVar ("a", t), loc)), loc), | |
213 (EStrcat ((EPrim (Prim.String (Prim.Normal, x ^ "/")), loc), | |
214 arg), loc)), | |
215 fm) | |
216 end) | |
217 fm xncs | |
218 | |
219 val dom = tAll | |
220 val ran = (TFfi ("Basis", "string"), loc) | |
221 in | |
222 ((fk2s fk ^ "ify_" ^ x, | |
223 n, | |
224 (TFun (dom, ran), loc), | |
225 (EAbs ("x", | |
226 dom, | |
227 ran, | |
228 (ECase ((ERel 0, loc), | |
229 branches, | |
230 {disc = dom, | |
231 result = ran}), loc)), loc), | |
232 ""), | |
233 fm) | |
234 end | |
235 | |
236 val (fm, n) = Fm.lookup fm fk i makeDecl | |
237 in | |
238 ((EApp ((ENamed n, loc), e), loc), fm) | |
239 end | |
240 | |
241 | TOption t => | |
242 let | |
243 val (body, fm) = fooify fm ((ERel 0, loc), t) | |
244 in | |
245 ((ECase (e, | |
246 [((PNone t, loc), | |
247 (EPrim (Prim.String (Prim.Normal, "None")), loc)), | |
248 | |
249 ((PSome (t, (PVar ("x", t), loc)), loc), | |
250 (EStrcat ((EPrim (Prim.String (Prim.Normal, "Some/")), loc), | |
251 body), loc))], | |
252 {disc = tAll, | |
253 result = (TFfi ("Basis", "string"), loc)}), loc), | |
254 fm) | |
255 end | |
256 | |
257 | TList t => | |
258 let | |
259 fun makeDecl n fm = | |
260 let | |
261 val rt = (TRecord [("1", t), ("2", (TList t, loc))], loc) | |
262 val (arg, fm) = fooify fm ((ERel 0, loc), rt) | |
263 | |
264 val branches = [((PNone rt, loc), | |
265 (EPrim (Prim.String (Prim.Normal, "Nil")), loc)), | |
266 ((PSome (rt, (PVar ("a", rt), loc)), loc), | |
267 (EStrcat ((EPrim (Prim.String (Prim.Normal, "Cons/")), loc), | |
268 arg), loc))] | |
269 | |
270 val dom = tAll | |
271 val ran = (TFfi ("Basis", "string"), loc) | |
272 in | |
273 ((fk2s fk ^ "ify_list", | |
274 n, | |
275 (TFun (dom, ran), loc), | |
276 (EAbs ("x", | |
277 dom, | |
278 ran, | |
279 (ECase ((ERel 0, loc), | |
280 branches, | |
281 {disc = dom, | |
282 result = ran}), loc)), loc), | |
283 ""), | |
284 fm) | |
285 end | |
286 | |
287 val (fm, n) = Fm.lookupList fm fk t makeDecl | |
288 in | |
289 ((EApp ((ENamed n, loc), e), loc), fm) | |
290 end | |
291 | |
292 | _ => (E.errorAt loc "Don't know how to encode attribute/URL type"; | |
293 Print.eprefaces' [("Type", MonoPrint.p_typ MonoEnv.empty tAll)]; | |
294 (dummyExp, fm)) | |
295 in | |
296 fooify | |
297 end | |
298 | |
299 fun urlify env expTyp = | |
300 let | |
301 val (exp, fm) = | |
302 fooifyExp | |
303 Url | |
304 (fn n => | |
305 let | |
306 val (_, t, _, s) = MonoEnv.lookupENamed env n | |
307 in | |
308 (t, s) | |
309 end) | |
310 (fn n => MonoEnv.lookupDatatype env n) | |
311 (!Fm.canonical) | |
312 expTyp | |
313 in | |
314 Fm.canonical := fm; | |
315 exp | |
316 end | |
317 end |