Mercurial > urweb
changeset 607:0dd40b6bfdf3
Start of RPCification
author | Adam Chlipala <adamc@hcoop.net> |
---|---|
date | Sat, 14 Feb 2009 14:07:56 -0500 |
parents | 5145181b02fa |
children | 330a7de47914 |
files | demo/crud2.sql src/compiler.sig src/compiler.sml src/core.sml src/core_print.sml src/core_util.sml src/monoize.sml src/reduce.sml src/reduce_local.sml src/rpcify.sig src/rpcify.sml src/shake.sml src/sources tests/rpc.ur tests/rpc.urp |
diffstat | 15 files changed, 269 insertions(+), 28 deletions(-) [+] |
line wrap: on
line diff
--- a/demo/crud2.sql Tue Jan 27 09:53:51 2009 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -CREATE TABLE uw_Crud2_t(uw_id int8 NOT NULL, uw_nam text NOT NULL, - uw_ready bool NOT NULL); - - CREATE SEQUENCE uw_Crud2_Crud_Make_seq; - - \ No newline at end of file
--- a/src/compiler.sig Tue Jan 27 09:53:51 2009 -0500 +++ b/src/compiler.sig Sat Feb 14 14:07:56 2009 -0500 @@ -66,6 +66,7 @@ val especialize : (Core.file, Core.file) phase val core_untangle : (Core.file, Core.file) phase val shake : (Core.file, Core.file) phase + val rpcify : (Core.file, Core.file) phase val tag : (Core.file, Core.file) phase val reduce : (Core.file, Core.file) phase val unpoly : (Core.file, Core.file) phase @@ -92,6 +93,7 @@ val toEspecialize : (string, Core.file) transform val toCore_untangle : (string, Core.file) transform val toShake1 : (string, Core.file) transform + val toRpcify : (string, Core.file) transform val toTag : (string, Core.file) transform val toReduce : (string, Core.file) transform val toUnpoly : (string, Core.file) transform
--- a/src/compiler.sml Tue Jan 27 09:53:51 2009 -0500 +++ b/src/compiler.sml Sat Feb 14 14:07:56 2009 -0500 @@ -446,12 +446,19 @@ val toShake1 = transform shake "shake1" o toCore_untangle +val rpcify = { + func = Rpcify.frob, + print = CorePrint.p_file CoreEnv.empty +} + +val toRpcify = transform rpcify "rpcify" o toShake1 + val tag = { func = Tag.tag, print = CorePrint.p_file CoreEnv.empty } -val toTag = transform tag "tag" o toShake1 +val toTag = transform tag "tag" o toRpcify val reduce = { func = Reduce.reduce,
--- a/src/core.sml Tue Jan 27 09:53:51 2009 -0500 +++ b/src/core.sml Sat Feb 14 14:07:56 2009 -0500 @@ -106,6 +106,8 @@ | ELet of string * con * exp * exp + | EServerCall of int * exp list * exp + withtype exp = exp' located datatype export_kind =
--- a/src/core_print.sml Tue Jan 27 09:53:51 2009 -0500 +++ b/src/core_print.sml Sat Feb 14 14:07:56 2009 -0500 @@ -394,6 +394,15 @@ newline, p_exp (E.pushERel env x t) e2] + | EServerCall (n, es, e) => box [string "Server(", + p_enamed env n, + string ",", + space, + p_list (p_exp env) es, + string ")[", + p_exp env e, + string "]"] + and p_exp env = p_exp' false env fun p_named x n =
--- a/src/core_util.sml Tue Jan 27 09:53:51 2009 -0500 +++ b/src/core_util.sml Sat Feb 14 14:07:56 2009 -0500 @@ -479,6 +479,13 @@ | (ELet (_, _, x1, e1), ELet (_, _, x2, e2)) => join (compare (x1, x2), fn () => compare (e1, e2)) + | (ELet _, _) => LESS + | (_, ELet _) => GREATER + + | (EServerCall (n1, es1, e1), EServerCall (n2, es2, e2)) => + join (Int.compare (n1, n2), + fn () => join (joinL compare (es1, es2), + fn () => compare (e1, e2))) datatype binder = RelC of string * kind @@ -653,6 +660,13 @@ fn e2' => (ELet (x, t', e1', e2'), loc)))) + | EServerCall (n, es, e) => + S.bind2 (ListUtil.mapfold (mfe ctx) es, + fn es' => + S.map2 (mfe ctx e, + fn e' => + (EServerCall (n, es', e'), loc))) + and mfp ctx (pAll as (p, loc)) = case p of PWild => S.return2 pAll
--- a/src/monoize.sml Tue Jan 27 09:53:51 2009 -0500 +++ b/src/monoize.sml Sat Feb 14 14:07:56 2009 -0500 @@ -2224,6 +2224,8 @@ in ((L'.ELet (x, t', e1, e2), loc), fm) end + + | L.EServerCall _ => raise Fail "Monoize EServerCall" end fun monoDecl (env, fm) (all as (d, loc)) =
--- a/src/reduce.sml Tue Jan 27 09:53:51 2009 -0500 +++ b/src/reduce.sml Sat Feb 14 14:07:56 2009 -0500 @@ -366,7 +366,9 @@ | EWrite e => (EWrite (exp env e), loc) | EClosure (n, es) => (EClosure (n, map (exp env) es), loc) - | ELet (x, t, e1, e2) => (ELet (x, con env t, exp env e1, exp (UnknownE :: env) e2), loc)) + | ELet (x, t, e1, e2) => (ELet (x, con env t, exp env e1, exp (UnknownE :: env) e2), loc) + + | EServerCall (n, es, e) => (EServerCall (n, map (exp env) es, exp env e), loc)) in {con = con, exp = exp} end
--- a/src/reduce_local.sml Tue Jan 27 09:53:51 2009 -0500 +++ b/src/reduce_local.sml Sat Feb 14 14:07:56 2009 -0500 @@ -131,6 +131,8 @@ | ELet (x, t, e1, e2) => (ELet (x, t, exp env e1, exp (Unknown :: env) e2), loc) + | EServerCall (n, es, e) => (EServerCall (n, map (exp env) es, exp env e), loc) + fun reduce file = let fun doDecl (d as (_, loc)) =
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rpcify.sig Sat Feb 14 14:07:56 2009 -0500 @@ -0,0 +1,32 @@ +(* Copyright (c) 2009, Adam Chlipala + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - The names of contributors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *) + +signature RPCIFY = sig + + val frob : Core.file -> Core.file + +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rpcify.sml Sat Feb 14 14:07:56 2009 -0500 @@ -0,0 +1,149 @@ +(* Copyright (c) 2009, Adam Chlipala + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - The names of contributors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *) + +structure Rpcify :> RPCIFY = struct + +open Core + +structure U = CoreUtil +structure E = CoreEnv + +structure IS = IntBinarySet +structure IM = IntBinaryMap + +structure SS = BinarySetFn(struct + type ord_key = string + val compare = String.compare + end) + +val ssBasis = SS.addList (SS.empty, + ["requestHeader", + "query", + "dml", + "nextval"]) + +val csBasis = SS.addList (SS.empty, + ["source", + "get", + "set", + "alert"]) + +type state = { + exps : int IM.map, + decls : (string * int * con * exp * string) list +} + +fun frob file = + let + fun sideish (basis, ssids) = + U.Exp.exists {kind = fn _ => false, + con = fn _ => false, + exp = fn ENamed n => IS.member (ssids, n) + | EFfi ("Basis", x) => SS.member (basis, x) + | EFfiApp ("Basis", x, _) => SS.member (basis, x) + | _ => false} + + fun whichIds basis = + let + fun decl ((d, _), ssids) = + let + val impure = sideish (basis, ssids) + in + case d of + DVal (_, n, _, e, _) => if impure e then + IS.add (ssids, n) + else + ssids + | DValRec xes => if List.exists (fn (_, _, _, e, _) => impure e) xes then + foldl (fn ((_, n, _, _, _), ssids) => IS.add (ssids, n)) + ssids xes + else + ssids + | _ => ssids + end + in + foldl decl IS.empty file + end + + val ssids = whichIds ssBasis + val csids = whichIds csBasis + + val serverSide = sideish (ssBasis, ssids) + val clientSide = sideish (csBasis, csids) + + fun exp (e, st) = + case e of + EApp ( + (EApp + ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), loc), _), _), t1), _), t2), _), + (EFfi ("Basis", "transaction_monad"), _)), _), + trans1), _), + trans2) => + (case (serverSide trans1, clientSide trans1, serverSide trans2, clientSide trans2) of + (true, false, false, _) => + let + fun getApp (e, args) = + case #1 e of + ENamed n => (n, args) + | EApp (e1, e2) => getApp (e1, e2 :: args) + | _ => (ErrorMsg.errorAt loc "Mixed client/server code doesn't use a named function for server part"; + (0, [])) + + val (n, args) = getApp (trans1, []) + in + (EServerCall (n, args, trans2), st) + end + | _ => (e, st)) + | _ => (e, st) + + fun decl (d, st : state) = + let + val (d, st) = U.Decl.foldMap {kind = fn x => x, + con = fn x => x, + exp = exp, + decl = fn x => x} + st d + in + (case #decls st of + [] => [d] + | ds => + case d of + (DValRec vis, loc) => [(DValRec (ds @ vis), loc)] + | (_, loc) => [(DValRec ds, loc), d], + {decls = [], + exps = #exps st}) + end + + val (file, _) = ListUtil.foldlMapConcat decl + {decls = [], + exps = IM.empty} + file + in + file + end + +end
--- a/src/shake.sml Tue Jan 27 09:53:51 2009 -0500 +++ b/src/shake.sml Sat Feb 14 14:07:56 2009 -0500 @@ -94,26 +94,31 @@ and shakeCon s = U.Con.fold {kind = kind, con = con} s fun exp (e, s) = - case e of - ENamed n => - if IS.member (#exp s, n) then - s - else - let - val s' = {exp = IS.add (#exp s, n), - con = #con s} - in - (*print ("Need " ^ Int.toString n ^ "\n");*) - case IM.find (edef, n) of - NONE => s' - | SOME (ns, t, e) => - let - val s' = shakeExp (shakeCon s' t) e - in - foldl (fn (n, s') => exp (ENamed n, s')) s' ns - end - end - | _ => s + let + fun check n = + if IS.member (#exp s, n) then + s + else + let + val s' = {exp = IS.add (#exp s, n), + con = #con s} + in + (*print ("Need " ^ Int.toString n ^ "\n");*) + case IM.find (edef, n) of + NONE => s' + | SOME (ns, t, e) => + let + val s' = shakeExp (shakeCon s' t) e + in + foldl (fn (n, s') => exp (ENamed n, s')) s' ns + end + end + in + case e of + ENamed n => check n + | EServerCall (n, _, _) => check n + | _ => s + end and shakeExp s = U.Exp.fold {kind = kind, con = con, exp = exp} s
--- a/src/sources Tue Jan 27 09:53:51 2009 -0500 +++ b/src/sources Sat Feb 14 14:07:56 2009 -0500 @@ -108,6 +108,9 @@ defunc.sig defunc.sml +rpcify.sig +rpcify.sml + tag.sig tag.sml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/rpc.ur Sat Feb 14 14:07:56 2009 -0500 @@ -0,0 +1,13 @@ +sequence s + +fun main () : transaction page = + let + fun getNext () = nextval s + in + s <- source 0; + return <xml><body> + <button value="Get It On!" + onclick={n <- getNext (); + set s n}/> + </body></xml> + end