annotate src/rpcify.sml @ 640:63b0bcacd535

RPC returning a default datatype
author Adam Chlipala <adamc@hcoop.net>
date Sun, 08 Mar 2009 13:28:21 -0400
parents c5991cdb0c4b
children 4a125bbc602d
rev   line source
adamc@607 1 (* Copyright (c) 2009, Adam Chlipala
adamc@607 2 * All rights reserved.
adamc@607 3 *
adamc@607 4 * Redistribution and use in source and binary forms, with or without
adamc@607 5 * modification, are permitted provided that the following conditions are met:
adamc@607 6 *
adamc@607 7 * - Redistributions of source code must retain the above copyright notice,
adamc@607 8 * this list of conditions and the following disclaimer.
adamc@607 9 * - Redistributions in binary form must reproduce the above copyright notice,
adamc@607 10 * this list of conditions and the following disclaimer in the documentation
adamc@607 11 * and/or other materials provided with the distribution.
adamc@607 12 * - The names of contributors may not be used to endorse or promote products
adamc@607 13 * derived from this software without specific prior written permission.
adamc@607 14 *
adamc@607 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
adamc@607 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
adamc@607 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
adamc@607 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
adamc@607 19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
adamc@607 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
adamc@607 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
adamc@607 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
adamc@607 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
adamc@607 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
adamc@607 25 * POSSIBILITY OF SUCH DAMAGE.
adamc@607 26 *)
adamc@607 27
adamc@607 28 structure Rpcify :> RPCIFY = struct
adamc@607 29
adamc@607 30 open Core
adamc@607 31
adamc@607 32 structure U = CoreUtil
adamc@607 33 structure E = CoreEnv
adamc@607 34
adamc@607 35 structure IS = IntBinarySet
adamc@607 36 structure IM = IntBinaryMap
adamc@607 37
adamc@607 38 structure SS = BinarySetFn(struct
adamc@607 39 type ord_key = string
adamc@607 40 val compare = String.compare
adamc@607 41 end)
adamc@607 42
adamc@607 43 val ssBasis = SS.addList (SS.empty,
adamc@607 44 ["requestHeader",
adamc@607 45 "query",
adamc@607 46 "dml",
adamc@607 47 "nextval"])
adamc@607 48
adamc@607 49 val csBasis = SS.addList (SS.empty,
adamc@607 50 ["source",
adamc@607 51 "get",
adamc@607 52 "set",
adamc@607 53 "alert"])
adamc@607 54
adamc@607 55 type state = {
adamc@608 56 cpsed : int IM.map,
adamc@608 57 cps_decls : (string * int * con * exp * string) list,
adamc@608 58
adamc@608 59 exported : IS.set,
adamc@608 60 export_decls : decl list
adamc@607 61 }
adamc@607 62
adamc@607 63 fun frob file =
adamc@607 64 let
adamc@607 65 fun sideish (basis, ssids) =
adamc@607 66 U.Exp.exists {kind = fn _ => false,
adamc@607 67 con = fn _ => false,
adamc@607 68 exp = fn ENamed n => IS.member (ssids, n)
adamc@607 69 | EFfi ("Basis", x) => SS.member (basis, x)
adamc@607 70 | EFfiApp ("Basis", x, _) => SS.member (basis, x)
adamc@607 71 | _ => false}
adamc@607 72
adamc@607 73 fun whichIds basis =
adamc@607 74 let
adamc@607 75 fun decl ((d, _), ssids) =
adamc@607 76 let
adamc@607 77 val impure = sideish (basis, ssids)
adamc@607 78 in
adamc@607 79 case d of
adamc@607 80 DVal (_, n, _, e, _) => if impure e then
adamc@607 81 IS.add (ssids, n)
adamc@607 82 else
adamc@607 83 ssids
adamc@607 84 | DValRec xes => if List.exists (fn (_, _, _, e, _) => impure e) xes then
adamc@607 85 foldl (fn ((_, n, _, _, _), ssids) => IS.add (ssids, n))
adamc@607 86 ssids xes
adamc@607 87 else
adamc@607 88 ssids
adamc@607 89 | _ => ssids
adamc@607 90 end
adamc@607 91 in
adamc@607 92 foldl decl IS.empty file
adamc@607 93 end
adamc@607 94
adamc@607 95 val ssids = whichIds ssBasis
adamc@607 96 val csids = whichIds csBasis
adamc@607 97
adamc@607 98 val serverSide = sideish (ssBasis, ssids)
adamc@607 99 val clientSide = sideish (csBasis, csids)
adamc@607 100
adamc@609 101 val tfuncs = foldl
adamc@609 102 (fn ((d, _), tfuncs) =>
adamc@609 103 let
adamc@609 104 fun doOne ((_, n, t, _, _), tfuncs) =
adamc@609 105 let
adamc@613 106 fun crawl (t, args) =
adamc@613 107 case #1 t of
adamc@609 108 CApp ((CFfi ("Basis", "transaction"), _), ran) => SOME (rev args, ran)
adamc@609 109 | TFun (arg, rest) => crawl (rest, arg :: args)
adamc@609 110 | _ => NONE
adamc@609 111 in
adamc@609 112 case crawl (t, []) of
adamc@609 113 NONE => tfuncs
adamc@609 114 | SOME sg => IM.insert (tfuncs, n, sg)
adamc@609 115 end
adamc@609 116 in
adamc@609 117 case d of
adamc@609 118 DVal vi => doOne (vi, tfuncs)
adamc@609 119 | DValRec vis => foldl doOne tfuncs vis
adamc@609 120 | _ => tfuncs
adamc@609 121 end)
adamc@609 122 IM.empty file
adamc@609 123
adamc@607 124 fun exp (e, st) =
adamc@607 125 case e of
adamc@607 126 EApp (
adamc@607 127 (EApp
adamc@607 128 ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), loc), _), _), t1), _), t2), _),
adamc@607 129 (EFfi ("Basis", "transaction_monad"), _)), _),
adamc@607 130 trans1), _),
adamc@607 131 trans2) =>
adamc@607 132 (case (serverSide trans1, clientSide trans1, serverSide trans2, clientSide trans2) of
adamc@613 133 (true, false, false, true) =>
adamc@607 134 let
adamc@607 135 fun getApp (e, args) =
adamc@607 136 case #1 e of
adamc@607 137 ENamed n => (n, args)
adamc@607 138 | EApp (e1, e2) => getApp (e1, e2 :: args)
adamc@607 139 | _ => (ErrorMsg.errorAt loc "Mixed client/server code doesn't use a named function for server part";
adamc@607 140 (0, []))
adamc@607 141
adamc@607 142 val (n, args) = getApp (trans1, [])
adamc@608 143
adamc@608 144 val (exported, export_decls) =
adamc@608 145 if IS.member (#exported st, n) then
adamc@608 146 (#exported st, #export_decls st)
adamc@608 147 else
adamc@608 148 (IS.add (#exported st, n),
adamc@608 149 (DExport (Rpc, n), loc) :: #export_decls st)
adamc@608 150
adamc@608 151 val st = {cpsed = #cpsed st,
adamc@608 152 cps_decls = #cps_decls st,
adamc@608 153
adamc@608 154 exported = exported,
adamc@608 155 export_decls = export_decls}
adamc@609 156
adamc@609 157 val ran =
adamc@609 158 case IM.find (tfuncs, n) of
adamc@613 159 NONE => (Print.prefaces "BAD" [("e", CorePrint.p_exp CoreEnv.empty (e, loc))];
adamc@613 160 raise Fail "Rpcify: Undetected transaction function")
adamc@609 161 | SOME (_, ran) => ran
adamc@607 162 in
adamc@609 163 (EServerCall (n, args, trans2, ran), st)
adamc@607 164 end
adamc@607 165 | _ => (e, st))
adamc@607 166 | _ => (e, st)
adamc@607 167
adamc@607 168 fun decl (d, st : state) =
adamc@607 169 let
adamc@607 170 val (d, st) = U.Decl.foldMap {kind = fn x => x,
adamc@607 171 con = fn x => x,
adamc@607 172 exp = exp,
adamc@607 173 decl = fn x => x}
adamc@607 174 st d
adamc@607 175 in
adamc@608 176 (List.revAppend (case #cps_decls st of
adamc@608 177 [] => [d]
adamc@608 178 | ds =>
adamc@608 179 case d of
adamc@608 180 (DValRec vis, loc) => [(DValRec (ds @ vis), loc)]
adamc@608 181 | (_, loc) => [d, (DValRec ds, loc)],
adamc@608 182 #export_decls st),
adamc@608 183 {cpsed = #cpsed st,
adamc@608 184 cps_decls = [],
adamc@608 185
adamc@608 186 exported = #exported st,
adamc@608 187 export_decls = []})
adamc@607 188 end
adamc@607 189
adamc@607 190 val (file, _) = ListUtil.foldlMapConcat decl
adamc@608 191 {cpsed = IM.empty,
adamc@608 192 cps_decls = [],
adamc@608 193
adamc@608 194 exported = IS.empty,
adamc@608 195 export_decls = []}
adamc@607 196 file
adamc@607 197 in
adamc@607 198 file
adamc@607 199 end
adamc@607 200
adamc@607 201 end