annotate src/mono_fooify.sml @ 2296:5104e480b3e3

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