From 9f6397d0f801f6e020aa6123f14ddc44e11deee7 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Thu, 6 Nov 2008 12:08:41 -0500
Subject: Reading cookies works
---
src/mono.sml | 2 ++
1 file changed, 2 insertions(+)
(limited to 'src/mono.sml')
diff --git a/src/mono.sml b/src/mono.sml
index b7ac6346..f465d2bd 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -94,6 +94,8 @@ datatype exp' =
| EDml of exp
| ENextval of exp
+ | EUnurlify of exp * typ
+
withtype exp = exp' located
--
cgit v1.2.3
From e478b4d432d65b33613a601f71204fc0c656c3db Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Fri, 19 Dec 2008 12:38:11 -0500
Subject: Displayed an alert dialog
---
include/urweb.h | 2 ++
lib/basis.urs | 7 ++++++-
src/c/urweb.c | 35 +++++++++++++++++++++++++++++++++++
src/cjrize.sml | 2 ++
src/mono.sml | 2 ++
src/mono_opt.sml | 5 +++++
src/mono_print.sml | 3 +++
src/mono_reduce.sml | 2 ++
src/mono_util.sml | 4 ++++
src/monoize.sml | 13 +++++++++++++
tests/alert.ur | 3 +++
tests/alert.urp | 3 +++
12 files changed, 80 insertions(+), 1 deletion(-)
create mode 100644 tests/alert.ur
create mode 100644 tests/alert.urp
(limited to 'src/mono.sml')
diff --git a/include/urweb.h b/include/urweb.h
index 3d7b967c..647f153a 100644
--- a/include/urweb.h
+++ b/include/urweb.h
@@ -94,6 +94,8 @@ uw_Basis_string uw_Basis_sqlifyTimeN(uw_context, uw_Basis_time*);
char *uw_Basis_ensqlBool(uw_Basis_bool);
+char *uw_Basis_jsifyString(uw_context, uw_Basis_string);
+
uw_Basis_string uw_Basis_intToString(uw_context, uw_Basis_int);
uw_Basis_string uw_Basis_floatToString(uw_context, uw_Basis_float);
uw_Basis_string uw_Basis_boolToString(uw_context, uw_Basis_bool);
diff --git a/lib/basis.urs b/lib/basis.urs
index ffba2b37..ac4c4832 100644
--- a/lib/basis.urs
+++ b/lib/basis.urs
@@ -100,6 +100,11 @@ val getCookie : t ::: Type -> http_cookie t -> transaction (option t)
val setCookie : t ::: Type -> http_cookie t -> t -> transaction unit
+(** JavaScript-y gadgets *)
+
+val alert : string -> transaction unit
+
+
(** SQL *)
con sql_table :: {Type} -> Type
@@ -403,7 +408,7 @@ val ul : bodyTag []
val hr : bodyTag []
-val a : bodyTag [Link = transaction page]
+val a : bodyTag [Link = transaction page, Onclick = transaction unit]
val form : ctx ::: {Unit} -> bind ::: {Type}
-> fn [[Body] ~ ctx] =>
diff --git a/src/c/urweb.c b/src/c/urweb.c
index 7a9b3e79..64cdb81e 100644
--- a/src/c/urweb.c
+++ b/src/c/urweb.c
@@ -1056,6 +1056,41 @@ char *uw_Basis_ensqlBool(uw_Basis_bool b) {
return (char *)&true;
}
+uw_Basis_string uw_Basis_jsifyString(uw_context ctx, uw_Basis_string s) {
+ char *r, *s2;
+
+ uw_check_heap(ctx, strlen(s) * 4 + 2);
+
+ r = s2 = ctx->heap_front;
+ *s2++ = '"';
+
+ for (; *s; s++) {
+ char c = *s;
+
+ switch (c) {
+ case '"':
+ strcpy(s2, "\\\"");
+ s2 += 2;
+ break;
+ case '\\':
+ strcpy(s2, "\\\\");
+ s2 += 2;
+ break;
+ default:
+ if (isprint(c))
+ *s2++ = c;
+ else {
+ sprintf(s2, "\\%3o", c);
+ s2 += 4;
+ }
+ }
+ }
+
+ strcpy(s2, "\"");
+ ctx->heap_front = s2 + 1;
+ return r;
+}
+
uw_Basis_string uw_Basis_intToString(uw_context ctx, uw_Basis_int n) {
int len;
char *r;
diff --git a/src/cjrize.sml b/src/cjrize.sml
index 6c34923b..1152b0ef 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -420,6 +420,8 @@ fun cifyExp (eAll as (e, loc), sm) =
((L'.EUnurlify (e, t), loc), sm)
end
+ | L.EJavaScript _ => raise Fail "EJavaScript remains"
+
fun cifyDecl ((d, loc), sm) =
case d of
L.DDatatype (x, n, xncs) =>
diff --git a/src/mono.sml b/src/mono.sml
index f465d2bd..187b1853 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -96,6 +96,8 @@ datatype exp' =
| EUnurlify of exp * typ
+ | EJavaScript of exp
+
withtype exp = exp' located
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index 6c0e6e21..7f83c003 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -360,6 +360,11 @@ fun exp e =
| EWrite (EPrim (Prim.String ""), loc) =>
ERecord []
+ | EJavaScript (EAbs (_, (TRecord [], _), _, (EFfiApp ("Basis", "alert", [s]), _)), loc) =>
+ EStrcat ((EPrim (Prim.String "alert("), loc),
+ (EStrcat ((EFfiApp ("Basis", "jsifyString", [s]), loc),
+ (EPrim (Prim.String ")"), loc)), loc))
+
| _ => e
and optExp e = #1 (U.Exp.map {typ = typ, exp = exp} e)
diff --git a/src/mono_print.sml b/src/mono_print.sml
index 8d91d048..7b675438 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -275,6 +275,9 @@ fun p_exp' par env (e, _) =
| EUnurlify (e, _) => box [string "unurlify(",
p_exp env e,
string ")"]
+ | EJavaScript e => box [string "JavaScript(",
+ p_exp env e,
+ string ")"]
and p_exp env = p_exp' false env
diff --git a/src/mono_reduce.sml b/src/mono_reduce.sml
index 9cf6d8e8..040414f3 100644
--- a/src/mono_reduce.sml
+++ b/src/mono_reduce.sml
@@ -75,6 +75,7 @@ fun impure (e, _) =
| ELet (_, _, e1, e2) => impure e1 orelse impure e2
| EClosure (_, es) => List.exists impure es
+ | EJavaScript e => impure e
val liftExpInExp = Monoize.liftExpInExp
@@ -329,6 +330,7 @@ fun reduce file =
| EDml e => summarize d e @ [WriteDb]
| ENextval e => summarize d e @ [WriteDb]
| EUnurlify (e, _) => summarize d e
+ | EJavaScript e => summarize d e
fun exp env e =
diff --git a/src/mono_util.sml b/src/mono_util.sml
index 2b2476e7..18b5c948 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -311,6 +311,10 @@ fun mapfoldB {typ = fc, exp = fe, bind} =
S.map2 (mft t,
fn t' =>
(EUnurlify (e', t'), loc)))
+ | EJavaScript e =>
+ S.map2 (mfe ctx e,
+ fn e' =>
+ (EJavaScript e', loc))
in
mfe
end
diff --git a/src/monoize.sml b/src/monoize.sml
index e23d4f80..e92a1c8a 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -1744,6 +1744,19 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
result = (L'.TFfi ("Basis", "string"), loc)}), loc),
fm)
end
+ | (L'.TFun _, _) =>
+ let
+ val s' = " " ^ lowercaseFirst x ^ "='"
+ in
+ ((L'.EStrcat (s,
+ (L'.EStrcat (
+ (L'.EPrim (Prim.String s'), loc),
+ (L'.EStrcat (
+ (L'.EJavaScript e, loc),
+ (L'.EPrim (Prim.String "'"), loc)), loc)),
+ loc)), loc),
+ fm)
+ end
| _ =>
let
val fooify =
diff --git a/tests/alert.ur b/tests/alert.ur
new file mode 100644
index 00000000..7b2eaacf
--- /dev/null
+++ b/tests/alert.ur
@@ -0,0 +1,3 @@
+fun main () : transaction page = return
+ Click Me!
+
diff --git a/tests/alert.urp b/tests/alert.urp
new file mode 100644
index 00000000..3976e9b0
--- /dev/null
+++ b/tests/alert.urp
@@ -0,0 +1,3 @@
+debug
+
+alert
--
cgit v1.2.3
From 80be553bea33f3d9cb19f399f64eed36017048a3 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sat, 20 Dec 2008 15:46:48 -0500
Subject: Initial support
---
lib/basis.urs | 5 +++-
src/cjrize.sml | 4 +++-
src/jscomp.sml | 66 +++++++++++++++++++++++++++++++++++++++--------------
src/mono.sml | 9 +++++++-
src/mono_print.sml | 13 ++++++++---
src/mono_reduce.sml | 7 ++++--
src/mono_util.sml | 16 +++++++++++--
src/monoize.sml | 33 ++++++++++++++++++++++++++-
tests/sreturn.ur | 5 ++++
tests/sreturn.urp | 3 +++
10 files changed, 133 insertions(+), 28 deletions(-)
create mode 100644 tests/sreturn.ur
create mode 100644 tests/sreturn.urp
(limited to 'src/mono.sml')
diff --git a/lib/basis.urs b/lib/basis.urs
index ac4c4832..a61bf3ce 100644
--- a/lib/basis.urs
+++ b/lib/basis.urs
@@ -376,6 +376,9 @@ con form = [Body, Form]
con tabl = [Body, Table]
con tr = [Body, Tr]
+val dyn : ctx ::: {Unit} -> use ::: {Type} -> bind ::: {Type} -> unit
+ -> tag [Signal = signal (xml ctx use bind)] ctx [] use bind
+
val head : unit -> tag [] html head [] []
val title : unit -> tag [] head [] [] []
@@ -433,7 +436,7 @@ con select = [Select]
val select : formTag string select []
val option : unit -> tag [Value = string, Selected = bool] select [] [] []
-val submit : ctx ::: {Unit} -> use ::: {Type}
+val submit : ctx ::: {Unit} -> use ::: {Type}
-> fn [[Form] ~ ctx] =>
unit
-> tag [Value = string, Action = $use -> transaction page]
diff --git a/src/cjrize.sml b/src/cjrize.sml
index 1152b0ef..f3c5e5a7 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -120,6 +120,7 @@ fun cifyTyp x =
in
((L'.TOption t, loc), sm)
end
+ | L.TSignal _ => raise Fail "Cjrize: TSignal remains"
in
cify IM.empty x
end
@@ -420,7 +421,8 @@ fun cifyExp (eAll as (e, loc), sm) =
((L'.EUnurlify (e, t), loc), sm)
end
- | L.EJavaScript _ => raise Fail "EJavaScript remains"
+ | L.EJavaScript _ => raise Fail "Cjrize: EJavaScript remains"
+ | L.ESignalReturn _ => raise Fail "Cjrize: ESignalReturn remains"
fun cifyDecl ((d, loc), sm) =
case d of
diff --git a/src/jscomp.sml b/src/jscomp.sml
index 0dd7882a..b0842c6b 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -69,8 +69,15 @@ fun varDepth (e, _) =
| ENextval _ => 0
| EUnurlify _ => 0
| EJavaScript _ => 0
+ | ESignalReturn e => varDepth e
-fun jsExp inAttr outer =
+fun strcat loc es =
+ case es of
+ [] => (EPrim (Prim.String ""), loc)
+ | [x] => x
+ | x :: es' => (EStrcat (x, strcat loc es'), loc)
+
+fun jsExp mode outer =
let
val len = length outer
@@ -85,11 +92,7 @@ fun jsExp inAttr outer =
PConVar n => str (Int.toString n)
| PConFfi {con, ...} => str ("\"_" ^ con ^ "\"")
- fun strcat es =
- case es of
- [] => (EPrim (Prim.String ""), loc)
- | [x] => x
- | x :: es' => (EStrcat (x, strcat es'), loc)
+
fun isNullable (t, _) =
case t of
@@ -99,17 +102,19 @@ fun jsExp inAttr outer =
fun unsupported s =
(EM.errorAt loc (s ^ " in code to be compiled to JavaScript");
(str "ERROR", st))
+
+ val strcat = strcat loc
in
case #1 e of
EPrim (Prim.String s) =>
(str ("\""
^ String.translate (fn #"'" =>
- if inAttr then
+ if mode = Attribute then
"\\047"
else
"'"
| #"<" =>
- if inAttr then
+ if mode = Script then
"<"
else
"\\074"
@@ -274,7 +279,14 @@ fun jsExp inAttr outer =
st)
end
- | EWrite _ => unsupported "EWrite"
+ | EWrite e =>
+ let
+ val (e, st) = jsE inner (e, st)
+ in
+ (strcat [str "document.write(",
+ e,
+ str ")"], st)
+ end
| ESeq (e1, e2) =>
let
@@ -301,6 +313,15 @@ fun jsExp inAttr outer =
| ENextval _ => unsupported "Nextval"
| EUnurlify _ => unsupported "EUnurlify"
| EJavaScript _ => unsupported "Nested JavaScript"
+ | ESignalReturn e =>
+ let
+ val (e, st) = jsE inner (e, st)
+ in
+ (strcat [(*str "sreturn(",*)
+ e(*,
+ str ")"*)],
+ st)
+ end
end
in
jsE
@@ -309,14 +330,25 @@ fun jsExp inAttr outer =
val decl : state -> decl -> decl * state =
U.Decl.foldMapB {typ = fn x => x,
exp = fn (env, e, st) =>
- case e of
- EJavaScript (EAbs (_, t, _, e), _) =>
- let
- val (e, st) = jsExp true (t :: env) 0 (e, st)
- in
- (#1 e, st)
- end
- | _ => (e, st),
+ let
+ fun doCode m env e =
+ let
+ val len = length env
+ fun str s = (EPrim (Prim.String s), #2 e)
+
+ val locals = List.tabulate
+ (varDepth e,
+ fn i => str ("var uwr" ^ Int.toString (len + i) ^ ";"))
+ val (e, st) = jsExp m env 0 (e, st)
+ in
+ (#1 (strcat (#2 e) (locals @ [e])), st)
+ end
+ in
+ case e of
+ EJavaScript (m, (EAbs (_, t, _, e), _)) => doCode m (t :: env) e
+ | EJavaScript (m, e) => doCode m env e
+ | _ => (e, st)
+ end,
decl = fn (_, e, st) => (e, st),
bind = fn (env, U.Decl.RelE (_, t)) => t :: env
| (env, _) => env}
diff --git a/src/mono.sml b/src/mono.sml
index 187b1853..c6e0ae8a 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -37,6 +37,7 @@ datatype typ' =
| TDatatype of int * (datatype_kind * (string * int * typ option) list) ref
| TFfi of string * string
| TOption of typ
+ | TSignal of typ
withtype typ = typ' located
@@ -55,6 +56,11 @@ datatype pat' =
withtype pat = pat' located
+datatype javascript_mode =
+ Attribute
+ | Script
+ | File
+
datatype exp' =
EPrim of Prim.t
| ERel of int
@@ -96,8 +102,9 @@ datatype exp' =
| EUnurlify of exp * typ
- | EJavaScript of exp
+ | EJavaScript of javascript_mode * exp
+ | ESignalReturn of exp
withtype exp = exp' located
diff --git a/src/mono_print.sml b/src/mono_print.sml
index 7b675438..89b6c35b 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -65,6 +65,9 @@ fun p_typ' par env (t, _) =
| TOption t => box [string "option(",
p_typ env t,
string ")"]
+ | TSignal t => box [string "signal(",
+ p_typ env t,
+ string ")"]
and p_typ env = p_typ' false env
@@ -275,9 +278,13 @@ fun p_exp' par env (e, _) =
| EUnurlify (e, _) => box [string "unurlify(",
p_exp env e,
string ")"]
- | EJavaScript e => box [string "JavaScript(",
- p_exp env e,
- string ")"]
+ | EJavaScript (_, e) => box [string "JavaScript(",
+ p_exp env e,
+ string ")"]
+
+ | ESignalReturn e => box [string "Return(",
+ p_exp env e,
+ string ")"]
and p_exp env = p_exp' false env
diff --git a/src/mono_reduce.sml b/src/mono_reduce.sml
index 040414f3..e1da02c9 100644
--- a/src/mono_reduce.sml
+++ b/src/mono_reduce.sml
@@ -75,7 +75,8 @@ fun impure (e, _) =
| ELet (_, _, e1, e2) => impure e1 orelse impure e2
| EClosure (_, es) => List.exists impure es
- | EJavaScript e => impure e
+ | EJavaScript (_, e) => impure e
+ | ESignalReturn e => impure e
val liftExpInExp = Monoize.liftExpInExp
@@ -330,7 +331,8 @@ fun reduce file =
| EDml e => summarize d e @ [WriteDb]
| ENextval e => summarize d e @ [WriteDb]
| EUnurlify (e, _) => summarize d e
- | EJavaScript e => summarize d e
+ | EJavaScript (_, e) => summarize d e
+ | ESignalReturn e => summarize d e
fun exp env e =
@@ -421,6 +423,7 @@ fun reduce file =
fun trySub () =
case t of
(TFfi ("Basis", "string"), _) => doSub ()
+ | (TSignal _, _) => e
| _ =>
case e' of
(ECase _, _) => e
diff --git a/src/mono_util.sml b/src/mono_util.sml
index ebc30984..553f802e 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -51,6 +51,7 @@ fun compare ((t1, _), (t2, _)) =
| (TDatatype (n1, _), TDatatype (n2, _)) => Int.compare (n1, n2)
| (TFfi (m1, x1), TFfi (m2, x2)) => join (String.compare (m1, m2), fn () => String.compare (x1, x2))
| (TOption t1, TOption t2) => compare (t1, t2)
+ | (TSignal t1, TSignal t2) => compare (t1, t2)
| (TFun _, _) => LESS
| (_, TFun _) => GREATER
@@ -64,6 +65,9 @@ fun compare ((t1, _), (t2, _)) =
| (TFfi _, _) => LESS
| (_, TFfi _) => GREATER
+ | (TOption _, _) => LESS
+ | (_, TOption _) => GREATER
+
and compareFields ((x1, t1), (x2, t2)) =
join (String.compare (x1, x2),
fn () => compare (t1, t2))
@@ -96,6 +100,10 @@ fun mapfold fc =
S.map2 (mft t,
fn t' =>
(TOption t, loc))
+ | TSignal t =>
+ S.map2 (mft t,
+ fn t' =>
+ (TSignal t, loc))
in
mft
end
@@ -311,10 +319,14 @@ fun mapfoldB {typ = fc, exp = fe, bind} =
S.map2 (mft t,
fn t' =>
(EUnurlify (e', t'), loc)))
- | EJavaScript e =>
+ | EJavaScript (m, e) =>
+ S.map2 (mfe ctx e,
+ fn e' =>
+ (EJavaScript (m, e'), loc))
+ | ESignalReturn e =>
S.map2 (mfe ctx e,
fn e' =>
- (EJavaScript e', loc))
+ (ESignalReturn e', loc))
in
mfe
end
diff --git a/src/monoize.sml b/src/monoize.sml
index e92a1c8a..1b7b467d 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -135,6 +135,8 @@ fun monoType env =
(L'.TFun ((L'.TRecord [], loc), mt env dtmap t), loc)
| L.CApp ((L.CFfi ("Basis", "source"), _), t) =>
(L'.TFfi ("Basis", "int"), loc)
+ | L.CApp ((L.CFfi ("Basis", "signal"), _), t) =>
+ (L'.TSignal (mt env dtmap t), loc)
| L.CApp ((L.CFfi ("Basis", "http_cookie"), _), _) =>
(L'.TFfi ("Basis", "string"), loc)
| L.CApp ((L.CFfi ("Basis", "sql_table"), _), _) =>
@@ -978,6 +980,16 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
fm)
end
+ | L.EApp ((L.ECApp ((L.ECApp ((L.EFfi ("Basis", "return"), _), _), _), t), _),
+ (L.EFfi ("Basis", "signal_monad"), _)) =>
+ let
+ val t = monoType env t
+ in
+ ((L'.EAbs ("x", t, (L'.TSignal t, loc),
+ (L'.ESignalReturn (L'.ERel 0, loc), loc)), loc),
+ fm)
+ end
+
| L.ECApp ((L.EFfi ("Basis", "getCookie"), _), t) =>
let
val s = (L'.TFfi ("Basis", "string"), loc)
@@ -1752,7 +1764,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L'.EStrcat (
(L'.EPrim (Prim.String s'), loc),
(L'.EStrcat (
- (L'.EJavaScript e, loc),
+ (L'.EJavaScript (L'.Attribute, e), loc),
(L'.EPrim (Prim.String "'"), loc)), loc)),
loc)), loc),
fm)
@@ -1833,6 +1845,25 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
case tag of
"body" => normal ("body", NONE,
SOME (L'.EFfiApp ("Basis", "get_script", [(L'.ERecord [], loc)]), loc))
+
+ | "dyn" =>
+ (case #1 attrs of
+ (*L'.ERecord [("Signal", (L'.ESignalReturn e, _), _)] => (e, fm)
+ | L'.ERecord [("Signal", (L'.EApp ((L'.EAbs (_, _, _, (L'.ESignalReturn (L'.ERel 0, _), _)), _),
+ e), _), _)] => (e, fm) *)
+
+ L'.ERecord [("Signal", e, _)] =>
+ ((L'.EStrcat
+ ((L'.EPrim (Prim.String ""), loc)), loc)), loc),
+ fm)
+ | _ => raise Fail "Monoize: Bad dyn attributes")
| "submit" => normal ("input type=\"submit\"", NONE, NONE)
diff --git a/tests/sreturn.ur b/tests/sreturn.ur
new file mode 100644
index 00000000..62db377d
--- /dev/null
+++ b/tests/sreturn.ur
@@ -0,0 +1,5 @@
+fun main () : transaction page = return
+ Before
+ Hi!
}/>
+ After
+
diff --git a/tests/sreturn.urp b/tests/sreturn.urp
new file mode 100644
index 00000000..5591aa5e
--- /dev/null
+++ b/tests/sreturn.urp
@@ -0,0 +1,3 @@
+debug
+
+sreturn
--
cgit v1.2.3
From ec745f90fc97e10948dc32ec4f44aabf5c6908db Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sat, 20 Dec 2008 16:19:26 -0500
Subject: Successfully generated a page element from a signal
---
Makefile.in | 3 +++
jslib/urweb.js | 1 +
src/c/driver.c | 5 -----
src/cjr.sml | 2 ++
src/cjr_env.sml | 1 +
src/cjr_print.sml | 20 ++++++++++++++++++++
src/cjrize.sml | 1 +
src/config.sig | 1 +
src/config.sml.in | 2 ++
src/jscomp.sml | 18 +++++++++++++-----
src/mono.sml | 3 +++
src/mono_env.sml | 1 +
src/mono_print.sml | 4 ++++
src/mono_shake.sml | 6 ++++--
src/mono_util.sml | 6 +++++-
src/monoize.sml | 4 +++-
src/prepare.sml | 1 +
17 files changed, 65 insertions(+), 14 deletions(-)
create mode 100644 jslib/urweb.js
(limited to 'src/mono.sml')
diff --git a/Makefile.in b/Makefile.in
index 57a083bd..ed65ceea 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -5,6 +5,7 @@ SITELISP := @SITELISP@
LIB_UR := $(LIB)/ur
LIB_C := $(LIB)/c
+LIB_JS := $(LIB)/js
all: smlnj mlton c
@@ -70,6 +71,8 @@ install:
cp lib/*.ur $(LIB_UR)/
mkdir -p $(LIB_C)
cp clib/*.o $(LIB_C)/
+ mkdir -p $(LIB_JS)
+ cp jslib/*.js $(LIB_JS)/
mkdir -p $(INCLUDE)
cp include/*.h $(INCLUDE)/
mkdir -p $(SITELISP)
diff --git a/jslib/urweb.js b/jslib/urweb.js
new file mode 100644
index 00000000..32912e4c
--- /dev/null
+++ b/jslib/urweb.js
@@ -0,0 +1 @@
+function sreturn(v) { return {v : v} }
diff --git a/src/c/driver.c b/src/c/driver.c
index a25cd743..34e57a6d 100644
--- a/src/c/driver.c
+++ b/src/c/driver.c
@@ -193,8 +193,6 @@ static void *worker(void *data) {
uw_set_headers(ctx, headers);
while (1) {
- uw_write(ctx, "");
-
if (uw_db_begin(ctx)) {
printf("Error running SQL BEGIN\n");
if (retries_left)
@@ -211,13 +209,10 @@ static void *worker(void *data) {
}
uw_write_header(ctx, "HTTP/1.1 200 OK\r\n");
- uw_write_header(ctx, "Content-type: text/html\r\n");
strcpy(path_copy, path);
fk = uw_begin(ctx, path_copy);
if (fk == SUCCESS) {
- uw_write(ctx, "");
-
if (uw_db_commit(ctx)) {
fk = FATAL;
diff --git a/src/cjr.sml b/src/cjr.sml
index 84aea54e..43a29a6c 100644
--- a/src/cjr.sml
+++ b/src/cjr.sml
@@ -109,6 +109,8 @@ datatype decl' =
| DDatabase of string
| DPreparedStatements of (string * int) list
+ | DJavaScript of string
+
withtype decl = decl' located
type file = decl list * (Core.export_kind * string * int * typ list) list
diff --git a/src/cjr_env.sml b/src/cjr_env.sml
index 49e86140..9921ee48 100644
--- a/src/cjr_env.sml
+++ b/src/cjr_env.sml
@@ -166,6 +166,7 @@ fun declBinds env (d, loc) =
| DSequence _ => env
| DDatabase _ => env
| DPreparedStatements _ => env
+ | DJavaScript _ => env
end
diff --git a/src/cjr_print.sml b/src/cjr_print.sml
index 8c3c3d86..06f9f5ca 100644
--- a/src/cjr_print.sml
+++ b/src/cjr_print.sml
@@ -1800,6 +1800,10 @@ fun p_decl env (dAll as (d, _) : decl) =
string "}"]
+ | DJavaScript s => box [string "static char jslib[] = \"",
+ string (String.toString s),
+ string "\";"]
+
datatype 'a search =
Found of 'a
| NotFound
@@ -2048,6 +2052,10 @@ fun p_file env (ds, ps) =
newline,
string "if (*request == '/') ++request;",
newline,
+ string "uw_write_header(ctx, \"Content-type: text/html\\r\\n\");",
+ newline,
+ string "uw_write(ctx, \"\");",
+ newline,
box [string "{",
newline,
box (ListUtil.mapi (fn (i, t) => box [p_typ env t,
@@ -2070,6 +2078,8 @@ fun p_file env (ds, ps) =
inputsVar,
string ", uw_unit_v);",
newline,
+ string "uw_write(ctx, \"\");",
+ newline,
string "return;",
newline,
string "}",
@@ -2374,6 +2384,16 @@ fun p_file env (ds, ps) =
newline,
string "void uw_handle(uw_context ctx, char *request) {",
newline,
+ string "if (!strcmp(request, \"/app.js\")) {",
+ newline,
+ box [string "uw_write_header(ctx, \"Content-type: text/javascript\\r\\n\");",
+ newline,
+ string "uw_write(ctx, jslib);",
+ newline,
+ string "return;",
+ newline],
+ string "}",
+ newline,
p_list_sep newline (fn x => x) pds',
newline,
string "uw_error(ctx, FATAL, \"Unknown page\");",
diff --git a/src/cjrize.sml b/src/cjrize.sml
index f3c5e5a7..78513ef7 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -528,6 +528,7 @@ fun cifyDecl ((d, loc), sm) =
| L.DSequence s =>
(SOME (L'.DSequence s, loc), NONE, sm)
| L.DDatabase s => (SOME (L'.DDatabase s, loc), NONE, sm)
+ | L.DJavaScript s => (SOME (L'.DJavaScript s, loc), NONE, sm)
fun cjrize ds =
let
diff --git a/src/config.sig b/src/config.sig
index 6075482e..90fb72e7 100644
--- a/src/config.sig
+++ b/src/config.sig
@@ -6,6 +6,7 @@ signature CONFIG = sig
val libUr : string
val libC : string
+ val libJs : string
val gccArgs : string
end
diff --git a/src/config.sml.in b/src/config.sml.in
index 9e53986b..c7d231d5 100644
--- a/src/config.sml.in
+++ b/src/config.sml.in
@@ -9,6 +9,8 @@ val libUr = OS.Path.joinDirFile {dir = lib,
file = "ur"}
val libC = OS.Path.joinDirFile {dir = lib,
file = "c"}
+val libJs = OS.Path.joinDirFile {dir = lib,
+ file = "js"}
val gccArgs = "@GCCARGS@"
diff --git a/src/jscomp.sml b/src/jscomp.sml
index b0842c6b..95c18016 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -285,7 +285,7 @@ fun jsExp mode outer =
in
(strcat [str "document.write(",
e,
- str ")"], st)
+ str ".v)"], st)
end
| ESeq (e1, e2) =>
@@ -317,9 +317,9 @@ fun jsExp mode outer =
let
val (e, st) = jsE inner (e, st)
in
- (strcat [(*str "sreturn(",*)
- e(*,
- str ")"*)],
+ (strcat [str "sreturn(",
+ e,
+ str ")"],
st)
end
end
@@ -369,8 +369,16 @@ fun process file =
{decls = [],
script = ""}
file
+
+ val inf = TextIO.openIn (OS.Path.joinDirFile {dir = Config.libJs, file = "urweb.js"})
+ fun lines acc =
+ case TextIO.inputLine inf of
+ NONE => String.concat (rev acc)
+ | SOME line => lines (line :: acc)
+ val lines = lines []
in
- ds
+ TextIO.closeIn inf;
+ (DJavaScript lines, ErrorMsg.dummySpan) :: ds
end
end
diff --git a/src/mono.sml b/src/mono.sml
index c6e0ae8a..1a7fde00 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -118,6 +118,9 @@ datatype decl' =
| DSequence of string
| DDatabase of string
+ | DJavaScript of string
+
+
withtype decl = decl' located
type file = decl list
diff --git a/src/mono_env.sml b/src/mono_env.sml
index cce4a4c4..248567de 100644
--- a/src/mono_env.sml
+++ b/src/mono_env.sml
@@ -110,6 +110,7 @@ fun declBinds env (d, loc) =
| DTable _ => env
| DSequence _ => env
| DDatabase _ => env
+ | DJavaScript _ => env
fun patBinds env (p, loc) =
case p of
diff --git a/src/mono_print.sml b/src/mono_print.sml
index 89b6c35b..e44bb74c 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -379,6 +379,10 @@ fun p_decl env (dAll as (d, _) : decl) =
| DDatabase s => box [string "database",
space,
string s]
+ | DJavaScript s => box [string "JavaScript(",
+ string s,
+ string ")"]
+
fun p_file env file =
let
diff --git a/src/mono_shake.sml b/src/mono_shake.sml
index 6714718a..34bd98be 100644
--- a/src/mono_shake.sml
+++ b/src/mono_shake.sml
@@ -56,7 +56,8 @@ fun shake file =
| ((DExport _, _), acc) => acc
| ((DTable _, _), acc) => acc
| ((DSequence _, _), acc) => acc
- | ((DDatabase _, _), acc) => acc)
+ | ((DDatabase _, _), acc) => acc
+ | ((DJavaScript _, _), acc) => acc)
(IM.empty, IM.empty) file
fun typ (c, s) =
@@ -112,7 +113,8 @@ fun shake file =
| (DExport _, _) => true
| (DTable _, _) => true
| (DSequence _, _) => true
- | (DDatabase _, _) => true) file
+ | (DDatabase _, _) => true
+ | (DJavaScript _, _) => true) file
end
end
diff --git a/src/mono_util.sml b/src/mono_util.sml
index 553f802e..9788a551 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -323,6 +323,7 @@ fun mapfoldB {typ = fc, exp = fe, bind} =
S.map2 (mfe ctx e,
fn e' =>
(EJavaScript (m, e'), loc))
+
| ESignalReturn e =>
S.map2 (mfe ctx e,
fn e' =>
@@ -421,6 +422,7 @@ fun mapfoldB {typ = fc, exp = fe, decl = fd, bind} =
| DTable _ => S.return2 dAll
| DSequence _ => S.return2 dAll
| DDatabase _ => S.return2 dAll
+ | DJavaScript _ => S.return2 dAll
and mfvi ctx (x, n, t, e, s) =
S.bind2 (mft t,
@@ -501,6 +503,7 @@ fun mapfoldB (all as {bind, ...}) =
| DTable _ => ctx
| DSequence _ => ctx
| DDatabase _ => ctx
+ | DJavaScript _ => ctx
in
S.map2 (mff ctx' ds',
fn ds' =>
@@ -548,7 +551,8 @@ val maxName = foldl (fn ((d, _) : decl, count) =>
| DExport _ => count
| DTable _ => count
| DSequence _ => count
- | DDatabase _ => count) 0
+ | DDatabase _ => count
+ | DJavaScript _ => count) 0
end
diff --git a/src/monoize.sml b/src/monoize.sml
index 1b7b467d..a0a0df30 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -1844,7 +1844,9 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
in
case tag of
"body" => normal ("body", NONE,
- SOME (L'.EFfiApp ("Basis", "get_script", [(L'.ERecord [], loc)]), loc))
+ SOME (L'.EStrcat ((L'.EPrim (Prim.String ""), loc),
+ (L'.EFfiApp ("Basis", "get_script", [(L'.ERecord [], loc)]),
+ loc)), loc))
| "dyn" =>
(case #1 attrs of
diff --git a/src/prepare.sml b/src/prepare.sml
index 708bcade..110f6f9a 100644
--- a/src/prepare.sml
+++ b/src/prepare.sml
@@ -258,6 +258,7 @@ fun prepDecl (d as (_, loc), sns) =
| DSequence _ => (d, sns)
| DDatabase _ => (d, sns)
| DPreparedStatements _ => (d, sns)
+ | DJavaScript _ => (d, sns)
fun prepare (ds, ps) =
let
--
cgit v1.2.3
From d5c3faacb1c3114fe6802973a62528cda8be8ac7 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sun, 21 Dec 2008 12:30:57 -0500
Subject: Handling singnal bind
---
jslib/urweb.js | 3 +-
src/cjrize.sml | 1 +
src/compiler.sig | 3 +-
src/compiler.sml | 8 +++--
src/jscomp.sml | 90 +++++++++++++++++++++++++++++++++++++++--------------
src/mono.sml | 1 +
src/mono_opt.sml | 3 ++
src/mono_print.sml | 6 ++++
src/mono_reduce.sml | 5 +++
src/mono_util.sml | 6 ++++
src/monoize.sml | 18 +++++++++--
tests/sbind.ur | 5 +++
tests/sbind.urp | 3 ++
13 files changed, 122 insertions(+), 30 deletions(-)
create mode 100644 tests/sbind.ur
create mode 100644 tests/sbind.urp
(limited to 'src/mono.sml')
diff --git a/jslib/urweb.js b/jslib/urweb.js
index b7a1af91..f552b26b 100644
--- a/jslib/urweb.js
+++ b/jslib/urweb.js
@@ -1,4 +1,5 @@
-function sreturn(v) { return {v : v} }
+function sr(v) { return {v : v} }
+function sb(x,y) { return {v : y(x.v).v} }
function dyn(s) {
var x = document.createElement("span");
diff --git a/src/cjrize.sml b/src/cjrize.sml
index 78513ef7..a46c725e 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -423,6 +423,7 @@ fun cifyExp (eAll as (e, loc), sm) =
| L.EJavaScript _ => raise Fail "Cjrize: EJavaScript remains"
| L.ESignalReturn _ => raise Fail "Cjrize: ESignalReturn remains"
+ | L.ESignalBind _ => raise Fail "Cjrize: ESignalBind remains"
fun cifyDecl ((d, loc), sm) =
case d of
diff --git a/src/compiler.sig b/src/compiler.sig
index 1f1f4973..c156b268 100644
--- a/src/compiler.sig
+++ b/src/compiler.sig
@@ -102,8 +102,9 @@ signature COMPILER = sig
val toUntangle : (string, Mono.file) transform
val toMono_reduce : (string, Mono.file) transform
val toMono_shake : (string, Mono.file) transform
- val toJscomp : (string, Mono.file) transform
val toMono_opt2 : (string, Mono.file) transform
+ val toJscomp : (string, Mono.file) transform
+ val toMono_opt3 : (string, Mono.file) transform
val toFuse : (string, Mono.file) transform
val toUntangle2 : (string, Mono.file) transform
val toMono_shake2 : (string, Mono.file) transform
diff --git a/src/compiler.sml b/src/compiler.sml
index ecee1065..6d499283 100644
--- a/src/compiler.sml
+++ b/src/compiler.sml
@@ -511,21 +511,23 @@ val mono_shake = {
val toMono_shake = transform mono_shake "mono_shake1" o toMono_reduce
+val toMono_opt2 = transform mono_opt "mono_opt2" o toMono_shake
+
val jscomp = {
func = JsComp.process,
print = MonoPrint.p_file MonoEnv.empty
}
-val toJscomp = transform jscomp "jscomp" o toMono_reduce
+val toJscomp = transform jscomp "jscomp" o toMono_opt2
-val toMono_opt2 = transform mono_opt "mono_opt2" o toJscomp
+val toMono_opt3 = transform mono_opt "mono_opt3" o toJscomp
val fuse = {
func = Fuse.fuse,
print = MonoPrint.p_file MonoEnv.empty
}
-val toFuse = transform fuse "fuse" o toMono_opt2
+val toFuse = transform fuse "fuse" o toMono_opt3
val toUntangle2 = transform untangle "untangle2" o toFuse
diff --git a/src/jscomp.sml b/src/jscomp.sml
index 95c18016..c38056e8 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -33,6 +33,20 @@ structure EM = ErrorMsg
structure E = MonoEnv
structure U = MonoUtil
+val funcs = [(("Basis", "alert"), "alert"),
+ (("Basis", "htmlifyString"), "escape")]
+
+structure FM = BinaryMapFn(struct
+ type ord_key = string * string
+ fun compare ((m1, x1), (m2, x2)) =
+ Order.join (String.compare (m1, m2),
+ fn () => String.compare (x1, x2))
+ end)
+
+val funcs = foldl (fn ((k, v), m) => FM.insert (m, k, v)) FM.empty funcs
+
+fun ffi k = FM.find (funcs, k)
+
type state = {
decls : decl list,
script : string
@@ -70,6 +84,7 @@ fun varDepth (e, _) =
| EUnurlify _ => 0
| EJavaScript _ => 0
| ESignalReturn e => varDepth e
+ | ESignalBind (e1, e2) => Int.max (varDepth e1, varDepth e2)
fun strcat loc es =
case es of
@@ -150,33 +165,50 @@ fun jsExp mode outer =
e, st)
end
- | EFfi (_, s) => (str s, st)
- | EFfiApp (_, s, []) => (str (s ^ "()"), st)
- | EFfiApp (_, s, [e]) =>
+ | EFfi k =>
let
- val (e, st) = jsE inner (e, st)
-
+ val name = case ffi k of
+ NONE => (EM.errorAt loc "Unsupported FFI identifier in JavaScript";
+ "ERROR")
+ | SOME s => s
in
- (strcat [str (s ^ "("),
- e,
- str ")"], st)
+ (str name, st)
end
- | EFfiApp (_, s, e :: es) =>
+ | EFfiApp (m, x, args) =>
let
- val (e, st) = jsE inner (e, st)
- val (es, st) = ListUtil.foldlMapConcat
- (fn (e, st) =>
- let
- val (e, st) = jsE inner (e, st)
- in
- ([str ",", e], st)
- end)
- st es
+ val name = case ffi (m, x) of
+ NONE => (EM.errorAt loc "Unsupported FFI function in JavaScript";
+ "ERROR")
+ | SOME s => s
in
- (strcat (str (s ^ "(")
- :: e
- :: es
- @ [str ")"]), st)
+ case args of
+ [] => (str (name ^ "()"), st)
+ | [e] =>
+ let
+ val (e, st) = jsE inner (e, st)
+
+ in
+ (strcat [str (name ^ "("),
+ e,
+ str ")"], st)
+ end
+ | e :: es =>
+ let
+ val (e, st) = jsE inner (e, st)
+ val (es, st) = ListUtil.foldlMapConcat
+ (fn (e, st) =>
+ let
+ val (e, st) = jsE inner (e, st)
+ in
+ ([str ",", e], st)
+ end)
+ st es
+ in
+ (strcat (str (name ^ "(")
+ :: e
+ :: es
+ @ [str ")"]), st)
+ end
end
| EApp (e1, e2) =>
@@ -317,11 +349,23 @@ fun jsExp mode outer =
let
val (e, st) = jsE inner (e, st)
in
- (strcat [str "sreturn(",
+ (strcat [str "sr(",
e,
str ")"],
st)
end
+ | ESignalBind (e1, e2) =>
+ let
+ val (e1, st) = jsE inner (e1, st)
+ val (e2, st) = jsE inner (e2, st)
+ in
+ (strcat [str "sb(",
+ e1,
+ str ",",
+ e2,
+ str ")"],
+ st)
+ end
end
in
jsE
diff --git a/src/mono.sml b/src/mono.sml
index 1a7fde00..54b77550 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -105,6 +105,7 @@ datatype exp' =
| EJavaScript of javascript_mode * exp
| ESignalReturn of exp
+ | ESignalBind of exp * exp
withtype exp = exp' located
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index 6c0e6e21..550a055c 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -360,6 +360,9 @@ fun exp e =
| EWrite (EPrim (Prim.String ""), loc) =>
ERecord []
+ | ESignalBind ((ESignalReturn e1, loc), e2) =>
+ optExp (EApp (e2, e1), loc)
+
| _ => e
and optExp e = #1 (U.Exp.map {typ = typ, exp = exp} e)
diff --git a/src/mono_print.sml b/src/mono_print.sml
index e44bb74c..608fe269 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -285,6 +285,12 @@ fun p_exp' par env (e, _) =
| ESignalReturn e => box [string "Return(",
p_exp env e,
string ")"]
+ | ESignalBind (e1, e2) => box [string "Return(",
+ p_exp env e1,
+ string ",",
+ space,
+ p_exp env e2,
+ string ")"]
and p_exp env = p_exp' false env
diff --git a/src/mono_reduce.sml b/src/mono_reduce.sml
index e1da02c9..841e034e 100644
--- a/src/mono_reduce.sml
+++ b/src/mono_reduce.sml
@@ -77,6 +77,7 @@ fun impure (e, _) =
| EClosure (_, es) => List.exists impure es
| EJavaScript (_, e) => impure e
| ESignalReturn e => impure e
+ | ESignalBind (e1, e2) => impure e1 orelse impure e2
val liftExpInExp = Monoize.liftExpInExp
@@ -333,6 +334,7 @@ fun reduce file =
| EUnurlify (e, _) => summarize d e
| EJavaScript (_, e) => summarize d e
| ESignalReturn e => summarize d e
+ | ESignalBind (e1, e2) => summarize d e1 @ summarize d e2
fun exp env e =
@@ -478,6 +480,9 @@ fun reduce file =
| EStrcat ((EPrim (Prim.String s1), _), (EPrim (Prim.String s2), _)) =>
EPrim (Prim.String (s1 ^ s2))
+ | ESignalBind ((ESignalReturn e1, loc), e2) =>
+ #1 (reduceExp env (EApp (e2, e1), loc))
+
| _ => e
in
(*Print.prefaces "exp'" [("r", MonoPrint.p_exp env (r, ErrorMsg.dummySpan))];*)
diff --git a/src/mono_util.sml b/src/mono_util.sml
index 9788a551..a85443d7 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -328,6 +328,12 @@ fun mapfoldB {typ = fc, exp = fe, bind} =
S.map2 (mfe ctx e,
fn e' =>
(ESignalReturn e', loc))
+ | ESignalBind (e1, e2) =>
+ S.bind2 (mfe ctx e1,
+ fn e1' =>
+ S.map2 (mfe ctx e2,
+ fn e2' =>
+ (ESignalBind (e1', e2'), loc)))
in
mfe
end
diff --git a/src/monoize.sml b/src/monoize.sml
index 63d84d8c..30bd5daa 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -957,8 +957,8 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
val mt1 = (L'.TFun (un, t1), loc)
val mt2 = (L'.TFun (un, t2), loc)
in
- ((L'.EAbs ("m1", mt1, (L'.TFun (mt1, (L'.TFun (mt2, (L'.TFun (un, un), loc)), loc)), loc),
- (L'.EAbs ("m2", mt2, (L'.TFun (un, un), loc),
+ ((L'.EAbs ("m1", mt1, (L'.TFun ((L'.TFun (t1, mt2), loc), (L'.TFun (un, un), loc)), loc),
+ (L'.EAbs ("m2", (L'.TFun (t1, mt2), loc), (L'.TFun (un, un), loc),
(L'.EAbs ("_", un, un,
(L'.ELet ("r", t1, (L'.EApp ((L'.ERel 2, loc),
(L'.ERecord [], loc)), loc),
@@ -989,6 +989,20 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L'.ESignalReturn (L'.ERel 0, loc), loc)), loc),
fm)
end
+ | L.EApp ((L.ECApp ((L.ECApp ((L.ECApp ((L.EFfi ("Basis", "bind"), _), _), _), t1), _), t2), _),
+ (L.EFfi ("Basis", "signal_monad"), _)) =>
+ let
+ val t1 = monoType env t1
+ val t2 = monoType env t2
+ val un = (L'.TRecord [], loc)
+ val mt1 = (L'.TSignal t1, loc)
+ val mt2 = (L'.TSignal t2, loc)
+ in
+ ((L'.EAbs ("m1", mt1, (L'.TFun ((L'.TFun (t1, mt2), loc), mt2), loc),
+ (L'.EAbs ("m2", (L'.TFun (t1, mt2), loc), mt2,
+ (L'.ESignalBind ((L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc),
+ fm)
+ end
| L.ECApp ((L.EFfi ("Basis", "getCookie"), _), t) =>
let
diff --git a/tests/sbind.ur b/tests/sbind.ur
new file mode 100644
index 00000000..6e3ca782
--- /dev/null
+++ b/tests/sbind.ur
@@ -0,0 +1,5 @@
+fun main () : transaction page = return
+ Before
+ {[s]}
}/>
+ After
+
diff --git a/tests/sbind.urp b/tests/sbind.urp
new file mode 100644
index 00000000..d8735c70
--- /dev/null
+++ b/tests/sbind.urp
@@ -0,0 +1,3 @@
+debug
+
+sbind
--
cgit v1.2.3
From f60bcb83cf4d8e0a6176a1dca6e557c49e9f9375 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sun, 21 Dec 2008 12:56:39 -0500
Subject: Trivial use of a source
---
jslib/urweb.js | 3 ++
src/c/urweb.c | 111 ++++++++++++++++++++++++++++++++++------------------
src/cjrize.sml | 1 +
src/jscomp.sml | 17 ++++++--
src/mono.sml | 1 +
src/mono_print.sml | 5 ++-
src/mono_reduce.sml | 3 +-
src/mono_util.sml | 4 ++
src/monoize.sml | 10 ++++-
tests/reactive.ur | 7 ++--
10 files changed, 116 insertions(+), 46 deletions(-)
(limited to 'src/mono.sml')
diff --git a/jslib/urweb.js b/jslib/urweb.js
index f552b26b..eab67626 100644
--- a/jslib/urweb.js
+++ b/jslib/urweb.js
@@ -1,3 +1,6 @@
+function sc(v) { return {v : v} }
+
+function ss(s) { return {v : s.v} }
function sr(v) { return {v : v} }
function sb(x,y) { return {v : y(x.v).v} }
diff --git a/src/c/urweb.c b/src/c/urweb.c
index 64cdb81e..11b99f4c 100644
--- a/src/c/urweb.c
+++ b/src/c/urweb.c
@@ -387,12 +387,84 @@ char *uw_Basis_get_script(uw_context ctx, uw_unit u) {
}
}
-int uw_Basis_new_client_source(uw_context ctx, uw_unit u) {
+uw_Basis_string uw_Basis_jsifyString(uw_context ctx, uw_Basis_string s) {
+ char *r, *s2;
+
+ uw_check_heap(ctx, strlen(s) * 4 + 2);
+
+ r = s2 = ctx->heap_front;
+ *s2++ = '"';
+
+ for (; *s; s++) {
+ char c = *s;
+
+ switch (c) {
+ case '"':
+ strcpy(s2, "\\\"");
+ s2 += 2;
+ break;
+ case '\\':
+ strcpy(s2, "\\\\");
+ s2 += 2;
+ break;
+ default:
+ if (isprint(c))
+ *s2++ = c;
+ else {
+ sprintf(s2, "\\%3o", c);
+ s2 += 4;
+ }
+ }
+ }
+
+ strcpy(s2, "\"");
+ ctx->heap_front = s2 + 1;
+ return r;
+}
+
+uw_Basis_string uw_Basis_jsifyString_ws(uw_context ctx, uw_Basis_string s) {
+ char *r, *s2;
+
+ uw_check_script(ctx, strlen(s) * 4 + 2);
+
+ r = s2 = ctx->script_front;
+ *s2++ = '"';
+
+ for (; *s; s++) {
+ char c = *s;
+
+ switch (c) {
+ case '"':
+ strcpy(s2, "\\\"");
+ s2 += 2;
+ break;
+ case '\\':
+ strcpy(s2, "\\\\");
+ s2 += 2;
+ break;
+ default:
+ if (isprint(c))
+ *s2++ = c;
+ else {
+ sprintf(s2, "\\%3o", c);
+ s2 += 4;
+ }
+ }
+ }
+
+ strcpy(s2, "\"");
+ ctx->script_front = s2 + 1;
+ return r;
+}
+
+int uw_Basis_new_client_source(uw_context ctx, uw_Basis_string s) {
size_t len;
uw_check_script(ctx, 8 + INTS_MAX);
- sprintf(ctx->script_front, "var e%d=0\n%n", ctx->source_count, &len);
+ sprintf(ctx->script_front, "var s%d=sc(%n", ctx->source_count, &len);
ctx->script_front += len;
+ uw_Basis_jsifyString_ws(ctx, s);
+ uw_write_script(ctx, ");");
return ctx->source_count++;
}
@@ -1056,41 +1128,6 @@ char *uw_Basis_ensqlBool(uw_Basis_bool b) {
return (char *)&true;
}
-uw_Basis_string uw_Basis_jsifyString(uw_context ctx, uw_Basis_string s) {
- char *r, *s2;
-
- uw_check_heap(ctx, strlen(s) * 4 + 2);
-
- r = s2 = ctx->heap_front;
- *s2++ = '"';
-
- for (; *s; s++) {
- char c = *s;
-
- switch (c) {
- case '"':
- strcpy(s2, "\\\"");
- s2 += 2;
- break;
- case '\\':
- strcpy(s2, "\\\\");
- s2 += 2;
- break;
- default:
- if (isprint(c))
- *s2++ = c;
- else {
- sprintf(s2, "\\%3o", c);
- s2 += 4;
- }
- }
- }
-
- strcpy(s2, "\"");
- ctx->heap_front = s2 + 1;
- return r;
-}
-
uw_Basis_string uw_Basis_intToString(uw_context ctx, uw_Basis_int n) {
int len;
char *r;
diff --git a/src/cjrize.sml b/src/cjrize.sml
index a46c725e..a9c51826 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -424,6 +424,7 @@ fun cifyExp (eAll as (e, loc), sm) =
| L.EJavaScript _ => raise Fail "Cjrize: EJavaScript remains"
| L.ESignalReturn _ => raise Fail "Cjrize: ESignalReturn remains"
| L.ESignalBind _ => raise Fail "Cjrize: ESignalBind remains"
+ | L.ESignalSource _ => raise Fail "Cjrize: ESignalSource remains"
fun cifyDecl ((d, loc), sm) =
case d of
diff --git a/src/jscomp.sml b/src/jscomp.sml
index c38056e8..f7ef6927 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -34,7 +34,8 @@ structure E = MonoEnv
structure U = MonoUtil
val funcs = [(("Basis", "alert"), "alert"),
- (("Basis", "htmlifyString"), "escape")]
+ (("Basis", "htmlifyString"), "escape"),
+ (("Basis", "new_client_source"), "sc")]
structure FM = BinaryMapFn(struct
type ord_key = string * string
@@ -85,6 +86,7 @@ fun varDepth (e, _) =
| EJavaScript _ => 0
| ESignalReturn e => varDepth e
| ESignalBind (e1, e2) => Int.max (varDepth e1, varDepth e2)
+ | ESignalSource e => varDepth e
fun strcat loc es =
case es of
@@ -168,7 +170,7 @@ fun jsExp mode outer =
| EFfi k =>
let
val name = case ffi k of
- NONE => (EM.errorAt loc "Unsupported FFI identifier in JavaScript";
+ NONE => (EM.errorAt loc ("Unsupported FFI identifier " ^ #2 k ^ " in JavaScript");
"ERROR")
| SOME s => s
in
@@ -177,7 +179,7 @@ fun jsExp mode outer =
| EFfiApp (m, x, args) =>
let
val name = case ffi (m, x) of
- NONE => (EM.errorAt loc "Unsupported FFI function in JavaScript";
+ NONE => (EM.errorAt loc ("Unsupported FFI function " ^ x ^ " in JavaScript");
"ERROR")
| SOME s => s
in
@@ -366,6 +368,15 @@ fun jsExp mode outer =
str ")"],
st)
end
+ | ESignalSource e =>
+ let
+ val (e, st) = jsE inner (e, st)
+ in
+ (strcat [str "ss(",
+ e,
+ str ")"],
+ st)
+ end
end
in
jsE
diff --git a/src/mono.sml b/src/mono.sml
index 54b77550..ae9a06c7 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -106,6 +106,7 @@ datatype exp' =
| ESignalReturn of exp
| ESignalBind of exp * exp
+ | ESignalSource of exp
withtype exp = exp' located
diff --git a/src/mono_print.sml b/src/mono_print.sml
index 608fe269..b3c0a568 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -285,12 +285,15 @@ fun p_exp' par env (e, _) =
| ESignalReturn e => box [string "Return(",
p_exp env e,
string ")"]
- | ESignalBind (e1, e2) => box [string "Return(",
+ | ESignalBind (e1, e2) => box [string "Bind(",
p_exp env e1,
string ",",
space,
p_exp env e2,
string ")"]
+ | ESignalSource e => box [string "Source(",
+ p_exp env e,
+ string ")"]
and p_exp env = p_exp' false env
diff --git a/src/mono_reduce.sml b/src/mono_reduce.sml
index 841e034e..a6777db5 100644
--- a/src/mono_reduce.sml
+++ b/src/mono_reduce.sml
@@ -78,6 +78,7 @@ fun impure (e, _) =
| EJavaScript (_, e) => impure e
| ESignalReturn e => impure e
| ESignalBind (e1, e2) => impure e1 orelse impure e2
+ | ESignalSource e => impure e
val liftExpInExp = Monoize.liftExpInExp
@@ -335,7 +336,7 @@ fun reduce file =
| EJavaScript (_, e) => summarize d e
| ESignalReturn e => summarize d e
| ESignalBind (e1, e2) => summarize d e1 @ summarize d e2
-
+ | ESignalSource e => summarize d e
fun exp env e =
let
diff --git a/src/mono_util.sml b/src/mono_util.sml
index a85443d7..b14e3ac9 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -334,6 +334,10 @@ fun mapfoldB {typ = fc, exp = fe, bind} =
S.map2 (mfe ctx e2,
fn e2' =>
(ESignalBind (e1', e2'), loc)))
+ | ESignalSource e =>
+ S.map2 (mfe ctx e,
+ fn e' =>
+ (ESignalSource e', loc))
in
mfe
end
diff --git a/src/monoize.sml b/src/monoize.sml
index 30bd5daa..d3d20e7c 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -975,7 +975,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
in
((L'.EAbs ("x", t, (L'.TFun ((L'.TRecord [], loc), (L'.TFfi ("Basis", "int"), loc)), loc),
(L'.EAbs ("_", (L'.TRecord [], loc), (L'.TFfi ("Basis", "int"), loc),
- (L'.EFfiApp ("Basis", "new_client_source", [(L'.ERecord [], loc)]), loc)), loc)),
+ (L'.EFfiApp ("Basis", "new_client_source", [(L'.ERel 1, loc)]), loc)), loc)),
loc),
fm)
end
@@ -1003,6 +1003,14 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L'.ESignalBind ((L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc),
fm)
end
+ | L.ECApp ((L.EFfi ("Basis", "signal"), _), t) =>
+ let
+ val t = monoType env t
+ in
+ ((L'.EAbs ("x", (L'.TFfi ("Basis", "int"), loc), (L'.TSignal t, loc),
+ (L'.ESignalSource (L'.ERel 0, loc), loc)), loc),
+ fm)
+ end
| L.ECApp ((L.EFfi ("Basis", "getCookie"), _), t) =>
let
diff --git a/tests/reactive.ur b/tests/reactive.ur
index cb49541f..95839c7d 100644
--- a/tests/reactive.ur
+++ b/tests/reactive.ur
@@ -1,4 +1,5 @@
fun main () : transaction page =
- x <- source ();
- y <- source ();
- return Hi!
+ x <- source TEST;
+ return
+
+
--
cgit v1.2.3
From 493ec594ea29706c85196d1b616ab28ed3da6797 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Tue, 30 Dec 2008 10:49:42 -0500
Subject: Setting a source server-side
---
include/urweb.h | 4 +++-
src/c/urweb.c | 31 +++++++++++++++++++++++++------
src/cjrize.sml | 1 +
src/jscomp.sml | 14 +++++++++++++-
src/mono.sml | 1 +
src/mono_print.sml | 1 +
src/mono_reduce.sml | 2 ++
src/mono_util.sml | 5 +++++
src/monoize.sml | 14 ++++++++------
tests/reactive2.ur | 6 ++++++
tests/reactive2.urp | 3 +++
11 files changed, 68 insertions(+), 14 deletions(-)
create mode 100644 tests/reactive2.ur
create mode 100644 tests/reactive2.urp
(limited to 'src/mono.sml')
diff --git a/include/urweb.h b/include/urweb.h
index 647f153a..a5bb8dc0 100644
--- a/include/urweb.h
+++ b/include/urweb.h
@@ -36,7 +36,9 @@ char *uw_get_optional_input(uw_context, int name);
void uw_write(uw_context, const char*);
-int uw_Basis_new_client_source(uw_context, uw_unit);
+uw_Basis_int uw_Basis_new_client_source(uw_context, uw_Basis_string);
+uw_unit uw_Basis_set_client_source(uw_context, uw_Basis_int, uw_Basis_string);
+
char *uw_Basis_get_script(uw_context, uw_unit);
char *uw_Basis_htmlifyInt(uw_context, uw_Basis_int);
diff --git a/src/c/urweb.c b/src/c/urweb.c
index 11b99f4c..2c6d493a 100644
--- a/src/c/urweb.c
+++ b/src/c/urweb.c
@@ -363,6 +363,7 @@ static void uw_check_script(uw_context ctx, size_t extra) {
ctx->script_front = new_script + (ctx->script_front - ctx->script);
ctx->script_back = new_script + next;
ctx->script = new_script;
+ printf("new_script = %p\n", new_script);
}
}
@@ -434,7 +435,7 @@ uw_Basis_string uw_Basis_jsifyString_ws(uw_context ctx, uw_Basis_string s) {
char c = *s;
switch (c) {
- case '"':
+ case '\'':
strcpy(s2, "\\\"");
s2 += 2;
break;
@@ -457,18 +458,36 @@ uw_Basis_string uw_Basis_jsifyString_ws(uw_context ctx, uw_Basis_string s) {
return r;
}
-int uw_Basis_new_client_source(uw_context ctx, uw_Basis_string s) {
- size_t len;
+uw_Basis_int uw_Basis_new_client_source(uw_context ctx, uw_Basis_string s) {
+ int len;
+ size_t s_len = strlen(s);
- uw_check_script(ctx, 8 + INTS_MAX);
+ uw_check_script(ctx, 12 + INTS_MAX + s_len);
sprintf(ctx->script_front, "var s%d=sc(%n", ctx->source_count, &len);
ctx->script_front += len;
- uw_Basis_jsifyString_ws(ctx, s);
- uw_write_script(ctx, ");");
+ strcpy(ctx->script_front, s);
+ ctx->script_front += s_len;
+ strcpy(ctx->script_front, ");");
+ ctx->script_front += 2;
return ctx->source_count++;
}
+uw_unit uw_Basis_set_client_source(uw_context ctx, uw_Basis_int n, uw_Basis_string s) {
+ int len;
+ size_t s_len = strlen(s);
+
+ uw_check_script(ctx, 6 + INTS_MAX + s_len);
+ sprintf(ctx->script_front, "s%d.v=%n", (int)n, &len);
+ ctx->script_front += len;
+ strcpy(ctx->script_front, s);
+ ctx->script_front += s_len;
+ strcpy(ctx->script_front, ";");
+ ctx->script_front++;
+
+ return uw_unit_v;
+}
+
static void uw_check(uw_context ctx, size_t extra) {
size_t desired = ctx->page_front - ctx->page + extra, next;
char *new_page;
diff --git a/src/cjrize.sml b/src/cjrize.sml
index a9c51826..6d0ece61 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -120,6 +120,7 @@ fun cifyTyp x =
in
((L'.TOption t, loc), sm)
end
+ | L.TSource => ((L'.TFfi ("Basis", "int"), loc), sm)
| L.TSignal _ => raise Fail "Cjrize: TSignal remains"
in
cify IM.empty x
diff --git a/src/jscomp.sml b/src/jscomp.sml
index f7ef6927..8b874289 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -121,6 +121,13 @@ fun jsExp mode outer =
(str "ERROR", st))
val strcat = strcat loc
+
+ fun quoteExp (t : typ) e =
+ case #1 t of
+ TSource => strcat [str "s",
+ (EFfiApp ("Basis", "htmlifyInt", [e]), loc)]
+ | _ => (EM.errorAt loc "Don't know how to embed type in JavaScript";
+ str "ERROR")
in
case #1 e of
EPrim (Prim.String s) =>
@@ -130,6 +137,7 @@ fun jsExp mode outer =
"\\047"
else
"'"
+ | #"\"" => "\\\""
| #"<" =>
if mode = Script then
"<"
@@ -143,7 +151,11 @@ fun jsExp mode outer =
if n < inner then
(str ("uwr" ^ var n), st)
else
- (str ("uwo" ^ var n), st)
+ let
+ val n = n - inner
+ in
+ (quoteExp (List.nth (outer, n)) (ERel n, loc), st)
+ end
| ENamed _ => raise Fail "Named"
| ECon (_, pc, NONE) => (patCon pc, st)
| ECon (_, pc, SOME e) =>
diff --git a/src/mono.sml b/src/mono.sml
index ae9a06c7..41457071 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -37,6 +37,7 @@ datatype typ' =
| TDatatype of int * (datatype_kind * (string * int * typ option) list) ref
| TFfi of string * string
| TOption of typ
+ | TSource
| TSignal of typ
withtype typ = typ' located
diff --git a/src/mono_print.sml b/src/mono_print.sml
index b3c0a568..a876cfac 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -65,6 +65,7 @@ fun p_typ' par env (t, _) =
| TOption t => box [string "option(",
p_typ env t,
string ")"]
+ | TSource => string "source"
| TSignal t => box [string "signal(",
p_typ env t,
string ")"]
diff --git a/src/mono_reduce.sml b/src/mono_reduce.sml
index a6777db5..072c548e 100644
--- a/src/mono_reduce.sml
+++ b/src/mono_reduce.sml
@@ -55,6 +55,7 @@ fun impure (e, _) =
| EFfi _ => false
| EFfiApp ("Basis", "set_cookie", _) => true
| EFfiApp ("Basis", "new_client_source", _) => true
+ | EFfiApp ("Basis", "set_client_source", _) => true
| EFfiApp _ => false
| EApp ((EFfi _, _), _) => false
| EApp _ => true
@@ -263,6 +264,7 @@ fun reduce file =
| EFfi _ => []
| EFfiApp ("Basis", "set_cookie", _) => [Unsure]
| EFfiApp ("Basis", "new_client_source", _) => [Unsure]
+ | EFfiApp ("Basis", "set_client_source", _) => [Unsure]
| EFfiApp (_, _, es) => List.concat (map (summarize d) es)
| EApp ((EFfi _, _), e) => summarize d e
| EApp _ =>
diff --git a/src/mono_util.sml b/src/mono_util.sml
index b14e3ac9..3f9183d0 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -51,6 +51,7 @@ fun compare ((t1, _), (t2, _)) =
| (TDatatype (n1, _), TDatatype (n2, _)) => Int.compare (n1, n2)
| (TFfi (m1, x1), TFfi (m2, x2)) => join (String.compare (m1, m2), fn () => String.compare (x1, x2))
| (TOption t1, TOption t2) => compare (t1, t2)
+ | (TSource, TSource) => EQUAL
| (TSignal t1, TSignal t2) => compare (t1, t2)
| (TFun _, _) => LESS
@@ -68,6 +69,9 @@ fun compare ((t1, _), (t2, _)) =
| (TOption _, _) => LESS
| (_, TOption _) => GREATER
+ | (TSource, _) => LESS
+ | (_, TSource) => GREATER
+
and compareFields ((x1, t1), (x2, t2)) =
join (String.compare (x1, x2),
fn () => compare (t1, t2))
@@ -100,6 +104,7 @@ fun mapfold fc =
S.map2 (mft t,
fn t' =>
(TOption t, loc))
+ | TSource => S.return2 cAll
| TSignal t =>
S.map2 (mft t,
fn t' =>
diff --git a/src/monoize.sml b/src/monoize.sml
index e34ef162..f40d49d0 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -134,7 +134,7 @@ fun monoType env =
| L.CApp ((L.CFfi ("Basis", "transaction"), _), t) =>
(L'.TFun ((L'.TRecord [], loc), mt env dtmap t), loc)
| L.CApp ((L.CFfi ("Basis", "source"), _), t) =>
- (L'.TFfi ("Basis", "int"), loc)
+ (L'.TSource, loc)
| L.CApp ((L.CFfi ("Basis", "signal"), _), t) =>
(L'.TSignal (mt env dtmap t), loc)
| L.CApp ((L.CFfi ("Basis", "http_cookie"), _), _) =>
@@ -973,9 +973,10 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
let
val t = monoType env t
in
- ((L'.EAbs ("x", t, (L'.TFun ((L'.TRecord [], loc), (L'.TFfi ("Basis", "int"), loc)), loc),
- (L'.EAbs ("_", (L'.TRecord [], loc), (L'.TFfi ("Basis", "int"), loc),
- (L'.EFfiApp ("Basis", "new_client_source", [(L'.ERel 1, loc)]), loc)), loc)),
+ ((L'.EAbs ("x", t, (L'.TFun ((L'.TRecord [], loc), (L'.TSource, loc)), loc),
+ (L'.EAbs ("_", (L'.TRecord [], loc), (L'.TSource, loc),
+ (L'.EFfiApp ("Basis", "new_client_source",
+ [(L'.EJavaScript (L'.File, (L'.ERel 1, loc)), loc)]), loc)), loc)),
loc),
fm)
end
@@ -983,12 +984,13 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
let
val t = monoType env t
in
- ((L'.EAbs ("src", (L'.TFfi ("Basis", "int"), loc),
+ ((L'.EAbs ("src", (L'.TSource, loc),
(L'.TFun (t, (L'.TFun ((L'.TRecord [], loc), (L'.TRecord [], loc)), loc)), loc),
(L'.EAbs ("v", t, (L'.TFun ((L'.TRecord [], loc), (L'.TRecord [], loc)), loc),
(L'.EAbs ("_", (L'.TRecord [], loc), (L'.TRecord [], loc),
(L'.EFfiApp ("Basis", "set_client_source",
- [(L'.ERel 2, loc), (L'.ERel 1, loc)]),
+ [(L'.ERel 2, loc),
+ (L'.EJavaScript (L'.File, (L'.ERel 1, loc)), loc)]),
loc)), loc)), loc)), loc),
fm)
end
diff --git a/tests/reactive2.ur b/tests/reactive2.ur
new file mode 100644
index 00000000..7164468e
--- /dev/null
+++ b/tests/reactive2.ur
@@ -0,0 +1,6 @@
+fun main () : transaction page =
+ x <- source TEST;
+ set x HI;
+ return
+
+
diff --git a/tests/reactive2.urp b/tests/reactive2.urp
new file mode 100644
index 00000000..bdc0d1be
--- /dev/null
+++ b/tests/reactive2.urp
@@ -0,0 +1,3 @@
+debug
+
+reactive2
--
cgit v1.2.3
From 8d3edc5aaa4617dd06623447cf9357067eadc072 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Tue, 30 Dec 2008 11:33:31 -0500
Subject: Harmonized source-setting between server and client
---
src/cjrize.sml | 2 ++
src/jscomp.sml | 15 ++++++++++-----
src/mono.sml | 2 +-
src/mono_opt.sml | 2 ++
src/mono_print.sml | 13 ++++++++-----
src/mono_reduce.sml | 4 ++--
src/mono_util.sml | 10 ++++++++--
src/monoize.sml | 16 ++++++++--------
8 files changed, 41 insertions(+), 23 deletions(-)
(limited to 'src/mono.sml')
diff --git a/src/cjrize.sml b/src/cjrize.sml
index 6d0ece61..1a5d10c0 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -422,7 +422,9 @@ fun cifyExp (eAll as (e, loc), sm) =
((L'.EUnurlify (e, t), loc), sm)
end
+ | L.EJavaScript (_, _, SOME e) => cifyExp (e, sm)
| L.EJavaScript _ => raise Fail "Cjrize: EJavaScript remains"
+
| L.ESignalReturn _ => raise Fail "Cjrize: ESignalReturn remains"
| L.ESignalBind _ => raise Fail "Cjrize: ESignalBind remains"
| L.ESignalSource _ => raise Fail "Cjrize: ESignalSource remains"
diff --git a/src/jscomp.sml b/src/jscomp.sml
index 8b874289..a4e3dd35 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -190,6 +190,12 @@ fun jsExp mode outer =
end
| EFfiApp (m, x, args) =>
let
+ val args =
+ case (m, x, args) of
+ ("Basis", "new_client_source", [(EJavaScript (_, e, _), _)]) => [e]
+ | ("Basis", "set_client_source", [e1, (EJavaScript (_, e2, _), _)]) => [e1, e2]
+ | _ => args
+
val name = case ffi (m, x) of
NONE => (EM.errorAt loc ("Unsupported FFI function " ^ x ^ " in JavaScript");
"ERROR")
@@ -200,7 +206,6 @@ fun jsExp mode outer =
| [e] =>
let
val (e, st) = jsE inner (e, st)
-
in
(strcat [str (name ^ "("),
e,
@@ -398,7 +403,7 @@ val decl : state -> decl -> decl * state =
U.Decl.foldMapB {typ = fn x => x,
exp = fn (env, e, st) =>
let
- fun doCode m env e =
+ fun doCode m env orig e =
let
val len = length env
fun str s = (EPrim (Prim.String s), #2 e)
@@ -408,12 +413,12 @@ val decl : state -> decl -> decl * state =
fn i => str ("var uwr" ^ Int.toString (len + i) ^ ";"))
val (e, st) = jsExp m env 0 (e, st)
in
- (#1 (strcat (#2 e) (locals @ [e])), st)
+ (EJavaScript (m, orig, SOME (strcat (#2 e) (locals @ [e]))), st)
end
in
case e of
- EJavaScript (m, (EAbs (_, t, _, e), _)) => doCode m (t :: env) e
- | EJavaScript (m, e) => doCode m env e
+ EJavaScript (m, orig as (EAbs (_, t, _, e), _), _) => doCode m (t :: env) orig e
+ | EJavaScript (m, e, _) => doCode m env e e
| _ => (e, st)
end,
decl = fn (_, e, st) => (e, st),
diff --git a/src/mono.sml b/src/mono.sml
index 41457071..b58396fa 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -103,7 +103,7 @@ datatype exp' =
| EUnurlify of exp * typ
- | EJavaScript of javascript_mode * exp
+ | EJavaScript of javascript_mode * exp * exp option
| ESignalReturn of exp
| ESignalBind of exp * exp
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index 550a055c..7f23d8b1 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -363,6 +363,8 @@ fun exp e =
| ESignalBind ((ESignalReturn e1, loc), e2) =>
optExp (EApp (e2, e1), loc)
+ | EJavaScript (_, _, SOME (e, _)) => e
+
| _ => e
and optExp e = #1 (U.Exp.map {typ = typ, exp = exp} e)
diff --git a/src/mono_print.sml b/src/mono_print.sml
index a876cfac..f8a23d1d 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -216,10 +216,12 @@ fun p_exp' par env (e, _) =
p_exp env e,
string ")"]
- | ESeq (e1, e2) => box [p_exp env e1,
+ | ESeq (e1, e2) => box [string "(",
+ p_exp env e1,
string ";",
space,
- p_exp env e2]
+ p_exp env e2,
+ string ")"]
| ELet (x, t, e1, e2) => box [string "(let",
space,
string x,
@@ -279,9 +281,10 @@ fun p_exp' par env (e, _) =
| EUnurlify (e, _) => box [string "unurlify(",
p_exp env e,
string ")"]
- | EJavaScript (_, e) => box [string "JavaScript(",
- p_exp env e,
- string ")"]
+ | EJavaScript (_, e, NONE) => box [string "JavaScript(",
+ p_exp env e,
+ string ")"]
+ | EJavaScript (_, _, SOME e) => p_exp env e
| ESignalReturn e => box [string "Return(",
p_exp env e,
diff --git a/src/mono_reduce.sml b/src/mono_reduce.sml
index 072c548e..c96f97cf 100644
--- a/src/mono_reduce.sml
+++ b/src/mono_reduce.sml
@@ -76,7 +76,7 @@ fun impure (e, _) =
| ELet (_, _, e1, e2) => impure e1 orelse impure e2
| EClosure (_, es) => List.exists impure es
- | EJavaScript (_, e) => impure e
+ | EJavaScript (_, e, _) => impure e
| ESignalReturn e => impure e
| ESignalBind (e1, e2) => impure e1 orelse impure e2
| ESignalSource e => impure e
@@ -335,7 +335,7 @@ fun reduce file =
| EDml e => summarize d e @ [WriteDb]
| ENextval e => summarize d e @ [WriteDb]
| EUnurlify (e, _) => summarize d e
- | EJavaScript (_, e) => summarize d e
+ | EJavaScript (_, e, _) => summarize d e
| ESignalReturn e => summarize d e
| ESignalBind (e1, e2) => summarize d e1 @ summarize d e2
| ESignalSource e => summarize d e
diff --git a/src/mono_util.sml b/src/mono_util.sml
index 3f9183d0..9ce3293b 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -324,10 +324,16 @@ fun mapfoldB {typ = fc, exp = fe, bind} =
S.map2 (mft t,
fn t' =>
(EUnurlify (e', t'), loc)))
- | EJavaScript (m, e) =>
+ | EJavaScript (m, e, NONE) =>
S.map2 (mfe ctx e,
fn e' =>
- (EJavaScript (m, e'), loc))
+ (EJavaScript (m, e', NONE), loc))
+ | EJavaScript (m, e, SOME e2) =>
+ S.bind2 (mfe ctx e,
+ fn e' =>
+ S.map2 (mfe ctx e2,
+ fn e2' =>
+ (EJavaScript (m, e', SOME e2'), loc)))
| ESignalReturn e =>
S.map2 (mfe ctx e,
diff --git a/src/monoize.sml b/src/monoize.sml
index f40d49d0..f62848c5 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -976,7 +976,8 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
((L'.EAbs ("x", t, (L'.TFun ((L'.TRecord [], loc), (L'.TSource, loc)), loc),
(L'.EAbs ("_", (L'.TRecord [], loc), (L'.TSource, loc),
(L'.EFfiApp ("Basis", "new_client_source",
- [(L'.EJavaScript (L'.File, (L'.ERel 1, loc)), loc)]), loc)), loc)),
+ [(L'.EJavaScript (L'.File, (L'.ERel 1, loc), NONE), loc)]),
+ loc)), loc)),
loc),
fm)
end
@@ -990,7 +991,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L'.EAbs ("_", (L'.TRecord [], loc), (L'.TRecord [], loc),
(L'.EFfiApp ("Basis", "set_client_source",
[(L'.ERel 2, loc),
- (L'.EJavaScript (L'.File, (L'.ERel 1, loc)), loc)]),
+ (L'.EJavaScript (L'.File, (L'.ERel 1, loc), NONE), loc)]),
loc)), loc)), loc)), loc),
fm)
end
@@ -1801,7 +1802,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L'.EStrcat (
(L'.EPrim (Prim.String s'), loc),
(L'.EStrcat (
- (L'.EJavaScript (L'.Attribute, e), loc),
+ (L'.EJavaScript (L'.Attribute, e, NONE), loc),
(L'.EPrim (Prim.String "'"), loc)), loc)),
loc)), loc),
fm)
@@ -1887,13 +1888,12 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
| "dyn" =>
(case #1 attrs of
- (*L'.ERecord [("Signal", (L'.EApp ((L'.EAbs (_, _, _, (L'.ESignalReturn (L'.ERel 0, _), _)), _),
- e), _), _)] => (e, fm) *)
-
- L'.ERecord [("Signal", e, _)] =>
+ L'.ERecord [("Signal", (L'.EApp ((L'.EAbs (_, _, _, (L'.ESignalReturn (L'.ERel 0, _), _)), _),
+ e), _), _)] => (e, fm)
+ | L'.ERecord [("Signal", e, _)] =>
((L'.EStrcat
((L'.EPrim (Prim.String ""), loc)), loc)), loc),
fm)
| _ => raise Fail "Monoize: Bad dyn attributes")
--
cgit v1.2.3
From 8bb915433716ecfdcf2c2209d1a62796ebde4714 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Thu, 1 Jan 2009 15:11:17 -0500
Subject: Injecting an int
---
src/jscomp.sml | 67 +++++++++++++++++++++++++++++++++++++++++----------------
src/mono.sml | 2 +-
src/monoize.sml | 5 +++--
tests/jsinj.ur | 14 ++++++++++++
tests/jsinj.urp | 3 +++
5 files changed, 70 insertions(+), 21 deletions(-)
create mode 100644 tests/jsinj.ur
create mode 100644 tests/jsinj.urp
(limited to 'src/mono.sml')
diff --git a/src/jscomp.sml b/src/jscomp.sml
index 67d8d9c1..b27a860b 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -102,6 +102,8 @@ fun strcat loc es =
| [x] => x
| x :: es' => (EStrcat (x, strcat loc es'), loc)
+exception Unsupported of string * EM.span
+
fun process file =
let
val nameds = foldl (fn ((DVal (_, n, t, e, _), _), nameds) => IM.insert (nameds, n, e)
@@ -111,13 +113,28 @@ fun process file =
| (_, nameds) => nameds)
IM.empty file
+ fun str loc s = (EPrim (Prim.String s), loc)
+
+ fun quoteExp loc (t : typ) e =
+ case #1 t of
+ TSource => strcat loc [str loc "s",
+ (EFfiApp ("Basis", "htmlifyInt", [e]), loc)]
+ | TRecord [] => str loc "null"
+
+ | TFfi ("Basis", "string") => e
+ | TFfi ("Basis", "int") => (EFfiApp ("Basis", "htmlifyInt", [e]), loc)
+
+ | _ => (EM.errorAt loc "Don't know how to embed type in JavaScript";
+ Print.prefaces "Can't embed" [("t", MonoPrint.p_typ MonoEnv.empty t)];
+ str loc "ERROR")
+
fun jsExp mode skip outer =
let
val len = length outer
fun jsE inner (e as (_, loc), st) =
let
- fun str s = (EPrim (Prim.String s), loc)
+ val str = str loc
fun var n = Int.toString (len + inner - n - 1)
@@ -134,22 +151,10 @@ fun process file =
| TRecord [] => true
| _ => false
- fun unsupported s =
- (EM.errorAt loc (s ^ " in code to be compiled to JavaScript");
- (str "ERROR", st))
+ fun unsupported s = raise Unsupported (s, loc)
val strcat = strcat loc
- fun quoteExp (t : typ) e =
- case #1 t of
- TSource => strcat [str "s",
- (EFfiApp ("Basis", "htmlifyInt", [e]), loc)]
- | TRecord [] => str "null"
- | TFfi ("Basis", "string") => e
- | _ => (EM.errorAt loc "Don't know how to embed type in JavaScript";
- Print.prefaces "Can't embed" [("t", MonoPrint.p_typ MonoEnv.empty t)];
- str "ERROR")
-
fun jsPrim p =
case p of
Prim.String s =>
@@ -241,7 +246,11 @@ fun process file =
EPrim (Prim.String s) => s
| EStrcat (e1, e2) => deStrcat e1 ^ deStrcat e2
| _ => raise Fail "Jscomp: deStrcat"
+
+ val quoteExp = quoteExp loc
in
+ (*Print.prefaces "jsE" [("e", MonoPrint.p_exp MonoEnv.empty e)];*)
+
case #1 e of
EPrim p => (jsPrim p, st)
| ERel n =>
@@ -513,12 +522,15 @@ fun process file =
str ")"], st)
end
+ | EJavaScript (_, _, SOME e) => (e, st)
+
| EClosure _ => unsupported "EClosure"
| EQuery _ => unsupported "Query"
| EDml _ => unsupported "DML"
| ENextval _ => unsupported "Nextval"
| EUnurlify _ => unsupported "EUnurlify"
- | EJavaScript _ => unsupported "Nested JavaScript"
+ | EJavaScript (_, e, _) => unsupported "Nested JavaScript"
+
| ESignalReturn e =>
let
val (e, st) = jsE inner (e, st)
@@ -572,9 +584,28 @@ fun process file =
end
in
case e of
- EJavaScript (m, orig as (EAbs (_, t, _, e), _), _) =>
- doCode m 1 (t :: env) orig e
- | EJavaScript (m, e, _) => doCode m 0 env e e
+ EJavaScript (m as Source t, orig, _) =>
+ (doCode m 0 env orig orig
+ handle Unsupported (s, loc) =>
+ let
+ val e = ELet ("js", t, orig, quoteExp (#2 orig) t
+ (ERel 0, #2 orig))
+ in
+ (EJavaScript (m, orig, SOME (e, #2 orig)), st)
+ end)
+
+ | EJavaScript (m, orig as (EAbs (_, t, _, e), _), _) =>
+ (doCode m 1 (t :: env) orig e
+ handle Unsupported (s, loc) =>
+ (EM.errorAt loc (s ^ " in code to be compiled to JavaScript");
+ (EPrim (Prim.String "ERROR"), st)))
+
+ | EJavaScript (m, orig, _) =>
+ (doCode m 0 env orig orig
+ handle Unsupported (s, loc) =>
+ (EM.errorAt loc (s ^ " in code to be compiled to JavaScript");
+ (EPrim (Prim.String "ERROR"), st)))
+
| _ => (e, st)
end,
decl = fn (_, e, st) => (e, st),
diff --git a/src/mono.sml b/src/mono.sml
index b58396fa..8999704c 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -60,7 +60,7 @@ withtype pat = pat' located
datatype javascript_mode =
Attribute
| Script
- | File
+ | Source of typ
datatype exp' =
EPrim of Prim.t
diff --git a/src/monoize.sml b/src/monoize.sml
index f62848c5..6c4534ac 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -976,7 +976,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
((L'.EAbs ("x", t, (L'.TFun ((L'.TRecord [], loc), (L'.TSource, loc)), loc),
(L'.EAbs ("_", (L'.TRecord [], loc), (L'.TSource, loc),
(L'.EFfiApp ("Basis", "new_client_source",
- [(L'.EJavaScript (L'.File, (L'.ERel 1, loc), NONE), loc)]),
+ [(L'.EJavaScript (L'.Source t, (L'.ERel 1, loc), NONE), loc)]),
loc)), loc)),
loc),
fm)
@@ -991,7 +991,8 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L'.EAbs ("_", (L'.TRecord [], loc), (L'.TRecord [], loc),
(L'.EFfiApp ("Basis", "set_client_source",
[(L'.ERel 2, loc),
- (L'.EJavaScript (L'.File, (L'.ERel 1, loc), NONE), loc)]),
+ (L'.EJavaScript (L'.Source t,
+ (L'.ERel 1, loc), NONE), loc)]),
loc)), loc)), loc)), loc),
fm)
end
diff --git a/tests/jsinj.ur b/tests/jsinj.ur
new file mode 100644
index 00000000..194d26be
--- /dev/null
+++ b/tests/jsinj.ur
@@ -0,0 +1,14 @@
+cookie int : int
+
+fun getOpt (t ::: Type) (o : option t) (v : t) : t =
+ case o of
+ None => v
+ | Some x => x
+
+fun main () : transaction page =
+ n <- getCookie int;
+ sn <- source (getOpt n 7);
+ return
+ {[n]}}/>
+ CHANGE
+
diff --git a/tests/jsinj.urp b/tests/jsinj.urp
new file mode 100644
index 00000000..dc929b9d
--- /dev/null
+++ b/tests/jsinj.urp
@@ -0,0 +1,3 @@
+debug
+
+jsinj
--
cgit v1.2.3
From e27335a18e8f4b1cca2749e8d41863b3cbef9b62 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sun, 15 Feb 2009 09:27:36 -0500
Subject: Export RPC functions and push RPC calls through to Mono
---
src/cjr_print.sml | 2 ++
src/cjrize.sml | 2 ++
src/core.sml | 1 +
src/core_print.sml | 1 +
src/jscomp.sml | 4 ++++
src/mono.sml | 2 ++
src/mono_print.sml | 9 +++++++++
src/mono_reduce.sml | 3 +++
src/mono_util.sml | 7 +++++++
src/monoize.sml | 8 +++++++-
src/rpcify.sml | 47 +++++++++++++++++++++++++++++++++++------------
11 files changed, 73 insertions(+), 13 deletions(-)
(limited to 'src/mono.sml')
diff --git a/src/cjr_print.sml b/src/cjr_print.sml
index f8b1f23b..8f5c8551 100644
--- a/src/cjr_print.sml
+++ b/src/cjr_print.sml
@@ -1849,6 +1849,7 @@ fun p_file env (ds, ps) =
val fields = foldl (fn ((ek, _, _, ts), fields) =>
case ek of
Core.Link => fields
+ | Core.Rpc => fields
| Core.Action =>
case List.nth (ts, length ts - 2) of
(TRecord i, _) =>
@@ -1971,6 +1972,7 @@ fun p_file env (ds, ps) =
val (ts, defInputs, inputsVar) =
case ek of
Core.Link => (List.take (ts, length ts - 1), string "", string "")
+ | Core.Rpc => (List.take (ts, length ts - 1), string "", string "")
| Core.Action =>
case List.nth (ts, length ts - 2) of
(TRecord i, _) =>
diff --git a/src/cjrize.sml b/src/cjrize.sml
index 1a5d10c0..77674158 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -429,6 +429,8 @@ fun cifyExp (eAll as (e, loc), sm) =
| L.ESignalBind _ => raise Fail "Cjrize: ESignalBind remains"
| L.ESignalSource _ => raise Fail "Cjrize: ESignalSource remains"
+ | L.EServerCall _ => raise Fail "Cjrize EServerCall"
+
fun cifyDecl ((d, loc), sm) =
case d of
L.DDatatype (x, n, xncs) =>
diff --git a/src/core.sml b/src/core.sml
index fbe150c1..62f046fe 100644
--- a/src/core.sml
+++ b/src/core.sml
@@ -113,6 +113,7 @@ withtype exp = exp' located
datatype export_kind =
Link
| Action
+ | Rpc
datatype decl' =
DCon of string * int * kind * con
diff --git a/src/core_print.sml b/src/core_print.sml
index 64cead70..e9a36fbb 100644
--- a/src/core_print.sml
+++ b/src/core_print.sml
@@ -436,6 +436,7 @@ fun p_export_kind ck =
case ck of
Link => string "link"
| Action => string "action"
+ | Rpc => string "rpc"
fun p_datatype env (x, n, xs, cons) =
let
diff --git a/src/jscomp.sml b/src/jscomp.sml
index f61ec3f0..627ba8f6 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -98,6 +98,7 @@ fun varDepth (e, _) =
| ESignalReturn e => varDepth e
| ESignalBind (e1, e2) => Int.max (varDepth e1, varDepth e2)
| ESignalSource e => varDepth e
+ | EServerCall (_, es, ek) => foldl Int.max (varDepth ek) (map varDepth es)
fun closedUpto d =
let
@@ -138,6 +139,7 @@ fun closedUpto d =
| ESignalReturn e => cu inner e
| ESignalBind (e1, e2) => cu inner e1 andalso cu inner e2
| ESignalSource e => cu inner e
+ | EServerCall (_, es, ek) => List.all (cu inner) es andalso cu inner ek
in
cu 0
end
@@ -809,6 +811,8 @@ fun process file =
str ")"],
st)
end
+
+ | EServerCall _ => raise Fail "Jscomp EServerCall"
end
in
jsE
diff --git a/src/mono.sml b/src/mono.sml
index 8999704c..547f8a55 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -109,6 +109,8 @@ datatype exp' =
| ESignalBind of exp * exp
| ESignalSource of exp
+ | EServerCall of int * exp list * exp
+
withtype exp = exp' located
datatype decl' =
diff --git a/src/mono_print.sml b/src/mono_print.sml
index 1e9de3d8..a859a1bd 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -308,6 +308,15 @@ fun p_exp' par env (e, _) =
p_exp env e,
string ")"]
+ | 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_vali env (x, n, t, e, s) =
diff --git a/src/mono_reduce.sml b/src/mono_reduce.sml
index 878fec92..7d39648a 100644
--- a/src/mono_reduce.sml
+++ b/src/mono_reduce.sml
@@ -81,6 +81,7 @@ fun impure (e, _) =
| ESignalReturn e => impure e
| ESignalBind (e1, e2) => impure e1 orelse impure e2
| ESignalSource e => impure e
+ | EServerCall _ => true
val liftExpInExp = Monoize.liftExpInExp
@@ -344,6 +345,8 @@ fun reduce file =
| ESignalReturn e => summarize d e
| ESignalBind (e1, e2) => summarize d e1 @ summarize d e2
| ESignalSource e => summarize d e
+
+ | EServerCall (_, es, ek) => List.concat (map (summarize d) es) @ summarize d ek @ [Unsure]
in
(*Print.prefaces "Summarize"
[("e", MonoPrint.p_exp MonoEnv.empty (e, ErrorMsg.dummySpan)),
diff --git a/src/mono_util.sml b/src/mono_util.sml
index 9ce3293b..13e0d32c 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -349,6 +349,13 @@ fun mapfoldB {typ = fc, exp = fe, bind} =
S.map2 (mfe ctx e,
fn e' =>
(ESignalSource e', loc))
+
+ | EServerCall (n, es, ek) =>
+ S.bind2 (ListUtil.mapfold (fn e => mfe ctx e) es,
+ fn es' =>
+ S.map2 (mfe ctx ek,
+ fn ek' =>
+ (EServerCall (n, es', ek'), loc)))
in
mfe
end
diff --git a/src/monoize.sml b/src/monoize.sml
index a1f61143..fb1ac2f1 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -2225,7 +2225,13 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
((L'.ELet (x, t', e1, e2), loc), fm)
end
- | L.EServerCall _ => raise Fail "Monoize EServerCall"
+ | L.EServerCall (n, es, ek) =>
+ let
+ val (es, fm) = ListUtil.foldlMap (fn (e, fm) => monoExp (env, st, fm) e) fm es
+ val (ek, fm) = monoExp (env, st, fm) ek
+ in
+ ((L'.EServerCall (n, es, ek), loc), fm)
+ end
end
fun monoDecl (env, fm) (all as (d, loc)) =
diff --git a/src/rpcify.sml b/src/rpcify.sml
index dec8dc18..09c44a7a 100644
--- a/src/rpcify.sml
+++ b/src/rpcify.sml
@@ -53,8 +53,11 @@ val csBasis = SS.addList (SS.empty,
"alert"])
type state = {
- exps : int IM.map,
- decls : (string * int * con * exp * string) list
+ cpsed : int IM.map,
+ cps_decls : (string * int * con * exp * string) list,
+
+ exported : IS.set,
+ export_decls : decl list
}
fun frob file =
@@ -114,6 +117,19 @@ fun frob file =
(0, []))
val (n, args) = getApp (trans1, [])
+
+ val (exported, export_decls) =
+ if IS.member (#exported st, n) then
+ (#exported st, #export_decls st)
+ else
+ (IS.add (#exported st, n),
+ (DExport (Rpc, n), loc) :: #export_decls st)
+
+ val st = {cpsed = #cpsed st,
+ cps_decls = #cps_decls st,
+
+ exported = exported,
+ export_decls = export_decls}
in
(EServerCall (n, args, trans2), st)
end
@@ -128,19 +144,26 @@ fun frob file =
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})
+ (List.revAppend (case #cps_decls st of
+ [] => [d]
+ | ds =>
+ case d of
+ (DValRec vis, loc) => [(DValRec (ds @ vis), loc)]
+ | (_, loc) => [d, (DValRec ds, loc)],
+ #export_decls st),
+ {cpsed = #cpsed st,
+ cps_decls = [],
+
+ exported = #exported st,
+ export_decls = []})
end
val (file, _) = ListUtil.foldlMapConcat decl
- {decls = [],
- exps = IM.empty}
+ {cpsed = IM.empty,
+ cps_decls = [],
+
+ exported = IS.empty,
+ export_decls = []}
file
in
file
--
cgit v1.2.3
From 1557ac806159fe58eaa442527f73e569dd04f88e Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sun, 15 Feb 2009 10:32:50 -0500
Subject: First gimpy RPC
---
lib/js/urweb.js | 29 +++++++++++++++++++++++++++++
src/cjr.sml | 2 +-
src/cjr_print.sml | 32 ++++++++++++++++++++++----------
src/cjrize.sml | 5 +++--
src/core.sml | 2 +-
src/core_print.sml | 16 ++++++++--------
src/core_util.sml | 10 ++++++----
src/jscomp.sml | 14 +++++++++++---
src/mono.sml | 4 ++--
src/mono_print.sml | 46 +++++++++++++++++++++++++---------------------
src/mono_reduce.sml | 2 +-
src/mono_shake.sml | 2 +-
src/mono_util.sml | 16 ++++++++++------
src/monoize.sml | 38 ++++++++++++++++++++++++++++----------
src/pathcheck.sml | 2 +-
src/reduce.sml | 2 +-
src/reduce_local.sml | 2 +-
src/rpcify.sml | 30 +++++++++++++++++++++++++++++-
src/shake.sml | 2 +-
tests/rpc.ur | 4 +++-
tests/rpc.urp | 2 +-
21 files changed, 185 insertions(+), 77 deletions(-)
(limited to 'src/mono.sml')
diff --git a/lib/js/urweb.js b/lib/js/urweb.js
index c46263b8..9dd4dbbe 100644
--- a/lib/js/urweb.js
+++ b/lib/js/urweb.js
@@ -111,3 +111,32 @@ function cr(n) {
return closures[n]();
}
+
+function getXHR()
+{
+ try {
+ return new XMLHttpRequest();
+ } catch (e) {
+ try {
+ return new ActiveXObject("Msxml2.XMLHTTP");
+ } catch (e) {
+ try {
+ return new ActiveXObject("Microsoft.XMLHTTP");
+ } catch (e) {
+ throw "Your browser doesn't seem to support AJAX.";
+ }
+ }
+ }
+}
+
+function rc(uri, k) {
+ var xhr = getXHR();
+
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4)
+ k(xhr.responseText);
+ };
+
+ xhr.open("GET", uri, true);
+ xhr.send(null);
+}
diff --git a/src/cjr.sml b/src/cjr.sml
index 43a29a6c..a38a1b0d 100644
--- a/src/cjr.sml
+++ b/src/cjr.sml
@@ -113,6 +113,6 @@ datatype decl' =
withtype decl = decl' located
-type file = decl list * (Core.export_kind * string * int * typ list) list
+type file = decl list * (Core.export_kind * string * int * typ list * typ) list
end
diff --git a/src/cjr_print.sml b/src/cjr_print.sml
index 8f5c8551..6074ca3b 100644
--- a/src/cjr_print.sml
+++ b/src/cjr_print.sml
@@ -1846,7 +1846,7 @@ fun p_file env (ds, ps) =
E.declBinds env d))
env ds
- val fields = foldl (fn ((ek, _, _, ts), fields) =>
+ val fields = foldl (fn ((ek, _, _, ts, _), fields) =>
case ek of
Core.Link => fields
| Core.Rpc => fields
@@ -1967,7 +1967,7 @@ fun p_file env (ds, ps) =
string "}"]
end
- fun p_page (ek, s, n, ts) =
+ fun p_page (ek, s, n, ts, ran) =
let
val (ts, defInputs, inputsVar) =
case ek of
@@ -2054,12 +2054,14 @@ fun p_file env (ds, ps) =
newline,
string "if (*request == '/') ++request;",
newline,
- string "uw_write_header(ctx, \"Content-type: text/html\\r\\n\");",
- newline,
- string "uw_write_header(ctx, \"Content-script-type: text/javascript\\r\\n\");",
- newline,
- string "uw_write(ctx, \"\");",
- newline,
+ box (case ek of
+ Core.Rpc => []
+ | _ => [string "uw_write_header(ctx, \"Content-type: text/html\\r\\n\");",
+ newline,
+ string "uw_write_header(ctx, \"Content-script-type: text/javascript\\r\\n\");",
+ newline,
+ string "uw_write(ctx, \"\");",
+ newline]),
box [string "{",
newline,
box (ListUtil.mapi (fn (i, t) => box [p_typ env t,
@@ -2073,6 +2075,14 @@ fun p_file env (ds, ps) =
string ";",
newline]) ts),
defInputs,
+ box (case ek of
+ Core.Rpc => [p_typ env ran,
+ space,
+ string "res",
+ space,
+ string "=",
+ space]
+ | _ => []),
p_enamed env n,
string "(",
p_list_sep (box [string ",", space])
@@ -2082,8 +2092,10 @@ fun p_file env (ds, ps) =
inputsVar,
string ", uw_unit_v);",
newline,
- string "uw_write(ctx, \"\");",
- newline,
+ box (case ek of
+ Core.Rpc => []
+ | _ => [string "uw_write(ctx, \"\");",
+ newline]),
string "return;",
newline,
string "}",
diff --git a/src/cjrize.sml b/src/cjrize.sml
index 77674158..16a82ec8 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -514,11 +514,12 @@ fun cifyDecl ((d, loc), sm) =
(SOME (L'.DFunRec vis, loc), NONE, sm)
end
- | L.DExport (ek, s, n, ts) =>
+ | L.DExport (ek, s, n, ts, t) =>
let
val (ts, sm) = ListUtil.foldlMap cifyTyp sm ts
+ val (t, sm) = cifyTyp (t, sm)
in
- (NONE, SOME (ek, "/" ^ s, n, ts), sm)
+ (NONE, SOME (ek, "/" ^ s, n, ts, t), sm)
end
| L.DTable (s, xts) =>
diff --git a/src/core.sml b/src/core.sml
index 62f046fe..c6e0cfef 100644
--- a/src/core.sml
+++ b/src/core.sml
@@ -106,7 +106,7 @@ datatype exp' =
| ELet of string * con * exp * exp
- | EServerCall of int * exp list * exp
+ | EServerCall of int * exp list * exp * con
withtype exp = exp' located
diff --git a/src/core_print.sml b/src/core_print.sml
index e9a36fbb..405ae14e 100644
--- a/src/core_print.sml
+++ b/src/core_print.sml
@@ -394,14 +394,14 @@ fun p_exp' par env (e, _) =
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 "]"]
+ | 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
diff --git a/src/core_util.sml b/src/core_util.sml
index 3d6808f9..a222dca4 100644
--- a/src/core_util.sml
+++ b/src/core_util.sml
@@ -482,7 +482,7 @@ fun compare ((e1, _), (e2, _)) =
| (ELet _, _) => LESS
| (_, ELet _) => GREATER
- | (EServerCall (n1, es1, e1), EServerCall (n2, es2, e2)) =>
+ | (EServerCall (n1, es1, e1, _), EServerCall (n2, es2, e2, _)) =>
join (Int.compare (n1, n2),
fn () => join (joinL compare (es1, es2),
fn () => compare (e1, e2)))
@@ -660,12 +660,14 @@ fun mapfoldB {kind = fk, con = fc, exp = fe, bind} =
fn e2' =>
(ELet (x, t', e1', e2'), loc))))
- | EServerCall (n, es, e) =>
+ | EServerCall (n, es, e, t) =>
S.bind2 (ListUtil.mapfold (mfe ctx) es,
fn es' =>
- S.map2 (mfe ctx e,
+ S.bind2 (mfe ctx e,
fn e' =>
- (EServerCall (n, es', e'), loc)))
+ S.map2 (mfc ctx t,
+ fn t' =>
+ (EServerCall (n, es', e', t'), loc))))
and mfp ctx (pAll as (p, loc)) =
case p of
diff --git a/src/jscomp.sml b/src/jscomp.sml
index 627ba8f6..de671fef 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -98,7 +98,7 @@ fun varDepth (e, _) =
| ESignalReturn e => varDepth e
| ESignalBind (e1, e2) => Int.max (varDepth e1, varDepth e2)
| ESignalSource e => varDepth e
- | EServerCall (_, es, ek) => foldl Int.max (varDepth ek) (map varDepth es)
+ | EServerCall (_, es, ek, _) => foldl Int.max (varDepth ek) (map varDepth es)
fun closedUpto d =
let
@@ -139,7 +139,7 @@ fun closedUpto d =
| ESignalReturn e => cu inner e
| ESignalBind (e1, e2) => cu inner e1 andalso cu inner e2
| ESignalSource e => cu inner e
- | EServerCall (_, es, ek) => List.all (cu inner) es andalso cu inner ek
+ | EServerCall (_, es, ek, _) => List.all (cu inner) es andalso cu inner ek
in
cu 0
end
@@ -812,7 +812,15 @@ fun process file =
st)
end
- | EServerCall _ => raise Fail "Jscomp EServerCall"
+ | EServerCall (x, es, ek, _) =>
+ let
+ val (ek, st) = jsE inner (ek, st)
+ in
+ (strcat [str ("rc(\"" ^ !Monoize.urlPrefix ^ x ^ "\","),
+ ek,
+ str ")"],
+ st)
+ end
end
in
jsE
diff --git a/src/mono.sml b/src/mono.sml
index 547f8a55..ea2b9720 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -109,7 +109,7 @@ datatype exp' =
| ESignalBind of exp * exp
| ESignalSource of exp
- | EServerCall of int * exp list * exp
+ | EServerCall of string * exp list * exp * typ
withtype exp = exp' located
@@ -117,7 +117,7 @@ datatype decl' =
DDatatype of string * int * (string * int * typ option) list
| DVal of string * int * typ * exp * string
| DValRec of (string * int * typ * exp * string) list
- | DExport of Core.export_kind * string * int * typ list
+ | DExport of Core.export_kind * string * int * typ list * typ
| DTable of string * (string * typ) list
| DSequence of string
diff --git a/src/mono_print.sml b/src/mono_print.sml
index a859a1bd..ba4c57f1 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -308,14 +308,14 @@ fun p_exp' par env (e, _) =
p_exp env e,
string ")"]
- | 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 "]"]
+ | EServerCall (n, es, e, _) => box [string "Server(",
+ string n,
+ string ",",
+ space,
+ p_list (p_exp env) es,
+ string ")[",
+ p_exp env e,
+ string "]"]
and p_exp env = p_exp' false env
@@ -378,19 +378,23 @@ fun p_decl env (dAll as (d, _) : decl) =
p_list_sep (box [newline, string "and", space]) (p_vali env) vis]
end
- | DExport (ek, s, n, ts) => box [string "export",
- space,
- CorePrint.p_export_kind ek,
- space,
- p_enamed env n,
- space,
- string "as",
- space,
- string s,
- p_list_sep (string "") (fn t => box [space,
- string "(",
- p_typ env t,
- string ")"]) ts]
+ | DExport (ek, s, n, ts, t) => box [string "export",
+ space,
+ CorePrint.p_export_kind ek,
+ space,
+ p_enamed env n,
+ space,
+ string "as",
+ space,
+ string s,
+ p_list_sep (string "") (fn t => box [space,
+ string "(",
+ p_typ env t,
+ string ")"]) ts,
+ space,
+ string "->",
+ space,
+ p_typ env t]
| DTable (s, xts) => box [string "(* SQL table ",
string s,
diff --git a/src/mono_reduce.sml b/src/mono_reduce.sml
index 7d39648a..2d0412fd 100644
--- a/src/mono_reduce.sml
+++ b/src/mono_reduce.sml
@@ -346,7 +346,7 @@ fun reduce file =
| ESignalBind (e1, e2) => summarize d e1 @ summarize d e2
| ESignalSource e => summarize d e
- | EServerCall (_, es, ek) => List.concat (map (summarize d) es) @ summarize d ek @ [Unsure]
+ | EServerCall (_, es, ek, _) => List.concat (map (summarize d) es) @ summarize d ek @ [Unsure]
in
(*Print.prefaces "Summarize"
[("e", MonoPrint.p_exp MonoEnv.empty (e, ErrorMsg.dummySpan)),
diff --git a/src/mono_shake.sml b/src/mono_shake.sml
index 34bd98be..4fd3caeb 100644
--- a/src/mono_shake.sml
+++ b/src/mono_shake.sml
@@ -44,7 +44,7 @@ type free = {
fun shake file =
let
val page_es = List.foldl
- (fn ((DExport (_, _, n, _), _), page_es) => n :: page_es
+ (fn ((DExport (_, _, n, _, _), _), page_es) => n :: page_es
| (_, page_es) => page_es) [] file
val (cdef, edef) = foldl (fn ((DDatatype (_, n, xncs), _), (cdef, edef)) =>
diff --git a/src/mono_util.sml b/src/mono_util.sml
index 13e0d32c..d1157218 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -350,12 +350,14 @@ fun mapfoldB {typ = fc, exp = fe, bind} =
fn e' =>
(ESignalSource e', loc))
- | EServerCall (n, es, ek) =>
+ | EServerCall (n, es, ek, t) =>
S.bind2 (ListUtil.mapfold (fn e => mfe ctx e) es,
fn es' =>
- S.map2 (mfe ctx ek,
+ S.bind2 (mfe ctx ek,
fn ek' =>
- (EServerCall (n, es', ek'), loc)))
+ S.map2 (mft t,
+ fn t' =>
+ (EServerCall (n, es', ek', t'), loc))))
in
mfe
end
@@ -443,10 +445,12 @@ fun mapfoldB {typ = fc, exp = fe, decl = fd, bind} =
fn vis' =>
(DValRec vis', loc))
end
- | DExport (ek, s, n, ts) =>
- S.map2 (ListUtil.mapfold mft ts,
+ | DExport (ek, s, n, ts, t) =>
+ S.bind2 (ListUtil.mapfold mft ts,
fn ts' =>
- (DExport (ek, s, n, ts'), loc))
+ S.map2 (mft t,
+ fn t' =>
+ (DExport (ek, s, n, ts', t'), loc)))
| DTable _ => S.return2 dAll
| DSequence _ => S.return2 dAll
| DDatabase _ => S.return2 dAll
diff --git a/src/monoize.sml b/src/monoize.sml
index fb1ac2f1..43c3f47d 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -2225,12 +2225,28 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
((L'.ELet (x, t', e1, e2), loc), fm)
end
- | L.EServerCall (n, es, ek) =>
+ | L.EServerCall (n, es, ek, t) =>
let
+ val t = monoType env t
+ val (_, _, _, name) = Env.lookupENamed env n
val (es, fm) = ListUtil.foldlMap (fn (e, fm) => monoExp (env, st, fm) e) fm es
val (ek, fm) = monoExp (env, st, fm) ek
- in
- ((L'.EServerCall (n, es, ek), loc), fm)
+
+ val ekf = (L'.EAbs ("f",
+ (L'.TFun (t,
+ (L'.TFun ((L'.TRecord [], loc),
+ (L'.TRecord [], loc)), loc)), loc),
+ (L'.TFun (t,
+ (L'.TRecord [], loc)), loc),
+ (L'.EAbs ("x",
+ t,
+ (L'.TRecord [], loc),
+ (L'.EApp ((L'.EApp ((L'.ERel 1, loc),
+ (L'.ERel 0, loc)), loc),
+ (L'.ERecord [], loc)), loc)), loc)), loc)
+ val ek = (L'.EApp (ekf, ek), loc)
+ in
+ ((L'.EServerCall (name, es, ek, t), loc), fm)
end
end
@@ -2280,16 +2296,18 @@ fun monoDecl (env, fm) (all as (d, loc)) =
let
val (_, t, _, s) = Env.lookupENamed env n
- fun unwind (t, _) =
- case t of
- L.TFun (dom, ran) => dom :: unwind ran
+ fun unwind (t, args) =
+ case #1 t of
+ L.TFun (dom, ran) => unwind (ran, dom :: args)
| L.CApp ((L.CFfi ("Basis", "transaction"), _), t) =>
- (L.TRecord (L.CRecord ((L.KType, loc), []), loc), loc) :: unwind t
- | _ => []
+ unwind (t, (L.TRecord (L.CRecord ((L.KType, loc), []), loc), loc) :: args)
+ | _ => (rev args, t)
- val ts = map (monoType env) (unwind t)
+ val (ts, ran) = unwind (t, [])
+ val ts = map (monoType env) ts
+ val ran = monoType env ran
in
- SOME (env, fm, [(L'.DExport (ek, s, n, ts), loc)])
+ SOME (env, fm, [(L'.DExport (ek, s, n, ts, ran), loc)])
end
| L.DTable (x, n, (L.CRecord (_, xts), _), s) =>
let
diff --git a/src/pathcheck.sml b/src/pathcheck.sml
index ed6a4124..036d286f 100644
--- a/src/pathcheck.sml
+++ b/src/pathcheck.sml
@@ -46,7 +46,7 @@ fun checkDecl ((d, loc), (funcs, rels)) =
(funcs, SS.add (rels, s)))
in
case d of
- DExport (_, s, _, _) =>
+ DExport (_, s, _, _, _) =>
(if SS.member (funcs, s) then
E.errorAt loc ("Duplicate function path " ^ s)
else
diff --git a/src/reduce.sml b/src/reduce.sml
index 89fce664..b428c01f 100644
--- a/src/reduce.sml
+++ b/src/reduce.sml
@@ -368,7 +368,7 @@ fun conAndExp (namedC, namedE) =
| 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))
+ | EServerCall (n, es, e, t) => (EServerCall (n, map (exp env) es, exp env e, con env t), loc))
in
{con = con, exp = exp}
end
diff --git a/src/reduce_local.sml b/src/reduce_local.sml
index 55bb5198..7de7d799 100644
--- a/src/reduce_local.sml
+++ b/src/reduce_local.sml
@@ -131,7 +131,7 @@ fun exp env (all as (e, loc)) =
| 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)
+ | EServerCall (n, es, e, t) => (EServerCall (n, map (exp env) es, exp env e, t), loc)
fun reduce file =
let
diff --git a/src/rpcify.sml b/src/rpcify.sml
index 09c44a7a..45d178ee 100644
--- a/src/rpcify.sml
+++ b/src/rpcify.sml
@@ -98,6 +98,29 @@ fun frob file =
val serverSide = sideish (ssBasis, ssids)
val clientSide = sideish (csBasis, csids)
+ val tfuncs = foldl
+ (fn ((d, _), tfuncs) =>
+ let
+ fun doOne ((_, n, t, _, _), tfuncs) =
+ let
+ fun crawl ((t, _), args) =
+ case t of
+ CApp ((CFfi ("Basis", "transaction"), _), ran) => SOME (rev args, ran)
+ | TFun (arg, rest) => crawl (rest, arg :: args)
+ | _ => NONE
+ in
+ case crawl (t, []) of
+ NONE => tfuncs
+ | SOME sg => IM.insert (tfuncs, n, sg)
+ end
+ in
+ case d of
+ DVal vi => doOne (vi, tfuncs)
+ | DValRec vis => foldl doOne tfuncs vis
+ | _ => tfuncs
+ end)
+ IM.empty file
+
fun exp (e, st) =
case e of
EApp (
@@ -130,8 +153,13 @@ fun frob file =
exported = exported,
export_decls = export_decls}
+
+ val ran =
+ case IM.find (tfuncs, n) of
+ NONE => raise Fail "Rpcify: Undetected transaction function"
+ | SOME (_, ran) => ran
in
- (EServerCall (n, args, trans2), st)
+ (EServerCall (n, args, trans2, ran), st)
end
| _ => (e, st))
| _ => (e, st)
diff --git a/src/shake.sml b/src/shake.sml
index 58c1d2c6..4df64efa 100644
--- a/src/shake.sml
+++ b/src/shake.sml
@@ -116,7 +116,7 @@ fun shake file =
in
case e of
ENamed n => check n
- | EServerCall (n, _, _) => check n
+ | EServerCall (n, _, _, _) => check n
| _ => s
end
diff --git a/tests/rpc.ur b/tests/rpc.ur
index 85191229..b2e9722c 100644
--- a/tests/rpc.ur
+++ b/tests/rpc.ur
@@ -8,6 +8,8 @@ fun main () : transaction page =
return
+ set s n}/>
+
+ Current: {[n]}}/>
end
diff --git a/tests/rpc.urp b/tests/rpc.urp
index 16b72b8b..02fd0f2b 100644
--- a/tests/rpc.urp
+++ b/tests/rpc.urp
@@ -1,5 +1,5 @@
debug
sql rpc.sql
-database rpc
+database dbname=rpc
rpc
--
cgit v1.2.3
From 4f0987ddef3dc105c3883aa9c1c69c29fbe86a8a Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sun, 15 Feb 2009 13:03:09 -0500
Subject: Parameterized RPC query
---
src/jscomp.sml | 16 +++++++++++-----
src/mono.sml | 2 +-
src/mono_print.sml | 7 ++-----
src/mono_reduce.sml | 2 +-
src/mono_util.sml | 14 ++++++--------
src/monoize.sml | 22 ++++++++++++++++++++--
tests/rpcN.ur | 16 ++++++++++++++++
tests/rpcN.urp | 5 +++++
8 files changed, 62 insertions(+), 22 deletions(-)
create mode 100644 tests/rpcN.ur
create mode 100644 tests/rpcN.urp
(limited to 'src/mono.sml')
diff --git a/src/jscomp.sml b/src/jscomp.sml
index 9651f930..383a9f6f 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -43,7 +43,10 @@ val funcs = [(("Basis", "alert"), "alert"),
(("Basis", "htmlifyInt"), "ts"),
(("Basis", "htmlifyString"), "eh"),
(("Basis", "new_client_source"), "sc"),
- (("Basis", "set_client_source"), "sv")]
+ (("Basis", "set_client_source"), "sv"),
+ (("Basis", "urlifyInt"), "ts"),
+ (("Basis", "urlifyFloat"), "ts"),
+ (("Basis", "urlifyString"), "escape")]
structure FM = BinaryMapFn(struct
type ord_key = string * string
@@ -98,7 +101,7 @@ fun varDepth (e, _) =
| ESignalReturn e => varDepth e
| ESignalBind (e1, e2) => Int.max (varDepth e1, varDepth e2)
| ESignalSource e => varDepth e
- | EServerCall (_, es, ek, _) => foldl Int.max (varDepth ek) (map varDepth es)
+ | EServerCall (e, ek, _) => Int.max (varDepth e, varDepth ek)
fun closedUpto d =
let
@@ -139,7 +142,7 @@ fun closedUpto d =
| ESignalReturn e => cu inner e
| ESignalBind (e1, e2) => cu inner e1 andalso cu inner e2
| ESignalSource e => cu inner e
- | EServerCall (_, es, ek, _) => List.all (cu inner) es andalso cu inner ek
+ | EServerCall (e, ek, _) => cu inner e andalso cu inner ek
in
cu 0
end
@@ -926,12 +929,15 @@ fun process file =
st)
end
- | EServerCall (x, es, ek, t) =>
+ | EServerCall (e, ek, t) =>
let
+ val (e, st) = jsE inner (e, st)
val (ek, st) = jsE inner (ek, st)
val (unurl, st) = unurlifyExp loc (t, st)
in
- (strcat [str ("rc(\"" ^ !Monoize.urlPrefix ^ x ^ "\", function(s){var t=s.split(\"/\");var i=0;return "
+ (strcat [str ("rc(\"" ^ !Monoize.urlPrefix ^ "\"+"),
+ e,
+ str (", function(s){var t=s.split(\"/\");var i=0;return "
^ unurl ^ "},"),
ek,
str ")"],
diff --git a/src/mono.sml b/src/mono.sml
index ea2b9720..b0be4c5f 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -109,7 +109,7 @@ datatype exp' =
| ESignalBind of exp * exp
| ESignalSource of exp
- | EServerCall of string * exp list * exp * typ
+ | EServerCall of exp * exp * typ
withtype exp = exp' located
diff --git a/src/mono_print.sml b/src/mono_print.sml
index ba4c57f1..a61b5847 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -308,11 +308,8 @@ fun p_exp' par env (e, _) =
p_exp env e,
string ")"]
- | EServerCall (n, es, e, _) => box [string "Server(",
- string n,
- string ",",
- space,
- p_list (p_exp env) es,
+ | EServerCall (n, e, _) => box [string "Server(",
+ p_exp env n,
string ")[",
p_exp env e,
string "]"]
diff --git a/src/mono_reduce.sml b/src/mono_reduce.sml
index 2d0412fd..1f640004 100644
--- a/src/mono_reduce.sml
+++ b/src/mono_reduce.sml
@@ -346,7 +346,7 @@ fun reduce file =
| ESignalBind (e1, e2) => summarize d e1 @ summarize d e2
| ESignalSource e => summarize d e
- | EServerCall (_, es, ek, _) => List.concat (map (summarize d) es) @ summarize d ek @ [Unsure]
+ | EServerCall (e, ek, _) => summarize d e @ summarize d ek @ [Unsure]
in
(*Print.prefaces "Summarize"
[("e", MonoPrint.p_exp MonoEnv.empty (e, ErrorMsg.dummySpan)),
diff --git a/src/mono_util.sml b/src/mono_util.sml
index d1157218..00113c9b 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -350,14 +350,12 @@ fun mapfoldB {typ = fc, exp = fe, bind} =
fn e' =>
(ESignalSource e', loc))
- | EServerCall (n, es, ek, t) =>
- S.bind2 (ListUtil.mapfold (fn e => mfe ctx e) es,
- fn es' =>
- S.bind2 (mfe ctx ek,
- fn ek' =>
- S.map2 (mft t,
- fn t' =>
- (EServerCall (n, es', ek', t'), loc))))
+ | EServerCall (n, ek, t) =>
+ S.bind2 (mfe ctx ek,
+ fn ek' =>
+ S.map2 (mft t,
+ fn t' =>
+ (EServerCall (n, ek', t'), loc)))
in
mfe
end
diff --git a/src/monoize.sml b/src/monoize.sml
index 43c3f47d..4efa2fea 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -2228,8 +2228,26 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
| L.EServerCall (n, es, ek, t) =>
let
val t = monoType env t
- val (_, _, _, name) = Env.lookupENamed env n
+ val (_, ft, _, name) = Env.lookupENamed env n
val (es, fm) = ListUtil.foldlMap (fn (e, fm) => monoExp (env, st, fm) e) fm es
+
+ fun encodeArgs (es, ft, acc, fm) =
+ case (es, ft) of
+ ([], _) => (rev acc, fm)
+ | (e :: es, (L.TFun (dom, ran), _)) =>
+ let
+ val (e, fm) = urlifyExp env fm (e, monoType env dom)
+ in
+ encodeArgs (es, ran, e
+ :: (L'.EPrim (Prim.String "/"), loc)
+ :: acc, fm)
+ end
+ | _ => raise Fail "Monoize: Not enough arguments visible in RPC function type"
+
+ val (call, fm) = encodeArgs (es, ft, [], fm)
+ val call = foldl (fn (e, call) => (L'.EStrcat (call, e), loc))
+ (L'.EPrim (Prim.String name), loc) call
+
val (ek, fm) = monoExp (env, st, fm) ek
val ekf = (L'.EAbs ("f",
@@ -2246,7 +2264,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L'.ERecord [], loc)), loc)), loc)), loc)
val ek = (L'.EApp (ekf, ek), loc)
in
- ((L'.EServerCall (name, es, ek, t), loc), fm)
+ ((L'.EServerCall (call, ek, t), loc), fm)
end
end
diff --git a/tests/rpcN.ur b/tests/rpcN.ur
new file mode 100644
index 00000000..857b5ed0
--- /dev/null
+++ b/tests/rpcN.ur
@@ -0,0 +1,16 @@
+table t : { A : int }
+
+fun main () : transaction page =
+ let
+ fun count a = r <- oneRow (SELECT COUNT( * ) AS N FROM t WHERE t.A = {[a]});
+ return r.N
+ in
+ s <- source 0;
+ return
+
+
+ Current: {[n]}}/>
+
+ end
diff --git a/tests/rpcN.urp b/tests/rpcN.urp
new file mode 100644
index 00000000..6181d8b6
--- /dev/null
+++ b/tests/rpcN.urp
@@ -0,0 +1,5 @@
+debug
+sql rpcN.sql
+database dbname=rpcN
+
+rpcN
--
cgit v1.2.3
From e2f6b11fd4fc806c5cdf88cf669ed5b2d9e34caf Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sun, 22 Mar 2009 16:03:45 -0400
Subject: Proper recv
---
lib/js/urweb.js | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++--
lib/ur/basis.urs | 1 +
src/cjrize.sml | 1 +
src/jscomp.sml | 22 +++++++++++++--
src/mono.sml | 1 +
src/mono_print.sml | 5 ++++
src/mono_reduce.sml | 2 ++
src/mono_util.sml | 8 ++++++
src/monoize.sml | 18 +++++++++++++
src/rpcify.sml | 3 ++-
src/scriptcheck.sml | 4 ++-
tests/channel.ur | 11 +++++++-
12 files changed, 147 insertions(+), 7 deletions(-)
(limited to 'src/mono.sml')
diff --git a/lib/js/urweb.js b/lib/js/urweb.js
index 18842188..6cb5c60a 100644
--- a/lib/js/urweb.js
+++ b/lib/js/urweb.js
@@ -1,6 +1,7 @@
function cons(v, ls) {
return { n : ls, v : v };
}
+
function callAll(ls) {
for (; ls; ls = ls.n)
ls.v();
@@ -192,7 +193,6 @@ function rc(uri, parse, k) {
requestUri(xhr, uri);
}
-
function path_join(s1, s2) {
if (s1.length > 0 && s1[s1.length-1] == '/')
return s1 + s2;
@@ -200,6 +200,37 @@ function path_join(s1, s2) {
return s1 + "/" + s2;
}
+var channels = [];
+
+function newQueue() {
+ return { front : null, back : null };
+}
+function enqueue(q, v) {
+ if (q.front == null) {
+ q.front = cons(v, null);
+ q.back = q.front;
+ } else {
+ var node = cons(v, null);
+ q.back.n = node;
+ q.back = node;
+ }
+}
+function dequeue(q) {
+ if (q.front == null)
+ return null;
+ else {
+ var r = q.front.v;
+ q.front = q.front.n;
+ if (q.front == null)
+ q.back = null;
+ return r;
+ }
+}
+
+function newChannel() {
+ return { msgs : newQueue(), listeners : newQueue() };
+}
+
function listener() {
var uri = path_join(url_prefix, ".msgs");
var xhr = getXHR();
@@ -218,7 +249,26 @@ function listener() {
whine("Empty message from remote server");
for (var i = 0; i+1 < lines.length; i += 2) {
- alert("Message(" + lines[i] + "): " + lines[i+1]);
+ var chn = lines[i];
+ var msg = lines[i+1];
+
+ if (chn < 0)
+ whine("Out-of-bounds channel in message from remote server");
+
+ var ch;
+
+ if (chn >= channels.length || channels[chn] == null) {
+ ch = newChannel();
+ channels[chn] = ch;
+ } else
+ ch = channels[chn];
+
+ var listener = dequeue(ch.listeners);
+ if (listener == null) {
+ enqueue(ch.msgs, msg);
+ } else {
+ listener(msg);
+ }
}
xhr.onreadystatechange = orsc;
@@ -233,3 +283,27 @@ function listener() {
xhr.onreadystatechange = orsc;
requestUri(xhr, uri);
}
+
+function rv(chn, parse, k) {
+ if (chn < 0)
+ whine("Out-of-bounds channel receive");
+
+ var ch;
+
+ if (chn >= channels.length || channels[chn] == null) {
+ ch = newChannel();
+ channels[chn] = ch;
+ } else
+ ch = channels[chn];
+
+ var msg = dequeue(ch.msgs);
+ if (msg == null) {
+ enqueue(ch.listeners, function(msg) { k(parse(msg))(null); });
+ } else {
+ k(parse(msg))(null);
+ }
+}
+
+function unesc(s) {
+ return unescape(s).replace("+", " ");
+}
diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs
index e7172db1..8c28dacb 100644
--- a/lib/ur/basis.urs
+++ b/lib/ur/basis.urs
@@ -460,3 +460,4 @@ con channel :: Type -> Type
val channel : t ::: Type -> transaction (channel t)
val subscribe : t ::: Type -> channel t -> transaction unit
val send : t ::: Type -> channel t -> t -> transaction unit
+val recv : t ::: Type -> channel t -> transaction t
diff --git a/src/cjrize.sml b/src/cjrize.sml
index e637c82c..27287d6e 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -430,6 +430,7 @@ fun cifyExp (eAll as (e, loc), sm) =
| L.ESignalSource _ => raise Fail "Cjrize: ESignalSource remains"
| L.EServerCall _ => raise Fail "Cjrize EServerCall"
+ | L.ERecv _ => raise Fail "Cjrize ERecv"
fun cifyDecl ((d, loc), sm) =
case d of
diff --git a/src/jscomp.sml b/src/jscomp.sml
index be227035..36d42754 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -49,7 +49,8 @@ val funcs = [(("Basis", "alert"), "alert"),
(("Basis", "urlifyInt"), "ts"),
(("Basis", "urlifyFloat"), "ts"),
(("Basis", "urlifyString"), "escape"),
- (("Basis", "urlifyChannel"), "ts")]
+ (("Basis", "urlifyChannel"), "ts"),
+ (("Basis", "recv"), "rv")]
structure FM = BinaryMapFn(struct
type ord_key = string * string
@@ -106,6 +107,7 @@ fun varDepth (e, _) =
| ESignalBind (e1, e2) => Int.max (varDepth e1, varDepth e2)
| ESignalSource e => varDepth e
| EServerCall (e, ek, _) => Int.max (varDepth e, varDepth ek)
+ | ERecv (e, ek, _) => Int.max (varDepth e, varDepth ek)
fun closedUpto d =
let
@@ -147,6 +149,7 @@ fun closedUpto d =
| ESignalBind (e1, e2) => cu inner e1 andalso cu inner e2
| ESignalSource e => cu inner e
| EServerCall (e, ek, _) => cu inner e andalso cu inner ek
+ | ERecv (e, ek, _) => cu inner e andalso cu inner ek
in
cu 0
end
@@ -342,7 +345,7 @@ fun process file =
@ ["}"]), st)
end
- | TFfi ("Basis", "string") => ("unescape(t[i++])", st)
+ | TFfi ("Basis", "string") => ("unesc(t[i++])", st)
| TFfi ("Basis", "int") => ("parseInt(t[i++])", st)
| TFfi ("Basis", "float") => ("parseFloat(t[i++])", st)
@@ -952,6 +955,21 @@ fun process file =
str ")"],
st)
end
+
+ | ERecv (e, ek, t) =>
+ let
+ val (e, st) = jsE inner (e, st)
+ val (ek, st) = jsE inner (ek, st)
+ val (unurl, st) = unurlifyExp loc (t, st)
+ in
+ (strcat [str "rv(",
+ e,
+ str (", function(s){var t=s.split(\"/\");var i=0;return "
+ ^ unurl ^ "},"),
+ ek,
+ str ")"],
+ st)
+ end
end
in
jsE
diff --git a/src/mono.sml b/src/mono.sml
index b0be4c5f..3aa65b6a 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -110,6 +110,7 @@ datatype exp' =
| ESignalSource of exp
| EServerCall of exp * exp * typ
+ | ERecv of exp * exp * typ
withtype exp = exp' located
diff --git a/src/mono_print.sml b/src/mono_print.sml
index a61b5847..cbe90371 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -313,6 +313,11 @@ fun p_exp' par env (e, _) =
string ")[",
p_exp env e,
string "]"]
+ | ERecv (n, e, _) => box [string "Recv(",
+ p_exp env n,
+ string ")[",
+ p_exp env e,
+ string "]"]
and p_exp env = p_exp' false env
diff --git a/src/mono_reduce.sml b/src/mono_reduce.sml
index b789e05f..b2f0ecee 100644
--- a/src/mono_reduce.sml
+++ b/src/mono_reduce.sml
@@ -85,6 +85,7 @@ fun impure (e, _) =
| ESignalBind (e1, e2) => impure e1 orelse impure e2
| ESignalSource e => impure e
| EServerCall _ => true
+ | ERecv _ => true
val liftExpInExp = Monoize.liftExpInExp
@@ -355,6 +356,7 @@ fun reduce file =
| ESignalSource e => summarize d e
| EServerCall (e, ek, _) => summarize d e @ summarize d ek @ [Unsure]
+ | ERecv (e, ek, _) => summarize d e @ summarize d ek @ [Unsure]
in
(*Print.prefaces "Summarize"
[("e", MonoPrint.p_exp MonoEnv.empty (e, ErrorMsg.dummySpan)),
diff --git a/src/mono_util.sml b/src/mono_util.sml
index dd5107c6..bbc9c7e7 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -358,6 +358,14 @@ fun mapfoldB {typ = fc, exp = fe, bind} =
S.map2 (mft t,
fn t' =>
(EServerCall (s', ek', t'), loc))))
+ | ERecv (s, ek, t) =>
+ S.bind2 (mfe ctx s,
+ fn s' =>
+ S.bind2 (mfe ctx ek,
+ fn ek' =>
+ S.map2 (mft t,
+ fn t' =>
+ (ERecv (s', ek', t'), loc))))
in
mfe
end
diff --git a/src/monoize.sml b/src/monoize.sml
index d6b5ae15..87530070 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -979,6 +979,24 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
loc)), loc)), loc)), loc)), loc),
fm)
end
+ | L.EApp ((L.EApp ((L.ECApp ((L.ECApp ((L.ECApp ((L.EFfi ("Basis", "bind"), _), _), _), _), _), t2), _),
+ (L.EFfi ("Basis", "transaction_monad"), _)), _),
+ (L.EApp ((L.ECApp ((L.EFfi ("Basis", "recv"), _), t1), _),
+ ch), loc)) =>
+ let
+ val t1 = monoType env t1
+ val t2 = monoType env t2
+ val un = (L'.TRecord [], loc)
+ val mt2 = (L'.TFun (un, t2), loc)
+ val (ch, fm) = monoExp (env, st, fm) ch
+ in
+ ((L'.EAbs ("m2", (L'.TFun (t1, mt2), loc), (L'.TFun (un, un), loc),
+ (L'.EAbs ("_", un, un,
+ (L'.ERecv (liftExpInExp 0 (liftExpInExp 0 ch),
+ (L'.ERel 1, loc),
+ t1), loc)), loc)), loc),
+ fm)
+ end
| L.ECApp ((L.EFfi ("Basis", "source"), _), t) =>
let
diff --git a/src/rpcify.sml b/src/rpcify.sml
index 1212b81e..a4bfe71a 100644
--- a/src/rpcify.sml
+++ b/src/rpcify.sml
@@ -59,7 +59,8 @@ val csBasis = SS.addList (SS.empty,
["source",
"get",
"set",
- "alert"])
+ "alert",
+ "recv"])
type state = {
cpsed : int IM.map,
diff --git a/src/scriptcheck.sml b/src/scriptcheck.sml
index 2bc185f9..0b51747f 100644
--- a/src/scriptcheck.sml
+++ b/src/scriptcheck.sml
@@ -41,10 +41,12 @@ val csBasis = SS.addList (SS.empty,
"set_client_source",
"new_channel",
"subscribe",
+ "send",
"recv"])
val scriptWords = ["",
+ char *r = uw_malloc(ctx, strlen(ctx->script_header) + 42 + buf_used(&ctx->script));
+ sprintf(r, "%s",
ctx->script_header,
ctx->script.start);
return r;
}
}
+uw_Basis_string uw_Basis_maybe_onload(uw_context ctx, uw_Basis_string s) {
+ if (s[0] == 0)
+ return "";
+ else {
+ char *r = uw_malloc(ctx, 11 + strlen(s));
+ sprintf(r, " onload='%s'", s);
+ return r;
+ }
+}
+
const char *uw_Basis_get_settings(uw_context ctx, uw_unit u) {
if (ctx->client == NULL)
return "";
diff --git a/src/cjrize.sml b/src/cjrize.sml
index 998ae38e..5e4b647a 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -431,6 +431,7 @@ fun cifyExp (eAll as (e, loc), sm) =
| L.EServerCall _ => raise Fail "Cjrize EServerCall"
| L.ERecv _ => raise Fail "Cjrize ERecv"
+ | L.ESleep _ => raise Fail "Cjrize ESleep"
fun cifyDecl ((d, loc), sm) =
case d of
diff --git a/src/jscomp.sml b/src/jscomp.sml
index c7577d0c..9cefc60f 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -110,6 +110,7 @@ fun varDepth (e, _) =
| ESignalSource e => varDepth e
| EServerCall (e, ek, _) => Int.max (varDepth e, varDepth ek)
| ERecv (e, ek, _) => Int.max (varDepth e, varDepth ek)
+ | ESleep (e, ek) => Int.max (varDepth e, varDepth ek)
fun closedUpto d =
let
@@ -152,6 +153,7 @@ fun closedUpto d =
| ESignalSource e => cu inner e
| EServerCall (e, ek, _) => cu inner e andalso cu inner ek
| ERecv (e, ek, _) => cu inner e andalso cu inner ek
+ | ESleep (e, ek) => cu inner e andalso cu inner ek
in
cu 0
end
@@ -973,6 +975,19 @@ fun process file =
str ")"],
st)
end
+
+ | ESleep (e, ek) =>
+ let
+ val (e, st) = jsE inner (e, st)
+ val (ek, st) = jsE inner (ek, st)
+ in
+ (strcat [str "window.setTimeout(",
+ ek,
+ str ", ",
+ e,
+ str ")"],
+ st)
+ end
end
in
jsE
diff --git a/src/mono.sml b/src/mono.sml
index f4bbc868..02afb2c0 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -111,6 +111,7 @@ datatype exp' =
| EServerCall of exp * exp * typ
| ERecv of exp * exp * typ
+ | ESleep of exp * exp
withtype exp = exp' located
diff --git a/src/mono_print.sml b/src/mono_print.sml
index b30fa4e8..a8ece085 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -318,6 +318,11 @@ fun p_exp' par env (e, _) =
string ")[",
p_exp env e,
string "]"]
+ | ESleep (n, e) => box [string "Sleep(",
+ p_exp env n,
+ string ")[",
+ p_exp env e,
+ string "]"]
and p_exp env = p_exp' false env
diff --git a/src/mono_reduce.sml b/src/mono_reduce.sml
index 08d5ad6d..2f60b26e 100644
--- a/src/mono_reduce.sml
+++ b/src/mono_reduce.sml
@@ -88,6 +88,7 @@ fun impure (e, _) =
| ESignalSource e => impure e
| EServerCall _ => true
| ERecv _ => true
+ | ESleep _ => true
val liftExpInExp = Monoize.liftExpInExp
@@ -361,6 +362,7 @@ fun reduce file =
| EServerCall (e, ek, _) => summarize d e @ summarize d ek @ [Unsure]
| ERecv (e, ek, _) => summarize d e @ summarize d ek @ [Unsure]
+ | ESleep (e, ek) => summarize d e @ summarize d ek @ [Unsure]
in
(*Print.prefaces "Summarize"
[("e", MonoPrint.p_exp MonoEnv.empty (e, ErrorMsg.dummySpan)),
diff --git a/src/mono_util.sml b/src/mono_util.sml
index bbc9c7e7..9455435c 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -360,12 +360,18 @@ fun mapfoldB {typ = fc, exp = fe, bind} =
(EServerCall (s', ek', t'), loc))))
| ERecv (s, ek, t) =>
S.bind2 (mfe ctx s,
- fn s' =>
- S.bind2 (mfe ctx ek,
- fn ek' =>
- S.map2 (mft t,
- fn t' =>
- (ERecv (s', ek', t'), loc))))
+ fn s' =>
+ S.bind2 (mfe ctx ek,
+ fn ek' =>
+ S.map2 (mft t,
+ fn t' =>
+ (ERecv (s', ek', t'), loc))))
+ | ESleep (s, ek) =>
+ S.bind2 (mfe ctx s,
+ fn s' =>
+ S.map2 (mfe ctx ek,
+ fn ek' =>
+ (ESleep (s', ek'), loc)))
in
mfe
end
diff --git a/src/monoize.sml b/src/monoize.sml
index ea2ce751..d974e373 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -1002,6 +1002,23 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
t1), loc)), loc)), loc),
fm)
end
+ | L.EApp ((L.EApp ((L.ECApp ((L.ECApp ((L.ECApp ((L.EFfi ("Basis", "bind"), _), _), _), _), _), t2), _),
+ (L.EFfi ("Basis", "transaction_monad"), _)), _),
+ (L.EAbs (_, _, _,
+ (L.EFfiApp ("Basis", "sleep", [n]), _)), loc)) =>
+ let
+ val t2 = monoType env t2
+ val un = (L'.TRecord [], loc)
+ val mt2 = (L'.TFun (un, t2), loc)
+ val (n, fm) = monoExp (env, st, fm) n
+ in
+ ((L'.EAbs ("m2", (L'.TFun (un, mt2), loc), (L'.TFun (un, un), loc),
+ (L'.EAbs ("_", un, un,
+ (L'.ESleep (n, (L'.EApp ((L'.ERel 1, loc),
+ (L'.ERecord [], loc)), loc)),
+ loc)), loc)), loc),
+ fm)
+ end
| L.ECApp ((L.EFfi ("Basis", "source"), _), t) =>
let
@@ -1952,12 +1969,13 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
NONE => tagStart
| SOME extra => (L'.EStrcat (tagStart, extra), loc)
+ val xml = case extraInner of
+ NONE => xml
+ | SOME ei => (L.EFfiApp ("Basis", "strcat", [ei, xml]), loc)
+
fun normal () =
let
val (xml, fm) = monoExp (env, st, fm) xml
- val xml = case extraInner of
- NONE => xml
- | SOME ei => (L'.EStrcat (ei, xml), loc)
in
((L'.EStrcat ((L'.EStrcat (tagStart, (L'.EPrim (Prim.String ">"), loc)), loc),
(L'.EStrcat (xml,
@@ -2012,13 +2030,12 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
end
in
normal ("body",
- SOME (L'.EStrcat ((L'.EPrim (Prim.String " onload='"), loc),
- (L'.EStrcat ((L'.EFfiApp ("Basis", "get_settings",
- [(L'.ERecord [], loc)]), loc),
- (L'.EStrcat (onload,
- (L'.EPrim (Prim.String "'"),
- loc)), loc)), loc)), loc),
- SOME (L'.EFfiApp ("Basis", "get_script", [(L'.ERecord [], loc)]), loc))
+ SOME (L'.EFfiApp ("Basis", "maybe_onload",
+ [(L'.EStrcat ((L'.EFfiApp ("Basis", "get_settings",
+ [(L'.ERecord [], loc)]), loc),
+ onload), loc)]),
+ loc),
+ SOME (L.EFfiApp ("Basis", "get_script", [(L.ERecord [], loc)]), loc))
end
| "dyn" =>
diff --git a/src/scriptcheck.sml b/src/scriptcheck.sml
index 34bf2337..a3928921 100644
--- a/src/scriptcheck.sml
+++ b/src/scriptcheck.sml
@@ -45,8 +45,7 @@ val pushBasis = SS.addList (SS.empty,
"self"])
val scriptWords = [""), loc)), loc)), loc),
fm)
| _ => raise Fail "Monoize: Bad dyn attributes")
@@ -2566,7 +2566,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
end
| SOME (_, src, _) =>
(strcat [str ""],
fm))
| _ => (Print.prefaces "Targs" (map (fn t => ("T", CorePrint.p_con env t)) targs);
@@ -2638,7 +2638,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
| SOME (_, src, _) =>
let
val sc = strcat [str "inp(\"input\",",
- (L'.EJavaScript (L'.Script, src, NONE), loc),
+ (L'.EJavaScript (L'.Script, src), loc),
str ",\"\")"]
val sc = setAttrs sc
in
@@ -2663,9 +2663,9 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
val (xml, fm) = monoExp (env, st, fm) xml
val sc = strcat [str "inp(\"select\",",
- (L'.EJavaScript (L'.Script, src, NONE), loc),
+ (L'.EJavaScript (L'.Script, src), loc),
str ",",
- (L'.EJavaScript (L'.Script, xml, NONE), loc),
+ (L'.EJavaScript (L'.Script, xml), loc),
str ")"]
val sc = setAttrs sc
in
--
cgit v1.2.3
From 9f1c85cf0ef4be94bf189dea486806298f09ab51 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sun, 9 Aug 2009 16:13:27 -0400
Subject: Library improvements; proper list [un]urlification; remove
server-side ServerCalls; eta reduction in type inference
---
lib/js/urweb.js | 18 +++++++++--
lib/ur/monad.ur | 35 +++++++++++++++++++++
lib/ur/monad.urs | 24 +++++++++++++++
lib/ur/top.ur | 12 ++++----
lib/ur/top.urs | 6 ++--
src/cjr_print.sml | 89 +++++++++++++++++++++++++++++++++++++++++++++++------
src/cjrize.sml | 1 +
src/compiler.sml | 9 ++++--
src/elab_ops.sml | 22 +++++++++++++
src/jscomp.sml | 18 ++++++++---
src/mono.sml | 2 +-
src/mono_opt.sig | 2 ++
src/mono_opt.sml | 8 +++++
src/mono_print.sml | 10 +++---
src/mono_reduce.sml | 2 +-
src/mono_util.sml | 8 +++--
src/monoize.sml | 19 ++++++++++--
17 files changed, 243 insertions(+), 42 deletions(-)
(limited to 'src/mono.sml')
diff --git a/lib/js/urweb.js b/lib/js/urweb.js
index 57ad5454..ef2c7b49 100644
--- a/lib/js/urweb.js
+++ b/lib/js/urweb.js
@@ -306,7 +306,7 @@ function dyn(pnode, s) {
var arr = dummy.getElementsByTagName("tbody");
firstChild = null;
- if (arr.length > 0) {
+ if (arr.length > 0 && table != null) {
var tbody = arr[0], next;
firstChild = document.createElement("script");
table.insertBefore(firstChild, x);
@@ -323,7 +323,7 @@ function dyn(pnode, s) {
var arr = dummy.getElementsByTagName("tr");
firstChild = null;
- if (arr.length > 0) {
+ if (arr.length > 0 && table != null) {
var tbody = arr[0], next;
firstChild = document.createElement("script");
table.insertBefore(firstChild, x);
@@ -468,7 +468,19 @@ function uf(s) {
}
function uu(s) {
- return unescape(s);
+ return unescape(s.replace(new RegExp ("\\+", "g"), " "));
+}
+
+function uul(getToken, getData) {
+ var tok = getToken();
+ if (tok == "Nil") {
+ return null;
+ } else if (tok == "Cons") {
+ var d = getData();
+ var l = uul(getToken, getData);
+ return {_1:d, _2:l};
+ } else
+ throw ("Can't unmarshal list (" + tok + ")");
}
diff --git a/lib/ur/monad.ur b/lib/ur/monad.ur
index 73001094..356173fd 100644
--- a/lib/ur/monad.ur
+++ b/lib/ur/monad.ur
@@ -7,3 +7,38 @@ fun exec [m ::: Type -> Type] (_ : monad m) [ts ::: {Type}] r (fd : folder ts) =
(return {}) [ts] fd r
fun ignore [m ::: Type -> Type] (_ : monad m) [t] (v : m t) = x <- v; return ()
+
+fun foldR [K] [m] (_ : monad m) [tf :: K -> Type] [tr :: {K} -> Type]
+ (f : nm :: Name -> t :: K -> rest :: {K}
+ -> [[nm] ~ rest] =>
+ tf t -> tr rest -> m (tr ([nm = t] ++ rest)))
+ (i : tr []) [r :: {K}] (fl : folder r) =
+ Top.fold [fn r :: {K} => $(map tf r) -> m (tr r)]
+ (fn [nm :: Name] [t :: K] [rest :: {K}] [[nm] ~ rest]
+ (acc : _ -> m (tr rest)) r =>
+ acc' <- acc (r -- nm);
+ f [nm] [t] [rest] ! r.nm acc')
+ (fn _ => return i)
+ [_] fl
+
+fun foldR2 [K] [m] (_ : monad m) [tf1 :: K -> Type] [tf2 :: K -> Type] [tr :: {K} -> Type]
+ (f : nm :: Name -> t :: K -> rest :: {K}
+ -> [[nm] ~ rest] =>
+ tf1 t -> tf2 t -> tr rest -> m (tr ([nm = t] ++ rest)))
+ (i : tr []) [r :: {K}] (fl : folder r) =
+ Top.fold [fn r :: {K} => $(map tf1 r) -> $(map tf2 r) -> m (tr r)]
+ (fn [nm :: Name] [t :: K] [rest :: {K}] [[nm] ~ rest]
+ (acc : _ -> _ -> m (tr rest)) r1 r2 =>
+ acc' <- acc (r1 -- nm) (r2 -- nm);
+ f [nm] [t] [rest] ! r1.nm r2.nm acc')
+ (fn _ _ => return i)
+ [_] fl
+
+fun mapR [K] [m] (_ : monad m) [tf :: K -> Type] [tr :: K -> Type]
+ (f : nm :: Name -> t :: K -> tf t -> m (tr t)) =
+ @@foldR [m] _ [tf] [fn r => $(map tr r)]
+ (fn [nm :: Name] [t :: K] [rest :: {K}] [[nm] ~ rest] (v : tf t)
+ (acc : $(map tr rest)) =>
+ v' <- f [nm] [t] v;
+ return (acc ++ {nm = v'}))
+ {}
diff --git a/lib/ur/monad.urs b/lib/ur/monad.urs
index b3cb3d6f..662d780f 100644
--- a/lib/ur/monad.urs
+++ b/lib/ur/monad.urs
@@ -3,3 +3,27 @@ val exec : m ::: (Type -> Type) -> monad m -> ts ::: {Type}
val ignore : m ::: (Type -> Type) -> monad m -> t ::: Type
-> m t -> m unit
+
+val foldR : K --> m ::: (Type -> Type) -> monad m
+ -> tf :: (K -> Type)
+ -> tr :: ({K} -> Type)
+ -> (nm :: Name -> t :: K -> rest :: {K}
+ -> [[nm] ~ rest] =>
+ tf t -> tr rest -> m (tr ([nm = t] ++ rest)))
+ -> tr []
+ -> r :: {K} -> folder r -> $(map tf r) -> m (tr r)
+
+val foldR2 : K --> m ::: (Type -> Type) -> monad m
+ -> tf1 :: (K -> Type) -> tf2 :: (K -> Type)
+ -> tr :: ({K} -> Type)
+ -> (nm :: Name -> t :: K -> rest :: {K}
+ -> [[nm] ~ rest] =>
+ tf1 t -> tf2 t -> tr rest -> m (tr ([nm = t] ++ rest)))
+ -> tr []
+ -> r :: {K} -> folder r -> $(map tf1 r) -> $(map tf2 r) -> m (tr r)
+
+val mapR : K --> m ::: (Type -> Type) -> monad m
+ -> tf :: (K -> Type)
+ -> tr :: (K -> Type)
+ -> (nm :: Name -> t :: K -> tf t -> m (tr t))
+ -> r :: {K} -> folder r -> $(map tf r) -> m ($(map tr r))
diff --git a/lib/ur/top.ur b/lib/ur/top.ur
index 3dac7ff0..ce110b27 100644
--- a/lib/ur/top.ur
+++ b/lib/ur/top.ur
@@ -98,12 +98,12 @@ fun mp [K] [tf1 :: K -> Type] [tf2 :: K -> Type] (f : t ::: K -> tf1 t -> tf2 t)
acc (r -- nm) ++ {nm = f r.nm})
(fn _ => {})
-fun map2 [K1] [K2] [tf1 :: K1 -> Type] [tf2 :: K2 -> Type] [tf :: K1 -> K2]
- (f : t ::: K1 -> tf1 t -> tf2 (tf t)) [r :: {K1}] (fl : folder r) =
- fl [fn r :: {K1} => $(map tf1 r) -> $(map tf2 (map tf r))]
- (fn [nm :: Name] [t :: K1] [rest :: {K1}] [[nm] ~ rest] acc r =>
- acc (r -- nm) ++ {nm = f r.nm})
- (fn _ => {})
+fun map2 [K] [tf1 :: K -> Type] [tf2 :: K -> Type] [tf3 :: K -> Type]
+ (f : t ::: K -> tf1 t -> tf2 t -> tf3 t) [r :: {K}] (fl : folder r) =
+ fl [fn r :: {K} => $(map tf1 r) -> $(map tf2 r) -> $(map tf3 r)]
+ (fn [nm :: Name] [t :: K] [rest :: {K}] [[nm] ~ rest] acc r1 r2 =>
+ acc (r1 -- nm) (r2 -- nm) ++ {nm = f r1.nm r2.nm})
+ (fn _ _ => {})
fun foldUR [tf :: Type] [tr :: {Unit} -> Type]
(f : nm :: Name -> rest :: {Unit}
diff --git a/lib/ur/top.urs b/lib/ur/top.urs
index 33c90651..bdf9d904 100644
--- a/lib/ur/top.urs
+++ b/lib/ur/top.urs
@@ -48,9 +48,9 @@ val txt : t ::: Type -> ctx ::: {Unit} -> use ::: {Type} -> show t -> t
val mp : K --> tf1 :: (K -> Type) -> tf2 :: (K -> Type)
-> (t ::: K -> tf1 t -> tf2 t)
-> r :: {K} -> folder r -> $(map tf1 r) -> $(map tf2 r)
-val map2 : K1 --> K2 --> tf1 :: (K1 -> Type) -> tf2 :: (K2 -> Type) -> tf :: (K1 -> K2)
- -> (t ::: K1 -> tf1 t -> tf2 (tf t))
- -> r :: {K1} -> folder r -> $(map tf1 r) -> $(map tf2 (map tf r))
+val map2 : K --> tf1 :: (K -> Type) -> tf2 :: (K -> Type) -> tf3 :: (K -> Type)
+ -> (t ::: K -> tf1 t -> tf2 t -> tf3 t)
+ -> r :: {K} -> folder r -> $(map tf1 r) -> $(map tf2 r) -> $(map tf3 r)
val foldUR : tf :: Type -> tr :: ({Unit} -> Type)
-> (nm :: Name -> rest :: {Unit}
diff --git a/src/cjr_print.sml b/src/cjr_print.sml
index 83b49719..0fd6339d 100644
--- a/src/cjr_print.sml
+++ b/src/cjr_print.sml
@@ -962,9 +962,11 @@ fun unurlify env (t, loc) =
unurlify' IS.empty t
end
+val urlify1 = ref 0
+
fun urlify env t =
let
- fun urlify' rf level (t as (_, loc)) =
+ fun urlify' rf rfl level (t as (_, loc)) =
case #1 t of
TFfi ("Basis", "unit") => box []
| TFfi (m, t) => box [string ("uw_" ^ ident m ^ "_urlify" ^ capitalize t
@@ -1007,7 +1009,7 @@ fun urlify env t =
newline]
else
[]),
- urlify' rf (level + 1) t,
+ urlify' rf rfl (level + 1) t,
string "}",
newline] :: blocks,
true)
@@ -1079,8 +1081,9 @@ fun urlify env t =
string "it0) {",
newline,
box [string "if (it0) {",
+ newline,
if isUnboxable t then
- urlify' rf 0 t
+ urlify' rf rfl 0 t
else
box [p_typ env t,
space,
@@ -1094,11 +1097,12 @@ fun urlify env t =
string has_arg,
string "/\");",
newline,
- urlify' rf 1 t,
+ urlify' rf rfl 1 t,
string ";",
newline],
string "} else {",
- box [string "uw_write(ctx, \"",
+ box [newline,
+ string "uw_write(ctx, \"",
string no_arg,
string "\");",
newline],
@@ -1165,7 +1169,7 @@ fun urlify env t =
string x',
string ";",
newline,
- urlify' rf 1 t,
+ urlify' rf rfl 1 t,
newline],
string "} else {",
newline,
@@ -1208,7 +1212,7 @@ fun urlify env t =
if isUnboxable t then
box [string "uw_write(ctx, \"Some/\");",
newline,
- urlify' rf level t]
+ urlify' rf rfl level t]
else
box [p_typ env t,
space,
@@ -1223,19 +1227,84 @@ fun urlify env t =
newline,
string "uw_write(ctx, \"Some/\");",
newline,
- urlify' rf (level + 1) t,
+ urlify' rf rfl (level + 1) t,
string ";",
newline],
string "} else {",
- box [string "uw_write(ctx, \"None\");",
+ box [newline,
+ string "uw_write(ctx, \"None\");",
newline],
string "}",
newline]
+ | TList (t, i) =>
+ if IS.member (rfl, i) then
+ box [string "urlifyl_",
+ string (Int.toString i),
+ string "(it",
+ string (Int.toString level),
+ string ");",
+ newline]
+ else
+ let
+ val rfl = IS.add (rfl, i)
+ in
+ box [string "({",
+ space,
+ string "void",
+ space,
+ string "urlifyl_",
+ string (Int.toString i),
+ string "(struct __uws_",
+ string (Int.toString i),
+ space,
+ string "*it0) {",
+ newline,
+ box [string "if (it0) {",
+ newline,
+ p_typ env t,
+ space,
+ string "it1",
+ space,
+ string "=",
+ space,
+ string "it0->__uwf_1;",
+ newline,
+ string "uw_write(ctx, \"Cons/\");",
+ newline,
+ urlify' rf rfl 1 t,
+ string ";",
+ newline,
+ string "uw_write(ctx, \"/\");",
+ newline,
+ string "urlifyl_",
+ string (Int.toString i),
+ string "(it0->__uwf_2);",
+ newline,
+ string "} else {",
+ newline,
+ box [string "uw_write(ctx, \"Nil\");",
+ newline],
+ string "}",
+ newline],
+ string "}",
+ newline,
+ newline,
+
+ string "urlifyl_",
+ string (Int.toString i),
+ string "(it",
+ string (Int.toString level),
+ string ");",
+ newline,
+ string "});",
+ newline]
+ end
+
| _ => (ErrorMsg.errorAt loc "Unable to choose a URL encoding function";
space)
in
- urlify' IS.empty 0 t
+ urlify' IS.empty IS.empty 0 t
end
fun sql_type_in env (tAll as (t, loc)) =
diff --git a/src/cjrize.sml b/src/cjrize.sml
index 5f3ea5a8..6a79b4e6 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -112,6 +112,7 @@ fun cifyTyp x =
end
| L.TRecord xts =>
let
+ val xts = ListMergeSort.sort (fn ((x, _), (y, _)) => String.compare (x, y) = GREATER) xts
val old_xts = xts
val (xts, sm) = ListUtil.foldlMap (fn ((x, t), sm) =>
let
diff --git a/src/compiler.sml b/src/compiler.sml
index c99c0eeb..13bb77f9 100644
--- a/src/compiler.sml
+++ b/src/compiler.sml
@@ -805,7 +805,7 @@ val monoize = {
val toMonoize = transform monoize "monoize" o toEffectize
val mono_opt = {
- func = MonoOpt.optimize,
+ func = (fn x => (MonoOpt.removeServerCalls := false; MonoOpt.optimize x)),
print = MonoPrint.p_file MonoEnv.empty
}
@@ -841,7 +841,12 @@ val jscomp = {
val toJscomp = transform jscomp "jscomp" o toMono_opt2
-val toMono_opt3 = transform mono_opt "mono_opt3" o toJscomp
+val mono_opt' = {
+ func = (fn x => (MonoOpt.removeServerCalls := true; MonoOpt.optimize x)),
+ print = MonoPrint.p_file MonoEnv.empty
+}
+
+val toMono_opt3 = transform mono_opt' "mono_opt3" o toJscomp
val fuse = {
func = Fuse.fuse,
diff --git a/src/elab_ops.sml b/src/elab_ops.sml
index a26ba17d..b5292e9b 100644
--- a/src/elab_ops.sml
+++ b/src/elab_ops.sml
@@ -131,6 +131,18 @@ fun subStrInSgn (m1, m2) =
sgn_item = fn sgi => sgi,
sgn = fn sgn => sgn}
+val occurs =
+ U.Con.existsB {kind = fn _ => false,
+ con = fn (n, c) =>
+ case c of
+ CRel n' => n' = n
+ | _ => false,
+ bind = fn (n, b) =>
+ case b of
+ U.Con.RelC _ => n + 1
+ | _ => n}
+ 0
+
fun hnormCon env (cAll as (c, loc)) =
case c of
@@ -156,6 +168,16 @@ fun hnormCon env (cAll as (c, loc)) =
| SOME (_, SOME c) => hnormCon env c
end
+ (* Eta reduction *)
+ | CAbs (x, k, b) =>
+ (case #1 (hnormCon (E.pushCRel env x k) b) of
+ CApp (f, (CRel 0, _)) =>
+ if occurs f then
+ cAll
+ else
+ hnormCon env (subConInCon (0, (CUnit, loc)) f)
+ | _ => cAll)
+
| CApp (c1, c2) =>
(case #1 (hnormCon env c1) of
CAbs (x, k, cb) =>
diff --git a/src/jscomp.sml b/src/jscomp.sml
index 63f3d883..d42c659e 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -86,7 +86,7 @@ fun varDepth (e, _) =
| ESignalReturn e => varDepth e
| ESignalBind (e1, e2) => Int.max (varDepth e1, varDepth e2)
| ESignalSource e => varDepth e
- | EServerCall (e, ek, _, _) => Int.max (varDepth e, varDepth ek)
+ | EServerCall (e, ek, _, _, _) => Int.max (varDepth e, varDepth ek)
| ERecv (e, ek, _) => Int.max (varDepth e, varDepth ek)
| ESleep (e, ek) => Int.max (varDepth e, varDepth ek)
@@ -130,7 +130,7 @@ fun closedUpto d =
| ESignalReturn e => cu inner e
| ESignalBind (e1, e2) => cu inner e1 andalso cu inner e2
| ESignalSource e => cu inner e
- | EServerCall (e, ek, _, _) => cu inner e andalso cu inner ek
+ | EServerCall (e, ek, _, _, _) => cu inner e andalso cu inner ek
| ERecv (e, ek, _) => cu inner e andalso cu inner ek
| ESleep (e, ek) => cu inner e andalso cu inner ek
in
@@ -434,6 +434,13 @@ fun process file =
("(t[i++]==\"Some\"?" ^ e ^ ":null)", st)
end
+ | TList t =>
+ let
+ val (e, st) = unurlifyExp loc (t, st)
+ in
+ ("uul(function(){return t[i++];},function(){return " ^ e ^ "})", st)
+ end
+
| TDatatype (n, ref (dk, cs)) =>
(case IM.find (#decoders st, n) of
SOME n' => ("(tmp=_n" ^ Int.toString n' ^ "(t,i),i=tmp._1,tmp._2)", st)
@@ -1034,7 +1041,7 @@ fun process file =
st)
end
- | EServerCall (e, ek, t, eff) =>
+ | EServerCall (e, ek, t, eff, _) =>
let
val (e, st) = jsE inner (e, st)
val (ek, st) = jsE inner (ek, st)
@@ -1313,12 +1320,13 @@ fun process file =
((ESignalSource e, loc), st)
end
- | EServerCall (e1, e2, t, ef) =>
+ | EServerCall (e1, e2, t, ef, ue) =>
let
val (e1, st) = exp outer (e1, st)
val (e2, st) = exp outer (e2, st)
+ val (ue, st) = exp outer (ue, st)
in
- ((EServerCall (e1, e2, t, ef), loc), st)
+ ((EServerCall (e1, e2, t, ef, ue), loc), st)
end
| ERecv (e1, e2, t) =>
let
diff --git a/src/mono.sml b/src/mono.sml
index 64ed448c..2d29af48 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -114,7 +114,7 @@ datatype exp' =
| ESignalBind of exp * exp
| ESignalSource of exp
- | EServerCall of exp * exp * typ * effect
+ | EServerCall of exp * exp * typ * effect * exp
| ERecv of exp * exp * typ
| ESleep of exp * exp
diff --git a/src/mono_opt.sig b/src/mono_opt.sig
index d0268087..7368f684 100644
--- a/src/mono_opt.sig
+++ b/src/mono_opt.sig
@@ -30,4 +30,6 @@ signature MONO_OPT = sig
val optimize : Mono.file -> Mono.file
val optExp : Mono.exp -> Mono.exp
+ val removeServerCalls : bool ref
+
end
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index bf39b311..7bfce88b 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -30,6 +30,8 @@ structure MonoOpt :> MONO_OPT = struct
open Mono
structure U = MonoUtil
+val removeServerCalls = ref false
+
fun typ t = t
fun decl d = d
@@ -480,6 +482,12 @@ fun exp e =
| [] => raise Fail "MonoOpt impossible nil")
| NONE => e
end
+
+ | EServerCall (_, _, _, _, ue) =>
+ if !removeServerCalls then
+ optExp ue
+ else
+ e
| _ => e
diff --git a/src/mono_print.sml b/src/mono_print.sml
index 71bc734a..ed63b2a0 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -335,11 +335,11 @@ fun p_exp' par env (e, _) =
p_exp env e,
string ")"]
- | EServerCall (n, e, _, _) => box [string "Server(",
- p_exp env n,
- string ")[",
- p_exp env e,
- string "]"]
+ | EServerCall (n, e, _, _, _) => box [string "Server(",
+ p_exp env n,
+ string ")[",
+ p_exp env e,
+ string "]"]
| ERecv (n, e, _) => box [string "Recv(",
p_exp env n,
string ")[",
diff --git a/src/mono_reduce.sml b/src/mono_reduce.sml
index 4bbb430d..62368f9b 100644
--- a/src/mono_reduce.sml
+++ b/src/mono_reduce.sml
@@ -354,7 +354,7 @@ fun reduce file =
| ESignalBind (e1, e2) => summarize d e1 @ summarize d e2
| ESignalSource e => summarize d e
- | EServerCall (e, ek, _, _) => summarize d e @ summarize d ek @ [Unsure]
+ | EServerCall (e, ek, _, _, _) => summarize d e @ summarize d ek @ [Unsure]
| ERecv (e, ek, _) => summarize d e @ summarize d ek @ [Unsure]
| ESleep (e, ek) => summarize d e @ summarize d ek @ [Unsure]
in
diff --git a/src/mono_util.sml b/src/mono_util.sml
index e2bed8eb..0a4bb048 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -362,14 +362,16 @@ fun mapfoldB {typ = fc, exp = fe, bind} =
fn e' =>
(ESignalSource e', loc))
- | EServerCall (s, ek, t, eff) =>
+ | EServerCall (s, ek, t, eff, ue) =>
S.bind2 (mfe ctx s,
fn s' =>
S.bind2 (mfe ctx ek,
fn ek' =>
- S.map2 (mft t,
+ S.bind2 (mft t,
fn t' =>
- (EServerCall (s', ek', t', eff), loc))))
+ S.map2 (mfe ctx ue,
+ fn ue' =>
+ (EServerCall (s', ek', t', eff, ue'), loc)))))
| ERecv (s, ek, t) =>
S.bind2 (mfe ctx s,
fn s' =>
diff --git a/src/monoize.sml b/src/monoize.sml
index d774c697..c0351756 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -93,7 +93,12 @@ fun monoType env =
L.TFun (c1, c2) => (L'.TFun (mt env dtmap c1, mt env dtmap c2), loc)
| L.TCFun _ => poly ()
| L.TRecord (L.CRecord ((L.KType, _), xcs), _) =>
- (L'.TRecord (map (fn (x, t) => (monoName env x, mt env dtmap t)) xcs), loc)
+ let
+ val xcs = map (fn (x, t) => (monoName env x, mt env dtmap t)) xcs
+ val xcs = ListMergeSort.sort (fn ((x, _), (y, _)) => String.compare (x, y) = GREATER) xcs
+ in
+ (L'.TRecord xcs, loc)
+ end
| L.TRecord _ => poly ()
| L.CApp ((L.CFfi ("Basis", "option"), _), t) =>
@@ -3076,6 +3081,8 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
e,
monoType env t), fm)
end) fm xes
+
+ val xes = ListMergeSort.sort (fn ((x, _, _), (y, _, _)) => String.compare (x, y) = GREATER) xes
in
((L'.ERecord xes, loc), fm)
end
@@ -3154,6 +3161,12 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
val (ek, fm) = monoExp (env, st, fm) ek
+ val unRpced = foldl (fn (e1, e2) => (L'.EApp (e2, e1), loc)) (L'.ENamed n, loc) es
+ val unRpced = (L'.EApp (unRpced, (L'.ERecord [], loc)), loc)
+ val unRpced = (L'.EApp (ek, unRpced), loc)
+ val unRpced = (L'.EApp (unRpced, (L'.ERecord [], loc)), loc)
+ val unit = (L'.TRecord [], loc)
+
val ekf = (L'.EAbs ("f",
(L'.TFun (t,
(L'.TFun ((L'.TRecord [], loc),
@@ -3171,9 +3184,9 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
L'.ReadCookieWrite
else
L'.ReadOnly
- val e = (L'.EServerCall (call, ek, t, eff), loc)
+
+ val e = (L'.EServerCall (call, ek, t, eff, unRpced), loc)
val e = liftExpInExp 0 e
- val unit = (L'.TRecord [], loc)
val e = (L'.EAbs ("_", unit, unit, e), loc)
in
(e, fm)
--
cgit v1.2.3
From 7c866487f8ab0dd9b9c73bee013c18805a0c4489 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Tue, 25 Aug 2009 13:57:56 -0400
Subject: grid1 compiles but gets stuck in JS
---
lib/ur/monad.ur | 13 +++
lib/ur/monad.urs | 9 ++
lib/ur/top.ur | 21 ++++
lib/ur/top.urs | 15 +++
src/c/urweb.c | 2 +-
src/compiler.sml | 9 +-
src/core_print.sml | 1 +
src/jscomp.sml | 30 ++++--
src/mono.sml | 2 +-
src/mono_opt.sig | 4 +-
src/mono_opt.sml | 8 --
src/mono_print.sml | 10 +-
src/mono_reduce.sml | 2 +-
src/mono_util.sml | 8 +-
src/monoize.sml | 6 +-
src/reduce.sml | 286 ++++++++++++++++++++++++++++++++++++++--------------
src/urweb.grm | 7 ++
17 files changed, 315 insertions(+), 118 deletions(-)
(limited to 'src/mono.sml')
diff --git a/lib/ur/monad.ur b/lib/ur/monad.ur
index 356173fd..d6690839 100644
--- a/lib/ur/monad.ur
+++ b/lib/ur/monad.ur
@@ -34,6 +34,19 @@ fun foldR2 [K] [m] (_ : monad m) [tf1 :: K -> Type] [tf2 :: K -> Type] [tr :: {K
(fn _ _ => return i)
[_] fl
+fun foldR3 [K] [m] (_ : monad m) [tf1 :: K -> Type] [tf2 :: K -> Type] [tf3 :: K -> Type] [tr :: {K} -> Type]
+ (f : nm :: Name -> t :: K -> rest :: {K}
+ -> [[nm] ~ rest] =>
+ tf1 t -> tf2 t -> tf3 t -> tr rest -> m (tr ([nm = t] ++ rest)))
+ (i : tr []) [r :: {K}] (fl : folder r) =
+ Top.fold [fn r :: {K} => $(map tf1 r) -> $(map tf2 r) -> $(map tf3 r) -> m (tr r)]
+ (fn [nm :: Name] [t :: K] [rest :: {K}] [[nm] ~ rest]
+ (acc : _ -> _ -> _ -> m (tr rest)) r1 r2 r3 =>
+ acc' <- acc (r1 -- nm) (r2 -- nm) (r3 -- nm);
+ f [nm] [t] [rest] ! r1.nm r2.nm r3.nm acc')
+ (fn _ _ _ => return i)
+ [_] fl
+
fun mapR [K] [m] (_ : monad m) [tf :: K -> Type] [tr :: K -> Type]
(f : nm :: Name -> t :: K -> tf t -> m (tr t)) =
@@foldR [m] _ [tf] [fn r => $(map tr r)]
diff --git a/lib/ur/monad.urs b/lib/ur/monad.urs
index 662d780f..f64e2362 100644
--- a/lib/ur/monad.urs
+++ b/lib/ur/monad.urs
@@ -22,6 +22,15 @@ val foldR2 : K --> m ::: (Type -> Type) -> monad m
-> tr []
-> r :: {K} -> folder r -> $(map tf1 r) -> $(map tf2 r) -> m (tr r)
+val foldR3 : K --> m ::: (Type -> Type) -> monad m
+ -> tf1 :: (K -> Type) -> tf2 :: (K -> Type) -> tf3 :: (K -> Type)
+ -> tr :: ({K} -> Type)
+ -> (nm :: Name -> t :: K -> rest :: {K}
+ -> [[nm] ~ rest] =>
+ tf1 t -> tf2 t -> tf3 t -> tr rest -> m (tr ([nm = t] ++ rest)))
+ -> tr []
+ -> r :: {K} -> folder r -> $(map tf1 r) -> $(map tf2 r) -> $(map tf3 r) -> m (tr r)
+
val mapR : K --> m ::: (Type -> Type) -> monad m
-> tf :: (K -> Type)
-> tr :: (K -> Type)
diff --git a/lib/ur/top.ur b/lib/ur/top.ur
index ce110b27..7073884f 100644
--- a/lib/ur/top.ur
+++ b/lib/ur/top.ur
@@ -155,6 +155,17 @@ fun foldR2 [K] [tf1 :: K -> Type] [tf2 :: K -> Type] [tr :: {K} -> Type]
f [nm] [t] [rest] ! r1.nm r2.nm (acc (r1 -- nm) (r2 -- nm)))
(fn _ _ => i)
+fun foldR3 [K] [tf1 :: K -> Type] [tf2 :: K -> Type] [tf3 :: K -> Type] [tr :: {K} -> Type]
+ (f : nm :: Name -> t :: K -> rest :: {K}
+ -> [[nm] ~ rest] =>
+ tf1 t -> tf2 t -> tf3 t -> tr rest -> tr ([nm = t] ++ rest))
+ (i : tr []) [r :: {K}] (fl : folder r) =
+ fl [fn r :: {K} => $(map tf1 r) -> $(map tf2 r) -> $(map tf3 r) -> tr r]
+ (fn [nm :: Name] [t :: K] [rest :: {K}] [[nm] ~ rest]
+ (acc : _ -> _ -> _ -> tr rest) r1 r2 r3 =>
+ f [nm] [t] [rest] ! r1.nm r2.nm r3.nm (acc (r1 -- nm) (r2 -- nm) (r3 -- nm)))
+ (fn _ _ _ => i)
+
fun foldRX [K] [tf :: K -> Type] [ctx :: {Unit}]
(f : nm :: Name -> t :: K -> rest :: {K}
-> [[nm] ~ rest] =>
@@ -174,6 +185,16 @@ fun foldRX2 [K] [tf1 :: K -> Type] [tf2 :: K -> Type] [ctx :: {Unit}]
{f [nm] [t] [rest] ! r1 r2}{acc})
+fun foldRX3 [K] [tf1 :: K -> Type] [tf2 :: K -> Type] [tf3 :: K -> Type] [ctx :: {Unit}]
+ (f : nm :: Name -> t :: K -> rest :: {K}
+ -> [[nm] ~ rest] =>
+ tf1 t -> tf2 t -> tf3 t -> xml ctx [] []) =
+ foldR3 [tf1] [tf2] [tf3] [fn _ => xml ctx [] []]
+ (fn [nm :: Name] [t :: K] [rest :: {K}] [[nm] ~ rest]
+ r1 r2 r3 acc =>
+ {f [nm] [t] [rest] ! r1 r2 r3}{acc})
+
+
fun queryI [tables ::: {{Type}}] [exps ::: {Type}]
[tables ~ exps] (q : sql_query tables exps)
(f : $(exps ++ map (fn fields :: {Type} => $fields) tables)
diff --git a/lib/ur/top.urs b/lib/ur/top.urs
index bdf9d904..a19961f4 100644
--- a/lib/ur/top.urs
+++ b/lib/ur/top.urs
@@ -84,6 +84,14 @@ val foldR2 : K --> tf1 :: (K -> Type) -> tf2 :: (K -> Type)
-> tr []
-> r :: {K} -> folder r -> $(map tf1 r) -> $(map tf2 r) -> tr r
+val foldR3 : K --> tf1 :: (K -> Type) -> tf2 :: (K -> Type) -> tf3 :: (K -> Type)
+ -> tr :: ({K} -> Type)
+ -> (nm :: Name -> t :: K -> rest :: {K}
+ -> [[nm] ~ rest] =>
+ tf1 t -> tf2 t -> tf3 t -> tr rest -> tr ([nm = t] ++ rest))
+ -> tr []
+ -> r :: {K} -> folder r -> $(map tf1 r) -> $(map tf2 r) -> $(map tf3 r) -> tr r
+
val foldRX : K --> tf :: (K -> Type) -> ctx :: {Unit}
-> (nm :: Name -> t :: K -> rest :: {K}
-> [[nm] ~ rest] =>
@@ -97,6 +105,13 @@ val foldRX2 : K --> tf1 :: (K -> Type) -> tf2 :: (K -> Type) -> ctx :: {Unit}
-> r :: {K} -> folder r
-> $(map tf1 r) -> $(map tf2 r) -> xml ctx [] []
+val foldRX3 : K --> tf1 :: (K -> Type) -> tf2 :: (K -> Type) -> tf3 :: (K -> Type) -> ctx :: {Unit}
+ -> (nm :: Name -> t :: K -> rest :: {K}
+ -> [[nm] ~ rest] =>
+ tf1 t -> tf2 t -> tf3 t -> xml ctx [] [])
+ -> r :: {K} -> folder r
+ -> $(map tf1 r) -> $(map tf2 r) -> $(map tf3 r) -> xml ctx [] []
+
val queryI : tables ::: {{Type}} -> exps ::: {Type}
-> [tables ~ exps] =>
sql_query tables exps
diff --git a/src/c/urweb.c b/src/c/urweb.c
index 572d1658..068282f2 100644
--- a/src/c/urweb.c
+++ b/src/c/urweb.c
@@ -1235,7 +1235,7 @@ uw_Basis_string uw_Basis_jsifyString(uw_context ctx, uw_Basis_string s) {
}
strcpy(s2, "\"");
- ctx->heap.front = s2 + 1;
+ ctx->heap.front = s2 + 2;
return r;
}
diff --git a/src/compiler.sml b/src/compiler.sml
index 13bb77f9..c99c0eeb 100644
--- a/src/compiler.sml
+++ b/src/compiler.sml
@@ -805,7 +805,7 @@ val monoize = {
val toMonoize = transform monoize "monoize" o toEffectize
val mono_opt = {
- func = (fn x => (MonoOpt.removeServerCalls := false; MonoOpt.optimize x)),
+ func = MonoOpt.optimize,
print = MonoPrint.p_file MonoEnv.empty
}
@@ -841,12 +841,7 @@ val jscomp = {
val toJscomp = transform jscomp "jscomp" o toMono_opt2
-val mono_opt' = {
- func = (fn x => (MonoOpt.removeServerCalls := true; MonoOpt.optimize x)),
- print = MonoPrint.p_file MonoEnv.empty
-}
-
-val toMono_opt3 = transform mono_opt' "mono_opt3" o toJscomp
+val toMono_opt3 = transform mono_opt "mono_opt3" o toJscomp
val fuse = {
func = Fuse.fuse,
diff --git a/src/core_print.sml b/src/core_print.sml
index 5daf7137..84b247a2 100644
--- a/src/core_print.sml
+++ b/src/core_print.sml
@@ -427,6 +427,7 @@ fun p_exp' par env (e, _) =
string x,
space,
string ":",
+ space,
p_con env t,
space,
string "=",
diff --git a/src/jscomp.sml b/src/jscomp.sml
index f2a48cf3..7a6c3094 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -86,7 +86,7 @@ fun varDepth (e, _) =
| ESignalReturn e => varDepth e
| ESignalBind (e1, e2) => Int.max (varDepth e1, varDepth e2)
| ESignalSource e => varDepth e
- | EServerCall (e, ek, _, _, _) => Int.max (varDepth e, varDepth ek)
+ | EServerCall (e, ek, _, _) => Int.max (varDepth e, varDepth ek)
| ERecv (e, ek, _) => Int.max (varDepth e, varDepth ek)
| ESleep (e, ek) => Int.max (varDepth e, varDepth ek)
@@ -130,7 +130,7 @@ fun closedUpto d =
| ESignalReturn e => cu inner e
| ESignalBind (e1, e2) => cu inner e1 andalso cu inner e2
| ESignalSource e => cu inner e
- | EServerCall (e, ek, _, _, _) => cu inner e andalso cu inner ek
+ | EServerCall (e, ek, _, _) => cu inner e andalso cu inner ek
| ERecv (e, ek, _) => cu inner e andalso cu inner ek
| ESleep (e, ek) => cu inner e andalso cu inner ek
in
@@ -389,6 +389,7 @@ fun process file =
fun unurlifyExp loc (t : typ, st) =
case #1 t of
TRecord [] => ("null", st)
+ | TFfi ("Basis", "unit") => ("null", st)
| TRecord [(x, t)] =>
let
val (e, st) = unurlifyExp loc (t, st)
@@ -524,6 +525,7 @@ fun process file =
fun unsupported s =
(EM.errorAt loc (s ^ " in code to be compiled to JavaScript[2]");
+ Print.preface ("Code", MonoPrint.p_exp MonoEnv.empty e);
(str "ERROR", st))
val strcat = strcat loc
@@ -669,7 +671,24 @@ fun process file =
raise Fail "Jscomp: deStrcat")
val quoteExp = quoteExp loc
+
+ val hasQuery = U.Exp.exists {typ = fn _ => false,
+ exp = fn EQuery _ => true
+ | _ => false}
+
+ val indirectQuery = U.Exp.exists {typ = fn _ => false,
+ exp = fn ENamed n =>
+ (case IM.find (nameds, n) of
+ NONE => false
+ | SOME e => hasQuery e)
+ | _ => false}
+
in
+ (*if indirectQuery e then
+ Print.preface ("Indirect", MonoPrint.p_exp MonoEnv.empty e)
+ else
+ ();*)
+
(*Print.prefaces "jsE" [("e", MonoPrint.p_exp MonoEnv.empty e),
("inner", Print.PD.string (Int.toString inner))];*)
@@ -1041,7 +1060,7 @@ fun process file =
st)
end
- | EServerCall (e, ek, t, eff, _) =>
+ | EServerCall (e, ek, t, eff) =>
let
val (e, st) = jsE inner (e, st)
val (ek, st) = jsE inner (ek, st)
@@ -1320,13 +1339,12 @@ fun process file =
((ESignalSource e, loc), st)
end
- | EServerCall (e1, e2, t, ef, ue) =>
+ | EServerCall (e1, e2, t, ef) =>
let
val (e1, st) = exp outer (e1, st)
val (e2, st) = exp outer (e2, st)
- val (ue, st) = exp outer (ue, st)
in
- ((EServerCall (e1, e2, t, ef, ue), loc), st)
+ ((EServerCall (e1, e2, t, ef), loc), st)
end
| ERecv (e1, e2, t) =>
let
diff --git a/src/mono.sml b/src/mono.sml
index 2d29af48..64ed448c 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -114,7 +114,7 @@ datatype exp' =
| ESignalBind of exp * exp
| ESignalSource of exp
- | EServerCall of exp * exp * typ * effect * exp
+ | EServerCall of exp * exp * typ * effect
| ERecv of exp * exp * typ
| ESleep of exp * exp
diff --git a/src/mono_opt.sig b/src/mono_opt.sig
index 7368f684..1d0fec5c 100644
--- a/src/mono_opt.sig
+++ b/src/mono_opt.sig
@@ -29,7 +29,5 @@ signature MONO_OPT = sig
val optimize : Mono.file -> Mono.file
val optExp : Mono.exp -> Mono.exp
-
- val removeServerCalls : bool ref
-
+
end
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index 7bfce88b..bf39b311 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -30,8 +30,6 @@ structure MonoOpt :> MONO_OPT = struct
open Mono
structure U = MonoUtil
-val removeServerCalls = ref false
-
fun typ t = t
fun decl d = d
@@ -482,12 +480,6 @@ fun exp e =
| [] => raise Fail "MonoOpt impossible nil")
| NONE => e
end
-
- | EServerCall (_, _, _, _, ue) =>
- if !removeServerCalls then
- optExp ue
- else
- e
| _ => e
diff --git a/src/mono_print.sml b/src/mono_print.sml
index ed63b2a0..71bc734a 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -335,11 +335,11 @@ fun p_exp' par env (e, _) =
p_exp env e,
string ")"]
- | EServerCall (n, e, _, _, _) => box [string "Server(",
- p_exp env n,
- string ")[",
- p_exp env e,
- string "]"]
+ | EServerCall (n, e, _, _) => box [string "Server(",
+ p_exp env n,
+ string ")[",
+ p_exp env e,
+ string "]"]
| ERecv (n, e, _) => box [string "Recv(",
p_exp env n,
string ")[",
diff --git a/src/mono_reduce.sml b/src/mono_reduce.sml
index 62368f9b..4bbb430d 100644
--- a/src/mono_reduce.sml
+++ b/src/mono_reduce.sml
@@ -354,7 +354,7 @@ fun reduce file =
| ESignalBind (e1, e2) => summarize d e1 @ summarize d e2
| ESignalSource e => summarize d e
- | EServerCall (e, ek, _, _, _) => summarize d e @ summarize d ek @ [Unsure]
+ | EServerCall (e, ek, _, _) => summarize d e @ summarize d ek @ [Unsure]
| ERecv (e, ek, _) => summarize d e @ summarize d ek @ [Unsure]
| ESleep (e, ek) => summarize d e @ summarize d ek @ [Unsure]
in
diff --git a/src/mono_util.sml b/src/mono_util.sml
index 0a4bb048..e2bed8eb 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -362,16 +362,14 @@ fun mapfoldB {typ = fc, exp = fe, bind} =
fn e' =>
(ESignalSource e', loc))
- | EServerCall (s, ek, t, eff, ue) =>
+ | EServerCall (s, ek, t, eff) =>
S.bind2 (mfe ctx s,
fn s' =>
S.bind2 (mfe ctx ek,
fn ek' =>
- S.bind2 (mft t,
+ S.map2 (mft t,
fn t' =>
- S.map2 (mfe ctx ue,
- fn ue' =>
- (EServerCall (s', ek', t', eff, ue'), loc)))))
+ (EServerCall (s', ek', t', eff), loc))))
| ERecv (s, ek, t) =>
S.bind2 (mfe ctx s,
fn s' =>
diff --git a/src/monoize.sml b/src/monoize.sml
index a5772976..12112648 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -3162,10 +3162,6 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
val (ek, fm) = monoExp (env, st, fm) ek
- val unRpced = foldl (fn (e1, e2) => (L'.EApp (e2, e1), loc)) (L'.ENamed n, loc) es
- val unRpced = (L'.EApp (unRpced, (L'.ERecord [], loc)), loc)
- val unRpced = (L'.EApp (ek, unRpced), loc)
- val unRpced = (L'.EApp (unRpced, (L'.ERecord [], loc)), loc)
val unit = (L'.TRecord [], loc)
val ekf = (L'.EAbs ("f",
@@ -3186,7 +3182,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
else
L'.ReadOnly
- val e = (L'.EServerCall (call, ek, t, eff, unRpced), loc)
+ val e = (L'.EServerCall (call, ek, t, eff), loc)
val e = liftExpInExp 0 e
val e = (L'.EAbs ("_", unit, unit, e), loc)
in
diff --git a/src/reduce.sml b/src/reduce.sml
index 82d37420..373d4cec 100644
--- a/src/reduce.sml
+++ b/src/reduce.sml
@@ -254,12 +254,12 @@ fun kindConAndExp (namedC, namedE) =
let
(*val () = Print.prefaces "exp" [("e", CorePrint.p_exp CoreEnv.empty all),
("env", Print.PD.string (e2s env))]*)
- (*val () = if dangling (edepth env) all then
+ val () = if dangling (edepth env) all then
(Print.prefaces "exp" [("e", CorePrint.p_exp CoreEnv.empty all),
("env", Print.PD.string (e2s env))];
raise Fail "!")
else
- ()*)
+ ()
val r = case e of
EPrim _ => all
@@ -299,17 +299,6 @@ fun kindConAndExp (namedC, namedE) =
| EFfi _ => all
| EFfiApp (m, f, es) => (EFfiApp (m, f, map (exp env) es), loc)
- | EApp (
- (EApp
- ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), loc), _), _), t1), _), t2), _),
- _), _),
- (EApp (
- (EApp (
- (ECApp (
- (ECApp ((EFfi ("Basis", "return"), _), _), _),
- _), _),
- _), _), v), _)), _), trans2) => exp env (EApp (trans2, v), loc)
-
(*| EApp (
(EApp
((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), loc), _), _), t1), _), t2), _),
@@ -341,73 +330,216 @@ fun kindConAndExp (namedC, namedE) =
loc)
end*)
- | EApp (
- (EApp
- ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), loc), _), _), t1), _), t2), _),
- (EFfi ("Basis", "transaction_monad"), _)), _),
- (EServerCall (n, es, ke, dom, ran), _)), _),
- trans2) =>
- let
- val e' = (EFfi ("Basis", "bind"), loc)
- val e' = (ECApp (e', (CFfi ("Basis", "transaction"), loc)), loc)
- val e' = (ECApp (e', dom), loc)
- val e' = (ECApp (e', t2), loc)
- val e' = (EApp (e', (EFfi ("Basis", "transaction_monad"), loc)), loc)
- val e' = (EApp (e', (EApp (E.liftExpInExp 0 ke, (ERel 0, loc)), loc)), loc)
- val e' = (EApp (e', E.liftExpInExp 0 trans2), loc)
- val e' = (EAbs ("x", dom, t2, e'), loc)
- val e' = (EServerCall (n, es, e', dom, t2), loc)
- in
- exp env e'
- end
-
- | EApp (
- (EApp
- ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), loc), mt), _), _), _), t3), _),
- me), _),
- (EApp ((EApp
- ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), _), _), _), t1), _), t2), _),
- _), _),
- trans1), _), trans2), _)), _),
- trans3) =>
- let
- val e'' = (EFfi ("Basis", "bind"), loc)
- val e'' = (ECApp (e'', mt), loc)
- val e'' = (ECApp (e'', t2), loc)
- val e'' = (ECApp (e'', t3), loc)
- val e'' = (EApp (e'', me), loc)
- val e'' = (EApp (e'', (EApp (E.liftExpInExp 0 trans2, (ERel 0, loc)), loc)), loc)
- val e'' = (EApp (e'', E.liftExpInExp 0 trans3), loc)
- val e'' = (EAbs ("xb", t1, (CApp (mt, t3), loc), e''), loc)
-
- val e' = (EFfi ("Basis", "bind"), loc)
- val e' = (ECApp (e', mt), loc)
- val e' = (ECApp (e', t1), loc)
- val e' = (ECApp (e', t3), loc)
- val e' = (EApp (e', me), loc)
- val e' = (EApp (e', trans1), loc)
- val e' = (EApp (e', e''), loc)
- (*val () = print "Before\n"*)
- val ee' = exp env e'
- (*val () = print "After\n"*)
- in
- (*Print.prefaces "Commute" [("Pre", CorePrint.p_exp CoreEnv.empty (e, loc)),
- ("Mid", CorePrint.p_exp CoreEnv.empty e'),
- ("env", Print.PD.string (e2s env)),
- ("Post", CorePrint.p_exp CoreEnv.empty ee')];*)
- ee'
- end
-
| EApp (e1, e2) =>
let
+ val env' = deKnown env
+
+ fun reassoc e =
+ case #1 e of
+ EApp
+ ((EApp
+ ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), loc), _), _),
+ t1),
+ _), t2), _),
+ (EFfi ("Basis", "transaction_monad"), _)), _),
+ (EServerCall (n, es, (EAbs (_, _, _, ke), _), dom, ran), _)), _),
+ trans3) =>
+ let
+ val e' = (EFfi ("Basis", "bind"), loc)
+ val e' = (ECApp (e', (CFfi ("Basis", "transaction"), loc)), loc)
+ val e' = (ECApp (e', dom), loc)
+ val e' = (ECApp (e', t2), loc)
+ val e' = (EApp (e', (EFfi ("Basis", "transaction_monad"), loc)), loc)
+ val e' = (EApp (e', ke), loc)
+ val e' = (EApp (e', E.liftExpInExp 0 trans3), loc)
+ val e' = reassoc e'
+ val e' = (EAbs ("x", dom, t2, e'), loc)
+ val e' = (EServerCall (n, es, e', dom, t2), loc)
+ in
+ e'
+ end
+
+ | EApp
+ ((EApp
+ ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), loc), _), _),
+ t1),
+ _), t2), _),
+ (EFfi ("Basis", "transaction_monad"), _)), _),
+ (EServerCall (n, es, ke, dom, ran), _)), _),
+ trans3) =>
+ let
+ val e' = (EFfi ("Basis", "bind"), loc)
+ val e' = (ECApp (e', (CFfi ("Basis", "transaction"), loc)), loc)
+ val e' = (ECApp (e', dom), loc)
+ val e' = (ECApp (e', t2), loc)
+ val e' = (EApp (e', (EFfi ("Basis", "transaction_monad"), loc)), loc)
+ val e' = (EApp (e', exp (UnknownE :: env')
+ (EApp (E.liftExpInExp 0 ke, (ERel 0, loc)), loc)),
+ loc)
+ val e' = (EApp (e', E.liftExpInExp 0 trans3), loc)
+ val e' = reassoc e'
+ val e' = (EAbs ("x", dom, t2, e'), loc)
+ val e' = (EServerCall (n, es, e', dom, t2), loc)
+ in
+ e'
+ end
+
+ | EApp
+ ((EApp
+ ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), loc), mt),
+ _), _), _), t3), _),
+ me), _),
+ (EApp ((EApp
+ ((EApp ((ECApp ((ECApp ((ECApp (
+ (EFfi ("Basis", "bind"), _), _), _),
+ t1), _), t2), _),
+ _), _),
+ trans1), _), (EAbs (_, _, _, trans2), _)), _)), _),
+ trans3) =>
+ let
+ val e'' = (EFfi ("Basis", "bind"), loc)
+ val e'' = (ECApp (e'', mt), loc)
+ val e'' = (ECApp (e'', t2), loc)
+ val e'' = (ECApp (e'', t3), loc)
+ val e'' = (EApp (e'', me), loc)
+ val e'' = (EApp (e'', trans2), loc)
+ val e'' = (EApp (e'', E.liftExpInExp 0 trans3), loc)
+ val e'' = reassoc e''
+ val e'' = (EAbs ("xb", t1, (CApp (mt, t3), loc), e''), loc)
+
+ val e' = (EFfi ("Basis", "bind"), loc)
+ val e' = (ECApp (e', mt), loc)
+ val e' = (ECApp (e', t1), loc)
+ val e' = (ECApp (e', t3), loc)
+ val e' = (EApp (e', me), loc)
+ val e' = (EApp (e', trans1), loc)
+ val e' = (EApp (e', e''), loc)
+ in
+ e'
+ end
+
+ | EApp
+ ((EApp
+ ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), loc), mt),
+ _), _), _), t3), _),
+ me), _),
+ (EApp ((EApp
+ ((EApp ((ECApp ((ECApp ((ECApp (
+ (EFfi ("Basis", "bind"), _), _), _),
+ t1), _), t2), _),
+ _), _),
+ trans1), _), trans2), _)), _),
+ trans3) =>
+ let
+ val e'' = (EFfi ("Basis", "bind"), loc)
+ val e'' = (ECApp (e'', mt), loc)
+ val e'' = (ECApp (e'', t2), loc)
+ val e'' = (ECApp (e'', t3), loc)
+ val e'' = (EApp (e'', me), loc)
+ val () = print "In2\n"
+ val e'' = (EApp (e'', exp (UnknownE :: env')
+ (EApp (E.liftExpInExp 0 trans2, (ERel 0, loc)),
+ loc)),
+ loc)
+ val () = print "Out2\n"
+ val e'' = (EApp (e'', E.liftExpInExp 0 trans3), loc)
+ val e'' = reassoc e''
+ val e'' = (EAbs ("xb", t1, (CApp (mt, t3), loc), e''), loc)
+
+ val e' = (EFfi ("Basis", "bind"), loc)
+ val e' = (ECApp (e', mt), loc)
+ val e' = (ECApp (e', t1), loc)
+ val e' = (ECApp (e', t3), loc)
+ val e' = (EApp (e', me), loc)
+ val e' = (EApp (e', trans1), loc)
+ val e' = (EApp (e', e''), loc)
+ in
+ e'
+ end
+
+ | _ => e
+
val e1 = exp env e1
val e2 = exp env e2
+ val e12 = reassoc (EApp (e1, e2), loc)
in
- case #1 e1 of
- EAbs (_, _, _, b) =>
+ case #1 e12 of
+ EApp ((EAbs (_, _, _, b), _), e2) =>
((*Print.preface ("Body", CorePrint.p_exp CoreEnv.empty b);*)
- exp (KnownE e2 :: deKnown env) b)
- | _ => (EApp (e1, e2), loc)
+ exp (KnownE e2 :: env') b)
+ (*| EApp
+ ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), loc), _), _), t1),
+ _), t2), _),
+ _), _),
+ (EApp (
+ (EApp (
+ (ECApp (
+ (ECApp ((EFfi ("Basis", "return"), _), _), _),
+ _), _),
+ _), _), v), _)) =>
+ (ELet ("rv", con env t1, v,
+ exp (deKnown env) (EApp (E.liftExpInExp 0 e2, (ERel 0, loc)), loc)), loc)*)
+ (*| EApp
+ ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), loc), _), _), t1),
+ _), t2), _),
+ (EFfi ("Basis", "transaction_monad"), _)), _),
+ (EServerCall (n, es, ke, dom, ran), _)) =>
+ let
+ val e' = (EFfi ("Basis", "bind"), loc)
+ val e' = (ECApp (e', (CFfi ("Basis", "transaction"), loc)), loc)
+ val e' = (ECApp (e', dom), loc)
+ val e' = (ECApp (e', t2), loc)
+ val e' = (EApp (e', (EFfi ("Basis", "transaction_monad"), loc)), loc)
+ val e' = (EApp (e', (EApp (E.liftExpInExp 0 ke, (ERel 0, loc)), loc)), loc)
+ val e' = (EApp (e', E.liftExpInExp 0 (exp env e2)), loc)
+ val e' = (EAbs ("x", dom, t2, e'), loc)
+ val e' = (EServerCall (n, es, e', dom, t2), loc)
+ val e' = exp (deKnown env) e'
+ in
+ (*Print.prefaces "SC" [("Old", CorePrint.p_exp CoreEnv.empty all),
+ ("New", CorePrint.p_exp CoreEnv.empty e')]*)
+ e'
+ end
+ | EApp
+ ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), loc), mt),
+ _), _), _), t3), _),
+ me), _),
+ (EApp ((EApp
+ ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), _), _), _),
+ t1), _), t2), _),
+ _), _),
+ trans1), _), trans2), _)) =>
+ let
+ val e'' = (EFfi ("Basis", "bind"), loc)
+ val e'' = (ECApp (e'', mt), loc)
+ val e'' = (ECApp (e'', t2), loc)
+ val e'' = (ECApp (e'', t3), loc)
+ val e'' = (EApp (e'', me), loc)
+ val e'' = (EApp (e'', (EApp (E.liftExpInExp 0 trans2, (ERel 0, loc)), loc)), loc)
+ val e'' = (EApp (e'', E.liftExpInExp 0 e2), loc)
+ val e'' = (EAbs ("xb", t1, (CApp (mt, t3), loc), e''), loc)
+
+ val e' = (EFfi ("Basis", "bind"), loc)
+ val e' = (ECApp (e', mt), loc)
+ val e' = (ECApp (e', t1), loc)
+ val e' = (ECApp (e', t3), loc)
+ val e' = (EApp (e', me), loc)
+ val e' = (EApp (e', trans1), loc)
+ val e' = (EApp (e', e''), loc)
+ (*val () = Print.prefaces "Going in" [("e", CorePrint.p_exp CoreEnv.empty (e, loc)),
+ ("e1", CorePrint.p_exp CoreEnv.empty e1),
+ ("e'", CorePrint.p_exp CoreEnv.empty e')]*)
+ val ee' = exp (deKnown env) e'
+ val () = Print.prefaces "Coming out" [("ee'", CorePrint.p_exp CoreEnv.empty ee')]
+ in
+ (*Print.prefaces "Commute" [("Pre", CorePrint.p_exp CoreEnv.empty (e, loc)),
+ ("Mid", CorePrint.p_exp CoreEnv.empty e'),
+ ("env", Print.PD.string (e2s env)),
+ ("Post", CorePrint.p_exp CoreEnv.empty ee')];*)
+ ee'
+ end
+ | _ => (EApp (e1, exp env e2), loc)*)
+ | _ => e12
end
| EAbs (x, dom, ran, e) => (EAbs (x, con env dom, con env ran, exp (UnknownE :: env) e), loc)
@@ -568,7 +700,8 @@ fun kindConAndExp (namedC, namedE) =
| 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, t1, t2) => (EServerCall (n, map (exp env) es, exp env e,
con env t1, con env t2), loc)
@@ -618,7 +751,8 @@ fun reduce file =
(namedC, IM.insert (namedE, n, e)))
end
| DValRec vis =>
- ((DValRec (map (fn (x, n, t, e, s) => (x, n, con namedC [] t, exp (namedC, namedE) [] e, s)) vis), loc),
+ ((DValRec (map (fn (x, n, t, e, s) => (x, n, con namedC [] t,
+ exp (namedC, namedE) [] e, s)) vis), loc),
st)
| DExport _ => (d, st)
| DTable (s, n, c, s', pe, pc, ce, cc) => ((DTable (s, n, con namedC [] c, s',
diff --git a/src/urweb.grm b/src/urweb.grm
index b954ba8c..37a74e5a 100644
--- a/src/urweb.grm
+++ b/src/urweb.grm
@@ -1087,6 +1087,13 @@ eterm : LPAREN eexp RPAREN (#1 eexp, s (LPARENleft, RPARENright))
(EField (e, ident), loc))
(EVar (#1 path, #2 path, Infer), s (pathleft, pathright)) idents
end)
+ | LPAREN eexp RPAREN DOT idents (let
+ val loc = s (LPARENleft, identsright)
+ in
+ foldl (fn (ident, e) =>
+ (EField (e, ident), loc))
+ eexp idents
+ end)
| AT path DOT idents (let
val loc = s (ATleft, identsright)
in
--
cgit v1.2.3
From 5a88b41a6655f601c989ae94ce1fc8bb391ca630 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sun, 25 Oct 2009 14:07:10 -0400
Subject: RPC uses VM support for call/cc
---
CHANGELOG | 9 +++
lib/js/urweb.js | 16 +++-
src/compiler.sig | 2 -
src/compiler.sml | 9 +--
src/core.sml | 3 +-
src/core_print.sml | 22 ++----
src/core_untangle.sml | 3 +-
src/core_util.sml | 35 ++-------
src/effectize.sml | 4 +-
src/jscomp.sml | 12 +--
src/mono.sml | 4 +-
src/mono_print.sml | 8 +-
src/mono_reduce.sml | 2 +-
src/mono_util.sml | 10 +--
src/monoize.sml | 37 +--------
src/reduce.sml | 101 +------------------------
src/reduce_local.sml | 3 +-
src/rpcify.sml | 6 +-
src/shake.sml | 3 +-
src/sources | 3 -
src/tailify.sig | 32 --------
src/tailify.sml | 206 --------------------------------------------------
22 files changed, 59 insertions(+), 471 deletions(-)
delete mode 100644 src/tailify.sig
delete mode 100644 src/tailify.sml
(limited to 'src/mono.sml')
diff --git a/CHANGELOG b/CHANGELOG
index b45fbe74..f1a1b7db 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,12 @@
+========
+Next
+========
+
+- Bug fixes
+- Optimization improvements
+- Removed a restriction that prevented some RPCs from compiling
+- New extra demo: conference1
+
========
20091012
========
diff --git a/lib/js/urweb.js b/lib/js/urweb.js
index 653f8d2f..6ca4becd 100644
--- a/lib/js/urweb.js
+++ b/lib/js/urweb.js
@@ -632,7 +632,7 @@ function rc(prefix, uri, parse, k, needsSig) {
if (isok) {
try {
- execF(k, parse(xhr.responseText));
+ k(parse(xhr.responseText));
} catch (v) {
doExn(v);
}
@@ -854,7 +854,11 @@ function execP(env, p, v) {
}
function exec0(env, e) {
- var stack = null;
+ return exec1(env, null, e);
+}
+
+function exec1(env, stack, e) {
+ var stack, usedK = false;
var saveEnv = function() {
if (stack.next != null && stack.next.data.c != "<")
@@ -883,8 +887,9 @@ function exec0(env, e) {
case "f":
fr.args[fr.pos++] = v;
if (fr.a == null) {
- e = {c: "c", v: fr.f.apply(null, fr.args)};
stack = stack.next;
+ e = {c: "c", v: fr.f.apply(null, fr.args)};
+ if (usedK) return null;
} else {
e = fr.a.data;
fr.a = fr.a.next;
@@ -1014,6 +1019,11 @@ function exec0(env, e) {
env = e.env;
e = e.body;
break;
+ case "K":
+ { var savedStack = stack.next, savedEnv = env;
+ e = {c: "c", v: function(v) { return exec1(savedEnv, savedStack, {c: "c", v: v}); } };}
+ usedK = true;
+ break;
default:
whine("Unknown Ur expression kind " + e.c);
}
diff --git a/src/compiler.sig b/src/compiler.sig
index 5192cf6e..3f04801f 100644
--- a/src/compiler.sig
+++ b/src/compiler.sig
@@ -86,7 +86,6 @@ signature COMPILER = sig
val reduce : (Core.file, Core.file) phase
val unpoly : (Core.file, Core.file) phase
val specialize : (Core.file, Core.file) phase
- val tailify : (Core.file, Core.file) phase
val marshalcheck : (Core.file, Core.file) phase
val effectize : (Core.file, Core.file) phase
val monoize : (Core.file, Mono.file) phase
@@ -121,7 +120,6 @@ signature COMPILER = sig
val toSpecialize : (string, Core.file) transform
val toShake3 : (string, Core.file) transform
val toEspecialize : (string, Core.file) transform
- val toTailify : (string, Core.file) transform
val toReduce2 : (string, Core.file) transform
val toShake4 : (string, Core.file) transform
val toMarshalcheck : (string, Core.file) transform
diff --git a/src/compiler.sml b/src/compiler.sml
index b1939356..6fd107a7 100644
--- a/src/compiler.sml
+++ b/src/compiler.sml
@@ -779,14 +779,7 @@ val toShake3 = transform shake "shake3" o toSpecialize
val toEspecialize = transform especialize "especialize" o toShake3
-val tailify = {
- func = Tailify.frob,
- print = CorePrint.p_file CoreEnv.empty
-}
-
-val toTailify = transform tailify "tailify" o toEspecialize
-
-val toReduce2 = transform reduce "reduce2" o toTailify
+val toReduce2 = transform reduce "reduce2" o toEspecialize
val toShake4 = transform shake "shake4" o toReduce2
diff --git a/src/core.sml b/src/core.sml
index 04126cc0..6bead3dc 100644
--- a/src/core.sml
+++ b/src/core.sml
@@ -115,8 +115,7 @@ datatype exp' =
| ELet of string * con * exp * exp
- | EServerCall of int * exp list * exp * con * con
- | ETailCall of int * exp list * exp * con * con
+ | EServerCall of int * exp list * con
withtype exp = exp' located
diff --git a/src/core_print.sml b/src/core_print.sml
index 64a4e461..02407f01 100644
--- a/src/core_print.sml
+++ b/src/core_print.sml
@@ -438,22 +438,12 @@ fun p_exp' par env (e, _) =
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 "]"]
- | ETailCall (n, es, e, _, _) => box [string "Tail(",
- p_enamed env n,
- string ",",
- space,
- p_list (p_exp env) es,
- string ")[",
- p_exp env e,
- string "]"]
+ | EServerCall (n, es, _) => box [string "Server(",
+ p_enamed env n,
+ string ",",
+ space,
+ p_list (p_exp env) es,
+ string ")"]
| EKAbs (x, e) => box [string x,
space,
diff --git a/src/core_untangle.sml b/src/core_untangle.sml
index f00bd95b..d734cc6f 100644
--- a/src/core_untangle.sml
+++ b/src/core_untangle.sml
@@ -48,8 +48,7 @@ fun exp thisGroup (e, s) =
case e of
ENamed n => try n
| EClosure (n, _) => try n
- | EServerCall (n, _, _, _, _) => try n
- | ETailCall (n, _, _, _, _) => try n
+ | EServerCall (n, _, _) => try n
| _ => s
end
diff --git a/src/core_util.sml b/src/core_util.sml
index 4722eca1..cedde841 100644
--- a/src/core_util.sml
+++ b/src/core_util.sml
@@ -532,20 +532,12 @@ fun compare ((e1, _), (e2, _)) =
| (ELet _, _) => LESS
| (_, ELet _) => GREATER
- | (EServerCall (n1, es1, e1, _, _), EServerCall (n2, es2, e2, _, _)) =>
+ | (EServerCall (n1, es1, _), EServerCall (n2, es2, _)) =>
join (Int.compare (n1, n2),
- fn () => join (joinL compare (es1, es2),
- fn () => compare (e1, e2)))
+ fn () => joinL compare (es1, es2))
| (EServerCall _, _) => LESS
| (_, EServerCall _) => GREATER
- | (ETailCall (n1, es1, e1, _, _), ETailCall (n2, es2, e2, _, _)) =>
- join (Int.compare (n1, n2),
- fn () => join (joinL compare (es1, es2),
- fn () => compare (e1, e2)))
- | (ETailCall _, _) => LESS
- | (_, ETailCall _) => GREATER
-
| (EKAbs (_, e1), EKAbs (_, e2)) => compare (e1, e2)
| (EKAbs _, _) => LESS
| (_, EKAbs _) => GREATER
@@ -725,27 +717,12 @@ fun mapfoldB {kind = fk, con = fc, exp = fe, bind} =
fn e2' =>
(ELet (x, t', e1', e2'), loc))))
- | EServerCall (n, es, e, t1, t2) =>
- S.bind2 (ListUtil.mapfold (mfe ctx) es,
- fn es' =>
- S.bind2 (mfe ctx e,
- fn e' =>
- S.bind2 (mfc ctx t1,
- fn t1' =>
- S.map2 (mfc ctx t2,
- fn t2' =>
- (EServerCall (n, es', e', t1', t2'), loc)))))
-
- | ETailCall (n, es, e, t1, t2) =>
+ | EServerCall (n, es, t) =>
S.bind2 (ListUtil.mapfold (mfe ctx) es,
fn es' =>
- S.bind2 (mfe ctx e,
- fn e' =>
- S.bind2 (mfc ctx t1,
- fn t1' =>
- S.map2 (mfc ctx t2,
- fn t2' =>
- (ETailCall (n, es', e', t1', t2'), loc)))))
+ S.map2 (mfc ctx t,
+ fn t' =>
+ (EServerCall (n, es', t'), loc)))
| EKAbs (x, e) =>
S.map2 (mfe (bind (ctx, RelK x)) e,
diff --git a/src/effectize.sml b/src/effectize.sml
index d458561d..fcaaa79e 100644
--- a/src/effectize.sml
+++ b/src/effectize.sml
@@ -46,7 +46,7 @@ fun effectize file =
EFfi f => effectful f
| EFfiApp (m, x, _) => effectful (m, x)
| ENamed n => IM.inDomain (evs, n)
- | EServerCall (n, _, _, _, _) => IM.inDomain (evs, n)
+ | EServerCall (n, _, _) => IM.inDomain (evs, n)
| _ => false
fun couldWriteOnload evs = U.Exp.exists {kind = fn _ => false,
@@ -70,7 +70,7 @@ fun effectize file =
case e of
EFfi ("Basis", "getCookie") => true
| ENamed n => IM.inDomain (evs, n)
- | EServerCall (n, _, _, _, _) => IM.inDomain (evs, n)
+ | EServerCall (n, _, _) => IM.inDomain (evs, n)
| _ => false
fun couldReadCookie evs = U.Exp.exists {kind = fn _ => false,
diff --git a/src/jscomp.sml b/src/jscomp.sml
index b6e4a3b6..9d456c5c 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -900,10 +900,9 @@ fun process file =
st)
end
- | EServerCall (e, ek, t, eff) =>
+ | EServerCall (e, t, eff) =>
let
val (e, st) = jsE inner (e, st)
- val (ek, st) = jsE inner (ek, st)
val (unurl, st) = unurlifyExp loc (t, st)
in
(strcat [str ("{c:\"f\",f:rc,a:cons({c:\"c\",v:\""
@@ -911,9 +910,7 @@ fun process file =
^ "\"},cons("),
e,
str (",cons({c:\"c\",v:function(s){var t=s.split(\"/\");var i=0;return "
- ^ unurl ^ "}},cons("),
- ek,
- str (",cons({c:\"c\",v:"
+ ^ unurl ^ "}},cons({c:\"K\"},cons({c:\"c\",v:"
^ (case eff of
ReadCookieWrite => "true"
| _ => "false")
@@ -1165,12 +1162,11 @@ fun process file =
((ESignalSource e, loc), st)
end
- | EServerCall (e1, e2, t, ef) =>
+ | EServerCall (e1, t, ef) =>
let
val (e1, st) = exp outer (e1, st)
- val (e2, st) = exp outer (e2, st)
in
- ((EServerCall (e1, e2, t, ef), loc), st)
+ ((EServerCall (e1, t, ef), loc), st)
end
| ERecv (e1, e2, t) =>
let
diff --git a/src/mono.sml b/src/mono.sml
index 64ed448c..7ce6cee1 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -113,8 +113,8 @@ datatype exp' =
| ESignalReturn of exp
| ESignalBind of exp * exp
| ESignalSource of exp
-
- | EServerCall of exp * exp * typ * effect
+
+ | EServerCall of exp * typ * effect
| ERecv of exp * exp * typ
| ESleep of exp * exp
diff --git a/src/mono_print.sml b/src/mono_print.sml
index 71bc734a..49b636c3 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -335,11 +335,9 @@ fun p_exp' par env (e, _) =
p_exp env e,
string ")"]
- | EServerCall (n, e, _, _) => box [string "Server(",
- p_exp env n,
- string ")[",
- p_exp env e,
- string "]"]
+ | EServerCall (n, _, _) => box [string "Server(",
+ p_exp env n,
+ string ")"]
| ERecv (n, e, _) => box [string "Recv(",
p_exp env n,
string ")[",
diff --git a/src/mono_reduce.sml b/src/mono_reduce.sml
index 40d3c9e5..d09c957c 100644
--- a/src/mono_reduce.sml
+++ b/src/mono_reduce.sml
@@ -450,7 +450,7 @@ fun reduce file =
| ESignalBind (e1, e2) => summarize d e1 @ summarize d e2
| ESignalSource e => summarize d e
- | EServerCall (e, _, _, _) => summarize d e @ [Unsure]
+ | EServerCall (e, _, _) => summarize d e @ [Unsure]
| ERecv (e, _, _) => summarize d e @ [Unsure]
| ESleep (e, _) => summarize d e @ [Unsure]
in
diff --git a/src/mono_util.sml b/src/mono_util.sml
index c660a4a3..24024470 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -362,14 +362,12 @@ fun mapfoldB {typ = fc, exp = fe, bind} =
fn e' =>
(ESignalSource e', loc))
- | EServerCall (s, ek, t, eff) =>
+ | EServerCall (s, t, eff) =>
S.bind2 (mfe ctx s,
fn s' =>
- S.bind2 (mfe ctx ek,
- fn ek' =>
- S.map2 (mft t,
- fn t' =>
- (EServerCall (s', ek', t', eff), loc))))
+ S.map2 (mft t,
+ fn t' =>
+ (EServerCall (s', t', eff), loc)))
| ERecv (s, ek, t) =>
S.bind2 (mfe ctx s,
fn s' =>
diff --git a/src/monoize.sml b/src/monoize.sml
index 0a9f8e86..ff01b7f7 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -3201,22 +3201,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
((L'.ELet (x, t', e1, e2), loc), fm)
end
- | L.ETailCall (n, es, ek, _, (L.TRecord (L.CRecord (_, []), _), _)) =>
- let
- val (es, fm) = ListUtil.foldlMap (fn (e, fm) => monoExp (env, st, fm) e) fm es
- val (ek, fm) = monoExp (env, st, fm) ek
-
- val e = (L'.ENamed n, loc)
- val e = foldl (fn (arg, e) => (L'.EApp (e, arg), loc)) e es
- val e = (L'.EApp (e, ek), loc)
- in
- (e, fm)
- end
- | L.ETailCall _ => (E.errorAt loc "Full scope of tail call continuation isn't known";
- Print.eprefaces' [("Expression", CorePrint.p_exp env all)];
- (dummyExp, fm))
-
- | L.EServerCall (n, es, ek, t, (L.TRecord (L.CRecord (_, []), _), _)) =>
+ | L.EServerCall (n, es, t) =>
let
val t = monoType env t
val (_, ft, _, name) = Env.lookupENamed env n
@@ -3239,37 +3224,19 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
val call = foldl (fn (e, call) => (L'.EStrcat (call, e), loc))
(L'.EPrim (Prim.String name), loc) call
- val (ek, fm) = monoExp (env, st, fm) ek
-
val unit = (L'.TRecord [], loc)
- val ekf = (L'.EAbs ("f",
- (L'.TFun (t,
- (L'.TFun ((L'.TRecord [], loc),
- (L'.TRecord [], loc)), loc)), loc),
- (L'.TFun (t,
- (L'.TRecord [], loc)), loc),
- (L'.EAbs ("x",
- t,
- (L'.TRecord [], loc),
- (L'.EApp ((L'.EApp ((L'.ERel 1, loc),
- (L'.ERel 0, loc)), loc),
- (L'.ERecord [], loc)), loc)), loc)), loc)
- val ek = (L'.EApp (ekf, ek), loc)
val eff = if IS.member (!readCookie, n) then
L'.ReadCookieWrite
else
L'.ReadOnly
- val e = (L'.EServerCall (call, ek, t, eff), loc)
+ val e = (L'.EServerCall (call, t, eff), loc)
val e = liftExpInExp 0 e
val e = (L'.EAbs ("_", unit, unit, e), loc)
in
(e, fm)
end
- | L.EServerCall _ => (E.errorAt loc "Full scope of server call continuation isn't known";
- Print.eprefaces' [("Expression", CorePrint.p_exp env all)];
- (dummyExp, fm))
| L.EKAbs _ => poly ()
| L.EKApp _ => poly ()
diff --git a/src/reduce.sml b/src/reduce.sml
index 38465fda..1310c7d0 100644
--- a/src/reduce.sml
+++ b/src/reduce.sml
@@ -408,102 +408,6 @@ fun kindConAndExp (namedC, namedE) =
fun reassoc e =
case #1 e of
EApp
- ((EApp
- ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), loc), _), _),
- t1),
- _), t2), _),
- (EFfi ("Basis", "transaction_monad"), _)), _),
- (EServerCall (n, es, (EAbs (_, _, _, ke), _), dom, ran), _)), _),
- trans3) =>
- let
- val e' = (EFfi ("Basis", "bind"), loc)
- val e' = (ECApp (e', (CFfi ("Basis", "transaction"), loc)), loc)
- val e' = (ECApp (e', dom), loc)
- val e' = (ECApp (e', t2), loc)
- val e' = (EApp (e', (EFfi ("Basis", "transaction_monad"), loc)), loc)
- val e' = (EApp (e', ke), loc)
- val e' = (EApp (e', E.liftExpInExp 0 trans3), loc)
- val e' = reassoc e'
- val e' = (EAbs ("x", dom, t2, e'), loc)
- val e' = (EServerCall (n, es, e', dom, t2), loc)
- in
- e'
- end
-
- | EApp
- ((EApp
- ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), loc), _), _),
- t1),
- _), t2), _),
- (EFfi ("Basis", "transaction_monad"), _)), _),
- (EServerCall (n, es, ke, dom, ran), _)), _),
- trans3) =>
- let
- val e' = (EFfi ("Basis", "bind"), loc)
- val e' = (ECApp (e', (CFfi ("Basis", "transaction"), loc)), loc)
- val e' = (ECApp (e', dom), loc)
- val e' = (ECApp (e', t2), loc)
- val e' = (EApp (e', (EFfi ("Basis", "transaction_monad"), loc)), loc)
- val e' = (EApp (e', exp (UnknownE :: env')
- (EApp (E.liftExpInExp 0 ke, (ERel 0, loc)), loc)),
- loc)
- val e' = (EApp (e', E.liftExpInExp 0 trans3), loc)
- val e' = reassoc e'
- val e' = (EAbs ("x", dom, t2, e'), loc)
- val e' = (EServerCall (n, es, e', dom, t2), loc)
- in
- e'
- end
-
- | EApp
- ((EApp
- ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), loc), _), _),
- t1),
- _), t2), _),
- (EFfi ("Basis", "transaction_monad"), _)), _),
- (ETailCall (n, es, (EAbs (_, _, _, ke), _), dom, ran), _)), _),
- trans3) =>
- let
- val e' = (EFfi ("Basis", "bind"), loc)
- val e' = (ECApp (e', (CFfi ("Basis", "transaction"), loc)), loc)
- val e' = (ECApp (e', dom), loc)
- val e' = (ECApp (e', t2), loc)
- val e' = (EApp (e', (EFfi ("Basis", "transaction_monad"), loc)), loc)
- val e' = (EApp (e', ke), loc)
- val e' = (EApp (e', E.liftExpInExp 0 trans3), loc)
- val e' = reassoc e'
- val e' = (EAbs ("x", dom, t2, e'), loc)
- val e' = (ETailCall (n, es, e', dom, t2), loc)
- in
- e'
- end
-
- | EApp
- ((EApp
- ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), loc), _), _),
- t1),
- _), t2), _),
- (EFfi ("Basis", "transaction_monad"), _)), _),
- (ETailCall (n, es, ke, dom, ran), _)), _),
- trans3) =>
- let
- val e' = (EFfi ("Basis", "bind"), loc)
- val e' = (ECApp (e', (CFfi ("Basis", "transaction"), loc)), loc)
- val e' = (ECApp (e', dom), loc)
- val e' = (ECApp (e', t2), loc)
- val e' = (EApp (e', (EFfi ("Basis", "transaction_monad"), loc)), loc)
- val e' = (EApp (e', exp (UnknownE :: env')
- (EApp (E.liftExpInExp 0 ke, (ERel 0, loc)), loc)),
- loc)
- val e' = (EApp (e', E.liftExpInExp 0 trans3), loc)
- val e' = reassoc e'
- val e' = (EAbs ("x", dom, t2, e'), loc)
- val e' = (ETailCall (n, es, e', dom, t2), loc)
- in
- e'
- end
-
- | EApp
((EApp
((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), loc), mt),
_), _), _), t3), _),
@@ -792,10 +696,7 @@ fun kindConAndExp (namedC, namedE) =
| ELet (x, t, e1, e2) =>
(ELet (x, con env t, exp env e1, exp (UnknownE :: env) e2), loc)
- | EServerCall (n, es, e, t1, t2) => (EServerCall (n, map (exp env) es, exp env e,
- con env t1, con env t2), loc)
- | ETailCall (n, es, e, t1, t2) => (ETailCall (n, map (exp env) es, exp env e,
- con env t1, con env t2), loc)
+ | EServerCall (n, es, t) => (EServerCall (n, map (exp env) es, con env t), loc)
in
(*if dangling (edepth' (deKnown env)) r then
(Print.prefaces "exp" [("e", CorePrint.p_exp CoreEnv.empty all),
diff --git a/src/reduce_local.sml b/src/reduce_local.sml
index ae752304..a9f28617 100644
--- a/src/reduce_local.sml
+++ b/src/reduce_local.sml
@@ -139,8 +139,7 @@ fun exp env (all as (e, loc)) =
| ELet (x, t, e1, e2) => (ELet (x, t, exp env e1, exp (Unknown :: env) e2), loc)
- | EServerCall (n, es, e, t1, t2) => (EServerCall (n, map (exp env) es, exp env e, t1, t2), loc)
- | ETailCall (n, es, e, t1, t2) => (ETailCall (n, map (exp env) es, exp env e, t1, t2), loc)
+ | EServerCall (n, es, t) => (EServerCall (n, map (exp env) es, t), loc)
fun reduce file =
let
diff --git a/src/rpcify.sml b/src/rpcify.sml
index 0e5a1076..3569e2bc 100644
--- a/src/rpcify.sml
+++ b/src/rpcify.sml
@@ -112,11 +112,7 @@ fun frob file =
val st = {exported = exported,
export_decls = export_decls}
- val k = (ECApp ((EFfi ("Basis", "return"), loc),
- (CFfi ("Basis", "transaction"), loc)), loc)
- val k = (ECApp (k, ran), loc)
- val k = (EApp (k, (EFfi ("Basis", "transaction_monad"), loc)), loc)
- val e' = EServerCall (n, args, k, ran, ran)
+ val e' = EServerCall (n, args, ran)
in
(e', st)
end
diff --git a/src/shake.sml b/src/shake.sml
index 501f8209..ea97dafa 100644
--- a/src/shake.sml
+++ b/src/shake.sml
@@ -137,8 +137,7 @@ fun shake file =
in
case e of
ENamed n => check n
- | EServerCall (n, _, _, _, _) => check n
- | ETailCall (n, _, _, _, _) => check n
+ | EServerCall (n, _, _) => check n
| _ => s
end
diff --git a/src/sources b/src/sources
index 54910b8f..ddc7deff 100644
--- a/src/sources
+++ b/src/sources
@@ -131,9 +131,6 @@ especialize.sml
rpcify.sig
rpcify.sml
-tailify.sig
-tailify.sml
-
tag.sig
tag.sml
diff --git a/src/tailify.sig b/src/tailify.sig
deleted file mode 100644
index c0d1fb35..00000000
--- a/src/tailify.sig
+++ /dev/null
@@ -1,32 +0,0 @@
-(* 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 TAILIFY = sig
-
- val frob : Core.file -> Core.file
-
-end
diff --git a/src/tailify.sml b/src/tailify.sml
deleted file mode 100644
index 4b086e09..00000000
--- a/src/tailify.sml
+++ /dev/null
@@ -1,206 +0,0 @@
-(* 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 Tailify :> TAILIFY = struct
-
-open Core
-
-structure U = CoreUtil
-structure E = CoreEnv
-
-fun multiLiftExpInExp n e =
- if n = 0 then
- e
- else
- multiLiftExpInExp (n - 1) (E.liftExpInExp 0 e)
-
-structure IS = IntBinarySet
-structure IM = IntBinaryMap
-
-type state = {
- cpsed : exp' IM.map,
- rpc : IS.set
-}
-
-fun frob file =
- let
- fun exp (e, st : state) =
- case e of
- ENamed n =>
- (case IM.find (#cpsed st, n) of
- NONE => (e, st)
- | SOME re => (re, st))
-
- | _ => (e, st)
-
- and doExp (e, st) = U.Exp.foldMap {kind = fn x => x,
- con = fn x => x,
- exp = exp} st (ReduceLocal.reduceExp e)
-
- fun decl (d, st : state) =
- let
- fun makesServerCall b (e, _) =
- case e of
- EServerCall _ => true
- | ETailCall _ => raise Fail "Tailify: ETailCall too early"
- | ENamed n => IS.member (#rpc st, n)
-
- | EPrim _ => false
- | ERel n => List.nth (b, n)
- | ECon (_, _, _, NONE) => false
- | ECon (_, _, _, SOME e) => makesServerCall b e
- | EFfi _ => false
- | EFfiApp (_, _, es) => List.exists (makesServerCall b) es
- | EApp (e1, e2) => makesServerCall b e1 orelse makesServerCall b e2
- | EAbs (_, _, _, e1) => makesServerCall (false :: b) e1
- | ECApp (e1, _) => makesServerCall b e1
- | ECAbs (_, _, e1) => makesServerCall b e1
-
- | EKAbs (_, e1) => makesServerCall b e1
- | EKApp (e1, _) => makesServerCall b e1
-
- | ERecord xes => List.exists (fn ((CName s, _), e, _) =>
- not (String.isPrefix "On" s) andalso makesServerCall b e
- | (_, e, _) => makesServerCall b e) xes
- | EField (e1, _, _) => makesServerCall b e1
- | EConcat (e1, _, e2, _) => makesServerCall b e1 orelse makesServerCall b e2
- | ECut (e1, _, _) => makesServerCall b e1
- | ECutMulti (e1, _, _) => makesServerCall b e1
-
- | ECase (e1, pes, _) => makesServerCall b e1
- orelse List.exists (fn (p, e) =>
- makesServerCall (List.tabulate (E.patBindsN p,
- fn _ => false) @ b)
- e) pes
-
- | EWrite e1 => makesServerCall b e1
-
- | EClosure (_, es) => List.exists (makesServerCall b) es
-
- | ELet (_, _, e1, e2) => makesServerCall (makesServerCall b e1 :: b) e2
-
- val makesServerCall = makesServerCall []
-
- val (d, st) =
- case #1 d of
- DValRec vis =>
- if List.exists (fn (_, _, _, e, _) => makesServerCall e) vis then
- let
- val rpc = foldl (fn ((_, n, _, _, _), rpc) =>
- IS.add (rpc, n)) (#rpc st) vis
-
- val (cpsed, vis') =
- foldl (fn (vi as (x, n, t, e, s), (cpsed, vis')) =>
- let
- fun getArgs (t, acc) =
- case #1 t of
- TFun (dom, ran) =>
- getArgs (ran, dom :: acc)
- | _ => (rev acc, t)
- val (ts, ran) = getArgs (t, [])
- val ran = case #1 ran of
- CApp (_, ran) => ran
- | _ => raise Fail "Rpcify: Tail function not transactional"
- val len = length ts
-
- val loc = #2 e
- val args = ListUtil.mapi
- (fn (i, _) =>
- (ERel (len - i - 1), loc))
- ts
- val k = (EFfi ("Basis", "return"), loc)
- val trans = (CFfi ("Basis", "transaction"), loc)
- val k = (ECApp (k, trans), loc)
- val k = (ECApp (k, ran), loc)
- val k = (EApp (k, (EFfi ("Basis", "transaction_monad"),
- loc)), loc)
- val re = (ETailCall (n, args, k, ran, ran), loc)
- val (re, _) = foldr (fn (dom, (re, ran)) =>
- ((EAbs ("x", dom, ran, re),
- loc),
- (TFun (dom, ran), loc)))
- (re, ran) ts
-
- val be = multiLiftExpInExp (len + 1) e
- val be = ListUtil.foldli
- (fn (i, _, be) =>
- (EApp (be, (ERel (len - i), loc)), loc))
- be ts
- val ne = (EFfi ("Basis", "bind"), loc)
- val ne = (ECApp (ne, trans), loc)
- val ne = (ECApp (ne, ran), loc)
- val unit = (TRecord (CRecord ((KType, loc), []),
- loc), loc)
- val ne = (ECApp (ne, unit), loc)
- val ne = (EApp (ne, (EFfi ("Basis", "transaction_monad"),
- loc)), loc)
- val ne = (EApp (ne, be), loc)
- val ne = (EApp (ne, (ERel 0, loc)), loc)
- val tunit = (CApp (trans, unit), loc)
- val kt = (TFun (ran, tunit), loc)
- val ne = (EAbs ("k", kt, tunit, ne), loc)
- val (ne, res) = foldr (fn (dom, (ne, ran)) =>
- ((EAbs ("x", dom, ran, ne), loc),
- (TFun (dom, ran), loc)))
- (ne, (TFun (kt, tunit), loc)) ts
- in
- (IM.insert (cpsed, n, #1 re),
- (x, n, res, ne, s) :: vis')
- end)
- (#cpsed st, []) vis
- in
- ((DValRec (rev vis'), ErrorMsg.dummySpan),
- {cpsed = cpsed,
- rpc = rpc})
- end
- else
- (d, st)
- | DVal (x, n, t, e, s) =>
- (d,
- {cpsed = #cpsed st,
- rpc = if makesServerCall e then
- IS.add (#rpc st, n)
- else
- #rpc st})
- | _ => (d, st)
- in
- U.Decl.foldMap {kind = fn x => x,
- con = fn x => x,
- exp = exp,
- decl = fn x => x}
- st d
- end
-
- val (file, _) = ListUtil.foldlMap decl
- {cpsed = IM.empty,
- rpc = IS.empty}
- file
- in
- file
- end
-
-end
--
cgit v1.2.3
From 2385b6b946eb1215d75a3dddccb05aaf8f605ba3 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sun, 25 Oct 2009 15:29:21 -0400
Subject: Use call/cc for recv and sleep
---
CHANGELOG | 3 ++-
lib/js/urweb.js | 10 +++++++---
src/cjrize.sml | 1 +
src/jscomp.sml | 40 ++++++++++++++++++++++++----------------
src/mono.sml | 5 +++--
src/mono_print.sml | 19 +++++++++----------
src/mono_reduce.sml | 6 ++++--
src/mono_util.sml | 23 ++++++++++++-----------
src/monoize.sml | 33 ++++++---------------------------
9 files changed, 68 insertions(+), 72 deletions(-)
(limited to 'src/mono.sml')
diff --git a/CHANGELOG b/CHANGELOG
index f1a1b7db..5ac1a04a 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -4,7 +4,8 @@ Next
- Bug fixes
- Optimization improvements
-- Removed a restriction that prevented some RPCs from compiling
+- Removed a restriction that prevented some RPCs and calls to sleep or recv
+ from compiling
- New extra demo: conference1
========
diff --git a/lib/js/urweb.js b/lib/js/urweb.js
index 6ca4becd..62f94f52 100644
--- a/lib/js/urweb.js
+++ b/lib/js/urweb.js
@@ -779,10 +779,10 @@ function rv(chn, parse, k) {
var msg = dequeue(ch.msgs);
if (msg == null) {
- enqueue(ch.listeners, function(msg) { execF(execF(k, parse(msg)), null); });
+ enqueue(ch.listeners, function(msg) { k(parse(msg)); });
} else {
try {
- execF(execF(k, parse(msg)), null);
+ k(parse(msg));
} catch (v) {
doExn(v);
}
@@ -790,7 +790,11 @@ function rv(chn, parse, k) {
}
function sl(ms, k) {
- window.setTimeout(function() { execF(k, null); }, ms);
+ window.setTimeout(function() { k(null); }, ms);
+}
+
+function sp(e) {
+ execF(e, null);
}
diff --git a/src/cjrize.sml b/src/cjrize.sml
index bf814266..c7bf7c9d 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -479,6 +479,7 @@ fun cifyExp (eAll as (e, loc), sm) =
| L.EServerCall _ => raise Fail "Cjrize EServerCall"
| L.ERecv _ => raise Fail "Cjrize ERecv"
| L.ESleep _ => raise Fail "Cjrize ESleep"
+ | L.ESpawn _ => raise Fail "Cjrize ESpawn"
fun cifyDecl ((d, loc), sm) =
case d of
diff --git a/src/jscomp.sml b/src/jscomp.sml
index 9d456c5c..c6b8e7b9 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -918,31 +918,35 @@ fun process file =
st)
end
- | ERecv (e, ek, t) =>
+ | ERecv (e, t) =>
let
val (e, st) = jsE inner (e, st)
- val (ek, st) = jsE inner (ek, st)
val (unurl, st) = unurlifyExp loc (t, st)
in
(strcat [str ("{c:\"f\",f:rv,a:cons("),
e,
str (",cons({c:\"c\",v:function(s){var t=s.split(\"/\");var i=0;return "
- ^ unurl ^ "}},cons("),
- ek,
- str (",null)))}")],
+ ^ unurl ^ "}},cons({c:\"K\"},null)))}")],
st)
end
- | ESleep (e, ek) =>
+ | ESleep e =>
let
val (e, st) = jsE inner (e, st)
- val (ek, st) = jsE inner (ek, st)
in
(strcat [str "{c:\"f\",f:sl,a:cons(",
e,
- str ",cons(",
- ek,
- str ",null))}"],
+ str ",cons({c:\"K\"},null))}"],
+ st)
+ end
+
+ | ESpawn e =>
+ let
+ val (e, st) = jsE inner (e, st)
+ in
+ (strcat [str "{c:\"f\",f:sp,a:cons(",
+ e,
+ str ",null)}"],
st)
end
end
@@ -1168,19 +1172,23 @@ fun process file =
in
((EServerCall (e1, t, ef), loc), st)
end
- | ERecv (e1, e2, t) =>
+ | ERecv (e1, t) =>
let
val (e1, st) = exp outer (e1, st)
- val (e2, st) = exp outer (e2, st)
in
- ((ERecv (e1, e2, t), loc), st)
+ ((ERecv (e1, t), loc), st)
end
- | ESleep (e1, e2) =>
+ | ESleep e1 =>
+ let
+ val (e1, st) = exp outer (e1, st)
+ in
+ ((ESleep e1, loc), st)
+ end
+ | ESpawn e1 =>
let
val (e1, st) = exp outer (e1, st)
- val (e2, st) = exp outer (e2, st)
in
- ((ESleep (e1, e2), loc), st)
+ ((ESpawn e1, loc), st)
end)
fun decl (d as (_, loc), st) =
diff --git a/src/mono.sml b/src/mono.sml
index 7ce6cee1..35aada16 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -115,8 +115,9 @@ datatype exp' =
| ESignalSource of exp
| EServerCall of exp * typ * effect
- | ERecv of exp * exp * typ
- | ESleep of exp * exp
+ | ERecv of exp * typ
+ | ESleep of exp
+ | ESpawn of exp
withtype exp = exp' located
diff --git a/src/mono_print.sml b/src/mono_print.sml
index 49b636c3..6ac3393d 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -338,16 +338,15 @@ fun p_exp' par env (e, _) =
| EServerCall (n, _, _) => box [string "Server(",
p_exp env n,
string ")"]
- | ERecv (n, e, _) => box [string "Recv(",
- p_exp env n,
- string ")[",
- p_exp env e,
- string "]"]
- | ESleep (n, e) => box [string "Sleep(",
- p_exp env n,
- string ")[",
- p_exp env e,
- string "]"]
+ | ERecv (n, _) => box [string "Recv(",
+ p_exp env n,
+ string ")"]
+ | ESleep n => box [string "Sleep(",
+ p_exp env n,
+ string ")"]
+ | ESpawn n => box [string "Spawn(",
+ p_exp env n,
+ string ")"]
and p_exp env = p_exp' false env
diff --git a/src/mono_reduce.sml b/src/mono_reduce.sml
index d09c957c..04cd199e 100644
--- a/src/mono_reduce.sml
+++ b/src/mono_reduce.sml
@@ -112,6 +112,7 @@ fun impure (e, _) =
| EServerCall _ => true
| ERecv _ => true
| ESleep _ => true
+ | ESpawn _ => true
val liftExpInExp = Monoize.liftExpInExp
@@ -451,8 +452,9 @@ fun reduce file =
| ESignalSource e => summarize d e
| EServerCall (e, _, _) => summarize d e @ [Unsure]
- | ERecv (e, _, _) => summarize d e @ [Unsure]
- | ESleep (e, _) => summarize d e @ [Unsure]
+ | ERecv (e, _) => summarize d e @ [Unsure]
+ | ESleep e => summarize d e @ [Unsure]
+ | ESpawn e => summarize d e @ [Unsure]
in
(*Print.prefaces "Summarize"
[("e", MonoPrint.p_exp MonoEnv.empty (e, ErrorMsg.dummySpan)),
diff --git a/src/mono_util.sml b/src/mono_util.sml
index 24024470..f8e45dc3 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -368,20 +368,21 @@ fun mapfoldB {typ = fc, exp = fe, bind} =
S.map2 (mft t,
fn t' =>
(EServerCall (s', t', eff), loc)))
- | ERecv (s, ek, t) =>
+ | ERecv (s, t) =>
S.bind2 (mfe ctx s,
fn s' =>
- S.bind2 (mfe ctx ek,
- fn ek' =>
- S.map2 (mft t,
- fn t' =>
- (ERecv (s', ek', t'), loc))))
- | ESleep (s, ek) =>
- S.bind2 (mfe ctx s,
+ S.map2 (mft t,
+ fn t' =>
+ (ERecv (s', t'), loc)))
+ | ESleep s =>
+ S.map2 (mfe ctx s,
+ fn s' =>
+ (ESleep s', loc))
+
+ | ESpawn s =>
+ S.map2 (mfe ctx s,
fn s' =>
- S.map2 (mfe ctx ek,
- fn ek' =>
- (ESleep (s', ek'), loc)))
+ (ESpawn s', loc))
and mfmode ctx mode =
case mode of
diff --git a/src/monoize.sml b/src/monoize.sml
index ff01b7f7..4e337388 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -1207,42 +1207,21 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
fm)
end
- | L.EApp ((L.EApp ((L.ECApp ((L.ECApp ((L.ECApp ((L.EFfi ("Basis", "bind"), _), _), _), _), _), t2), _),
- (L.EFfi ("Basis", "transaction_monad"), _)), _),
- (L.EApp ((L.ECApp ((L.EFfi ("Basis", "recv"), _), t1), _),
- ch), loc)) =>
+ | L.EApp ((L.ECApp ((L.EFfi ("Basis", "recv"), _), t1), _), ch) =>
let
- val t1 = monoType env t1
- val t2 = monoType env t2
val un = (L'.TRecord [], loc)
- val mt2 = (L'.TFun (un, t2), loc)
+ val t1 = monoType env t1
val (ch, fm) = monoExp (env, st, fm) ch
in
- ((L'.EAbs ("m2", (L'.TFun (t1, mt2), loc), (L'.TFun (un, un), loc),
- (L'.EAbs ("_", un, un,
- (L'.ERecv (liftExpInExp 0 (liftExpInExp 0 ch),
- (L'.ERel 1, loc),
- t1), loc)), loc)), loc),
- fm)
+ ((L'.EAbs ("_", un, un, (L'.ERecv (liftExpInExp 0 ch, t1), loc)), loc), fm)
end
| L.EFfiApp ("Basis", "recv", _) => poly ()
- | L.EApp ((L.EApp ((L.ECApp ((L.ECApp ((L.ECApp ((L.EFfi ("Basis", "bind"), _), _), _), _), _), t2), _),
- (L.EFfi ("Basis", "transaction_monad"), _)), _),
- (L.EAbs (_, _, _,
- (L.EFfiApp ("Basis", "sleep", [n]), _)), loc)) =>
+ | L.EFfiApp ("Basis", "sleep", [n]) =>
let
- val t2 = monoType env t2
- val un = (L'.TRecord [], loc)
- val mt2 = (L'.TFun (un, t2), loc)
val (n, fm) = monoExp (env, st, fm) n
in
- ((L'.EAbs ("m2", (L'.TFun (un, mt2), loc), (L'.TFun (un, un), loc),
- (L'.EAbs ("_", un, un,
- (L'.ESleep (liftExpInExp 0 n, (L'.EApp ((L'.ERel 1, loc),
- (L'.ERecord [], loc)), loc)),
- loc)), loc)), loc),
- fm)
+ ((L'.ESleep n, loc), fm)
end
| L.EFfiApp ("Basis", "sleep", _) => poly ()
@@ -1302,7 +1281,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
let
val (e, fm) = monoExp (env, st, fm) e
in
- ((L'.EApp (e, (L'.ERecord [], loc)), loc), fm)
+ ((L'.ESpawn e, loc), fm)
end
| L.EFfi ("Basis", "signal_monad") => ((L'.ERecord [], loc), fm)
--
cgit v1.2.3
From b04e123d0e1159d431aae00c3e8f1cc4a1b95684 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Thu, 10 Dec 2009 13:32:09 -0500
Subject: Basis.url and redirects
---
CHANGELOG | 6 +
include/types.h | 2 +-
include/urweb.h | 1 +
lib/ur/basis.urs | 3 +
src/c/request.c | 2 +-
src/c/urweb.c | 46 +++++-
src/checknest.sml | 2 +
src/cjr.sml | 1 +
src/cjr_print.sml | 14 ++
src/cjrize.sml | 7 +
src/jscomp.sml | 7 +
src/mono.sml | 1 +
src/mono_opt.sml | 9 +-
src/mono_print.sml | 8 +
src/mono_reduce.sml | 2 +
src/mono_util.sml | 6 +
src/monoize.sml | 420 ++++++++++++++++++++++++++++------------------------
src/prepare.sml | 7 +
src/scriptcheck.sml | 1 +
src/tag.sml | 227 ++++++++++++++++------------
tests/makeUrl.ur | 3 +
tests/makeUrl.urp | 3 +
tests/makeUrl.urs | 1 +
tests/redirect.ur | 15 ++
tests/redirect.urp | 4 +
tests/redirect.urs | 1 +
26 files changed, 496 insertions(+), 303 deletions(-)
create mode 100644 tests/makeUrl.ur
create mode 100644 tests/makeUrl.urp
create mode 100644 tests/makeUrl.urs
create mode 100644 tests/redirect.ur
create mode 100644 tests/redirect.urp
create mode 100644 tests/redirect.urs
(limited to 'src/mono.sml')
diff --git a/CHANGELOG b/CHANGELOG
index f4eb32ea..36267b96 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,9 @@
+========
+Next
+========
+
+- Reifying expressions as URLs and redirecting to them explicitly
+
========
20091203
========
diff --git a/include/types.h b/include/types.h
index 19eae5ad..767b2345 100644
--- a/include/types.h
+++ b/include/types.h
@@ -39,7 +39,7 @@ typedef struct uw_Basis_file {
uw_Basis_blob data;
} uw_Basis_file;
-typedef enum { SUCCESS, FATAL, BOUNDED_RETRY, UNLIMITED_RETRY, RETURN_BLOB } failure_kind;
+typedef enum { SUCCESS, FATAL, BOUNDED_RETRY, UNLIMITED_RETRY, RETURN_INDIRECTLY } failure_kind;
typedef enum { SERVED, KEEP_OPEN, FAILED } request_result;
diff --git a/include/urweb.h b/include/urweb.h
index 76bb9f25..0a23018a 100644
--- a/include/urweb.h
+++ b/include/urweb.h
@@ -209,6 +209,7 @@ uw_Basis_blob uw_Basis_fileData(uw_context, uw_Basis_file);
uw_Basis_int uw_Basis_blobSize(uw_context, uw_Basis_blob);
__attribute__((noreturn)) void uw_return_blob(uw_context, uw_Basis_blob, uw_Basis_string mimeType);
+__attribute__((noreturn)) void uw_redirect(uw_context, uw_Basis_string url);
uw_Basis_time uw_Basis_now(uw_context);
extern const uw_Basis_time uw_Basis_minTime;
diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs
index 200d9896..b56c5e5e 100644
--- a/lib/ur/basis.urs
+++ b/lib/ur/basis.urs
@@ -560,8 +560,11 @@ con tabl = [Body, Table]
con tr = [Body, Tr]
type url
+val show_url : show url
val bless : string -> url
val checkUrl : string -> option url
+val url : transaction page -> url
+val redirect : t ::: Type -> url -> transaction t
val dyn : ctx ::: {Unit} -> use ::: {Type} -> bind ::: {Type} -> [ctx ~ body] => unit
-> tag [Signal = signal (xml (body ++ ctx) use bind)] (body ++ ctx) [] use bind
diff --git a/src/c/request.c b/src/c/request.c
index 069de4aa..2357a86b 100644
--- a/src/c/request.c
+++ b/src/c/request.c
@@ -374,7 +374,7 @@ request_result uw_request(uw_request_context rc, uw_context ctx,
}
strcpy(rc->path_copy, path);
fk = uw_begin(ctx, rc->path_copy);
- if (fk == SUCCESS || fk == RETURN_BLOB) {
+ if (fk == SUCCESS || fk == RETURN_INDIRECTLY) {
uw_commit(ctx);
return SERVED;
} else if (fk == BOUNDED_RETRY) {
diff --git a/src/c/urweb.c b/src/c/urweb.c
index 95142a2d..476e3794 100644
--- a/src/c/urweb.c
+++ b/src/c/urweb.c
@@ -199,6 +199,7 @@ static client *find_client(unsigned id) {
}
static char *on_success = "HTTP/1.1 200 OK\r\n";
+static char *on_redirect = "HTTP/1.1 303 See Other\r\n";
void uw_set_on_success(char *s) {
on_success = s;
@@ -352,7 +353,7 @@ struct uw_context {
void *get_header_data;
buf outHeaders, page, heap, script;
- int returning_blob;
+ int returning_indirectly;
input *inputs, *subinputs, *cur_container;
size_t n_subinputs, used_subinputs;
@@ -396,7 +397,7 @@ uw_context uw_init() {
buf_init(&ctx->outHeaders, 0);
buf_init(&ctx->page, 0);
- ctx->returning_blob = 0;
+ ctx->returning_indirectly = 0;
buf_init(&ctx->heap, 0);
buf_init(&ctx->script, 1);
ctx->script.start[0] = 0;
@@ -475,7 +476,7 @@ void uw_reset_keep_error_message(uw_context ctx) {
buf_reset(&ctx->script);
ctx->script.start[0] = 0;
buf_reset(&ctx->page);
- ctx->returning_blob = 0;
+ ctx->returning_indirectly = 0;
buf_reset(&ctx->heap);
ctx->regions = NULL;
ctx->cleanup_front = ctx->cleanup;
@@ -2793,7 +2794,7 @@ void uw_commit(uw_context ctx) {
ctx->transactionals[i].free(ctx->transactionals[i].data);
// Splice script data into appropriate part of page
- if (ctx->returning_blob || ctx->script_header[0] == 0) {
+ if (ctx->returning_indirectly || ctx->script_header[0] == 0) {
char *start = strstr(ctx->page.start, "");
if (start) {
memmove(start, start + 4, buf_used(&ctx->page) - (start - ctx->page.start) - 4);
@@ -2942,7 +2943,17 @@ failure_kind uw_initialize(uw_context ctx) {
extern int uw_check_url(const char *);
extern int uw_check_mime(const char *);
+static int url_bad(uw_Basis_string s) {
+ for (; *s; ++s)
+ if (!isgraph(*s))
+ return 1;
+
+ return 0;
+}
+
uw_Basis_string uw_Basis_bless(uw_context ctx, uw_Basis_string s) {
+ if (url_bad(s))
+ uw_error(ctx, FATAL, "Invalid URL %s", uw_Basis_htmlifyString(ctx, s));
if (uw_check_url(s))
return s;
else
@@ -2950,6 +2961,8 @@ uw_Basis_string uw_Basis_bless(uw_context ctx, uw_Basis_string s) {
}
uw_Basis_string uw_Basis_checkUrl(uw_context ctx, uw_Basis_string s) {
+ if (url_bad(s))
+ return NULL;
if (uw_check_url(s))
return s;
else
@@ -3024,7 +3037,7 @@ __attribute__((noreturn)) void uw_return_blob(uw_context ctx, uw_Basis_blob b, u
cleanup *cl;
int len;
- ctx->returning_blob = 1;
+ ctx->returning_indirectly = 1;
buf_reset(&ctx->outHeaders);
buf_reset(&ctx->page);
@@ -3044,7 +3057,28 @@ __attribute__((noreturn)) void uw_return_blob(uw_context ctx, uw_Basis_blob b, u
ctx->cleanup_front = ctx->cleanup;
- longjmp(ctx->jmp_buf, RETURN_BLOB);
+ longjmp(ctx->jmp_buf, RETURN_INDIRECTLY);
+}
+
+__attribute__((noreturn)) void uw_redirect(uw_context ctx, uw_Basis_string url) {
+ cleanup *cl;
+ int len;
+
+ ctx->returning_indirectly = 1;
+ buf_reset(&ctx->outHeaders);
+ buf_reset(&ctx->page);
+
+ uw_write_header(ctx, on_redirect);
+ uw_write_header(ctx, "Location: ");
+ uw_write_header(ctx, url);
+ uw_write_header(ctx, "\r\n\r\n");
+
+ for (cl = ctx->cleanup; cl < ctx->cleanup_front; ++cl)
+ cl->func(cl->arg);
+
+ ctx->cleanup_front = ctx->cleanup;
+
+ longjmp(ctx->jmp_buf, RETURN_INDIRECTLY);
}
uw_Basis_string uw_Basis_unAs(uw_context ctx, uw_Basis_string s) {
diff --git a/src/checknest.sml b/src/checknest.sml
index 27a1796c..49519705 100644
--- a/src/checknest.sml
+++ b/src/checknest.sml
@@ -57,6 +57,7 @@ fun expUses globals =
| EError (e, _) => eu e
| EReturnBlob {blob, mimeType, ...} => IS.union (eu blob, eu mimeType)
+ | ERedirect (e, _) => eu e
| EWrite e => eu e
| ESeq (e1, e2) => IS.union (eu e1, eu e2)
@@ -117,6 +118,7 @@ fun annotateExp globals =
| EError (e, t) => (EError (ae e, t), loc)
| EReturnBlob {blob, mimeType, t} => (EReturnBlob {blob = ae blob, mimeType = ae mimeType, t = t}, loc)
+ | ERedirect (e, t) => (ERedirect (ae e, t), loc)
| EWrite e => (EWrite (ae e), loc)
| ESeq (e1, e2) => (ESeq (ae e1, ae e2), loc)
diff --git a/src/cjr.sml b/src/cjr.sml
index 8c4267f6..2b8ce6fe 100644
--- a/src/cjr.sml
+++ b/src/cjr.sml
@@ -77,6 +77,7 @@ datatype exp' =
| EError of exp * typ
| EReturnBlob of {blob : exp, mimeType : exp, t : typ}
+ | ERedirect of exp * typ
| EWrite of exp
| ESeq of exp * exp
diff --git a/src/cjr_print.sml b/src/cjr_print.sml
index e459db62..a1d5ed2c 100644
--- a/src/cjr_print.sml
+++ b/src/cjr_print.sml
@@ -1451,6 +1451,20 @@ fun p_exp' par env (e, loc) =
string "tmp;",
newline,
string "})"]
+ | ERedirect (e, t) =>
+ box [string "({",
+ newline,
+ p_typ env t,
+ space,
+ string "tmp;",
+ newline,
+ string "uw_redirect(ctx, ",
+ p_exp env e,
+ string ");",
+ newline,
+ string "tmp;",
+ newline,
+ string "})"]
| EApp ((EError (e, (TFun (_, ran), _)), loc), _) =>
p_exp env (EError (e, ran), loc)
| EApp ((EReturnBlob {blob, mimeType, t = (TFun (_, ran), _)}, loc), _) =>
diff --git a/src/cjrize.sml b/src/cjrize.sml
index c7bf7c9d..703b9477 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -367,6 +367,13 @@ fun cifyExp (eAll as (e, loc), sm) =
in
((L'.EReturnBlob {blob = blob, mimeType = mimeType, t = t}, loc), sm)
end
+ | L.ERedirect (e, t) =>
+ let
+ val (e, sm) = cifyExp (e, sm)
+ val (t, sm) = cifyTyp (t, sm)
+ in
+ ((L'.ERedirect (e, t), loc), sm)
+ end
| L.EStrcat (e1, e2) =>
let
diff --git a/src/jscomp.sml b/src/jscomp.sml
index 4be870cb..471711d2 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -870,6 +870,7 @@ fun process file =
| ENextval _ => unsupported "Nextval"
| EUnurlify _ => unsupported "EUnurlify"
| EReturnBlob _ => unsupported "EUnurlify"
+ | ERedirect _ => unsupported "ERedirect"
| ESignalReturn e =>
let
@@ -1081,6 +1082,12 @@ fun process file =
in
((EReturnBlob {blob = blob, mimeType = mimeType, t = t}, loc), st)
end
+ | ERedirect (e, t) =>
+ let
+ val (e, st) = exp outer (e, st)
+ in
+ ((ERedirect (e, t), loc), st)
+ end
| EWrite e =>
let
diff --git a/src/mono.sml b/src/mono.sml
index 35aada16..92424ee3 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -90,6 +90,7 @@ datatype exp' =
| EError of exp * typ
| EReturnBlob of {blob : exp, mimeType : exp, t : typ}
+ | ERedirect of exp * typ
| EWrite of exp
| ESeq of exp * exp
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index eb4f5811..5d81d24d 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -115,6 +115,8 @@ fun unAs s =
doChars (String.explode s, [])
end
+fun checkUrl s = CharVector.all Char.isGraph s andalso Settings.checkUrl s
+
fun exp e =
case e of
EPrim (Prim.String s) =>
@@ -405,11 +407,16 @@ fun exp e =
optExp (EApp (e2, e1), loc)
| EFfiApp ("Basis", "bless", [(se as EPrim (Prim.String s), loc)]) =>
- (if Settings.checkUrl s then
+ (if checkUrl s then
()
else
ErrorMsg.errorAt loc ("Invalid URL " ^ s ^ " passed to 'bless'");
se)
+ | EFfiApp ("Basis", "checkUrl", [(se as EPrim (Prim.String s), loc)]) =>
+ (if checkUrl s then
+ ESome ((TFfi ("Basis", "string"), loc), (se, loc))
+ else
+ ENone (TFfi ("Basis", "string"), loc))
| EFfiApp ("Basis", "blessMime", [(se as EPrim (Prim.String s), loc)]) =>
(if Settings.checkMime s then
()
diff --git a/src/mono_print.sml b/src/mono_print.sml
index 6ac3393d..cfaa410b 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -239,6 +239,14 @@ fun p_exp' par env (e, _) =
space,
p_typ env t,
string ")"]
+ | ERedirect (e, t) => box [string "(redirect",
+ space,
+ p_exp env e,
+ space,
+ string ":",
+ space,
+ p_typ env t,
+ string ")"]
| EStrcat (e1, e2) => parenIf par (box [p_exp' true env e1,
space,
diff --git a/src/mono_reduce.sml b/src/mono_reduce.sml
index 04cd199e..a15ce34b 100644
--- a/src/mono_reduce.sml
+++ b/src/mono_reduce.sml
@@ -98,6 +98,7 @@ fun impure (e, _) =
| EError (e, _) => impure e
| EReturnBlob {blob = e1, mimeType = e2, ...} => impure e1 orelse impure e2
+ | ERedirect (e, _) => impure e
| EStrcat (e1, e2) => impure e1 orelse impure e2
@@ -429,6 +430,7 @@ fun reduce file =
| EError (e, _) => summarize d e @ [Unsure]
| EReturnBlob {blob = e1, mimeType = e2, ...} => summarize d e1 @ summarize d e2 @ [Unsure]
+ | ERedirect (e, _) => summarize d e @ [Unsure]
| EWrite e => summarize d e @ [WritePage]
diff --git a/src/mono_util.sml b/src/mono_util.sml
index f8e45dc3..91b4412e 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -263,6 +263,12 @@ fun mapfoldB {typ = fc, exp = fe, bind} =
S.map2 (mft t,
fn t' =>
(EReturnBlob {blob = blob', mimeType = mimeType', t = t'}, loc))))
+ | ERedirect (e, t) =>
+ S.bind2 (mfe ctx e,
+ fn e' =>
+ S.map2 (mft t,
+ fn t' =>
+ (ERedirect (e', t'), loc)))
| EStrcat (e1, e2) =>
S.bind2 (mfe ctx e1,
diff --git a/src/monoize.sml b/src/monoize.sml
index 25b7d9c3..2d1a1f33 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -395,6 +395,8 @@ fun capitalize s =
else
str (Char.toUpper (String.sub (s, 0))) ^ String.extract (s, 1, NONE)
+val inTag = ref false
+
fun fooifyExp fk env =
let
fun fooify fm (e, tAll as (t, loc)) =
@@ -1065,6 +1067,12 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
in
((L'.EAbs ("s", s, s, (L'.ERel 0, loc)), loc), fm)
end
+ | L.EFfi ("Basis", "show_url") =>
+ let
+ val s = (L'.TFfi ("Basis", "string"), loc)
+ in
+ ((L'.EAbs ("s", s, s, (L'.ERel 0, loc)), loc), fm)
+ end
| L.EFfi ("Basis", "show_char") =>
((L'.EFfi ("Basis", "charToString"), loc), fm)
| L.EFfi ("Basis", "show_bool") =>
@@ -2472,6 +2480,9 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
tag), _),
xml) =>
let
+ val inT = !inTag
+ val () = inTag := true
+
fun getTag' (e, _) =
case e of
L.EFfi ("Basis", tag) => (tag, [])
@@ -2707,206 +2718,207 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L'.EPrim (Prim.String ")"), loc)), loc)), loc)
end
in
- case tag of
- "body" => let
- val onload = execify onload
- val onunload = execify onunload
- in
- normal ("body",
- SOME (L'.EStrcat ((L'.EFfiApp ("Basis", "maybe_onload",
- [(L'.EStrcat ((L'.EFfiApp ("Basis", "get_settings",
- [(L'.ERecord [], loc)]), loc),
- onload), loc)]),
- loc),
- (L'.EFfiApp ("Basis", "maybe_onunload",
- [onunload]),
- loc)), loc),
- SOME (L'.EFfiApp ("Basis", "get_script", [(L'.ERecord [], loc)]), loc))
- end
-
- | "dyn" =>
- let
- fun inTag tag = case targs of
- (L.CRecord (_, ctx), _) :: _ =>
- List.exists (fn ((L.CName tag', _), _) => tag' = tag
- | _ => false) ctx
- | _ => false
-
- val tag = if inTag "Tr" then
- "tr"
- else if inTag "Table" then
- "table"
- else
- "span"
- in
- case attrs of
- [("Signal", e, _)] =>
- ((L'.EStrcat
- ((L'.EPrim (Prim.String ("")), loc)), loc)), loc),
- fm)
- | _ => raise Fail "Monoize: Bad dyn attributes"
- end
-
- | "submit" => normal ("input type=\"submit\"", NONE, NONE)
- | "button" => normal ("input type=\"submit\"", NONE, NONE)
- | "hidden" => input "hidden"
-
- | "textbox" =>
- (case targs of
- [_, (L.CName name, _)] =>
- (case List.find (fn ("Source", _, _) => true | _ => false) attrs of
- NONE =>
- let
- val (ts, fm) = tagStart "input"
- in
- ((L'.EStrcat (ts,
- (L'.EPrim (Prim.String (" name=\"" ^ name ^ "\" />")),
- loc)), loc), fm)
- end
- | SOME (_, src, _) =>
- (strcat [str ""],
- fm))
- | _ => (Print.prefaces "Targs" (map (fn t => ("T", CorePrint.p_con env t)) targs);
- raise Fail "No name passed to textbox tag"))
- | "password" => input "password"
- | "textarea" =>
- (case targs of
- [_, (L.CName name, _)] =>
- let
- val (ts, fm) = tagStart "textarea"
- val (xml, fm) = monoExp (env, st, fm) xml
- in
- ((L'.EStrcat ((L'.EStrcat (ts,
- (L'.EPrim (Prim.String (" name=\"" ^ name ^ "\">")), loc)), loc),
- (L'.EStrcat (xml,
- (L'.EPrim (Prim.String ""),
- loc)), loc)),
- loc), fm)
- end
- | _ => (Print.prefaces "Targs" (map (fn t => ("T", CorePrint.p_con env t)) targs);
- raise Fail "No name passed to ltextarea tag"))
-
- | "checkbox" => input "checkbox"
- | "upload" => input "file"
-
- | "radio" =>
- (case targs of
- [_, (L.CName name, _)] =>
- monoExp (env, St.setRadioGroup (st, name), fm) xml
- | _ => (Print.prefaces "Targs" (map (fn t => ("T", CorePrint.p_con env t)) targs);
- raise Fail "No name passed to radio tag"))
- | "radioOption" =>
- (case St.radioGroup st of
- NONE => raise Fail "No name for radioGroup"
- | SOME name =>
- normal ("input",
- SOME (L'.EPrim (Prim.String (" type=\"radio\" name=\"" ^ name ^ "\"")), loc),
- NONE))
-
- | "select" =>
- (case targs of
- [_, (L.CName name, _)] =>
- let
- val (ts, fm) = tagStart "select"
- val (xml, fm) = monoExp (env, st, fm) xml
- in
- ((L'.EStrcat ((L'.EStrcat (ts,
- (L'.EPrim (Prim.String (" name=\"" ^ name ^ "\">")),
- loc)), loc),
- (L'.EStrcat (xml,
- (L'.EPrim (Prim.String ""),
- loc)), loc)),
- loc),
- fm)
- end
- | _ => (Print.prefaces "Targs" (map (fn t => ("T", CorePrint.p_con env t)) targs);
- raise Fail "No name passed to lselect tag"))
-
- | "ctextbox" =>
- (case List.find (fn ("Source", _, _) => true | _ => false) attrs of
- NONE =>
- let
- val (ts, fm) = tagStart "input"
- in
- ((L'.EStrcat (ts,
- (L'.EPrim (Prim.String " />"), loc)),
- loc), fm)
- end
- | SOME (_, src, _) =>
- let
- val sc = strcat [str "inp(exec(",
- (L'.EJavaScript (L'.Script, src), loc),
- str "))"]
- val sc = setAttrs sc
- in
- (strcat [str ""],
+ (case tag of
+ "body" => let
+ val onload = execify onload
+ val onunload = execify onunload
+ in
+ normal ("body",
+ SOME (L'.EStrcat ((L'.EFfiApp ("Basis", "maybe_onload",
+ [(L'.EStrcat ((L'.EFfiApp ("Basis", "get_settings",
+ [(L'.ERecord [], loc)]), loc),
+ onload), loc)]),
+ loc),
+ (L'.EFfiApp ("Basis", "maybe_onunload",
+ [onunload]),
+ loc)), loc),
+ SOME (L'.EFfiApp ("Basis", "get_script", [(L'.ERecord [], loc)]), loc))
+ end
+
+ | "dyn" =>
+ let
+ fun inTag tag = case targs of
+ (L.CRecord (_, ctx), _) :: _ =>
+ List.exists (fn ((L.CName tag', _), _) => tag' = tag
+ | _ => false) ctx
+ | _ => false
+
+ val tag = if inTag "Tr" then
+ "tr"
+ else if inTag "Table" then
+ "table"
+ else
+ "span"
+ in
+ case attrs of
+ [("Signal", e, _)] =>
+ ((L'.EStrcat
+ ((L'.EPrim (Prim.String ("")), loc)), loc)), loc),
fm)
- end)
+ | _ => raise Fail "Monoize: Bad dyn attributes"
+ end
+
+ | "submit" => normal ("input type=\"submit\"", NONE, NONE)
+ | "button" => normal ("input type=\"submit\"", NONE, NONE)
+ | "hidden" => input "hidden"
+
+ | "textbox" =>
+ (case targs of
+ [_, (L.CName name, _)] =>
+ (case List.find (fn ("Source", _, _) => true | _ => false) attrs of
+ NONE =>
+ let
+ val (ts, fm) = tagStart "input"
+ in
+ ((L'.EStrcat (ts,
+ (L'.EPrim (Prim.String (" name=\"" ^ name ^ "\" />")),
+ loc)), loc), fm)
+ end
+ | SOME (_, src, _) =>
+ (strcat [str ""],
+ fm))
+ | _ => (Print.prefaces "Targs" (map (fn t => ("T", CorePrint.p_con env t)) targs);
+ raise Fail "No name passed to textbox tag"))
+ | "password" => input "password"
+ | "textarea" =>
+ (case targs of
+ [_, (L.CName name, _)] =>
+ let
+ val (ts, fm) = tagStart "textarea"
+ val (xml, fm) = monoExp (env, st, fm) xml
+ in
+ ((L'.EStrcat ((L'.EStrcat (ts,
+ (L'.EPrim (Prim.String (" name=\"" ^ name ^ "\">")), loc)), loc),
+ (L'.EStrcat (xml,
+ (L'.EPrim (Prim.String ""),
+ loc)), loc)),
+ loc), fm)
+ end
+ | _ => (Print.prefaces "Targs" (map (fn t => ("T", CorePrint.p_con env t)) targs);
+ raise Fail "No name passed to ltextarea tag"))
+
+ | "checkbox" => input "checkbox"
+ | "upload" => input "file"
+
+ | "radio" =>
+ (case targs of
+ [_, (L.CName name, _)] =>
+ monoExp (env, St.setRadioGroup (st, name), fm) xml
+ | _ => (Print.prefaces "Targs" (map (fn t => ("T", CorePrint.p_con env t)) targs);
+ raise Fail "No name passed to radio tag"))
+ | "radioOption" =>
+ (case St.radioGroup st of
+ NONE => raise Fail "No name for radioGroup"
+ | SOME name =>
+ normal ("input",
+ SOME (L'.EPrim (Prim.String (" type=\"radio\" name=\"" ^ name ^ "\"")), loc),
+ NONE))
+
+ | "select" =>
+ (case targs of
+ [_, (L.CName name, _)] =>
+ let
+ val (ts, fm) = tagStart "select"
+ val (xml, fm) = monoExp (env, st, fm) xml
+ in
+ ((L'.EStrcat ((L'.EStrcat (ts,
+ (L'.EPrim (Prim.String (" name=\"" ^ name ^ "\">")),
+ loc)), loc),
+ (L'.EStrcat (xml,
+ (L'.EPrim (Prim.String ""),
+ loc)), loc)),
+ loc),
+ fm)
+ end
+ | _ => (Print.prefaces "Targs" (map (fn t => ("T", CorePrint.p_con env t)) targs);
+ raise Fail "No name passed to lselect tag"))
+
+ | "ctextbox" =>
+ (case List.find (fn ("Source", _, _) => true | _ => false) attrs of
+ NONE =>
+ let
+ val (ts, fm) = tagStart "input"
+ in
+ ((L'.EStrcat (ts,
+ (L'.EPrim (Prim.String " />"), loc)),
+ loc), fm)
+ end
+ | SOME (_, src, _) =>
+ let
+ val sc = strcat [str "inp(exec(",
+ (L'.EJavaScript (L'.Script, src), loc),
+ str "))"]
+ val sc = setAttrs sc
+ in
+ (strcat [str ""],
+ fm)
+ end)
- | "ccheckbox" =>
- (case List.find (fn ("Source", _, _) => true | _ => false) attrs of
- NONE =>
- let
- val (ts, fm) = tagStart "input type=\"checkbox\""
- in
- ((L'.EStrcat (ts,
- (L'.EPrim (Prim.String " />"), loc)),
- loc), fm)
- end
- | SOME (_, src, _) =>
- let
- val sc = strcat [str "chk(exec(",
- (L'.EJavaScript (L'.Script, src), loc),
- str "))"]
- val sc = setAttrs sc
- in
- (strcat [str ""],
- fm)
- end)
+ | "ccheckbox" =>
+ (case List.find (fn ("Source", _, _) => true | _ => false) attrs of
+ NONE =>
+ let
+ val (ts, fm) = tagStart "input type=\"checkbox\""
+ in
+ ((L'.EStrcat (ts,
+ (L'.EPrim (Prim.String " />"), loc)),
+ loc), fm)
+ end
+ | SOME (_, src, _) =>
+ let
+ val sc = strcat [str "chk(exec(",
+ (L'.EJavaScript (L'.Script, src), loc),
+ str "))"]
+ val sc = setAttrs sc
+ in
+ (strcat [str ""],
+ fm)
+ end)
- | "cselect" =>
- (case List.find (fn ("Source", _, _) => true | _ => false) attrs of
- NONE =>
- let
- val (xml, fm) = monoExp (env, st, fm) xml
- val (ts, fm) = tagStart "select"
- in
- (strcat [ts,
- str ">",
- xml,
- str ""],
- fm)
- end
- | SOME (_, src, _) =>
- let
- val (xml, fm) = monoExp (env, st, fm) xml
-
- val sc = strcat [str "sel(exec(",
- (L'.EJavaScript (L'.Script, src), loc),
- str "),exec(",
- (L'.EJavaScript (L'.Script, xml), loc),
- str "))"]
- val sc = setAttrs sc
- in
- (strcat [str ""],
- fm)
- end)
+ | "cselect" =>
+ (case List.find (fn ("Source", _, _) => true | _ => false) attrs of
+ NONE =>
+ let
+ val (xml, fm) = monoExp (env, st, fm) xml
+ val (ts, fm) = tagStart "select"
+ in
+ (strcat [ts,
+ str ">",
+ xml,
+ str ""],
+ fm)
+ end
+ | SOME (_, src, _) =>
+ let
+ val (xml, fm) = monoExp (env, st, fm) xml
+
+ val sc = strcat [str "sel(exec(",
+ (L'.EJavaScript (L'.Script, src), loc),
+ str "),exec(",
+ (L'.EJavaScript (L'.Script, xml), loc),
+ str "))"]
+ val sc = setAttrs sc
+ in
+ (strcat [str ""],
+ fm)
+ end)
- | "coption" => normal ("option", NONE, NONE)
+ | "coption" => normal ("option", NONE, NONE)
- | "tabl" => normal ("table", NONE, NONE)
- | _ => normal (tag, NONE, NONE)
+ | "tabl" => normal ("table", NONE, NONE)
+ | _ => normal (tag, NONE, NONE))
+ before inTag := inT
end
| L.EApp ((L.ECApp (
@@ -3121,6 +3133,16 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
t = t}, loc)), loc)), loc)), loc),
fm)
end
+ | L.ECApp ((L.EFfi ("Basis", "redirect"), _), t) =>
+ let
+ val t = monoType env t
+ val un = (L'.TRecord [], loc)
+ in
+ ((L'.EAbs ("url", (L'.TFfi ("Basis", "string"), loc), (L'.TFun (un, t), loc),
+ (L'.EAbs ("_", un, t,
+ (L'.ERedirect ((L'.ERel 1, loc), t), loc)), loc)), loc),
+ fm)
+ end
| L.EApp (e1, e2) =>
let
@@ -3198,9 +3220,13 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
let
val (es, fm) = ListUtil.foldlMap (fn (e, fm) =>
monoExp (env, st, fm) e)
- fm es
+ fm es
+ val e = (L'.EClosure (n, es), loc)
in
- ((L'.EClosure (n, es), loc), fm)
+ if !inTag then
+ (e, fm)
+ else
+ urlifyExp env fm (e, dummyTyp)
end
| L.ELet (x, t, e1, e2) =>
diff --git a/src/prepare.sml b/src/prepare.sml
index e7afc77f..58344a1f 100644
--- a/src/prepare.sml
+++ b/src/prepare.sml
@@ -202,6 +202,13 @@ fun prepExp (e as (_, loc), st) =
((EReturnBlob {blob = blob, mimeType = mimeType, t = t}, loc), st)
end
+ | ERedirect (e, t) =>
+ let
+ val (e, st) = prepExp (e, st)
+ in
+ ((ERedirect (e, t), loc), st)
+ end
+
| EWrite e =>
let
val (e, st) = prepExp (e, st)
diff --git a/src/scriptcheck.sml b/src/scriptcheck.sml
index c4623fc3..6dc11c65 100644
--- a/src/scriptcheck.sml
+++ b/src/scriptcheck.sml
@@ -106,6 +106,7 @@ fun classify (ds, ps) =
| ECase (e, pes, _) => hasClient e orelse List.exists (hasClient o #2) pes
| EError (e, _) => hasClient e
| EReturnBlob {blob = e1, mimeType = e2, ...} => hasClient e1 orelse hasClient e2
+ | ERedirect (e, _) => hasClient e
| EWrite e => hasClient e
| ESeq (e1, e2) => hasClient e1 orelse hasClient e2
| ELet (_, _, e1, e2) => hasClient e1 orelse hasClient e2
diff --git a/src/tag.sml b/src/tag.sml
index b4574b79..9510d360 100644
--- a/src/tag.sml
+++ b/src/tag.sml
@@ -46,115 +46,148 @@ fun both (loc, f) = (ErrorMsg.errorAt loc ("Function " ^ f ^ " needed for both a
"Make sure that the signature of the containing module hides any form handlers.\n"))
fun exp env (e, s) =
- case e of
- EApp (
- (EApp (
- (EApp (
- (EApp (
- (ECApp (
- (ECApp (
- (ECApp (
- (ECApp (
- (ECApp (
- (ECApp (
- (ECApp (
- (ECApp (
- (EFfi ("Basis", "tag"),
- loc), given), _), absent), _), outer), _), inner), _),
- useOuter), _), useInner), _), bindOuter), _), bindInner), _),
- class), _),
- attrs), _),
- tag), _),
- xml) =>
- (case attrs of
- (ERecord xets, _) =>
- let
- val (xets, s) =
- ListUtil.foldlMap (fn ((x, e, t), (count, tags, byTag, newTags)) =>
- let
- fun tagIt (ek, newAttr) =
- let
- val eOrig = e
+ let
+ fun tagIt (e, ek : export_kind, newAttr, (count, tags, byTag, newTags)) =
+ let
+ val loc = #2 e
+
+ val eOrig = e
- fun unravel (e, _) =
- case e of
- ENamed n => (n, [])
- | EApp (e1, e2) =>
- let
- val (n, es) = unravel e1
- in
- (n, es @ [e2])
- end
- | _ => (ErrorMsg.errorAt loc ("Invalid " ^ newAttr
- ^ " expression");
- Print.epreface ("Expression",
- CorePrint.p_exp CoreEnv.empty eOrig);
- (0, []))
+ fun unravel (e, _) =
+ case e of
+ ENamed n => (n, [])
+ | EApp (e1, e2) =>
+ let
+ val (n, es) = unravel e1
+ in
+ (n, es @ [e2])
+ end
+ | _ => (ErrorMsg.errorAt loc ("Invalid " ^ newAttr
+ ^ " expression");
+ Print.epreface ("Expression",
+ CorePrint.p_exp CoreEnv.empty eOrig);
+ (0, []))
- val (f, args) = unravel e
+ val (f, args) = unravel e
- val (cn, count, tags, newTags) =
- case IM.find (tags, f) of
- NONE =>
- (count, count + 1, IM.insert (tags, f, count),
- (ek, f, count) :: newTags)
- | SOME cn => (cn, count, tags, newTags)
-
- val (_, _, _, s) = E.lookupENamed env f
+ val (cn, count, tags, newTags) =
+ case IM.find (tags, f) of
+ NONE =>
+ (count, count + 1, IM.insert (tags, f, count),
+ (ek, f, count) :: newTags)
+ | SOME cn => (cn, count, tags, newTags)
+
+ val (_, _, _, s) = E.lookupENamed env f
- val byTag = case SM.find (byTag, s) of
- NONE => SM.insert (byTag, s, (ek, f))
- | SOME (ek', f') =>
- (if f = f' then
- ()
- else
- ErrorMsg.errorAt loc
- ("Duplicate HTTP tag "
- ^ s);
- if ek = ek' then
- ()
- else
- both (loc, s);
- byTag)
+ val byTag = case SM.find (byTag, s) of
+ NONE => SM.insert (byTag, s, (ek, f))
+ | SOME (ek', f') =>
+ (if f = f' then
+ ()
+ else
+ ErrorMsg.errorAt loc
+ ("Duplicate HTTP tag "
+ ^ s);
+ if ek = ek' then
+ ()
+ else
+ both (loc, s);
+ byTag)
- val e = (EClosure (cn, args), loc)
- val t = (CFfi ("Basis", "string"), loc)
- in
- (((CName newAttr, loc), e, t),
- (count, tags, byTag, newTags))
- end
- in
- case x of
- (CName "Link", _) => tagIt (Link, "Link")
- | (CName "Action", _) => tagIt (Action ReadWrite, "Action")
- | _ => ((x, e, t), (count, tags, byTag, newTags))
- end)
- s xets
- in
- (EApp (
- (EApp (
- (EApp (
- (EApp (
+ val e = (EClosure (cn, args), loc)
+ in
+ (e, (count, tags, byTag, newTags))
+ end
+ in
+ case e of
+ EApp (
+ (EApp (
+ (EApp (
+ (EApp (
+ (ECApp (
+ (ECApp (
+ (ECApp (
+ (ECApp (
+ (ECApp (
+ (ECApp (
(ECApp (
(ECApp (
- (ECApp (
- (ECApp (
+ (EFfi ("Basis", "tag"),
+ loc), given), _), absent), _), outer), _), inner), _),
+ useOuter), _), useInner), _), bindOuter), _), bindInner), _),
+ class), _),
+ attrs), _),
+ tag), _),
+ xml) =>
+ (case attrs of
+ (ERecord xets, _) =>
+ let
+ val (xets, s) =
+ ListUtil.foldlMap (fn ((x, e, t), s) =>
+ let
+ fun tagIt' (ek, newAttr) =
+ let
+ val (e', s) = tagIt (e, ek, newAttr, s)
+ val t = (CFfi ("Basis", "string"), loc)
+ in
+ (((CName newAttr, loc), e', t), s)
+ end
+ in
+ case x of
+ (CName "Link", _) => tagIt' (Link, "Link")
+ | (CName "Action", _) => tagIt' (Action ReadWrite, "Action")
+ | _ => ((x, e, t), s)
+ end)
+ s xets
+ in
+ (EApp (
+ (EApp (
+ (EApp (
+ (EApp (
(ECApp (
(ECApp (
(ECApp (
(ECApp (
- (EFfi ("Basis", "tag"),
- loc), given), loc), absent), loc), outer), loc), inner), loc),
- useOuter), loc), useInner), loc), bindOuter), loc), bindInner), loc),
- class), loc),
- (ERecord xets, loc)), loc),
- tag), loc),
- xml), s)
- end
- | _ => (ErrorMsg.errorAt loc "Attribute record is too complex";
- (e, s)))
+ (ECApp (
+ (ECApp (
+ (ECApp (
+ (ECApp (
+ (EFfi ("Basis", "tag"),
+ loc), given), loc), absent), loc), outer), loc), inner), loc),
+ useOuter), loc), useInner), loc), bindOuter), loc), bindInner), loc),
+ class), loc),
+ (ERecord xets, loc)), loc),
+ tag), loc),
+ xml), s)
+ end
+ | _ => (ErrorMsg.errorAt loc "Attribute record is too complex";
+ (e, s)))
+
+ | EFfiApp ("Basis", "url", [(ERel 0, _)]) => (e, s)
- | _ => (e, s)
+ | EFfiApp ("Basis", "url", [e]) =>
+ let
+ val (e, s) = tagIt (e, Link, "Url", s)
+ in
+ (#1 e, s)
+ end
+
+ | EApp ((ENamed n, _), e') =>
+ let
+ val (_, _, eo, _) = E.lookupENamed env n
+ in
+ case eo of
+ SOME (EAbs (_, _, _, (EFfiApp ("Basis", "url", [(ERel 0, _)]), _)), _) =>
+ let
+ val (e, s) = tagIt (e', Link, "Url", s)
+ in
+ (#1 e, s)
+ end
+ | _ => (e, s)
+ end
+
+ | _ => (e, s)
+ end
fun decl (d, s) = (d, s)
diff --git a/tests/makeUrl.ur b/tests/makeUrl.ur
new file mode 100644
index 00000000..12026dab
--- /dev/null
+++ b/tests/makeUrl.ur
@@ -0,0 +1,3 @@
+fun other () = return Hi!
+
+fun main () = return {[Basis.url (main ())]}, {[url (other ())]}
diff --git a/tests/makeUrl.urp b/tests/makeUrl.urp
new file mode 100644
index 00000000..83451c4c
--- /dev/null
+++ b/tests/makeUrl.urp
@@ -0,0 +1,3 @@
+debug
+
+makeUrl
diff --git a/tests/makeUrl.urs b/tests/makeUrl.urs
new file mode 100644
index 00000000..6ac44e0b
--- /dev/null
+++ b/tests/makeUrl.urs
@@ -0,0 +1 @@
+val main : unit -> transaction page
diff --git a/tests/redirect.ur b/tests/redirect.ur
new file mode 100644
index 00000000..da5114ca
--- /dev/null
+++ b/tests/redirect.ur
@@ -0,0 +1,15 @@
+fun other () = redirect (bless "http://www.google.com/")
+
+fun further () = case checkUrl "http://www.google.com/" of
+ None => return Darn.
+ | Some url => redirect url
+
+fun failing () = case checkUrl "http://www.yahoo.com/" of
+ None => return Darn.
+ | Some url => redirect url
+
+fun main () = return
+ Go there
+ Go also there
+ Fail there
+
diff --git a/tests/redirect.urp b/tests/redirect.urp
new file mode 100644
index 00000000..670d3212
--- /dev/null
+++ b/tests/redirect.urp
@@ -0,0 +1,4 @@
+debug
+allow url http://www.google.com/
+
+redirect
diff --git a/tests/redirect.urs b/tests/redirect.urs
new file mode 100644
index 00000000..6ac44e0b
--- /dev/null
+++ b/tests/redirect.urs
@@ -0,0 +1 @@
+val main : unit -> transaction page
--
cgit v1.2.3
From b225596addee1a3cfd6c3189cff923e7f0e8f7c9 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sun, 13 Dec 2009 14:20:41 -0500
Subject: Initializers and setval
---
CHANGELOG | 1 +
lib/ur/basis.urs | 1 +
src/checknest.sml | 4 ++++
src/cjr.sml | 3 +++
src/cjr_env.sml | 1 +
src/cjr_print.sml | 23 ++++++++++++++++++++++-
src/cjrize.sml | 17 +++++++++++++++++
src/core.sml | 1 +
src/core_env.sml | 1 +
src/core_print.sml | 3 +++
src/core_util.sml | 8 +++++++-
src/corify.sml | 6 +++++-
src/elab.sml | 1 +
src/elab_env.sml | 1 +
src/elab_print.sml | 3 +++
src/elab_util.sml | 8 +++++++-
src/elaborate.sml | 10 ++++++++++
src/elisp/urweb-defs.el | 8 +++++---
src/elisp/urweb-mode.el | 4 ++--
src/expl.sml | 1 +
src/expl_env.sml | 1 +
src/expl_print.sml | 3 +++
src/explify.sml | 1 +
src/jscomp.sml | 8 ++++++++
src/mono.sml | 3 +++
src/mono_env.sml | 1 +
src/mono_print.sml | 9 +++++++++
src/mono_reduce.sml | 3 +++
src/mono_shake.sml | 42 +++++++++++++++++++++++++++++++-----------
src/mono_util.sml | 14 +++++++++++++-
src/monoize.sml | 15 +++++++++++++++
src/mysql.sml | 3 +++
src/postgres.sml | 43 +++++++++++++++++++++++++++++++++++++++++++
src/prepare.sml | 14 ++++++++++++++
src/reduce.sml | 9 +++++++++
src/reduce_local.sml | 1 +
src/scriptcheck.sml | 1 +
src/settings.sig | 1 +
src/settings.sml | 4 ++++
src/shake.sml | 7 +++++--
src/source.sml | 1 +
src/source_print.sml | 3 +++
src/sqlite.sml | 2 ++
src/unnest.sml | 1 +
src/urweb.grm | 3 ++-
src/urweb.lex | 1 +
tests/init.ur | 6 ++++++
tests/init.urp | 5 +++++
48 files changed, 286 insertions(+), 24 deletions(-)
create mode 100644 tests/init.ur
create mode 100644 tests/init.urp
(limited to 'src/mono.sml')
diff --git a/CHANGELOG b/CHANGELOG
index 15e92fd5..e1e14aea 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -6,6 +6,7 @@ Next
- More syntactic sugar for SQL
- Typing of SQL queries no longer exposes which tables were used in joins but
had none of their fields projected
+- Module-level initializers
========
20091203
diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs
index b9d1f55f..f7e098d4 100644
--- a/lib/ur/basis.urs
+++ b/lib/ur/basis.urs
@@ -523,6 +523,7 @@ val delete : fields ::: {Type} -> uniques ::: {{Unit}}
type sql_sequence
val nextval : sql_sequence -> transaction int
+val setval : sql_sequence -> int -> transaction unit
(** XML *)
diff --git a/src/checknest.sml b/src/checknest.sml
index 49519705..c0f843d6 100644
--- a/src/checknest.sml
+++ b/src/checknest.sml
@@ -87,6 +87,7 @@ fun expUses globals =
SOME {id, ...} => IS.add (s, id)
| _ => s
end
+ | ESetval {seq, count} => IS.union (eu seq, eu count)
| EUnurlify (e, _) => eu e
in
@@ -144,6 +145,9 @@ fun annotateExp globals =
| ENextval {seq, prepared} =>
(ENextval {seq = ae seq,
prepared = prepared}, loc)
+ | ESetval {seq, count} =>
+ (ESetval {seq = ae seq,
+ count = ae count}, loc)
| EUnurlify (e, t) => (EUnurlify (ae e, t), loc)
in
diff --git a/src/cjr.sml b/src/cjr.sml
index 2b8ce6fe..9be54670 100644
--- a/src/cjr.sml
+++ b/src/cjr.sml
@@ -95,6 +95,7 @@ datatype exp' =
prepared : {id : int, dml : string} option }
| ENextval of { seq : exp,
prepared : {id : int, query : string} option }
+ | ESetval of { seq : exp, count : exp }
| EUnurlify of exp * typ
withtype exp = exp' located
@@ -117,6 +118,8 @@ datatype decl' =
| DCookie of string
| DStyle of string
+ | DInitializer of exp
+
withtype decl = decl' located
datatype sidedness =
diff --git a/src/cjr_env.sml b/src/cjr_env.sml
index 217efb3a..e4d978d5 100644
--- a/src/cjr_env.sml
+++ b/src/cjr_env.sml
@@ -171,5 +171,6 @@ fun declBinds env (d, loc) =
| DJavaScript _ => env
| DCookie _ => env
| DStyle _ => env
+ | DInitializer _ => env
end
diff --git a/src/cjr_print.sml b/src/cjr_print.sml
index a1d5ed2c..6a5116ce 100644
--- a/src/cjr_print.sml
+++ b/src/cjr_print.sml
@@ -1849,6 +1849,20 @@ fun p_exp' par env (e, loc) =
newline,
string "})"]
+ | ESetval {seq, count} =>
+ box [string "({",
+ newline,
+
+ #setval (Settings.currentDbms ()) {loc = loc,
+ seqE = p_exp env seq,
+ count = p_exp env count},
+ newline,
+ newline,
+
+ string "uw_unit_v;",
+ newline,
+ string "})"]
+
| EUnurlify (e, t) =>
let
fun getIt () =
@@ -2085,6 +2099,8 @@ fun p_decl env (dAll as (d, _) : decl) =
space,
string "*/"]
+ | DInitializer _ => box []
+
datatype 'a search =
Found of 'a
| NotFound
@@ -2716,6 +2732,8 @@ fun p_file env (ds, ps) =
newline],
string "}",
newline]
+
+ val initializers = List.mapPartial (fn (DInitializer e, _) => SOME e | _ => NONE) ds
in
box [string "#include ",
newline,
@@ -2849,7 +2867,10 @@ fun p_file env (ds, ps) =
string "void uw_initializer(uw_context ctx) {",
newline,
- box [p_enamed env (!initialize),
+ box [p_list_sep (box []) (fn e => box [p_exp env e,
+ string ";",
+ newline]) initializers,
+ p_enamed env (!initialize),
string "(ctx, uw_unit_v);",
newline],
string "}",
diff --git a/src/cjrize.sml b/src/cjrize.sml
index 703b9477..3936f6a5 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -468,6 +468,13 @@ fun cifyExp (eAll as (e, loc), sm) =
in
((L'.ENextval {seq = e, prepared = NONE}, loc), sm)
end
+ | L.ESetval (e1, e2) =>
+ let
+ val (e1, sm) = cifyExp (e1, sm)
+ val (e2, sm) = cifyExp (e2, sm)
+ in
+ ((L'.ESetval {seq = e1, count = e2}, loc), sm)
+ end
| L.EUnurlify (e, t) =>
let
@@ -653,6 +660,16 @@ fun cifyDecl ((d, loc), sm) =
| L.DJavaScript s => (SOME (L'.DJavaScript s, loc), NONE, sm)
| L.DCookie args => (SOME (L'.DCookie args, loc), NONE, sm)
| L.DStyle args => (SOME (L'.DStyle args, loc), NONE, sm)
+ | L.DInitializer e =>
+ (case #1 e of
+ L.EAbs (_, _, _, e) =>
+ let
+ val (e, sm) = cifyExp (e, sm)
+ in
+ (SOME (L'.DInitializer e, loc), NONE, sm)
+ end
+ | _ => (ErrorMsg.errorAt loc "Initializer has not been fully determined";
+ (NONE, NONE, sm)))
fun cjrize ds =
let
diff --git a/src/core.sml b/src/core.sml
index 6bead3dc..a60bfd3b 100644
--- a/src/core.sml
+++ b/src/core.sml
@@ -134,6 +134,7 @@ datatype decl' =
| DDatabase of string
| DCookie of string * int * con * string
| DStyle of string * int * string
+ | DInitializer of exp
withtype decl = decl' located
diff --git a/src/core_env.sml b/src/core_env.sml
index e8cd139f..5e0af98c 100644
--- a/src/core_env.sml
+++ b/src/core_env.sml
@@ -348,6 +348,7 @@ fun declBinds env (d, loc) =
in
pushENamed env x n t NONE s
end
+ | DInitializer _ => env
fun patBinds env (p, loc) =
case p of
diff --git a/src/core_print.sml b/src/core_print.sml
index 02407f01..7dd43d56 100644
--- a/src/core_print.sml
+++ b/src/core_print.sml
@@ -611,6 +611,9 @@ fun p_decl env (dAll as (d, _) : decl) =
string "as",
space,
string s]
+ | DInitializer e => box [string "initializer",
+ space,
+ p_exp env e]
fun p_file env file =
let
diff --git a/src/core_util.sml b/src/core_util.sml
index cedde841..7ead1157 100644
--- a/src/core_util.sml
+++ b/src/core_util.sml
@@ -971,6 +971,10 @@ fun mapfoldB {kind = fk, con = fc, exp = fe, decl = fd, bind} =
fn c' =>
(DCookie (x, n, c', s), loc))
| DStyle _ => S.return2 dAll
+ | DInitializer e =>
+ S.map2 (mfe ctx e,
+ fn e' =>
+ (DInitializer e', loc))
and mfvi ctx (x, n, t, e, s) =
S.bind2 (mfc ctx t,
@@ -1125,6 +1129,7 @@ fun mapfoldB (all as {bind, ...}) =
in
bind (ctx, NamedE (x, n, t, NONE, s))
end
+ | DInitializer _ => ctx
in
S.map2 (mff ctx' ds',
fn ds' =>
@@ -1187,7 +1192,8 @@ val maxName = foldl (fn ((d, _) : decl, count) =>
| DView (_, n, _, _, _) => Int.max (n, count)
| DDatabase _ => count
| DCookie (_, n, _, _) => Int.max (n, count)
- | DStyle (_, n, _) => Int.max (n, count)) 0
+ | DStyle (_, n, _) => Int.max (n, count)
+ | DInitializer _ => count) 0
end
diff --git a/src/corify.sml b/src/corify.sml
index 9bf322f3..cc0500af 100644
--- a/src/corify.sml
+++ b/src/corify.sml
@@ -1064,6 +1064,9 @@ fun corifyDecl mods (all as (d, loc : EM.span), st) =
([(L'.DStyle (x, n, s), loc)], st)
end
+ | L.DInitializer e =>
+ ([(L'.DInitializer (corifyExp st e), loc)], st)
+
and corifyStr mods ((str, _), st) =
case str of
L.StrConst ds =>
@@ -1120,7 +1123,8 @@ fun maxName ds = foldl (fn ((d, _), n) =>
| L.DView (_, _, n', _, _) => Int.max (n, n')
| L.DDatabase _ => n
| L.DCookie (_, _, n', _) => Int.max (n, n')
- | L.DStyle (_, _, n') => Int.max (n, n'))
+ | L.DStyle (_, _, n') => Int.max (n, n')
+ | L.DInitializer _ => n)
0 ds
and maxNameStr (str, _) =
diff --git a/src/elab.sml b/src/elab.sml
index 76ea6725..1cd7aefa 100644
--- a/src/elab.sml
+++ b/src/elab.sml
@@ -170,6 +170,7 @@ datatype decl' =
| DDatabase of string
| DCookie of int * string * int * con
| DStyle of int * string * int
+ | DInitializer of exp
and str' =
StrConst of decl list
diff --git a/src/elab_env.sml b/src/elab_env.sml
index 4636fda8..763cf801 100644
--- a/src/elab_env.sml
+++ b/src/elab_env.sml
@@ -1622,5 +1622,6 @@ fun declBinds env (d, loc) =
in
pushENamedAs env x n t
end
+ | DInitializer _ => env
end
diff --git a/src/elab_print.sml b/src/elab_print.sml
index 3e4ea659..906c836d 100644
--- a/src/elab_print.sml
+++ b/src/elab_print.sml
@@ -799,6 +799,9 @@ fun p_decl env (dAll as (d, _) : decl) =
| DStyle (_, x, n) => box [string "style",
space,
p_named x n]
+ | DInitializer e => box [string "initializer",
+ space,
+ p_exp env e]
and p_str env (str, _) =
case str of
diff --git a/src/elab_util.sml b/src/elab_util.sml
index e7985026..2a044e71 100644
--- a/src/elab_util.sml
+++ b/src/elab_util.sml
@@ -853,7 +853,8 @@ fun mapfoldB {kind = fk, con = fc, exp = fe, sgn_item = fsgi, sgn = fsg, str = f
bind (ctx, NamedE (x, (CApp ((CModProj (n, [], "cookie"), loc),
c), loc)))
| DStyle (tn, x, n) =>
- bind (ctx, NamedE (x, (CModProj (n, [], "css_class"), loc))),
+ bind (ctx, NamedE (x, (CModProj (n, [], "css_class"), loc)))
+ | DInitializer _ => ctx,
mfd ctx d)) ctx ds,
fn ds' => (StrConst ds', loc))
| StrVar _ => S.return2 strAll
@@ -978,6 +979,10 @@ fun mapfoldB {kind = fk, con = fc, exp = fe, sgn_item = fsgi, sgn = fsg, str = f
fn c' =>
(DCookie (tn, x, n, c'), loc))
| DStyle _ => S.return2 dAll
+ | DInitializer e =>
+ S.map2 (mfe ctx e,
+ fn e' =>
+ (DInitializer e', loc))
and mfvi ctx (x, n, c, e) =
S.bind2 (mfc ctx c,
@@ -1120,6 +1125,7 @@ and maxNameDecl (d, _) =
| DDatabase _ => 0
| DCookie (n1, _, n2, _) => Int.max (n1, n2)
| DStyle (n1, _, n2) => Int.max (n1, n2)
+ | DInitializer _ => 0
and maxNameStr (str, _) =
case str of
StrConst ds => maxName ds
diff --git a/src/elaborate.sml b/src/elaborate.sml
index 71842ec2..327004e2 100644
--- a/src/elaborate.sml
+++ b/src/elaborate.sml
@@ -2548,6 +2548,7 @@ and sgiOfDecl (d, loc) =
| L'.DDatabase _ => []
| L'.DCookie (tn, x, n, c) => [(L'.SgiVal (x, n, (L'.CApp (cookieOf (), c), loc)), loc)]
| L'.DStyle (tn, x, n) => [(L'.SgiVal (x, n, styleOf ()), loc)]
+ | L'.DInitializer _ => []
and subSgn' counterparts env strLoc sgn1 (sgn2 as (_, loc2)) =
((*prefaces "subSgn" [("sgn1", p_sgn env sgn1),
@@ -3668,6 +3669,15 @@ and elabDecl (dAll as (d, loc), (env, denv, gs)) =
in
([(L'.DStyle (!basis_r, x, n), loc)], (env, denv, gs))
end
+ | L.DInitializer e =>
+ let
+ val (e', t, gs) = elabExp (env, denv) e
+ val t' = (L'.CApp ((L'.CModProj (!basis_r, [], "transaction"), loc),
+ (L'.TRecord (L'.CRecord ((L'.KType, loc), []), loc), loc)), loc)
+ in
+ checkCon env e' t t';
+ ([(L'.DInitializer e', loc)], (env, denv, gs))
+ end
(*val tcs = List.filter (fn TypeClass _ => true | _ => false) (#3 (#2 r))*)
in
diff --git a/src/elisp/urweb-defs.el b/src/elisp/urweb-defs.el
index e1382692..bb0e257d 100644
--- a/src/elisp/urweb-defs.el
+++ b/src/elisp/urweb-defs.el
@@ -108,7 +108,7 @@ notion of \"the end of an outline\".")
"datatype" "type" "open" "include"
urweb-module-head-syms
"con" "map" "where" "extern" "constraint" "constraints"
- "table" "sequence" "class" "cookie")
+ "table" "sequence" "class" "cookie" "initializer")
"Symbols starting an sexp.")
;; (defconst urweb-not-arg-start-re
@@ -134,7 +134,8 @@ notion of \"the end of an outline\".")
(,urweb-=-starter-syms nil)
(("case" "datatype" "if" "then" "else"
"let" "open" "sig" "struct" "type" "val"
- "con" "constraint" "table" "sequence" "class" "cookie")))))
+ "con" "constraint" "table" "sequence" "class" "cookie"
+ "initializer")))))
(defconst urweb-starters-indent-after
(urweb-syms-re "let" "in" "struct" "sig")
@@ -188,7 +189,8 @@ for all symbols and in all lines starting with the given symbol."
(append urweb-module-head-syms
'("datatype" "fun"
"open" "type" "val" "and"
- "con" "constraint" "table" "sequence" "class" "cookie"))
+ "con" "constraint" "table" "sequence" "class" "cookie"
+ "initializer"))
"The starters of new expressions.")
(defconst urweb-exptrail-syms
diff --git a/src/elisp/urweb-mode.el b/src/elisp/urweb-mode.el
index 72005af9..ab274f22 100644
--- a/src/elisp/urweb-mode.el
+++ b/src/elisp/urweb-mode.el
@@ -136,7 +136,7 @@ See doc for the variable `urweb-mode-info'."
"datatype" "else" "end" "extern" "fn" "map"
"fun" "functor" "if" "include"
"of" "open" "let" "in"
- "rec" "sequence" "sig" "signature" "cookie" "style"
+ "rec" "sequence" "sig" "signature" "cookie" "style" "initializer"
"struct" "structure" "table" "view" "then" "type" "val" "where"
"with"
@@ -226,7 +226,7 @@ See doc for the variable `urweb-mode-info'."
("\\<\\(\\(data\\)?type\\|con\\|class\\)\\s-+\\(\\sw+\\)"
(1 font-lock-keyword-face)
(3 (amAttribute font-lock-type-def-face)))
- ("\\<\\(val\\|table\\|sequence\\|cookie\\|style\\)\\s-+\\(\\sw+\\>\\s-*\\)?\\(\\sw+\\)\\s-*[=:]"
+ ("\\<\\(val\\|table\\|sequence\\|cookie\\|style\\|initializer\\)\\s-+\\(\\sw+\\>\\s-*\\)?\\(\\sw+\\)\\s-*[=:]"
(1 font-lock-keyword-face)
(3 (amAttribute font-lock-variable-name-face)))
("\\<\\(structure\\|functor\\)\\s-+\\(\\sw+\\)"
diff --git a/src/expl.sml b/src/expl.sml
index 4a9acd8a..eb79e2b0 100644
--- a/src/expl.sml
+++ b/src/expl.sml
@@ -147,6 +147,7 @@ datatype decl' =
| DDatabase of string
| DCookie of int * string * int * con
| DStyle of int * string * int
+ | DInitializer of exp
and str' =
StrConst of decl list
diff --git a/src/expl_env.sml b/src/expl_env.sml
index 836af42c..f16eeb8e 100644
--- a/src/expl_env.sml
+++ b/src/expl_env.sml
@@ -343,6 +343,7 @@ fun declBinds env (d, loc) =
in
pushENamed env x n t
end
+ | DInitializer _ => env
fun sgiBinds env (sgi, loc) =
case sgi of
diff --git a/src/expl_print.sml b/src/expl_print.sml
index 0783facc..624afa63 100644
--- a/src/expl_print.sml
+++ b/src/expl_print.sml
@@ -713,6 +713,9 @@ fun p_decl env (dAll as (d, _) : decl) =
| DStyle (_, x, n) => box [string "style",
space,
p_named x n]
+ | DInitializer e => box [string "initializer",
+ space,
+ p_exp env e]
and p_str env (str, _) =
case str of
diff --git a/src/explify.sml b/src/explify.sml
index 3ec588fa..d66b3530 100644
--- a/src/explify.sml
+++ b/src/explify.sml
@@ -195,6 +195,7 @@ fun explifyDecl (d, loc : EM.span) =
| L.DDatabase s => SOME (L'.DDatabase s, loc)
| L.DCookie (nt, x, n, c) => SOME (L'.DCookie (nt, x, n, explifyCon c), loc)
| L.DStyle (nt, x, n) => SOME (L'.DStyle (nt, x, n), loc)
+ | L.DInitializer e => SOME (L'.DInitializer (explifyExp e), loc)
and explifyStr (str, loc) =
case str of
diff --git a/src/jscomp.sml b/src/jscomp.sml
index 471711d2..ca20e71d 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -868,6 +868,7 @@ fun process file =
| EQuery _ => unsupported "Query"
| EDml _ => unsupported "DML"
| ENextval _ => unsupported "Nextval"
+ | ESetval _ => unsupported "Nextval"
| EUnurlify _ => unsupported "EUnurlify"
| EReturnBlob _ => unsupported "EUnurlify"
| ERedirect _ => unsupported "ERedirect"
@@ -1142,6 +1143,13 @@ fun process file =
in
((ENextval e, loc), st)
end
+ | ESetval (e1, e2) =>
+ let
+ val (e1, st) = exp outer (e1, st)
+ val (e2, st) = exp outer (e2, st)
+ in
+ ((ESetval (e1, e2), loc), st)
+ end
| EUnurlify (e, t) =>
let
diff --git a/src/mono.sml b/src/mono.sml
index 92424ee3..1962c6c5 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -106,6 +106,7 @@ datatype exp' =
initial : exp }
| EDml of exp
| ENextval of exp
+ | ESetval of exp * exp
| EUnurlify of exp * typ
@@ -138,6 +139,8 @@ datatype decl' =
| DCookie of string
| DStyle of string
+ | DInitializer of exp
+
withtype decl = decl' located
type file = decl list
diff --git a/src/mono_env.sml b/src/mono_env.sml
index 3114176d..6ffab153 100644
--- a/src/mono_env.sml
+++ b/src/mono_env.sml
@@ -129,6 +129,7 @@ fun declBinds env (d, loc) =
| DJavaScript _ => env
| DCookie _ => env
| DStyle _ => env
+ | DInitializer _ => env
fun patBinds env (p, loc) =
case p of
diff --git a/src/mono_print.sml b/src/mono_print.sml
index cfaa410b..13c45329 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -320,6 +320,12 @@ fun p_exp' par env (e, _) =
| ENextval e => box [string "nextval(",
p_exp env e,
string ")"]
+ | ESetval (e1, e2) => box [string "setval(",
+ p_exp env e1,
+ string ",",
+ space,
+ p_exp env e2,
+ string ")"]
| EUnurlify (e, _) => box [string "unurlify(",
p_exp env e,
string ")"]
@@ -485,6 +491,9 @@ fun p_decl env (dAll as (d, _) : decl) =
| DStyle s => box [string "style",
space,
string s]
+ | DInitializer e => box [string "initializer",
+ space,
+ p_exp env e]
fun p_file env file =
diff --git a/src/mono_reduce.sml b/src/mono_reduce.sml
index f29117cf..aa6b7051 100644
--- a/src/mono_reduce.sml
+++ b/src/mono_reduce.sml
@@ -51,6 +51,7 @@ fun simpleImpure (tsyms, syms) =
| EQuery _ => true
| EDml _ => true
| ENextval _ => true
+ | ESetval _ => true
| EFfiApp (m, x, _) => Settings.isEffectful (m, x)
| EServerCall _ => true
| ERecv _ => true
@@ -75,6 +76,7 @@ fun impure (e, _) =
| EQuery _ => true
| EDml _ => true
| ENextval _ => true
+ | ESetval _ => true
| EUnurlify _ => true
| EAbs _ => false
@@ -448,6 +450,7 @@ fun reduce file =
| EDml e => summarize d e @ [WriteDb]
| ENextval e => summarize d e @ [WriteDb]
+ | ESetval (e1, e2) => summarize d e1 @ summarize d e2 @ [WriteDb]
| EUnurlify (e, _) => summarize d e
| EJavaScript (_, e) => summarize d e
| ESignalReturn e => summarize d e
diff --git a/src/mono_shake.sml b/src/mono_shake.sml
index 40b83934..fc46cf96 100644
--- a/src/mono_shake.sml
+++ b/src/mono_shake.sml
@@ -43,10 +43,22 @@ type free = {
fun shake file =
let
- val page_es = List.foldl
- (fn ((DExport (_, _, n, _, _), _), page_es) => n :: page_es
- | ((DDatabase {expunge = n1, initialize = n2, ...}, _), page_es) => n1 :: n2 :: page_es
- | (_, page_es) => page_es) [] file
+ val usedVars = U.Exp.fold {typ = fn (c, st as (cs, es)) =>
+ case c of
+ TDatatype (n, _) => (IS.add (cs, n), es)
+ | _ => st,
+ exp = fn (e, st as (cs, es)) =>
+ case e of
+ ENamed n => (cs, IS.add (es, n))
+ | _ => st}
+
+ val (page_cs, page_es) =
+ List.foldl
+ (fn ((DExport (_, _, n, _, _), _), (page_cs, page_es)) => (page_cs, IS.add (page_es, n))
+ | ((DDatabase {expunge = n1, initialize = n2, ...}, _), (page_cs, page_es)) =>
+ (page_cs, IS.addList (page_es, [n1, n2]))
+ | ((DInitializer e, _), st) => usedVars st e
+ | (_, st) => st) (IS.empty, IS.empty) file
val (cdef, edef) = foldl (fn ((DDatatype dts, _), (cdef, edef)) =>
(foldl (fn ((_, n, xncs), cdef) => IM.insert (cdef, n, xncs)) cdef dts, edef)
@@ -61,7 +73,8 @@ fun shake file =
| ((DDatabase _, _), acc) => acc
| ((DJavaScript _, _), acc) => acc
| ((DCookie _, _), acc) => acc
- | ((DStyle _, _), acc) => acc)
+ | ((DStyle _, _), acc) => acc
+ | ((DInitializer _, _), acc) => acc)
(IM.empty, IM.empty) file
fun typ (c, s) =
@@ -104,12 +117,18 @@ fun shake file =
and shakeExp s = U.Exp.fold {typ = typ, exp = exp} s
- val s = {con = IS.empty, exp = IS.addList (IS.empty, page_es)}
+ val s = {con = page_cs, exp = page_es}
+
+ val s = IS.foldl (fn (n, s) =>
+ case IM.find (cdef, n) of
+ NONE => raise Fail "MonoShake: Couldn't find 'datatype'"
+ | SOME xncs => foldl (fn ((_, _, SOME c), s) => shakeTyp s c
+ | _ => s) s xncs) s page_cs
- val s = foldl (fn (n, s) =>
- case IM.find (edef, n) of
- NONE => raise Fail "Shake: Couldn't find 'val'"
- | SOME (t, e) => shakeExp s e) s page_es
+ val s = IS.foldl (fn (n, s) =>
+ case IM.find (edef, n) of
+ NONE => raise Fail "MonoShake: Couldn't find 'val'"
+ | SOME (t, e) => shakeExp s e) s page_es
in
List.filter (fn (DDatatype dts, _) => List.exists (fn (_, n, _) => IS.member (#con s, n)) dts
| (DVal (_, n, _, _, _), _) => IS.member (#exp s, n)
@@ -121,7 +140,8 @@ fun shake file =
| (DDatabase _, _) => true
| (DJavaScript _, _) => true
| (DCookie _, _) => true
- | (DStyle _, _) => true) file
+ | (DStyle _, _) => true
+ | (DInitializer _, _) => true) file
end
end
diff --git a/src/mono_util.sml b/src/mono_util.sml
index 91b4412e..184ce168 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -340,6 +340,12 @@ fun mapfoldB {typ = fc, exp = fe, bind} =
S.map2 (mfe ctx e,
fn e' =>
(ENextval e', loc))
+ | ESetval (e1, e2) =>
+ S.bind2 (mfe ctx e1,
+ fn e1' =>
+ S.map2 (mfe ctx e2,
+ fn e2' =>
+ (ESetval (e1', e2'), loc)))
| EUnurlify (e, t) =>
S.bind2 (mfe ctx e,
fn e' =>
@@ -522,6 +528,10 @@ fun mapfoldB {typ = fc, exp = fe, decl = fd, bind} =
| DJavaScript _ => S.return2 dAll
| DCookie _ => S.return2 dAll
| DStyle _ => S.return2 dAll
+ | DInitializer e =>
+ S.map2 (mfe ctx e,
+ fn e' =>
+ (DInitializer e', loc))
and mfvi ctx (x, n, t, e, s) =
S.bind2 (mft t,
@@ -608,6 +618,7 @@ fun mapfoldB (all as {bind, ...}) =
| DJavaScript _ => ctx
| DCookie _ => ctx
| DStyle _ => ctx
+ | DInitializer _ => ctx
in
S.map2 (mff ctx' ds',
fn ds' =>
@@ -660,7 +671,8 @@ val maxName = foldl (fn ((d, _) : decl, count) =>
| DDatabase _ => count
| DJavaScript _ => count
| DCookie _ => count
- | DStyle _ => count) 0
+ | DStyle _ => count
+ | DInitializer _ => count) 0
end
diff --git a/src/monoize.sml b/src/monoize.sml
index b92b9c70..503fd6b3 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -2475,6 +2475,13 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
in
((L'.ENextval e, loc), fm)
end
+ | L.EFfiApp ("Basis", "setval", [e1, e2]) =>
+ let
+ val (e1, fm) = monoExp (env, st, fm) e1
+ val (e2, fm) = monoExp (env, st, fm) e2
+ in
+ ((L'.ESetval (e1, e2), loc), fm)
+ end
| L.EApp (
(L.ECApp (
@@ -3471,6 +3478,14 @@ fun monoDecl (env, fm) (all as (d, loc)) =
[(L'.DStyle s, loc),
(L'.DVal (x, n, t', e, s), loc)])
end
+ | L.DInitializer e =>
+ let
+ val (e, fm) = monoExp (env, St.empty, fm) e
+ in
+ SOME (env,
+ fm,
+ [(L'.DInitializer e, loc)])
+ end
end
datatype expungable = Client | Channel
diff --git a/src/mysql.sml b/src/mysql.sml
index 514a9257..40409ff0 100644
--- a/src/mysql.sml
+++ b/src/mysql.sml
@@ -1503,6 +1503,8 @@ fun nextval {loc, seqE, seqName} =
fun nextvalPrepared _ = raise Fail "MySQL.nextvalPrepared called"
+fun setval _ = raise Fail "MySQL.setval called"
+
fun sqlifyString s = "'" ^ String.translate (fn #"'" => "\\'"
| #"\\" => "\\\\"
| ch =>
@@ -1529,6 +1531,7 @@ val () = addDbms {name = "mysql",
dmlPrepared = dmlPrepared,
nextval = nextval,
nextvalPrepared = nextvalPrepared,
+ setval = setval,
sqlifyString = sqlifyString,
p_cast = p_cast,
p_blank = p_blank,
diff --git a/src/postgres.sml b/src/postgres.sml
index 51e856db..c4bbb067 100644
--- a/src/postgres.sml
+++ b/src/postgres.sml
@@ -867,6 +867,48 @@ fun nextvalPrepared {loc, id, query} =
string (String.toString query),
string "\""]}]
+fun setvalCommon {loc, query} =
+ box [string "if (res == NULL) uw_error(ctx, FATAL, \"Out of memory allocating setval result.\");",
+ newline,
+ newline,
+
+ string "if (PQresultStatus(res) != PGRES_TUPLES_OK) {",
+ newline,
+ box [string "PQclear(res);",
+ newline,
+ string "uw_error(ctx, FATAL, \"",
+ string (ErrorMsg.spanToString loc),
+ string ": Query failed:\\n%s\\n%s\", ",
+ query,
+ string ", PQerrorMessage(conn));",
+ newline],
+ string "}",
+ newline,
+ newline,
+
+ string "PQclear(res);",
+ newline]
+
+fun setval {loc, seqE, count} =
+ let
+ val query = box [string "uw_Basis_strcat(ctx, \"SELECT SETVAL('\", uw_Basis_strcat(ctx, ",
+ seqE,
+ string ", uw_Basis_strcat(ctx, \"', \", uw_Basis_strcat(ctx, uw_Basis_sqlifyInt(ctx, ",
+ count,
+ string "), \")\"))))"]
+ in
+ box [string "char *query = ",
+ query,
+ string ";",
+ newline,
+ string "PGconn *conn = uw_get_db(ctx);",
+ newline,
+ string "PGresult *res = PQexecParams(conn, query, 0, NULL, NULL, NULL, NULL, 0);",
+ newline,
+ newline,
+ setvalCommon {loc = loc, query = string "query"}]
+ end
+
fun sqlifyString s = "E'" ^ String.translate (fn #"'" => "\\'"
| #"\\" => "\\\\"
| ch =>
@@ -892,6 +934,7 @@ val () = addDbms {name = "postgres",
dmlPrepared = dmlPrepared,
nextval = nextval,
nextvalPrepared = nextvalPrepared,
+ setval = setval,
sqlifyString = sqlifyString,
p_cast = p_cast,
p_blank = p_blank,
diff --git a/src/prepare.sml b/src/prepare.sml
index 58344a1f..7cbd7d76 100644
--- a/src/prepare.sml
+++ b/src/prepare.sml
@@ -273,6 +273,14 @@ fun prepExp (e as (_, loc), st) =
else
(e, st)
+ | ESetval {seq = e1, count = e2} =>
+ let
+ val (e1, st) = prepExp (e1, st)
+ val (e2, st) = prepExp (e2, st)
+ in
+ ((ESetval {seq = e1, count = e2}, loc), st)
+ end
+
| EUnurlify (e, t) =>
let
val (e, st) = prepExp (e, st)
@@ -317,6 +325,12 @@ fun prepDecl (d as (_, loc), st) =
| DJavaScript _ => (d, st)
| DCookie _ => (d, st)
| DStyle _ => (d, st)
+ | DInitializer e =>
+ let
+ val (e, st) = prepExp (e, st)
+ in
+ ((DInitializer e, loc), st)
+ end
fun prepare (ds, ps) =
let
diff --git a/src/reduce.sml b/src/reduce.sml
index 1310c7d0..cedb79fa 100644
--- a/src/reduce.sml
+++ b/src/reduce.sml
@@ -804,6 +804,15 @@ fun reduce file =
| DDatabase _ => (d, st)
| DCookie (s, n, c, s') => ((DCookie (s, n, con namedC [] c, s'), loc), st)
| DStyle (s, n, s') => ((DStyle (s, n, s'), loc), st)
+ | DInitializer e =>
+ let
+ val e = exp (namedC, namedE) [] e
+ in
+ ((DInitializer e, loc),
+ (polyC,
+ namedC,
+ namedE))
+ end
val (file, _) = ListUtil.foldlMap doDecl (IS.empty, IM.empty, IM.empty) file
in
diff --git a/src/reduce_local.sml b/src/reduce_local.sml
index 4ddddfbf..82490118 100644
--- a/src/reduce_local.sml
+++ b/src/reduce_local.sml
@@ -251,6 +251,7 @@ fun reduce file =
| DDatabase _ => d
| DCookie _ => d
| DStyle _ => d
+ | DInitializer e => (DInitializer (exp [] e), loc)
in
map doDecl file
end
diff --git a/src/scriptcheck.sml b/src/scriptcheck.sml
index 6dc11c65..5cd056d5 100644
--- a/src/scriptcheck.sml
+++ b/src/scriptcheck.sml
@@ -114,6 +114,7 @@ fun classify (ds, ps) =
orelse hasClient initial
| EDml {dml, ...} => hasClient dml
| ENextval {seq, ...} => hasClient seq
+ | ESetval {seq, count, ...} => hasClient seq orelse hasClient count
| EUnurlify (e, _) => hasClient e
in
hasClient
diff --git a/src/settings.sig b/src/settings.sig
index 61095ff8..574832a2 100644
--- a/src/settings.sig
+++ b/src/settings.sig
@@ -147,6 +147,7 @@ signature SETTINGS = sig
inputs : sql_type list} -> Print.PD.pp_desc,
nextval : {loc : ErrorMsg.span, seqE : Print.PD.pp_desc, seqName : string option} -> Print.PD.pp_desc,
nextvalPrepared : {loc : ErrorMsg.span, id : int, query : string} -> Print.PD.pp_desc,
+ setval : {loc : ErrorMsg.span, seqE : Print.PD.pp_desc, count : Print.PD.pp_desc} -> Print.PD.pp_desc,
sqlifyString : string -> string,
p_cast : string * sql_type -> string,
p_blank : int * sql_type -> string (* Prepared statement input *),
diff --git a/src/settings.sml b/src/settings.sml
index f5d5a3ab..a7f2cc9f 100644
--- a/src/settings.sml
+++ b/src/settings.sml
@@ -79,6 +79,7 @@ fun mayClientToServer x = S.member (!clientToServer, x)
val effectfulBase = basis ["dml",
"nextval",
+ "setval",
"set_cookie",
"clear_cookie",
"new_client_source",
@@ -120,6 +121,7 @@ val serverBase = basis ["requestHeader",
"query",
"dml",
"nextval",
+ "setval",
"channel",
"send"]
val server = ref serverBase
@@ -355,6 +357,7 @@ type dbms = {
inputs : sql_type list} -> Print.PD.pp_desc,
nextval : {loc : ErrorMsg.span, seqName : string option, seqE : Print.PD.pp_desc} -> Print.PD.pp_desc,
nextvalPrepared : {loc : ErrorMsg.span, id : int, query : string} -> Print.PD.pp_desc,
+ setval : {loc : ErrorMsg.span, seqE : Print.PD.pp_desc, count : Print.PD.pp_desc} -> Print.PD.pp_desc,
sqlifyString : string -> string,
p_cast : string * sql_type -> string,
p_blank : int * sql_type -> string,
@@ -382,6 +385,7 @@ val curDb = ref ({name = "",
dmlPrepared = fn _ => Print.box [],
nextval = fn _ => Print.box [],
nextvalPrepared = fn _ => Print.box [],
+ setval = fn _ => Print.box [],
sqlifyString = fn s => s,
p_cast = fn _ => "",
p_blank = fn _ => "",
diff --git a/src/shake.sml b/src/shake.sml
index dde131fc..787500ea 100644
--- a/src/shake.sml
+++ b/src/shake.sml
@@ -79,6 +79,7 @@ fun shake file =
in
(usedE, usedC)
end
+ | ((DInitializer e, _), st) => usedVars st e
| (_, acc) => acc) (IS.empty, IS.empty) file
val (cdef, edef) = foldl (fn ((DCon (_, n, _, c), _), (cdef, edef)) => (IM.insert (cdef, n, [c]), edef)
@@ -104,7 +105,8 @@ fun shake file =
| ((DCookie (_, n, c, _), _), (cdef, edef)) =>
(cdef, IM.insert (edef, n, ([], c, dummye)))
| ((DStyle (_, n, _), _), (cdef, edef)) =>
- (cdef, IM.insert (edef, n, ([], dummyt, dummye))))
+ (cdef, IM.insert (edef, n, ([], dummyt, dummye)))
+ | ((DInitializer _, _), acc) => acc)
(IM.empty, IM.empty) file
fun kind (_, s) = s
@@ -183,7 +185,8 @@ fun shake file =
| (DTable _, _) => true
| (DDatabase _, _) => true
| (DCookie _, _) => true
- | (DStyle _, _) => true) file
+ | (DStyle _, _) => true
+ | (DInitializer _, _) => true) file
end
end
diff --git a/src/source.sml b/src/source.sml
index c5950b36..e52872f0 100644
--- a/src/source.sml
+++ b/src/source.sml
@@ -167,6 +167,7 @@ datatype decl' =
| DDatabase of string
| DCookie of string * con
| DStyle of string
+ | DInitializer of exp
and str' =
StrConst of decl list
diff --git a/src/source_print.sml b/src/source_print.sml
index 7ec584d7..31fc2500 100644
--- a/src/source_print.sml
+++ b/src/source_print.sml
@@ -662,6 +662,9 @@ fun p_decl ((d, _) : decl) =
| DStyle x => box [string "style",
space,
string x]
+ | DInitializer e => box [string "initializer",
+ space,
+ p_exp e]
and p_str (str, _) =
case str of
diff --git a/src/sqlite.sml b/src/sqlite.sml
index 8a61c25e..440c7c28 100644
--- a/src/sqlite.sml
+++ b/src/sqlite.sml
@@ -757,6 +757,7 @@ fun nextval {loc, seqE, seqName} =
newline]
fun nextvalPrepared _ = raise Fail "SQLite.nextvalPrepared called"
+fun setval _ = raise Fail "SQLite.setval called"
fun sqlifyString s = "'" ^ String.translate (fn #"'" => "''"
| ch =>
@@ -783,6 +784,7 @@ val () = addDbms {name = "sqlite",
dmlPrepared = dmlPrepared,
nextval = nextval,
nextvalPrepared = nextvalPrepared,
+ setval = setval,
sqlifyString = sqlifyString,
p_cast = p_cast,
p_blank = p_blank,
diff --git a/src/unnest.sml b/src/unnest.sml
index a4bdb7a9..c4d9a8b5 100644
--- a/src/unnest.sml
+++ b/src/unnest.sml
@@ -422,6 +422,7 @@ fun unnest file =
| DDatabase _ => default ()
| DCookie _ => default ()
| DStyle _ => default ()
+ | DInitializer _ => explore ()
end
and doStr (all as (str, loc), st) =
diff --git a/src/urweb.grm b/src/urweb.grm
index 87a8547d..8780d9f6 100644
--- a/src/urweb.grm
+++ b/src/urweb.grm
@@ -201,7 +201,7 @@ fun patType loc (p : pat) =
| LET | IN
| STRUCTURE | SIGNATURE | STRUCT | SIG | END | FUNCTOR | WHERE | EXTERN | SQL | SELECT1
| INCLUDE | OPEN | CONSTRAINT | CONSTRAINTS | EXPORT | TABLE | SEQUENCE | VIEW
- | COOKIE | STYLE
+ | COOKIE | STYLE | INITIALIZER
| CASE | IF | THEN | ELSE | ANDALSO | ORELSE
| XML_BEGIN of string | XML_END | XML_BEGIN_END of string
@@ -479,6 +479,7 @@ decl : CON SYMBOL cargl2 kopt EQ cexp (let
end)
| COOKIE SYMBOL COLON cexp ([(DCookie (SYMBOL, cexp), s (COOKIEleft, cexpright))])
| STYLE SYMBOL ([(DStyle SYMBOL, s (STYLEleft, SYMBOLright))])
+ | INITIALIZER eexp ([(DInitializer eexp, s (INITIALIZERleft, eexpright))])
dtype : SYMBOL dargs EQ barOpt dcons (SYMBOL, dargs, dcons)
diff --git a/src/urweb.lex b/src/urweb.lex
index ed6e310b..d04822f7 100644
--- a/src/urweb.lex
+++ b/src/urweb.lex
@@ -402,6 +402,7 @@ notags = [^<{\n]+;
"class" => (Tokens.CLASS (pos yypos, pos yypos + size yytext));
"cookie" => (Tokens.COOKIE (pos yypos, pos yypos + size yytext));
"style" => (Tokens.STYLE (pos yypos, pos yypos + size yytext));
+ "initializer" => (Tokens.INITIALIZER (pos yypos, pos yypos + size yytext));
"Type" => (Tokens.TYPE (pos yypos, pos yypos + size yytext));
"Name" => (Tokens.NAME (pos yypos, pos yypos + size yytext));
diff --git a/tests/init.ur b/tests/init.ur
new file mode 100644
index 00000000..0a44a9e4
--- /dev/null
+++ b/tests/init.ur
@@ -0,0 +1,6 @@
+sequence seq
+table fred : {A : int, B : int}
+
+initializer
+ setval seq 1;
+ dml (INSERT INTO fred (A, B) VALUES (0, 1))
diff --git a/tests/init.urp b/tests/init.urp
new file mode 100644
index 00000000..a2166e44
--- /dev/null
+++ b/tests/init.urp
@@ -0,0 +1,5 @@
+debug
+database dbname=init
+sql init.sql
+
+init
--
cgit v1.2.3
From 6179a09d47c5af4db1ac41d00b8cb7ec36741c3e Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Tue, 15 Dec 2009 10:19:05 -0500
Subject: Convert to task syntax
---
CHANGELOG | 2 +-
lib/ur/basis.urs | 6 ++++++
src/cjr.sml | 4 +++-
src/cjr_env.sml | 2 +-
src/cjr_print.sml | 4 ++--
src/cjrize.sml | 10 +++++++---
src/core.sml | 2 +-
src/core_env.sml | 2 +-
src/core_print.sml | 8 ++++++--
src/core_util.sml | 14 ++++++++------
src/corify.sml | 6 +++---
src/elab.sml | 2 +-
src/elab_env.sml | 2 +-
src/elab_print.sml | 8 ++++++--
src/elab_util.sml | 14 ++++++++------
src/elaborate.sml | 18 +++++++++++-------
src/elisp/urweb-defs.el | 6 +++---
src/elisp/urweb-mode.el | 4 ++--
src/expl.sml | 2 +-
src/expl_env.sml | 2 +-
src/expl_print.sml | 8 ++++++--
src/explify.sml | 2 +-
src/mono.sml | 2 +-
src/mono_env.sml | 2 +-
src/mono_print.sml | 8 ++++++--
src/mono_shake.sml | 6 +++---
src/mono_util.sml | 14 ++++++++------
src/monoize.sml | 7 ++++---
src/prepare.sml | 4 ++--
src/reduce.sml | 7 ++++---
src/reduce_local.sml | 2 +-
src/shake.sml | 6 +++---
src/source.sml | 2 +-
src/source_print.sml | 8 ++++++--
src/unnest.sml | 2 +-
src/urweb.grm | 4 ++--
src/urweb.lex | 2 +-
tests/init.ur | 2 +-
38 files changed, 125 insertions(+), 81 deletions(-)
(limited to 'src/mono.sml')
diff --git a/CHANGELOG b/CHANGELOG
index e1e14aea..ec2eda90 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -6,7 +6,7 @@ Next
- More syntactic sugar for SQL
- Typing of SQL queries no longer exposes which tables were used in joins but
had none of their fields projected
-- Module-level initializers
+- Tasks
========
20091203
diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs
index f7e098d4..f550ce67 100644
--- a/lib/ur/basis.urs
+++ b/lib/ur/basis.urs
@@ -757,3 +757,9 @@ val onDisconnect : transaction unit -> transaction unit
val onServerError : (string -> transaction unit) -> transaction unit
val show_xml : ctx ::: {Unit} -> use ::: {Type} -> bind ::: {Type} -> show (xml ctx use bind)
+
+
+(** Tasks *)
+
+type task_kind
+val initialize : task_kind
diff --git a/src/cjr.sml b/src/cjr.sml
index 9be54670..f5392d49 100644
--- a/src/cjr.sml
+++ b/src/cjr.sml
@@ -100,6 +100,8 @@ datatype exp' =
withtype exp = exp' located
+datatype task = Initialize
+
datatype decl' =
DStruct of int * (string * typ) list
| DDatatype of (datatype_kind * string * int * (string * int * typ option) list) list
@@ -118,7 +120,7 @@ datatype decl' =
| DCookie of string
| DStyle of string
- | DInitializer of exp
+ | DTask of task * exp
withtype decl = decl' located
diff --git a/src/cjr_env.sml b/src/cjr_env.sml
index e4d978d5..ac83f263 100644
--- a/src/cjr_env.sml
+++ b/src/cjr_env.sml
@@ -171,6 +171,6 @@ fun declBinds env (d, loc) =
| DJavaScript _ => env
| DCookie _ => env
| DStyle _ => env
- | DInitializer _ => env
+ | DTask _ => env
end
diff --git a/src/cjr_print.sml b/src/cjr_print.sml
index 6a5116ce..2d547519 100644
--- a/src/cjr_print.sml
+++ b/src/cjr_print.sml
@@ -2099,7 +2099,7 @@ fun p_decl env (dAll as (d, _) : decl) =
space,
string "*/"]
- | DInitializer _ => box []
+ | DTask _ => box []
datatype 'a search =
Found of 'a
@@ -2733,7 +2733,7 @@ fun p_file env (ds, ps) =
string "}",
newline]
- val initializers = List.mapPartial (fn (DInitializer e, _) => SOME e | _ => NONE) ds
+ val initializers = List.mapPartial (fn (DTask (Initialize, e), _) => SOME e | _ => NONE) ds
in
box [string "#include ",
newline,
diff --git a/src/cjrize.sml b/src/cjrize.sml
index 3936f6a5..0136bdf6 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -660,13 +660,17 @@ fun cifyDecl ((d, loc), sm) =
| L.DJavaScript s => (SOME (L'.DJavaScript s, loc), NONE, sm)
| L.DCookie args => (SOME (L'.DCookie args, loc), NONE, sm)
| L.DStyle args => (SOME (L'.DStyle args, loc), NONE, sm)
- | L.DInitializer e =>
- (case #1 e of
+ | L.DTask (e1, e2) =>
+ (case #1 e2 of
L.EAbs (_, _, _, e) =>
let
+ val tk = case #1 e1 of
+ L.EFfi ("Basis", "initialize") => L'.Initialize
+ | _ => (ErrorMsg.errorAt loc "Task kind not fully determined";
+ L'.Initialize)
val (e, sm) = cifyExp (e, sm)
in
- (SOME (L'.DInitializer e, loc), NONE, sm)
+ (SOME (L'.DTask (tk, e), loc), NONE, sm)
end
| _ => (ErrorMsg.errorAt loc "Initializer has not been fully determined";
(NONE, NONE, sm)))
diff --git a/src/core.sml b/src/core.sml
index a60bfd3b..78a1eded 100644
--- a/src/core.sml
+++ b/src/core.sml
@@ -134,7 +134,7 @@ datatype decl' =
| DDatabase of string
| DCookie of string * int * con * string
| DStyle of string * int * string
- | DInitializer of exp
+ | DTask of exp * exp
withtype decl = decl' located
diff --git a/src/core_env.sml b/src/core_env.sml
index 5e0af98c..4c50bdd7 100644
--- a/src/core_env.sml
+++ b/src/core_env.sml
@@ -348,7 +348,7 @@ fun declBinds env (d, loc) =
in
pushENamed env x n t NONE s
end
- | DInitializer _ => env
+ | DTask _ => env
fun patBinds env (p, loc) =
case p of
diff --git a/src/core_print.sml b/src/core_print.sml
index 7dd43d56..c1f93587 100644
--- a/src/core_print.sml
+++ b/src/core_print.sml
@@ -611,9 +611,13 @@ fun p_decl env (dAll as (d, _) : decl) =
string "as",
space,
string s]
- | DInitializer e => box [string "initializer",
+ | DTask (e1, e2) => box [string "task",
space,
- p_exp env e]
+ p_exp env e1,
+ space,
+ string "=",
+ space,
+ p_exp env e2]
fun p_file env file =
let
diff --git a/src/core_util.sml b/src/core_util.sml
index 7ead1157..599e1abc 100644
--- a/src/core_util.sml
+++ b/src/core_util.sml
@@ -971,10 +971,12 @@ fun mapfoldB {kind = fk, con = fc, exp = fe, decl = fd, bind} =
fn c' =>
(DCookie (x, n, c', s), loc))
| DStyle _ => S.return2 dAll
- | DInitializer e =>
- S.map2 (mfe ctx e,
- fn e' =>
- (DInitializer e', loc))
+ | DTask (e1, e2) =>
+ S.bind2 (mfe ctx e1,
+ fn e1' =>
+ S.map2 (mfe ctx e2,
+ fn e2' =>
+ (DTask (e1', e2'), loc)))
and mfvi ctx (x, n, t, e, s) =
S.bind2 (mfc ctx t,
@@ -1129,7 +1131,7 @@ fun mapfoldB (all as {bind, ...}) =
in
bind (ctx, NamedE (x, n, t, NONE, s))
end
- | DInitializer _ => ctx
+ | DTask _ => ctx
in
S.map2 (mff ctx' ds',
fn ds' =>
@@ -1193,7 +1195,7 @@ val maxName = foldl (fn ((d, _) : decl, count) =>
| DDatabase _ => count
| DCookie (_, n, _, _) => Int.max (n, count)
| DStyle (_, n, _) => Int.max (n, count)
- | DInitializer _ => count) 0
+ | DTask _ => count) 0
end
diff --git a/src/corify.sml b/src/corify.sml
index cc0500af..9259b4f2 100644
--- a/src/corify.sml
+++ b/src/corify.sml
@@ -1064,8 +1064,8 @@ fun corifyDecl mods (all as (d, loc : EM.span), st) =
([(L'.DStyle (x, n, s), loc)], st)
end
- | L.DInitializer e =>
- ([(L'.DInitializer (corifyExp st e), loc)], st)
+ | L.DTask (e1, e2) =>
+ ([(L'.DTask (corifyExp st e1, corifyExp st e2), loc)], st)
and corifyStr mods ((str, _), st) =
case str of
@@ -1124,7 +1124,7 @@ fun maxName ds = foldl (fn ((d, _), n) =>
| L.DDatabase _ => n
| L.DCookie (_, _, n', _) => Int.max (n, n')
| L.DStyle (_, _, n') => Int.max (n, n')
- | L.DInitializer _ => n)
+ | L.DTask _ => n)
0 ds
and maxNameStr (str, _) =
diff --git a/src/elab.sml b/src/elab.sml
index 1cd7aefa..a0f9a4e8 100644
--- a/src/elab.sml
+++ b/src/elab.sml
@@ -170,7 +170,7 @@ datatype decl' =
| DDatabase of string
| DCookie of int * string * int * con
| DStyle of int * string * int
- | DInitializer of exp
+ | DTask of exp * exp
and str' =
StrConst of decl list
diff --git a/src/elab_env.sml b/src/elab_env.sml
index 763cf801..5092c6fb 100644
--- a/src/elab_env.sml
+++ b/src/elab_env.sml
@@ -1622,6 +1622,6 @@ fun declBinds env (d, loc) =
in
pushENamedAs env x n t
end
- | DInitializer _ => env
+ | DTask _ => env
end
diff --git a/src/elab_print.sml b/src/elab_print.sml
index 906c836d..62b5262f 100644
--- a/src/elab_print.sml
+++ b/src/elab_print.sml
@@ -799,9 +799,13 @@ fun p_decl env (dAll as (d, _) : decl) =
| DStyle (_, x, n) => box [string "style",
space,
p_named x n]
- | DInitializer e => box [string "initializer",
+ | DTask (e1, e2) => box [string "task",
space,
- p_exp env e]
+ p_exp env e1,
+ space,
+ string "=",
+ space,
+ p_exp env e2]
and p_str env (str, _) =
case str of
diff --git a/src/elab_util.sml b/src/elab_util.sml
index 2a044e71..d0e140c5 100644
--- a/src/elab_util.sml
+++ b/src/elab_util.sml
@@ -854,7 +854,7 @@ fun mapfoldB {kind = fk, con = fc, exp = fe, sgn_item = fsgi, sgn = fsg, str = f
c), loc)))
| DStyle (tn, x, n) =>
bind (ctx, NamedE (x, (CModProj (n, [], "css_class"), loc)))
- | DInitializer _ => ctx,
+ | DTask _ => ctx,
mfd ctx d)) ctx ds,
fn ds' => (StrConst ds', loc))
| StrVar _ => S.return2 strAll
@@ -979,10 +979,12 @@ fun mapfoldB {kind = fk, con = fc, exp = fe, sgn_item = fsgi, sgn = fsg, str = f
fn c' =>
(DCookie (tn, x, n, c'), loc))
| DStyle _ => S.return2 dAll
- | DInitializer e =>
- S.map2 (mfe ctx e,
- fn e' =>
- (DInitializer e', loc))
+ | DTask (e1, e2) =>
+ S.bind2 (mfe ctx e1,
+ fn e1' =>
+ S.map2 (mfe ctx e2,
+ fn e2' =>
+ (DTask (e1', e2'), loc)))
and mfvi ctx (x, n, c, e) =
S.bind2 (mfc ctx c,
@@ -1125,7 +1127,7 @@ and maxNameDecl (d, _) =
| DDatabase _ => 0
| DCookie (n1, _, n2, _) => Int.max (n1, n2)
| DStyle (n1, _, n2) => Int.max (n1, n2)
- | DInitializer _ => 0
+ | DTask _ => 0
and maxNameStr (str, _) =
case str of
StrConst ds => maxName ds
diff --git a/src/elaborate.sml b/src/elaborate.sml
index d1b9648a..2a237c50 100644
--- a/src/elaborate.sml
+++ b/src/elaborate.sml
@@ -2548,7 +2548,7 @@ and sgiOfDecl (d, loc) =
| L'.DDatabase _ => []
| L'.DCookie (tn, x, n, c) => [(L'.SgiVal (x, n, (L'.CApp (cookieOf (), c), loc)), loc)]
| L'.DStyle (tn, x, n) => [(L'.SgiVal (x, n, styleOf ()), loc)]
- | L'.DInitializer _ => []
+ | L'.DTask _ => []
and subSgn' counterparts env strLoc sgn1 (sgn2 as (_, loc2)) =
((*prefaces "subSgn" [("sgn1", p_sgn env sgn1),
@@ -3669,14 +3669,18 @@ and elabDecl (dAll as (d, loc), (env, denv, gs)) =
in
([(L'.DStyle (!basis_r, x, n), loc)], (env, denv, gs))
end
- | L.DInitializer e =>
+ | L.DTask (e1, e2) =>
let
- val (e', t, gs') = elabExp (env, denv) e
- val t' = (L'.CApp ((L'.CModProj (!basis_r, [], "transaction"), loc),
- (L'.TRecord (L'.CRecord ((L'.KType, loc), []), loc), loc)), loc)
+ val (e1', t1, gs1) = elabExp (env, denv) e1
+ val (e2', t2, gs2) = elabExp (env, denv) e2
+
+ val t1' = (L'.CModProj (!basis_r, [], "task_kind"), loc)
+ val t2' = (L'.CApp ((L'.CModProj (!basis_r, [], "transaction"), loc),
+ (L'.TRecord (L'.CRecord ((L'.KType, loc), []), loc), loc)), loc)
in
- checkCon env e' t t';
- ([(L'.DInitializer e', loc)], (env, denv, gs' @ gs))
+ checkCon env e1' t1 t1';
+ checkCon env e2' t2 t2';
+ ([(L'.DTask (e1', e2'), loc)], (env, denv, gs2 @ gs1 @ gs))
end
(*val tcs = List.filter (fn TypeClass _ => true | _ => false) (#3 (#2 r))*)
diff --git a/src/elisp/urweb-defs.el b/src/elisp/urweb-defs.el
index bb0e257d..c697a274 100644
--- a/src/elisp/urweb-defs.el
+++ b/src/elisp/urweb-defs.el
@@ -108,7 +108,7 @@ notion of \"the end of an outline\".")
"datatype" "type" "open" "include"
urweb-module-head-syms
"con" "map" "where" "extern" "constraint" "constraints"
- "table" "sequence" "class" "cookie" "initializer")
+ "table" "sequence" "class" "cookie" "task")
"Symbols starting an sexp.")
;; (defconst urweb-not-arg-start-re
@@ -135,7 +135,7 @@ notion of \"the end of an outline\".")
(("case" "datatype" "if" "then" "else"
"let" "open" "sig" "struct" "type" "val"
"con" "constraint" "table" "sequence" "class" "cookie"
- "initializer")))))
+ "task")))))
(defconst urweb-starters-indent-after
(urweb-syms-re "let" "in" "struct" "sig")
@@ -190,7 +190,7 @@ for all symbols and in all lines starting with the given symbol."
'("datatype" "fun"
"open" "type" "val" "and"
"con" "constraint" "table" "sequence" "class" "cookie"
- "initializer"))
+ "task"))
"The starters of new expressions.")
(defconst urweb-exptrail-syms
diff --git a/src/elisp/urweb-mode.el b/src/elisp/urweb-mode.el
index ab274f22..107ea3bc 100644
--- a/src/elisp/urweb-mode.el
+++ b/src/elisp/urweb-mode.el
@@ -136,7 +136,7 @@ See doc for the variable `urweb-mode-info'."
"datatype" "else" "end" "extern" "fn" "map"
"fun" "functor" "if" "include"
"of" "open" "let" "in"
- "rec" "sequence" "sig" "signature" "cookie" "style" "initializer"
+ "rec" "sequence" "sig" "signature" "cookie" "style" "task"
"struct" "structure" "table" "view" "then" "type" "val" "where"
"with"
@@ -226,7 +226,7 @@ See doc for the variable `urweb-mode-info'."
("\\<\\(\\(data\\)?type\\|con\\|class\\)\\s-+\\(\\sw+\\)"
(1 font-lock-keyword-face)
(3 (amAttribute font-lock-type-def-face)))
- ("\\<\\(val\\|table\\|sequence\\|cookie\\|style\\|initializer\\)\\s-+\\(\\sw+\\>\\s-*\\)?\\(\\sw+\\)\\s-*[=:]"
+ ("\\<\\(val\\|table\\|sequence\\|cookie\\|style\\|task\\)\\s-+\\(\\sw+\\>\\s-*\\)?\\(\\sw+\\)\\s-*[=:]"
(1 font-lock-keyword-face)
(3 (amAttribute font-lock-variable-name-face)))
("\\<\\(structure\\|functor\\)\\s-+\\(\\sw+\\)"
diff --git a/src/expl.sml b/src/expl.sml
index eb79e2b0..17797626 100644
--- a/src/expl.sml
+++ b/src/expl.sml
@@ -147,7 +147,7 @@ datatype decl' =
| DDatabase of string
| DCookie of int * string * int * con
| DStyle of int * string * int
- | DInitializer of exp
+ | DTask of exp * exp
and str' =
StrConst of decl list
diff --git a/src/expl_env.sml b/src/expl_env.sml
index f16eeb8e..0bf7323f 100644
--- a/src/expl_env.sml
+++ b/src/expl_env.sml
@@ -343,7 +343,7 @@ fun declBinds env (d, loc) =
in
pushENamed env x n t
end
- | DInitializer _ => env
+ | DTask _ => env
fun sgiBinds env (sgi, loc) =
case sgi of
diff --git a/src/expl_print.sml b/src/expl_print.sml
index 624afa63..5284eecb 100644
--- a/src/expl_print.sml
+++ b/src/expl_print.sml
@@ -713,9 +713,13 @@ fun p_decl env (dAll as (d, _) : decl) =
| DStyle (_, x, n) => box [string "style",
space,
p_named x n]
- | DInitializer e => box [string "initializer",
+ | DTask (e1, e2) => box [string "task",
space,
- p_exp env e]
+ p_exp env e1,
+ space,
+ string "=",
+ space,
+ p_exp env e2]
and p_str env (str, _) =
case str of
diff --git a/src/explify.sml b/src/explify.sml
index d66b3530..aff91a34 100644
--- a/src/explify.sml
+++ b/src/explify.sml
@@ -195,7 +195,7 @@ fun explifyDecl (d, loc : EM.span) =
| L.DDatabase s => SOME (L'.DDatabase s, loc)
| L.DCookie (nt, x, n, c) => SOME (L'.DCookie (nt, x, n, explifyCon c), loc)
| L.DStyle (nt, x, n) => SOME (L'.DStyle (nt, x, n), loc)
- | L.DInitializer e => SOME (L'.DInitializer (explifyExp e), loc)
+ | L.DTask (e1, e2) => SOME (L'.DTask (explifyExp e1, explifyExp e2), loc)
and explifyStr (str, loc) =
case str of
diff --git a/src/mono.sml b/src/mono.sml
index 1962c6c5..e5e68bfa 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -139,7 +139,7 @@ datatype decl' =
| DCookie of string
| DStyle of string
- | DInitializer of exp
+ | DTask of exp * exp
withtype decl = decl' located
diff --git a/src/mono_env.sml b/src/mono_env.sml
index 6ffab153..c2e6cf02 100644
--- a/src/mono_env.sml
+++ b/src/mono_env.sml
@@ -129,7 +129,7 @@ fun declBinds env (d, loc) =
| DJavaScript _ => env
| DCookie _ => env
| DStyle _ => env
- | DInitializer _ => env
+ | DTask _ => env
fun patBinds env (p, loc) =
case p of
diff --git a/src/mono_print.sml b/src/mono_print.sml
index 13c45329..da34c220 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -491,9 +491,13 @@ fun p_decl env (dAll as (d, _) : decl) =
| DStyle s => box [string "style",
space,
string s]
- | DInitializer e => box [string "initializer",
+ | DTask (e1, e2) => box [string "task",
space,
- p_exp env e]
+ p_exp env e1,
+ space,
+ string "=",
+ space,
+ p_exp env e2]
fun p_file env file =
diff --git a/src/mono_shake.sml b/src/mono_shake.sml
index fc46cf96..048cc190 100644
--- a/src/mono_shake.sml
+++ b/src/mono_shake.sml
@@ -57,7 +57,7 @@ fun shake file =
(fn ((DExport (_, _, n, _, _), _), (page_cs, page_es)) => (page_cs, IS.add (page_es, n))
| ((DDatabase {expunge = n1, initialize = n2, ...}, _), (page_cs, page_es)) =>
(page_cs, IS.addList (page_es, [n1, n2]))
- | ((DInitializer e, _), st) => usedVars st e
+ | ((DTask (e1, e2), _), st) => usedVars (usedVars st e2) e1
| (_, st) => st) (IS.empty, IS.empty) file
val (cdef, edef) = foldl (fn ((DDatatype dts, _), (cdef, edef)) =>
@@ -74,7 +74,7 @@ fun shake file =
| ((DJavaScript _, _), acc) => acc
| ((DCookie _, _), acc) => acc
| ((DStyle _, _), acc) => acc
- | ((DInitializer _, _), acc) => acc)
+ | ((DTask _, _), acc) => acc)
(IM.empty, IM.empty) file
fun typ (c, s) =
@@ -141,7 +141,7 @@ fun shake file =
| (DJavaScript _, _) => true
| (DCookie _, _) => true
| (DStyle _, _) => true
- | (DInitializer _, _) => true) file
+ | (DTask _, _) => true) file
end
end
diff --git a/src/mono_util.sml b/src/mono_util.sml
index 184ce168..894e35d0 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -528,10 +528,12 @@ fun mapfoldB {typ = fc, exp = fe, decl = fd, bind} =
| DJavaScript _ => S.return2 dAll
| DCookie _ => S.return2 dAll
| DStyle _ => S.return2 dAll
- | DInitializer e =>
- S.map2 (mfe ctx e,
- fn e' =>
- (DInitializer e', loc))
+ | DTask (e1, e2) =>
+ S.bind2 (mfe ctx e1,
+ fn e1' =>
+ S.map2 (mfe ctx e2,
+ fn e2' =>
+ (DTask (e1', e2'), loc)))
and mfvi ctx (x, n, t, e, s) =
S.bind2 (mft t,
@@ -618,7 +620,7 @@ fun mapfoldB (all as {bind, ...}) =
| DJavaScript _ => ctx
| DCookie _ => ctx
| DStyle _ => ctx
- | DInitializer _ => ctx
+ | DTask _ => ctx
in
S.map2 (mff ctx' ds',
fn ds' =>
@@ -672,7 +674,7 @@ val maxName = foldl (fn ((d, _) : decl, count) =>
| DJavaScript _ => count
| DCookie _ => count
| DStyle _ => count
- | DInitializer _ => count) 0
+ | DTask _ => count) 0
end
diff --git a/src/monoize.sml b/src/monoize.sml
index 503fd6b3..f6a56c33 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -3478,13 +3478,14 @@ fun monoDecl (env, fm) (all as (d, loc)) =
[(L'.DStyle s, loc),
(L'.DVal (x, n, t', e, s), loc)])
end
- | L.DInitializer e =>
+ | L.DTask (e1, e2) =>
let
- val (e, fm) = monoExp (env, St.empty, fm) e
+ val (e1, fm) = monoExp (env, St.empty, fm) e1
+ val (e2, fm) = monoExp (env, St.empty, fm) e2
in
SOME (env,
fm,
- [(L'.DInitializer e, loc)])
+ [(L'.DTask (e1, e2), loc)])
end
end
diff --git a/src/prepare.sml b/src/prepare.sml
index 7cbd7d76..2d144c67 100644
--- a/src/prepare.sml
+++ b/src/prepare.sml
@@ -325,11 +325,11 @@ fun prepDecl (d as (_, loc), st) =
| DJavaScript _ => (d, st)
| DCookie _ => (d, st)
| DStyle _ => (d, st)
- | DInitializer e =>
+ | DTask (tk, e) =>
let
val (e, st) = prepExp (e, st)
in
- ((DInitializer e, loc), st)
+ ((DTask (tk, e), loc), st)
end
fun prepare (ds, ps) =
diff --git a/src/reduce.sml b/src/reduce.sml
index cedb79fa..95b26da8 100644
--- a/src/reduce.sml
+++ b/src/reduce.sml
@@ -804,11 +804,12 @@ fun reduce file =
| DDatabase _ => (d, st)
| DCookie (s, n, c, s') => ((DCookie (s, n, con namedC [] c, s'), loc), st)
| DStyle (s, n, s') => ((DStyle (s, n, s'), loc), st)
- | DInitializer e =>
+ | DTask (e1, e2) =>
let
- val e = exp (namedC, namedE) [] e
+ val e1 = exp (namedC, namedE) [] e1
+ val e2 = exp (namedC, namedE) [] e2
in
- ((DInitializer e, loc),
+ ((DTask (e1, e2), loc),
(polyC,
namedC,
namedE))
diff --git a/src/reduce_local.sml b/src/reduce_local.sml
index 82490118..b040a1ec 100644
--- a/src/reduce_local.sml
+++ b/src/reduce_local.sml
@@ -251,7 +251,7 @@ fun reduce file =
| DDatabase _ => d
| DCookie _ => d
| DStyle _ => d
- | DInitializer e => (DInitializer (exp [] e), loc)
+ | DTask (e1, e2) => (DTask (exp [] e1, exp [] e2), loc)
in
map doDecl file
end
diff --git a/src/shake.sml b/src/shake.sml
index 787500ea..d1810bea 100644
--- a/src/shake.sml
+++ b/src/shake.sml
@@ -79,7 +79,7 @@ fun shake file =
in
(usedE, usedC)
end
- | ((DInitializer e, _), st) => usedVars st e
+ | ((DTask (e1, e2), _), st) => usedVars (usedVars st e1) e2
| (_, acc) => acc) (IS.empty, IS.empty) file
val (cdef, edef) = foldl (fn ((DCon (_, n, _, c), _), (cdef, edef)) => (IM.insert (cdef, n, [c]), edef)
@@ -106,7 +106,7 @@ fun shake file =
(cdef, IM.insert (edef, n, ([], c, dummye)))
| ((DStyle (_, n, _), _), (cdef, edef)) =>
(cdef, IM.insert (edef, n, ([], dummyt, dummye)))
- | ((DInitializer _, _), acc) => acc)
+ | ((DTask _, _), acc) => acc)
(IM.empty, IM.empty) file
fun kind (_, s) = s
@@ -186,7 +186,7 @@ fun shake file =
| (DDatabase _, _) => true
| (DCookie _, _) => true
| (DStyle _, _) => true
- | (DInitializer _, _) => true) file
+ | (DTask _, _) => true) file
end
end
diff --git a/src/source.sml b/src/source.sml
index e52872f0..dc867026 100644
--- a/src/source.sml
+++ b/src/source.sml
@@ -167,7 +167,7 @@ datatype decl' =
| DDatabase of string
| DCookie of string * con
| DStyle of string
- | DInitializer of exp
+ | DTask of exp * exp
and str' =
StrConst of decl list
diff --git a/src/source_print.sml b/src/source_print.sml
index 31fc2500..e3b4fe94 100644
--- a/src/source_print.sml
+++ b/src/source_print.sml
@@ -662,9 +662,13 @@ fun p_decl ((d, _) : decl) =
| DStyle x => box [string "style",
space,
string x]
- | DInitializer e => box [string "initializer",
+ | DTask (e1, e2) => box [string "task",
space,
- p_exp e]
+ p_exp e1,
+ space,
+ string "=",
+ space,
+ p_exp e2]
and p_str (str, _) =
case str of
diff --git a/src/unnest.sml b/src/unnest.sml
index c4d9a8b5..e030bbc6 100644
--- a/src/unnest.sml
+++ b/src/unnest.sml
@@ -422,7 +422,7 @@ fun unnest file =
| DDatabase _ => default ()
| DCookie _ => default ()
| DStyle _ => default ()
- | DInitializer _ => explore ()
+ | DTask _ => explore ()
end
and doStr (all as (str, loc), st) =
diff --git a/src/urweb.grm b/src/urweb.grm
index 8780d9f6..afe7be07 100644
--- a/src/urweb.grm
+++ b/src/urweb.grm
@@ -201,7 +201,7 @@ fun patType loc (p : pat) =
| LET | IN
| STRUCTURE | SIGNATURE | STRUCT | SIG | END | FUNCTOR | WHERE | EXTERN | SQL | SELECT1
| INCLUDE | OPEN | CONSTRAINT | CONSTRAINTS | EXPORT | TABLE | SEQUENCE | VIEW
- | COOKIE | STYLE | INITIALIZER
+ | COOKIE | STYLE | TASK
| CASE | IF | THEN | ELSE | ANDALSO | ORELSE
| XML_BEGIN of string | XML_END | XML_BEGIN_END of string
@@ -479,7 +479,7 @@ decl : CON SYMBOL cargl2 kopt EQ cexp (let
end)
| COOKIE SYMBOL COLON cexp ([(DCookie (SYMBOL, cexp), s (COOKIEleft, cexpright))])
| STYLE SYMBOL ([(DStyle SYMBOL, s (STYLEleft, SYMBOLright))])
- | INITIALIZER eexp ([(DInitializer eexp, s (INITIALIZERleft, eexpright))])
+ | TASK eapps EQ eexp ([(DTask (eapps, eexp), s (TASKleft, eexpright))])
dtype : SYMBOL dargs EQ barOpt dcons (SYMBOL, dargs, dcons)
diff --git a/src/urweb.lex b/src/urweb.lex
index d04822f7..5fb767b1 100644
--- a/src/urweb.lex
+++ b/src/urweb.lex
@@ -402,7 +402,7 @@ notags = [^<{\n]+;
"class" => (Tokens.CLASS (pos yypos, pos yypos + size yytext));
"cookie" => (Tokens.COOKIE (pos yypos, pos yypos + size yytext));
"style" => (Tokens.STYLE (pos yypos, pos yypos + size yytext));
- "initializer" => (Tokens.INITIALIZER (pos yypos, pos yypos + size yytext));
+ "task" => (Tokens.TASK (pos yypos, pos yypos + size yytext));
"Type" => (Tokens.TYPE (pos yypos, pos yypos + size yytext));
"Name" => (Tokens.NAME (pos yypos, pos yypos + size yytext));
diff --git a/tests/init.ur b/tests/init.ur
index 0a44a9e4..aafbb55f 100644
--- a/tests/init.ur
+++ b/tests/init.ur
@@ -1,6 +1,6 @@
sequence seq
table fred : {A : int, B : int}
-initializer
+task initialize =
setval seq 1;
dml (INSERT INTO fred (A, B) VALUES (0, 1))
--
cgit v1.2.3
From 21678b3f280cd85961e3354faecc29aab4819de4 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Thu, 31 Dec 2009 11:41:57 -0500
Subject: Basis.serialize; separate file for mhash; run transactional finishers
in reverse order; set needs_sig properly
---
Makefile.in | 4 ++--
lib/ur/basis.urs | 5 +++++
src/c/mhash.c | 41 +++++++++++++++++++++++++++++++++++++++++
src/c/request.c | 41 -----------------------------------------
src/c/urweb.c | 20 ++++++++++++--------
src/cjr.sml | 2 +-
src/cjr_print.sml | 6 +++---
src/cjrize.sml | 4 ++--
src/compiler.sml | 2 +-
src/core.sml | 2 +-
src/core_print.sml | 20 ++++++++++----------
src/corify.sml | 2 +-
src/effectize.sml | 44 ++++++++++++++++++++++++++++++++------------
src/marshalcheck.sml | 2 +-
src/mono.sml | 2 +-
src/mono_print.sml | 34 +++++++++++++++++-----------------
src/mono_shake.sml | 2 +-
src/mono_util.sml | 4 ++--
src/monoize.sml | 31 +++++++++++++++++++++++++++----
src/pathcheck.sml | 2 +-
src/rpcify.sml | 2 +-
src/scriptcheck.sml | 5 +++--
src/shake.sml | 2 +-
src/tag.sml | 4 ++--
24 files changed, 168 insertions(+), 115 deletions(-)
create mode 100644 src/c/mhash.c
(limited to 'src/mono.sml')
diff --git a/Makefile.in b/Makefile.in
index 5016abb3..32e123b4 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -17,7 +17,7 @@ all: smlnj mlton c
smlnj: src/urweb.cm
mlton: bin/urweb
-OBJS := memmem urweb request queue http cgi fastcgi
+OBJS := memmem mhash urweb request queue http cgi fastcgi
SOS := urweb urweb_http urweb_cgi urweb_fastcgi
c: $(OBJS:%=lib/c/%.o) $(SOS:%=lib/c/lib%.so.$(LD_MAJOR).$(LD_MINOR))
@@ -33,7 +33,7 @@ lib/c/%.do: src/c/%.c include/*.h
lib/c/%.o: src/c/%.c include/*.h
gcc -Wimplicit -O3 -I include -c $< -o $@ $(CFLAGS)
-URWEB_OS := memmem urweb queue request
+URWEB_OS := memmem urweb queue request mhash
lib/c/liburweb.so.$(LD_MAJOR).$(LD_MINOR): $(URWEB_OS:%=lib/c/%.do)
gcc -shared -Wl,-soname,liburweb.so.$(LD_MAJOR) -o $@ $^
diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs
index ffce96c0..330bea31 100644
--- a/lib/ur/basis.urs
+++ b/lib/ur/basis.urs
@@ -194,6 +194,11 @@ val sql_blob : sql_injectable_prim blob
val sql_channel : t ::: Type -> sql_injectable_prim (channel t)
val sql_client : sql_injectable_prim client
+con serialized :: Type -> Type
+val serialize : t ::: Type -> t -> serialized t
+val deserialize : t ::: Type -> serialized t -> t
+val sql_serialized : t ::: Type -> sql_injectable_prim (serialized t)
+
con primary_key :: {Type} -> {{Unit}} -> Type
val no_primary_key : fs ::: {Type} -> primary_key fs []
val primary_key : rest ::: {Type} -> t ::: Type -> key1 :: Name -> keys :: {Type}
diff --git a/src/c/mhash.c b/src/c/mhash.c
new file mode 100644
index 00000000..becb9d97
--- /dev/null
+++ b/src/c/mhash.c
@@ -0,0 +1,41 @@
+#include
+
+#define KEYSIZE 16
+#define PASSSIZE 4
+
+#define HASH_ALGORITHM MHASH_SHA256
+#define HASH_BLOCKSIZE 32
+#define KEYGEN_ALGORITHM KEYGEN_MCRYPT
+
+int uw_hash_blocksize = HASH_BLOCKSIZE;
+
+static int password[PASSSIZE];
+static unsigned char private_key[KEYSIZE];
+
+void uw_init_crypto() {
+ KEYGEN kg = {{HASH_ALGORITHM, HASH_ALGORITHM}};
+ int i;
+
+ assert(mhash_get_block_size(HASH_ALGORITHM) == HASH_BLOCKSIZE);
+
+ for (i = 0; i < PASSSIZE; ++i)
+ password[i] = rand();
+
+ if (mhash_keygen_ext(KEYGEN_ALGORITHM, kg,
+ private_key, sizeof(private_key),
+ (unsigned char*)password, sizeof(password)) < 0) {
+ fprintf(stderr, "Key generation failed\n");
+ exit(1);
+ }
+}
+
+void uw_sign(const char *in, char *out) {
+ MHASH td;
+
+ td = mhash_hmac_init(HASH_ALGORITHM, private_key, sizeof(private_key),
+ mhash_get_hash_pblock(HASH_ALGORITHM));
+
+ mhash(td, in, strlen(in));
+ if (mhash_hmac_deinit(td, out) < 0)
+ fprintf(stderr, "Signing failed\n");
+}
diff --git a/src/c/request.c b/src/c/request.c
index 5c8159cc..f190ec98 100644
--- a/src/c/request.c
+++ b/src/c/request.c
@@ -67,35 +67,6 @@ uw_context uw_request_new_context(uw_app *app, void *logger_data, uw_logger log_
return ctx;
}
-#define KEYSIZE 16
-#define PASSSIZE 4
-
-#define HASH_ALGORITHM MHASH_SHA256
-#define HASH_BLOCKSIZE 32
-#define KEYGEN_ALGORITHM KEYGEN_MCRYPT
-
-int uw_hash_blocksize = HASH_BLOCKSIZE;
-
-static int password[PASSSIZE];
-static unsigned char private_key[KEYSIZE];
-
-static void init_crypto(void *logger_data, uw_logger log_error) {
- KEYGEN kg = {{HASH_ALGORITHM, HASH_ALGORITHM}};
- int i;
-
- assert(mhash_get_block_size(HASH_ALGORITHM) == HASH_BLOCKSIZE);
-
- for (i = 0; i < PASSSIZE; ++i)
- password[i] = rand();
-
- if (mhash_keygen_ext(KEYGEN_ALGORITHM, kg,
- private_key, sizeof(private_key),
- (unsigned char*)password, sizeof(password)) < 0) {
- log_error(logger_data, "Key generation failed\n");
- exit(1);
- }
-}
-
void uw_request_init(uw_app *app, void *logger_data, uw_logger log_error, uw_logger log_debug) {
uw_context ctx;
failure_kind fk;
@@ -121,20 +92,8 @@ void uw_request_init(uw_app *app, void *logger_data, uw_logger log_error, uw_log
}
uw_free(ctx);
-
- init_crypto(logger_data, log_error);
}
-void uw_sign(const char *in, char *out) {
- MHASH td;
-
- td = mhash_hmac_init(HASH_ALGORITHM, private_key, sizeof(private_key),
- mhash_get_hash_pblock(HASH_ALGORITHM));
-
- mhash(td, in, strlen(in));
- if (mhash_hmac_deinit(td, out) < 0)
- fprintf(stderr, "Signing failed\n");
-}
typedef struct uw_rc {
size_t path_copy_size;
diff --git a/src/c/urweb.c b/src/c/urweb.c
index 455b3e1e..3773e1fb 100644
--- a/src/c/urweb.c
+++ b/src/c/urweb.c
@@ -289,10 +289,14 @@ static void client_send(client *c, buf *msg) {
// Global entry points
+extern void uw_init_crypto();
+
void uw_global_init() {
srand(time(NULL) ^ getpid());
clients = malloc(0);
+
+ uw_init_crypto();
}
void uw_app_init(uw_app *app) {
@@ -420,7 +424,7 @@ uw_context uw_init() {
ctx->script_header = "";
ctx->needs_push = 0;
ctx->needs_sig = 0;
-
+
ctx->error_message[0] = 0;
ctx->source_count = 0;
@@ -2766,14 +2770,14 @@ uw_unit uw_Basis_send(uw_context ctx, uw_Basis_channel chn, uw_Basis_string msg)
}
void uw_commit(uw_context ctx) {
- unsigned i;
+ int i;
- for (i = 0; i < ctx->used_transactionals; ++i)
+ for (i = ctx->used_transactionals-1; i >= 0; --i)
if (ctx->transactionals[i].rollback != NULL)
if (ctx->transactionals[i].commit)
ctx->transactionals[i].commit(ctx->transactionals[i].data);
- for (i = 0; i < ctx->used_transactionals; ++i)
+ for (i = ctx->used_transactionals-1; i >= 0; --i)
if (ctx->transactionals[i].rollback == NULL)
if (ctx->transactionals[i].commit)
ctx->transactionals[i].commit(ctx->transactionals[i].data);
@@ -2793,7 +2797,7 @@ void uw_commit(uw_context ctx) {
if (ctx->client)
release_client(ctx->client);
- for (i = 0; i < ctx->used_transactionals; ++i)
+ for (i = ctx->used_transactionals-1; i >= 0; --i)
if (ctx->transactionals[i].free)
ctx->transactionals[i].free(ctx->transactionals[i].data);
@@ -2832,7 +2836,7 @@ void uw_commit(uw_context ctx) {
}
int uw_rollback(uw_context ctx) {
- size_t i;
+ int i;
cleanup *cl;
if (ctx->client)
@@ -2843,11 +2847,11 @@ int uw_rollback(uw_context ctx) {
ctx->cleanup_front = ctx->cleanup;
- for (i = 0; i < ctx->used_transactionals; ++i)
+ for (i = ctx->used_transactionals-1; i >= 0; --i)
if (ctx->transactionals[i].rollback != NULL)
ctx->transactionals[i].rollback(ctx->transactionals[i].data);
- for (i = 0; i < ctx->used_transactionals; ++i)
+ for (i = ctx->used_transactionals-1; i >= 0; --i)
if (ctx->transactionals[i].free)
ctx->transactionals[i].free(ctx->transactionals[i].data);
diff --git a/src/cjr.sml b/src/cjr.sml
index f5392d49..53448a29 100644
--- a/src/cjr.sml
+++ b/src/cjr.sml
@@ -132,6 +132,6 @@ datatype sidedness =
datatype effect = datatype Export.effect
datatype export_kind = datatype Export.export_kind
-type file = decl list * (export_kind * string * int * typ list * typ * sidedness) list
+type file = decl list * (export_kind * string * int * typ list * typ * sidedness * bool) list
end
diff --git a/src/cjr_print.sml b/src/cjr_print.sml
index 30e34fad..9f63edaf 100644
--- a/src/cjr_print.sml
+++ b/src/cjr_print.sml
@@ -2184,7 +2184,7 @@ fun p_file env (ds, ps) =
end
| _ => NONE
- val fields = foldl (fn ((ek, _, _, ts, _, _), fields) =>
+ val fields = foldl (fn ((ek, _, _, ts, _, _, _), fields) =>
case ek of
Link => fields
| Rpc _ => fields
@@ -2480,7 +2480,7 @@ fun p_file env (ds, ps) =
newline]
end
- fun p_page (ek, s, n, ts, ran, side) =
+ fun p_page (ek, s, n, ts, ran, side, tellSig) =
let
val (ts, defInputs, inputsVar, fields) =
case ek of
@@ -2612,7 +2612,7 @@ fun p_file env (ds, ps) =
string ");",
newline,
string "uw_set_needs_sig(ctx, ",
- string (if couldWrite ek then
+ string (if tellSig then
"1"
else
"0"),
diff --git a/src/cjrize.sml b/src/cjrize.sml
index 0136bdf6..e2807372 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -590,12 +590,12 @@ fun cifyDecl ((d, loc), sm) =
(SOME (L'.DFunRec vis, loc), NONE, sm)
end
- | L.DExport (ek, s, n, ts, t) =>
+ | L.DExport (ek, s, n, ts, t, b) =>
let
val (ts, sm) = ListUtil.foldlMap cifyTyp sm ts
val (t, sm) = cifyTyp (t, sm)
in
- (NONE, SOME (ek, "/" ^ s, n, ts, t, L'.ServerAndPullAndPush), sm)
+ (NONE, SOME (ek, "/" ^ s, n, ts, t, L'.ServerAndPullAndPush, b), sm)
end
| L.DTable (s, xts, pe, ce) =>
diff --git a/src/compiler.sml b/src/compiler.sml
index 28b8dc2c..026df6fd 100644
--- a/src/compiler.sml
+++ b/src/compiler.sml
@@ -1029,7 +1029,7 @@ fun compileC {cname, oname, ename, libs, profile, debug, link = link'} =
val lib = if Settings.getStaticLinking () then
clibFile "request.o" ^ " " ^ clibFile "queue.o" ^ " " ^ clibFile "urweb.o"
- ^ " " ^ clibFile "memmem.o" ^ " " ^ #linkStatic proto
+ ^ " " ^ clibFile "memmem.o" ^ " " ^ clibFile "mhash.o" ^ " " ^ #linkStatic proto
else
"-L" ^ Config.libC ^ " -lurweb " ^ #linkDynamic proto
diff --git a/src/core.sml b/src/core.sml
index 78a1eded..90005f16 100644
--- a/src/core.sml
+++ b/src/core.sml
@@ -127,7 +127,7 @@ datatype decl' =
| DDatatype of (string * int * string list * (string * int * con option) list) list
| DVal of string * int * con * exp * string
| DValRec of (string * int * con * exp * string) list
- | DExport of export_kind * int
+ | DExport of export_kind * int * bool
| DTable of string * int * con * string * exp * con * exp * con
| DSequence of string * int * string
| DView of string * int * string * exp * con
diff --git a/src/core_print.sml b/src/core_print.sml
index c1f93587..d6be76a3 100644
--- a/src/core_print.sml
+++ b/src/core_print.sml
@@ -547,16 +547,16 @@ fun p_decl env (dAll as (d, _) : decl) =
space,
p_list_sep (box [newline, string "and", space]) (p_vali env) vis]
end
- | DExport (ek, n) => box [string "export",
- space,
- Export.p_export_kind ek,
- space,
- p_enamed env n,
- space,
- string "as",
- space,
- (p_con env (#2 (E.lookupENamed env n))
- handle E.UnboundNamed _ => string "UNBOUND")]
+ | DExport (ek, n, _) => box [string "export",
+ space,
+ Export.p_export_kind ek,
+ space,
+ p_enamed env n,
+ space,
+ string "as",
+ space,
+ (p_con env (#2 (E.lookupENamed env n))
+ handle E.UnboundNamed _ => string "UNBOUND")]
| DTable (x, n, c, s, pe, _, ce, _) => box [string "table",
space,
p_named x n,
diff --git a/src/corify.sml b/src/corify.sml
index 9259b4f2..a1a5c745 100644
--- a/src/corify.sml
+++ b/src/corify.sml
@@ -1001,7 +1001,7 @@ fun corifyDecl mods (all as (d, loc : EM.span), st) =
e), loc) :: wds,
(fn st =>
case #1 (corifyExp st (L.EModProj (en, [], "wrap_" ^ s), loc)) of
- L'.ENamed n => (L'.DExport (L'.Link, n), loc)
+ L'.ENamed n => (L'.DExport (L'.Link, n, false), loc)
| _ => raise Fail "Corify: Value to export didn't corify properly")
:: eds)
else
diff --git a/src/effectize.sml b/src/effectize.sml
index fcaaa79e..1685fbe9 100644
--- a/src/effectize.sml
+++ b/src/effectize.sml
@@ -66,6 +66,15 @@ fun effectize file =
con = fn _ => false,
exp = exp evs}
+ fun exp writers readers e =
+ case e of
+ EServerCall (n, _, _) => IM.inDomain (writers, n) andalso IM.inDomain (readers, n)
+ | _ => false
+
+ fun couldWriteWithRpc writers readers = U.Exp.exists {kind = fn _ => false,
+ con = fn _ => false,
+ exp = exp writers readers}
+
fun exp evs e =
case e of
EFfi ("Basis", "getCookie") => true
@@ -77,7 +86,7 @@ fun effectize file =
con = fn _ => false,
exp = exp evs}
- fun doDecl (d, evs as (writers, readers)) =
+ fun doDecl (d, evs as (writers, readers, pushers)) =
case #1 d of
DVal (x, n, t, e, s) =>
(d, (if couldWrite writers e then
@@ -87,11 +96,15 @@ fun effectize file =
if couldReadCookie readers e then
IM.insert (readers, n, (#2 d, s))
else
- readers))
+ readers,
+ if couldWriteWithRpc writers readers e then
+ IM.insert (pushers, n, (#2 d, s))
+ else
+ pushers))
| DValRec vis =>
let
fun oneRound evs =
- foldl (fn ((_, n, _, e, s), (changed, (writers, readers))) =>
+ foldl (fn ((_, n, _, e, s), (changed, (writers, readers, pushers))) =>
let
val (changed, writers) =
if couldWrite writers e andalso not (IM.inDomain (writers, n)) then
@@ -104,8 +117,15 @@ fun effectize file =
(true, IM.insert (readers, n, (#2 d, s)))
else
(changed, readers)
+
+ val (changed, pushers) =
+ if couldWriteWithRpc writers readers e
+ andalso not (IM.inDomain (pushers, n)) then
+ (true, IM.insert (pushers, n, (#2 d, s)))
+ else
+ (changed, pushers)
in
- (changed, (writers, readers))
+ (changed, (writers, readers, pushers))
end) (false, evs) vis
fun loop evs =
@@ -118,34 +138,34 @@ fun effectize file =
evs
end
in
- (d, loop (writers, readers))
+ (d, loop (writers, readers, pushers))
end
- | DExport (Link, n) =>
+ | DExport (Link, n, _) =>
(case IM.find (writers, n) of
NONE => ()
| SOME (loc, s) => ErrorMsg.errorAt loc ("A link (" ^ s ^ ") could cause side effects; try implementing it with a form instead");
- (d, evs))
- | DExport (Action _, n) =>
+ ((DExport (Link, n, IM.inDomain (pushers, n)), #2 d), evs))
+ | DExport (Action _, n, _) =>
((DExport (Action (if IM.inDomain (writers, n) then
if IM.inDomain (readers, n) then
ReadCookieWrite
else
ReadWrite
else
- ReadOnly), n), #2 d),
+ ReadOnly), n, IM.inDomain (pushers, n)), #2 d),
evs)
- | DExport (Rpc _, n) =>
+ | DExport (Rpc _, n, _) =>
((DExport (Rpc (if IM.inDomain (writers, n) then
if IM.inDomain (readers, n) then
ReadCookieWrite
else
ReadWrite
else
- ReadOnly), n), #2 d),
+ ReadOnly), n, IM.inDomain (pushers, n)), #2 d),
evs)
| _ => (d, evs)
- val (file, _) = ListUtil.foldlMap doDecl (IM.empty, IM.empty) file
+ val (file, _) = ListUtil.foldlMap doDecl (IM.empty, IM.empty, IM.empty) file
in
file
end
diff --git a/src/marshalcheck.sml b/src/marshalcheck.sml
index 10129aef..de6879ae 100644
--- a/src/marshalcheck.sml
+++ b/src/marshalcheck.sml
@@ -89,7 +89,7 @@ fun check file =
foldl (fn ((_, n, t, _, tag), emap) => IM.insert (emap, n, (t, tag)))
emap vis)
- | DExport (_, n) =>
+ | DExport (_, n, _) =>
(case IM.find (emap, n) of
NONE => raise Fail "MarshalCheck: Unknown export"
| SOME (t, tag) =>
diff --git a/src/mono.sml b/src/mono.sml
index e5e68bfa..af5e9031 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -127,7 +127,7 @@ datatype decl' =
DDatatype of (string * int * (string * int * typ option) list) list
| DVal of string * int * typ * exp * string
| DValRec of (string * int * typ * exp * string) list
- | DExport of export_kind * string * int * typ list * typ
+ | DExport of export_kind * string * int * typ list * typ * bool
| DTable of string * (string * typ) list * exp * exp
| DSequence of string
diff --git a/src/mono_print.sml b/src/mono_print.sml
index da34c220..d190640e 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -423,23 +423,23 @@ fun p_decl env (dAll as (d, _) : decl) =
p_list_sep (box [newline, string "and", space]) (p_vali env) vis]
end
- | DExport (ek, s, n, ts, t) => box [string "export",
- space,
- Export.p_export_kind ek,
- space,
- p_enamed env n,
- space,
- string "as",
- space,
- string s,
- p_list_sep (string "") (fn t => box [space,
- string "(",
- p_typ env t,
- string ")"]) ts,
- space,
- string "->",
- space,
- p_typ env t]
+ | DExport (ek, s, n, ts, t, _) => box [string "export",
+ space,
+ Export.p_export_kind ek,
+ space,
+ p_enamed env n,
+ space,
+ string "as",
+ space,
+ string s,
+ p_list_sep (string "") (fn t => box [space,
+ string "(",
+ p_typ env t,
+ string ")"]) ts,
+ space,
+ string "->",
+ space,
+ p_typ env t]
| DTable (s, xts, pe, ce) => box [string "(* SQL table ",
string s,
diff --git a/src/mono_shake.sml b/src/mono_shake.sml
index 048cc190..e53b6930 100644
--- a/src/mono_shake.sml
+++ b/src/mono_shake.sml
@@ -54,7 +54,7 @@ fun shake file =
val (page_cs, page_es) =
List.foldl
- (fn ((DExport (_, _, n, _, _), _), (page_cs, page_es)) => (page_cs, IS.add (page_es, n))
+ (fn ((DExport (_, _, n, _, _, _), _), (page_cs, page_es)) => (page_cs, IS.add (page_es, n))
| ((DDatabase {expunge = n1, initialize = n2, ...}, _), (page_cs, page_es)) =>
(page_cs, IS.addList (page_es, [n1, n2]))
| ((DTask (e1, e2), _), st) => usedVars (usedVars st e2) e1
diff --git a/src/mono_util.sml b/src/mono_util.sml
index 894e35d0..02619437 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -507,12 +507,12 @@ fun mapfoldB {typ = fc, exp = fe, decl = fd, bind} =
fn vis' =>
(DValRec vis', loc))
end
- | DExport (ek, s, n, ts, t) =>
+ | DExport (ek, s, n, ts, t, b) =>
S.bind2 (ListUtil.mapfold mft ts,
fn ts' =>
S.map2 (mft t,
fn t' =>
- (DExport (ek, s, n, ts', t'), loc)))
+ (DExport (ek, s, n, ts', t', b), loc)))
| DTable (s, xts, pe, ce) =>
S.bind2 (mfe ctx pe,
fn pe' =>
diff --git a/src/monoize.sml b/src/monoize.sml
index 0f03111c..afe2012f 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -162,6 +162,9 @@ fun monoType env =
(L'.TFfi ("Basis", "string"), loc)
| L.CFfi ("Basis", "css_class") => (L'.TFfi ("Basis", "string"), loc)
+ | L.CApp ((L.CFfi ("Basis", "serialized"), _), _) =>
+ (L'.TFfi ("Basis", "string"), loc)
+
| L.CApp ((L.CFfi ("Basis", "transaction"), _), t) =>
(L'.TFun ((L'.TRecord [], loc), mt env dtmap t), loc)
| L.CApp ((L.CFfi ("Basis", "source"), _), t) =>
@@ -1975,6 +1978,10 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
((L'.EAbs ("x", (L'.TFfi ("Basis", "client"), loc), (L'.TFfi ("Basis", "string"), loc),
(L'.EFfiApp ("Basis", "sqlifyClient", [(L'.ERel 0, loc)]), loc)), loc),
fm)
+ | L.ECApp ((L.EFfi ("Basis", "sql_serialized"), _), _) =>
+ ((L'.EAbs ("x", (L'.TFfi ("Basis", "string"), loc), (L'.TFfi ("Basis", "string"), loc),
+ (L'.EFfiApp ("Basis", "sqlifyString", [(L'.ERel 0, loc)]), loc)), loc),
+ fm)
| L.ECApp ((L.EFfi ("Basis", "sql_prim"), _), t) =>
let
val t = monoType env t
@@ -3235,6 +3242,22 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
fm)
end
+ | L.ECApp ((L.EFfi ("Basis", "serialize"), _), t) =>
+ let
+ val t = monoType env t
+ val (e, fm) = urlifyExp env fm ((L'.ERel 0, loc), t)
+ in
+ ((L'.EAbs ("v", t, (L'.TFfi ("Basis", "string"), loc), e), loc),
+ fm)
+ end
+ | L.ECApp ((L.EFfi ("Basis", "deserialize"), _), t) =>
+ let
+ val t = monoType env t
+ in
+ ((L'.EAbs ("v", (L'.TFfi ("Basis", "string"), loc), t, (L'.EUnurlify ((L'.ERel 0, loc), t), loc)), loc),
+ fm)
+ end
+
| L.EFfiApp ("Basis", "url", [e]) =>
let
val (e, fm) = monoExp (env, st, fm) e
@@ -3432,7 +3455,7 @@ fun monoDecl (env, fm) (all as (d, loc)) =
fm,
[(L'.DValRec vis, loc)])
end
- | L.DExport (ek, n) =>
+ | L.DExport (ek, n, b) =>
let
val (_, t, _, s) = Env.lookupENamed env n
@@ -3447,7 +3470,7 @@ fun monoDecl (env, fm) (all as (d, loc)) =
val ts = map (monoType env) ts
val ran = monoType env ran
in
- SOME (env, fm, [(L'.DExport (ek, s, n, ts, ran), loc)])
+ SOME (env, fm, [(L'.DExport (ek, s, n, ts, ran, b), loc)])
end
| L.DTable (x, n, (L.CRecord (_, xts), _), s, pe, _, ce, _) =>
let
@@ -3538,8 +3561,8 @@ fun monoize env file =
(* Calculate which exported functions need cookie signature protection *)
val rcook = foldl (fn ((d, _), rcook) =>
case d of
- L.DExport (L.Action L.ReadCookieWrite, n) => IS.add (rcook, n)
- | L.DExport (L.Rpc L.ReadCookieWrite, n) => IS.add (rcook, n)
+ L.DExport (L.Action L.ReadCookieWrite, n, _) => IS.add (rcook, n)
+ | L.DExport (L.Rpc L.ReadCookieWrite, n, _) => IS.add (rcook, n)
| _ => rcook)
IS.empty file
val () = readCookie := rcook
diff --git a/src/pathcheck.sml b/src/pathcheck.sml
index a493595d..15405db7 100644
--- a/src/pathcheck.sml
+++ b/src/pathcheck.sml
@@ -67,7 +67,7 @@ fun checkDecl ((d, loc), (funcs, rels, cookies, styles)) =
(funcs, rels, cookies, SS.add (styles, s)))
in
case d of
- DExport (_, s, _, _, _) => doFunc s
+ DExport (_, s, _, _, _, _) => doFunc s
| DTable (s, _, pe, ce) =>
let
diff --git a/src/rpcify.sml b/src/rpcify.sml
index 3569e2bc..63330942 100644
--- a/src/rpcify.sml
+++ b/src/rpcify.sml
@@ -107,7 +107,7 @@ fun frob file =
(#exported st, #export_decls st)
else
(IS.add (#exported st, n),
- (DExport (Rpc ReadWrite, n), loc) :: #export_decls st)
+ (DExport (Rpc ReadWrite, n, false), loc) :: #export_decls st)
val st = {exported = exported,
export_decls = export_decls}
diff --git a/src/scriptcheck.sml b/src/scriptcheck.sml
index 5cd056d5..7dec8d80 100644
--- a/src/scriptcheck.sml
+++ b/src/scriptcheck.sml
@@ -159,7 +159,7 @@ fun classify (ds, ps) =
val foundBad = ref false
- val ps = map (fn (ek, x, n, ts, t, _) =>
+ val ps = map (fn (ek, x, n, ts, t, _, b) =>
(ek, x, n, ts, t,
if IS.member (push_ids, n) then
(if not (#persistent proto) andalso not (!foundBad) then
@@ -172,7 +172,8 @@ fun classify (ds, ps) =
else if IS.member (pull_ids, n) then
ServerAndPull
else
- ServerOnly)) ps
+ ServerOnly,
+ b)) ps
in
(ds, ps)
end
diff --git a/src/shake.sml b/src/shake.sml
index ae3e2ea5..39ebdde0 100644
--- a/src/shake.sml
+++ b/src/shake.sml
@@ -67,7 +67,7 @@ fun shake file =
val (usedE, usedC) =
List.foldl
- (fn ((DExport (_, n), _), (usedE, usedC)) => (IS.add (usedE, n), usedC)
+ (fn ((DExport (_, n, _), _), (usedE, usedC)) => (IS.add (usedE, n), usedC)
| ((DTable (_, _, c, _, pe, pc, ce, cc), _), (usedE, usedC)) =>
let
val usedC = usedVarsC usedC c
diff --git a/src/tag.sml b/src/tag.sml
index f1aef1ce..fdc04c81 100644
--- a/src/tag.sml
+++ b/src/tag.sml
@@ -197,7 +197,7 @@ fun tag file =
fun doDecl (d as (d', loc), (env, count, tags, byTag)) =
case d' of
- DExport (ek, n) =>
+ DExport (ek, n, _) =>
let
val (_, _, _, s) = E.lookupENamed env n
in
@@ -276,7 +276,7 @@ fun tag file =
end
in
(("wrap_" ^ fnam, cn, t, abs, tag),
- (DExport (ek, cn), loc))
+ (DExport (ek, cn, false), loc))
end) newTags
val (newVals, newExports) = ListPair.unzip newDs
--
cgit v1.2.3
From 9890b6de2e6877c67650f64410127ee2dfe8581e Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sun, 3 Jan 2010 12:47:27 -0500
Subject: Proper C-side deserialization; Shake.sliceDb
---
src/checknest.sml | 4 ++--
src/cjr.sml | 2 +-
src/cjr_print.sml | 36 +++++++++++++++++++++++++++++++++++-
src/cjrize.sml | 4 ++--
src/jscomp.sml | 9 +++++----
src/mono.sml | 2 +-
src/mono_print.sml | 6 +++---
src/mono_reduce.sml | 2 +-
src/mono_util.sml | 4 ++--
src/monoize.sml | 5 +++--
src/prepare.sml | 4 ++--
src/scriptcheck.sml | 2 +-
src/shake.sig | 3 +++
src/shake.sml | 24 +++++++++++++++++-------
14 files changed, 78 insertions(+), 29 deletions(-)
(limited to 'src/mono.sml')
diff --git a/src/checknest.sml b/src/checknest.sml
index c0f843d6..a53c7083 100644
--- a/src/checknest.sml
+++ b/src/checknest.sml
@@ -89,7 +89,7 @@ fun expUses globals =
end
| ESetval {seq, count} => IS.union (eu seq, eu count)
- | EUnurlify (e, _) => eu e
+ | EUnurlify (e, _, _) => eu e
in
eu
end
@@ -149,7 +149,7 @@ fun annotateExp globals =
(ESetval {seq = ae seq,
count = ae count}, loc)
- | EUnurlify (e, t) => (EUnurlify (ae e, t), loc)
+ | EUnurlify (e, t, b) => (EUnurlify (ae e, t, b), loc)
in
ae
end
diff --git a/src/cjr.sml b/src/cjr.sml
index 53448a29..a19109d2 100644
--- a/src/cjr.sml
+++ b/src/cjr.sml
@@ -96,7 +96,7 @@ datatype exp' =
| ENextval of { seq : exp,
prepared : {id : int, query : string} option }
| ESetval of { seq : exp, count : exp }
- | EUnurlify of exp * typ
+ | EUnurlify of exp * typ * bool
withtype exp = exp' located
diff --git a/src/cjr_print.sml b/src/cjr_print.sml
index 8c5a24b4..faf5f7b2 100644
--- a/src/cjr_print.sml
+++ b/src/cjr_print.sml
@@ -1863,7 +1863,7 @@ fun p_exp' par env (e, loc) =
newline,
string "})"]
- | EUnurlify (e, t) =>
+ | EUnurlify (e, t, true) =>
let
fun getIt () =
if isUnboxable t then
@@ -1898,6 +1898,40 @@ fun p_exp' par env (e, loc) =
string "})"]
end
+ | EUnurlify (e, t, false) =>
+ let
+ fun getIt () =
+ if isUnboxable t then
+ unurlify false env t
+ else
+ box [string "({",
+ newline,
+ p_typ env t,
+ string " *tmp = uw_malloc(ctx, sizeof(",
+ p_typ env t,
+ string "));",
+ newline,
+ string "*tmp = ",
+ unurlify false env t,
+ string ";",
+ newline,
+ string "tmp;",
+ newline,
+ string "})"]
+ in
+ box [string "({",
+ newline,
+ string "uw_Basis_string request = uw_maybe_strdup(ctx, ",
+ p_exp env e,
+ string ");",
+ newline,
+ newline,
+ unurlify false env t,
+ string ";",
+ newline,
+ string "})"]
+ end
+
and p_exp env = p_exp' false env
fun p_fun env (fx, n, args, ran, e) =
diff --git a/src/cjrize.sml b/src/cjrize.sml
index e2807372..6e41a69b 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -476,12 +476,12 @@ fun cifyExp (eAll as (e, loc), sm) =
((L'.ESetval {seq = e1, count = e2}, loc), sm)
end
- | L.EUnurlify (e, t) =>
+ | L.EUnurlify (e, t, b) =>
let
val (e, sm) = cifyExp (e, sm)
val (t, sm) = cifyTyp (t, sm)
in
- ((L'.EUnurlify (e, t), loc), sm)
+ ((L'.EUnurlify (e, t, b), loc), sm)
end
| L.EJavaScript _ => raise Fail "Cjrize: EJavaScript remains"
diff --git a/src/jscomp.sml b/src/jscomp.sml
index 11d75a3a..b99a6858 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -869,10 +869,11 @@ fun process file =
| EDml _ => unsupported "DML"
| ENextval _ => unsupported "Nextval"
| ESetval _ => unsupported "Nextval"
- | EReturnBlob _ => unsupported "EUnurlify"
+ | EReturnBlob _ => unsupported "EReturnBlob"
| ERedirect _ => unsupported "ERedirect"
+ | EUnurlify (_, _, true) => unsupported "EUnurlify"
- | EUnurlify (e, t) =>
+ | EUnurlify (e, t, false) =>
let
val (e, st) = jsE inner (e, st)
val (e', st) = unurlifyExp loc (t, st)
@@ -1162,11 +1163,11 @@ fun process file =
((ESetval (e1, e2), loc), st)
end
- | EUnurlify (e, t) =>
+ | EUnurlify (e, t, b) =>
let
val (e, st) = exp outer (e, st)
in
- ((EUnurlify (e, t), loc), st)
+ ((EUnurlify (e, t, b), loc), st)
end
| EJavaScript (m, e') =>
diff --git a/src/mono.sml b/src/mono.sml
index af5e9031..898feb9b 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -108,7 +108,7 @@ datatype exp' =
| ENextval of exp
| ESetval of exp * exp
- | EUnurlify of exp * typ
+ | EUnurlify of exp * typ * bool
| EJavaScript of javascript_mode * exp
diff --git a/src/mono_print.sml b/src/mono_print.sml
index a5e795b2..d1f5fc27 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -334,9 +334,9 @@ fun p_exp' par env (e, _) =
space,
p_exp env e2,
string ")"]
- | EUnurlify (e, _) => box [string "unurlify(",
- p_exp env e,
- string ")"]
+ | EUnurlify (e, _, _) => box [string "unurlify(",
+ p_exp env e,
+ string ")"]
| EJavaScript (m, e) => box [string "JavaScript(",
p_mode env m,
string ",",
diff --git a/src/mono_reduce.sml b/src/mono_reduce.sml
index 16cfd9f9..10de1c56 100644
--- a/src/mono_reduce.sml
+++ b/src/mono_reduce.sml
@@ -451,7 +451,7 @@ fun reduce file =
| EDml e => summarize d e @ [WriteDb]
| ENextval e => summarize d e @ [WriteDb]
| ESetval (e1, e2) => summarize d e1 @ summarize d e2 @ [WriteDb]
- | EUnurlify (e, _) => summarize d e
+ | EUnurlify (e, _, _) => summarize d e
| EJavaScript (_, e) => summarize d e
| ESignalReturn e => summarize d e
| ESignalBind (e1, e2) => summarize d e1 @ summarize d e2
diff --git a/src/mono_util.sml b/src/mono_util.sml
index 02619437..a75843c4 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -346,12 +346,12 @@ fun mapfoldB {typ = fc, exp = fe, bind} =
S.map2 (mfe ctx e2,
fn e2' =>
(ESetval (e1', e2'), loc)))
- | EUnurlify (e, t) =>
+ | EUnurlify (e, t, b) =>
S.bind2 (mfe ctx e,
fn e' =>
S.map2 (mft t,
fn t' =>
- (EUnurlify (e', t'), loc)))
+ (EUnurlify (e', t', b), loc)))
| EJavaScript (m, e) =>
S.bind2 (mfmode ctx m,
fn m' =>
diff --git a/src/monoize.sml b/src/monoize.sml
index ff5a0f3a..bda6cfe4 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -1338,7 +1338,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
((L'.EAbs ("c", s, (L'.TFun (un, s), loc),
(L'.EAbs ("_", un, s,
(L'.EUnurlify ((L'.EFfiApp ("Basis", "get_cookie", [(L'.ERel 1, loc)]), loc),
- t),
+ t, true),
loc)), loc)), loc),
fm)
end
@@ -3255,7 +3255,8 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
let
val t = monoType env t
in
- ((L'.EAbs ("v", (L'.TFfi ("Basis", "string"), loc), t, (L'.EUnurlify ((L'.ERel 0, loc), t), loc)), loc),
+ ((L'.EAbs ("v", (L'.TFfi ("Basis", "string"), loc), t, (L'.EUnurlify ((L'.ERel 0, loc), t, false),
+ loc)), loc),
fm)
end
diff --git a/src/prepare.sml b/src/prepare.sml
index 2d144c67..2f49405b 100644
--- a/src/prepare.sml
+++ b/src/prepare.sml
@@ -281,11 +281,11 @@ fun prepExp (e as (_, loc), st) =
((ESetval {seq = e1, count = e2}, loc), st)
end
- | EUnurlify (e, t) =>
+ | EUnurlify (e, t, b) =>
let
val (e, st) = prepExp (e, st)
in
- ((EUnurlify (e, t), loc), st)
+ ((EUnurlify (e, t, b), loc), st)
end
fun prepDecl (d as (_, loc), st) =
diff --git a/src/scriptcheck.sml b/src/scriptcheck.sml
index 7dec8d80..129f4281 100644
--- a/src/scriptcheck.sml
+++ b/src/scriptcheck.sml
@@ -115,7 +115,7 @@ fun classify (ds, ps) =
| EDml {dml, ...} => hasClient dml
| ENextval {seq, ...} => hasClient seq
| ESetval {seq, count, ...} => hasClient seq orelse hasClient count
- | EUnurlify (e, _) => hasClient e
+ | EUnurlify (e, _, _) => hasClient e
in
hasClient
end
diff --git a/src/shake.sig b/src/shake.sig
index 6c617435..2b805dea 100644
--- a/src/shake.sig
+++ b/src/shake.sig
@@ -31,4 +31,7 @@ signature SHAKE = sig
val shake : Core.file -> Core.file
+ val sliceDb : bool ref
+ (* Set this to try to delete anything not needed to determine the database schema. *)
+
end
diff --git a/src/shake.sml b/src/shake.sml
index 39ebdde0..686a043c 100644
--- a/src/shake.sml
+++ b/src/shake.sml
@@ -29,6 +29,8 @@
structure Shake :> SHAKE = struct
+val sliceDb = ref false
+
open Core
structure U = CoreUtil
@@ -67,7 +69,11 @@ fun shake file =
val (usedE, usedC) =
List.foldl
- (fn ((DExport (_, n, _), _), (usedE, usedC)) => (IS.add (usedE, n), usedC)
+ (fn ((DExport (_, n, _), _), st as (usedE, usedC)) =>
+ if !sliceDb then
+ st
+ else
+ (IS.add (usedE, n), usedC)
| ((DTable (_, _, c, _, pe, pc, ce, cc), _), (usedE, usedC)) =>
let
val usedC = usedVarsC usedC c
@@ -79,7 +85,11 @@ fun shake file =
in
(usedE, usedC)
end
- | ((DTask (e1, e2), _), st) => usedVars (usedVars st e1) e2
+ | ((DTask (e1, e2), _), st) =>
+ if !sliceDb then
+ st
+ else
+ usedVars (usedVars st e1) e2
| (_, acc) => acc) (IS.empty, IS.empty) file
val (cdef, edef) = foldl (fn ((DCon (_, n, _, c), _), (cdef, edef)) => (IM.insert (cdef, n, [c]), edef)
@@ -186,14 +196,14 @@ fun shake file =
| (DDatatype dts, _) => List.exists (fn (_, n, _, _) => IS.member (#con s, n)) dts
| (DVal (_, n, _, _, _), _) => IS.member (#exp s, n)
| (DValRec vis, _) => List.exists (fn (_, n, _, _, _) => IS.member (#exp s, n)) vis
- | (DExport _, _) => true
+ | (DExport _, _) => not (!sliceDb)
| (DView _, _) => true
| (DSequence _, _) => true
| (DTable _, _) => true
- | (DDatabase _, _) => true
- | (DCookie _, _) => true
- | (DStyle _, _) => true
- | (DTask _, _) => true) file
+ | (DDatabase _, _) => not (!sliceDb)
+ | (DCookie _, _) => not (!sliceDb)
+ | (DStyle _, _) => not (!sliceDb)
+ | (DTask _, _) => not (!sliceDb)) file
end
end
--
cgit v1.2.3
From 6a326e3bb3eb16e04f3cca082f0dd67278e85785 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sun, 4 Apr 2010 12:29:34 -0400
Subject: Pushing policies through
---
lib/ur/basis.urs | 9 +++++++++
src/cjrize.sml | 1 +
src/core.sml | 1 +
src/core_env.sml | 1 +
src/core_print.sml | 3 +++
src/core_util.sml | 8 +++++++-
src/corify.sml | 6 +++++-
src/css.sml | 1 +
src/elab.sml | 1 +
src/elab_env.sml | 1 +
src/elab_print.sml | 3 +++
src/elab_util.sml | 8 +++++++-
src/elaborate.sml | 10 ++++++++++
src/elisp/urweb-defs.el | 6 +++---
src/elisp/urweb-mode.el | 4 ++--
src/expl.sml | 1 +
src/expl_env.sml | 1 +
src/expl_print.sml | 3 +++
src/explify.sml | 1 +
src/mono.sml | 6 +++++-
src/mono_env.sml | 1 +
src/mono_print.sml | 9 +++++++++
src/mono_shake.sml | 13 +++++++++++--
src/mono_util.sml | 14 +++++++++++++-
src/monoize.sml | 14 ++++++++++++++
src/reduce.sml | 9 +++++++++
src/reduce_local.sml | 1 +
src/shake.sml | 11 +++++++++--
src/source.sml | 1 +
src/source_print.sml | 3 +++
src/unnest.sml | 1 +
src/urweb.grm | 3 ++-
src/urweb.lex | 1 +
tests/policy.ur | 3 +++
tests/policy.urp | 1 +
35 files changed, 145 insertions(+), 15 deletions(-)
create mode 100644 tests/policy.ur
create mode 100644 tests/policy.urp
(limited to 'src/mono.sml')
diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs
index 8388e107..aad04b5f 100644
--- a/lib/ur/basis.urs
+++ b/lib/ur/basis.urs
@@ -795,4 +795,13 @@ type task_kind
val initialize : task_kind
+(** Information flow security *)
+
+type sql_policy
+
+val query_policy : tables ::: {{Type}} -> exps ::: {Type}
+ -> [tables ~ exps] => sql_query [] tables exps
+ -> sql_policy
+
+
val debug : string -> transaction unit
diff --git a/src/cjrize.sml b/src/cjrize.sml
index 6e41a69b..b98b3c25 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -674,6 +674,7 @@ fun cifyDecl ((d, loc), sm) =
end
| _ => (ErrorMsg.errorAt loc "Initializer has not been fully determined";
(NONE, NONE, sm)))
+ | L.DPolicy _ => (NONE, NONE, sm)
fun cjrize ds =
let
diff --git a/src/core.sml b/src/core.sml
index 90005f16..e5358f48 100644
--- a/src/core.sml
+++ b/src/core.sml
@@ -135,6 +135,7 @@ datatype decl' =
| DCookie of string * int * con * string
| DStyle of string * int * string
| DTask of exp * exp
+ | DPolicy of exp
withtype decl = decl' located
diff --git a/src/core_env.sml b/src/core_env.sml
index 9001e29c..478ef495 100644
--- a/src/core_env.sml
+++ b/src/core_env.sml
@@ -349,6 +349,7 @@ fun declBinds env (d, loc) =
pushENamed env x n t NONE s
end
| DTask _ => env
+ | DPolicy _ => env
fun patBinds env (p, loc) =
case p of
diff --git a/src/core_print.sml b/src/core_print.sml
index d6be76a3..fd0556e6 100644
--- a/src/core_print.sml
+++ b/src/core_print.sml
@@ -618,6 +618,9 @@ fun p_decl env (dAll as (d, _) : decl) =
string "=",
space,
p_exp env e2]
+ | DPolicy e1 => box [string "policy",
+ space,
+ p_exp env e1]
fun p_file env file =
let
diff --git a/src/core_util.sml b/src/core_util.sml
index 247dd32e..eedcd2bb 100644
--- a/src/core_util.sml
+++ b/src/core_util.sml
@@ -992,6 +992,10 @@ fun mapfoldB {kind = fk, con = fc, exp = fe, decl = fd, bind} =
S.map2 (mfe ctx e2,
fn e2' =>
(DTask (e1', e2'), loc)))
+ | DPolicy e =>
+ S.map2 (mfe ctx e,
+ fn e' =>
+ (DPolicy e', loc))
and mfvi ctx (x, n, t, e, s) =
S.bind2 (mfc ctx t,
@@ -1147,6 +1151,7 @@ fun mapfoldB (all as {bind, ...}) =
bind (ctx, NamedE (x, n, t, NONE, s))
end
| DTask _ => ctx
+ | DPolicy _ => ctx
in
S.map2 (mff ctx' ds',
fn ds' =>
@@ -1210,7 +1215,8 @@ val maxName = foldl (fn ((d, _) : decl, count) =>
| DDatabase _ => count
| DCookie (_, n, _, _) => Int.max (n, count)
| DStyle (_, n, _) => Int.max (n, count)
- | DTask _ => count) 0
+ | DTask _ => count
+ | DPolicy _ => count) 0
end
diff --git a/src/corify.sml b/src/corify.sml
index 6931600e..88473455 100644
--- a/src/corify.sml
+++ b/src/corify.sml
@@ -1080,6 +1080,9 @@ fun corifyDecl mods (all as (d, loc : EM.span), st) =
| L.DTask (e1, e2) =>
([(L'.DTask (corifyExp st e1, corifyExp st e2), loc)], st)
+ | L.DPolicy e1 =>
+ ([(L'.DPolicy (corifyExp st e1), loc)], st)
+
and corifyStr mods ((str, _), st) =
case str of
L.StrConst ds =>
@@ -1137,7 +1140,8 @@ fun maxName ds = foldl (fn ((d, _), n) =>
| L.DDatabase _ => n
| L.DCookie (_, _, n', _) => Int.max (n, n')
| L.DStyle (_, _, n') => Int.max (n, n')
- | L.DTask _ => n)
+ | L.DTask _ => n
+ | L.DPolicy _ => n)
0 ds
and maxNameStr (str, _) =
diff --git a/src/css.sml b/src/css.sml
index 7189904f..3df35ed1 100644
--- a/src/css.sml
+++ b/src/css.sml
@@ -287,6 +287,7 @@ fun summarize file =
| DCookie _ => st
| DStyle (_, n, s) => (IM.insert (globals, n, (SOME s, [])), classes)
| DTask _ => st
+ | DPolicy _ => st
end
val (globals, classes) = foldl decl (IM.empty, IM.empty) file
diff --git a/src/elab.sml b/src/elab.sml
index a0f9a4e8..e040a059 100644
--- a/src/elab.sml
+++ b/src/elab.sml
@@ -171,6 +171,7 @@ datatype decl' =
| DCookie of int * string * int * con
| DStyle of int * string * int
| DTask of exp * exp
+ | DPolicy of exp
and str' =
StrConst of decl list
diff --git a/src/elab_env.sml b/src/elab_env.sml
index 5092c6fb..dd050c9e 100644
--- a/src/elab_env.sml
+++ b/src/elab_env.sml
@@ -1623,5 +1623,6 @@ fun declBinds env (d, loc) =
pushENamedAs env x n t
end
| DTask _ => env
+ | DPolicy _ => env
end
diff --git a/src/elab_print.sml b/src/elab_print.sml
index 62b5262f..86448659 100644
--- a/src/elab_print.sml
+++ b/src/elab_print.sml
@@ -806,6 +806,9 @@ fun p_decl env (dAll as (d, _) : decl) =
string "=",
space,
p_exp env e2]
+ | DPolicy e1 => box [string "policy",
+ space,
+ p_exp env e1]
and p_str env (str, _) =
case str of
diff --git a/src/elab_util.sml b/src/elab_util.sml
index d0e140c5..8345e3f3 100644
--- a/src/elab_util.sml
+++ b/src/elab_util.sml
@@ -854,7 +854,8 @@ fun mapfoldB {kind = fk, con = fc, exp = fe, sgn_item = fsgi, sgn = fsg, str = f
c), loc)))
| DStyle (tn, x, n) =>
bind (ctx, NamedE (x, (CModProj (n, [], "css_class"), loc)))
- | DTask _ => ctx,
+ | DTask _ => ctx
+ | DPolicy _ => ctx,
mfd ctx d)) ctx ds,
fn ds' => (StrConst ds', loc))
| StrVar _ => S.return2 strAll
@@ -985,6 +986,10 @@ fun mapfoldB {kind = fk, con = fc, exp = fe, sgn_item = fsgi, sgn = fsg, str = f
S.map2 (mfe ctx e2,
fn e2' =>
(DTask (e1', e2'), loc)))
+ | DPolicy e1 =>
+ S.map2 (mfe ctx e1,
+ fn e1' =>
+ (DPolicy e1', loc))
and mfvi ctx (x, n, c, e) =
S.bind2 (mfc ctx c,
@@ -1128,6 +1133,7 @@ and maxNameDecl (d, _) =
| DCookie (n1, _, n2, _) => Int.max (n1, n2)
| DStyle (n1, _, n2) => Int.max (n1, n2)
| DTask _ => 0
+ | DPolicy _ => 0
and maxNameStr (str, _) =
case str of
StrConst ds => maxName ds
diff --git a/src/elaborate.sml b/src/elaborate.sml
index 1651f344..07818a57 100644
--- a/src/elaborate.sml
+++ b/src/elaborate.sml
@@ -2595,6 +2595,7 @@ and sgiOfDecl (d, loc) =
| L'.DCookie (tn, x, n, c) => [(L'.SgiVal (x, n, (L'.CApp (cookieOf (), c), loc)), loc)]
| L'.DStyle (tn, x, n) => [(L'.SgiVal (x, n, styleOf ()), loc)]
| L'.DTask _ => []
+ | L'.DPolicy _ => []
and subSgn' counterparts env strLoc sgn1 (sgn2 as (_, loc2)) =
((*prefaces "subSgn" [("sgn1", p_sgn env sgn1),
@@ -3729,6 +3730,15 @@ and elabDecl (dAll as (d, loc), (env, denv, gs)) =
checkCon env e2' t2 t2';
([(L'.DTask (e1', e2'), loc)], (env, denv, gs2 @ gs1 @ gs))
end
+ | L.DPolicy e1 =>
+ let
+ val (e1', t1, gs1) = elabExp (env, denv) e1
+
+ val t1' = (L'.CModProj (!basis_r, [], "sql_policy"), loc)
+ in
+ checkCon env e1' t1 t1';
+ ([(L'.DPolicy e1', loc)], (env, denv, gs1 @ gs))
+ end
(*val tcs = List.filter (fn TypeClass _ => true | _ => false) (#3 (#2 r))*)
in
diff --git a/src/elisp/urweb-defs.el b/src/elisp/urweb-defs.el
index c697a274..8054d829 100644
--- a/src/elisp/urweb-defs.el
+++ b/src/elisp/urweb-defs.el
@@ -108,7 +108,7 @@ notion of \"the end of an outline\".")
"datatype" "type" "open" "include"
urweb-module-head-syms
"con" "map" "where" "extern" "constraint" "constraints"
- "table" "sequence" "class" "cookie" "task")
+ "table" "sequence" "class" "cookie" "task" "policy")
"Symbols starting an sexp.")
;; (defconst urweb-not-arg-start-re
@@ -135,7 +135,7 @@ notion of \"the end of an outline\".")
(("case" "datatype" "if" "then" "else"
"let" "open" "sig" "struct" "type" "val"
"con" "constraint" "table" "sequence" "class" "cookie"
- "task")))))
+ "task" "policy")))))
(defconst urweb-starters-indent-after
(urweb-syms-re "let" "in" "struct" "sig")
@@ -190,7 +190,7 @@ for all symbols and in all lines starting with the given symbol."
'("datatype" "fun"
"open" "type" "val" "and"
"con" "constraint" "table" "sequence" "class" "cookie"
- "task"))
+ "task" "policy"))
"The starters of new expressions.")
(defconst urweb-exptrail-syms
diff --git a/src/elisp/urweb-mode.el b/src/elisp/urweb-mode.el
index 107ea3bc..c9fe5f19 100644
--- a/src/elisp/urweb-mode.el
+++ b/src/elisp/urweb-mode.el
@@ -136,7 +136,7 @@ See doc for the variable `urweb-mode-info'."
"datatype" "else" "end" "extern" "fn" "map"
"fun" "functor" "if" "include"
"of" "open" "let" "in"
- "rec" "sequence" "sig" "signature" "cookie" "style" "task"
+ "rec" "sequence" "sig" "signature" "cookie" "style" "task" "policy"
"struct" "structure" "table" "view" "then" "type" "val" "where"
"with"
@@ -226,7 +226,7 @@ See doc for the variable `urweb-mode-info'."
("\\<\\(\\(data\\)?type\\|con\\|class\\)\\s-+\\(\\sw+\\)"
(1 font-lock-keyword-face)
(3 (amAttribute font-lock-type-def-face)))
- ("\\<\\(val\\|table\\|sequence\\|cookie\\|style\\|task\\)\\s-+\\(\\sw+\\>\\s-*\\)?\\(\\sw+\\)\\s-*[=:]"
+ ("\\<\\(val\\|table\\|sequence\\|cookie\\|style\\|task\\|policy\\)\\s-+\\(\\sw+\\>\\s-*\\)?\\(\\sw+\\)\\s-*[=:]"
(1 font-lock-keyword-face)
(3 (amAttribute font-lock-variable-name-face)))
("\\<\\(structure\\|functor\\)\\s-+\\(\\sw+\\)"
diff --git a/src/expl.sml b/src/expl.sml
index 17797626..1212383f 100644
--- a/src/expl.sml
+++ b/src/expl.sml
@@ -148,6 +148,7 @@ datatype decl' =
| DCookie of int * string * int * con
| DStyle of int * string * int
| DTask of exp * exp
+ | DPolicy of exp
and str' =
StrConst of decl list
diff --git a/src/expl_env.sml b/src/expl_env.sml
index 0bf7323f..583e4881 100644
--- a/src/expl_env.sml
+++ b/src/expl_env.sml
@@ -344,6 +344,7 @@ fun declBinds env (d, loc) =
pushENamed env x n t
end
| DTask _ => env
+ | DPolicy _ => env
fun sgiBinds env (sgi, loc) =
case sgi of
diff --git a/src/expl_print.sml b/src/expl_print.sml
index 5284eecb..15838729 100644
--- a/src/expl_print.sml
+++ b/src/expl_print.sml
@@ -720,6 +720,9 @@ fun p_decl env (dAll as (d, _) : decl) =
string "=",
space,
p_exp env e2]
+ | DPolicy e1 => box [string "policy",
+ space,
+ p_exp env e1]
and p_str env (str, _) =
case str of
diff --git a/src/explify.sml b/src/explify.sml
index aff91a34..0013906f 100644
--- a/src/explify.sml
+++ b/src/explify.sml
@@ -196,6 +196,7 @@ fun explifyDecl (d, loc : EM.span) =
| L.DCookie (nt, x, n, c) => SOME (L'.DCookie (nt, x, n, explifyCon c), loc)
| L.DStyle (nt, x, n) => SOME (L'.DStyle (nt, x, n), loc)
| L.DTask (e1, e2) => SOME (L'.DTask (explifyExp e1, explifyExp e2), loc)
+ | L.DPolicy e1 => SOME (L'.DPolicy (explifyExp e1), loc)
and explifyStr (str, loc) =
case str of
diff --git a/src/mono.sml b/src/mono.sml
index 898feb9b..33ab5bd4 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -1,4 +1,4 @@
-(* Copyright (c) 2008, Adam Chlipala
+(* Copyright (c) 2008-2010, Adam Chlipala
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -123,6 +123,8 @@ datatype exp' =
withtype exp = exp' located
+datatype policy = PolQuery of exp
+
datatype decl' =
DDatatype of (string * int * (string * int * typ option) list) list
| DVal of string * int * typ * exp * string
@@ -141,6 +143,8 @@ datatype decl' =
| DTask of exp * exp
+ | DPolicy of policy
+
withtype decl = decl' located
type file = decl list
diff --git a/src/mono_env.sml b/src/mono_env.sml
index c2e6cf02..87f96488 100644
--- a/src/mono_env.sml
+++ b/src/mono_env.sml
@@ -130,6 +130,7 @@ fun declBinds env (d, loc) =
| DCookie _ => env
| DStyle _ => env
| DTask _ => env
+ | DPolicy _ => env
fun patBinds env (p, loc) =
case p of
diff --git a/src/mono_print.sml b/src/mono_print.sml
index d1f5fc27..50c4717a 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -412,6 +412,12 @@ fun p_datatype env (x, n, cons) =
cons]
end
+fun p_policy env pol =
+ case pol of
+ PolQuery e => box [string "query",
+ space,
+ p_exp env e]
+
fun p_decl env (dAll as (d, _) : decl) =
case d of
DDatatype x => box [string "datatype",
@@ -506,6 +512,9 @@ fun p_decl env (dAll as (d, _) : decl) =
string "=",
space,
p_exp env e2]
+ | DPolicy p => box [string "policy",
+ space,
+ p_policy env p]
fun p_file env file =
diff --git a/src/mono_shake.sml b/src/mono_shake.sml
index e53b6930..358b31d2 100644
--- a/src/mono_shake.sml
+++ b/src/mono_shake.sml
@@ -58,6 +58,13 @@ fun shake file =
| ((DDatabase {expunge = n1, initialize = n2, ...}, _), (page_cs, page_es)) =>
(page_cs, IS.addList (page_es, [n1, n2]))
| ((DTask (e1, e2), _), st) => usedVars (usedVars st e2) e1
+ | ((DPolicy pol, _), st) =>
+ let
+ val e1 = case pol of
+ PolQuery e1 => e1
+ in
+ usedVars st e1
+ end
| (_, st) => st) (IS.empty, IS.empty) file
val (cdef, edef) = foldl (fn ((DDatatype dts, _), (cdef, edef)) =>
@@ -74,7 +81,8 @@ fun shake file =
| ((DJavaScript _, _), acc) => acc
| ((DCookie _, _), acc) => acc
| ((DStyle _, _), acc) => acc
- | ((DTask _, _), acc) => acc)
+ | ((DTask _, _), acc) => acc
+ | ((DPolicy _, _), acc) => acc)
(IM.empty, IM.empty) file
fun typ (c, s) =
@@ -141,7 +149,8 @@ fun shake file =
| (DJavaScript _, _) => true
| (DCookie _, _) => true
| (DStyle _, _) => true
- | (DTask _, _) => true) file
+ | (DTask _, _) => true
+ | (DPolicy _, _) => true) file
end
end
diff --git a/src/mono_util.sml b/src/mono_util.sml
index a75843c4..094f216b 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -534,6 +534,16 @@ fun mapfoldB {typ = fc, exp = fe, decl = fd, bind} =
S.map2 (mfe ctx e2,
fn e2' =>
(DTask (e1', e2'), loc)))
+ | DPolicy pol =>
+ S.map2 (mfpol ctx pol,
+ fn p' =>
+ (DPolicy p', loc))
+
+ and mfpol ctx pol =
+ case pol of
+ PolQuery e =>
+ S.map2 (mfe ctx e,
+ PolQuery)
and mfvi ctx (x, n, t, e, s) =
S.bind2 (mft t,
@@ -621,6 +631,7 @@ fun mapfoldB (all as {bind, ...}) =
| DCookie _ => ctx
| DStyle _ => ctx
| DTask _ => ctx
+ | DPolicy _ => ctx
in
S.map2 (mff ctx' ds',
fn ds' =>
@@ -674,7 +685,8 @@ val maxName = foldl (fn ((d, _) : decl, count) =>
| DJavaScript _ => count
| DCookie _ => count
| DStyle _ => count
- | DTask _ => count) 0
+ | DTask _ => count
+ | DPolicy _ => count) 0
end
diff --git a/src/monoize.sml b/src/monoize.sml
index 25ea87f5..6f229766 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -3738,6 +3738,20 @@ fun monoDecl (env, fm) (all as (d, loc)) =
fm,
[(L'.DTask (e1, e2), loc)])
end
+ | L.DPolicy e =>
+ let
+ val (e, make) =
+ case #1 e of
+ L.EApp ((L.ECApp ((L.ECApp ((L.EFfi ("Basis", "query_policy"), _), _), _), _), _), e) =>
+ (e, L'.PolQuery)
+ | _ => (poly (); (e, L'.PolQuery))
+
+ val (e, fm) = monoExp (env, St.empty, fm) e
+ in
+ SOME (env,
+ fm,
+ [(L'.DPolicy (make e), loc)])
+ end
end
datatype expungable = Client | Channel
diff --git a/src/reduce.sml b/src/reduce.sml
index b7ad567a..cefe1955 100644
--- a/src/reduce.sml
+++ b/src/reduce.sml
@@ -746,6 +746,15 @@ fun reduce file =
namedC,
namedE))
end
+ | DPolicy e1 =>
+ let
+ val e1 = exp (namedC, namedE) [] e1
+ in
+ ((DPolicy e1, loc),
+ (polyC,
+ namedC,
+ namedE))
+ end
val (file, _) = ListUtil.foldlMap doDecl (IS.empty, IM.empty, IM.empty) file
in
diff --git a/src/reduce_local.sml b/src/reduce_local.sml
index b040a1ec..4c5ab52e 100644
--- a/src/reduce_local.sml
+++ b/src/reduce_local.sml
@@ -252,6 +252,7 @@ fun reduce file =
| DCookie _ => d
| DStyle _ => d
| DTask (e1, e2) => (DTask (exp [] e1, exp [] e2), loc)
+ | DPolicy e1 => (DPolicy (exp [] e1), loc)
in
map doDecl file
end
diff --git a/src/shake.sml b/src/shake.sml
index 686a043c..f679c6e8 100644
--- a/src/shake.sml
+++ b/src/shake.sml
@@ -90,6 +90,11 @@ fun shake file =
st
else
usedVars (usedVars st e1) e2
+ | ((DPolicy e1, _), st) =>
+ if !sliceDb then
+ st
+ else
+ usedVars st e1
| (_, acc) => acc) (IS.empty, IS.empty) file
val (cdef, edef) = foldl (fn ((DCon (_, n, _, c), _), (cdef, edef)) => (IM.insert (cdef, n, [c]), edef)
@@ -116,7 +121,8 @@ fun shake file =
(cdef, IM.insert (edef, n, ([], c, dummye)))
| ((DStyle (_, n, _), _), (cdef, edef)) =>
(cdef, IM.insert (edef, n, ([], dummyt, dummye)))
- | ((DTask _, _), acc) => acc)
+ | ((DTask _, _), acc) => acc
+ | ((DPolicy _, _), acc) => acc)
(IM.empty, IM.empty) file
fun kind (_, s) = s
@@ -203,7 +209,8 @@ fun shake file =
| (DDatabase _, _) => not (!sliceDb)
| (DCookie _, _) => not (!sliceDb)
| (DStyle _, _) => not (!sliceDb)
- | (DTask _, _) => not (!sliceDb)) file
+ | (DTask _, _) => not (!sliceDb)
+ | (DPolicy _, _) => not (!sliceDb)) file
end
end
diff --git a/src/source.sml b/src/source.sml
index dc867026..9768cfc0 100644
--- a/src/source.sml
+++ b/src/source.sml
@@ -168,6 +168,7 @@ datatype decl' =
| DCookie of string * con
| DStyle of string
| DTask of exp * exp
+ | DPolicy of exp
and str' =
StrConst of decl list
diff --git a/src/source_print.sml b/src/source_print.sml
index e3b4fe94..590d15d5 100644
--- a/src/source_print.sml
+++ b/src/source_print.sml
@@ -669,6 +669,9 @@ fun p_decl ((d, _) : decl) =
string "=",
space,
p_exp e2]
+ | DPolicy e1 => box [string "policy",
+ space,
+ p_exp e1]
and p_str (str, _) =
case str of
diff --git a/src/unnest.sml b/src/unnest.sml
index e030bbc6..77589bfb 100644
--- a/src/unnest.sml
+++ b/src/unnest.sml
@@ -423,6 +423,7 @@ fun unnest file =
| DCookie _ => default ()
| DStyle _ => default ()
| DTask _ => explore ()
+ | DPolicy _ => explore ()
end
and doStr (all as (str, loc), st) =
diff --git a/src/urweb.grm b/src/urweb.grm
index ad3de6b2..3df9554f 100644
--- a/src/urweb.grm
+++ b/src/urweb.grm
@@ -202,7 +202,7 @@ fun patType loc (p : pat) =
| LET | IN
| STRUCTURE | SIGNATURE | STRUCT | SIG | END | FUNCTOR | WHERE | EXTERN | SQL | SELECT1
| INCLUDE | OPEN | CONSTRAINT | CONSTRAINTS | EXPORT | TABLE | SEQUENCE | VIEW
- | COOKIE | STYLE | TASK
+ | COOKIE | STYLE | TASK | POLICY
| CASE | IF | THEN | ELSE | ANDALSO | ORELSE
| XML_BEGIN of string | XML_END | XML_BEGIN_END of string
@@ -481,6 +481,7 @@ decl : CON SYMBOL cargl2 kopt EQ cexp (let
| COOKIE SYMBOL COLON cexp ([(DCookie (SYMBOL, cexp), s (COOKIEleft, cexpright))])
| STYLE SYMBOL ([(DStyle SYMBOL, s (STYLEleft, SYMBOLright))])
| TASK eapps EQ eexp ([(DTask (eapps, eexp), s (TASKleft, eexpright))])
+ | POLICY eexp ([(DPolicy eexp, s (POLICYleft, eexpright))])
dtype : SYMBOL dargs EQ barOpt dcons (SYMBOL, dargs, dcons)
diff --git a/src/urweb.lex b/src/urweb.lex
index 45f555dd..8930c463 100644
--- a/src/urweb.lex
+++ b/src/urweb.lex
@@ -416,6 +416,7 @@ xint = x[0-9a-fA-F][0-9a-fA-F];
"cookie" => (Tokens.COOKIE (pos yypos, pos yypos + size yytext));
"style" => (Tokens.STYLE (pos yypos, pos yypos + size yytext));
"task" => (Tokens.TASK (pos yypos, pos yypos + size yytext));
+ "policy" => (Tokens.POLICY (pos yypos, pos yypos + size yytext));
"Type" => (Tokens.TYPE (pos yypos, pos yypos + size yytext));
"Name" => (Tokens.NAME (pos yypos, pos yypos + size yytext));
diff --git a/tests/policy.ur b/tests/policy.ur
new file mode 100644
index 00000000..db87b582
--- /dev/null
+++ b/tests/policy.ur
@@ -0,0 +1,3 @@
+table fruit : { Id : int, Nam : string, Weight : float }
+
+policy query_policy (SELECT * FROM fruit)
diff --git a/tests/policy.urp b/tests/policy.urp
new file mode 100644
index 00000000..b26ebd4a
--- /dev/null
+++ b/tests/policy.urp
@@ -0,0 +1 @@
+policy
--
cgit v1.2.3
From ed25721e17d6798aad7b7a0cea8e5393bb840a91 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Thu, 8 Apr 2010 09:57:37 -0400
Subject: Change query_policy to sendClient; all arguments passed to SQL
predicates are variables
---
lib/ur/basis.urs | 6 +-
src/iflow.sml | 207 ++++++++++++++++++++++++++++++++--------------------
src/mono.sml | 2 +-
src/mono_print.sml | 6 +-
src/mono_reduce.sml | 17 +++--
src/mono_shake.sml | 2 +-
src/mono_util.sml | 4 +-
src/monoize.sml | 6 +-
tests/policy.ur | 20 ++---
9 files changed, 162 insertions(+), 108 deletions(-)
(limited to 'src/mono.sml')
diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs
index 72970351..959a050d 100644
--- a/lib/ur/basis.urs
+++ b/lib/ur/basis.urs
@@ -800,9 +800,9 @@ val initialize : task_kind
type sql_policy
-val query_policy : tables ::: {{Type}} -> exps ::: {Type}
- -> [tables ~ exps] => sql_query [] tables exps
- -> sql_policy
+val sendClient : tables ::: {{Type}} -> exps ::: {Type}
+ -> [tables ~ exps] => sql_query [] tables exps
+ -> sql_policy
val debug : string -> transaction unit
diff --git a/src/iflow.sml b/src/iflow.sml
index 92181d87..e49700cf 100644
--- a/src/iflow.sml
+++ b/src/iflow.sml
@@ -412,6 +412,7 @@ structure Cc :> sig
val assert : t * exp * exp -> t
val query : t * exp * exp -> bool
val allPeers : t * exp -> exp list
+ val p_t : t Print.printer
end = struct
fun eq (e1, e2) = eeq (simplify e1, simplify e2)
@@ -440,50 +441,102 @@ fun allPeers (t, e) =
end) t
end
-fun assert (t, e1, e2) =
- let
- val r1 = lookup (t, e1)
- val r2 = lookup (t, e2)
+open Print
- fun doUn k (t', e1, e2) =
- case e2 of
- Func (f, [e]) =>
+val p_t = p_list (fn (e1, e2) => box [p_exp (simplify e1),
+ space,
+ PD.string "->",
+ space,
+ p_exp (simplify e2)])
+
+fun query (t, e1, e2) =
+ let
+ fun doUn e =
+ case e of
+ Func (f, [e1]) =>
if String.isPrefix "un" f then
let
- val f' = String.extract (f, 2, NONE)
+ val s = String.extract (f, 2, NONE)
in
- foldl (fn (e', t') =>
- case e' of
- Func (f'', [e'']) =>
- if f'' = f' then
- (lookup (t', e1), k e'') :: t'
- else
- t'
- | _ => t') t' (allPeers (t, e))
+ case ListUtil.search (fn e =>
+ case e of
+ Func (f', [e']) =>
+ if f' = s then
+ SOME e'
+ else
+ NONE
+ | _ => NONE) (allPeers (t, e1)) of
+ NONE => e
+ | SOME e => doUn e
end
else
- t'
- | Proj (e2, f) => doUn (fn e' => k (Proj (e', f))) (t', e1, e2)
- | _ => t'
+ e
+ | _ => e
+
+ val e1' = doUn (lookup (t, doUn (simplify e1)))
+ val e2' = doUn (lookup (t, doUn (simplify e2)))
+ in
+ (*prefaces "CC query" [("e1", p_exp (simplify e1)),
+ ("e2", p_exp (simplify e2)),
+ ("e1'", p_exp (simplify e1')),
+ ("e2'", p_exp (simplify e2')),
+ ("t", p_t t)];*)
+ eq (e1', e2')
+ end
+
+fun assert (t, e1, e2) =
+ let
+ val r1 = lookup (t, e1)
+ val r2 = lookup (t, e2)
in
if eq (r1, r2) then
t
else
- doUn (fn x => x) (doUn (fn x => x) ((r1, r2) :: t, e1, e2), e2, e1)
+ let
+ fun doUn (t, e1, e2) =
+ case e1 of
+ Func (f, [e]) => if String.isPrefix "un" f then
+ let
+ val s = String.extract (f, 2, NONE)
+ in
+ foldl (fn (e', t) =>
+ case e' of
+ Func (f', [e']) =>
+ if f' = s then
+ assert (assert (t, e', e1), e', e2)
+ else
+ t
+ | _ => t) t (allPeers (t, e))
+ end
+ else
+ t
+ | _ => t
+
+ fun doProj (t, e1, e2) =
+ foldl (fn ((e1', e2'), t) =>
+ let
+ fun doOne (e, t) =
+ case e of
+ Proj (e', f) =>
+ if query (t, e1, e') then
+ assert (t, e, Proj (e2, f))
+ else
+ t
+ | _ => t
+ in
+ doOne (e1', doOne (e2', t))
+ end) t t
+
+ val t = (r1, r2) :: t
+ val t = doUn (t, r1, r2)
+ val t = doUn (t, r2, r1)
+ val t = doProj (t, r1, r2)
+ val t = doProj (t, r2, r1)
+ in
+ t
+ end
end
-open Print
-
-fun query (t, e1, e2) =
- ((*prefaces "CC query" [("e1", p_exp (simplify e1)),
- ("e2", p_exp (simplify e2)),
- ("t", p_list (fn (e1, e2) => box [p_exp (simplify e1),
- space,
- PD.string "->",
- space,
- p_exp (simplify e2)]) t)];*)
- eq (lookup (t, e1), lookup (t, e2)))
-
end
fun rimp cc ((r1, es1), (r2, es2)) =
@@ -491,19 +544,7 @@ fun rimp cc ((r1, es1), (r2, es2)) =
(Sql r1', Sql r2') =>
r1' = r2' andalso
(case (es1, es2) of
- ([Recd xes1], [Recd xes2]) =>
- let
- val saved = save ()
- in
- if List.all (fn (f, e2) =>
- case ListUtil.search (fn (f', e1) => if f' = f then SOME e1 else NONE) xes1 of
- NONE => true
- | SOME e1 => eq (e1, e2)) xes2 then
- true
- else
- (restore saved;
- false)
- end
+ ([e1], [e2]) => eq (e1, e2)
| _ => false)
| (Eq, Eq) =>
(case (es1, es2) of
@@ -533,6 +574,9 @@ fun rimp cc ((r1, es1), (r2, es2)) =
| Func (f, [e]) => String.isPrefix "un" f andalso matches e
| _ => false
in
+ (*Print.prefaces "Checking peers" [("e2", p_exp e2),
+ ("peers", Print.p_list p_exp (Cc.allPeers (cc, e2))),
+ ("db", Cc.p_t cc)];*)
List.exists matches (Cc.allPeers (cc, e2))
end
| _ => false)
@@ -562,7 +606,8 @@ fun imply (p1, p2) =
let
fun hps hyps =
case hyps of
- [] => ((*Print.preface ("Fail", p_prop (Reln g));*)
+ [] => ((*Print.prefaces "Fail" [("g", p_prop (Reln g)),
+ ("db", Cc.p_t cc)];*)
onFail ())
| ACond _ :: hyps => hps hyps
| AReln h :: hyps =>
@@ -925,13 +970,27 @@ datatype queryMode =
SomeCol of exp
| AllCols of exp
-fun queryProp env rv oe e =
+fun queryProp env rvN rv oe e =
case parse query e of
NONE => (print ("Warning: Information flow checker can't parse SQL query at "
^ ErrorMsg.spanToString (#2 e) ^ "\n");
- (Unknown, []))
+ (rvN, Var 0, Unknown, []))
| SOME r =>
let
+ val (rvN, count) = rv rvN
+
+ val (rvs, rvN) = ListUtil.foldlMap (fn ((_, v), rvN) =>
+ let
+ val (rvN, e) = rv rvN
+ in
+ ((v, e), rvN)
+ end) rvN (#From r)
+
+ fun rvOf v =
+ case List.find (fn (v', _) => v' = v) rvs of
+ NONE => raise Fail "Iflow.queryProp: Bad table variable"
+ | SOME (_, e) => e
+
fun usedFields e =
case e of
SqConst _ => []
@@ -942,26 +1001,13 @@ fun queryProp env rv oe e =
| SqFunc (_, e) => usedFields e
| Count => []
- val allUsed = removeDups (List.mapPartial (fn SqField x => SOME x | _ => NONE) (#Select r)
- @ (case #Where r of
- NONE => []
- | SOME e => usedFields e))
-
val p =
- foldl (fn ((t, v), p) =>
- And (p,
- Reln (Sql t,
- [Recd (foldl (fn ((v', f), fs) =>
- if v' = v then
- (f, Proj (Proj (rv, v), f)) :: fs
- else
- fs) [] allUsed)])))
- True (#From r)
+ foldl (fn ((t, v), p) => And (p, Reln (Sql t, [rvOf v]))) True (#From r)
fun expIn e =
case e of
SqConst p => inl (Const p)
- | Field (v, f) => inl (Proj (Proj (rv, v), f))
+ | Field (v, f) => inl (Proj (rvOf v, f))
| Binop (bo, e1, e2) =>
inr (case (bo, expIn e1, expIn e2) of
(Exps f, inl e1, inl e2) => f (e1, e2)
@@ -985,7 +1031,7 @@ fun queryProp env rv oe e =
inl (case expIn e of
inl e => Func (f, [e])
| _ => raise Fail ("Iflow: non-expresion passed to function " ^ f))
- | Count => inl (Proj (rv, "$COUNT"))
+ | Count => inl count
val p = case #Where r of
NONE => p
@@ -994,12 +1040,14 @@ fun queryProp env rv oe e =
inr p' => And (p, p')
| _ => p
in
- (And (p, case oe of
+ (rvN,
+ count,
+ And (p, case oe of
SomeCol oe =>
foldl (fn (si, p) =>
let
val p' = case si of
- SqField (v, f) => Reln (Eq, [oe, Proj (Proj (rv, v), f)])
+ SqField (v, f) => Reln (Eq, [oe, Proj (rvOf v, f)])
| SqExp (e, f) =>
case expIn e of
inr _ => Unknown
@@ -1013,7 +1061,7 @@ fun queryProp env rv oe e =
let
val p' = case si of
SqField (v, f) => Reln (Eq, [Proj (Proj (oe, v), f),
- Proj (Proj (rv, v), f)])
+ Proj (rvOf v, f)])
| SqExp (e, f) =>
case expIn e of
inr p => Cond (Proj (oe, f), p)
@@ -1025,7 +1073,7 @@ fun queryProp env rv oe e =
case #Where r of
NONE => []
- | SOME e => map (fn (v, f) => Proj (Proj (rv, v), f)) (usedFields e))
+ | SOME e => map (fn (v, f) => Proj (rvOf v, f)) (usedFields e))
end
fun evalPat env e (pt, _) =
@@ -1118,7 +1166,7 @@ fun evalExp env (e as (_, loc), st as (nv, p, sent)) =
let
val (es, st) = ListUtil.foldlMap (evalExp env) st es
in
- (Func ("unit", []), (#1 st, p, foldl (fn (e, sent) => addSent (#2 st, e, sent)) sent es))
+ (Recd [], (#1 st, p, foldl (fn (e, sent) => addSent (#2 st, e, sent)) sent es))
end
else if Settings.isEffectful (m, s) andalso not (Settings.isBenignEffectful (m, s)) then
default ()
@@ -1213,7 +1261,7 @@ fun evalExp env (e as (_, loc), st as (nv, p, sent)) =
let
val (e, st) = evalExp env (e, st)
in
- (Func ("unit", []), (#1 st, p, addSent (#2 st, e, sent)))
+ (Recd [], (#1 st, p, addSent (#2 st, e, sent)))
end
| ESeq (e1, e2) =>
let
@@ -1240,13 +1288,15 @@ fun evalExp env (e as (_, loc), st as (nv, p, sent)) =
val (i, st) = evalExp env (i, st)
val r = #1 st
- val rv = #1 st + 1
- val acc = #1 st + 2
- val st' = (#1 st + 3, #2 st, #3 st)
+ val acc = #1 st + 1
+ val st' = (#1 st + 2, #2 st, #3 st)
val (b, st') = evalExp (Var acc :: Var r :: env) (b, st')
- val (qp, used) = queryProp env (Var rv) (AllCols (Var r)) q
+ val (rvN, count, qp, used) =
+ queryProp env
+ (#1 st') (fn rvN => (rvN + 1, Var rvN))
+ (AllCols (Var r)) q
val p' = And (qp, #2 st')
@@ -1254,11 +1304,11 @@ fun evalExp env (e as (_, loc), st as (nv, p, sent)) =
(#1 st + 1, #2 st, Var r)
else
let
- val out = #1 st'
+ val out = rvN
val p = Or (Reln (Eq, [Var out, i]),
And (Reln (Eq, [Var out, b]),
- And (Reln (Gt, [Proj (Var rv, "$COUNT"),
+ And (Reln (Gt, [count,
Const (Prim.Int 0)]),
p')))
in
@@ -1323,8 +1373,9 @@ fun check file =
(sent @ vals, pols)
end
- | DPolicy (PolQuery e) => (vals, #1 (queryProp [] (Lvar 0) (SomeCol (Var 0)) e) :: pols)
-
+ | DPolicy (PolClient e) => (vals, #3 (queryProp [] 0 (fn rvN => (rvN + 1, Lvar rvN))
+ (SomeCol (Var 0)) e) :: pols)
+
| _ => (vals, pols)
val () = reset ()
diff --git a/src/mono.sml b/src/mono.sml
index 33ab5bd4..f8f57ae7 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -123,7 +123,7 @@ datatype exp' =
withtype exp = exp' located
-datatype policy = PolQuery of exp
+datatype policy = PolClient of exp
datatype decl' =
DDatatype of (string * int * (string * int * typ option) list) list
diff --git a/src/mono_print.sml b/src/mono_print.sml
index 50c4717a..76a89cc7 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -414,9 +414,9 @@ fun p_datatype env (x, n, cons) =
fun p_policy env pol =
case pol of
- PolQuery e => box [string "query",
- space,
- p_exp env e]
+ PolClient e => box [string "sendClient",
+ space,
+ p_exp env e]
fun p_decl env (dAll as (d, _) : decl) =
case d of
diff --git a/src/mono_reduce.sml b/src/mono_reduce.sml
index e5dd3213..bb23a21a 100644
--- a/src/mono_reduce.sml
+++ b/src/mono_reduce.sml
@@ -423,18 +423,21 @@ fun reduce file =
| ERecord xets => List.concat (map (summarize d o #2) xets)
| EField (e, _) => summarize d e
- | ECase (e, pes, _) => summarize d e @ [Unsure]
- (*let
+ | ECase (e, pes, _) =>
+ let
val lss = map (fn (p, e) => summarize (d + patBinds p) e) pes
in
case lss of
[] => raise Fail "Empty pattern match"
| ls :: lss =>
- if List.all (fn ls' => ls' = ls) lss then
- summarize d e @ ls
- else
- [Unsure]
- end*)
+ summarize d e
+ @ (if List.all (fn ls' => ls' = ls) lss then
+ ls
+ else if length (List.filter (not o List.null) (ls :: lss)) <= 1 then
+ valOf (List.find (not o List.null) (ls :: lss))
+ else
+ [Unsure])
+ end
| EStrcat (e1, e2) => summarize d e1 @ summarize d e2
| EError (e, _) => summarize d e @ [Unsure]
diff --git a/src/mono_shake.sml b/src/mono_shake.sml
index 358b31d2..3a681302 100644
--- a/src/mono_shake.sml
+++ b/src/mono_shake.sml
@@ -61,7 +61,7 @@ fun shake file =
| ((DPolicy pol, _), st) =>
let
val e1 = case pol of
- PolQuery e1 => e1
+ PolClient e1 => e1
in
usedVars st e1
end
diff --git a/src/mono_util.sml b/src/mono_util.sml
index 094f216b..a7f27fd8 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -541,9 +541,9 @@ fun mapfoldB {typ = fc, exp = fe, decl = fd, bind} =
and mfpol ctx pol =
case pol of
- PolQuery e =>
+ PolClient e =>
S.map2 (mfe ctx e,
- PolQuery)
+ PolClient)
and mfvi ctx (x, n, t, e, s) =
S.bind2 (mft t,
diff --git a/src/monoize.sml b/src/monoize.sml
index 073c26de..a4e6a37c 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -3744,9 +3744,9 @@ fun monoDecl (env, fm) (all as (d, loc)) =
let
val (e, make) =
case #1 e of
- L.EApp ((L.ECApp ((L.ECApp ((L.EFfi ("Basis", "query_policy"), _), _), _), _), _), e) =>
- (e, L'.PolQuery)
- | _ => (poly (); (e, L'.PolQuery))
+ L.EApp ((L.ECApp ((L.ECApp ((L.EFfi ("Basis", "sendClient"), _), _), _), _), _), e) =>
+ (e, L'.PolClient)
+ | _ => (poly (); (e, L'.PolClient))
val (e, fm) = monoExp (env, St.empty, fm) e
in
diff --git a/tests/policy.ur b/tests/policy.ur
index 40850393..6d4e341e 100644
--- a/tests/policy.ur
+++ b/tests/policy.ur
@@ -9,18 +9,18 @@ table order : { Id : order, Fruit : fruit, Qty : int, Code : int }
CONSTRAINT Fruit FOREIGN KEY Fruit REFERENCES fruit(Id)
(* Everyone may knows IDs and names. *)
-policy query_policy (SELECT fruit.Id, fruit.Nam
- FROM fruit)
+policy sendClient (SELECT fruit.Id, fruit.Nam
+ FROM fruit)
(* The weight is sensitive information; you must know the secret. *)
-policy query_policy (SELECT fruit.Weight, fruit.Secret
- FROM fruit
- WHERE known(fruit.Secret))
-
-policy query_policy (SELECT order.Id, order.Fruit, order.Qty
- FROM order, fruit
- WHERE order.Fruit = fruit.Id
- AND order.Qty = 13)
+policy sendClient (SELECT fruit.Weight, fruit.Secret
+ FROM fruit
+ WHERE known(fruit.Secret))
+
+policy sendClient (SELECT order.Id, order.Fruit, order.Qty
+ FROM order, fruit
+ WHERE order.Fruit = fruit.Id
+ AND order.Qty = 13)
fun fname r =
x <- queryX (SELECT fruit.Weight
--
cgit v1.2.3
From 7b4f69ace67601a0f22de52f91f96deff540fd37 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sun, 11 Apr 2010 10:57:52 -0400
Subject: Insert policies
---
lib/ur/basis.urs | 4 +
src/iflow.sml | 369 ++++++++++++++++++++++++++++++++++++++++-------------
src/mono.sml | 4 +-
src/mono_print.sml | 3 +
src/mono_shake.sml | 1 +
src/mono_util.sml | 3 +
src/monoize.sml | 2 +
7 files changed, 298 insertions(+), 88 deletions(-)
(limited to 'src/mono.sml')
diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs
index 959a050d..8ae6597e 100644
--- a/lib/ur/basis.urs
+++ b/lib/ur/basis.urs
@@ -804,5 +804,9 @@ val sendClient : tables ::: {{Type}} -> exps ::: {Type}
-> [tables ~ exps] => sql_query [] tables exps
-> sql_policy
+val mayInsert : fs ::: {Type} -> tables ::: {{Type}} -> [[New] ~ tables]
+ => sql_query [] ([New = fs] ++ tables) []
+ -> sql_policy
+
val debug : string -> transaction unit
diff --git a/src/iflow.sml b/src/iflow.sml
index af45ea53..cce52fec 100644
--- a/src/iflow.sml
+++ b/src/iflow.sml
@@ -884,8 +884,10 @@ fun imply (hyps, goals, outs) =
("db", Cc.p_database cc)];*)
false)) acc
(*andalso (Print.preface ("Finding", Cc.p_database cc); true)*)
- andalso Cc.builtFrom (cc, {Derived = Var 0,
- Base = outs}))
+ andalso (case outs of
+ NONE => true
+ | SOME outs => Cc.builtFrom (cc, {Derived = Var 0,
+ Base = outs})))
handle Cc.Contradiction => false
end handle Cc.Undetermined => false)
orelse onFail ()
@@ -1218,6 +1220,24 @@ val query = log "query"
(wrap (follow (follow select from) (opt wher))
(fn ((fs, ts), wher) => {Select = fs, From = ts, Where = wher}))
+datatype dml =
+ Insert of string * (string * sqexp) list
+
+val insert = log "insert"
+ (wrapP (follow (const "INSERT INTO ")
+ (follow uw_ident
+ (follow (const " (")
+ (follow (list uw_ident)
+ (follow (const ") VALUES (")
+ (follow (list sqexp)
+ (const ")")))))))
+ (fn ((), (tab, ((), (fs, ((), (es, ())))))) =>
+ (SOME (Insert (tab, ListPair.zipEq (fs, es))))
+ handle ListPair.UnequalLengths => NONE))
+
+val dml = log "dml"
+ insert
+
fun removeDups (ls : (string * string) list) =
case ls of
[] => []
@@ -1235,7 +1255,66 @@ datatype queryMode =
SomeCol
| AllCols of exp
-exception Default
+fun expIn rv env rvOf =
+ let
+ fun expIn (e, rvN) =
+ let
+ fun default () =
+ let
+ val (rvN, e) = rv rvN
+ in
+ (inl e, rvN)
+ end
+ in
+ case e of
+ SqConst p => (inl (Const p), rvN)
+ | Field (v, f) => (inl (Proj (rvOf v, f)), rvN)
+ | Binop (bo, e1, e2) =>
+ let
+ val (e1, rvN) = expIn (e1, rvN)
+ val (e2, rvN) = expIn (e2, rvN)
+ in
+ (inr (case (bo, e1, e2) of
+ (Exps f, inl e1, inl e2) => f (e1, e2)
+ | (Props f, inr p1, inr p2) => f (p1, p2)
+ | _ => Unknown), rvN)
+ end
+ | SqKnown e =>
+ (case expIn (e, rvN) of
+ (inl e, rvN) => (inr (Reln (Known, [e])), rvN)
+ | _ => (inr Unknown, rvN))
+ | Inj e =>
+ let
+ fun deinj e =
+ case #1 e of
+ ERel n => (List.nth (env, n), rvN)
+ | EField (e, f) =>
+ let
+ val (e, rvN) = deinj e
+ in
+ (Proj (e, f), rvN)
+ end
+ | _ =>
+ let
+ val (rvN, e) = rv rvN
+ in
+ (e, rvN)
+ end
+
+ val (e, rvN) = deinj e
+ in
+ (inl e, rvN)
+ end
+ | SqFunc (f, e) =>
+ (case expIn (e, rvN) of
+ (inl e, rvN) => (inl (Func (Other f, [e])), rvN)
+ | _ => default ())
+
+ | Count => default ()
+ end
+ in
+ expIn
+ end
fun queryProp env rvN rv oe e =
let
@@ -1272,68 +1351,56 @@ fun queryProp env rvN rv oe e =
val p =
foldl (fn ((t, v), p) => And (p, Reln (Sql t, [rvOf v]))) True (#From r)
- fun expIn e =
- case e of
- SqConst p => inl (Const p)
- | Field (v, f) => inl (Proj (rvOf v, f))
- | Binop (bo, e1, e2) =>
- inr (case (bo, expIn e1, expIn e2) of
- (Exps f, inl e1, inl e2) => f (e1, e2)
- | (Props f, inr p1, inr p2) => f (p1, p2)
- | _ => Unknown)
- | SqKnown e =>
- inr (case expIn e of
- inl e => Reln (Known, [e])
- | _ => Unknown)
- | Inj e =>
- let
- fun deinj (e, _) =
- case e of
- ERel n => List.nth (env, n)
- | EField (e, f) => Proj (deinj e, f)
- | _ => raise Fail "Iflow: non-variable injected into query"
- in
- inl (deinj e)
- end
- | SqFunc (f, e) =>
- inl (case expIn e of
- inl e => Func (Other f, [e])
- | _ => raise Fail ("Iflow: non-expresion passed to function " ^ f))
- | Count => raise Default
-
- val p = case #Where r of
- NONE => p
- | SOME e =>
- case expIn e of
- inr p' => And (p, p')
- | _ => p
+ val expIn = expIn rv env rvOf
+
+ val (p, rvN) = case #Where r of
+ NONE => (p, rvN)
+ | SOME e =>
+ case expIn (e, rvN) of
+ (inr p', rvN) => (And (p, p'), rvN)
+ | _ => (p, rvN)
fun normal () =
case oe of
SomeCol =>
- (rvN, p, True,
- List.mapPartial (fn si =>
- case si of
- SqField (v, f) => SOME (Proj (rvOf v, f))
- | SqExp (e, f) =>
- case expIn e of
- inr _ => NONE
- | inl e => SOME e) (#Select r))
- | AllCols oe =>
- (rvN, And (p, foldl (fn (si, p) =>
+ let
+ val (sis, rvN) =
+ ListUtil.foldlMap
+ (fn (si, rvN) =>
+ case si of
+ SqField (v, f) => (Proj (rvOf v, f), rvN)
+ | SqExp (e, f) =>
+ case expIn (e, rvN) of
+ (inr _, _) =>
let
- val p' = case si of
- SqField (v, f) => Reln (Eq, [Proj (Proj (oe, v), f),
- Proj (rvOf v, f)])
- | SqExp (e, f) =>
- case expIn e of
- inr p => Cond (Proj (oe, f), p)
- | inl e => Reln (Eq, [Proj (oe, f), e])
+ val (rvN, e) = rv rvN
in
- And (p, p')
- end)
- True (#Select r)),
- True, [])
+ (e, rvN)
+ end
+ | (inl e, rvN) => (e, rvN)) rvN (#Select r)
+ in
+ (rvN, p, True, sis)
+ end
+ | AllCols oe =>
+ let
+ val (p', rvN) =
+ foldl (fn (si, (p, rvN)) =>
+ let
+ val (p', rvN) =
+ case si of
+ SqField (v, f) => (Reln (Eq, [Proj (Proj (oe, v), f),
+ Proj (rvOf v, f)]), rvN)
+ | SqExp (e, f) =>
+ case expIn (e, rvN) of
+ (inr p, rvN) => (Cond (Proj (oe, f), p), rvN)
+ | (inl e, rvN) => (Reln (Eq, [Proj (oe, f), e]), rvN)
+ in
+ (And (p, p'), rvN)
+ end)
+ (True, rvN) (#Select r)
+ in
+ (rvN, And (p, p'), True, [])
+ end
val (rvN, p, wp, outs) =
case #Select r of
@@ -1370,7 +1437,50 @@ fun queryProp env rvN rv oe e =
NONE => []
| SOME e => map (fn (v, f) => Proj (rvOf v, f)) (usedFields e), outs)
end
- handle Default => default ()
+ end
+
+fun insertProp rvN rv e =
+ let
+ fun default () = (print ("Warning: Information flow checker can't parse SQL query at "
+ ^ ErrorMsg.spanToString (#2 e) ^ "\n");
+ Unknown)
+ in
+ case parse query e of
+ NONE => default ()
+ | SOME r =>
+ let
+ val (rvs, rvN) = ListUtil.foldlMap (fn ((_, v), rvN) =>
+ let
+ val (rvN, e) = rv rvN
+ in
+ ((v, e), rvN)
+ end) rvN (#From r)
+
+ fun rvOf v =
+ case List.find (fn (v', _) => v' = v) rvs of
+ NONE => raise Fail "Iflow.insertProp: Bad table variable"
+ | SOME (_, e) => e
+
+ val p =
+ foldl (fn ((t, v), p) =>
+ let
+ val t =
+ case v of
+ "New" => "$New"
+ | _ => t
+ in
+ And (p, Reln (Sql t, [rvOf v]))
+ end) True (#From r)
+
+ val expIn = expIn rv [] rvOf
+ in
+ case #Where r of
+ NONE => p
+ | SOME e =>
+ case expIn (e, rvN) of
+ (inr p', _) => And (p, p')
+ | _ => p
+ end
end
fun evalPat env e (pt, _) =
@@ -1428,6 +1538,7 @@ fun removeRedundant p1 =
datatype cflow = Case | Where
datatype flow = Data | Control of cflow
type check = ErrorMsg.span * exp * prop
+type insert = ErrorMsg.span * prop
structure St :> sig
type t
@@ -1449,57 +1560,77 @@ structure St :> sig
val sent : t -> (check * flow) list
val addSent : t * (check * flow) -> t
val setSent : t * (check * flow) list -> t
+
+ val inserted : t -> insert list
+ val addInsert : t * insert -> t
end = struct
type t = {Var : int,
Ambient : prop,
Path : (check * cflow) list,
- Sent : (check * flow) list}
+ Sent : (check * flow) list,
+ Insert : insert list}
fun create {Var = v, Ambient = p} = {Var = v,
Ambient = p,
Path = [],
- Sent = []}
+ Sent = [],
+ Insert = []}
fun curVar (t : t) = #Var t
fun nextVar (t : t) = ({Var = #Var t + 1,
Ambient = #Ambient t,
Path = #Path t,
- Sent = #Sent t}, #Var t)
+ Sent = #Sent t,
+ Insert = #Insert t}, #Var t)
fun ambient (t : t) = #Ambient t
fun setAmbient (t : t, p) = {Var = #Var t,
Ambient = p,
Path = #Path t,
- Sent = #Sent t}
+ Sent = #Sent t,
+ Insert = #Insert t}
fun paths (t : t) = #Path t
fun addPath (t : t, c) = {Var = #Var t,
Ambient = #Ambient t,
Path = c :: #Path t,
- Sent = #Sent t}
+ Sent = #Sent t,
+ Insert = #Insert t}
fun addPaths (t : t, cs) = {Var = #Var t,
Ambient = #Ambient t,
Path = cs @ #Path t,
- Sent = #Sent t}
+ Sent = #Sent t,
+ Insert = #Insert t}
fun clearPaths (t : t) = {Var = #Var t,
Ambient = #Ambient t,
Path = [],
- Sent = #Sent t}
+ Sent = #Sent t,
+ Insert = #Insert t}
fun setPaths (t : t, cs) = {Var = #Var t,
Ambient = #Ambient t,
Path = cs,
- Sent = #Sent t}
+ Sent = #Sent t,
+ Insert = #Insert t}
fun sent (t : t) = #Sent t
fun addSent (t : t, c) = {Var = #Var t,
Ambient = #Ambient t,
Path = #Path t,
- Sent = c :: #Sent t}
+ Sent = c :: #Sent t,
+ Insert = #Insert t}
fun setSent (t : t, cs) = {Var = #Var t,
Ambient = #Ambient t,
Path = #Path t,
- Sent = cs}
+ Sent = cs,
+ Insert = #Insert t}
+
+fun inserted (t : t) = #Insert t
+fun addInsert (t : t, c) = {Var = #Var t,
+ Ambient = #Ambient t,
+ Path = #Path t,
+ Sent = #Sent t,
+ Insert = c :: #Insert t}
end
@@ -1720,7 +1851,44 @@ fun evalExp env (e as (_, loc), st) =
in
(res, St.addPaths (St.setSent (st, sent), paths))
end
- | EDml _ => default ()
+ | EDml e =>
+ (case parse dml e of
+ NONE => (print ("Warning: Information flow checker can't parse DML command at "
+ ^ ErrorMsg.spanToString loc ^ "\n");
+ default ())
+ | SOME d =>
+ case d of
+ Insert (tab, es) =>
+ let
+ val (st, new) = St.nextVar st
+
+ fun rv st =
+ let
+ val (st, n) = St.nextVar st
+ in
+ (st, Var n)
+ end
+
+ val expIn = expIn rv env (fn "New" => Var new
+ | _ => raise Fail "Iflow.evalExp: Bad field expression in EDml")
+
+ val (es, st) = ListUtil.foldlMap
+ (fn ((x, e), st) =>
+ let
+ val (e, st) = case expIn (e, st) of
+ (inl e, st) => (e, st)
+ | (inr _, _) => raise Fail
+ ("Iflow.evalExp: Selecting "
+ ^ "boolean expression")
+ in
+ ((x, e), st)
+ end)
+ st es
+ in
+ (Recd [], St.addInsert (st, (loc, And (St.ambient st,
+ Reln (Sql "$New", [Recd es])))))
+ end)
+
| ENextval _ => default ()
| ESetval _ => default ()
@@ -1756,7 +1924,7 @@ fun check file =
DExport (_, _, n, _, _, _) => IS.add (exptd, n)
| _ => exptd) IS.empty file
- fun decl ((d, _), (vals, pols)) =
+ fun decl ((d, _), (vals, inserts, client, insert)) =
case d of
DVal (_, n, _, e, _) =>
let
@@ -1776,21 +1944,36 @@ fun check file =
val (_, st) = evalExp env (e, St.create {Var = nv,
Ambient = p})
in
- (St.sent st @ vals, pols)
+ (St.sent st @ vals, St.inserted st @ inserts, client, insert)
end
- | DPolicy (PolClient e) =>
+ | DPolicy pol =>
let
- val (_, p, _, _, outs) = queryProp [] 0 (fn rvN => (rvN + 1, Lvar rvN)) SomeCol e
+ fun rv rvN = (rvN + 1, Lvar rvN)
in
- (vals, (p, outs) :: pols)
+ case pol of
+ PolClient e =>
+ let
+ val (_, p, _, _, outs) = queryProp [] 0 rv SomeCol e
+ in
+ (vals, inserts, (p, outs) :: client, insert)
+ end
+ | PolInsert e =>
+ let
+ val p = insertProp 0 rv e
+ in
+ (vals, inserts,client, p :: insert)
+ end
end
- | _ => (vals, pols)
+ | _ => (vals, inserts, client, insert)
val () = reset ()
- val (vals, pols) = foldl decl ([], []) file
+ val (vals, inserts, client, insert) = foldl decl ([], [], [], []) file
+
+ val decompH = decomp true (fn (e1, e2) => e1 andalso e2 ())
+ val decompG = decomp false (fn (e1, e2) => e1 orelse e2 ())
in
app (fn ((loc, e, p), fl) =>
let
@@ -1798,14 +1981,14 @@ fun check file =
let
val p = And (p, Reln (Eq, [Var 0, e]))
in
- if decomp true (fn (e1, e2) => e1 andalso e2 ()) p
- (fn hyps =>
- (fl <> Control Where
- andalso imply (hyps, [AReln (Known, [Var 0])], [Var 0]))
- orelse List.exists (fn (p', outs) =>
- decomp false (fn (e1, e2) => e1 orelse e2 ()) p'
- (fn goals => imply (hyps, goals, outs)))
- pols) then
+ if decompH p
+ (fn hyps =>
+ (fl <> Control Where
+ andalso imply (hyps, [AReln (Known, [Var 0])], SOME [Var 0]))
+ orelse List.exists (fn (p', outs) =>
+ decompG p'
+ (fn goals => imply (hyps, goals, SOME outs)))
+ client) then
()
else
(ErrorMsg.errorAt loc "The information flow policy may be violated here.";
@@ -1824,7 +2007,19 @@ fun check file =
| Finish => ()
in
doAll e
- end) vals
+ end) vals;
+
+ app (fn (loc, p) =>
+ if decompH p
+ (fn hyps =>
+ List.exists (fn p' =>
+ decompG p'
+ (fn goals => imply (hyps, goals, NONE)))
+ insert) then
+ ()
+ else
+ (ErrorMsg.errorAt loc "The information flow policy may be violated here.";
+ Print.preface ("The state satisifies this predicate:", p_prop p))) inserts
end
val check = fn file =>
diff --git a/src/mono.sml b/src/mono.sml
index f8f57ae7..9585fbc1 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -123,7 +123,9 @@ datatype exp' =
withtype exp = exp' located
-datatype policy = PolClient of exp
+datatype policy =
+ PolClient of exp
+ | PolInsert of exp
datatype decl' =
DDatatype of (string * int * (string * int * typ option) list) list
diff --git a/src/mono_print.sml b/src/mono_print.sml
index 76a89cc7..e98fc924 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -417,6 +417,9 @@ fun p_policy env pol =
PolClient e => box [string "sendClient",
space,
p_exp env e]
+ | PolInsert e => box [string "mayInsert",
+ space,
+ p_exp env e]
fun p_decl env (dAll as (d, _) : decl) =
case d of
diff --git a/src/mono_shake.sml b/src/mono_shake.sml
index 3a681302..4df9a6a0 100644
--- a/src/mono_shake.sml
+++ b/src/mono_shake.sml
@@ -62,6 +62,7 @@ fun shake file =
let
val e1 = case pol of
PolClient e1 => e1
+ | PolInsert e1 => e1
in
usedVars st e1
end
diff --git a/src/mono_util.sml b/src/mono_util.sml
index a7f27fd8..fa019b00 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -544,6 +544,9 @@ fun mapfoldB {typ = fc, exp = fe, decl = fd, bind} =
PolClient e =>
S.map2 (mfe ctx e,
PolClient)
+ | PolInsert e =>
+ S.map2 (mfe ctx e,
+ PolInsert)
and mfvi ctx (x, n, t, e, s) =
S.bind2 (mft t,
diff --git a/src/monoize.sml b/src/monoize.sml
index a4e6a37c..5bdc2aa2 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -3746,6 +3746,8 @@ fun monoDecl (env, fm) (all as (d, loc)) =
case #1 e of
L.EApp ((L.ECApp ((L.ECApp ((L.EFfi ("Basis", "sendClient"), _), _), _), _), _), e) =>
(e, L'.PolClient)
+ | L.EApp ((L.ECApp ((L.ECApp ((L.EFfi ("Basis", "mayInsert"), _), _), _), _), _), e) =>
+ (e, L'.PolInsert)
| _ => (poly (); (e, L'.PolClient))
val (e, fm) = monoExp (env, St.empty, fm) e
--
cgit v1.2.3
From accb8e1bf49e1c1e8300bda9be3cf72ce592ab44 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sun, 11 Apr 2010 12:38:21 -0400
Subject: Delete policies
---
lib/ur/basis.urs | 4 +
src/iflow.sml | 286 +++++++++++++++++++++++++++++++++++++++--------------
src/mono.sml | 1 +
src/mono_print.sml | 3 +
src/mono_shake.sml | 1 +
src/mono_util.sml | 3 +
src/monoize.sml | 2 +
7 files changed, 225 insertions(+), 75 deletions(-)
(limited to 'src/mono.sml')
diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs
index 8ae6597e..501284b7 100644
--- a/lib/ur/basis.urs
+++ b/lib/ur/basis.urs
@@ -808,5 +808,9 @@ val mayInsert : fs ::: {Type} -> tables ::: {{Type}} -> [[New] ~ tables]
=> sql_query [] ([New = fs] ++ tables) []
-> sql_policy
+val mayDelete : fs ::: {Type} -> tables ::: {{Type}} -> [[Old] ~ tables]
+ => sql_query [] ([Old = fs] ++ tables) []
+ -> sql_policy
+
val debug : string -> transaction unit
diff --git a/src/iflow.sml b/src/iflow.sml
index cce52fec..f275d013 100644
--- a/src/iflow.sml
+++ b/src/iflow.sml
@@ -411,7 +411,7 @@ datatype node = Node of {Rep : node ref option ref,
Dt0 of string
| Dt1 of string * node ref
| Prim of Prim.t
- | Recrd of node ref SM.map ref
+ | Recrd of node ref SM.map ref * bool
| VFinish
| Nothing
@@ -446,22 +446,29 @@ fun p_rep n =
case !(#Rep (unNode n)) of
SOME n => p_rep n
| NONE =>
- case #Variety (unNode n) of
- Nothing => string ("?" ^ Int.toString (Unsafe.cast n))
- | Dt0 s => string ("Dt0(" ^ s ^ ")")
- | Dt1 (s, n) => box[string ("Dt1(" ^ s ^ ","),
- space,
- p_rep n,
- string ")"]
- | Prim p => Prim.p_t p
- | Recrd (ref m) => box [string "{",
- p_list (fn (x, n) => box [string x,
- space,
- string "=",
- space,
- p_rep n]) (SM.listItemsi m),
- string "}"]
- | VFinish => string "FINISH"
+ box [string (Int.toString (Unsafe.cast n) ^ ":"),
+ space,
+ case #Variety (unNode n) of
+ Nothing => string "?"
+ | Dt0 s => string ("Dt0(" ^ s ^ ")")
+ | Dt1 (s, n) => box[string ("Dt1(" ^ s ^ ","),
+ space,
+ p_rep n,
+ string ")"]
+ | Prim p => Prim.p_t p
+ | Recrd (ref m, b) => box [string "{",
+ p_list (fn (x, n) => box [string x,
+ space,
+ string "=",
+ space,
+ p_rep n]) (SM.listItemsi m),
+ string "}",
+ if b then
+ box [space,
+ string "(complete)"]
+ else
+ box []]
+ | VFinish => string "FINISH"]
fun p_database (db : database) =
box [string "Vars:",
@@ -489,15 +496,20 @@ fun repOf (n : representative) : representative =
end
fun markKnown r =
- if !(#Known (unNode r)) then
- ()
- else
- (#Known (unNode r) := true;
- SM.app markKnown (!(#Cons (unNode r)));
- case #Variety (unNode r) of
- Dt1 (_, r) => markKnown r
- | Recrd xes => SM.app markKnown (!xes)
- | _ => ())
+ let
+ val r = repOf r
+ in
+ (*Print.preface ("markKnown", p_rep r);*)
+ if !(#Known (unNode r)) then
+ ()(*TextIO.print "Already known\n"*)
+ else
+ (#Known (unNode r) := true;
+ SM.app markKnown (!(#Cons (unNode r)));
+ case #Variety (unNode r) of
+ Dt1 (_, r) => markKnown r
+ | Recrd (xes, _) => SM.app markKnown (!xes)
+ | _ => ())
+ end
fun representative (db : database, e) =
let
@@ -555,7 +567,7 @@ fun representative (db : database, e) =
val r' = ref (Node {Rep = ref NONE,
Cons = ref SM.empty,
Variety = Dt1 (f, r),
- Known = #Known (unNode r)})
+ Known = ref (!(#Known (unNode r)))})
in
#Cons (unNode r) := SM.insert (!(#Cons (unNode r)), f, r');
r'
@@ -577,7 +589,7 @@ fun representative (db : database, e) =
val r' = ref (Node {Rep = ref NONE,
Cons = cons,
Variety = Nothing,
- Known = #Known (unNode r)})
+ Known = ref (!(#Known (unNode r)))})
val r'' = ref (Node {Rep = ref NONE,
Cons = #Cons (unNode r),
@@ -628,7 +640,7 @@ fun representative (db : database, e) =
val r' = ref (Node {Rep = ref NONE,
Cons = ref SM.empty,
- Variety = Recrd (ref xes),
+ Variety = Recrd (ref xes, true),
Known = ref false})
in
#Records db := (xes, r') :: (!(#Records db));
@@ -640,14 +652,14 @@ fun representative (db : database, e) =
val r = rep e
in
case #Variety (unNode r) of
- Recrd xes =>
+ Recrd (xes, _) =>
(case SM.find (!xes, f) of
SOME r => repOf r
| NONE => let
val r = ref (Node {Rep = ref NONE,
Cons = ref SM.empty,
Variety = Nothing,
- Known = #Known (unNode r)})
+ Known = ref (!(#Known (unNode r)))})
in
xes := SM.insert (!xes, f, r);
r
@@ -657,11 +669,11 @@ fun representative (db : database, e) =
val r' = ref (Node {Rep = ref NONE,
Cons = ref SM.empty,
Variety = Nothing,
- Known = #Known (unNode r)})
+ Known = ref (!(#Known (unNode r)))})
val r'' = ref (Node {Rep = ref NONE,
Cons = #Cons (unNode r),
- Variety = Recrd (ref (SM.insert (SM.empty, f, r'))),
+ Variety = Recrd (ref (SM.insert (SM.empty, f, r')), false),
Known = #Known (unNode r)})
in
#Rep (unNode r) := SOME r'';
@@ -680,7 +692,12 @@ fun assert (db, a) =
ACond _ => ()
| AReln x =>
case x of
- (Known, [e]) => markKnown (representative (db, e))
+ (Known, [e]) =>
+ ((*Print.prefaces "Before" [("e", p_exp e),
+ ("db", p_database db)];*)
+ markKnown (representative (db, e))(*;
+ Print.prefaces "After" [("e", p_exp e),
+ ("db", p_database db)]*))
| (PCon0 f, [e]) =>
let
val r = representative (db, e)
@@ -744,7 +761,7 @@ fun assert (db, a) =
markEq (r1, r2)
else
raise Contradiction
- | (Recrd xes1, Recrd xes2) =>
+ | (Recrd (xes1, _), Recrd (xes2, _)) =>
let
fun unif (xes1, xes2) =
SM.appi (fn (x, r1) =>
@@ -805,7 +822,23 @@ fun check (db, a) =
ACond _ => false
| AReln x =>
case x of
- (Known, [e]) => !(#Known (unNode (representative (db, e))))
+ (Known, [e]) =>
+ let
+ fun isKnown r =
+ let
+ val r = repOf r
+ in
+ !(#Known (unNode r))
+ orelse case #Variety (unNode r) of
+ Dt1 (_, r) => isKnown r
+ | Recrd (xes, true) => List.all isKnown (SM.listItems (!xes))
+ | _ => false
+ end
+
+ val r = representative (db, e)
+ in
+ isKnown r
+ end
| (PCon0 f, [e]) =>
(case #Variety (unNode (representative (db, e))) of
Dt0 f' => f' = f
@@ -836,7 +869,7 @@ fun builtFrom (db, {Base = bs, Derived = d}) =
Dt0 _ => true
| Dt1 (_, d) => loop d
| Prim _ => true
- | Recrd xes => List.all loop (SM.listItems (!xes))
+ | Recrd (xes, _) => List.all loop (SM.listItems (!xes))
| VFinish => true
| Nothing => false
end
@@ -874,6 +907,7 @@ fun imply (hyps, goals, outs) =
val cc = Cc.database ()
val () = app (fn a => Cc.assert (cc, a)) hyps
in
+ (*Print.preface ("db", Cc.p_database cc);*)
(List.all (fn a =>
if Cc.check (cc, a) then
true
@@ -1222,6 +1256,7 @@ val query = log "query"
datatype dml =
Insert of string * (string * sqexp) list
+ | Delete of string * sqexp
val insert = log "insert"
(wrapP (follow (const "INSERT INTO ")
@@ -1232,11 +1267,19 @@ val insert = log "insert"
(follow (list sqexp)
(const ")")))))))
(fn ((), (tab, ((), (fs, ((), (es, ())))))) =>
- (SOME (Insert (tab, ListPair.zipEq (fs, es))))
+ (SOME (tab, ListPair.zipEq (fs, es)))
handle ListPair.UnequalLengths => NONE))
+val delete = log "delete"
+ (wrap (follow (const "DELETE FROM ")
+ (follow uw_ident
+ (follow (const " AS T_T WHERE ")
+ sqexp)))
+ (fn ((), (tab, ((), es))) => (tab, es)))
+
val dml = log "dml"
- insert
+ (altL [wrap insert Insert,
+ wrap delete Delete])
fun removeDups (ls : (string * string) list) =
case ls of
@@ -1421,13 +1464,13 @@ fun queryProp env rvN rv oe e =
end
| AllCols oe =>
let
- val oe = Proj (oe, f)
+ fun oeEq e = Reln (Eq, [oe, Recd [(f, e)]])
in
(rvN,
- Or (Reln (Eq, [oe, Func (DtCon0 "Basis.bool.False", [])]),
- And (Reln (Eq, [oe, Func (DtCon0 "Basis.bool.True", [])]),
+ Or (oeEq (Func (DtCon0 "Basis.bool.False", [])),
+ And (oeEq (Func (DtCon0 "Basis.bool.True", [])),
p)),
- Reln (Eq, [oe, Func (DtCon0 "Basis.bool.True", [])]),
+ oeEq (Func (DtCon0 "Basis.bool.True", [])),
[])
end)
| _ => normal ())
@@ -1483,6 +1526,43 @@ fun insertProp rvN rv e =
end
end
+fun deleteProp rvN rv e =
+ let
+ fun default () = (print ("Warning: Information flow checker can't parse SQL query at "
+ ^ ErrorMsg.spanToString (#2 e) ^ "\n");
+ Unknown)
+ in
+ case parse query e of
+ NONE => default ()
+ | SOME r =>
+ let
+ val (rvs, rvN) = ListUtil.foldlMap (fn ((_, v), rvN) =>
+ let
+ val (rvN, e) = rv rvN
+ in
+ ((v, e), rvN)
+ end) rvN (#From r)
+
+ fun rvOf v =
+ case List.find (fn (v', _) => v' = v) rvs of
+ NONE => raise Fail "Iflow.deleteProp: Bad table variable"
+ | SOME (_, e) => e
+
+ val p =
+ foldl (fn ((t, v), p) => And (p, Reln (Sql t, [rvOf v]))) True (#From r)
+
+ val expIn = expIn rv [] rvOf
+ in
+ And (Reln (Sql "$Old", [rvOf "Old"]),
+ case #Where r of
+ NONE => p
+ | SOME e =>
+ case expIn (e, rvN) of
+ (inr p', _) => And (p, p')
+ | _ => p)
+ end
+ end
+
fun evalPat env e (pt, _) =
case pt of
PWild => (env, True)
@@ -1538,7 +1618,7 @@ fun removeRedundant p1 =
datatype cflow = Case | Where
datatype flow = Data | Control of cflow
type check = ErrorMsg.span * exp * prop
-type insert = ErrorMsg.span * prop
+type dml = ErrorMsg.span * prop
structure St :> sig
type t
@@ -1561,76 +1641,98 @@ structure St :> sig
val addSent : t * (check * flow) -> t
val setSent : t * (check * flow) list -> t
- val inserted : t -> insert list
- val addInsert : t * insert -> t
+ val inserted : t -> dml list
+ val addInsert : t * dml -> t
+
+ val deleted : t -> dml list
+ val addDelete : t * dml -> t
end = struct
type t = {Var : int,
Ambient : prop,
Path : (check * cflow) list,
Sent : (check * flow) list,
- Insert : insert list}
+ Insert : dml list,
+ Delete : dml list}
fun create {Var = v, Ambient = p} = {Var = v,
Ambient = p,
Path = [],
Sent = [],
- Insert = []}
+ Insert = [],
+ Delete = []}
fun curVar (t : t) = #Var t
fun nextVar (t : t) = ({Var = #Var t + 1,
Ambient = #Ambient t,
Path = #Path t,
Sent = #Sent t,
- Insert = #Insert t}, #Var t)
+ Insert = #Insert t,
+ Delete = #Delete t}, #Var t)
fun ambient (t : t) = #Ambient t
fun setAmbient (t : t, p) = {Var = #Var t,
Ambient = p,
Path = #Path t,
Sent = #Sent t,
- Insert = #Insert t}
+ Insert = #Insert t,
+ Delete = #Delete t}
fun paths (t : t) = #Path t
fun addPath (t : t, c) = {Var = #Var t,
Ambient = #Ambient t,
Path = c :: #Path t,
Sent = #Sent t,
- Insert = #Insert t}
+ Insert = #Insert t,
+ Delete = #Delete t}
fun addPaths (t : t, cs) = {Var = #Var t,
Ambient = #Ambient t,
Path = cs @ #Path t,
Sent = #Sent t,
- Insert = #Insert t}
+ Insert = #Insert t,
+ Delete = #Delete t}
fun clearPaths (t : t) = {Var = #Var t,
Ambient = #Ambient t,
Path = [],
Sent = #Sent t,
- Insert = #Insert t}
+ Insert = #Insert t,
+ Delete = #Delete t}
fun setPaths (t : t, cs) = {Var = #Var t,
Ambient = #Ambient t,
Path = cs,
Sent = #Sent t,
- Insert = #Insert t}
+ Insert = #Insert t,
+ Delete = #Delete t}
fun sent (t : t) = #Sent t
fun addSent (t : t, c) = {Var = #Var t,
Ambient = #Ambient t,
Path = #Path t,
Sent = c :: #Sent t,
- Insert = #Insert t}
+ Insert = #Insert t,
+ Delete = #Delete t}
fun setSent (t : t, cs) = {Var = #Var t,
Ambient = #Ambient t,
Path = #Path t,
Sent = cs,
- Insert = #Insert t}
+ Insert = #Insert t,
+ Delete = #Delete t}
fun inserted (t : t) = #Insert t
fun addInsert (t : t, c) = {Var = #Var t,
Ambient = #Ambient t,
Path = #Path t,
Sent = #Sent t,
- Insert = c :: #Insert t}
+ Insert = c :: #Insert t,
+ Delete = #Delete t}
+
+fun deleted (t : t) = #Delete t
+fun addDelete (t : t, c) = {Var = #Var t,
+ Ambient = #Ambient t,
+ Path = #Path t,
+ Sent = #Sent t,
+ Insert = #Insert t,
+ Delete = c :: #Delete t}
end
@@ -1870,7 +1972,7 @@ fun evalExp env (e as (_, loc), st) =
end
val expIn = expIn rv env (fn "New" => Var new
- | _ => raise Fail "Iflow.evalExp: Bad field expression in EDml")
+ | _ => raise Fail "Iflow.evalExp: Bad field expression in UPDATE")
val (es, st) = ListUtil.foldlMap
(fn ((x, e), st) =>
@@ -1887,6 +1989,30 @@ fun evalExp env (e as (_, loc), st) =
in
(Recd [], St.addInsert (st, (loc, And (St.ambient st,
Reln (Sql "$New", [Recd es])))))
+ end
+ | Delete (tab, e) =>
+ let
+ val (st, old) = St.nextVar st
+
+ fun rv st =
+ let
+ val (st, n) = St.nextVar st
+ in
+ (st, Var n)
+ end
+
+ val expIn = expIn rv env (fn "T" => Var old
+ | _ => raise Fail "Iflow.evalExp: Bad field expression in DELETE")
+
+ val (p, st) = case expIn (e, st) of
+ (inl e, _) => raise Fail "Iflow.evalExp: DELETE with non-boolean"
+ | (inr p, st) => (p, st)
+
+ val p = And (p,
+ And (Reln (Sql "$Old", [Var old]),
+ Reln (Sql tab, [Var old])))
+ in
+ (Recd [], St.addDelete (st, (loc, And (St.ambient st, p))))
end)
| ENextval _ => default ()
@@ -1924,7 +2050,7 @@ fun check file =
DExport (_, _, n, _, _, _) => IS.add (exptd, n)
| _ => exptd) IS.empty file
- fun decl ((d, _), (vals, inserts, client, insert)) =
+ fun decl ((d, _), (vals, inserts, deletes, client, insert, delete)) =
case d of
DVal (_, n, _, e, _) =>
let
@@ -1944,7 +2070,7 @@ fun check file =
val (_, st) = evalExp env (e, St.create {Var = nv,
Ambient = p})
in
- (St.sent st @ vals, St.inserted st @ inserts, client, insert)
+ (St.sent st @ vals, St.inserted st @ inserts, St.deleted st @ deletes, client, insert, delete)
end
| DPolicy pol =>
@@ -1956,24 +2082,43 @@ fun check file =
let
val (_, p, _, _, outs) = queryProp [] 0 rv SomeCol e
in
- (vals, inserts, (p, outs) :: client, insert)
+ (vals, inserts, deletes, (p, outs) :: client, insert, delete)
end
| PolInsert e =>
let
val p = insertProp 0 rv e
in
- (vals, inserts,client, p :: insert)
+ (vals, inserts, deletes, client, p :: insert, delete)
+ end
+ | PolDelete e =>
+ let
+ val p = deleteProp 0 rv e
+ in
+ (vals, inserts, deletes, client, insert, p :: delete)
end
end
- | _ => (vals, inserts, client, insert)
+ | _ => (vals, inserts, deletes, client, insert, delete)
val () = reset ()
- val (vals, inserts, client, insert) = foldl decl ([], [], [], []) file
+ val (vals, inserts, deletes, client, insert, delete) = foldl decl ([], [], [], [], [], []) file
val decompH = decomp true (fn (e1, e2) => e1 andalso e2 ())
val decompG = decomp false (fn (e1, e2) => e1 orelse e2 ())
+
+ fun doDml (cmds, pols) =
+ app (fn (loc, p) =>
+ if decompH p
+ (fn hyps =>
+ List.exists (fn p' =>
+ decompG p'
+ (fn goals => imply (hyps, goals, NONE)))
+ pols) then
+ ()
+ else
+ (ErrorMsg.errorAt loc "The information flow policy may be violated here.";
+ Print.preface ("The state satisifies this predicate:", p_prop p))) cmds
in
app (fn ((loc, e, p), fl) =>
let
@@ -2009,17 +2154,8 @@ fun check file =
doAll e
end) vals;
- app (fn (loc, p) =>
- if decompH p
- (fn hyps =>
- List.exists (fn p' =>
- decompG p'
- (fn goals => imply (hyps, goals, NONE)))
- insert) then
- ()
- else
- (ErrorMsg.errorAt loc "The information flow policy may be violated here.";
- Print.preface ("The state satisifies this predicate:", p_prop p))) inserts
+ doDml (inserts, insert);
+ doDml (deletes, delete)
end
val check = fn file =>
diff --git a/src/mono.sml b/src/mono.sml
index 9585fbc1..284d4cd3 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -126,6 +126,7 @@ withtype exp = exp' located
datatype policy =
PolClient of exp
| PolInsert of exp
+ | PolDelete of exp
datatype decl' =
DDatatype of (string * int * (string * int * typ option) list) list
diff --git a/src/mono_print.sml b/src/mono_print.sml
index e98fc924..b1b3a8e0 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -420,6 +420,9 @@ fun p_policy env pol =
| PolInsert e => box [string "mayInsert",
space,
p_exp env e]
+ | PolDelete e => box [string "mayDelete",
+ space,
+ p_exp env e]
fun p_decl env (dAll as (d, _) : decl) =
case d of
diff --git a/src/mono_shake.sml b/src/mono_shake.sml
index 4df9a6a0..f1c2d70f 100644
--- a/src/mono_shake.sml
+++ b/src/mono_shake.sml
@@ -63,6 +63,7 @@ fun shake file =
val e1 = case pol of
PolClient e1 => e1
| PolInsert e1 => e1
+ | PolDelete e1 => e1
in
usedVars st e1
end
diff --git a/src/mono_util.sml b/src/mono_util.sml
index fa019b00..af01f560 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -547,6 +547,9 @@ fun mapfoldB {typ = fc, exp = fe, decl = fd, bind} =
| PolInsert e =>
S.map2 (mfe ctx e,
PolInsert)
+ | PolDelete e =>
+ S.map2 (mfe ctx e,
+ PolDelete)
and mfvi ctx (x, n, t, e, s) =
S.bind2 (mft t,
diff --git a/src/monoize.sml b/src/monoize.sml
index 5bdc2aa2..4a11b12d 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -3748,6 +3748,8 @@ fun monoDecl (env, fm) (all as (d, loc)) =
(e, L'.PolClient)
| L.EApp ((L.ECApp ((L.ECApp ((L.EFfi ("Basis", "mayInsert"), _), _), _), _), _), e) =>
(e, L'.PolInsert)
+ | L.EApp ((L.ECApp ((L.ECApp ((L.EFfi ("Basis", "mayDelete"), _), _), _), _), _), e) =>
+ (e, L'.PolDelete)
| _ => (poly (); (e, L'.PolClient))
val (e, fm) = monoExp (env, St.empty, fm) e
--
cgit v1.2.3
From 30b7dba0eaa5a961ded15729ba64bbf67ce8903e Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sun, 11 Apr 2010 13:11:25 -0400
Subject: Update policies
---
lib/ur/basis.urs | 4 ++
src/iflow.sml | 180 ++++++++++++++++++++++++++++++++++++++++++++++-------
src/mono.sml | 1 +
src/mono_print.sml | 3 +
src/mono_shake.sml | 1 +
src/mono_util.sml | 3 +
src/monoize.sml | 2 +
7 files changed, 170 insertions(+), 24 deletions(-)
(limited to 'src/mono.sml')
diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs
index 501284b7..3241cc9a 100644
--- a/lib/ur/basis.urs
+++ b/lib/ur/basis.urs
@@ -812,5 +812,9 @@ val mayDelete : fs ::: {Type} -> tables ::: {{Type}} -> [[Old] ~ tables]
=> sql_query [] ([Old = fs] ++ tables) []
-> sql_policy
+val mayUpdate : fs ::: {Type} -> tables ::: {{Type}} -> [[Old, New] ~ tables]
+ => sql_query [] ([Old = fs, New = fs] ++ tables) []
+ -> sql_policy
+
val debug : string -> transaction unit
diff --git a/src/iflow.sml b/src/iflow.sml
index 2b67b9ea..564cd20b 100644
--- a/src/iflow.sml
+++ b/src/iflow.sml
@@ -958,7 +958,7 @@ fun imply (hyps, goals, outs) =
in
reset ();
(*Print.prefaces "Big go" [("hyps", Print.p_list p_atom hyps),
- ("goals", Print.p_list p_atom goals)];*)
+ ("goals", Print.p_list p_atom goals)];*)
gls goals (fn () => false) []
end handle Cc.Contradiction => true
@@ -1257,6 +1257,7 @@ val query = log "query"
datatype dml =
Insert of string * (string * sqexp) list
| Delete of string * sqexp
+ | Update of string * (string * sqexp) list * sqexp
val insert = log "insert"
(wrapP (follow (const "INSERT INTO ")
@@ -1277,9 +1278,24 @@ val delete = log "delete"
sqexp)))
(fn ((), (tab, ((), es))) => (tab, es)))
+val setting = log "setting"
+ (wrap (follow uw_ident (follow (const " = ") sqexp))
+ (fn (f, ((), e)) => (f, e)))
+
+val update = log "update"
+ (wrap (follow (const "UPDATE ")
+ (follow uw_ident
+ (follow (const " AS T_T SET ")
+ (follow (list setting)
+ (follow (ws (const "WHERE "))
+ sqexp)))))
+ (fn ((), (tab, ((), (fs, ((), e))))) =>
+ (tab, fs, e)))
+
val dml = log "dml"
(altL [wrap insert Insert,
- wrap delete Delete])
+ wrap delete Delete,
+ wrap update Update])
fun removeDups (ls : (string * string) list) =
case ls of
@@ -1576,6 +1592,51 @@ fun deleteProp rvN rv e =
end
end
+fun updateProp rvN rv e =
+ let
+ fun default () = (print ("Warning: Information flow checker can't parse SQL query at "
+ ^ ErrorMsg.spanToString (#2 e) ^ "\n");
+ Unknown)
+ in
+ case parse query e of
+ NONE => default ()
+ | SOME r =>
+ let
+ val (rvs, rvN) = ListUtil.foldlMap (fn ((_, v), rvN) =>
+ let
+ val (rvN, e) = rv rvN
+ in
+ ((v, e), rvN)
+ end) rvN (#From r)
+
+ fun rvOf v =
+ case List.find (fn (v', _) => v' = v) rvs of
+ NONE => raise Fail "Iflow.insertProp: Bad table variable"
+ | SOME (_, e) => e
+
+ val p =
+ foldl (fn ((t, v), p) =>
+ let
+ val t =
+ case v of
+ "New" => "$New"
+ | _ => t
+ in
+ And (p, Reln (Sql t, [rvOf v]))
+ end) True (#From r)
+
+ val expIn = expIn rv [] rvOf
+ in
+ And (Reln (Sql "$Old", [rvOf "Old"]),
+ case #Where r of
+ NONE => p
+ | SOME e =>
+ case expIn (e, rvN) of
+ (inr p', _) => And (p, p')
+ | _ => p)
+ end
+ end
+
fun evalPat env e (pt, _) =
case pt of
PWild => (env, True)
@@ -1659,6 +1720,9 @@ structure St :> sig
val deleted : t -> dml list
val addDelete : t * dml -> t
+
+ val updated : t -> dml list
+ val addUpdate : t * dml -> t
end = struct
type t = {Var : int,
@@ -1666,14 +1730,16 @@ type t = {Var : int,
Path : (check * cflow) list,
Sent : (check * flow) list,
Insert : dml list,
- Delete : dml list}
+ Delete : dml list,
+ Update : dml list}
fun create {Var = v, Ambient = p} = {Var = v,
Ambient = p,
Path = [],
Sent = [],
Insert = [],
- Delete = []}
+ Delete = [],
+ Update = []}
fun curVar (t : t) = #Var t
fun nextVar (t : t) = ({Var = #Var t + 1,
@@ -1681,7 +1747,8 @@ fun nextVar (t : t) = ({Var = #Var t + 1,
Path = #Path t,
Sent = #Sent t,
Insert = #Insert t,
- Delete = #Delete t}, #Var t)
+ Delete = #Delete t,
+ Update = #Update t}, #Var t)
fun ambient (t : t) = #Ambient t
fun setAmbient (t : t, p) = {Var = #Var t,
@@ -1689,7 +1756,8 @@ fun setAmbient (t : t, p) = {Var = #Var t,
Path = #Path t,
Sent = #Sent t,
Insert = #Insert t,
- Delete = #Delete t}
+ Delete = #Delete t,
+ Update = #Update t}
fun paths (t : t) = #Path t
fun addPath (t : t, c) = {Var = #Var t,
@@ -1697,25 +1765,29 @@ fun addPath (t : t, c) = {Var = #Var t,
Path = c :: #Path t,
Sent = #Sent t,
Insert = #Insert t,
- Delete = #Delete t}
+ Delete = #Delete t,
+ Update = #Update t}
fun addPaths (t : t, cs) = {Var = #Var t,
Ambient = #Ambient t,
Path = cs @ #Path t,
Sent = #Sent t,
Insert = #Insert t,
- Delete = #Delete t}
+ Delete = #Delete t,
+ Update = #Update t}
fun clearPaths (t : t) = {Var = #Var t,
Ambient = #Ambient t,
Path = [],
Sent = #Sent t,
Insert = #Insert t,
- Delete = #Delete t}
+ Delete = #Delete t,
+ Update = #Update t}
fun setPaths (t : t, cs) = {Var = #Var t,
Ambient = #Ambient t,
Path = cs,
Sent = #Sent t,
Insert = #Insert t,
- Delete = #Delete t}
+ Delete = #Delete t,
+ Update = #Update t}
fun sent (t : t) = #Sent t
fun addSent (t : t, c) = {Var = #Var t,
@@ -1723,13 +1795,15 @@ fun addSent (t : t, c) = {Var = #Var t,
Path = #Path t,
Sent = c :: #Sent t,
Insert = #Insert t,
- Delete = #Delete t}
+ Delete = #Delete t,
+ Update = #Update t}
fun setSent (t : t, cs) = {Var = #Var t,
Ambient = #Ambient t,
Path = #Path t,
Sent = cs,
Insert = #Insert t,
- Delete = #Delete t}
+ Delete = #Delete t,
+ Update = #Update t}
fun inserted (t : t) = #Insert t
fun addInsert (t : t, c) = {Var = #Var t,
@@ -1737,7 +1811,8 @@ fun addInsert (t : t, c) = {Var = #Var t,
Path = #Path t,
Sent = #Sent t,
Insert = c :: #Insert t,
- Delete = #Delete t}
+ Delete = #Delete t,
+ Update = #Update t}
fun deleted (t : t) = #Delete t
fun addDelete (t : t, c) = {Var = #Var t,
@@ -1745,7 +1820,17 @@ fun addDelete (t : t, c) = {Var = #Var t,
Path = #Path t,
Sent = #Sent t,
Insert = #Insert t,
- Delete = c :: #Delete t}
+ Delete = c :: #Delete t,
+ Update = #Update t}
+
+fun updated (t : t) = #Update t
+fun addUpdate (t : t, c) = {Var = #Var t,
+ Ambient = #Ambient t,
+ Path = #Path t,
+ Sent = #Sent t,
+ Insert = #Insert t,
+ Delete = #Delete t,
+ Update = c :: #Update t}
end
@@ -1984,8 +2069,7 @@ fun evalExp env (e as (_, loc), st) =
(st, Var n)
end
- val expIn = expIn rv env (fn "New" => Var new
- | _ => raise Fail "Iflow.evalExp: Bad field expression in UPDATE")
+ val expIn = expIn rv env (fn _ => raise Fail "Iflow.evalExp: Bad field expression in INSERT")
val (es, st) = ListUtil.foldlMap
(fn ((x, e), st) =>
@@ -2026,6 +2110,45 @@ fun evalExp env (e as (_, loc), st) =
Reln (Sql tab, [Var old])))
in
(Recd [], St.addDelete (st, (loc, And (St.ambient st, p))))
+ end
+ | Update (tab, fs, e) =>
+ let
+ val (st, new) = St.nextVar st
+ val (st, old) = St.nextVar st
+
+ fun rv st =
+ let
+ val (st, n) = St.nextVar st
+ in
+ (st, Var n)
+ end
+
+ val expIn = expIn rv env (fn "T" => Var old
+ | _ => raise Fail "Iflow.evalExp: Bad field expression in UPDATE")
+
+ val (fs, st) = ListUtil.foldlMap
+ (fn ((x, e), st) =>
+ let
+ val (e, st) = case expIn (e, st) of
+ (inl e, st) => (e, st)
+ | (inr _, _) => raise Fail
+ ("Iflow.evalExp: Selecting "
+ ^ "boolean expression")
+ in
+ ((x, e), st)
+ end)
+ st fs
+
+ val (p, st) = case expIn (e, st) of
+ (inl e, _) => raise Fail "Iflow.evalExp: UPDATE with non-boolean"
+ | (inr p, st) => (p, st)
+
+ val p = And (p,
+ And (Reln (Sql "$New", [Recd fs]),
+ And (Reln (Sql "$Old", [Var old]),
+ Reln (Sql tab, [Var old]))))
+ in
+ (Recd [], St.addUpdate (st, (loc, And (St.ambient st, p))))
end)
| ENextval _ => default ()
@@ -2063,7 +2186,7 @@ fun check file =
DExport (_, _, n, _, _, _) => IS.add (exptd, n)
| _ => exptd) IS.empty file
- fun decl ((d, _), (vals, inserts, deletes, client, insert, delete)) =
+ fun decl ((d, _), (vals, inserts, deletes, updates, client, insert, delete, update)) =
case d of
DVal (_, n, _, e, _) =>
let
@@ -2083,7 +2206,8 @@ fun check file =
val (_, st) = evalExp env (e, St.create {Var = nv,
Ambient = p})
in
- (St.sent st @ vals, St.inserted st @ inserts, St.deleted st @ deletes, client, insert, delete)
+ (St.sent st @ vals, St.inserted st @ inserts, St.deleted st @ deletes, St.updated st @ updates,
+ client, insert, delete, update)
end
| DPolicy pol =>
@@ -2095,27 +2219,34 @@ fun check file =
let
val (_, p, _, _, outs) = queryProp [] 0 rv SomeCol e
in
- (vals, inserts, deletes, (p, outs) :: client, insert, delete)
+ (vals, inserts, deletes, updates, (p, outs) :: client, insert, delete, update)
end
| PolInsert e =>
let
val p = insertProp 0 rv e
in
- (vals, inserts, deletes, client, p :: insert, delete)
+ (vals, inserts, deletes, updates, client, p :: insert, delete, update)
end
| PolDelete e =>
let
val p = deleteProp 0 rv e
in
- (vals, inserts, deletes, client, insert, p :: delete)
+ (vals, inserts, deletes, updates, client, insert, p :: delete, update)
+ end
+ | PolUpdate e =>
+ let
+ val p = updateProp 0 rv e
+ in
+ (vals, inserts, deletes, updates, client, insert, delete, p :: update)
end
end
- | _ => (vals, inserts, deletes, client, insert, delete)
+ | _ => (vals, inserts, deletes, updates, client, insert, delete, update)
val () = reset ()
- val (vals, inserts, deletes, client, insert, delete) = foldl decl ([], [], [], [], [], []) file
+ val (vals, inserts, deletes, updates, client, insert, delete, update) =
+ foldl decl ([], [], [], [], [], [], [], []) file
val decompH = decomp true (fn (e1, e2) => e1 andalso e2 ())
val decompG = decomp false (fn (e1, e2) => e1 orelse e2 ())
@@ -2168,7 +2299,8 @@ fun check file =
end) vals;
doDml (inserts, insert);
- doDml (deletes, delete)
+ doDml (deletes, delete);
+ doDml (updates, update)
end
val check = fn file =>
diff --git a/src/mono.sml b/src/mono.sml
index 284d4cd3..79cde237 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -127,6 +127,7 @@ datatype policy =
PolClient of exp
| PolInsert of exp
| PolDelete of exp
+ | PolUpdate of exp
datatype decl' =
DDatatype of (string * int * (string * int * typ option) list) list
diff --git a/src/mono_print.sml b/src/mono_print.sml
index b1b3a8e0..b8016ff8 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -423,6 +423,9 @@ fun p_policy env pol =
| PolDelete e => box [string "mayDelete",
space,
p_exp env e]
+ | PolUpdate e => box [string "mayUpdate",
+ space,
+ p_exp env e]
fun p_decl env (dAll as (d, _) : decl) =
case d of
diff --git a/src/mono_shake.sml b/src/mono_shake.sml
index f1c2d70f..6b248636 100644
--- a/src/mono_shake.sml
+++ b/src/mono_shake.sml
@@ -64,6 +64,7 @@ fun shake file =
PolClient e1 => e1
| PolInsert e1 => e1
| PolDelete e1 => e1
+ | PolUpdate e1 => e1
in
usedVars st e1
end
diff --git a/src/mono_util.sml b/src/mono_util.sml
index af01f560..085b68f8 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -550,6 +550,9 @@ fun mapfoldB {typ = fc, exp = fe, decl = fd, bind} =
| PolDelete e =>
S.map2 (mfe ctx e,
PolDelete)
+ | PolUpdate e =>
+ S.map2 (mfe ctx e,
+ PolUpdate)
and mfvi ctx (x, n, t, e, s) =
S.bind2 (mft t,
diff --git a/src/monoize.sml b/src/monoize.sml
index 4a11b12d..601b690f 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -3750,6 +3750,8 @@ fun monoDecl (env, fm) (all as (d, loc)) =
(e, L'.PolInsert)
| L.EApp ((L.ECApp ((L.ECApp ((L.EFfi ("Basis", "mayDelete"), _), _), _), _), _), e) =>
(e, L'.PolDelete)
+ | L.EApp ((L.ECApp ((L.ECApp ((L.EFfi ("Basis", "mayUpdate"), _), _), _), _), _), e) =>
+ (e, L'.PolUpdate)
| _ => (poly (); (e, L'.PolClient))
val (e, fm) = monoExp (env, St.empty, fm) e
--
cgit v1.2.3
From afc53b9b899188bc63c0d812b0104c4b04c91f0d Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sun, 11 Apr 2010 17:55:37 -0400
Subject: sendOwnIds policies
---
lib/ur/basis.urs | 2 ++
src/iflow.sml | 49 +++++++++++++++++++++++++++++++++++++++----------
src/mono.sml | 1 +
src/mono_print.sml | 3 +++
src/mono_shake.sml | 1 +
src/mono_util.sml | 3 +++
src/monoize.sml | 2 ++
7 files changed, 51 insertions(+), 10 deletions(-)
(limited to 'src/mono.sml')
diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs
index 3241cc9a..5a30f3f4 100644
--- a/lib/ur/basis.urs
+++ b/lib/ur/basis.urs
@@ -804,6 +804,8 @@ val sendClient : tables ::: {{Type}} -> exps ::: {Type}
-> [tables ~ exps] => sql_query [] tables exps
-> sql_policy
+val sendOwnIds : sql_sequence -> sql_policy
+
val mayInsert : fs ::: {Type} -> tables ::: {{Type}} -> [[New] ~ tables]
=> sql_query [] ([New = fs] ++ tables) []
-> sql_policy
diff --git a/src/iflow.sml b/src/iflow.sml
index 3ff3d100..77f25a91 100644
--- a/src/iflow.sml
+++ b/src/iflow.sml
@@ -482,7 +482,7 @@ type database = {Vars : representative IM.map ref,
Consts : representative CM.map ref,
Con0s : representative SM.map ref,
Records : (representative SM.map * representative) list ref,
- Funcs : ((string * representative list) * representative) list ref }
+ Funcs : ((string * representative list) * representative) list ref}
fun database () = {Vars = ref IM.empty,
Consts = ref CM.empty,
@@ -847,6 +847,7 @@ fun assert (db, a) =
else
();
#Cons (unNode r2) := SM.unionWith #1 (!(#Cons (unNode r2)), !(#Cons (unNode r1)));
+
compactFuncs ())
and compactFuncs () =
@@ -1450,9 +1451,9 @@ fun expIn rv env rvOf =
let
fun default () =
let
- val (rvN, e) = rv rvN
+ val (rvN, e') = rv rvN
in
- (inl e, rvN)
+ (inl e', rvN)
end
in
case e of
@@ -1686,7 +1687,7 @@ fun insertProp rvN rv e =
let
val t =
case v of
- "New" => "$New"
+ "New" => t ^ "$New"
| _ => t
in
And (p, Reln (Sql t, [rvOf v]))
@@ -1767,7 +1768,7 @@ fun updateProp rvN rv e =
let
val t =
case v of
- "New" => "$New"
+ "New" => t ^ "$New"
| _ => t
in
And (p, Reln (Sql t, [rvOf v]))
@@ -1989,6 +1990,8 @@ fun evalExp env (e as (_, loc), st) =
let
val (st, nv) = St.nextVar st
in
+ (*Print.prefaces "default" [("e", MonoPrint.p_exp MonoEnv.empty e),
+ ("nv", p_exp (Var nv))];*)
(Var nv, st)
end
@@ -2233,7 +2236,7 @@ fun evalExp env (e as (_, loc), st) =
st es
in
(Recd [], St.addInsert (st, (loc, And (St.ambient st,
- Reln (Sql "$New", [Recd es])))))
+ Reln (Sql (tab ^ "$New"), [Recd es])))))
end
| Delete (tab, e) =>
let
@@ -2302,13 +2305,19 @@ fun evalExp env (e as (_, loc), st) =
| (inr p, st) => (p, st)
val p = And (p,
- And (Reln (Sql "$New", [Recd fs]),
+ And (Reln (Sql (tab ^ "$New"), [Recd fs]),
And (Reln (Sql "$Old", [Var old]),
Reln (Sql tab, [Var old]))))
in
(Recd [], St.addUpdate (st, (loc, And (St.ambient st, p))))
end)
+ | ENextval (EPrim (Prim.String seq), _) =>
+ let
+ val (st, nv) = St.nextVar st
+ in
+ (Var nv, St.setAmbient (st, And (St.ambient st, Reln (Sql (String.extract (seq, 3, NONE)), [Var nv]))))
+ end
| ENextval _ => default ()
| ESetval _ => default ()
@@ -2416,6 +2425,16 @@ fun check file =
in
(vals, inserts, deletes, updates, client, insert, delete, p :: update)
end
+ | PolSequence e =>
+ (case #1 e of
+ EPrim (Prim.String seq) =>
+ let
+ val p = Reln (Sql (String.extract (seq, 3, NONE)), [Lvar 0])
+ val outs = [Lvar 0]
+ in
+ (vals, inserts, deletes, updates, (p, outs) :: client, insert, delete, update)
+ end
+ | _ => (vals, inserts, deletes, updates, client, insert, delete, update))
end
| _ => (vals, inserts, deletes, updates, client, insert, delete, update)
@@ -2434,8 +2453,14 @@ fun check file =
if decompH p
(fn hyps =>
List.exists (fn p' =>
- decompG p'
- (fn goals => imply (hyps, goals, NONE)))
+ if decompG p'
+ (fn goals => imply (hyps, goals, NONE)) then
+ ((*reset ();
+ Print.prefaces "Match" [("hyp", p_prop p),
+ ("goal", p_prop p')];*)
+ true)
+ else
+ false)
pols) then
()
else
@@ -2487,7 +2512,11 @@ fun check file =
client
orelse tryCombos (0, client, True, [])
orelse (reset ();
- Print.preface ("Untenable hypotheses",
+ Print.preface ("Untenable hypotheses"
+ ^ (case fl of
+ Control Where => " (WHERE clause)"
+ | Control Case => " (case discriminee)"
+ | Data => " (returned data value)"),
Print.p_list p_atom hyps);
false)
end) then
diff --git a/src/mono.sml b/src/mono.sml
index 79cde237..9a960cd0 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -128,6 +128,7 @@ datatype policy =
| PolInsert of exp
| PolDelete of exp
| PolUpdate of exp
+ | PolSequence of exp
datatype decl' =
DDatatype of (string * int * (string * int * typ option) list) list
diff --git a/src/mono_print.sml b/src/mono_print.sml
index b8016ff8..25a8e9d8 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -426,6 +426,9 @@ fun p_policy env pol =
| PolUpdate e => box [string "mayUpdate",
space,
p_exp env e]
+ | PolSequence e => box [string "sendOwnIds",
+ space,
+ p_exp env e]
fun p_decl env (dAll as (d, _) : decl) =
case d of
diff --git a/src/mono_shake.sml b/src/mono_shake.sml
index 6b248636..b42c9535 100644
--- a/src/mono_shake.sml
+++ b/src/mono_shake.sml
@@ -65,6 +65,7 @@ fun shake file =
| PolInsert e1 => e1
| PolDelete e1 => e1
| PolUpdate e1 => e1
+ | PolSequence e1 => e1
in
usedVars st e1
end
diff --git a/src/mono_util.sml b/src/mono_util.sml
index 085b68f8..6bbbecb1 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -553,6 +553,9 @@ fun mapfoldB {typ = fc, exp = fe, decl = fd, bind} =
| PolUpdate e =>
S.map2 (mfe ctx e,
PolUpdate)
+ | PolSequence e =>
+ S.map2 (mfe ctx e,
+ PolSequence)
and mfvi ctx (x, n, t, e, s) =
S.bind2 (mft t,
diff --git a/src/monoize.sml b/src/monoize.sml
index 601b690f..3983624b 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -3752,6 +3752,8 @@ fun monoDecl (env, fm) (all as (d, loc)) =
(e, L'.PolDelete)
| L.EApp ((L.ECApp ((L.ECApp ((L.EFfi ("Basis", "mayUpdate"), _), _), _), _), _), e) =>
(e, L'.PolUpdate)
+ | L.EFfiApp ("Basis", "sendOwnIds", [e]) =>
+ (e, L'.PolSequence)
| _ => (poly (); (e, L'.PolClient))
val (e, fm) = monoExp (env, St.empty, fm) e
--
cgit v1.2.3
From 8179b6224c5d4eb3b3fbe48e6acf5d630138c3da Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Tue, 27 Jul 2010 11:42:30 -0400
Subject: Initial version of equalKnown working for secret
---
lib/ur/basis.urs | 3 ++
src/iflow.sml | 85 +++++++++++++++++++++++++++++++++++++++++-----------
src/mono.sml | 1 +
src/mono_print.sml | 5 ++++
src/mono_shake.sml | 1 +
src/mono_util.sml | 3 ++
src/monoize.sml | 9 ++++++
tests/equalKnown.ur | 24 +++++++++++++++
tests/equalKnown.urp | 1 +
tests/equalKnown.urs | 1 +
10 files changed, 115 insertions(+), 18 deletions(-)
create mode 100644 tests/equalKnown.ur
create mode 100644 tests/equalKnown.urp
create mode 100644 tests/equalKnown.urs
(limited to 'src/mono.sml')
diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs
index f6141bc7..7b17dd05 100644
--- a/lib/ur/basis.urs
+++ b/lib/ur/basis.urs
@@ -819,6 +819,9 @@ val mayUpdate : fs ::: {Type} -> tables ::: {{Type}} -> [[Old, New] ~ tables]
=> sql_query [] ([Old = fs, New = fs] ++ tables) []
-> sql_policy
+val equalKnown : nm :: Name -> t ::: Type -> fs ::: {Type} -> ks ::: {{Unit}}
+ -> [[nm] ~ fs] => sql_table ([nm = t] ++ fs) ks -> sql_policy
+
val also : sql_policy -> sql_policy -> sql_policy
val debug : string -> transaction unit
diff --git a/src/iflow.sml b/src/iflow.sml
index 92e568a1..bf75775b 100644
--- a/src/iflow.sml
+++ b/src/iflow.sml
@@ -1228,6 +1228,9 @@ structure St :> sig
val allowSend : atom list * exp list -> unit
val send : check -> unit
+ val allowEqualKnown : { table : string, field : string } -> unit
+ val mayTest : prop -> bool
+
val allowInsert : atom list -> unit
val insert : ErrorMsg.span -> unit
@@ -1506,11 +1509,40 @@ val deletable = ref ([] : atom list list)
fun allowDelete v = deletable := v :: !deletable
val delete = doable deletable
+val testable = ref ([] : { table : string, field : string } list)
+fun allowEqualKnown v = testable := v :: !testable
+fun mayTest p =
+ case p of
+ Reln (Eq, [e1, e2]) =>
+ let
+ val (_, hs, _) = !hyps
+
+ fun tableInHyps (tab, x) = List.exists (fn AReln (Sql tab', [Var x']) => tab' = tab andalso x' = x
+ | _ => false) hs
+
+ fun allowed (tab, v) =
+ case tab of
+ Proj (Var tab, fd) =>
+ List.exists (fn {table = tab', field = fd'} =>
+ fd' = fd
+ andalso tableInHyps (tab', tab)) (!testable)
+ andalso Cc.check (db, AReln (Known, [v]))
+ | _ => false
+ in
+ if allowed (e1, e2) orelse allowed (e2, e1) then
+ (Cc.assert (db, AReln (Eq, [e1, e2]));
+ true)
+ else
+ false
+ end
+ | _ => false
+
fun reset () = (Cc.clear db;
path := [];
hyps := (0, [], ref false);
nvar := 0;
sendable := [];
+ testable := [];
insertable := [];
updatable := [];
deletable := [])
@@ -1660,7 +1692,8 @@ type 'a doQuery = {
Add : atom -> unit,
Save : unit -> 'a,
Restore : 'a -> unit,
- Cont : queryMode
+ Cont : queryMode,
+ Send : exp -> unit
}
fun doQuery (arg : 'a doQuery) (e as (_, loc)) =
@@ -1699,24 +1732,24 @@ fun doQuery (arg : 'a doQuery) (e as (_, loc)) =
val saved = #Save arg ()
fun addFrom () = app (fn (t, v) => #Add arg (AReln (Sql t, [rvOf v]))) (#From r)
- fun usedFields e =
+ fun leavesE e =
case e of
- SqConst _ => []
- | SqTrue => []
- | SqFalse => []
- | Null => []
- | SqNot e => usedFields e
- | Field (v, f) => [(false, Proj (rvOf v, f))]
- | Computed _ => []
- | Binop (_, e1, e2) => usedFields e1 @ usedFields e2
- | SqKnown _ => []
- | Inj e =>
- (case deinj (#Env arg) e of
- NONE => (ErrorMsg.errorAt loc "Expression injected into SQL is too complicated";
- [])
- | SOME e => [(true, e)])
- | SqFunc (_, e) => usedFields e
- | Unmodeled => []
+ Const _ => []
+ | Var _ => []
+ | Lvar _ => []
+ | Func (_, es) => List.concat (map leavesE es)
+ | Recd xes => List.concat (map (leavesE o #2) xes)
+ | Proj _ => [e]
+
+ fun leavesP p =
+ case p of
+ True => []
+ | False => []
+ | Unknown => []
+ | And (p1, p2) => leavesP p1 @ leavesP p2
+ | Or (p1, p2) => leavesP p1 @ leavesP p2
+ | Reln (_, es) => List.concat (map leavesE es)
+ | Cond (e, p) => e :: leavesP p
fun normal' () =
case #Cont arg of
@@ -1769,8 +1802,17 @@ fun doQuery (arg : 'a doQuery) (e as (_, loc)) =
inl e => Reln (Eq, [e, Func (DtCon0 "Basis.bool.True", [])])
| inr p => p
+ fun getConjuncts p =
+ case p of
+ And (p1, p2) => getConjuncts p1 @ getConjuncts p2
+ | _ => [p]
+
val saved = #Save arg ()
+
+ val conjs = getConjuncts p
+ val conjs = List.filter (not o St.mayTest) conjs
in
+ app (fn p => app (#Send arg) (leavesP p)) conjs;
decomp {Save = #Save arg, Restore = #Restore arg, Add = #Add arg}
p (fn () => final () handle Cc.Contradiction => ());
#Restore arg saved
@@ -2076,6 +2118,7 @@ fun evalExp env (e as (_, loc)) k =
Add = fn a => St.assert [a],
Save = St.stash,
Restore = St.reinstate,
+ Send = fn e => St.send (e, loc),
Cont = AllCols (fn x =>
(St.assert [AReln (Eq, [r, x])];
evalExp (acc :: r :: env) b k))} q
@@ -2448,6 +2491,7 @@ fun check file =
Add = fn a => atoms := a :: !atoms,
Save = fn () => !atoms,
Restore = fn ls => atoms := ls,
+ Send = fn _ => (),
Cont = SomeCol (fn r => k (rev (!atoms), r))}
fun untab (tab, nams) = List.filter (fn AReln (Sql tab', [Lvar lv]) =>
@@ -2483,6 +2527,11 @@ fun check file =
St.allowSend ([p], outs)
end
| _ => ())
+ | PolEqualKnown {table = tab, field = nm} =>
+ (case #1 tab of
+ EPrim (Prim.String tab) => St.allowEqualKnown {table = String.extract (tab, 3, NONE),
+ field = nm}
+ | _ => ErrorMsg.errorAt loc "Table for 'equalKnown' policy isn't fully resolved.")
end
| _ => ()
diff --git a/src/mono.sml b/src/mono.sml
index 9a960cd0..2f5ab117 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -129,6 +129,7 @@ datatype policy =
| PolDelete of exp
| PolUpdate of exp
| PolSequence of exp
+ | PolEqualKnown of {table : exp, field : string}
datatype decl' =
DDatatype of (string * int * (string * int * typ option) list) list
diff --git a/src/mono_print.sml b/src/mono_print.sml
index 25a8e9d8..693b5e3e 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -429,6 +429,11 @@ fun p_policy env pol =
| PolSequence e => box [string "sendOwnIds",
space,
p_exp env e]
+ | PolEqualKnown {table = tab, field = nm} => box [string "equalKnown[",
+ string nm,
+ string "]",
+ space,
+ p_exp env tab]
fun p_decl env (dAll as (d, _) : decl) =
case d of
diff --git a/src/mono_shake.sml b/src/mono_shake.sml
index 50c4b387..6a5aefae 100644
--- a/src/mono_shake.sml
+++ b/src/mono_shake.sml
@@ -67,6 +67,7 @@ fun shake file =
| PolDelete e1 => e1
| PolUpdate e1 => e1
| PolSequence e1 => e1
+ | PolEqualKnown {table = e1, ...} => e1
in
usedVars st e1
end
diff --git a/src/mono_util.sml b/src/mono_util.sml
index 6bbbecb1..cb01a958 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -556,6 +556,9 @@ fun mapfoldB {typ = fc, exp = fe, decl = fd, bind} =
| PolSequence e =>
S.map2 (mfe ctx e,
PolSequence)
+ | PolEqualKnown {table = tab, field = nm} =>
+ S.map2 (mfe ctx tab,
+ fn tab => PolEqualKnown {table = tab, field = nm})
and mfvi ctx (x, n, t, e, s) =
S.bind2 (mft t,
diff --git a/src/monoize.sml b/src/monoize.sml
index d43002cb..5054cc9f 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -3804,6 +3804,15 @@ fun monoDecl (env, fm) (all as (d, loc)) =
(e, L'.PolUpdate)
| L.EFfiApp ("Basis", "sendOwnIds", [e]) =>
(e, L'.PolSequence)
+ | L.EApp ((L.ECApp
+ ((L.ECApp
+ ((L.ECApp
+ ((L.ECApp
+ ((L.EFfi ("Basis", "equalKnown"), _), nm), _), _), _),
+ _), _), _), _), tab) =>
+ (case #1 nm of
+ L.CName nm => (tab, fn tab => L'.PolEqualKnown {table = tab, field = nm})
+ | _ => (poly (); (e, L'.PolClient)))
| _ => (poly (); (e, L'.PolClient))
val (e, fm) = monoExp (env, St.empty, fm) e
diff --git a/tests/equalKnown.ur b/tests/equalKnown.ur
new file mode 100644
index 00000000..4af32490
--- /dev/null
+++ b/tests/equalKnown.ur
@@ -0,0 +1,24 @@
+type fruit = int
+table fruit : { Id : fruit, Nam : string, Weight : float, Secret : string }
+ PRIMARY KEY Id,
+ CONSTRAINT Nam UNIQUE Nam
+
+policy sendClient (SELECT fruit.Id, fruit.Nam
+ FROM fruit)
+
+policy sendClient (SELECT fruit.Weight
+ FROM fruit
+ WHERE known(fruit.Secret))
+
+policy equalKnown[#Secret] fruit
+
+fun main () =
+ x1 <- queryX (SELECT fruit.Id, fruit.Nam, fruit.Weight
+ FROM fruit
+ WHERE fruit.Nam = "apple"
+ AND fruit.Secret = "tasty")
+ (fn x => {[x.Fruit.Id]}: {[x.Fruit.Nam]}, {[x.Fruit.Weight]});
+
+ return
+
+
diff --git a/tests/equalKnown.urp b/tests/equalKnown.urp
new file mode 100644
index 00000000..380321fd
--- /dev/null
+++ b/tests/equalKnown.urp
@@ -0,0 +1 @@
+equalKnown
diff --git a/tests/equalKnown.urs b/tests/equalKnown.urs
new file mode 100644
index 00000000..6ac44e0b
--- /dev/null
+++ b/tests/equalKnown.urs
@@ -0,0 +1 @@
+val main : unit -> transaction page
--
cgit v1.2.3
From a5d7c214f42af261d900af8a7ac042b807c2abe2 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Tue, 27 Jul 2010 12:12:08 -0400
Subject: equalAny policies
---
lib/ur/basis.urs | 2 ++
src/iflow.sml | 21 +++++++++++----------
src/mono.sml | 2 +-
src/mono_print.sml | 12 +++++++-----
src/mono_shake.sml | 2 +-
src/mono_util.sml | 4 ++--
src/monoize.sml | 11 ++++++++++-
7 files changed, 34 insertions(+), 20 deletions(-)
(limited to 'src/mono.sml')
diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs
index 7b17dd05..8bc2b6ea 100644
--- a/lib/ur/basis.urs
+++ b/lib/ur/basis.urs
@@ -819,6 +819,8 @@ val mayUpdate : fs ::: {Type} -> tables ::: {{Type}} -> [[Old, New] ~ tables]
=> sql_query [] ([Old = fs, New = fs] ++ tables) []
-> sql_policy
+val equalAny : nm :: Name -> t ::: Type -> fs ::: {Type} -> ks ::: {{Unit}}
+ -> [[nm] ~ fs] => sql_table ([nm = t] ++ fs) ks -> sql_policy
val equalKnown : nm :: Name -> t ::: Type -> fs ::: {Type} -> ks ::: {{Unit}}
-> [[nm] ~ fs] => sql_table ([nm = t] ++ fs) ks -> sql_policy
diff --git a/src/iflow.sml b/src/iflow.sml
index bf75775b..c70240a7 100644
--- a/src/iflow.sml
+++ b/src/iflow.sml
@@ -1228,7 +1228,7 @@ structure St :> sig
val allowSend : atom list * exp list -> unit
val send : check -> unit
- val allowEqualKnown : { table : string, field : string } -> unit
+ val allowEqual : { table : string, field : string, known : bool } -> unit
val mayTest : prop -> bool
val allowInsert : atom list -> unit
@@ -1509,8 +1509,8 @@ val deletable = ref ([] : atom list list)
fun allowDelete v = deletable := v :: !deletable
val delete = doable deletable
-val testable = ref ([] : { table : string, field : string } list)
-fun allowEqualKnown v = testable := v :: !testable
+val testable = ref ([] : { table : string, field : string, known : bool } list)
+fun allowEqual v = testable := v :: !testable
fun mayTest p =
case p of
Reln (Eq, [e1, e2]) =>
@@ -1523,14 +1523,14 @@ fun mayTest p =
fun allowed (tab, v) =
case tab of
Proj (Var tab, fd) =>
- List.exists (fn {table = tab', field = fd'} =>
+ List.exists (fn {table = tab', field = fd', known} =>
fd' = fd
- andalso tableInHyps (tab', tab)) (!testable)
- andalso Cc.check (db, AReln (Known, [v]))
+ andalso tableInHyps (tab', tab)
+ andalso (not known orelse Cc.check (db, AReln (Known, [v])))) (!testable)
| _ => false
in
if allowed (e1, e2) orelse allowed (e2, e1) then
- (Cc.assert (db, AReln (Eq, [e1, e2]));
+ (assert [AReln (Eq, [e1, e2])];
true)
else
false
@@ -2527,10 +2527,11 @@ fun check file =
St.allowSend ([p], outs)
end
| _ => ())
- | PolEqualKnown {table = tab, field = nm} =>
+ | PolEqual {table = tab, field = nm, known} =>
(case #1 tab of
- EPrim (Prim.String tab) => St.allowEqualKnown {table = String.extract (tab, 3, NONE),
- field = nm}
+ EPrim (Prim.String tab) => St.allowEqual {table = String.extract (tab, 3, NONE),
+ field = nm,
+ known = known}
| _ => ErrorMsg.errorAt loc "Table for 'equalKnown' policy isn't fully resolved.")
end
diff --git a/src/mono.sml b/src/mono.sml
index 2f5ab117..0db9a684 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -129,7 +129,7 @@ datatype policy =
| PolDelete of exp
| PolUpdate of exp
| PolSequence of exp
- | PolEqualKnown of {table : exp, field : string}
+ | PolEqual of {table : exp, field : string, known : bool}
datatype decl' =
DDatatype of (string * int * (string * int * typ option) list) list
diff --git a/src/mono_print.sml b/src/mono_print.sml
index 693b5e3e..74467e08 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -429,11 +429,13 @@ fun p_policy env pol =
| PolSequence e => box [string "sendOwnIds",
space,
p_exp env e]
- | PolEqualKnown {table = tab, field = nm} => box [string "equalKnown[",
- string nm,
- string "]",
- space,
- p_exp env tab]
+ | PolEqual {table = tab, field = nm, known} => box [string "equal",
+ string (if known then "Known" else "Any"),
+ string "[",
+ string nm,
+ string "]",
+ space,
+ p_exp env tab]
fun p_decl env (dAll as (d, _) : decl) =
case d of
diff --git a/src/mono_shake.sml b/src/mono_shake.sml
index 6a5aefae..581f1357 100644
--- a/src/mono_shake.sml
+++ b/src/mono_shake.sml
@@ -67,7 +67,7 @@ fun shake file =
| PolDelete e1 => e1
| PolUpdate e1 => e1
| PolSequence e1 => e1
- | PolEqualKnown {table = e1, ...} => e1
+ | PolEqual {table = e1, ...} => e1
in
usedVars st e1
end
diff --git a/src/mono_util.sml b/src/mono_util.sml
index cb01a958..b0baa395 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -556,9 +556,9 @@ fun mapfoldB {typ = fc, exp = fe, decl = fd, bind} =
| PolSequence e =>
S.map2 (mfe ctx e,
PolSequence)
- | PolEqualKnown {table = tab, field = nm} =>
+ | PolEqual {table = tab, field = nm, known = b} =>
S.map2 (mfe ctx tab,
- fn tab => PolEqualKnown {table = tab, field = nm})
+ fn tab => PolEqual {table = tab, field = nm, known = b})
and mfvi ctx (x, n, t, e, s) =
S.bind2 (mft t,
diff --git a/src/monoize.sml b/src/monoize.sml
index 5054cc9f..f72c76a0 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -3811,7 +3811,16 @@ fun monoDecl (env, fm) (all as (d, loc)) =
((L.EFfi ("Basis", "equalKnown"), _), nm), _), _), _),
_), _), _), _), tab) =>
(case #1 nm of
- L.CName nm => (tab, fn tab => L'.PolEqualKnown {table = tab, field = nm})
+ L.CName nm => (tab, fn tab => L'.PolEqual {table = tab, field = nm, known = true})
+ | _ => (poly (); (e, L'.PolClient)))
+ | L.EApp ((L.ECApp
+ ((L.ECApp
+ ((L.ECApp
+ ((L.ECApp
+ ((L.EFfi ("Basis", "equalAny"), _), nm), _), _), _),
+ _), _), _), _), tab) =>
+ (case #1 nm of
+ L.CName nm => (tab, fn tab => L'.PolEqual {table = tab, field = nm, known = false})
| _ => (poly (); (e, L'.PolClient)))
| _ => (poly (); (e, L'.PolClient))
--
cgit v1.2.3
From 67ed059e3b57399c7a8231f3180f35357b7aa1c9 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Tue, 27 Jul 2010 14:04:09 -0400
Subject: Roll back WHERE checking
---
lib/ur/basis.urs | 5 ---
src/iflow.sml | 86 +++++++++++-----------------------------------------
src/mono.sml | 1 -
src/mono_print.sml | 7 -----
src/mono_shake.sml | 1 -
src/mono_util.sml | 3 --
src/monoize.sml | 18 -----------
tests/equalKnown.ur | 24 ---------------
tests/equalKnown.urp | 1 -
tests/equalKnown.urs | 1 -
10 files changed, 18 insertions(+), 129 deletions(-)
delete mode 100644 tests/equalKnown.ur
delete mode 100644 tests/equalKnown.urp
delete mode 100644 tests/equalKnown.urs
(limited to 'src/mono.sml')
diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs
index 8bc2b6ea..f6141bc7 100644
--- a/lib/ur/basis.urs
+++ b/lib/ur/basis.urs
@@ -819,11 +819,6 @@ val mayUpdate : fs ::: {Type} -> tables ::: {{Type}} -> [[Old, New] ~ tables]
=> sql_query [] ([Old = fs, New = fs] ++ tables) []
-> sql_policy
-val equalAny : nm :: Name -> t ::: Type -> fs ::: {Type} -> ks ::: {{Unit}}
- -> [[nm] ~ fs] => sql_table ([nm = t] ++ fs) ks -> sql_policy
-val equalKnown : nm :: Name -> t ::: Type -> fs ::: {Type} -> ks ::: {{Unit}}
- -> [[nm] ~ fs] => sql_table ([nm = t] ++ fs) ks -> sql_policy
-
val also : sql_policy -> sql_policy -> sql_policy
val debug : string -> transaction unit
diff --git a/src/iflow.sml b/src/iflow.sml
index c70240a7..92e568a1 100644
--- a/src/iflow.sml
+++ b/src/iflow.sml
@@ -1228,9 +1228,6 @@ structure St :> sig
val allowSend : atom list * exp list -> unit
val send : check -> unit
- val allowEqual : { table : string, field : string, known : bool } -> unit
- val mayTest : prop -> bool
-
val allowInsert : atom list -> unit
val insert : ErrorMsg.span -> unit
@@ -1509,40 +1506,11 @@ val deletable = ref ([] : atom list list)
fun allowDelete v = deletable := v :: !deletable
val delete = doable deletable
-val testable = ref ([] : { table : string, field : string, known : bool } list)
-fun allowEqual v = testable := v :: !testable
-fun mayTest p =
- case p of
- Reln (Eq, [e1, e2]) =>
- let
- val (_, hs, _) = !hyps
-
- fun tableInHyps (tab, x) = List.exists (fn AReln (Sql tab', [Var x']) => tab' = tab andalso x' = x
- | _ => false) hs
-
- fun allowed (tab, v) =
- case tab of
- Proj (Var tab, fd) =>
- List.exists (fn {table = tab', field = fd', known} =>
- fd' = fd
- andalso tableInHyps (tab', tab)
- andalso (not known orelse Cc.check (db, AReln (Known, [v])))) (!testable)
- | _ => false
- in
- if allowed (e1, e2) orelse allowed (e2, e1) then
- (assert [AReln (Eq, [e1, e2])];
- true)
- else
- false
- end
- | _ => false
-
fun reset () = (Cc.clear db;
path := [];
hyps := (0, [], ref false);
nvar := 0;
sendable := [];
- testable := [];
insertable := [];
updatable := [];
deletable := [])
@@ -1692,8 +1660,7 @@ type 'a doQuery = {
Add : atom -> unit,
Save : unit -> 'a,
Restore : 'a -> unit,
- Cont : queryMode,
- Send : exp -> unit
+ Cont : queryMode
}
fun doQuery (arg : 'a doQuery) (e as (_, loc)) =
@@ -1732,24 +1699,24 @@ fun doQuery (arg : 'a doQuery) (e as (_, loc)) =
val saved = #Save arg ()
fun addFrom () = app (fn (t, v) => #Add arg (AReln (Sql t, [rvOf v]))) (#From r)
- fun leavesE e =
+ fun usedFields e =
case e of
- Const _ => []
- | Var _ => []
- | Lvar _ => []
- | Func (_, es) => List.concat (map leavesE es)
- | Recd xes => List.concat (map (leavesE o #2) xes)
- | Proj _ => [e]
-
- fun leavesP p =
- case p of
- True => []
- | False => []
- | Unknown => []
- | And (p1, p2) => leavesP p1 @ leavesP p2
- | Or (p1, p2) => leavesP p1 @ leavesP p2
- | Reln (_, es) => List.concat (map leavesE es)
- | Cond (e, p) => e :: leavesP p
+ SqConst _ => []
+ | SqTrue => []
+ | SqFalse => []
+ | Null => []
+ | SqNot e => usedFields e
+ | Field (v, f) => [(false, Proj (rvOf v, f))]
+ | Computed _ => []
+ | Binop (_, e1, e2) => usedFields e1 @ usedFields e2
+ | SqKnown _ => []
+ | Inj e =>
+ (case deinj (#Env arg) e of
+ NONE => (ErrorMsg.errorAt loc "Expression injected into SQL is too complicated";
+ [])
+ | SOME e => [(true, e)])
+ | SqFunc (_, e) => usedFields e
+ | Unmodeled => []
fun normal' () =
case #Cont arg of
@@ -1802,17 +1769,8 @@ fun doQuery (arg : 'a doQuery) (e as (_, loc)) =
inl e => Reln (Eq, [e, Func (DtCon0 "Basis.bool.True", [])])
| inr p => p
- fun getConjuncts p =
- case p of
- And (p1, p2) => getConjuncts p1 @ getConjuncts p2
- | _ => [p]
-
val saved = #Save arg ()
-
- val conjs = getConjuncts p
- val conjs = List.filter (not o St.mayTest) conjs
in
- app (fn p => app (#Send arg) (leavesP p)) conjs;
decomp {Save = #Save arg, Restore = #Restore arg, Add = #Add arg}
p (fn () => final () handle Cc.Contradiction => ());
#Restore arg saved
@@ -2118,7 +2076,6 @@ fun evalExp env (e as (_, loc)) k =
Add = fn a => St.assert [a],
Save = St.stash,
Restore = St.reinstate,
- Send = fn e => St.send (e, loc),
Cont = AllCols (fn x =>
(St.assert [AReln (Eq, [r, x])];
evalExp (acc :: r :: env) b k))} q
@@ -2491,7 +2448,6 @@ fun check file =
Add = fn a => atoms := a :: !atoms,
Save = fn () => !atoms,
Restore = fn ls => atoms := ls,
- Send = fn _ => (),
Cont = SomeCol (fn r => k (rev (!atoms), r))}
fun untab (tab, nams) = List.filter (fn AReln (Sql tab', [Lvar lv]) =>
@@ -2527,12 +2483,6 @@ fun check file =
St.allowSend ([p], outs)
end
| _ => ())
- | PolEqual {table = tab, field = nm, known} =>
- (case #1 tab of
- EPrim (Prim.String tab) => St.allowEqual {table = String.extract (tab, 3, NONE),
- field = nm,
- known = known}
- | _ => ErrorMsg.errorAt loc "Table for 'equalKnown' policy isn't fully resolved.")
end
| _ => ()
diff --git a/src/mono.sml b/src/mono.sml
index 0db9a684..9a960cd0 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -129,7 +129,6 @@ datatype policy =
| PolDelete of exp
| PolUpdate of exp
| PolSequence of exp
- | PolEqual of {table : exp, field : string, known : bool}
datatype decl' =
DDatatype of (string * int * (string * int * typ option) list) list
diff --git a/src/mono_print.sml b/src/mono_print.sml
index 74467e08..25a8e9d8 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -429,13 +429,6 @@ fun p_policy env pol =
| PolSequence e => box [string "sendOwnIds",
space,
p_exp env e]
- | PolEqual {table = tab, field = nm, known} => box [string "equal",
- string (if known then "Known" else "Any"),
- string "[",
- string nm,
- string "]",
- space,
- p_exp env tab]
fun p_decl env (dAll as (d, _) : decl) =
case d of
diff --git a/src/mono_shake.sml b/src/mono_shake.sml
index 581f1357..50c4b387 100644
--- a/src/mono_shake.sml
+++ b/src/mono_shake.sml
@@ -67,7 +67,6 @@ fun shake file =
| PolDelete e1 => e1
| PolUpdate e1 => e1
| PolSequence e1 => e1
- | PolEqual {table = e1, ...} => e1
in
usedVars st e1
end
diff --git a/src/mono_util.sml b/src/mono_util.sml
index b0baa395..6bbbecb1 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -556,9 +556,6 @@ fun mapfoldB {typ = fc, exp = fe, decl = fd, bind} =
| PolSequence e =>
S.map2 (mfe ctx e,
PolSequence)
- | PolEqual {table = tab, field = nm, known = b} =>
- S.map2 (mfe ctx tab,
- fn tab => PolEqual {table = tab, field = nm, known = b})
and mfvi ctx (x, n, t, e, s) =
S.bind2 (mft t,
diff --git a/src/monoize.sml b/src/monoize.sml
index f72c76a0..d43002cb 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -3804,24 +3804,6 @@ fun monoDecl (env, fm) (all as (d, loc)) =
(e, L'.PolUpdate)
| L.EFfiApp ("Basis", "sendOwnIds", [e]) =>
(e, L'.PolSequence)
- | L.EApp ((L.ECApp
- ((L.ECApp
- ((L.ECApp
- ((L.ECApp
- ((L.EFfi ("Basis", "equalKnown"), _), nm), _), _), _),
- _), _), _), _), tab) =>
- (case #1 nm of
- L.CName nm => (tab, fn tab => L'.PolEqual {table = tab, field = nm, known = true})
- | _ => (poly (); (e, L'.PolClient)))
- | L.EApp ((L.ECApp
- ((L.ECApp
- ((L.ECApp
- ((L.ECApp
- ((L.EFfi ("Basis", "equalAny"), _), nm), _), _), _),
- _), _), _), _), tab) =>
- (case #1 nm of
- L.CName nm => (tab, fn tab => L'.PolEqual {table = tab, field = nm, known = false})
- | _ => (poly (); (e, L'.PolClient)))
| _ => (poly (); (e, L'.PolClient))
val (e, fm) = monoExp (env, St.empty, fm) e
diff --git a/tests/equalKnown.ur b/tests/equalKnown.ur
deleted file mode 100644
index 4af32490..00000000
--- a/tests/equalKnown.ur
+++ /dev/null
@@ -1,24 +0,0 @@
-type fruit = int
-table fruit : { Id : fruit, Nam : string, Weight : float, Secret : string }
- PRIMARY KEY Id,
- CONSTRAINT Nam UNIQUE Nam
-
-policy sendClient (SELECT fruit.Id, fruit.Nam
- FROM fruit)
-
-policy sendClient (SELECT fruit.Weight
- FROM fruit
- WHERE known(fruit.Secret))
-
-policy equalKnown[#Secret] fruit
-
-fun main () =
- x1 <- queryX (SELECT fruit.Id, fruit.Nam, fruit.Weight
- FROM fruit
- WHERE fruit.Nam = "apple"
- AND fruit.Secret = "tasty")
- (fn x => {[x.Fruit.Id]}: {[x.Fruit.Nam]}, {[x.Fruit.Weight]});
-
- return
-
-
diff --git a/tests/equalKnown.urp b/tests/equalKnown.urp
deleted file mode 100644
index 380321fd..00000000
--- a/tests/equalKnown.urp
+++ /dev/null
@@ -1 +0,0 @@
-equalKnown
diff --git a/tests/equalKnown.urs b/tests/equalKnown.urs
deleted file mode 100644
index 6ac44e0b..00000000
--- a/tests/equalKnown.urs
+++ /dev/null
@@ -1 +0,0 @@
-val main : unit -> transaction page
--
cgit v1.2.3
From ee175ea1f9151123e47d9cbfee0c6329b2e5d934 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sun, 5 Sep 2010 14:00:57 -0400
Subject: tryDml
---
lib/ur/basis.urs | 2 ++
src/checknest.sml | 5 +++--
src/cjr.sml | 5 ++++-
src/cjr_print.sml | 24 +++++++++++++++++-------
src/cjrize.sml | 4 ++--
src/iflow.sml | 8 ++++----
src/jscomp.sml | 4 ++--
src/mono.sml | 4 +++-
src/mono_print.sml | 6 +++---
src/mono_reduce.sml | 2 +-
src/mono_util.sml | 4 ++--
src/monoize.sml | 48 ++++++++++++++++++++++++++++--------------------
src/mysql.sml | 23 +++++++++++++----------
src/postgres.sml | 26 ++++++++++++++------------
src/prepare.sml | 4 ++--
src/settings.sig | 6 ++++--
src/settings.sml | 6 ++++--
src/sqlite.sml | 23 +++++++++++++----------
tests/tryDml.ur | 13 +++++++++++++
tests/tryDml.urp | 4 ++++
tests/tryDml.urs | 1 +
21 files changed, 139 insertions(+), 83 deletions(-)
create mode 100644 tests/tryDml.ur
create mode 100644 tests/tryDml.urp
create mode 100644 tests/tryDml.urs
(limited to 'src/mono.sml')
diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs
index c06482ed..6cd9915e 100644
--- a/lib/ur/basis.urs
+++ b/lib/ur/basis.urs
@@ -535,6 +535,8 @@ val query : tables ::: {{Type}} -> exps ::: {Type}
type dml
val dml : dml -> transaction unit
+val tryDml : dml -> transaction (option string)
+(* Returns an error message on failure. *)
val insert : fields ::: {Type} -> uniques ::: {{Unit}}
-> sql_table fields uniques
diff --git a/src/checknest.sml b/src/checknest.sml
index a53c7083..1147d3e6 100644
--- a/src/checknest.sml
+++ b/src/checknest.sml
@@ -138,9 +138,10 @@ fun annotateExp globals =
| SOME {id, query, ...} => SOME {id = id, query = query,
nested = IS.member (expUses globals body, id)}},
loc)
- | EDml {dml, prepared} =>
+ | EDml {dml, prepared, mode} =>
(EDml {dml = ae dml,
- prepared = prepared}, loc)
+ prepared = prepared,
+ mode = mode}, loc)
| ENextval {seq, prepared} =>
(ENextval {seq = ae seq,
diff --git a/src/cjr.sml b/src/cjr.sml
index a19109d2..f34662dc 100644
--- a/src/cjr.sml
+++ b/src/cjr.sml
@@ -56,6 +56,8 @@ datatype pat' =
withtype pat = pat' located
+datatype failure_mode = datatype Settings.failure_mode
+
datatype exp' =
EPrim of Prim.t
| ERel of int
@@ -92,7 +94,8 @@ datatype exp' =
initial : exp,
prepared : {id : int, query : string, nested : bool} option }
| EDml of { dml : exp,
- prepared : {id : int, dml : string} option }
+ prepared : {id : int, dml : string} option,
+ mode : failure_mode }
| ENextval of { seq : exp,
prepared : {id : int, query : string} option }
| ESetval of { seq : exp, count : exp }
diff --git a/src/cjr_print.sml b/src/cjr_print.sml
index 412531a6..7331196f 100644
--- a/src/cjr_print.sml
+++ b/src/cjr_print.sml
@@ -1791,8 +1791,11 @@ fun p_exp' par env (e, loc) =
box []]
end
- | EDml {dml, prepared} =>
- box [string "(uw_begin_region(ctx), ({",
+ | EDml {dml, prepared, mode} =>
+ box [case mode of
+ Settings.Error => box []
+ | Settings.None => string "({const char *uw_errmsg = NULL;",
+ string "(uw_begin_region(ctx), ({",
newline,
case prepared of
NONE => box [string "char *dml = ",
@@ -1800,7 +1803,7 @@ fun p_exp' par env (e, loc) =
string ";",
newline,
newline,
- #dml (Settings.currentDbms ()) loc]
+ #dml (Settings.currentDbms ()) (loc, mode)]
| SOME {id, dml = dml'} =>
let
val inputs = getPargs dml
@@ -1823,16 +1826,23 @@ fun p_exp' par env (e, loc) =
#dmlPrepared (Settings.currentDbms ()) {loc = loc,
id = id,
dml = dml',
- inputs = map #2 inputs}]
+ inputs = map #2 inputs,
+ mode = mode}]
end,
newline,
newline,
-
string "uw_end_region(ctx);",
newline,
- string "uw_unit_v;",
+
+ case mode of
+ Settings.Error => string "uw_unit_v;"
+ | Settings.None => string "uw_errmsg ? uw_strdup(ctx, uw_errmsg) : NULL;",
+
newline,
- string "}))"]
+ string "}))",
+ case mode of
+ Settings.Error => box []
+ | Settings.None => string ";})"]
| ENextval {seq, prepared} =>
box [string "({",
diff --git a/src/cjrize.sml b/src/cjrize.sml
index b98b3c25..22463cd4 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -455,11 +455,11 @@ fun cifyExp (eAll as (e, loc), sm) =
query = query, body = body, initial = initial, prepared = NONE}, loc), sm)
end
- | L.EDml e =>
+ | L.EDml (e, mode) =>
let
val (e, sm) = cifyExp (e, sm)
in
- ((L'.EDml {dml = e, prepared = NONE}, loc), sm)
+ ((L'.EDml {dml = e, prepared = NONE, mode = mode}, loc), sm)
end
| L.ENextval e =>
diff --git a/src/iflow.sml b/src/iflow.sml
index 92e568a1..c0e92cb1 100644
--- a/src/iflow.sml
+++ b/src/iflow.sml
@@ -2040,7 +2040,7 @@ fun evalExp env (e as (_, loc)) k =
val (ts, cs) = MonoUtil.Exp.fold {typ = fn (_, st) => st,
exp = fn (e, st as (cs, ts)) =>
case e of
- EDml e =>
+ EDml (e, _) =>
(case parse dml e of
NONE => st
| SOME c =>
@@ -2080,7 +2080,7 @@ fun evalExp env (e as (_, loc)) k =
(St.assert [AReln (Eq, [r, x])];
evalExp (acc :: r :: env) b k))} q
end)
- | EDml e =>
+ | EDml (e, _) =>
(case parse dml e of
NONE => (print ("Warning: Information flow checker can't parse DML command at "
^ ErrorMsg.spanToString loc ^ "\n");
@@ -2400,7 +2400,7 @@ fun check file =
query = doExp env query,
body = doExp (Unknown :: Unknown :: env) body,
initial = doExp env initial}, loc)
- | EDml e1 =>
+ | EDml (e1, mode) =>
(case parse dml e1 of
NONE => ()
| SOME c =>
@@ -2410,7 +2410,7 @@ fun check file =
tables := SS.add (!tables, tab)
| Update (tab, _, _) =>
tables := SS.add (!tables, tab);
- (EDml (doExp env e1), loc))
+ (EDml (doExp env e1, mode), loc))
| ENextval e1 => (ENextval (doExp env e1), loc)
| ESetval (e1, e2) => (ESetval (doExp env e1, doExp env e2), loc)
| EUnurlify (e1, t, b) => (EUnurlify (doExp env e1, t, b), loc)
diff --git a/src/jscomp.sml b/src/jscomp.sml
index f97725eb..2f7ee5ab 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -1147,11 +1147,11 @@ fun process file =
((EQuery {exps = exps, tables = tables, state = state,
query = query, body = body, initial = initial}, loc), st)
end
- | EDml e =>
+ | EDml (e, mode) =>
let
val (e, st) = exp outer (e, st)
in
- ((EDml e, loc), st)
+ ((EDml (e, mode), loc), st)
end
| ENextval e =>
let
diff --git a/src/mono.sml b/src/mono.sml
index 9a960cd0..554b1dc5 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -66,6 +66,8 @@ datatype javascript_mode =
datatype effect = datatype Export.effect
datatype export_kind = datatype Export.export_kind
+datatype failure_mode = datatype Settings.failure_mode
+
datatype exp' =
EPrim of Prim.t
| ERel of int
@@ -104,7 +106,7 @@ datatype exp' =
query : exp,
body : exp,
initial : exp }
- | EDml of exp
+ | EDml of exp * failure_mode
| ENextval of exp
| ESetval of exp * exp
diff --git a/src/mono_print.sml b/src/mono_print.sml
index 25a8e9d8..c3f2866e 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -322,9 +322,9 @@ fun p_exp' par env (e, _) =
string "in",
space,
p_exp (E.pushERel (E.pushERel env "r" dummyt NONE) "acc" dummyt NONE) body]
- | EDml e => box [string "dml(",
- p_exp env e,
- string ")"]
+ | EDml (e, _) => box [string "dml(",
+ p_exp env e,
+ string ")"]
| ENextval e => box [string "nextval(",
p_exp env e,
string ")"]
diff --git a/src/mono_reduce.sml b/src/mono_reduce.sml
index 5e735b79..ce9f4a4e 100644
--- a/src/mono_reduce.sml
+++ b/src/mono_reduce.sml
@@ -465,7 +465,7 @@ fun reduce file =
[ReadDb],
summarize (d + 2) body]
- | EDml e => summarize d e @ [WriteDb]
+ | EDml (e, _) => summarize d e @ [WriteDb]
| ENextval e => summarize d e @ [WriteDb]
| ESetval (e1, e2) => summarize d e1 @ summarize d e2 @ [WriteDb]
| EUnurlify (e, _, _) => summarize d e
diff --git a/src/mono_util.sml b/src/mono_util.sml
index 6bbbecb1..8a567e83 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -332,10 +332,10 @@ fun mapfoldB {typ = fc, exp = fe, bind} =
initial = initial'},
loc)))))))
- | EDml e =>
+ | EDml (e, fm) =>
S.map2 (mfe ctx e,
fn e' =>
- (EDml e', loc))
+ (EDml (e', fm), loc))
| ENextval e =>
S.map2 (mfe ctx e,
fn e' =>
diff --git a/src/monoize.sml b/src/monoize.sml
index cde1af70..07e69834 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -1748,7 +1748,15 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
let
val (e, fm) = monoExp (env, st, fm) e
in
- ((L'.EDml e, loc),
+ ((L'.EDml (e, L'.Error), loc),
+ fm)
+ end
+
+ | L.EFfiApp ("Basis", "tryDml", [e]) =>
+ let
+ val (e, fm) = monoExp (env, st, fm) e
+ in
+ ((L'.EDml (e, L'.None), loc),
fm)
end
@@ -4014,13 +4022,13 @@ fun monoize env file =
val e =
foldl (fn ((x, v), e) =>
(L'.ESeq (
- (L'.EDml (L'.EStrcat (
- (L'.EPrim (Prim.String ("UPDATE uw_"
- ^ tab
- ^ " SET uw_"
- ^ x
- ^ " = NULL WHERE ")), loc),
- cond (x, v)), loc), loc),
+ (L'.EDml ((L'.EStrcat (
+ (L'.EPrim (Prim.String ("UPDATE uw_"
+ ^ tab
+ ^ " SET uw_"
+ ^ x
+ ^ " = NULL WHERE ")), loc),
+ cond (x, v)), loc), L'.Error), loc),
e), loc))
e nullable
@@ -4039,7 +4047,7 @@ fun monoize env file =
^ tab
^ " WHERE ")), loc),
cond eb), loc)
- ebs), loc),
+ ebs, L'.Error), loc),
e), loc)
in
e
@@ -4067,15 +4075,15 @@ fun monoize env file =
[] => e
| (x, _) :: ebs =>
(L'.ESeq (
- (L'.EDml (L'.EPrim (Prim.String
- (foldl (fn ((x, _), s) =>
- s ^ ", uw_" ^ x ^ " = NULL")
- ("UPDATE uw_"
- ^ tab
- ^ " SET uw_"
- ^ x
- ^ " = NULL")
- ebs)), loc), loc),
+ (L'.EDml ((L'.EPrim (Prim.String
+ (foldl (fn ((x, _), s) =>
+ s ^ ", uw_" ^ x ^ " = NULL")
+ ("UPDATE uw_"
+ ^ tab
+ ^ " SET uw_"
+ ^ x
+ ^ " = NULL")
+ ebs)), loc), L'.Error), loc),
e), loc)
val e =
@@ -4083,8 +4091,8 @@ fun monoize env file =
[] => e
| eb :: ebs =>
(L'.ESeq (
- (L'.EDml (L'.EPrim (Prim.String ("DELETE FROM uw_"
- ^ tab)), loc), loc),
+ (L'.EDml ((L'.EPrim (Prim.String ("DELETE FROM uw_"
+ ^ tab)), loc), L'.Error), loc),
e), loc)
in
e
diff --git a/src/mysql.sml b/src/mysql.sml
index 12d52255..44d88c1d 100644
--- a/src/mysql.sml
+++ b/src/mysql.sml
@@ -1194,16 +1194,19 @@ fun queryPrepared {loc, id, query, inputs, cols, doCols, nested} =
else
box []]
-fun dmlCommon {loc, dml} =
- box [string "if (mysql_stmt_execute(stmt)) uw_error(ctx, FATAL, \"",
- string (ErrorMsg.spanToString loc),
- string ": Error executing DML: %s\\n%s\", ",
- dml,
- string ", mysql_error(conn->conn));",
+fun dmlCommon {loc, dml, mode} =
+ box [string "if (mysql_stmt_execute(stmt)) ",
+ case mode of
+ Settings.Error => box [string "uw_error(ctx, FATAL, \"",
+ string (ErrorMsg.spanToString loc),
+ string ": Error executing DML: %s\\n%s\", ",
+ dml,
+ string ", mysql_error(conn->conn));"]
+ | Settings.None => string "uw_errmsg = mysql_error(conn->conn);",
newline,
newline]
-fun dml loc =
+fun dml (loc, mode) =
box [string "uw_conn *conn = uw_get_db(ctx);",
newline,
string "MYSQL_STMT *stmt = mysql_stmt_init(conn->conn);",
@@ -1220,12 +1223,12 @@ fun dml loc =
newline,
newline,
- dmlCommon {loc = loc, dml = string "dml"},
+ dmlCommon {loc = loc, dml = string "dml", mode = mode},
string "uw_pop_cleanup(ctx);",
newline]
-fun dmlPrepared {loc, id, dml, inputs} =
+fun dmlPrepared {loc, id, dml, inputs, mode} =
box [string "uw_conn *conn = uw_get_db(ctx);",
newline,
string "MYSQL_BIND in[",
@@ -1471,7 +1474,7 @@ fun dmlPrepared {loc, id, dml, inputs} =
dmlCommon {loc = loc, dml = box [string "\"",
string (String.toCString dml),
- string "\""]}]
+ string "\""], mode = mode}]
fun nextval {loc, seqE, seqName} =
box [string "uw_conn *conn = uw_get_db(ctx);",
diff --git a/src/postgres.sml b/src/postgres.sml
index 12e928c5..bf1e8536 100644
--- a/src/postgres.sml
+++ b/src/postgres.sml
@@ -708,7 +708,7 @@ fun queryPrepared {loc, id, query, inputs, cols, doCols, nested = _} =
string (String.toCString query),
string "\""]}]
-fun dmlCommon {loc, dml} =
+fun dmlCommon {loc, dml, mode} =
box [string "if (res == NULL) uw_error(ctx, FATAL, \"Out of memory allocating DML result.\");",
newline,
newline,
@@ -723,13 +723,15 @@ fun dmlCommon {loc, dml} =
newline],
string "}",
newline,
- string "PQclear(res);",
- newline,
- string "uw_error(ctx, FATAL, \"",
- string (ErrorMsg.spanToString loc),
- string ": DML failed:\\n%s\\n%s\", ",
- dml,
- string ", PQerrorMessage(conn));",
+ case mode of
+ Settings.Error => box [string "PQclear(res);",
+ newline,
+ string "uw_error(ctx, FATAL, \"",
+ string (ErrorMsg.spanToString loc),
+ string ": DML failed:\\n%s\\n%s\", ",
+ dml,
+ string ", PQerrorMessage(conn));"]
+ | Settings.None => string "uw_errmsg = PQerrorMessage(conn);",
newline],
string "}",
newline,
@@ -738,15 +740,15 @@ fun dmlCommon {loc, dml} =
string "PQclear(res);",
newline]
-fun dml loc =
+fun dml (loc, mode) =
box [string "PGconn *conn = uw_get_db(ctx);",
newline,
string "PGresult *res = PQexecParams(conn, dml, 0, NULL, NULL, NULL, NULL, 0);",
newline,
newline,
- dmlCommon {loc = loc, dml = string "dml"}]
+ dmlCommon {loc = loc, dml = string "dml", mode = mode}]
-fun dmlPrepared {loc, id, dml, inputs} =
+fun dmlPrepared {loc, id, dml, inputs, mode} =
box [string "PGconn *conn = uw_get_db(ctx);",
newline,
string "const int paramFormats[] = { ",
@@ -787,7 +789,7 @@ fun dmlPrepared {loc, id, dml, inputs} =
newline,
dmlCommon {loc = loc, dml = box [string "\"",
string (String.toCString dml),
- string "\""]}]
+ string "\""], mode = mode}]
fun nextvalCommon {loc, query} =
box [string "if (res == NULL) uw_error(ctx, FATAL, \"Out of memory allocating nextval result.\");",
diff --git a/src/prepare.sml b/src/prepare.sml
index 2f49405b..81de2fa7 100644
--- a/src/prepare.sml
+++ b/src/prepare.sml
@@ -246,11 +246,11 @@ fun prepExp (e as (_, loc), st) =
initial = initial, prepared = SOME {id = id, query = s, nested = true}}, loc), st)
end
- | EDml {dml, ...} =>
+ | EDml {dml, mode, ...} =>
(case prepString (dml, st) of
NONE => (e, st)
| SOME (id, s, st) =>
- ((EDml {dml = dml, prepared = SOME {id = id, dml = s}}, loc), st))
+ ((EDml {dml = dml, prepared = SOME {id = id, dml = s}, mode = mode}, loc), st))
| ENextval {seq, ...} =>
if #supportsNextval (Settings.currentDbms ()) then
diff --git a/src/settings.sig b/src/settings.sig
index a5f0cfa7..51d06902 100644
--- a/src/settings.sig
+++ b/src/settings.sig
@@ -124,6 +124,8 @@ signature SETTINGS = sig
val isBlob : sql_type -> bool
val isNotNull : sql_type -> bool
+ datatype failure_mode = Error | None
+
type dbms = {
name : string,
(* Call it this on the command line *)
@@ -149,9 +151,9 @@ signature SETTINGS = sig
-> Print.PD.pp_desc,
nested : bool}
-> Print.PD.pp_desc,
- dml : ErrorMsg.span -> Print.PD.pp_desc,
+ dml : ErrorMsg.span * failure_mode -> Print.PD.pp_desc,
dmlPrepared : {loc : ErrorMsg.span, id : int, dml : string,
- inputs : sql_type list} -> Print.PD.pp_desc,
+ inputs : sql_type list, mode : failure_mode} -> Print.PD.pp_desc,
nextval : {loc : ErrorMsg.span, seqE : Print.PD.pp_desc, seqName : string option} -> Print.PD.pp_desc,
nextvalPrepared : {loc : ErrorMsg.span, id : int, query : string} -> Print.PD.pp_desc,
setval : {loc : ErrorMsg.span, seqE : Print.PD.pp_desc, count : Print.PD.pp_desc} -> Print.PD.pp_desc,
diff --git a/src/settings.sml b/src/settings.sml
index 93b022ab..af16f9ca 100644
--- a/src/settings.sml
+++ b/src/settings.sml
@@ -363,6 +363,8 @@ fun isBlob Blob = true
fun isNotNull (Nullable _) = false
| isNotNull _ = true
+datatype failure_mode = Error | None
+
type dbms = {
name : string,
header : string,
@@ -384,9 +386,9 @@ type dbms = {
-> Print.PD.pp_desc,
nested : bool}
-> Print.PD.pp_desc,
- dml : ErrorMsg.span -> Print.PD.pp_desc,
+ dml : ErrorMsg.span * failure_mode -> Print.PD.pp_desc,
dmlPrepared : {loc : ErrorMsg.span, id : int, dml : string,
- inputs : sql_type list} -> Print.PD.pp_desc,
+ inputs : sql_type list, mode : failure_mode} -> Print.PD.pp_desc,
nextval : {loc : ErrorMsg.span, seqName : string option, seqE : Print.PD.pp_desc} -> Print.PD.pp_desc,
nextvalPrepared : {loc : ErrorMsg.span, id : int, query : string} -> Print.PD.pp_desc,
setval : {loc : ErrorMsg.span, seqE : Print.PD.pp_desc, count : Print.PD.pp_desc} -> Print.PD.pp_desc,
diff --git a/src/sqlite.sml b/src/sqlite.sml
index 74093f21..20afd5bc 100644
--- a/src/sqlite.sml
+++ b/src/sqlite.sml
@@ -688,7 +688,7 @@ fun queryPrepared {loc, id, query, inputs, cols, doCols, nested} =
box [string "uw_pop_cleanup(ctx);",
newline]]
-fun dmlCommon {loc, dml} =
+fun dmlCommon {loc, dml, mode} =
box [string "int r;",
newline,
@@ -701,14 +701,17 @@ fun dmlCommon {loc, dml} =
newline,
newline,
- string "if (r != SQLITE_DONE) uw_error(ctx, FATAL, \"",
- string (ErrorMsg.spanToString loc),
- string ": DML step failed: %s
%s\", ",
- dml,
- string ", sqlite3_errmsg(conn->conn));",
+ string "if (r != SQLITE_DONE) ",
+ case mode of
+ Settings.Error => box [string "uw_error(ctx, FATAL, \"",
+ string (ErrorMsg.spanToString loc),
+ string ": DML step failed: %s
%s\", ",
+ dml,
+ string ", sqlite3_errmsg(conn->conn));"]
+ | Settings.None => string "uw_errmsg = sqlite3_errmsg(conn->conn);",
newline]
-fun dml loc =
+fun dml (loc, mode) =
box [string "uw_conn *conn = uw_get_db(ctx);",
newline,
string "sqlite3_stmt *stmt;",
@@ -721,12 +724,12 @@ fun dml loc =
newline,
newline,
- dmlCommon {loc = loc, dml = string "dml"},
+ dmlCommon {loc = loc, dml = string "dml", mode = mode},
string "uw_pop_cleanup(ctx);",
newline]
-fun dmlPrepared {loc, id, dml, inputs} =
+fun dmlPrepared {loc, id, dml, inputs, mode = mode} =
box [string "uw_conn *conn = uw_get_db(ctx);",
newline,
p_pre_inputs inputs,
@@ -761,7 +764,7 @@ fun dmlPrepared {loc, id, dml, inputs} =
dmlCommon {loc = loc, dml = box [string "\"",
string (String.toCString dml),
- string "\""]},
+ string "\""], mode = mode},
string "uw_pop_cleanup(ctx);",
newline,
diff --git a/tests/tryDml.ur b/tests/tryDml.ur
new file mode 100644
index 00000000..bfe98cdb
--- /dev/null
+++ b/tests/tryDml.ur
@@ -0,0 +1,13 @@
+table t : {Id : int}
+ PRIMARY KEY Id
+
+fun doStuff () =
+ dml (INSERT INTO t (Id) VALUES (0));
+ o1 <- tryDml (INSERT INTO t (Id) VALUES (0));
+ dml (INSERT INTO t (Id) VALUES (1));
+ o2 <- tryDml (INSERT INTO t (Id) VALUES (1));
+ return {[o1]}; {[o2]}
+
+fun main () = return
+
+
diff --git a/tests/tryDml.urp b/tests/tryDml.urp
new file mode 100644
index 00000000..cf42105b
--- /dev/null
+++ b/tests/tryDml.urp
@@ -0,0 +1,4 @@
+database dbname=trydml
+sql trydml.sql
+
+tryDml
diff --git a/tests/tryDml.urs b/tests/tryDml.urs
new file mode 100644
index 00000000..6ac44e0b
--- /dev/null
+++ b/tests/tryDml.urs
@@ -0,0 +1 @@
+val main : unit -> transaction page
--
cgit v1.2.3
From 5545969f485ef2fb944db8e7b0237acbabeb8d4c Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Tue, 7 Sep 2010 08:28:07 -0400
Subject: Server-side 'onError'
---
include/types.h | 4 ++
include/urweb.h | 1 +
src/c/request.c | 101 ++++++++++++++++++++++++++++++++-------------------
src/c/urweb.c | 18 ++++++++-
src/cjr.sml | 1 +
src/cjr_env.sml | 1 +
src/cjr_print.sml | 26 +++++++++++--
src/cjrize.sml | 1 +
src/compiler.sig | 3 +-
src/compiler.sml | 23 ++++++++++--
src/core.sml | 1 +
src/core_env.sml | 1 +
src/core_print.sml | 1 +
src/core_util.sml | 6 ++-
src/corify.sml | 14 ++++++-
src/css.sml | 1 +
src/demo.sml | 3 +-
src/elab.sml | 1 +
src/elab_env.sml | 1 +
src/elab_print.sml | 1 +
src/elab_util.sml | 5 ++-
src/elaborate.sml | 27 ++++++++++++++
src/expl.sml | 1 +
src/expl_env.sml | 1 +
src/expl_print.sml | 1 +
src/explify.sml | 3 +-
src/mono.sml | 1 +
src/mono_env.sml | 1 +
src/mono_print.sml | 2 +-
src/mono_shake.sml | 7 +++-
src/mono_util.sml | 5 ++-
src/monoize.sml | 3 ++
src/prepare.sml | 1 +
src/reduce.sml | 1 +
src/reduce_local.sml | 1 +
src/settings.sig | 2 +
src/settings.sml | 4 ++
src/shake.sml | 11 +++++-
src/source.sml | 1 +
src/source_print.sml | 1 +
src/unnest.sml | 1 +
tests/onerror.ur | 4 ++
tests/onerror.urp | 4 ++
tests/onerror.urs | 1 +
tests/onerrorE.ur | 5 +++
45 files changed, 244 insertions(+), 59 deletions(-)
create mode 100644 tests/onerror.ur
create mode 100644 tests/onerror.urp
create mode 100644 tests/onerror.urs
create mode 100644 tests/onerrorE.ur
(limited to 'src/mono.sml')
diff --git a/include/types.h b/include/types.h
index 138760e5..ac70c34f 100644
--- a/include/types.h
+++ b/include/types.h
@@ -73,6 +73,10 @@ typedef struct {
uw_Basis_string (*cookie_sig)(uw_context);
int (*check_url)(const char *);
int (*check_mime)(const char *);
+
+ void (*on_error)(uw_context, char *);
} uw_app;
+#define ERROR_BUF_LEN 1024
+
#endif
diff --git a/include/urweb.h b/include/urweb.h
index 32e9b4e1..f254da2a 100644
--- a/include/urweb.h
+++ b/include/urweb.h
@@ -36,6 +36,7 @@ failure_kind uw_begin_init(uw_context);
void uw_set_on_success(char *);
void uw_set_headers(uw_context, char *(*get_header)(void *, const char *), void *get_header_data);
failure_kind uw_begin(uw_context, char *path);
+failure_kind uw_begin_onError(uw_context, char *msg);
void uw_login(uw_context);
void uw_commit(uw_context);
int uw_rollback(uw_context);
diff --git a/src/c/request.c b/src/c/request.c
index 5e57d7b0..f72a3199 100644
--- a/src/c/request.c
+++ b/src/c/request.c
@@ -131,6 +131,8 @@ request_result uw_request(uw_request_context rc, uw_context ctx,
char *inputs;
const char *prefix = uw_get_url_prefix(ctx);
char *s;
+ int had_error = 0;
+ char errmsg[ERROR_BUF_LEN];
for (s = path; *s; ++s) {
if (s[0] == '%' && s[1] == '2' && s[2] == '7') {
@@ -336,32 +338,42 @@ request_result uw_request(uw_request_context rc, uw_context ctx,
log_debug(logger_data, "Serving URI %s....\n", path);
while (1) {
- size_t path_len = strlen(path);
+ if (!had_error) {
+ size_t path_len = strlen(path);
- on_success(ctx);
+ on_success(ctx);
+
+ if (path_len + 1 > rc->path_copy_size) {
+ rc->path_copy_size = path_len + 1;
+ rc->path_copy = realloc(rc->path_copy, rc->path_copy_size);
+ }
+ strcpy(rc->path_copy, path);
+ fk = uw_begin(ctx, rc->path_copy);
+ } else
+ fk = uw_begin_onError(ctx, errmsg);
- if (path_len + 1 > rc->path_copy_size) {
- rc->path_copy_size = path_len + 1;
- rc->path_copy = realloc(rc->path_copy, rc->path_copy_size);
- }
- strcpy(rc->path_copy, path);
- fk = uw_begin(ctx, rc->path_copy);
if (fk == SUCCESS || fk == RETURN_INDIRECTLY) {
uw_commit(ctx);
- if (uw_has_error(ctx)) {
+ if (uw_has_error(ctx) && !had_error) {
log_error(logger_data, "Fatal error: %s\n", uw_error_message(ctx));
uw_reset_keep_error_message(ctx);
on_failure(ctx);
- uw_write_header(ctx, "Content-type: text/html\r\n");
- uw_write(ctx, "Fatal Error");
- uw_write(ctx, "Fatal error: ");
- uw_write(ctx, uw_error_message(ctx));
- uw_write(ctx, "\n");
+
+ if (uw_get_app(ctx)->on_error) {
+ had_error = 1;
+ strcpy(errmsg, uw_error_message(ctx));
+ } else {
+ uw_write_header(ctx, "Content-type: text/html\r\n");
+ uw_write(ctx, "Fatal Error");
+ uw_write(ctx, "Fatal error: ");
+ uw_write(ctx, uw_error_message(ctx));
+ uw_write(ctx, "\n");
- return FAILED;
+ return FAILED;
+ }
} else
- return SERVED;
+ return had_error ? FAILED : SERVED;
} else if (fk == BOUNDED_RETRY) {
if (retries_left) {
log_debug(logger_data, "Error triggers bounded retry: %s\n", uw_error_message(ctx));
@@ -372,14 +384,19 @@ request_result uw_request(uw_request_context rc, uw_context ctx,
try_rollback(ctx, logger_data, log_error);
- uw_reset_keep_error_message(ctx);
- on_failure(ctx);
- uw_write_header(ctx, "Content-type: text/plain\r\n");
- uw_write(ctx, "Fatal error (out of retries): ");
- uw_write(ctx, uw_error_message(ctx));
- uw_write(ctx, "\n");
-
- return FAILED;
+ if (!had_error && uw_get_app(ctx)->on_error) {
+ had_error = 1;
+ strcpy(errmsg, uw_error_message(ctx));
+ } else {
+ uw_reset_keep_error_message(ctx);
+ on_failure(ctx);
+ uw_write_header(ctx, "Content-type: text/plain\r\n");
+ uw_write(ctx, "Fatal error (out of retries): ");
+ uw_write(ctx, uw_error_message(ctx));
+ uw_write(ctx, "\n");
+
+ return FAILED;
+ }
}
} else if (fk == UNLIMITED_RETRY)
log_debug(logger_data, "Error triggers unlimited retry: %s\n", uw_error_message(ctx));
@@ -388,26 +405,36 @@ request_result uw_request(uw_request_context rc, uw_context ctx,
try_rollback(ctx, logger_data, log_error);
- uw_reset_keep_error_message(ctx);
- on_failure(ctx);
- uw_write_header(ctx, "Content-type: text/html\r\n");
- uw_write(ctx, "Fatal Error");
- uw_write(ctx, "Fatal error: ");
- uw_write(ctx, uw_error_message(ctx));
- uw_write(ctx, "\n");
+ if (uw_get_app(ctx)->on_error && !had_error) {
+ had_error = 1;
+ strcpy(errmsg, uw_error_message(ctx));
+ } else {
+ uw_reset_keep_error_message(ctx);
+ on_failure(ctx);
+ uw_write_header(ctx, "Content-type: text/html\r\n");
+ uw_write(ctx, "Fatal Error");
+ uw_write(ctx, "Fatal error: ");
+ uw_write(ctx, uw_error_message(ctx));
+ uw_write(ctx, "\n");
- return FAILED;
+ return FAILED;
+ }
} else {
log_error(logger_data, "Unknown uw_handle return code!\n");
try_rollback(ctx, logger_data, log_error);
- uw_reset_keep_request(ctx);
- on_failure(ctx);
- uw_write_header(ctx, "Content-type: text/plain\r\n");
- uw_write(ctx, "Unknown uw_handle return code!\n");
+ if (uw_get_app(ctx)->on_error && !had_error) {
+ had_error = 1;
+ strcpy(errmsg, "Unknown uw_handle return code");
+ } else {
+ uw_reset_keep_request(ctx);
+ on_failure(ctx);
+ uw_write_header(ctx, "Content-type: text/plain\r\n");
+ uw_write(ctx, "Unknown uw_handle return code!\n");
- return FAILED;
+ return FAILED;
+ }
}
if (try_rollback(ctx, logger_data, log_error))
diff --git a/src/c/urweb.c b/src/c/urweb.c
index 74e1b12e..cac518ec 100644
--- a/src/c/urweb.c
+++ b/src/c/urweb.c
@@ -353,8 +353,6 @@ int uw_time = 0;
// Single-request state
-#define ERROR_BUF_LEN 1024
-
typedef struct regions {
struct regions *next;
} regions;
@@ -714,6 +712,22 @@ failure_kind uw_begin(uw_context ctx, char *path) {
return r;
}
+failure_kind uw_begin_onError(uw_context ctx, char *msg) {
+ int r = setjmp(ctx->jmp_buf);
+
+ if (ctx->app->on_error) {
+ if (r == 0) {
+ if (ctx->app->db_begin(ctx))
+ uw_error(ctx, BOUNDED_RETRY, "Error running SQL BEGIN");
+
+ ctx->app->on_error(ctx, msg);
+ }
+
+ return r;
+ } else
+ uw_error(ctx, FATAL, "Tried to run nonexistent onError handler");
+}
+
uw_Basis_client uw_Basis_self(uw_context ctx) {
if (ctx->client == NULL)
uw_error(ctx, FATAL, "Call to Basis.self() from page that has only server-side code");
diff --git a/src/cjr.sml b/src/cjr.sml
index f34662dc..5013033f 100644
--- a/src/cjr.sml
+++ b/src/cjr.sml
@@ -124,6 +124,7 @@ datatype decl' =
| DStyle of string
| DTask of task * exp
+ | DOnError of int
withtype decl = decl' located
diff --git a/src/cjr_env.sml b/src/cjr_env.sml
index ac83f263..21188b51 100644
--- a/src/cjr_env.sml
+++ b/src/cjr_env.sml
@@ -172,5 +172,6 @@ fun declBinds env (d, loc) =
| DCookie _ => env
| DStyle _ => env
| DTask _ => env
+ | DOnError _ => env
end
diff --git a/src/cjr_print.sml b/src/cjr_print.sml
index 7331196f..9b5edab5 100644
--- a/src/cjr_print.sml
+++ b/src/cjr_print.sml
@@ -113,9 +113,11 @@ and p_typ env = p_typ' false env
fun p_rel env n = string ("__uwr_" ^ ident (#1 (E.lookupERel env n)) ^ "_" ^ Int.toString (E.countERels env - n - 1))
handle CjrEnv.UnboundRel _ => string ("__uwr_UNBOUND_" ^ Int.toString (E.countERels env - n - 1))
-fun p_enamed env n =
- string ("__uwn_" ^ ident (#1 (E.lookupENamed env n)) ^ "_" ^ Int.toString n)
- handle CjrEnv.UnboundNamed _ => string ("__uwn_UNBOUND_" ^ Int.toString n)
+fun p_enamed' env n =
+ "__uwn_" ^ ident (#1 (E.lookupENamed env n)) ^ "_" ^ Int.toString n
+ handle CjrEnv.UnboundNamed _ => "__uwn_UNBOUND_" ^ Int.toString n
+
+fun p_enamed env n = string (p_enamed' env n)
fun p_con_named env n =
string ("__uwc_" ^ ident (#1 (E.lookupConstructor env n)) ^ "_" ^ Int.toString n)
@@ -2156,6 +2158,7 @@ fun p_decl env (dAll as (d, _) : decl) =
string "*/"]
| DTask _ => box []
+ | DOnError _ => box []
datatype 'a search =
Found of 'a
@@ -2791,6 +2794,8 @@ fun p_file env (ds, ps) =
val initializers = List.mapPartial (fn (DTask (Initialize, e), _) => SOME e | _ => NONE) ds
+ val onError = ListUtil.search (fn (DOnError n, _) => SOME n | _ => NONE) ds
+
val now = Time.now ()
val nowD = Date.fromTimeUniv now
val rfcFmt = "%a, %d %b %Y %H:%M:%S"
@@ -2957,6 +2962,18 @@ fun p_file env (ds, ps) =
string "static void uw_initializer(uw_context ctx) { };",
newline],
+ case onError of
+ NONE => box []
+ | SOME n => box [string "static void uw_onError(uw_context ctx, char *msg) {",
+ newline,
+ box [string "uw_write(ctx, ",
+ p_enamed env n,
+ string "(ctx, msg, uw_unit_v));",
+ newline],
+ string "}",
+ newline,
+ newline],
+
string "uw_app uw_application = {",
p_list_sep (box [string ",", newline]) string
[Int.toString (SM.foldl Int.max 0 fnums + 1),
@@ -2965,7 +2982,8 @@ fun p_file env (ds, ps) =
"uw_client_init", "uw_initializer", "uw_expunger",
"uw_db_init", "uw_db_begin", "uw_db_commit", "uw_db_rollback", "uw_db_close",
"uw_handle",
- "uw_input_num", "uw_cookie_sig", "uw_check_url", "uw_check_mime"],
+ "uw_input_num", "uw_cookie_sig", "uw_check_url", "uw_check_mime",
+ case onError of NONE => "NULL" | SOME _ => "uw_onError"],
string "};",
newline]
end
diff --git a/src/cjrize.sml b/src/cjrize.sml
index 22463cd4..2e7afa43 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -675,6 +675,7 @@ fun cifyDecl ((d, loc), sm) =
| _ => (ErrorMsg.errorAt loc "Initializer has not been fully determined";
(NONE, NONE, sm)))
| L.DPolicy _ => (NONE, NONE, sm)
+ | L.DOnError n => (SOME (L'.DOnError n, loc), NONE, sm)
fun cjrize ds =
let
diff --git a/src/compiler.sig b/src/compiler.sig
index c9b96a52..d0f6ac72 100644
--- a/src/compiler.sig
+++ b/src/compiler.sig
@@ -54,7 +54,8 @@ signature COMPILER = sig
protocol : string option,
dbms : string option,
sigFile : string option,
- safeGets : string list
+ safeGets : string list,
+ onError : (string * string list * string) option
}
val compile : string -> bool
val compiler : string -> unit
diff --git a/src/compiler.sml b/src/compiler.sml
index 6167f08a..c01024f0 100644
--- a/src/compiler.sml
+++ b/src/compiler.sml
@@ -58,7 +58,8 @@ type job = {
protocol : string option,
dbms : string option,
sigFile : string option,
- safeGets : string list
+ safeGets : string list,
+ onError : (string * string list * string) option
}
type ('src, 'dst) phase = {
@@ -396,6 +397,7 @@ fun parseUrp' accLibs fname =
val dbms = ref NONE
val sigFile = ref (Settings.getSigFile ())
val safeGets = ref []
+ val onError = ref NONE
fun finish sources =
let
@@ -425,7 +427,8 @@ fun parseUrp' accLibs fname =
protocol = !protocol,
dbms = !dbms,
sigFile = !sigFile,
- safeGets = rev (!safeGets)
+ safeGets = rev (!safeGets),
+ onError = !onError
}
fun mergeO f (old, new) =
@@ -469,7 +472,8 @@ fun parseUrp' accLibs fname =
protocol = mergeO #2 (#protocol old, #protocol new),
dbms = mergeO #2 (#dbms old, #dbms new),
sigFile = mergeO #2 (#sigFile old, #sigFile new),
- safeGets = #safeGets old @ #safeGets new
+ safeGets = #safeGets old @ #safeGets new,
+ onError = mergeO #2 (#onError old, #onError new)
}
in
if accLibs then
@@ -631,6 +635,12 @@ fun parseUrp' accLibs fname =
(case String.fields (fn ch => ch = #"=") arg of
[n, v] => pathmap := M.insert (!pathmap, n, v)
| _ => ErrorMsg.error "path argument not of the form name=value'")
+ | "onError" =>
+ (case String.fields (fn ch => ch = #".") arg of
+ m1 :: (fs as _ :: _) =>
+ onError := SOME (m1, List.take (fs, length fs - 1), List.last fs)
+ | _ => ErrorMsg.error "invalid 'onError' argument")
+
| _ => ErrorMsg.error ("Unrecognized command '" ^ cmd ^ "'");
read ()
end
@@ -657,6 +667,7 @@ fun parseUrp' accLibs fname =
Option.app Settings.setProtocol (#protocol job);
Option.app Settings.setDbms (#dbms job);
Settings.setSafeGets (#safeGets job);
+ Settings.setOnError (#onError job);
job
end
in
@@ -709,7 +720,7 @@ structure SS = BinarySetFn(struct
end)
val parse = {
- func = fn {database, sources = fnames, ffi, ...} : job =>
+ func = fn {database, sources = fnames, ffi, onError, ...} : job =>
let
val mrs = !moduleRoots
@@ -884,6 +895,10 @@ val parse = {
val ds = case database of
NONE => ds
| SOME s => (Source.DDatabase s, loc) :: ds
+
+ val ds = case onError of
+ NONE => ds
+ | SOME v => ds @ [(Source.DOnError v, loc)]
in
ds
end handle Empty => ds
diff --git a/src/core.sml b/src/core.sml
index e5358f48..6d9e56b6 100644
--- a/src/core.sml
+++ b/src/core.sml
@@ -136,6 +136,7 @@ datatype decl' =
| DStyle of string * int * string
| DTask of exp * exp
| DPolicy of exp
+ | DOnError of int
withtype decl = decl' located
diff --git a/src/core_env.sml b/src/core_env.sml
index 478ef495..9a4f9ec7 100644
--- a/src/core_env.sml
+++ b/src/core_env.sml
@@ -350,6 +350,7 @@ fun declBinds env (d, loc) =
end
| DTask _ => env
| DPolicy _ => env
+ | DOnError _ => env
fun patBinds env (p, loc) =
case p of
diff --git a/src/core_print.sml b/src/core_print.sml
index f18ea4b9..ca8066b3 100644
--- a/src/core_print.sml
+++ b/src/core_print.sml
@@ -628,6 +628,7 @@ fun p_decl env (dAll as (d, _) : decl) =
| DPolicy e1 => box [string "policy",
space,
p_exp env e1]
+ | DOnError _ => string "ONERROR"
fun p_file env file =
let
diff --git a/src/core_util.sml b/src/core_util.sml
index eedcd2bb..e71d7276 100644
--- a/src/core_util.sml
+++ b/src/core_util.sml
@@ -997,6 +997,8 @@ fun mapfoldB {kind = fk, con = fc, exp = fe, decl = fd, bind} =
fn e' =>
(DPolicy e', loc))
+ | DOnError _ => S.return2 dAll
+
and mfvi ctx (x, n, t, e, s) =
S.bind2 (mfc ctx t,
fn t' =>
@@ -1152,6 +1154,7 @@ fun mapfoldB (all as {bind, ...}) =
end
| DTask _ => ctx
| DPolicy _ => ctx
+ | DOnError _ => ctx
in
S.map2 (mff ctx' ds',
fn ds' =>
@@ -1216,7 +1219,8 @@ val maxName = foldl (fn ((d, _) : decl, count) =>
| DCookie (_, n, _, _) => Int.max (n, count)
| DStyle (_, n, _) => Int.max (n, count)
| DTask _ => count
- | DPolicy _ => count) 0
+ | DPolicy _ => count
+ | DOnError _ => count) 0
end
diff --git a/src/corify.sml b/src/corify.sml
index 88473455..27e6c4c7 100644
--- a/src/corify.sml
+++ b/src/corify.sml
@@ -1083,6 +1083,17 @@ fun corifyDecl mods (all as (d, loc : EM.span), st) =
| L.DPolicy e1 =>
([(L'.DPolicy (corifyExp st e1), loc)], st)
+ | L.DOnError (m, ms, x) =>
+ let
+ val st = St.lookupStrById st m
+ val st = foldl St.lookupStrByName st ms
+ in
+ case St.lookupValByName st x of
+ St.ENormal n => ([(L'.DOnError n, loc)], st)
+ | _ => (ErrorMsg.errorAt loc "Wrong type of identifier for 'onError'";
+ ([], st))
+ end
+
and corifyStr mods ((str, _), st) =
case str of
L.StrConst ds =>
@@ -1141,7 +1152,8 @@ fun maxName ds = foldl (fn ((d, _), n) =>
| L.DCookie (_, _, n', _) => Int.max (n, n')
| L.DStyle (_, _, n') => Int.max (n, n')
| L.DTask _ => n
- | L.DPolicy _ => n)
+ | L.DPolicy _ => n
+ | L.DOnError _ => n)
0 ds
and maxNameStr (str, _) =
diff --git a/src/css.sml b/src/css.sml
index 31c4b9b1..73f180d9 100644
--- a/src/css.sml
+++ b/src/css.sml
@@ -288,6 +288,7 @@ fun summarize file =
| DStyle (_, n, s) => (IM.insert (globals, n, (SOME s, [])), classes)
| DTask _ => st
| DPolicy _ => st
+ | DOnError _ => st
end
val (globals, classes) = foldl decl (IM.empty, IM.empty) file
diff --git a/src/demo.sml b/src/demo.sml
index a67411de..358815de 100644
--- a/src/demo.sml
+++ b/src/demo.sml
@@ -115,7 +115,8 @@ fun make' {prefix, dirname, guided} =
protocol = mergeWith #2 (#protocol combined, #protocol urp),
dbms = mergeWith #2 (#dbms combined, #dbms urp),
sigFile = mergeWith #2 (#sigFile combined, #sigFile urp),
- safeGets = []
+ safeGets = [],
+ onError = NONE
}
val parse = Compiler.run (Compiler.transform Compiler.parseUrp "Demo parseUrp")
diff --git a/src/elab.sml b/src/elab.sml
index e040a059..6d405af6 100644
--- a/src/elab.sml
+++ b/src/elab.sml
@@ -172,6 +172,7 @@ datatype decl' =
| DStyle of int * string * int
| DTask of exp * exp
| DPolicy of exp
+ | DOnError of int * string list * string
and str' =
StrConst of decl list
diff --git a/src/elab_env.sml b/src/elab_env.sml
index bb34c345..16596622 100644
--- a/src/elab_env.sml
+++ b/src/elab_env.sml
@@ -1633,5 +1633,6 @@ fun declBinds env (d, loc) =
end
| DTask _ => env
| DPolicy _ => env
+ | DOnError _ => env
end
diff --git a/src/elab_print.sml b/src/elab_print.sml
index 42a0a107..4fb7ee73 100644
--- a/src/elab_print.sml
+++ b/src/elab_print.sml
@@ -816,6 +816,7 @@ fun p_decl env (dAll as (d, _) : decl) =
| DPolicy e1 => box [string "policy",
space,
p_exp env e1]
+ | DOnError _ => string "ONERROR"
and p_str env (str, _) =
case str of
diff --git a/src/elab_util.sml b/src/elab_util.sml
index ec6c51ba..ccfb86a3 100644
--- a/src/elab_util.sml
+++ b/src/elab_util.sml
@@ -883,7 +883,8 @@ fun mapfoldB {kind = fk, con = fc, exp = fe, sgn_item = fsgi, sgn = fsg, str = f
| DStyle (tn, x, n) =>
bind (ctx, NamedE (x, (CModProj (n, [], "css_class"), loc)))
| DTask _ => ctx
- | DPolicy _ => ctx,
+ | DPolicy _ => ctx
+ | DOnError _ => ctx,
mfd ctx d)) ctx ds,
fn ds' => (StrConst ds', loc))
| StrVar _ => S.return2 strAll
@@ -1018,6 +1019,7 @@ fun mapfoldB {kind = fk, con = fc, exp = fe, sgn_item = fsgi, sgn = fsg, str = f
S.map2 (mfe ctx e1,
fn e1' =>
(DPolicy e1', loc))
+ | DOnError _ => S.return2 dAll
and mfvi ctx (x, n, c, e) =
S.bind2 (mfc ctx c,
@@ -1162,6 +1164,7 @@ and maxNameDecl (d, _) =
| DStyle (n1, _, n2) => Int.max (n1, n2)
| DTask _ => 0
| DPolicy _ => 0
+ | DOnError _ => 0
and maxNameStr (str, _) =
case str of
StrConst ds => maxName ds
diff --git a/src/elaborate.sml b/src/elaborate.sml
index 505699bd..e7848f21 100644
--- a/src/elaborate.sml
+++ b/src/elaborate.sml
@@ -2679,6 +2679,7 @@ and sgiOfDecl (d, loc) =
| L'.DStyle (tn, x, n) => [(L'.SgiVal (x, n, styleOf ()), loc)]
| L'.DTask _ => []
| L'.DPolicy _ => []
+ | L'.DOnError _ => []
and subSgn' counterparts env strLoc sgn1 (sgn2 as (_, loc2)) =
((*prefaces "subSgn" [("sgn1", p_sgn env sgn1),
@@ -3858,6 +3859,32 @@ and elabDecl (dAll as (d, loc), (env, denv, gs)) =
([(L'.DPolicy e1', loc)], (env, denv, gs1 @ gs))
end
+ | L.DOnError (m1, ms, s) =>
+ (case E.lookupStr env m1 of
+ NONE => (expError env (UnboundStrInExp (loc, m1));
+ ([], (env, denv, [])))
+ | SOME (n, sgn) =>
+ let
+ val (str, sgn) = foldl (fn (m, (str, sgn)) =>
+ case E.projectStr env {sgn = sgn, str = str, field = m} of
+ NONE => (conError env (UnboundStrInCon (loc, m));
+ (strerror, sgnerror))
+ | SOME sgn => ((L'.StrProj (str, m), loc), sgn))
+ ((L'.StrVar n, loc), sgn) ms
+
+ val t = case E.projectVal env {sgn = sgn, str = str, field = s} of
+ NONE => (expError env (UnboundExp (loc, s));
+ cerror)
+ | SOME t => t
+
+ val page = (L'.CModProj (!basis_r, [], "page"), loc)
+ val xpage = (L'.CApp ((L'.CModProj (!basis_r, [], "transaction"), loc), page), loc)
+ val func = (L'.TFun ((L'.CModProj (!basis_r, [], "xbody"), loc), xpage), loc)
+ in
+ unifyCons env loc t func;
+ ([(L'.DOnError (n, ms, s), loc)], (env, denv, gs))
+ end)
+
(*val tcs = List.filter (fn TypeClass _ => true | _ => false) (#3 (#2 r))*)
in
(*prefaces "/elabDecl" [("d", SourcePrint.p_decl dAll)];*)
diff --git a/src/expl.sml b/src/expl.sml
index 1212383f..119c1d92 100644
--- a/src/expl.sml
+++ b/src/expl.sml
@@ -149,6 +149,7 @@ datatype decl' =
| DStyle of int * string * int
| DTask of exp * exp
| DPolicy of exp
+ | DOnError of int * string list * string
and str' =
StrConst of decl list
diff --git a/src/expl_env.sml b/src/expl_env.sml
index 9abe7099..f5a5eb0a 100644
--- a/src/expl_env.sml
+++ b/src/expl_env.sml
@@ -345,6 +345,7 @@ fun declBinds env (d, loc) =
end
| DTask _ => env
| DPolicy _ => env
+ | DOnError _ => env
fun sgiBinds env (sgi, loc) =
case sgi of
diff --git a/src/expl_print.sml b/src/expl_print.sml
index 5a914194..d89b0512 100644
--- a/src/expl_print.sml
+++ b/src/expl_print.sml
@@ -730,6 +730,7 @@ fun p_decl env (dAll as (d, _) : decl) =
| DPolicy e1 => box [string "policy",
space,
p_exp env e1]
+ | DOnError _ => string "ONERROR"
and p_str env (str, _) =
case str of
diff --git a/src/explify.sml b/src/explify.sml
index 0013906f..4f4f83e1 100644
--- a/src/explify.sml
+++ b/src/explify.sml
@@ -1,4 +1,4 @@
-(* Copyright (c) 2008, Adam Chlipala
+(* Copyright (c) 2008-2010, Adam Chlipala
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -197,6 +197,7 @@ fun explifyDecl (d, loc : EM.span) =
| L.DStyle (nt, x, n) => SOME (L'.DStyle (nt, x, n), loc)
| L.DTask (e1, e2) => SOME (L'.DTask (explifyExp e1, explifyExp e2), loc)
| L.DPolicy e1 => SOME (L'.DPolicy (explifyExp e1), loc)
+ | L.DOnError v => SOME (L'.DOnError v, loc)
and explifyStr (str, loc) =
case str of
diff --git a/src/mono.sml b/src/mono.sml
index 554b1dc5..1d446dda 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -151,6 +151,7 @@ datatype decl' =
| DTask of exp * exp
| DPolicy of policy
+ | DOnError of int
withtype decl = decl' located
diff --git a/src/mono_env.sml b/src/mono_env.sml
index 87f96488..1df38db3 100644
--- a/src/mono_env.sml
+++ b/src/mono_env.sml
@@ -131,6 +131,7 @@ fun declBinds env (d, loc) =
| DStyle _ => env
| DTask _ => env
| DPolicy _ => env
+ | DOnError _ => env
fun patBinds env (p, loc) =
case p of
diff --git a/src/mono_print.sml b/src/mono_print.sml
index c3f2866e..63c98f44 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -527,7 +527,7 @@ fun p_decl env (dAll as (d, _) : decl) =
| DPolicy p => box [string "policy",
space,
p_policy env p]
-
+ | DOnError _ => string "ONERROR"
fun p_file env file =
let
diff --git a/src/mono_shake.sml b/src/mono_shake.sml
index 50c4b387..d8baf07e 100644
--- a/src/mono_shake.sml
+++ b/src/mono_shake.sml
@@ -70,6 +70,7 @@ fun shake file =
in
usedVars st e1
end
+ | ((DOnError n, _), (page_cs, page_es)) => (page_cs, IS.add (page_es, n))
| (_, st) => st) (IS.empty, IS.empty) file
val (cdef, edef) = foldl (fn ((DDatatype dts, _), (cdef, edef)) =>
@@ -87,7 +88,8 @@ fun shake file =
| ((DCookie _, _), acc) => acc
| ((DStyle _, _), acc) => acc
| ((DTask _, _), acc) => acc
- | ((DPolicy _, _), acc) => acc)
+ | ((DPolicy _, _), acc) => acc
+ | ((DOnError _, _), acc) => acc)
(IM.empty, IM.empty) file
fun typ (c, s) =
@@ -155,7 +157,8 @@ fun shake file =
| (DCookie _, _) => true
| (DStyle _, _) => true
| (DTask _, _) => true
- | (DPolicy _, _) => true) file
+ | (DPolicy _, _) => true
+ | (DOnError _, _) => true) file
end
end
diff --git a/src/mono_util.sml b/src/mono_util.sml
index 8a567e83..d75b8300 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -538,6 +538,7 @@ fun mapfoldB {typ = fc, exp = fe, decl = fd, bind} =
S.map2 (mfpol ctx pol,
fn p' =>
(DPolicy p', loc))
+ | DOnError _ => S.return2 dAll
and mfpol ctx pol =
case pol of
@@ -644,6 +645,7 @@ fun mapfoldB (all as {bind, ...}) =
| DStyle _ => ctx
| DTask _ => ctx
| DPolicy _ => ctx
+ | DOnError _ => ctx
in
S.map2 (mff ctx' ds',
fn ds' =>
@@ -698,7 +700,8 @@ val maxName = foldl (fn ((d, _) : decl, count) =>
| DCookie _ => count
| DStyle _ => count
| DTask _ => count
- | DPolicy _ => count) 0
+ | DPolicy _ => count
+ | DOnError _ => count) 0
end
diff --git a/src/monoize.sml b/src/monoize.sml
index 07e69834..bd5787b4 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -3962,6 +3962,9 @@ fun monoDecl (env, fm) (all as (d, loc)) =
in
SOME (env, fm, ps)
end
+ | L.DOnError n => SOME (env,
+ fm,
+ [(L'.DOnError n, loc)])
end
datatype expungable = Client | Channel
diff --git a/src/prepare.sml b/src/prepare.sml
index 81de2fa7..4d81940f 100644
--- a/src/prepare.sml
+++ b/src/prepare.sml
@@ -331,6 +331,7 @@ fun prepDecl (d as (_, loc), st) =
in
((DTask (tk, e), loc), st)
end
+ | DOnError _ => (d, st)
fun prepare (ds, ps) =
let
diff --git a/src/reduce.sml b/src/reduce.sml
index 36c9f44e..7a962926 100644
--- a/src/reduce.sml
+++ b/src/reduce.sml
@@ -803,6 +803,7 @@ fun reduce file =
namedC,
namedE))
end
+ | DOnError _ => (d, st)
val (file, _) = ListUtil.foldlMap doDecl (IS.empty, IM.empty, IM.empty) file
in
diff --git a/src/reduce_local.sml b/src/reduce_local.sml
index cfa6bfd8..0e87e34a 100644
--- a/src/reduce_local.sml
+++ b/src/reduce_local.sml
@@ -378,6 +378,7 @@ fun reduce file =
| DStyle _ => d
| DTask (e1, e2) => (DTask (exp [] e1, exp [] e2), loc)
| DPolicy e1 => (DPolicy (exp [] e1), loc)
+ | DOnError _ => d
in
map doDecl file
end
diff --git a/src/settings.sig b/src/settings.sig
index 51d06902..3ebf9300 100644
--- a/src/settings.sig
+++ b/src/settings.sig
@@ -206,4 +206,6 @@ signature SETTINGS = sig
val setSafeGets : string list -> unit
val isSafeGet : string -> bool
+ val setOnError : (string * string list * string) option -> unit
+ val getOnError : unit -> (string * string list * string) option
end
diff --git a/src/settings.sml b/src/settings.sml
index af16f9ca..5da1a24e 100644
--- a/src/settings.sml
+++ b/src/settings.sml
@@ -486,4 +486,8 @@ val safeGet = ref SS.empty
fun setSafeGets ls = safeGet := SS.addList (SS.empty, ls)
fun isSafeGet x = SS.member (!safeGet, x)
+val onError = ref (NONE : (string * string list * string) option)
+fun setOnError x = onError := x
+fun getOnError () = !onError
+
end
diff --git a/src/shake.sml b/src/shake.sml
index bc81def9..096c31fd 100644
--- a/src/shake.sml
+++ b/src/shake.sml
@@ -101,6 +101,11 @@ fun shake file =
st
else
usedVars st e1
+ | ((DOnError n, _), st as (usedE, usedC)) =>
+ if !sliceDb then
+ st
+ else
+ (IS.add (usedE, n), usedC)
| (_, acc) => acc) (IS.empty, IS.empty) file
val (cdef, edef) = foldl (fn ((DCon (_, n, _, c), _), (cdef, edef)) => (IM.insert (cdef, n, [c]), edef)
@@ -128,7 +133,8 @@ fun shake file =
| ((DStyle (_, n, _), _), (cdef, edef)) =>
(cdef, IM.insert (edef, n, ([], dummyt, dummye)))
| ((DTask _, _), acc) => acc
- | ((DPolicy _, _), acc) => acc)
+ | ((DPolicy _, _), acc) => acc
+ | ((DOnError _, _), acc) => acc)
(IM.empty, IM.empty) file
fun kind (_, s) = s
@@ -216,7 +222,8 @@ fun shake file =
| (DCookie _, _) => not (!sliceDb)
| (DStyle _, _) => not (!sliceDb)
| (DTask _, _) => not (!sliceDb)
- | (DPolicy _, _) => not (!sliceDb)) file
+ | (DPolicy _, _) => not (!sliceDb)
+ | (DOnError _, _) => not (!sliceDb)) file
end
end
diff --git a/src/source.sml b/src/source.sml
index 9768cfc0..b85384ab 100644
--- a/src/source.sml
+++ b/src/source.sml
@@ -169,6 +169,7 @@ datatype decl' =
| DStyle of string
| DTask of exp * exp
| DPolicy of exp
+ | DOnError of string * string list * string
and str' =
StrConst of decl list
diff --git a/src/source_print.sml b/src/source_print.sml
index 590d15d5..f6218d22 100644
--- a/src/source_print.sml
+++ b/src/source_print.sml
@@ -672,6 +672,7 @@ fun p_decl ((d, _) : decl) =
| DPolicy e1 => box [string "policy",
space,
p_exp e1]
+ | DOnError _ => string "ONERROR"
and p_str (str, _) =
case str of
diff --git a/src/unnest.sml b/src/unnest.sml
index a2ec32b0..2d6956cb 100644
--- a/src/unnest.sml
+++ b/src/unnest.sml
@@ -434,6 +434,7 @@ fun unnest file =
| DStyle _ => default ()
| DTask _ => explore ()
| DPolicy _ => explore ()
+ | DOnError _ => default ()
end
and doStr (all as (str, loc), st) =
diff --git a/tests/onerror.ur b/tests/onerror.ur
new file mode 100644
index 00000000..9877d8d7
--- /dev/null
+++ b/tests/onerror.ur
@@ -0,0 +1,4 @@
+fun main n =
+ case n of
+ 0 => error Zero is bad!
+ | _ => return
diff --git a/tests/onerror.urp b/tests/onerror.urp
new file mode 100644
index 00000000..39d7ac7d
--- /dev/null
+++ b/tests/onerror.urp
@@ -0,0 +1,4 @@
+onError OnerrorE.err
+
+onerrorE
+onerror
diff --git a/tests/onerror.urs b/tests/onerror.urs
new file mode 100644
index 00000000..38b757ea
--- /dev/null
+++ b/tests/onerror.urs
@@ -0,0 +1 @@
+val main : int -> transaction page
diff --git a/tests/onerrorE.ur b/tests/onerrorE.ur
new file mode 100644
index 00000000..b2948c71
--- /dev/null
+++ b/tests/onerrorE.ur
@@ -0,0 +1,5 @@
+fun err x = return
+ Bad thing!
+
+ {x}
+
--
cgit v1.2.3
From 38d3bc508b3b882e81599bdb0e1d4a2572c23dd0 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Thu, 23 Dec 2010 17:46:40 -0500
Subject: [De]serialization of times in JavaScript; proper integer division in
JavaScript; Basis.crypt; Top.mkRead'; more aggressive Mono-level inlining,
for values of function-y types
---
include/urweb.h | 3 +++
lib/js/urweb.js | 2 ++
lib/ur/basis.urs | 5 +++++
lib/ur/top.ur | 7 ++++++-
lib/ur/top.urs | 2 ++
src/c/urweb.c | 34 ++++++++++++++++++++++++++++++++++
src/cjr_print.sml | 4 +++-
src/cjrize.sml | 2 +-
src/iflow.sml | 4 ++--
src/jscomp.sml | 11 ++++++-----
src/mono.sml | 4 +++-
src/mono_opt.sml | 2 +-
src/mono_print.sml | 10 +++++-----
src/mono_reduce.sml | 18 ++++++++++++++----
src/mono_util.sml | 4 ++--
src/monoize.sml | 30 +++++++++++++++---------------
src/settings.sml | 1 +
src/urweb.grm | 4 +++-
18 files changed, 108 insertions(+), 39 deletions(-)
(limited to 'src/mono.sml')
diff --git a/include/urweb.h b/include/urweb.h
index 548e77fe..c52e1c26 100644
--- a/include/urweb.h
+++ b/include/urweb.h
@@ -169,6 +169,7 @@ char *uw_Basis_ensqlBool(uw_Basis_bool);
char *uw_Basis_jsifyString(uw_context, uw_Basis_string);
char *uw_Basis_jsifyChar(uw_context, uw_Basis_char);
char *uw_Basis_jsifyChannel(uw_context, uw_Basis_channel);
+char *uw_Basis_jsifyTime(uw_context, uw_Basis_time);
uw_Basis_string uw_Basis_intToString(uw_context, uw_Basis_int);
uw_Basis_string uw_Basis_floatToString(uw_context, uw_Basis_float);
@@ -301,4 +302,6 @@ uw_Basis_string uw_Basis_timef(uw_context, const char *fmt, uw_Basis_time);
uw_Basis_time uw_Basis_stringToTimef(uw_context, const char *fmt, uw_Basis_string);
uw_Basis_time uw_Basis_stringToTimef_error(uw_context, const char *fmt, uw_Basis_string);
+uw_Basis_string uw_Basis_crypt(uw_context, uw_Basis_string key, uw_Basis_string salt);
+
#endif
diff --git a/lib/js/urweb.js b/lib/js/urweb.js
index f98476b7..bba58453 100644
--- a/lib/js/urweb.js
+++ b/lib/js/urweb.js
@@ -19,7 +19,9 @@ function plus(x, y) { return x + y; }
function minus(x, y) { return x - y; }
function times(x, y) { return x * y; }
function div(x, y) { return x / y; }
+function divInt(x, y) { var n = x / y; return n < 0 ? Math.ceil(n) : Math.floor(n); }
function mod(x, y) { return x % y; }
+function modInt(x, y) { var n = x % y; return n < 0 ? Math.ceil(n) : Math.floor(n); }
function lt(x, y) { return x < y; }
function le(x, y) { return x <= y; }
diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs
index 8cf516f8..95deb982 100644
--- a/lib/ur/basis.urs
+++ b/lib/ur/basis.urs
@@ -146,6 +146,11 @@ val minusSeconds : time -> int -> time
val timef : string -> time -> string (* Uses strftime() format string *)
+(** * Encryption *)
+
+val crypt : string -> string -> string
+
+
(** HTTP operations *)
con http_cookie :: Type -> Type
diff --git a/lib/ur/top.ur b/lib/ur/top.ur
index 32d06a43..19259e92 100644
--- a/lib/ur/top.ur
+++ b/lib/ur/top.ur
@@ -89,7 +89,7 @@ fun read_option [t ::: Type] (_ : read t) =
None => None
| v => Some v)
-fun txt [t] [ctx ::: {Unit}] [use ::: {Type}] (_ : show t) (v : t) =
+fun txt [t] [ctx ::: {Unit}] [use ::: {Type}] (_ : show t) (v : t) : xml ctx use [] =
cdata (show v)
fun map0 [K] [tf :: K -> Type] (f : t :: K -> tf t) [r ::: {K}] (fl : folder r) =
@@ -343,3 +343,8 @@ fun eqNullable' [tables ::: {{Type}}] [agg ::: {{Type}}] [exps ::: {Type}]
case e2 of
None => (SQL {e1} IS NULL)
| Some _ => sql_binary sql_eq e1 (sql_inject e2)
+
+fun mkRead' [t ::: Type] (f : string -> option t) (name : string) : read t =
+ mkRead (fn s => case f s of
+ None => error Invalid {txt name}: {txt s}
+ | Some v => v) f
diff --git a/lib/ur/top.urs b/lib/ur/top.urs
index a18bf437..74b04ed1 100644
--- a/lib/ur/top.urs
+++ b/lib/ur/top.urs
@@ -231,3 +231,5 @@ val eqNullable' : tables ::: {{Type}} -> agg ::: {{Type}} -> exps ::: {Type}
-> sql_exp tables agg exps (option t)
-> option t
-> sql_exp tables agg exps bool
+
+val mkRead' : t ::: Type -> (string -> option t) -> string -> read t
diff --git a/src/c/urweb.c b/src/c/urweb.c
index a09978cd..efe50591 100644
--- a/src/c/urweb.c
+++ b/src/c/urweb.c
@@ -13,6 +13,7 @@
#include
#include
#include
+#include
#include
@@ -2006,6 +2007,27 @@ uw_unit uw_Basis_htmlifyFloat_w(uw_context ctx, uw_Basis_float n) {
return uw_unit_v;
}
+char *uw_Basis_jsifyTime(uw_context ctx, uw_Basis_time n) {
+ int len;
+ char *r;
+
+ uw_check_heap(ctx, INTS_MAX);
+ r = ctx->heap.front;
+ sprintf(r, "%lld%n", (uw_Basis_int)n, &len);
+ ctx->heap.front += len+1;
+ return r;
+}
+
+uw_unit uw_Basis_jsifyInt_w(uw_context ctx, uw_Basis_time n) {
+ int len;
+
+ uw_check(ctx, INTS_MAX);
+ sprintf(ctx->page.front, "%lld%n", (uw_Basis_int)n, &len);
+ ctx->page.front += len;
+
+ return uw_unit_v;
+}
+
char *uw_Basis_htmlifyString(uw_context ctx, uw_Basis_string s) {
char *r, *s2;
@@ -3568,3 +3590,15 @@ failure_kind uw_runCallback(uw_context ctx, void (*callback)(uw_context)) {
return r;
}
+
+uw_Basis_string uw_Basis_crypt(uw_context ctx, uw_Basis_string key, uw_Basis_string salt) {
+ struct crypt_data *data;
+
+ if ((data = uw_get_global(ctx, "crypt")) == NULL) {
+ data = malloc(sizeof(struct crypt_data));
+ data->initialized = 0;
+ uw_set_global(ctx, "crypt", data, free);
+ }
+
+ return uw_strdup(ctx, crypt_r(key, salt, data));
+}
diff --git a/src/cjr_print.sml b/src/cjr_print.sml
index b4f75eb5..53060ab2 100644
--- a/src/cjr_print.sml
+++ b/src/cjr_print.sml
@@ -635,7 +635,9 @@ fun unurlify fromClient env (t, loc) =
string (Int.toString (size x')),
string "] == 0 || request[",
string (Int.toString (size x')),
- string ("] == '/')) ? __uwc_" ^ ident x' ^ "_" ^ Int.toString n),
+ string "] == '/')) ? (request += ",
+ string (Int.toString (size x')),
+ string (", (*request == '/' ? ++request : NULL), __uwc_" ^ ident x' ^ "_" ^ Int.toString n ^ ")"),
space,
string ":",
space,
diff --git a/src/cjrize.sml b/src/cjrize.sml
index 9c297fad..2c13e494 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -300,7 +300,7 @@ fun cifyExp (eAll as (e, loc), sm) =
in
((L'.EUnop (s, e1), loc), sm)
end
- | L.EBinop (s, e1, e2) =>
+ | L.EBinop (_, s, e1, e2) =>
let
val (e1, sm) = cifyExp (e1, sm)
val (e2, sm) = cifyExp (e2, sm)
diff --git a/src/iflow.sml b/src/iflow.sml
index c0e92cb1..f6e03271 100644
--- a/src/iflow.sml
+++ b/src/iflow.sml
@@ -1965,7 +1965,7 @@ fun evalExp env (e as (_, loc)) k =
| EAbs _ => default ()
| EUnop (s, e1) => evalExp env e1 (fn e1 => k (Func (Other s, [e1])))
- | EBinop (s, e1, e2) => evalExp env e1 (fn e1 => evalExp env e2 (fn e2 => k (Func (Other s, [e1, e2]))))
+ | EBinop (_, s, e1, e2) => evalExp env e1 (fn e1 => evalExp env e2 (fn e2 => k (Func (Other s, [e1, e2]))))
| ERecord xets =>
let
fun doFields (xes, acc) =
@@ -2352,7 +2352,7 @@ fun check file =
end
| EAbs (x, t1, t2, e) => (EAbs (x, t1, t2, doExp (Unknown :: env) e), loc)
| EUnop (uo, e1) => (EUnop (uo, doExp env e1), loc)
- | EBinop (bo, e1, e2) => (EBinop (bo, doExp env e1, doExp env e2), loc)
+ | EBinop (bi, bo, e1, e2) => (EBinop (bi, bo, doExp env e1, doExp env e2), loc)
| ERecord xets => (ERecord (map (fn (x, e, t) => (x, doExp env e, t)) xets), loc)
| EField (e1, f) => (EField (doExp env e1, f), loc)
| ECase (e, pes, ts) =>
diff --git a/src/jscomp.sml b/src/jscomp.sml
index 992a2e30..3b859814 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -126,6 +126,7 @@ fun process file =
| TFfi ("Basis", "int") => ((EFfiApp ("Basis", "htmlifyInt", [e]), loc), st)
| TFfi ("Basis", "float") => ((EFfiApp ("Basis", "htmlifyFloat", [e]), loc), st)
| TFfi ("Basis", "channel") => ((EFfiApp ("Basis", "jsifyChannel", [e]), loc), st)
+ | TFfi ("Basis", "time") => ((EFfiApp ("Basis", "jsifyTime", [e]), loc), st)
| TFfi ("Basis", "bool") => ((ECase (e,
[((PCon (Enum, PConFfi {mod = "Basis",
@@ -701,7 +702,7 @@ fun process file =
str ",null)}"],
st)
end
- | EBinop (s, e1, e2) =>
+ | EBinop (bi, s, e1, e2) =>
let
val name = case s of
"==" => "eq"
@@ -709,8 +710,8 @@ fun process file =
| "+" => "plus"
| "-" => "minus"
| "*" => "times"
- | "/" => "div"
- | "%" => "mod"
+ | "/" => (case bi of Int => "divInt" | NotInt => "div")
+ | "%" => (case bi of Int => "modInt" | NotInt => "mod")
| "<" => "lt"
| "<=" => "le"
| "strcmp" => "strcmp"
@@ -1039,12 +1040,12 @@ fun process file =
in
((EUnop (s, e), loc), st)
end
- | EBinop (s, e1, e2) =>
+ | EBinop (bi, s, e1, e2) =>
let
val (e1, st) = exp outer (e1, st)
val (e2, st) = exp outer (e2, st)
in
- ((EBinop (s, e1, e2), loc), st)
+ ((EBinop (bi, s, e1, e2), loc), st)
end
| ERecord xets =>
diff --git a/src/mono.sml b/src/mono.sml
index 1d446dda..bf38c0bc 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -68,6 +68,8 @@ datatype export_kind = datatype Export.export_kind
datatype failure_mode = datatype Settings.failure_mode
+datatype binop_intness = Int | NotInt
+
datatype exp' =
EPrim of Prim.t
| ERel of int
@@ -81,7 +83,7 @@ datatype exp' =
| EAbs of string * typ * typ * exp
| EUnop of string * exp
- | EBinop of string * exp * exp
+ | EBinop of binop_intness * string * exp * exp
| ERecord of (string * exp * typ) list
| EField of exp * string
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index 34f43143..d05e38fd 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -536,7 +536,7 @@ fun exp e =
| EFfiApp ("Basis", "attrifyString_w", [(EFfiApp ("Basis", "str1", [e]), _)]) =>
EFfiApp ("Basis", "attrifyChar_w", [e])
- | EBinop ("+", (EPrim (Prim.Int n1), _), (EPrim (Prim.Int n2), _)) => EPrim (Prim.Int (Int64.+ (n1, n2)))
+ | EBinop (_, "+", (EPrim (Prim.Int n1), _), (EPrim (Prim.Int n2), _)) => EPrim (Prim.Int (Int64.+ (n1, n2)))
| _ => e
diff --git a/src/mono_print.sml b/src/mono_print.sml
index 63c98f44..2d296745 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -187,11 +187,11 @@ fun p_exp' par env (e, _) =
| EUnop (s, e) => parenIf true (box [string s,
space,
p_exp' true env e])
- | EBinop (s, e1, e2) => parenIf true (box [p_exp' true env e1,
- space,
- string s,
- space,
- p_exp' true env e2])
+ | EBinop (_, s, e1, e2) => parenIf true (box [p_exp' true env e1,
+ space,
+ string s,
+ space,
+ p_exp' true env e2])
| ERecord xes => box [string "{",
p_list (fn (x, e, _) =>
diff --git a/src/mono_reduce.sml b/src/mono_reduce.sml
index 59ec5a55..f8b209d5 100644
--- a/src/mono_reduce.sml
+++ b/src/mono_reduce.sml
@@ -92,7 +92,7 @@ fun impure (e, _) =
| EApp _ => true
| EUnop (_, e) => impure e
- | EBinop (_, e1, e2) => impure e1 orelse impure e2
+ | EBinop (_, _, e1, e2) => impure e1 orelse impure e2
| ERecord xes => List.exists (fn (_, e, _) => impure e) xes
| EField (e, _) => impure e
@@ -365,11 +365,21 @@ fun reduce file =
val size = U.Exp.fold {typ = fn (_, n) => n,
exp = fn (_, n) => n + 1} 0
- fun mayInline (n, e) =
+ val functionInside' = U.Typ.exists (fn c => case c of
+ TFun _ => true
+ | _ => false)
+
+ fun functionInside t =
+ case #1 t of
+ TFun (t1, t2) => functionInside' t1 orelse functionInside t2
+ | _ => functionInside' t
+
+ fun mayInline (n, e, t) =
case IM.find (uses, n) of
NONE => false
| SOME count => count <= 1
orelse size e <= Settings.getMonoInline ()
+ orelse functionInside t
fun summarize d (e, _) =
let
@@ -426,7 +436,7 @@ fun reduce file =
| EAbs _ => []
| EUnop (_, e) => summarize d e
- | EBinop (_, e1, e2) => summarize d e1 @ summarize d e2
+ | EBinop (_, _, e1, e2) => summarize d e1 @ summarize d e2
| ERecord xets => List.concat (map (summarize d o #2) xets)
| EField (e, _) => summarize d e
@@ -701,7 +711,7 @@ fun reduce file =
let
val eo = case eo of
NONE => NONE
- | SOME e => if mayInline (n, e) then
+ | SOME e => if mayInline (n, e, t) then
SOME e
else
NONE
diff --git a/src/mono_util.sml b/src/mono_util.sml
index 56472155..bb09f84d 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -200,12 +200,12 @@ fun mapfoldB {typ = fc, exp = fe, bind} =
S.map2 (mfe ctx e,
fn e' =>
(EUnop (s, e'), loc))
- | EBinop (s, e1, e2) =>
+ | EBinop (bi, s, e1, e2) =>
S.bind2 (mfe ctx e1,
fn e1' =>
S.map2 (mfe ctx e2,
fn e2' =>
- (EBinop (s, e1', e2'), loc)))
+ (EBinop (bi, s, e1', e2'), loc)))
| ERecord xes =>
S.map2 (ListUtil.mapfold (fn (x, e, t) =>
diff --git a/src/monoize.sml b/src/monoize.sml
index 0c0d9d2e..35c6fa83 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -895,42 +895,42 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L'.TFun ((L'.TFfi ("Basis", "int"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc),
(L'.EAbs ("y", (L'.TFfi ("Basis", "int"), loc),
(L'.TFfi ("Basis", "bool"), loc),
- (L'.EBinop ("==", (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc),
+ (L'.EBinop (L'.Int, "==", (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc),
fm)
| L.EFfi ("Basis", "eq_float") =>
((L'.EAbs ("x", (L'.TFfi ("Basis", "float"), loc),
(L'.TFun ((L'.TFfi ("Basis", "float"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc),
(L'.EAbs ("y", (L'.TFfi ("Basis", "float"), loc),
(L'.TFfi ("Basis", "bool"), loc),
- (L'.EBinop ("==", (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc),
+ (L'.EBinop (L'.NotInt, "==", (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc),
fm)
| L.EFfi ("Basis", "eq_bool") =>
((L'.EAbs ("x", (L'.TFfi ("Basis", "bool"), loc),
(L'.TFun ((L'.TFfi ("Basis", "bool"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc),
(L'.EAbs ("y", (L'.TFfi ("Basis", "bool"), loc),
(L'.TFfi ("Basis", "bool"), loc),
- (L'.EBinop ("==", (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc),
+ (L'.EBinop (L'.NotInt, "==", (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc),
fm)
| L.EFfi ("Basis", "eq_string") =>
((L'.EAbs ("x", (L'.TFfi ("Basis", "string"), loc),
(L'.TFun ((L'.TFfi ("Basis", "string"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc),
(L'.EAbs ("y", (L'.TFfi ("Basis", "string"), loc),
(L'.TFfi ("Basis", "bool"), loc),
- (L'.EBinop ("!strcmp", (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc),
+ (L'.EBinop (L'.NotInt, "!strcmp", (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc),
fm)
| L.EFfi ("Basis", "eq_char") =>
((L'.EAbs ("x", (L'.TFfi ("Basis", "char"), loc),
(L'.TFun ((L'.TFfi ("Basis", "char"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc),
(L'.EAbs ("y", (L'.TFfi ("Basis", "char"), loc),
(L'.TFfi ("Basis", "bool"), loc),
- (L'.EBinop ("==", (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc),
+ (L'.EBinop (L'.NotInt, "==", (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc),
fm)
| L.EFfi ("Basis", "eq_time") =>
((L'.EAbs ("x", (L'.TFfi ("Basis", "time"), loc),
(L'.TFun ((L'.TFfi ("Basis", "time"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc),
(L'.EAbs ("y", (L'.TFfi ("Basis", "time"), loc),
(L'.TFfi ("Basis", "bool"), loc),
- (L'.EBinop ("==", (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc),
+ (L'.EBinop (L'.NotInt, "==", (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc),
fm)
| L.ECApp ((L.EFfi ("Basis", "mkEq"), _), t) =>
@@ -999,7 +999,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L'.TFun ((L'.TFfi ("Basis", "int"), loc), (L'.TFfi ("Basis", "int"), loc)), loc),
(L'.EAbs ("y", (L'.TFfi ("Basis", "int"), loc),
(L'.TFfi ("Basis", "int"), loc),
- (L'.EBinop (s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
+ (L'.EBinop (L'.Int, s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
in
numEx ((L'.TFfi ("Basis", "int"), loc),
Prim.Int (Int64.fromInt 0),
@@ -1019,7 +1019,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L'.TFun ((L'.TFfi ("Basis", "float"), loc), (L'.TFfi ("Basis", "float"), loc)), loc),
(L'.EAbs ("y", (L'.TFfi ("Basis", "float"), loc),
(L'.TFfi ("Basis", "float"), loc),
- (L'.EBinop (s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
+ (L'.EBinop (L'.NotInt, s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
in
numEx ((L'.TFfi ("Basis", "float"), loc),
Prim.Float 0.0,
@@ -1086,7 +1086,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L'.TFun ((L'.TFfi ("Basis", "int"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc),
(L'.EAbs ("y", (L'.TFfi ("Basis", "int"), loc),
(L'.TFfi ("Basis", "bool"), loc),
- (L'.EBinop (s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
+ (L'.EBinop (L'.Int, s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
in
ordEx ((L'.TFfi ("Basis", "int"), loc),
intBin "<",
@@ -1099,7 +1099,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L'.TFun ((L'.TFfi ("Basis", "float"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc),
(L'.EAbs ("y", (L'.TFfi ("Basis", "float"), loc),
(L'.TFfi ("Basis", "bool"), loc),
- (L'.EBinop (s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
+ (L'.EBinop (L'.NotInt, s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
in
ordEx ((L'.TFfi ("Basis", "float"), loc),
floatBin "<",
@@ -1112,7 +1112,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L'.TFun ((L'.TFfi ("Basis", "bool"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc),
(L'.EAbs ("y", (L'.TFfi ("Basis", "bool"), loc),
(L'.TFfi ("Basis", "bool"), loc),
- (L'.EBinop (s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
+ (L'.EBinop (L'.NotInt, s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
in
ordEx ((L'.TFfi ("Basis", "bool"), loc),
boolBin "<",
@@ -1125,8 +1125,8 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L'.TFun ((L'.TFfi ("Basis", "string"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc),
(L'.EAbs ("y", (L'.TFfi ("Basis", "string"), loc),
(L'.TFfi ("Basis", "bool"), loc),
- (L'.EBinop (s,
- (L'.EBinop ("strcmp",
+ (L'.EBinop (L'.NotInt, s,
+ (L'.EBinop (L'.NotInt, "strcmp",
(L'.ERel 1, loc),
(L'.ERel 0, loc)), loc),
(L'.EPrim (Prim.Int (Int64.fromInt 0)), loc)), loc)), loc)), loc)
@@ -1142,7 +1142,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L'.TFun ((L'.TFfi ("Basis", "char"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc),
(L'.EAbs ("y", (L'.TFfi ("Basis", "char"), loc),
(L'.TFfi ("Basis", "bool"), loc),
- (L'.EBinop (s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
+ (L'.EBinop (L'.NotInt, s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
in
ordEx ((L'.TFfi ("Basis", "char"), loc),
charBin "<",
@@ -1155,7 +1155,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L'.TFun ((L'.TFfi ("Basis", "time"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc),
(L'.EAbs ("y", (L'.TFfi ("Basis", "time"), loc),
(L'.TFfi ("Basis", "bool"), loc),
- (L'.EBinop (s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
+ (L'.EBinop (L'.NotInt, s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
in
ordEx ((L'.TFfi ("Basis", "time"), loc),
boolBin "<",
diff --git a/src/settings.sml b/src/settings.sml
index 4c611336..97c39abf 100644
--- a/src/settings.sml
+++ b/src/settings.sml
@@ -171,6 +171,7 @@ val jsFuncsBase = basisM [("alert", "alert"),
("stringToInt_error", "pi"),
("urlifyInt", "ts"),
("urlifyFloat", "ts"),
+ ("urlifyTime", "ts"),
("urlifyString", "uf"),
("urlifyBool", "ub"),
("recv", "rv"),
diff --git a/src/urweb.grm b/src/urweb.grm
index 21c4a50c..5803f445 100644
--- a/src/urweb.grm
+++ b/src/urweb.grm
@@ -1232,7 +1232,9 @@ eterm : LPAREN eexp RPAREN (#1 eexp, s (LPARENleft, RPARENright))
val e = (EApp (e, texp), loc)
in
if length fields <> length sqlexps then
- ErrorMsg.errorAt loc "Length mismatch in INSERT field specification"
+ ErrorMsg.errorAt loc ("Length mismatch in INSERT field specification ("
+ ^ Int.toString (length fields)
+ ^ " vs. " ^ Int.toString (length sqlexps) ^ ")")
else
();
(EApp (e, (ERecord (ListPair.zip (fields, sqlexps)), loc)), loc)
--
cgit v1.2.3
From 09b5839acfe26561fa87c89168133fc93c1083cc Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sat, 7 Jan 2012 15:56:22 -0500
Subject: First part of changes to avoid depending on C function call argument
order of evaluation (omitting normal Ur function calls, so far)
---
include/urweb.h | 8 +--
src/checknest.sml | 4 +-
src/cjr.sml | 2 +-
src/cjr_print.sml | 140 ++++++++++++++++++++++++++++++++--------------
src/cjrize.sml | 13 ++++-
src/core.sml | 2 +-
src/core_print.sml | 2 +-
src/core_util.sml | 10 +++-
src/corify.sml | 4 +-
src/css.sml | 2 +-
src/especialize.sml | 7 ++-
src/iflow.sml | 18 +++---
src/jscomp.sml | 25 +++++----
src/mono.sml | 2 +-
src/mono_opt.sml | 154 +++++++++++++++++++++++++--------------------------
src/mono_print.sml | 2 +-
src/mono_reduce.sml | 16 +++---
src/mono_util.sml | 10 +++-
src/monoize.sml | 151 +++++++++++++++++++++++++++-----------------------
src/prepare.sml | 34 +++++++-----
src/reduce.sml | 2 +-
src/reduce_local.sml | 2 +-
src/scriptcheck.sml | 8 +--
src/tag.sml | 16 +++---
24 files changed, 369 insertions(+), 265 deletions(-)
(limited to 'src/mono.sml')
diff --git a/include/urweb.h b/include/urweb.h
index 53f59c5a..4230da1a 100644
--- a/include/urweb.h
+++ b/include/urweb.h
@@ -30,7 +30,7 @@ void uw_free(uw_context);
void uw_reset(uw_context);
void uw_reset_keep_request(uw_context);
void uw_reset_keep_error_message(uw_context);
-const char *uw_get_url_prefix(uw_context);
+char *uw_get_url_prefix(uw_context);
failure_kind uw_begin_init(uw_context);
void uw_set_on_success(char *);
@@ -75,9 +75,9 @@ uw_Basis_source uw_Basis_new_client_source(uw_context, uw_Basis_string);
uw_unit uw_Basis_set_client_source(uw_context, uw_Basis_source, uw_Basis_string);
void uw_set_script_header(uw_context, const char*);
-const char *uw_Basis_get_settings(uw_context, uw_unit);
-const char *uw_Basis_get_script(uw_context, uw_unit);
-const char *uw_get_real_script(uw_context);
+char *uw_Basis_get_settings(uw_context, uw_unit);
+char *uw_Basis_get_script(uw_context, uw_unit);
+char *uw_get_real_script(uw_context);
uw_Basis_string uw_Basis_maybe_onload(uw_context, uw_Basis_string);
uw_Basis_string uw_Basis_maybe_onunload(uw_context, uw_Basis_string);
diff --git a/src/checknest.sml b/src/checknest.sml
index 1147d3e6..05ad8e9a 100644
--- a/src/checknest.sml
+++ b/src/checknest.sml
@@ -44,7 +44,7 @@ fun expUses globals =
| ENone _ => IS.empty
| ESome (_, e) => eu e
| EFfi _ => IS.empty
- | EFfiApp (_, _, es) => foldl IS.union IS.empty (map eu es)
+ | EFfiApp (_, _, es) => foldl IS.union IS.empty (map (eu o #1) es)
| EApp (e, es) => foldl IS.union (eu e) (map eu es)
| EUnop (_, e) => eu e
@@ -106,7 +106,7 @@ fun annotateExp globals =
| ENone _ => e
| ESome (t, e) => (ESome (t, ae e), loc)
| EFfi _ => e
- | EFfiApp (m, f, es) => (EFfiApp (m, f, map ae es), loc)
+ | EFfiApp (m, f, es) => (EFfiApp (m, f, map (fn (e, t) => (ae e, t)) es), loc)
| EApp (e, es) => (EApp (ae e, map ae es), loc)
| EUnop (uo, e) => (EUnop (uo, ae e), loc)
diff --git a/src/cjr.sml b/src/cjr.sml
index 7ea665ce..c348d01a 100644
--- a/src/cjr.sml
+++ b/src/cjr.sml
@@ -66,7 +66,7 @@ datatype exp' =
| ENone of typ
| ESome of typ * exp
| EFfi of string * string
- | EFfiApp of string * string * exp list
+ | EFfiApp of string * string * (exp * typ) list
| EApp of exp * exp list
| EUnop of string * exp
diff --git a/src/cjr_print.sml b/src/cjr_print.sml
index 851fa02d..e69b87f1 100644
--- a/src/cjr_print.sml
+++ b/src/cjr_print.sml
@@ -490,23 +490,23 @@ fun p_sql_type t = string (Settings.p_sql_ctype t)
fun getPargs (e, _) =
case e of
EPrim (Prim.String _) => []
- | EFfiApp ("Basis", "strcat", [e1, e2]) => getPargs e1 @ getPargs e2
+ | EFfiApp ("Basis", "strcat", [(e1, _), (e2, _)]) => getPargs e1 @ getPargs e2
- | EFfiApp ("Basis", "sqlifyInt", [e]) => [(e, Int)]
- | EFfiApp ("Basis", "sqlifyFloat", [e]) => [(e, Float)]
- | EFfiApp ("Basis", "sqlifyString", [e]) => [(e, String)]
- | EFfiApp ("Basis", "sqlifyBool", [e]) => [(e, Bool)]
- | EFfiApp ("Basis", "sqlifyTime", [e]) => [(e, Time)]
- | EFfiApp ("Basis", "sqlifyBlob", [e]) => [(e, Blob)]
- | EFfiApp ("Basis", "sqlifyChannel", [e]) => [(e, Channel)]
- | EFfiApp ("Basis", "sqlifyClient", [e]) => [(e, Client)]
+ | EFfiApp ("Basis", "sqlifyInt", [(e, _)]) => [(e, Int)]
+ | EFfiApp ("Basis", "sqlifyFloat", [(e, _)]) => [(e, Float)]
+ | EFfiApp ("Basis", "sqlifyString", [(e, _)]) => [(e, String)]
+ | EFfiApp ("Basis", "sqlifyBool", [(e, _)]) => [(e, Bool)]
+ | EFfiApp ("Basis", "sqlifyTime", [(e, _)]) => [(e, Time)]
+ | EFfiApp ("Basis", "sqlifyBlob", [(e, _)]) => [(e, Blob)]
+ | EFfiApp ("Basis", "sqlifyChannel", [(e, _)]) => [(e, Channel)]
+ | EFfiApp ("Basis", "sqlifyClient", [(e, _)]) => [(e, Client)]
| ECase (e,
[((PNone _, _),
(EPrim (Prim.String "NULL"), _)),
((PSome (_, (PVar _, _)), _),
- (EFfiApp (m, x, [(ERel 0, _)]), _))],
- _) => map (fn (x, y) => (x, Nullable y)) (getPargs (EFfiApp (m, x, [e]), #2 e))
+ (EFfiApp (m, x, [((ERel 0, _), _)]), _))],
+ {disc = t, ...}) => map (fn (x, y) => (x, Nullable y)) (getPargs (EFfiApp (m, x, [(e, t)]), #2 e))
| ECase (e,
[((PCon (_, PConFfi {mod = "Basis", con = "True", ...}, _), _),
@@ -1442,7 +1442,63 @@ fun potentiallyFancy (e, _) =
val self = ref (NONE : int option)
-fun p_exp' par tail env (e, loc) =
+(* The crucial thing to do here is assign arguments to local variables, to enforce order of evaluation.
+ * Otherwise, we are at the mercy of C's undefined order of function argument evaluation. *)
+fun pFuncall env (m, x, es, extra) =
+ case es of
+ [] => box [string "uw_",
+ p_ident m,
+ string "_",
+ p_ident x,
+ string "(ctx",
+ case extra of
+ NONE => box []
+ | SOME extra => box [string ",",
+ space,
+ string extra],
+ string ")"]
+ | [(e, _)] => box [string "uw_",
+ p_ident m,
+ string "_",
+ p_ident x,
+ string "(ctx,",
+ space,
+ p_exp' false false env e,
+ case extra of
+ NONE => box []
+ | SOME extra => box [string ",",
+ space,
+ string extra],
+ string ")"]
+ | _ => box [string "({",
+ newline,
+ p_list_sepi (box []) (fn i => fn (e, t) =>
+ box [p_typ env t,
+ space,
+ string "arg",
+ string (Int.toString i),
+ space,
+ string "=",
+ space,
+ p_exp' false false env e,
+ string ";",
+ newline]) es,
+ string "uw_",
+ p_ident m,
+ string "_",
+ p_ident x,
+ string "(ctx, ",
+ p_list_sepi (box [string ",", space]) (fn i => fn _ => box [string "arg", string (Int.toString i)]) es,
+ case extra of
+ NONE => box []
+ | SOME extra => box [string ",",
+ space,
+ string extra],
+ string ");",
+ newline,
+ string "})"]
+
+and p_exp' par tail env (e, loc) =
case e of
EPrim p => Prim.p_t_GCC p
| ERel n => p_rel env n
@@ -1571,16 +1627,30 @@ fun p_exp' par tail env (e, loc) =
string "})"]
| EReturnBlob {blob, mimeType, t} =>
box [string "({",
+ newline,
+ string "uw_Basis_blob",
+ space,
+ string "blob",
+ space,
+ string "=",
+ space,
+ p_exp' false false env blob,
+ string ";",
+ newline,
+ string "uw_Basis_string",
+ space,
+ string "mimeType",
+ space,
+ string "=",
+ space,
+ p_exp' false false env mimeType,
+ string ";",
newline,
p_typ env t,
space,
string "tmp;",
newline,
- string "uw_return_blob(ctx, ",
- p_exp' false false env blob,
- string ", ",
- p_exp' false false env mimeType,
- string ");",
+ string "uw_return_blob(ctx, blob, mimeType);",
newline,
string "tmp;",
newline,
@@ -1604,37 +1674,23 @@ fun p_exp' par tail env (e, loc) =
| EApp ((EReturnBlob {blob, mimeType, t = (TFun (_, ran), _)}, loc), _) =>
p_exp' false false env (EReturnBlob {blob = blob, mimeType = mimeType, t = ran}, loc)
- | EFfiApp ("Basis", "strcat", [e1, e2]) =>
+ | EFfiApp ("Basis", "strcat", [(e1, _), (e2, _)]) =>
let
fun flatten e =
case #1 e of
- EFfiApp ("Basis", "strcat", [e1, e2]) => flatten e1 @ flatten e2
+ EFfiApp ("Basis", "strcat", [(e1, _), (e2, _)]) => flatten e1 @ flatten e2
| _ => [e]
+
+ val es = flatten e1 @ flatten e2
+ val t = (TFfi ("Basis", "string"), loc)
+ val es = map (fn e => (e, t)) es
in
- case flatten e1 @ flatten e2 of
- [e1, e2] => box [string "uw_Basis_strcat(ctx, ",
- p_exp' false false env e1,
- string ",",
- p_exp' false false env e2,
- string ")"]
- | es => box [string "uw_Basis_mstrcat(ctx, ",
- p_list (p_exp' false false env) es,
- string ", NULL)"]
+ case es of
+ [_, _] => pFuncall env ("Basis", "strcat", es, NONE)
+ | _ => pFuncall env ("Basis", "mstrcat", es, SOME "NULL")
end
- | EFfiApp (m, x, []) => box [string "uw_",
- p_ident m,
- string "_",
- p_ident x,
- string "(ctx)"]
-
- | EFfiApp (m, x, es) => box [string "uw_",
- p_ident m,
- string "_",
- p_ident x,
- string "(ctx, ",
- p_list (p_exp' false false env) es,
- string ")"]
+ | EFfiApp (m, x, es) => pFuncall env (m, x, es, NONE)
| EApp (f, args) =>
let
fun default () = parenIf par (box [p_exp' true false env f,
@@ -3036,7 +3092,7 @@ fun p_file env (ds, ps) =
case e of
ECon (_, _, SOME e) => expDb e
| ESome (_, e) => expDb e
- | EFfiApp (_, _, es) => List.exists expDb es
+ | EFfiApp (_, _, es) => List.exists (expDb o #1) es
| EApp (e, es) => expDb e orelse List.exists expDb es
| EUnop (_, e) => expDb e
| EBinop (_, e1, e2) => expDb e1 orelse expDb e2
diff --git a/src/cjrize.sml b/src/cjrize.sml
index 2b46c32d..a0ec2ece 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -277,7 +277,13 @@ fun cifyExp (eAll as (e, loc), sm) =
| L.EFfi mx => ((L'.EFfi mx, loc), sm)
| L.EFfiApp (m, x, es) =>
let
- val (es, sm) = ListUtil.foldlMap cifyExp sm es
+ val (es, sm) = ListUtil.foldlMap (fn ((e, t), sm) =>
+ let
+ val (t, sm) = cifyTyp (t, sm)
+ val (e, sm) = cifyExp (e, sm)
+ in
+ ((e, t), sm)
+ end) sm es
in
((L'.EFfiApp (m, x, es), loc), sm)
end
@@ -384,8 +390,9 @@ fun cifyExp (eAll as (e, loc), sm) =
let
val (e1, sm) = cifyExp (e1, sm)
val (e2, sm) = cifyExp (e2, sm)
+ val s = (L'.TFfi ("Basis", "string"), loc)
in
- ((L'.EFfiApp ("Basis", "strcat", [e1, e2]), loc), sm)
+ ((L'.EFfiApp ("Basis", "strcat", [(e1, s), (e2, s)]), loc), sm)
end
| L.EWrite e =>
@@ -673,7 +680,7 @@ fun cifyDecl ((d, loc), sm) =
val tk = case #1 e1 of
L.EFfi ("Basis", "initialize") => L'.Initialize
| L.EFfi ("Basis", "clientLeaves") => L'.ClientLeaves
- | L.EFfiApp ("Basis", "periodic", [(L.EPrim (Prim.Int n), _)]) => L'.Periodic n
+ | L.EFfiApp ("Basis", "periodic", [((L.EPrim (Prim.Int n), _), _)]) => L'.Periodic n
| _ => (ErrorMsg.errorAt loc "Task kind not fully determined";
L'.Initialize)
val (e, sm) = cifyExp (e, sm)
diff --git a/src/core.sml b/src/core.sml
index 6d9e56b6..4641d1ab 100644
--- a/src/core.sml
+++ b/src/core.sml
@@ -92,7 +92,7 @@ datatype exp' =
| ENamed of int
| ECon of datatype_kind * patCon * con list * exp option
| EFfi of string * string
- | EFfiApp of string * string * exp list
+ | EFfiApp of string * string * (exp * con) list
| EApp of exp * exp
| EAbs of string * con * con * exp
| ECApp of exp * con
diff --git a/src/core_print.sml b/src/core_print.sml
index 8e46db04..910ec10a 100644
--- a/src/core_print.sml
+++ b/src/core_print.sml
@@ -276,7 +276,7 @@ fun p_exp' par env (e, _) =
string ".",
string x,
string "(",
- p_list (p_exp env) es,
+ p_list (p_exp env o #1) es,
string "))"]
| EApp (e1, e2) => parenIf par (box [p_exp' true env e1,
space,
diff --git a/src/core_util.sml b/src/core_util.sml
index e71d7276..d41dfe33 100644
--- a/src/core_util.sml
+++ b/src/core_util.sml
@@ -468,7 +468,7 @@ fun compare ((e1, _), (e2, _)) =
| (EFfiApp (f1, x1, es1), EFfiApp (f2, x2, es2)) =>
join (String.compare (f1, f2),
fn () => join (String.compare (x1, x2),
- fn () => joinL compare (es1, es2)))
+ fn () => joinL (fn ((e1, _), (e2, _)) => compare (e1, e2))(es1, es2)))
| (EFfiApp _, _) => LESS
| (_, EFfiApp _) => GREATER
@@ -586,6 +586,12 @@ fun mapfoldB {kind = fk, con = fc, exp = fe, bind} =
fun mfe ctx e acc =
S.bindP (mfe' ctx e acc, fe ctx)
+ and mfet ctx (e, t) =
+ S.bind2 (mfe ctx e,
+ fn e' =>
+ S.map2 (mfc ctx t,
+ fn t' => (e', t')))
+
and mfe' ctx (eAll as (e, loc)) =
case e of
EPrim _ => S.return2 eAll
@@ -603,7 +609,7 @@ fun mapfoldB {kind = fk, con = fc, exp = fe, bind} =
(ECon (dk, n, cs', SOME e'), loc)))
| EFfi _ => S.return2 eAll
| EFfiApp (m, x, es) =>
- S.map2 (ListUtil.mapfold (mfe ctx) es,
+ S.map2 (ListUtil.mapfold (mfet ctx) es,
fn es' =>
(EFfiApp (m, x, es'), loc))
| EApp (e1, e2) =>
diff --git a/src/corify.sml b/src/corify.sml
index d9e5d30c..bc14d408 100644
--- a/src/corify.sml
+++ b/src/corify.sml
@@ -562,8 +562,8 @@ fun corifyExp st (e, loc) =
fun makeApp n =
let
- val (actuals, _) = foldr (fn (_, (actuals, n)) =>
- ((L'.ERel n, loc) :: actuals,
+ val (actuals, _) = foldr (fn (t, (actuals, n)) =>
+ (((L'.ERel n, loc), t) :: actuals,
n + 1)) ([], n) args
in
(L'.EFfiApp (m, x, actuals), loc)
diff --git a/src/css.sml b/src/css.sml
index 90c0b5dd..07160898 100644
--- a/src/css.sml
+++ b/src/css.sml
@@ -138,7 +138,7 @@ fun summarize file =
| ECon (_, _, _, NONE) => ([], classes)
| ECon (_, _, _, SOME e) => exp (e, classes)
| EFfi _ => ([], classes)
- | EFfiApp (_, _, es) => expList (es, classes)
+ | EFfiApp (_, _, es) => expList (map #1 es, classes)
| EApp (
(EApp (
diff --git a/src/especialize.sml b/src/especialize.sml
index 8720a7b1..74babe47 100644
--- a/src/especialize.sml
+++ b/src/especialize.sml
@@ -180,7 +180,12 @@ fun specialize' (funcs, specialized) file =
| EFfi _ => (e, st)
| EFfiApp (m, x, es) =>
let
- val (es, st) = ListUtil.foldlMap (fn (e, st) => exp (env, e, st)) st es
+ val (es, st) = ListUtil.foldlMap (fn ((e, t), st) =>
+ let
+ val (e, st) = exp (env, e, st)
+ in
+ ((e, t), st)
+ end) st es
in
((EFfiApp (m, x, es), loc), st)
end
diff --git a/src/iflow.sml b/src/iflow.sml
index f6e03271..c65271b3 100644
--- a/src/iflow.sml
+++ b/src/iflow.sml
@@ -1044,7 +1044,7 @@ fun known' chs =
fun sqlify chs =
case chs of
- Exp (EFfiApp ("Basis", f, [e]), _) :: chs =>
+ Exp (EFfiApp ("Basis", f, [(e, _)]), _) :: chs =>
if String.isPrefix "sqlify" f then
SOME (e, chs)
else
@@ -1859,7 +1859,7 @@ fun evalExp env (e as (_, loc)) k =
[] =>
(if s = "set_cookie" then
case es of
- [_, cname, _, _, _] =>
+ [_, (cname, _), _, _, _] =>
(case #1 cname of
EPrim (Prim.String cname) =>
St.havocCookie cname
@@ -1868,7 +1868,7 @@ fun evalExp env (e as (_, loc)) k =
else
();
k (Recd []))
- | e :: es =>
+ | (e, _) :: es =>
evalExp env e (fn e => (St.send (e, loc); doArgs es))
in
doArgs es
@@ -1880,7 +1880,7 @@ fun evalExp env (e as (_, loc)) k =
fun doArgs (es, acc) =
case es of
[] => k (Func (Other (m ^ "." ^ s), rev acc))
- | e :: es =>
+ | (e, _) :: es =>
evalExp env e (fn e => doArgs (es, e :: acc))
in
doArgs (es, [])
@@ -1904,7 +1904,7 @@ fun evalExp env (e as (_, loc)) k =
k e
end
| EFfiApp x => doFfi x
- | EApp ((EFfi (m, s), _), e) => doFfi (m, s, [e])
+ | EApp ((EFfi (m, s), _), e) => doFfi (m, s, [(e, (TRecord [], loc))])
| EApp (e1 as (EError _, _), _) => evalExp env e1 k
@@ -2051,7 +2051,7 @@ fun evalExp env (e as (_, loc)) k =
| Update (tab, _, _) =>
(cs, SS.add (ts, tab)))
| EFfiApp ("Basis", "set_cookie",
- [_, (EPrim (Prim.String cname), _),
+ [_, ((EPrim (Prim.String cname), _), _),
_, _, _]) =>
(SS.add (cs, cname), ts)
| _ => st}
@@ -2189,7 +2189,7 @@ fun evalExp env (e as (_, loc)) k =
| ENextval _ => default ()
| ESetval _ => default ()
- | EUnurlify ((EFfiApp ("Basis", "get_cookie", [(EPrim (Prim.String cname), _)]), _), _, _) =>
+ | EUnurlify ((EFfiApp ("Basis", "get_cookie", [((EPrim (Prim.String cname), _), _)]), _), _, _) =>
let
val e = Var (St.nextVar ())
val e' = Func (Other ("cookie/" ^ cname), [])
@@ -2301,10 +2301,10 @@ fun check file =
| EFfi _ => e
| EFfiApp (m, f, es) =>
(case (m, f, es) of
- ("Basis", "set_cookie", [_, (EPrim (Prim.String cname), _), _, _, _]) =>
+ ("Basis", "set_cookie", [_, ((EPrim (Prim.String cname), _), _), _, _, _]) =>
cookies := SS.add (!cookies, cname)
| _ => ();
- (EFfiApp (m, f, map (doExp env) es), loc))
+ (EFfiApp (m, f, map (fn (e, t) => (doExp env e, t)) es), loc))
| EApp (e1, e2) =>
let
diff --git a/src/jscomp.sml b/src/jscomp.sml
index 57f59b12..901ea9fe 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -91,7 +91,7 @@ fun process file =
fun quoteExp loc (t : typ) (e, st) =
case #1 t of
- TSource => ((EFfiApp ("Basis", "htmlifySource", [e]), loc), st)
+ TSource => ((EFfiApp ("Basis", "htmlifySource", [(e, t)]), loc), st)
| TRecord [] => (str loc "null", st)
| TRecord [(x, t)] =>
@@ -120,12 +120,12 @@ fun process file =
@ [str loc "}"]), st)
end
- | TFfi ("Basis", "string") => ((EFfiApp ("Basis", "jsifyString", [e]), loc), st)
- | TFfi ("Basis", "char") => ((EFfiApp ("Basis", "jsifyChar", [e]), loc), st)
- | TFfi ("Basis", "int") => ((EFfiApp ("Basis", "htmlifyInt", [e]), loc), st)
- | TFfi ("Basis", "float") => ((EFfiApp ("Basis", "htmlifyFloat", [e]), loc), st)
- | TFfi ("Basis", "channel") => ((EFfiApp ("Basis", "jsifyChannel", [e]), loc), st)
- | TFfi ("Basis", "time") => ((EFfiApp ("Basis", "jsifyTime", [e]), loc), st)
+ | TFfi ("Basis", "string") => ((EFfiApp ("Basis", "jsifyString", [(e, t)]), loc), st)
+ | TFfi ("Basis", "char") => ((EFfiApp ("Basis", "jsifyChar", [(e, t)]), loc), st)
+ | TFfi ("Basis", "int") => ((EFfiApp ("Basis", "htmlifyInt", [(e, t)]), loc), st)
+ | TFfi ("Basis", "float") => ((EFfiApp ("Basis", "htmlifyFloat", [(e, t)]), loc), st)
+ | TFfi ("Basis", "channel") => ((EFfiApp ("Basis", "jsifyChannel", [(e, t)]), loc), st)
+ | TFfi ("Basis", "time") => ((EFfiApp ("Basis", "jsifyTime", [(e, t)]), loc), st)
| TFfi ("Basis", "bool") => ((ECase (e,
[((PCon (Enum, PConFfi {mod = "Basis",
@@ -511,7 +511,7 @@ fun process file =
case e of
EPrim (Prim.String s) => jsifyStringMulti (level, s)
| EStrcat (e1, e2) => deStrcat level e1 ^ deStrcat level e2
- | EFfiApp ("Basis", "jsifyString", [e]) => "\"" ^ deStrcat (level + 1) e ^ "\""
+ | EFfiApp ("Basis", "jsifyString", [(e, _)]) => "\"" ^ deStrcat (level + 1) e ^ "\""
| _ => (Print.prefaces "deStrcat" [("e", MonoPrint.p_exp MonoEnv.empty all)];
raise Fail "Jscomp: deStrcat")
@@ -645,7 +645,7 @@ fun process file =
"ERROR")
| SOME s => s
- val (e, st) = foldr (fn (e, (acc, st)) =>
+ val (e, st) = foldr (fn ((e, _), (acc, st)) =>
let
val (e, st) = jsE inner (e, st)
in
@@ -1024,7 +1024,12 @@ fun process file =
| EFfi _ => (e, st)
| EFfiApp (m, x, es) =>
let
- val (es, st) = ListUtil.foldlMap (exp outer) st es
+ val (es, st) = ListUtil.foldlMap (fn ((e, t), st) =>
+ let
+ val (e, st) = exp outer (e, st)
+ in
+ ((e, t), st)
+ end) st es
in
((EFfiApp (m, x, es), loc), st)
end
diff --git a/src/mono.sml b/src/mono.sml
index bf38c0bc..2c83d1bc 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -78,7 +78,7 @@ datatype exp' =
| ENone of typ
| ESome of typ * exp
| EFfi of string * string
- | EFfiApp of string * string * exp list
+ | EFfiApp of string * string * (exp * typ) list
| EApp of exp * exp
| EAbs of string * typ * typ * exp
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index 5abbf900..199c807b 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -138,7 +138,7 @@ fun exp e =
EPrim (Prim.String (String.implode (rev chs)))
end
- | EFfiApp ("Basis", "strcat", [e1, e2]) => exp (EStrcat (e1, e2))
+ | EFfiApp ("Basis", "strcat", [(e1, _), (e2, _)]) => exp (EStrcat (e1, e2))
| EStrcat ((EPrim (Prim.String s1), loc), (EPrim (Prim.String s2), _)) =>
let
@@ -182,153 +182,153 @@ fun exp e =
ESeq ((EWrite (EPrim (Prim.String (s1 ^ s2)), loc), loc),
e)
- | EFfiApp ("Basis", "htmlifySpecialChar", [(EPrim (Prim.Char ch), _)]) =>
+ | EFfiApp ("Basis", "htmlifySpecialChar", [((EPrim (Prim.Char ch), _), _)]) =>
EPrim (Prim.String (htmlifySpecialChar ch))
| EWrite (EFfiApp ("Basis", "htmlifySpecialChar", [e]), _) =>
EFfiApp ("Basis", "htmlifySpecialChar_w", [e])
- | EFfiApp ("Basis", "htmlifyString", [(EFfiApp ("Basis", "intToString", [(EPrim (Prim.Int n), _)]), _)]) =>
+ | EFfiApp ("Basis", "htmlifyString", [((EFfiApp ("Basis", "intToString", [((EPrim (Prim.Int n), _), _)]), _), _)]) =>
EPrim (Prim.String (htmlifyInt n))
- | EFfiApp ("Basis", "htmlifyString", [(EFfiApp ("Basis", "intToString", es), _)]) =>
+ | EFfiApp ("Basis", "htmlifyString", [((EFfiApp ("Basis", "intToString", es), _), _)]) =>
EFfiApp ("Basis", "htmlifyInt", es)
- | EFfiApp ("Basis", "htmlifyString", [(EApp ((EFfi ("Basis", "intToString"), _),
- (EPrim (Prim.Int n), _)), _)]) =>
+ | EFfiApp ("Basis", "htmlifyString", [((EApp ((EFfi ("Basis", "intToString"), _),
+ (EPrim (Prim.Int n), _)), _), _)]) =>
EPrim (Prim.String (htmlifyInt n))
- | EFfiApp ("Basis", "htmlifyString", [(EApp ((EFfi ("Basis", "intToString"), _),
- e), _)]) =>
- EFfiApp ("Basis", "htmlifyInt", [e])
+ | EFfiApp ("Basis", "htmlifyString", [((EApp ((EFfi ("Basis", "intToString"), _),
+ e), loc), _)]) =>
+ EFfiApp ("Basis", "htmlifyInt", [(e, (TFfi ("Basis", "int"), loc))])
| EWrite (EFfiApp ("Basis", "htmlifyInt", [e]), _) =>
EFfiApp ("Basis", "htmlifyInt_w", [e])
- | EFfiApp ("Basis", "htmlifyString", [(EFfiApp ("Basis", "floatToString", [(EPrim (Prim.Float n), _)]), _)]) =>
+ | EFfiApp ("Basis", "htmlifyString", [((EFfiApp ("Basis", "floatToString", [((EPrim (Prim.Float n), _), _)]), _), _)]) =>
EPrim (Prim.String (htmlifyFloat n))
- | EFfiApp ("Basis", "htmlifyString", [(EFfiApp ("Basis", "floatToString", es), _)]) =>
+ | EFfiApp ("Basis", "htmlifyString", [((EFfiApp ("Basis", "floatToString", es), _), _)]) =>
EFfiApp ("Basis", "htmlifyFloat", es)
- | EFfiApp ("Basis", "htmlifyString", [(EApp ((EFfi ("Basis", "floatToString"), _),
- (EPrim (Prim.Float n), _)), _)]) =>
+ | EFfiApp ("Basis", "htmlifyString", [((EApp ((EFfi ("Basis", "floatToString"), _),
+ (EPrim (Prim.Float n), _)), _), _)]) =>
EPrim (Prim.String (htmlifyFloat n))
- | EFfiApp ("Basis", "htmlifyString", [(EApp ((EFfi ("Basis", "floatToString"), _),
- e), _)]) =>
- EFfiApp ("Basis", "htmlifyFloat", [e])
+ | EFfiApp ("Basis", "htmlifyString", [((EApp ((EFfi ("Basis", "floatToString"), _),
+ e), loc), _)]) =>
+ EFfiApp ("Basis", "htmlifyFloat", [(e, (TFfi ("Basis", "float"), loc))])
| EWrite (EFfiApp ("Basis", "htmlifyFloat", [e]), _) =>
EFfiApp ("Basis", "htmlifyFloat_w", [e])
- | EFfiApp ("Basis", "htmlifyString", [(EFfiApp ("Basis", "boolToString",
- [(ECon (Enum, PConFfi {con = "True", ...}, NONE), _)]), _)]) =>
+ | EFfiApp ("Basis", "htmlifyString", [((EFfiApp ("Basis", "boolToString",
+ [((ECon (Enum, PConFfi {con = "True", ...}, NONE), _), _)]), _), _)]) =>
EPrim (Prim.String "True")
- | EFfiApp ("Basis", "htmlifyString", [(EFfiApp ("Basis", "boolToString",
- [(ECon (Enum, PConFfi {con = "False", ...}, NONE), _)]), _)]) =>
+ | EFfiApp ("Basis", "htmlifyString", [((EFfiApp ("Basis", "boolToString",
+ [((ECon (Enum, PConFfi {con = "False", ...}, NONE), _), _)]), _), _)]) =>
EPrim (Prim.String "False")
- | EFfiApp ("Basis", "htmlifyString", [(EFfiApp ("Basis", "boolToString", es), _)]) =>
+ | EFfiApp ("Basis", "htmlifyString", [((EFfiApp ("Basis", "boolToString", es), _), _)]) =>
EFfiApp ("Basis", "htmlifyBool", es)
- | EFfiApp ("Basis", "htmlifyString", [(EApp ((EFfi ("Basis", "boolToString"), _),
- (ECon (Enum, PConFfi {con = "True", ...}, NONE), _)), _)]) =>
+ | EFfiApp ("Basis", "htmlifyString", [((EApp ((EFfi ("Basis", "boolToString"), _),
+ (ECon (Enum, PConFfi {con = "True", ...}, NONE), _)), _), _)]) =>
EPrim (Prim.String "True")
- | EFfiApp ("Basis", "htmlifyString", [(EApp ((EFfi ("Basis", "boolToString"), _),
- (ECon (Enum, PConFfi {con = "False", ...}, NONE), _)), _)]) =>
+ | EFfiApp ("Basis", "htmlifyString", [((EApp ((EFfi ("Basis", "boolToString"), _),
+ (ECon (Enum, PConFfi {con = "False", ...}, NONE), _)), _), _)]) =>
EPrim (Prim.String "False")
- | EFfiApp ("Basis", "htmlifyString", [(EApp ((EFfi ("Basis", "boolToString"), _),
- e), _)]) =>
- EFfiApp ("Basis", "htmlifyBool", [e])
+ | EFfiApp ("Basis", "htmlifyString", [((EApp ((EFfi ("Basis", "boolToString"), _),
+ e), loc), _)]) =>
+ EFfiApp ("Basis", "htmlifyBool", [(e, (TFfi ("Basis", "bool"), loc))])
| EWrite (EFfiApp ("Basis", "htmlifyBool", [e]), _) =>
EFfiApp ("Basis", "htmlifyBool_w", [e])
- | EFfiApp ("Basis", "htmlifyString", [(EApp ((EFfi ("Basis", "timeToString"), _), e), _)]) =>
- EFfiApp ("Basis", "htmlifyTime", [e])
- | EFfiApp ("Basis", "htmlifyString_w", [(EApp ((EFfi ("Basis", "timeToString"), _), e), _)]) =>
- EFfiApp ("Basis", "htmlifyTime_w", [e])
+ | EFfiApp ("Basis", "htmlifyString", [((EApp ((EFfi ("Basis", "timeToString"), _), e), loc), _)]) =>
+ EFfiApp ("Basis", "htmlifyTime", [(e, (TFfi ("Basis", "time"), loc))])
+ | EFfiApp ("Basis", "htmlifyString_w", [((EApp ((EFfi ("Basis", "timeToString"), loc), e), _), _)]) =>
+ EFfiApp ("Basis", "htmlifyTime_w", [(e, (TFfi ("Basis", "time"), loc))])
| EWrite (EFfiApp ("Basis", "htmlifyTime", [e]), _) =>
EFfiApp ("Basis", "htmlifyTime_w", [e])
- | EFfiApp ("Basis", "htmlifyString", [(EPrim (Prim.String s), _)]) =>
+ | EFfiApp ("Basis", "htmlifyString", [((EPrim (Prim.String s), _), _)]) =>
EPrim (Prim.String (htmlifyString s))
- | EWrite (EFfiApp ("Basis", "htmlifyString", [(EPrim (Prim.String s), _)]), loc) =>
+ | EWrite (EFfiApp ("Basis", "htmlifyString", [((EPrim (Prim.String s), _), _)]), loc) =>
EWrite (EPrim (Prim.String (htmlifyString s)), loc)
| EWrite (EFfiApp ("Basis", "htmlifyString", [e]), _) =>
EFfiApp ("Basis", "htmlifyString_w", [e])
- | EFfiApp ("Basis", "htmlifyString_w", [(EPrim (Prim.String s), loc)]) =>
+ | EFfiApp ("Basis", "htmlifyString_w", [((EPrim (Prim.String s), loc), _)]) =>
EWrite (EPrim (Prim.String (htmlifyString s)), loc)
| EWrite (EFfiApp ("Basis", "htmlifySource", [e]), _) =>
EFfiApp ("Basis", "htmlifySource_w", [e])
- | EFfiApp ("Basis", "attrifyInt", [(EPrim (Prim.Int n), _)]) =>
+ | EFfiApp ("Basis", "attrifyInt", [((EPrim (Prim.Int n), _), _)]) =>
EPrim (Prim.String (attrifyInt n))
- | EWrite (EFfiApp ("Basis", "attrifyInt", [(EPrim (Prim.Int n), _)]), loc) =>
+ | EWrite (EFfiApp ("Basis", "attrifyInt", [((EPrim (Prim.Int n), _), _)]), loc) =>
EWrite (EPrim (Prim.String (attrifyInt n)), loc)
| EWrite (EFfiApp ("Basis", "attrifyInt", [e]), _) =>
EFfiApp ("Basis", "attrifyInt_w", [e])
- | EFfiApp ("Basis", "attrifyFloat", [(EPrim (Prim.Float n), _)]) =>
+ | EFfiApp ("Basis", "attrifyFloat", [((EPrim (Prim.Float n), _), _)]) =>
EPrim (Prim.String (attrifyFloat n))
- | EWrite (EFfiApp ("Basis", "attrifyFloat", [(EPrim (Prim.Float n), _)]), loc) =>
+ | EWrite (EFfiApp ("Basis", "attrifyFloat", [((EPrim (Prim.Float n), _), _)]), loc) =>
EWrite (EPrim (Prim.String (attrifyFloat n)), loc)
| EWrite (EFfiApp ("Basis", "attrifyFloat", [e]), _) =>
EFfiApp ("Basis", "attrifyFloat_w", [e])
- | EFfiApp ("Basis", "attrifyString", [(EPrim (Prim.String s), _)]) =>
+ | EFfiApp ("Basis", "attrifyString", [((EPrim (Prim.String s), _), _)]) =>
EPrim (Prim.String (attrifyString s))
- | EWrite (EFfiApp ("Basis", "attrifyString", [(EPrim (Prim.String s), _)]), loc) =>
+ | EWrite (EFfiApp ("Basis", "attrifyString", [((EPrim (Prim.String s), _), _)]), loc) =>
EWrite (EPrim (Prim.String (attrifyString s)), loc)
| EWrite (EFfiApp ("Basis", "attrifyString", [e]), _) =>
EFfiApp ("Basis", "attrifyString_w", [e])
- | EFfiApp ("Basis", "attrifyChar", [(EPrim (Prim.Char s), _)]) =>
+ | EFfiApp ("Basis", "attrifyChar", [((EPrim (Prim.Char s), _), _)]) =>
EPrim (Prim.String (attrifyChar s))
- | EWrite (EFfiApp ("Basis", "attrifyChar", [(EPrim (Prim.Char s), _)]), loc) =>
+ | EWrite (EFfiApp ("Basis", "attrifyChar", [((EPrim (Prim.Char s), _), _)]), loc) =>
EWrite (EPrim (Prim.String (attrifyChar s)), loc)
| EWrite (EFfiApp ("Basis", "attrifyChar", [e]), _) =>
EFfiApp ("Basis", "attrifyChar_w", [e])
- | EFfiApp ("Basis", "attrifyCss_class", [(EPrim (Prim.String s), _)]) =>
+ | EFfiApp ("Basis", "attrifyCss_class", [((EPrim (Prim.String s), _), _)]) =>
EPrim (Prim.String s)
- | EWrite (EFfiApp ("Basis", "attrifyCss_class", [(EPrim (Prim.String s), _)]), loc) =>
+ | EWrite (EFfiApp ("Basis", "attrifyCss_class", [((EPrim (Prim.String s), _), _)]), loc) =>
EWrite (EPrim (Prim.String s), loc)
| EWrite (EFfiApp ("Basis", "attrifyCss_class", [e]), _) =>
EFfiApp ("Basis", "attrifyString_w", [e])
- | EFfiApp ("Basis", "urlifyInt", [(EPrim (Prim.Int n), _)]) =>
+ | EFfiApp ("Basis", "urlifyInt", [((EPrim (Prim.Int n), _), _)]) =>
EPrim (Prim.String (urlifyInt n))
- | EWrite (EFfiApp ("Basis", "urlifyInt", [(EPrim (Prim.Int n), _)]), loc) =>
+ | EWrite (EFfiApp ("Basis", "urlifyInt", [((EPrim (Prim.Int n), _), _)]), loc) =>
EWrite (EPrim (Prim.String (urlifyInt n)), loc)
| EWrite (EFfiApp ("Basis", "urlifyInt", [e]), _) =>
EFfiApp ("Basis", "urlifyInt_w", [e])
- | EFfiApp ("Basis", "urlifyFloat", [(EPrim (Prim.Float n), _)]) =>
+ | EFfiApp ("Basis", "urlifyFloat", [((EPrim (Prim.Float n), _), _)]) =>
EPrim (Prim.String (urlifyFloat n))
- | EWrite (EFfiApp ("Basis", "urlifyFloat", [(EPrim (Prim.Float n), _)]), loc) =>
+ | EWrite (EFfiApp ("Basis", "urlifyFloat", [((EPrim (Prim.Float n), _), _)]), loc) =>
EWrite (EPrim (Prim.String (urlifyFloat n)), loc)
| EWrite (EFfiApp ("Basis", "urlifyFloat", [e]), _) =>
EFfiApp ("Basis", "urlifyFloat_w", [e])
- | EFfiApp ("Basis", "urlifyString", [(EPrim (Prim.String s), _)]) =>
+ | EFfiApp ("Basis", "urlifyString", [((EPrim (Prim.String s), _), _)]) =>
EPrim (Prim.String (urlifyString s))
- | EWrite (EFfiApp ("Basis", "urlifyString", [(EPrim (Prim.String s), _)]), loc) =>
+ | EWrite (EFfiApp ("Basis", "urlifyString", [((EPrim (Prim.String s), _), _)]), loc) =>
EWrite (EPrim (Prim.String (urlifyString s)), loc)
| EWrite (EFfiApp ("Basis", "urlifyString", [e]), _) =>
EFfiApp ("Basis", "urlifyString_w", [e])
- | EFfiApp ("Basis", "urlifyBool", [(ECon (Enum, PConFfi {con = "True", ...}, NONE), _)]) =>
+ | EFfiApp ("Basis", "urlifyBool", [((ECon (Enum, PConFfi {con = "True", ...}, NONE), _), _)]) =>
EPrim (Prim.String "1")
- | EFfiApp ("Basis", "urlifyBool", [(ECon (Enum, PConFfi {con = "False", ...}, NONE), _)]) =>
+ | EFfiApp ("Basis", "urlifyBool", [((ECon (Enum, PConFfi {con = "False", ...}, NONE), _), _)]) =>
EPrim (Prim.String "0")
- | EWrite (EFfiApp ("Basis", "urlifyBool", [(ECon (Enum, PConFfi {con = "True", ...}, NONE), _)]), loc) =>
+ | EWrite (EFfiApp ("Basis", "urlifyBool", [((ECon (Enum, PConFfi {con = "True", ...}, NONE), _), _)]), loc) =>
EWrite (EPrim (Prim.String "1"), loc)
- | EWrite (EFfiApp ("Basis", "urlifyBool", [(ECon (Enum, PConFfi {con = "False", ...}, NONE), _)]), loc) =>
+ | EWrite (EFfiApp ("Basis", "urlifyBool", [((ECon (Enum, PConFfi {con = "False", ...}, NONE), _), _)]), loc) =>
EWrite (EPrim (Prim.String "0"), loc)
| EWrite (EFfiApp ("Basis", "urlifyBool", [e]), _) =>
EFfiApp ("Basis", "urlifyBool_w", [e])
- | EFfiApp ("Basis", "sqlifyInt", [(EPrim (Prim.Int n), _)]) =>
+ | EFfiApp ("Basis", "sqlifyInt", [((EPrim (Prim.Int n), _), _)]) =>
EPrim (Prim.String (sqlifyInt n))
- | EFfiApp ("Basis", "sqlifyIntN", [(ENone _, _)]) =>
+ | EFfiApp ("Basis", "sqlifyIntN", [((ENone _, _), _)]) =>
EPrim (Prim.String "NULL")
- | EFfiApp ("Basis", "sqlifyIntN", [(ESome (_, (EPrim (Prim.Int n), _)), _)]) =>
+ | EFfiApp ("Basis", "sqlifyIntN", [((ESome (_, (EPrim (Prim.Int n), _)), _), _)]) =>
EPrim (Prim.String (sqlifyInt n))
- | EFfiApp ("Basis", "sqlifyFloat", [(EPrim (Prim.Float n), _)]) =>
+ | EFfiApp ("Basis", "sqlifyFloat", [((EPrim (Prim.Float n), _), _)]) =>
EPrim (Prim.String (sqlifyFloat n))
- | EFfiApp ("Basis", "sqlifyBool", [b as (_, loc)]) =>
+ | EFfiApp ("Basis", "sqlifyBool", [(b as (_, loc), _)]) =>
optExp (ECase (b,
[((PCon (Enum, PConFfi {mod = "Basis", datatyp = "bool", con = "True", arg = NONE}, NONE), loc),
(EPrim (Prim.String (#trueString (Settings.currentDbms ()))), loc)),
@@ -336,9 +336,9 @@ fun exp e =
(EPrim (Prim.String (#falseString (Settings.currentDbms ()))), loc))],
{disc = (TFfi ("Basis", "bool"), loc),
result = (TFfi ("Basis", "string"), loc)}), loc)
- | EFfiApp ("Basis", "sqlifyString", [(EPrim (Prim.String n), _)]) =>
+ | EFfiApp ("Basis", "sqlifyString", [((EPrim (Prim.String n), _), _)]) =>
EPrim (Prim.String (sqlifyString n))
- | EFfiApp ("Basis", "sqlifyChar", [(EPrim (Prim.Char n), _)]) =>
+ | EFfiApp ("Basis", "sqlifyChar", [((EPrim (Prim.Char n), _), _)]) =>
EPrim (Prim.String (sqlifyChar n))
| EWrite (ECase (discE, pes, {disc, ...}), loc) =>
@@ -418,52 +418,52 @@ fun exp e =
| ESignalBind ((ESignalReturn e1, loc), e2) =>
optExp (EApp (e2, e1), loc)
- | EFfiApp ("Basis", "bless", [(se as EPrim (Prim.String s), loc)]) =>
+ | EFfiApp ("Basis", "bless", [((se as EPrim (Prim.String s), loc), _)]) =>
(if checkUrl s then
()
else
ErrorMsg.errorAt loc ("Invalid URL " ^ s ^ " passed to 'bless'");
se)
- | EFfiApp ("Basis", "checkUrl", [(se as EPrim (Prim.String s), loc)]) =>
+ | EFfiApp ("Basis", "checkUrl", [((se as EPrim (Prim.String s), loc), _)]) =>
(if checkUrl s then
ESome ((TFfi ("Basis", "string"), loc), (se, loc))
else
ENone (TFfi ("Basis", "string"), loc))
- | EFfiApp ("Basis", "blessMime", [(se as EPrim (Prim.String s), loc)]) =>
+ | EFfiApp ("Basis", "blessMime", [((se as EPrim (Prim.String s), loc), _)]) =>
(if Settings.checkMime s then
()
else
ErrorMsg.errorAt loc ("Invalid string " ^ s ^ " passed to 'blessMime'");
se)
- | EFfiApp ("Basis", "checkMime", [(se as EPrim (Prim.String s), loc)]) =>
+ | EFfiApp ("Basis", "checkMime", [((se as EPrim (Prim.String s), loc), _)]) =>
(if Settings.checkMime s then
ESome ((TFfi ("Basis", "string"), loc), (se, loc))
else
ENone (TFfi ("Basis", "string"), loc))
- | EFfiApp ("Basis", "blessRequestHeader", [(se as EPrim (Prim.String s), loc)]) =>
+ | EFfiApp ("Basis", "blessRequestHeader", [((se as EPrim (Prim.String s), loc), _)]) =>
(if Settings.checkRequestHeader s then
()
else
ErrorMsg.errorAt loc ("Invalid string " ^ s ^ " passed to 'blessRequestHeader'");
se)
- | EFfiApp ("Basis", "checkRequestHeader", [(se as EPrim (Prim.String s), loc)]) =>
+ | EFfiApp ("Basis", "checkRequestHeader", [((se as EPrim (Prim.String s), loc), _)]) =>
(if Settings.checkRequestHeader s then
ESome ((TFfi ("Basis", "string"), loc), (se, loc))
else
ENone (TFfi ("Basis", "string"), loc))
- | EFfiApp ("Basis", "blessResponseHeader", [(se as EPrim (Prim.String s), loc)]) =>
+ | EFfiApp ("Basis", "blessResponseHeader", [((se as EPrim (Prim.String s), loc), _)]) =>
(if Settings.checkResponseHeader s then
()
else
ErrorMsg.errorAt loc ("Invalid string " ^ s ^ " passed to 'blessResponseHeader'");
se)
- | EFfiApp ("Basis", "checkResponseHeader", [(se as EPrim (Prim.String s), loc)]) =>
+ | EFfiApp ("Basis", "checkResponseHeader", [((se as EPrim (Prim.String s), loc), _)]) =>
(if Settings.checkResponseHeader s then
ESome ((TFfi ("Basis", "string"), loc), (se, loc))
else
ENone (TFfi ("Basis", "string"), loc))
- | EFfiApp ("Basis", "checkString", [(EPrim (Prim.String s), loc)]) =>
+ | EFfiApp ("Basis", "checkString", [((EPrim (Prim.String s), loc), _)]) =>
let
fun uwify (cs, acc) =
case cs of
@@ -491,7 +491,7 @@ fun exp e =
EPrim (Prim.String s)
end
- | EFfiApp ("Basis", "viewify", [(EPrim (Prim.String s), loc)]) =>
+ | EFfiApp ("Basis", "viewify", [((EPrim (Prim.String s), loc), _)]) =>
let
fun uwify (cs, acc) =
case cs of
@@ -516,9 +516,9 @@ fun exp e =
EPrim (Prim.String s)
end
- | EFfiApp ("Basis", "unAs", [(EPrim (Prim.String s), _)]) =>
+ | EFfiApp ("Basis", "unAs", [((EPrim (Prim.String s), _), _)]) =>
EPrim (Prim.String (unAs s))
- | EFfiApp ("Basis", "unAs", [e']) =>
+ | EFfiApp ("Basis", "unAs", [(e', _)]) =>
let
fun parts (e as (_, loc)) =
case #1 e of
@@ -543,11 +543,11 @@ fun exp e =
| NONE => e
end
- | EFfiApp ("Basis", "str1", [(EPrim (Prim.Char ch), _)]) =>
+ | EFfiApp ("Basis", "str1", [((EPrim (Prim.Char ch), _), _)]) =>
EPrim (Prim.String (str ch))
- | EFfiApp ("Basis", "attrifyString", [(EFfiApp ("Basis", "str1", [e]), _)]) =>
+ | EFfiApp ("Basis", "attrifyString", [((EFfiApp ("Basis", "str1", [e]), _), _)]) =>
EFfiApp ("Basis", "attrifyChar", [e])
- | EFfiApp ("Basis", "attrifyString_w", [(EFfiApp ("Basis", "str1", [e]), _)]) =>
+ | EFfiApp ("Basis", "attrifyString_w", [((EFfiApp ("Basis", "str1", [e]), _), _)]) =>
EFfiApp ("Basis", "attrifyChar_w", [e])
| EBinop (_, "+", (EPrim (Prim.Int n1), _), (EPrim (Prim.Int n2), _)) => EPrim (Prim.Int (Int64.+ (n1, n2)))
diff --git a/src/mono_print.sml b/src/mono_print.sml
index 2d296745..bf1b0935 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -167,7 +167,7 @@ fun p_exp' par env (e, _) =
string ".",
string x,
string "(",
- p_list (p_exp env) es,
+ p_list (p_exp env o #1) es,
string "))"]
| EApp (e1, e2) => parenIf par (box [p_exp env e1,
space,
diff --git a/src/mono_reduce.sml b/src/mono_reduce.sml
index 3507480e..88628ac2 100644
--- a/src/mono_reduce.sml
+++ b/src/mono_reduce.sml
@@ -390,20 +390,20 @@ fun reduce file =
| ENone _ => []
| ESome (_, e) => summarize d e
| EFfi _ => []
- | EFfiApp ("Basis", "get_cookie", [e]) =>
+ | EFfiApp ("Basis", "get_cookie", [(e, _)]) =>
summarize d e @ [ReadCookie]
| EFfiApp ("Basis", "set_cookie", es) =>
- List.concat (map (summarize d) es) @ [WriteCookie]
+ List.concat (map (summarize d o #1) es) @ [WriteCookie]
| EFfiApp ("Basis", "clear_cookie", es) =>
- List.concat (map (summarize d) es) @ [WriteCookie]
+ List.concat (map (summarize d o #1) es) @ [WriteCookie]
| EFfiApp (m, x, es) =>
if Settings.isEffectful (m, x) orelse Settings.isBenignEffectful (m, x) then
- List.concat (map (summarize d) es) @ [if m = "Basis" andalso String.isSuffix "_w" x then
- WritePage
- else
- Unsure]
+ List.concat (map (summarize d o #1) es) @ [if m = "Basis" andalso String.isSuffix "_w" x then
+ WritePage
+ else
+ Unsure]
else
- List.concat (map (summarize d) es)
+ List.concat (map (summarize d o #1) es)
| EApp ((EFfi _, _), e) => summarize d e
| EApp _ =>
let
diff --git a/src/mono_util.sml b/src/mono_util.sml
index 39305d1b..38016f85 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -156,6 +156,12 @@ fun mapfoldB {typ = fc, exp = fe, bind} =
fun mfe ctx e acc =
S.bindP (mfe' ctx e acc, fe ctx)
+ and mfet ctx (e, t) =
+ S.bind2 (mfe ctx e,
+ fn e' =>
+ S.map2 (mft t,
+ fn t' => (e', t')))
+
and mfe' ctx (eAll as (e, loc)) =
case e of
EPrim _ => S.return2 eAll
@@ -178,7 +184,7 @@ fun mapfoldB {typ = fc, exp = fe, bind} =
(ESome (t', e'), loc)))
| EFfi _ => S.return2 eAll
| EFfiApp (m, x, es) =>
- S.map2 (ListUtil.mapfold (fn e => mfe ctx e) es,
+ S.map2 (ListUtil.mapfold (fn e => mfet ctx e) es,
fn es' =>
(EFfiApp (m, x, es'), loc))
| EApp (e1, e2) =>
@@ -479,7 +485,7 @@ fun appLoc f =
| ENone _ => ()
| ESome (_, e) => appl e
| EFfi _ => ()
- | EFfiApp (_, _, es) => app appl es
+ | EFfiApp (_, _, es) => app (appl o #1) es
| EApp (e1, e2) => (appl e1; appl e2)
| EAbs (_, _, _, e1) => appl e1
| EUnop (_, e1) => appl e1
diff --git a/src/monoize.sml b/src/monoize.sml
index 82e0030c..d952c396 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -509,7 +509,7 @@ fun fooifyExp fk env =
| _ =>
case t of
L'.TFfi ("Basis", "unit") => ((L'.EPrim (Prim.String ""), loc), fm)
- | L'.TFfi (m, x) => ((L'.EFfiApp (m, fk2s fk ^ "ify" ^ capitalize x, [e]), loc), fm)
+ | L'.TFfi (m, x) => ((L'.EFfiApp (m, fk2s fk ^ "ify" ^ capitalize x, [(e, tAll)]), loc), fm)
| L'.TRecord [] => ((L'.EPrim (Prim.String ""), loc), fm)
| L'.TRecord ((x, t) :: xts) =>
@@ -944,7 +944,8 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L'.TFun ((L'.TFfi ("Basis", "time"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc),
(L'.EAbs ("y", (L'.TFfi ("Basis", "time"), loc),
(L'.TFfi ("Basis", "bool"), loc),
- (L'.EFfiApp ("Basis", "eq_time", [(L'.ERel 1, loc), (L'.ERel 0, loc)]), loc)), loc)), loc),
+ (L'.EFfiApp ("Basis", "eq_time", [((L'.ERel 1, loc), (L'.TFfi ("Basis", "time"), loc)),
+ ((L'.ERel 0, loc), (L'.TFfi ("Basis", "time"), loc))]), loc)), loc)), loc),
fm)
| L.ECApp ((L.EFfi ("Basis", "mkEq"), _), t) =>
@@ -1169,7 +1170,8 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L'.TFun ((L'.TFfi ("Basis", "time"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc),
(L'.EAbs ("y", (L'.TFfi ("Basis", "time"), loc),
(L'.TFfi ("Basis", "bool"), loc),
- (L'.EFfiApp ("Basis", s, [(L'.ERel 1, loc), (L'.ERel 0, loc)]), loc)), loc)), loc)
+ (L'.EFfiApp ("Basis", s, [((L'.ERel 1, loc), (L'.TFfi ("Basis", "time"), loc)),
+ ((L'.ERel 0, loc), (L'.TFfi ("Basis", "time"), loc))]), loc)), loc)), loc)
in
ordEx ((L'.TFfi ("Basis", "time"), loc),
boolBin "lt_time",
@@ -1368,14 +1370,14 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
end
| L.EFfiApp ("Basis", "recv", _) => poly ()
- | L.EFfiApp ("Basis", "float", [e]) =>
+ | L.EFfiApp ("Basis", "float", [(e, t)]) =>
let
val (e, fm) = monoExp (env, st, fm) e
in
- ((L'.EFfiApp ("Basis", "floatFromInt", [e]), loc), fm)
+ ((L'.EFfiApp ("Basis", "floatFromInt", [(e, monoType env t)]), loc), fm)
end
- | L.EFfiApp ("Basis", "sleep", [n]) =>
+ | L.EFfiApp ("Basis", "sleep", [(n, _)]) =>
let
val (n, fm) = monoExp (env, st, fm) n
in
@@ -1390,7 +1392,8 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
((L'.EAbs ("x", t, (L'.TFun ((L'.TRecord [], loc), (L'.TSource, loc)), loc),
(L'.EAbs ("_", (L'.TRecord [], loc), (L'.TSource, loc),
(L'.EFfiApp ("Basis", "new_client_source",
- [(L'.EJavaScript (L'.Source t, (L'.ERel 1, loc)), loc)]),
+ [((L'.EJavaScript (L'.Source t, (L'.ERel 1, loc)), loc),
+ (L'.TSource, loc))]),
loc)), loc)),
loc),
fm)
@@ -1404,9 +1407,10 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L'.EAbs ("v", t, (L'.TFun ((L'.TRecord [], loc), (L'.TRecord [], loc)), loc),
(L'.EAbs ("_", (L'.TRecord [], loc), (L'.TRecord [], loc),
(L'.EFfiApp ("Basis", "set_client_source",
- [(L'.ERel 2, loc),
- (L'.EJavaScript (L'.Source t,
- (L'.ERel 1, loc)), loc)]),
+ [((L'.ERel 2, loc), (L'.TSource, loc)),
+ ((L'.EJavaScript (L'.Source t,
+ (L'.ERel 1, loc)), loc),
+ t)]),
loc)), loc)), loc)), loc),
fm)
end
@@ -1418,7 +1422,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L'.TFun ((L'.TRecord [], loc), t), loc),
(L'.EAbs ("_", (L'.TRecord [], loc), t,
(L'.EFfiApp ("Basis", "get_client_source",
- [(L'.ERel 1, loc)]),
+ [((L'.ERel 1, loc), (L'.TSource, loc))]),
loc)), loc)), loc),
fm)
end
@@ -1430,12 +1434,12 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L'.TFun ((L'.TRecord [], loc), t), loc),
(L'.EAbs ("_", (L'.TRecord [], loc), t,
(L'.EFfiApp ("Basis", "current",
- [(L'.ERel 1, loc)]),
+ [((L'.ERel 1, loc), (L'.TSource, loc))]),
loc)), loc)), loc),
fm)
end
- | L.EFfiApp ("Basis", "spawn", [e]) =>
+ | L.EFfiApp ("Basis", "spawn", [(e, _)]) =>
let
val (e, fm) = monoExp (env, st, fm) e
in
@@ -1480,7 +1484,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
in
((L'.EAbs ("c", s, (L'.TFun (un, s), loc),
(L'.EAbs ("_", un, s,
- (L'.EUnurlify ((L'.EFfiApp ("Basis", "get_cookie", [(L'.ERel 1, loc)]), loc),
+ (L'.EUnurlify ((L'.EFfiApp ("Basis", "get_cookie", [((L'.ERel 1, loc), s)]), loc),
t, true),
loc)), loc)), loc),
fm)
@@ -1502,13 +1506,13 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
((L'.EAbs ("c", s, (L'.TFun (rt, (L'.TFun (un, un), loc)), loc),
(L'.EAbs ("r", rt, (L'.TFun (un, un), loc),
(L'.EAbs ("_", un, un,
- (L'.EFfiApp ("Basis", "set_cookie", [(L'.EPrim (Prim.String
- (Settings.getUrlPrefix ())),
- loc),
- (L'.ERel 2, loc),
- e,
- fd "Expires",
- fd "Secure"])
+ (L'.EFfiApp ("Basis", "set_cookie", [((L'.EPrim (Prim.String
+ (Settings.getUrlPrefix ())),
+ loc), s),
+ ((L'.ERel 2, loc), s),
+ (e, s),
+ (fd "Expires", (L'.TOption (L'.TFfi ("Basis", "time"), loc), loc)),
+ (fd "Secure", (L'.TFfi ("Basis", "bool"), loc))])
, loc)), loc)), loc)), loc),
fm)
end
@@ -1521,17 +1525,17 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
((L'.EAbs ("c", s, (L'.TFun (un, un), loc),
(L'.EAbs ("_", un, un,
(L'.EFfiApp ("Basis", "clear_cookie",
- [(L'.EPrim (Prim.String
- (Settings.getUrlPrefix ())),
- loc),
- (L'.ERel 1, loc)]),
+ [((L'.EPrim (Prim.String
+ (Settings.getUrlPrefix ())),
+ loc), s),
+ ((L'.ERel 1, loc), s)]),
loc)), loc)), loc),
fm)
end
| L.ECApp ((L.EFfi ("Basis", "channel"), _), t) =>
((L'.EAbs ("_", (L'.TRecord [], loc), (L'.TFfi ("Basis", "channel"), loc),
- (L'.EFfiApp ("Basis", "new_channel", [(L'.ERecord [], loc)]), loc)), loc),
+ (L'.EFfiApp ("Basis", "new_channel", [((L'.ERecord [], loc), (L'.TRecord [], loc))]), loc)), loc),
fm)
| L.ECApp ((L.EFfi ("Basis", "send"), _), t) =>
let
@@ -1543,8 +1547,8 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L'.EAbs ("v", t, (L'.TFun ((L'.TRecord [], loc), (L'.TRecord [], loc)), loc),
(L'.EAbs ("_", (L'.TRecord [], loc), (L'.TRecord [], loc),
(L'.EFfiApp ("Basis", "send",
- [(L'.ERel 2, loc),
- e]),
+ [((L'.ERel 2, loc), (L'.TFfi ("Basis", "channel"), loc)),
+ (e, (L'.TFfi ("Basis", "string"), loc))]),
loc)), loc)), loc)), loc),
fm)
end
@@ -1763,11 +1767,11 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
((L'.EAbs ("e", string, string,
(L'.EStrcat ((L'.EPrim (Prim.String "CHECK "), loc),
(L'.EFfiApp ("Basis", "checkString",
- [(L'.ERel 0, loc)]), loc)), loc)), loc),
+ [((L'.ERel 0, loc), string)]), loc)), loc)), loc),
fm)
end
- | L.EFfiApp ("Basis", "dml", [e]) =>
+ | L.EFfiApp ("Basis", "dml", [(e, _)]) =>
let
val (e, fm) = monoExp (env, st, fm) e
in
@@ -1775,7 +1779,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
fm)
end
- | L.EFfiApp ("Basis", "tryDml", [e]) =>
+ | L.EFfiApp ("Basis", "tryDml", [(e, _)]) =>
let
val (e, fm) = monoExp (env, st, fm) e
in
@@ -1841,13 +1845,14 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
strcat [sc ("uw_" ^ x
^ " = "),
(L'.EFfiApp ("Basis", "unAs",
- [(L'.EField
- ((L'.ERel 2,
- loc),
- x), loc)]), loc)])
+ [((L'.EField
+ ((L'.ERel 2,
+ loc),
+ x), loc),
+ s)]), loc)])
changed),
sc " WHERE ",
- (L'.EFfiApp ("Basis", "unAs", [(L'.ERel 0, loc)]), loc)]),
+ (L'.EFfiApp ("Basis", "unAs", [((L'.ERel 0, loc), s)]), loc)]),
loc)), loc)), loc),
fm)
end
@@ -1869,7 +1874,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
strcat [sc "DELETE FROM ",
(L'.ERel 1, loc),
sc " WHERE ",
- (L'.EFfiApp ("Basis", "unAs", [(L'.ERel 0, loc)]), loc)]), loc)), loc),
+ (L'.EFfiApp ("Basis", "unAs", [((L'.ERel 0, loc), s)]), loc)]), loc)), loc),
fm)
end
@@ -2108,43 +2113,43 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
| L.EFfi ("Basis", "sql_int") =>
((L'.EAbs ("x", (L'.TFfi ("Basis", "int"), loc), (L'.TFfi ("Basis", "string"), loc),
- (L'.EFfiApp ("Basis", "sqlifyInt", [(L'.ERel 0, loc)]), loc)), loc),
+ (L'.EFfiApp ("Basis", "sqlifyInt", [((L'.ERel 0, loc), (L'.TFfi ("Basis", "int"), loc))]), loc)), loc),
fm)
| L.EFfi ("Basis", "sql_float") =>
((L'.EAbs ("x", (L'.TFfi ("Basis", "float"), loc), (L'.TFfi ("Basis", "string"), loc),
- (L'.EFfiApp ("Basis", "sqlifyFloat", [(L'.ERel 0, loc)]), loc)), loc),
+ (L'.EFfiApp ("Basis", "sqlifyFloat", [((L'.ERel 0, loc), (L'.TFfi ("Basis", "float"), loc))]), loc)), loc),
fm)
| L.EFfi ("Basis", "sql_bool") =>
((L'.EAbs ("x", (L'.TFfi ("Basis", "bool"), loc), (L'.TFfi ("Basis", "string"), loc),
- (L'.EFfiApp ("Basis", "sqlifyBool", [(L'.ERel 0, loc)]), loc)), loc),
+ (L'.EFfiApp ("Basis", "sqlifyBool", [((L'.ERel 0, loc), (L'.TFfi ("Basis", "bool"), loc))]), loc)), loc),
fm)
| L.EFfi ("Basis", "sql_string") =>
((L'.EAbs ("x", (L'.TFfi ("Basis", "string"), loc), (L'.TFfi ("Basis", "string"), loc),
- (L'.EFfiApp ("Basis", "sqlifyString", [(L'.ERel 0, loc)]), loc)), loc),
+ (L'.EFfiApp ("Basis", "sqlifyString", [((L'.ERel 0, loc), (L'.TFfi ("Basis", "string"), loc))]), loc)), loc),
fm)
| L.EFfi ("Basis", "sql_char") =>
((L'.EAbs ("x", (L'.TFfi ("Basis", "char"), loc), (L'.TFfi ("Basis", "string"), loc),
- (L'.EFfiApp ("Basis", "sqlifyChar", [(L'.ERel 0, loc)]), loc)), loc),
+ (L'.EFfiApp ("Basis", "sqlifyChar", [((L'.ERel 0, loc), (L'.TFfi ("Basis", "char"), loc))]), loc)), loc),
fm)
| L.EFfi ("Basis", "sql_time") =>
((L'.EAbs ("x", (L'.TFfi ("Basis", "time"), loc), (L'.TFfi ("Basis", "string"), loc),
- (L'.EFfiApp ("Basis", "sqlifyTime", [(L'.ERel 0, loc)]), loc)), loc),
+ (L'.EFfiApp ("Basis", "sqlifyTime", [((L'.ERel 0, loc), (L'.TFfi ("Basis", "time"), loc))]), loc)), loc),
fm)
| L.EFfi ("Basis", "sql_blob") =>
((L'.EAbs ("x", (L'.TFfi ("Basis", "blob"), loc), (L'.TFfi ("Basis", "string"), loc),
- (L'.EFfiApp ("Basis", "sqlifyBlob", [(L'.ERel 0, loc)]), loc)), loc),
+ (L'.EFfiApp ("Basis", "sqlifyBlob", [((L'.ERel 0, loc), (L'.TFfi ("Basis", "blob"), loc))]), loc)), loc),
fm)
| L.ECApp ((L.EFfi ("Basis", "sql_channel"), _), _) =>
((L'.EAbs ("x", (L'.TFfi ("Basis", "channel"), loc), (L'.TFfi ("Basis", "string"), loc),
- (L'.EFfiApp ("Basis", "sqlifyChannel", [(L'.ERel 0, loc)]), loc)), loc),
+ (L'.EFfiApp ("Basis", "sqlifyChannel", [((L'.ERel 0, loc), (L'.TFfi ("Basis", "channel"), loc))]), loc)), loc),
fm)
| L.EFfi ("Basis", "sql_client") =>
((L'.EAbs ("x", (L'.TFfi ("Basis", "client"), loc), (L'.TFfi ("Basis", "string"), loc),
- (L'.EFfiApp ("Basis", "sqlifyClient", [(L'.ERel 0, loc)]), loc)), loc),
+ (L'.EFfiApp ("Basis", "sqlifyClient", [((L'.ERel 0, loc), (L'.TFfi ("Basis", "client"), loc))]), loc)), loc),
fm)
| L.ECApp ((L.EFfi ("Basis", "sql_serialized"), _), _) =>
((L'.EAbs ("x", (L'.TFfi ("Basis", "string"), loc), (L'.TFfi ("Basis", "string"), loc),
- (L'.EFfiApp ("Basis", "sqlifyString", [(L'.ERel 0, loc)]), loc)), loc),
+ (L'.EFfiApp ("Basis", "sqlifyString", [((L'.ERel 0, loc), (L'.TFfi ("Basis", "string"), loc))]), loc)), loc),
fm)
| L.ECApp ((L.EFfi ("Basis", "sql_prim"), _), t) =>
let
@@ -2430,26 +2435,26 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
| L.EFfi ("Basis", "sql_no_limit") =>
((L'.EPrim (Prim.String ""), loc), fm)
- | L.EFfiApp ("Basis", "sql_limit", [e]) =>
+ | L.EFfiApp ("Basis", "sql_limit", [(e, t)]) =>
let
val (e, fm) = monoExp (env, st, fm) e
in
(strcat [
(L'.EPrim (Prim.String " LIMIT "), loc),
- (L'.EFfiApp ("Basis", "sqlifyInt", [e]), loc)
+ (L'.EFfiApp ("Basis", "sqlifyInt", [(e, monoType env t)]), loc)
],
fm)
end
| L.EFfi ("Basis", "sql_no_offset") =>
((L'.EPrim (Prim.String ""), loc), fm)
- | L.EFfiApp ("Basis", "sql_offset", [e]) =>
+ | L.EFfiApp ("Basis", "sql_offset", [(e, t)]) =>
let
val (e, fm) = monoExp (env, st, fm) e
in
(strcat [
(L'.EPrim (Prim.String " OFFSET "), loc),
- (L'.EFfiApp ("Basis", "sqlifyInt", [e]), loc)
+ (L'.EFfiApp ("Basis", "sqlifyInt", [(e, monoType env t)]), loc)
],
fm)
end
@@ -2914,13 +2919,13 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
fm)
end
- | L.EFfiApp ("Basis", "nextval", [e]) =>
+ | L.EFfiApp ("Basis", "nextval", [(e, _)]) =>
let
val (e, fm) = monoExp (env, st, fm) e
in
((L'.ENextval e, loc), fm)
end
- | L.EFfiApp ("Basis", "setval", [e1, e2]) =>
+ | L.EFfiApp ("Basis", "setval", [(e1, _), (e2, _)]) =>
let
val (e1, fm) = monoExp (env, st, fm) e1
val (e2, fm) = monoExp (env, st, fm) e2
@@ -2930,7 +2935,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
| L.EFfi ("Basis", "null") => ((L'.EPrim (Prim.String ""), loc), fm)
- | L.EFfiApp ("Basis", "classes", [s1, s2]) =>
+ | L.EFfiApp ("Basis", "classes", [(s1, _), (s2, _)]) =>
let
val (s1, fm) = monoExp (env, st, fm) s1
val (s2, fm) = monoExp (env, st, fm) s2
@@ -2947,13 +2952,13 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
let
val (se, fm) = monoExp (env, st, fm) se
in
- ((L'.EFfiApp ("Basis", "htmlifyString", [se]), loc), fm)
+ ((L'.EFfiApp ("Basis", "htmlifyString", [(se, (L'.TFfi ("Basis", "string"), loc))]), loc), fm)
end
| L.ECApp (
(L.ECApp ((L.EFfi ("Basis", "cdataChar"), _), _), _),
_) =>
((L'.EAbs ("ch", (L'.TFfi ("Basis", "char"), loc), (L'.TFfi ("Basis", "string"), loc),
- (L'.EFfiApp ("Basis", "htmlifySpecialChar", [(L'.ERel 0, loc)]), loc)), loc), fm)
+ (L'.EFfiApp ("Basis", "htmlifySpecialChar", [((L'.ERel 0, loc), (L'.TFfi ("Basis", "char"), loc))]), loc)), loc), fm)
| L.EApp (
(L.EApp (
@@ -3010,7 +3015,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
fun getTag (e, _) =
case e of
- L.EFfiApp ("Basis", tag, [(L.ERecord [], _)]) => (tag, [])
+ L.EFfiApp ("Basis", tag, [((L.ERecord [], _), _)]) => (tag, [])
| L.EApp (e, (L.ERecord [], _)) => getTag' e
| _ => (E.errorAt loc "Non-constant XML tag";
Print.eprefaces' [("Expression", CorePrint.p_exp env tag)];
@@ -3297,17 +3302,20 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
"body" => let
val onload = execify onload
val onunload = execify onunload
+ val s = (L'.TFfi ("Basis", "string"), loc)
in
normal ("body",
SOME (L'.EStrcat ((L'.EFfiApp ("Basis", "maybe_onload",
- [(L'.EStrcat ((L'.EFfiApp ("Basis", "get_settings",
- [(L'.ERecord [], loc)]), loc),
- onload), loc)]),
+ [((L'.EStrcat ((L'.EFfiApp ("Basis", "get_settings",
+ [((L'.ERecord [], loc),
+ (L'.TRecord [], loc))]), loc),
+ onload), loc),
+ s)]),
loc),
(L'.EFfiApp ("Basis", "maybe_onunload",
- [onunload]),
+ [(onunload, s)]),
loc)), loc),
- SOME (L'.EFfiApp ("Basis", "get_script", [(L'.ERecord [], loc)]), loc))
+ SOME (L'.EFfiApp ("Basis", "get_script", [((L'.ERecord [], loc), (L'.TRecord [], loc))]), loc))
end
| "dyn" =>
@@ -3645,7 +3653,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
end
val sigName = getSigName ()
- val sigSet = (L'.EFfiApp ("Basis", "sigString", [(L'.ERecord [], loc)]), loc)
+ val sigSet = (L'.EFfiApp ("Basis", "sigString", [((L'.ERecord [], loc), (L'.TRecord [], loc))]), loc)
val sigSet = (L'.EStrcat ((L'.EPrim (Prim.String ("
+ | L.EFfiApp ("Basis", "url", [(e, _)]) =>
let
val (e, fm) = monoExp (env, st, fm) e
val (e, fm) = urlifyExp env fm (e, dummyTyp)
@@ -3815,7 +3823,12 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
| L.EFfi mx => ((L'.EFfi mx, loc), fm)
| L.EFfiApp (m, x, es) =>
let
- val (es, fm) = ListUtil.foldlMap (fn (e, fm) => monoExp (env, st, fm) e) fm es
+ val (es, fm) = ListUtil.foldlMap (fn ((e, t), fm) =>
+ let
+ val (e, fm) = monoExp (env, st, fm) e
+ in
+ ((e, monoType env t), fm)
+ end) fm es
in
((L'.EFfiApp (m, x, es), loc), fm)
end
@@ -4054,7 +4067,7 @@ fun monoDecl (env, fm) (all as (d, loc)) =
val xts = map (fn (x, t) => (monoName env x, monoType env t)) xts
val (e, fm) = monoExp (env, St.empty, fm) e
- val e = (L'.EFfiApp ("Basis", "viewify", [e]), loc)
+ val e = (L'.EFfiApp ("Basis", "viewify", [(e, t')]), loc)
in
SOME (Env.pushENamed env x n t NONE s,
fm,
@@ -4110,7 +4123,7 @@ fun monoDecl (env, fm) (all as (d, loc)) =
let
fun policies (e, fm) =
case #1 e of
- L.EFfiApp ("Basis", "also", [e1, e2]) =>
+ L.EFfiApp ("Basis", "also", [(e1, _), (e2, _)]) =>
let
val (ps1, fm) = policies (e1, fm)
val (ps2, fm) = policies (e2, fm)
@@ -4129,7 +4142,7 @@ fun monoDecl (env, fm) (all as (d, loc)) =
(e, L'.PolDelete)
| L.EApp ((L.ECApp ((L.ECApp ((L.EFfi ("Basis", "mayUpdate"), _), _), _), _), _), e) =>
(e, L'.PolUpdate)
- | L.EFfiApp ("Basis", "sendOwnIds", [e]) =>
+ | L.EFfiApp ("Basis", "sendOwnIds", [(e, _)]) =>
(e, L'.PolSequence)
| _ => (poly (); (e, L'.PolClient))
@@ -4186,7 +4199,7 @@ fun monoize env file =
fun expunger () =
let
- val target = (L'.EFfiApp ("Basis", "sqlifyClient", [(L'.ERel 0, loc)]), loc)
+ val target = (L'.EFfiApp ("Basis", "sqlifyClient", [((L'.ERel 0, loc), (L'.TFfi ("Basis", "client"), loc))]), loc)
fun doTable (tab, xts, e) =
case xts of
diff --git a/src/prepare.sml b/src/prepare.sml
index 1b7454dc..7f55959c 100644
--- a/src/prepare.sml
+++ b/src/prepare.sml
@@ -67,25 +67,25 @@ fun prepString (e, st) =
case #1 e of
EPrim (Prim.String s) =>
SOME (s :: ss, n)
- | EFfiApp ("Basis", "strcat", [e1, e2]) =>
+ | EFfiApp ("Basis", "strcat", [(e1, _), (e2, _)]) =>
(case prepString' (e1, ss, n) of
NONE => NONE
| SOME (ss, n) => prepString' (e2, ss, n))
- | EFfiApp ("Basis", "sqlifyInt", [e]) => doOne Int
- | EFfiApp ("Basis", "sqlifyFloat", [e]) => doOne Float
- | EFfiApp ("Basis", "sqlifyString", [e]) => doOne String
- | EFfiApp ("Basis", "sqlifyBool", [e]) => doOne Bool
- | EFfiApp ("Basis", "sqlifyTime", [e]) => doOne Time
- | EFfiApp ("Basis", "sqlifyBlob", [e]) => doOne Blob
- | EFfiApp ("Basis", "sqlifyChannel", [e]) => doOne Channel
- | EFfiApp ("Basis", "sqlifyClient", [e]) => doOne Client
+ | EFfiApp ("Basis", "sqlifyInt", [_]) => doOne Int
+ | EFfiApp ("Basis", "sqlifyFloat", [_]) => doOne Float
+ | EFfiApp ("Basis", "sqlifyString", [_]) => doOne String
+ | EFfiApp ("Basis", "sqlifyBool", [_]) => doOne Bool
+ | EFfiApp ("Basis", "sqlifyTime", [_]) => doOne Time
+ | EFfiApp ("Basis", "sqlifyBlob", [_]) => doOne Blob
+ | EFfiApp ("Basis", "sqlifyChannel", [_]) => doOne Channel
+ | EFfiApp ("Basis", "sqlifyClient", [_]) => doOne Client
| ECase (e,
[((PNone _, _),
(EPrim (Prim.String "NULL"), _)),
((PSome (_, (PVar _, _)), _),
- (EFfiApp (m, x, [(ERel 0, _)]), _))],
- _) => prepString' ((EFfiApp (m, x, [e]), #2 e), ss, n)
+ (EFfiApp (m, x, [((ERel 0, _), _)]), _))],
+ {disc = t, ...}) => prepString' ((EFfiApp (m, x, [(e, t)]), #2 e), ss, n)
| ECase (e,
[((PCon (_, PConFfi {mod = "Basis", con = "True", ...}, _), _),
@@ -130,7 +130,12 @@ fun prepExp (e as (_, loc), st) =
| EFfi _ => (e, st)
| EFfiApp (m, x, es) =>
let
- val (es, st) = ListUtil.foldlMap prepExp st es
+ val (es, st) = ListUtil.foldlMap (fn ((e, t), st) =>
+ let
+ val (e, st) = prepExp (e, st)
+ in
+ ((e, t), st)
+ end) st es
in
((EFfiApp (m, x, es), loc), st)
end
@@ -260,9 +265,10 @@ fun prepExp (e as (_, loc), st) =
(EPrim (Prim.String ("SELECT NEXTVAL('" ^ s ^ "')")), loc)
| _ =>
let
- val s' = (EFfiApp ("Basis", "strcat", [seq, (EPrim (Prim.String "')"), loc)]), loc)
+ val t = (TFfi ("Basis", "string"), loc)
+ val s' = (EFfiApp ("Basis", "strcat", [(seq, t), ((EPrim (Prim.String "')"), loc), t)]), loc)
in
- (EFfiApp ("Basis", "strcat", [(EPrim (Prim.String "SELECT NEXTVAL('"), loc), s']), loc)
+ (EFfiApp ("Basis", "strcat", [((EPrim (Prim.String "SELECT NEXTVAL('"), loc), t), (s', t)]), loc)
end
in
case prepString (s, st) of
diff --git a/src/reduce.sml b/src/reduce.sml
index 9371e9bd..1fbf526d 100644
--- a/src/reduce.sml
+++ b/src/reduce.sml
@@ -493,7 +493,7 @@ fun kindConAndExp (namedC, namedE) =
bindType (CFfi ("Basis", "signal"), loc) loc)], loc)
| EFfi _ => all
- | EFfiApp (m, f, es) => (EFfiApp (m, f, map (exp env) es), loc)
+ | EFfiApp (m, f, es) => (EFfiApp (m, f, map (fn (e, t) => (exp env e, con env t)) es), loc)
(*| EApp (
(EApp
diff --git a/src/reduce_local.sml b/src/reduce_local.sml
index 0e87e34a..a6e4f7fc 100644
--- a/src/reduce_local.sml
+++ b/src/reduce_local.sml
@@ -256,7 +256,7 @@ fun exp env (all as (e, loc)) =
| ENamed _ => all
| ECon (dk, pc, cs, eo) => (ECon (dk, patCon pc, map (con env) cs, Option.map (exp env) eo), loc)
| EFfi _ => all
- | EFfiApp (m, f, es) => (EFfiApp (m, f, map (exp env) es), loc)
+ | EFfiApp (m, f, es) => (EFfiApp (m, f, map (fn (e, t) => (exp env e, con env t)) es), loc)
| EApp (e1, e2) =>
let
diff --git a/src/scriptcheck.sml b/src/scriptcheck.sml
index 129f4281..6c6c5588 100644
--- a/src/scriptcheck.sml
+++ b/src/scriptcheck.sml
@@ -92,12 +92,12 @@ fun classify (ds, ps) =
| EFfi ("Basis", x) => SS.member (basis, x)
| EFfi _ => false
| EFfiApp ("Basis", "maybe_onload",
- [(EFfiApp ("Basis", "strcat", all as [_, (EPrim (Prim.String s), _)]), _)]) =>
- List.exists hasClient all
+ [((EFfiApp ("Basis", "strcat", all as [_, ((EPrim (Prim.String s), _), _)]), _), _)]) =>
+ List.exists (hasClient o #1) all
orelse (onload andalso size s > 0)
| EFfiApp ("Basis", x, es) => SS.member (basis, x)
- orelse List.exists hasClient es
- | EFfiApp (_, _, es) => List.exists hasClient es
+ orelse List.exists (hasClient o #1) es
+ | EFfiApp (_, _, es) => List.exists (hasClient o #1) es
| EApp (e, es) => hasClient e orelse List.exists hasClient es
| EUnop (_, e) => hasClient e
| EBinop (_, e1, e2) => hasClient e1 orelse hasClient e2
diff --git a/src/tag.sml b/src/tag.sml
index 26c23586..6037cb17 100644
--- a/src/tag.sml
+++ b/src/tag.sml
@@ -170,22 +170,22 @@ fun exp env (e, s) =
end
| _ => (e, s))
- | EFfiApp ("Basis", "url", [(ERel 0, _)]) => (e, s)
+ | EFfiApp ("Basis", "url", [((ERel 0, _), _)]) => (e, s)
- | EFfiApp ("Basis", "url", [e]) =>
+ | EFfiApp ("Basis", "url", [(e, t)]) =>
let
val (e, s) = tagIt (e, Link, "Url", s)
in
- (EFfiApp ("Basis", "url", [e]), s)
+ (EFfiApp ("Basis", "url", [(e, t)]), s)
end
- | EFfiApp ("Basis", "effectfulUrl", [(ERel 0, _)]) => (e, s)
+ | EFfiApp ("Basis", "effectfulUrl", [((ERel 0, _), _)]) => (e, s)
- | EFfiApp ("Basis", "effectfulUrl", [e]) =>
+ | EFfiApp ("Basis", "effectfulUrl", [(e, t)]) =>
let
val (e, s) = tagIt (e, Extern ReadCookieWrite, "Url", s)
in
- (EFfiApp ("Basis", "url", [e]), s)
+ (EFfiApp ("Basis", "url", [(e, t)]), s)
end
| EApp ((ENamed n, _), e') =>
@@ -193,11 +193,11 @@ fun exp env (e, s) =
val (_, _, eo, _) = E.lookupENamed env n
in
case eo of
- SOME (EAbs (_, _, _, (EFfiApp ("Basis", "url", [(ERel 0, _)]), _)), _) =>
+ SOME (EAbs (_, _, _, (EFfiApp ("Basis", "url", [((ERel 0, _), t)]), _)), _) =>
let
val (e, s) = tagIt (e', Link, "Url", s)
in
- (EFfiApp ("Basis", "url", [e]), s)
+ (EFfiApp ("Basis", "url", [(e, t)]), s)
end
| _ => (e, s)
end
--
cgit v1.2.3
From 7e9bfe341668ef03fb3f5420eb11aa183ac30ea5 Mon Sep 17 00:00:00 2001
From: "Edward Z. Yang"
Date: Mon, 12 Mar 2012 12:00:13 -0700
Subject: Some minor documentation to the Mono AST.
---
src/mono.sml | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
(limited to 'src/mono.sml')
diff --git a/src/mono.sml b/src/mono.sml
index 2c83d1bc..65dc9abc 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -44,7 +44,7 @@ datatype typ' =
withtype typ = typ' located
datatype patCon =
- PConVar of int
+ PConVar of int (* constructor identifier *)
| PConFfi of {mod : string, datatyp : string, con : string, arg : typ option}
datatype pat' =
@@ -72,8 +72,8 @@ datatype binop_intness = Int | NotInt
datatype exp' =
EPrim of Prim.t
- | ERel of int
- | ENamed of int
+ | ERel of int (* deBruijn index *)
+ | ENamed of int (* named variable *)
| ECon of datatype_kind * patCon * exp option
| ENone of typ
| ESome of typ * exp
@@ -102,10 +102,11 @@ datatype exp' =
| EClosure of int * exp list
- | EQuery of { exps : (string * typ) list,
+ | EQuery of { exps : (string * typ) list, (* name of computed field, type of field*)
tables : (string * (string * typ) list) list,
state : typ,
- query : exp,
+ query : exp, (* exp of string type containing sql query
+ (after mono opt) *)
body : exp,
initial : exp }
| EDml of exp * failure_mode
--
cgit v1.2.3
From db4655954148bfbef6eab52cc810b0038c620528 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Tue, 13 Mar 2012 11:59:03 -0400
Subject: Remove seemingly inaccurate part of comment (perhaps clarified
version can be added back in later)
---
src/mono.sml | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
(limited to 'src/mono.sml')
diff --git a/src/mono.sml b/src/mono.sml
index 65dc9abc..4a0278fd 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -105,8 +105,7 @@ datatype exp' =
| EQuery of { exps : (string * typ) list, (* name of computed field, type of field*)
tables : (string * (string * typ) list) list,
state : typ,
- query : exp, (* exp of string type containing sql query
- (after mono opt) *)
+ query : exp, (* exp of string type containing sql query *)
body : exp,
initial : exp }
| EDml of exp * failure_mode
--
cgit v1.2.3
From 3d21914a4b831ee9c727dd4296e56961c1e4ea89 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Fri, 15 Mar 2013 16:09:55 -0400
Subject: Make Scriptcheck catch more script/message-passing uses, and move the
phase earlier in compilation
---
src/cjr.sml | 5 +-
src/cjrize.sml | 9 +++-
src/compiler.sig | 4 +-
src/compiler.sml | 18 ++++----
src/fuse.sml | 4 +-
src/iflow.sml | 6 +--
src/jscomp.sml | 8 ++--
src/mono.sml | 7 ++-
src/mono_print.sml | 2 +-
src/mono_reduce.sml | 4 +-
src/mono_shake.sml | 34 +++++++-------
src/mono_util.sml | 55 +++++++++++-----------
src/monoize.sml | 2 +-
src/name_js.sml | 6 +--
src/pathcheck.sml | 2 +-
src/scriptcheck.sig | 2 +-
src/scriptcheck.sml | 131 +++++++++++-----------------------------------------
src/untangle.sml | 4 +-
18 files changed, 119 insertions(+), 184 deletions(-)
(limited to 'src/mono.sml')
diff --git a/src/cjr.sml b/src/cjr.sml
index c348d01a..3a37b26f 100644
--- a/src/cjr.sml
+++ b/src/cjr.sml
@@ -128,10 +128,7 @@ datatype decl' =
withtype decl = decl' located
-datatype sidedness =
- ServerOnly
- | ServerAndPull
- | ServerAndPullAndPush
+datatype sidedness = datatype Mono.sidedness
datatype effect = datatype Export.effect
datatype export_kind = datatype Export.export_kind
diff --git a/src/cjrize.sml b/src/cjrize.sml
index 9e41fda4..0f4bdb42 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -694,7 +694,7 @@ fun cifyDecl ((d, loc), sm) =
| L.DPolicy _ => (NONE, NONE, sm)
| L.DOnError n => (SOME (L'.DOnError n, loc), NONE, sm)
-fun cjrize ds =
+fun cjrize (ds, sideInfo) =
let
val (dsF, ds, ps, sm) = foldl (fn (d, (dsF, ds, ps, sm)) =>
let
@@ -722,6 +722,13 @@ fun cjrize ds =
(dsF, ds, ps, Sm.clearDeclares sm)
end)
([], [], [], Sm.empty) ds
+
+ val sideInfo = foldl (fn ((n, mode), mp) => IM.insert (mp, n, mode)) IM.empty sideInfo
+
+ val ps = map (fn (ek, s, n, ts, t, _, b) =>
+ (ek, s, n, ts, t,
+ getOpt (IM.find (sideInfo, n), L'.ServerOnly),
+ b)) ps
in
(List.revAppend (dsF, rev ds),
ps)
diff --git a/src/compiler.sig b/src/compiler.sig
index 7e4f2f6a..fcf664eb 100644
--- a/src/compiler.sig
+++ b/src/compiler.sig
@@ -116,12 +116,12 @@ signature COMPILER = sig
val mono_shake : (Mono.file, Mono.file) phase
val iflow : (Mono.file, Mono.file) phase
val namejs : (Mono.file, Mono.file) phase
+ val scriptcheck : (Mono.file, Mono.file) phase
val jscomp : (Mono.file, Mono.file) phase
val fuse : (Mono.file, Mono.file) phase
val pathcheck : (Mono.file, Mono.file) phase
val sidecheck : (Mono.file, Mono.file) phase
val cjrize : (Mono.file, Cjr.file) phase
- val scriptcheck : (Cjr.file, Cjr.file) phase
val prepare : (Cjr.file, Cjr.file) phase
val checknest : (Cjr.file, Cjr.file) phase
val sqlify : (Mono.file, Cjr.file) phase
@@ -170,6 +170,7 @@ signature COMPILER = sig
val toIflow : (string, Mono.file) transform
val toNamejs : (string, Mono.file) transform
val toNamejs_untangle : (string, Mono.file) transform
+ val toScriptcheck : (string, Mono.file) transform
val toJscomp : (string, Mono.file) transform
val toMono_opt3 : (string, Mono.file) transform
val toFuse : (string, Mono.file) transform
@@ -184,7 +185,6 @@ signature COMPILER = sig
val toPathcheck : (string, Mono.file) transform
val toSidecheck : (string, Mono.file) transform
val toCjrize : (string, Cjr.file) transform
- val toScriptcheck : (string, Cjr.file) transform
val toPrepare : (string, Cjr.file) transform
val toChecknest : (string, Cjr.file) transform
val toSqlify : (string, Cjr.file) transform
diff --git a/src/compiler.sml b/src/compiler.sml
index f8dd07e2..77542811 100644
--- a/src/compiler.sml
+++ b/src/compiler.sml
@@ -1363,12 +1363,19 @@ val toNamejs = transform namejs "namejs" o toIflow
val toNamejs_untangle = transform untangle "namejs_untangle" o toNamejs
+val scriptcheck = {
+ func = ScriptCheck.classify,
+ print = MonoPrint.p_file MonoEnv.empty
+}
+
+val toScriptcheck = transform scriptcheck "scriptcheck" o toNamejs_untangle
+
val jscomp = {
func = JsComp.process,
print = MonoPrint.p_file MonoEnv.empty
}
-val toJscomp = transform jscomp "jscomp" o toNamejs_untangle
+val toJscomp = transform jscomp "jscomp" o toScriptcheck
val toMono_opt3 = transform mono_opt "mono_opt3" o toJscomp
@@ -1410,19 +1417,12 @@ val cjrize = {
val toCjrize = transform cjrize "cjrize" o toSidecheck
-val scriptcheck = {
- func = ScriptCheck.classify,
- print = CjrPrint.p_file CjrEnv.empty
-}
-
-val toScriptcheck = transform scriptcheck "scriptcheck" o toCjrize
-
val prepare = {
func = Prepare.prepare,
print = CjrPrint.p_file CjrEnv.empty
}
-val toPrepare = transform prepare "prepare" o toScriptcheck
+val toPrepare = transform prepare "prepare" o toCjrize
val checknest = {
func = fn f => if #supportsNestedPrepared (Settings.currentDbms ()) then f else Checknest.annotate f,
diff --git a/src/fuse.sml b/src/fuse.sml
index 565fc591..5193e59a 100644
--- a/src/fuse.sml
+++ b/src/fuse.sml
@@ -144,9 +144,9 @@ fun fuse file =
(funcs, maxName))
end
- val (file, _) = ListUtil.foldlMap doDecl (IM.empty, U.File.maxName file + 1) file
+ val (ds, _) = ListUtil.foldlMap doDecl (IM.empty, U.File.maxName file + 1) (#1 file)
in
- file
+ (ds, #2 file)
end
end
diff --git a/src/iflow.sml b/src/iflow.sml
index fe0be731..8c933dc4 100644
--- a/src/iflow.sml
+++ b/src/iflow.sml
@@ -1795,7 +1795,7 @@ fun evalExp env (e as (_, loc)) k =
datatype var_source = Input of int | SubInput of int | Unknown
-fun check file =
+fun check (file : file) =
let
val () = (St.reset ();
rfuns := IM.empty)
@@ -1810,7 +1810,7 @@ fun check file =
val exptd = foldl (fn ((d, _), exptd) =>
case d of
DExport (_, _, n, _, _, _) => IS.add (exptd, n)
- | _ => exptd) IS.empty file
+ | _ => exptd) IS.empty (#1 file)
fun decl (d, loc) =
case d of
@@ -2071,7 +2071,7 @@ fun check file =
| _ => ()
in
- app decl file
+ app decl (#1 file)
end
val check = fn file =>
diff --git a/src/jscomp.sml b/src/jscomp.sml
index ea34a3b5..ffb68ab2 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -61,7 +61,7 @@ exception CantEmbed of typ
fun inString {needle, haystack} = String.isSubstring needle haystack
-fun process file =
+fun process (file : file) =
let
val (someTs, nameds) =
foldl (fn ((DVal (_, n, t, e, _), _), (someTs, nameds)) => (someTs, IM.insert (nameds, n, e))
@@ -77,7 +77,7 @@ fun process file =
someTs) someTs dts,
nameds)
| (_, state) => state)
- (IM.empty, IM.empty) file
+ (IM.empty, IM.empty) (#1 file)
fun str loc s = (EPrim (Prim.String s), loc)
@@ -1304,7 +1304,7 @@ fun process file =
listInjectors = TM.empty,
decoders = IM.empty,
maxName = U.File.maxName file + 1}
- file
+ (#1 file)
val inf = TextIO.openIn (OS.Path.joinDirFile {dir = Settings.libJs (), file = "urweb.js"})
fun lines acc =
@@ -1334,7 +1334,7 @@ fun process file =
""
in
TextIO.closeIn inf;
- (DJavaScript script, ErrorMsg.dummySpan) :: ds
+ ((DJavaScript script, ErrorMsg.dummySpan) :: ds, #2 file)
end
end
diff --git a/src/mono.sml b/src/mono.sml
index 4a0278fd..f269c52d 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -157,6 +157,11 @@ datatype decl' =
withtype decl = decl' located
-type file = decl list
+datatype sidedness =
+ ServerOnly
+ | ServerAndPull
+ | ServerAndPullAndPush
+
+type file = decl list * (int * sidedness) list
end
diff --git a/src/mono_print.sml b/src/mono_print.sml
index e5ef4cf8..12b36f2a 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -530,7 +530,7 @@ fun p_decl env (dAll as (d, _) : decl) =
p_policy env p]
| DOnError _ => string "ONERROR"
-fun p_file env file =
+fun p_file env (file, _) =
let
val (pds, _) = ListUtil.foldlMap (fn (d, env) =>
(p_decl env d,
diff --git a/src/mono_reduce.sml b/src/mono_reduce.sml
index 71c87095..e7fac5ed 100644
--- a/src/mono_reduce.sml
+++ b/src/mono_reduce.sml
@@ -308,7 +308,7 @@ val freeInAbs = U.Exp.existsB {typ = fn _ => false,
U.Exp.RelE _ => n + 1
| _ => n} 0
-fun reduce file =
+fun reduce (file : file) =
let
val (timpures, impures, absCounts) =
foldl (fn ((d, _), (timpures, impures, absCounts)) =>
@@ -366,7 +366,7 @@ fun reduce file =
absCounts vis)
| _ => (timpures, impures, absCounts)
end)
- (IS.empty, IS.empty, IM.empty) file
+ (IS.empty, IS.empty, IM.empty) (#1 file)
val uses = U.File.fold {typ = fn (_, m) => m,
exp = fn (e, m) =>
diff --git a/src/mono_shake.sml b/src/mono_shake.sml
index b6de9410..5818fea0 100644
--- a/src/mono_shake.sml
+++ b/src/mono_shake.sml
@@ -41,7 +41,7 @@ type free = {
exp : IS.set
}
-fun shake file =
+fun shake (file : file) =
let
val (cdef, edef) = foldl (fn ((DDatatype dts, _), (cdef, edef)) =>
(foldl (fn ((_, n, xncs), cdef) => IM.insert (cdef, n, xncs)) cdef dts, edef)
@@ -60,7 +60,7 @@ fun shake file =
| ((DTask _, _), acc) => acc
| ((DPolicy _, _), acc) => acc
| ((DOnError _, _), acc) => acc)
- (IM.empty, IM.empty) file
+ (IM.empty, IM.empty) (#1 file)
fun typ (c, s) =
case c of
@@ -130,7 +130,7 @@ fun shake file =
usedVars st e1
end
| ((DOnError n, _), (page_cs, page_es)) => (page_cs, IS.add (page_es, n))
- | (_, st) => st) (IS.empty, IS.empty) file
+ | (_, st) => st) (IS.empty, IS.empty) (#1 file)
val s = {con = page_cs, exp = page_es}
@@ -145,20 +145,20 @@ fun shake file =
NONE => raise Fail "MonoShake: Couldn't find 'val'"
| SOME (t, e) => shakeExp s e) s page_es
in
- List.filter (fn (DDatatype dts, _) => List.exists (fn (_, n, _) => IS.member (#con s, n)) dts
- | (DVal (_, n, _, _, _), _) => IS.member (#exp s, n)
- | (DValRec vis, _) => List.exists (fn (_, n, _, _, _) => IS.member (#exp s, n)) vis
- | (DExport _, _) => true
- | (DTable _, _) => true
- | (DSequence _, _) => true
- | (DView _, _) => true
- | (DDatabase _, _) => true
- | (DJavaScript _, _) => true
- | (DCookie _, _) => true
- | (DStyle _, _) => true
- | (DTask _, _) => true
- | (DPolicy _, _) => true
- | (DOnError _, _) => true) file
+ (List.filter (fn (DDatatype dts, _) => List.exists (fn (_, n, _) => IS.member (#con s, n)) dts
+ | (DVal (_, n, _, _, _), _) => IS.member (#exp s, n)
+ | (DValRec vis, _) => List.exists (fn (_, n, _, _, _) => IS.member (#exp s, n)) vis
+ | (DExport _, _) => true
+ | (DTable _, _) => true
+ | (DSequence _, _) => true
+ | (DView _, _) => true
+ | (DDatabase _, _) => true
+ | (DJavaScript _, _) => true
+ | (DCookie _, _) => true
+ | (DStyle _, _) => true
+ | (DTask _, _) => true
+ | (DPolicy _, _) => true
+ | (DOnError _, _) => true) (#1 file), #2 file)
end
end
diff --git a/src/mono_util.sml b/src/mono_util.sml
index 58498996..61638858 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -664,9 +664,9 @@ fun mapfoldB (all as {bind, ...}) =
let
val mfd = Decl.mapfoldB all
- fun mff ctx ds =
+ fun mff ctx (ds, ps) =
case ds of
- nil => S.return2 nil
+ nil => S.return2 (nil, ps)
| d :: ds' =>
S.bind2 (mfd ctx d,
fn d' =>
@@ -705,9 +705,9 @@ fun mapfoldB (all as {bind, ...}) =
| DPolicy _ => ctx
| DOnError _ => ctx
in
- S.map2 (mff ctx' ds',
- fn ds' =>
- d' :: ds')
+ S.map2 (mff ctx' (ds', ps),
+ fn (ds', _) =>
+ (d' :: ds', ps))
end)
in
mff
@@ -741,27 +741,28 @@ fun fold {typ, exp, decl} s d =
S.Continue (_, s) => s
| S.Return _ => raise Fail "MonoUtil.File.fold: Impossible"
-val maxName = foldl (fn ((d, _) : decl, count) =>
- case d of
- DDatatype dts =>
- foldl (fn ((_, n, ns), count) =>
- foldl (fn ((_, n', _), m) => Int.max (n', m))
- (Int.max (n, count)) ns) count dts
- | DVal (_, n, _, _, _) => Int.max (n, count)
- | DValRec vis => foldl (fn ((_, n, _, _, _), count) => Int.max (n, count)) count vis
- | DExport _ => count
- | DTable _ => count
- | DSequence _ => count
- | DView _ => count
- | DDatabase _ => count
- | DJavaScript _ => count
- | DCookie _ => count
- | DStyle _ => count
- | DTask _ => count
- | DPolicy _ => count
- | DOnError _ => count) 0
-
-fun appLoc f =
+fun maxName (f : file) =
+ foldl (fn ((d, _) : decl, count) =>
+ case d of
+ DDatatype dts =>
+ foldl (fn ((_, n, ns), count) =>
+ foldl (fn ((_, n', _), m) => Int.max (n', m))
+ (Int.max (n, count)) ns) count dts
+ | DVal (_, n, _, _, _) => Int.max (n, count)
+ | DValRec vis => foldl (fn ((_, n, _, _, _), count) => Int.max (n, count)) count vis
+ | DExport _ => count
+ | DTable _ => count
+ | DSequence _ => count
+ | DView _ => count
+ | DDatabase _ => count
+ | DJavaScript _ => count
+ | DCookie _ => count
+ | DStyle _ => count
+ | DTask _ => count
+ | DPolicy _ => count
+ | DOnError _ => count) 0 (#1 f)
+
+fun appLoc f (fl : file) =
let
val eal = Exp.appLoc f
@@ -790,7 +791,7 @@ fun appLoc f =
| PolUpdate e1 => eal e1
| PolSequence e1 => eal e1
in
- app appl
+ app appl (#1 fl)
end
end
diff --git a/src/monoize.sml b/src/monoize.sml
index e07c0c90..ce7bfbe9 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -4656,7 +4656,7 @@ fun monoize env file =
pvars := RM.empty;
pvarDefs := [];
pvarOldDefs := [];
- rev ds
+ (rev ds, [])
end
end
diff --git a/src/name_js.sml b/src/name_js.sml
index 70ac000c..53abd7a3 100644
--- a/src/name_js.sml
+++ b/src/name_js.sml
@@ -72,7 +72,7 @@ fun squish vs = U.Exp.mapB {typ = fn x => x,
fun rewrite file =
let
- val (file, _) = ListUtil.foldlMapConcat (fn (d, nextName) =>
+ val (ds, _) = ListUtil.foldlMapConcat (fn (d, nextName) =>
let
val (d, (nextName, newDs)) =
U.Decl.foldMapB {typ = fn x => x,
@@ -143,9 +143,9 @@ fun rewrite file =
DValRec vis => [(DValRec (vis @ newDs), #2 d)]
| _ => List.revAppend (map (fn vi => (DVal vi, #2 d)) newDs, [d]),
nextName)
- end) (U.File.maxName file + 1) file
+ end) (U.File.maxName file + 1) (#1 file)
in
- file
+ (ds, #2 file)
end
end
diff --git a/src/pathcheck.sml b/src/pathcheck.sml
index 15405db7..c1bb667b 100644
--- a/src/pathcheck.sml
+++ b/src/pathcheck.sml
@@ -110,6 +110,6 @@ fun checkDecl ((d, loc), (funcs, rels, cookies, styles)) =
| _ => (funcs, rels, cookies, styles)
end
-fun check ds = ignore (foldl checkDecl (SS.empty, SS.empty, SS.empty, SS.empty) ds)
+fun check (ds, _) = ignore (foldl checkDecl (SS.empty, SS.empty, SS.empty, SS.empty) ds)
end
diff --git a/src/scriptcheck.sig b/src/scriptcheck.sig
index bc9b6377..afb557b7 100644
--- a/src/scriptcheck.sig
+++ b/src/scriptcheck.sig
@@ -27,6 +27,6 @@
signature SCRIPT_CHECK = sig
- val classify : Cjr.file -> Cjr.file
+ val classify : Mono.file -> Mono.file
end
diff --git a/src/scriptcheck.sml b/src/scriptcheck.sml
index 6c6c5588..e5db476a 100644
--- a/src/scriptcheck.sml
+++ b/src/scriptcheck.sml
@@ -27,7 +27,7 @@
structure ScriptCheck :> SCRIPT_CHECK = struct
-open Cjr
+open Mono
structure SS = BinarySetFn(struct
type ord_key = string
@@ -35,98 +35,31 @@ structure SS = BinarySetFn(struct
end)
structure IS = IntBinarySet
-val pullBasis = SS.addList (SS.empty,
- ["new_client_source",
- "get_client_source",
- "set_client_source"])
-
val pushBasis = SS.addList (SS.empty,
["new_channel",
"self"])
-val events = ["abort",
- "blur",
- "change",
- "click",
- "dblclick",
- "error",
- "focus",
- "keydown",
- "keypress",
- "keyup",
- "load",
- "mousedown",
- "mousemove",
- "mouseout",
- "mouseover",
- "mouseup",
- "reset",
- "resize",
- "select",
- "submit",
- "unload"]
-
-val scriptWords = "