From d321a012ed51bf14ce6271198ccb29784efb7bd5 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Thu, 30 Oct 2008 14:36:48 -0400
Subject: time type
---
src/mono_opt.sml | 7 +++++++
1 file changed, 7 insertions(+)
(limited to 'src/mono_opt.sml')
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index 843bdf90..8d11fe1a 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -197,6 +197,13 @@ fun exp e =
| 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])
+ | EWrite (EFfiApp ("Basis", "htmlifyTime", [e]), _) =>
+ EFfiApp ("Basis", "htmlifyTime_w", [e])
+
| EFfiApp ("Basis", "htmlifyString", [(EPrim (Prim.String s), _)]) =>
EPrim (Prim.String (htmlifyString s))
| EWrite (EFfiApp ("Basis", "htmlifyString", [(EPrim (Prim.String s), _)]), loc) =>
--
cgit v1.2.3
From 36a9df5f71b954949b92520c6e472548aa5ebfb1 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sat, 1 Nov 2008 16:50:28 -0400
Subject: Remove empty writes
---
src/mono_opt.sml | 3 +++
1 file changed, 3 insertions(+)
(limited to 'src/mono_opt.sml')
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index 8d11fe1a..3cf2bcd4 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -311,6 +311,9 @@ fun exp e =
| EWrite (ELet (x, t, e1, e2), loc) =>
optExp (ELet (x, t, e1, (EWrite e2, loc)), loc)
+ | EWrite (EPrim (Prim.String ""), loc) =>
+ ERecord []
+
| _ => e
and optExp e = #1 (U.Exp.map {typ = typ, exp = exp} e)
--
cgit v1.2.3
From 047a2f193646e08db526768dca8376b7270eecb5 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sat, 1 Nov 2008 21:19:43 -0400
Subject: Almost have that nested save function compiling
---
src/cjrize.sml | 19 ++++---
src/core_util.sml | 2 +-
src/elab_util.sml | 21 +++++---
src/especialize.sml | 149 +++++++++++++++++++++++++++++++++++++---------------
src/expl_print.sml | 1 +
src/expl_util.sml | 2 +-
src/mono_opt.sml | 15 +++++-
src/mono_reduce.sig | 4 +-
src/shake.sml | 28 +++++++---
src/sources | 6 +--
src/termination.sml | 10 +++-
src/unnest.sml | 35 +++++++-----
tests/blog.ur | 16 ++++++
tests/blog.urp | 4 ++
tests/blog.urs | 1 +
tests/nest.ur | 22 +++++++-
tests/nest2.ur | 15 ++++++
tests/nest2.urp | 3 ++
18 files changed, 268 insertions(+), 85 deletions(-)
create mode 100644 tests/blog.ur
create mode 100644 tests/blog.urp
create mode 100644 tests/blog.urs
create mode 100644 tests/nest2.ur
create mode 100644 tests/nest2.urp
(limited to 'src/mono_opt.sml')
diff --git a/src/cjrize.sml b/src/cjrize.sml
index 05ceb0f9..db2bd48f 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -39,6 +39,7 @@ structure Sm :> sig
val find : t * (string * L.typ) list * (string * L'.typ) list -> t * int
val declares : t -> (int * (string * L'.typ) list) list
+ val clearDeclares : t -> t
end = struct
structure FM = BinaryMapFn(struct
@@ -61,6 +62,8 @@ fun find ((n, m, ds), xts, xts') =
fun declares (_, _, ds) = ds
+fun clearDeclares (n, m, _) = (n, m, [])
+
end
fun cifyTyp x =
@@ -520,23 +523,25 @@ fun cjrize ds =
val (dsF, ds, ps, sm) = foldl (fn (d, (dsF, ds, ps, sm)) =>
let
val (dop, pop, sm) = cifyDecl (d, sm)
+
val (dsF, ds) = case dop of
NONE => (dsF, ds)
- | SOME (d as (L'.DDatatype (dk, x, n, _), loc)) =>
- ((L'.DDatatypeForward (dk, x, n), loc) :: dsF,
- d :: ds)
+ | SOME (d as (L'.DDatatype _, loc)) =>
+ (d :: dsF, ds)
| SOME d => (dsF, d :: ds)
+
+ val dsF = map (fn v => (L'.DStruct v, ErrorMsg.dummySpan)) (Sm.declares sm)
+ @ dsF
+
val ps = case pop of
NONE => ps
| SOME p => p :: ps
in
- (dsF, ds, ps, sm)
+ (dsF, ds, ps, Sm.clearDeclares sm)
end)
([], [], [], Sm.empty) ds
in
- (List.revAppend (dsF,
- List.revAppend (map (fn v => (L'.DStruct v, ErrorMsg.dummySpan)) (Sm.declares sm),
- rev ds)),
+ (List.revAppend (dsF, rev ds),
ps)
end
diff --git a/src/core_util.sml b/src/core_util.sml
index 2a690736..2450562f 100644
--- a/src/core_util.sml
+++ b/src/core_util.sml
@@ -492,7 +492,7 @@ fun mapfoldB {kind = fk, con = fc, exp = fe, bind} =
fn t' =>
S.bind2 (mfe ctx e1,
fn e1' =>
- S.map2 (mfe ctx e2,
+ S.map2 (mfe (bind (ctx, RelE (x, t'))) e2,
fn e2' =>
(ELet (x, t', e1', e2'), loc))))
diff --git a/src/elab_util.sml b/src/elab_util.sml
index 2e190d1e..57a94486 100644
--- a/src/elab_util.sml
+++ b/src/elab_util.sml
@@ -375,14 +375,19 @@ fun mapfoldB {kind = fk, con = fc, exp = fe, bind} =
| ELet (des, e) =>
let
val (des, ctx) = foldl (fn (ed, (des, ctx)) =>
- (S.bind2 (des,
- fn des' =>
- S.map2 (mfed ctx ed,
+ let
+ val ctx' =
+ case #1 ed of
+ EDVal (x, t, _) => bind (ctx, RelE (x, t))
+ | EDValRec vis =>
+ foldl (fn ((x, t, _), ctx) => bind (ctx, RelE (x, t))) ctx vis
+ in
+ (S.bind2 (des,
+ fn des' =>
+ S.map2 (mfed ctx ed,
fn ed' => des' @ [ed'])),
- case #1 ed of
- EDVal (x, t, _) => bind (ctx, RelE (x, t))
- | EDValRec vis =>
- foldl (fn ((x, t, _), env) => bind (ctx, RelE (x, t))) ctx vis))
+ ctx')
+ end)
(S.return2 [], ctx) des
in
S.bind2 (des,
@@ -400,7 +405,7 @@ fun mapfoldB {kind = fk, con = fc, exp = fe, bind} =
(EDVal vi', loc))
| EDValRec vis =>
let
- val ctx = foldl (fn ((x, t, _), env) => bind (ctx, RelE (x, t))) ctx vis
+ val ctx = foldl (fn ((x, t, _), ctx) => bind (ctx, RelE (x, t))) ctx vis
in
S.map2 (ListUtil.mapfold (mfvi ctx) vis,
fn vis' =>
diff --git a/src/especialize.sml b/src/especialize.sml
index b2f0c7e6..d5e93680 100644
--- a/src/especialize.sml
+++ b/src/especialize.sml
@@ -32,17 +32,43 @@ open Core
structure E = CoreEnv
structure U = CoreUtil
-structure ILK = struct
-type ord_key = int list
-val compare = Order.joinL Int.compare
+datatype skey =
+ Named of int
+ | App of skey * skey
+
+structure K = struct
+type ord_key = skey list
+fun compare' (k1, k2) =
+ case (k1, k2) of
+ (Named n1, Named n2) => Int.compare (n1, n2)
+ | (Named _, _) => LESS
+ | (_, Named _) => GREATER
+
+ | (App (x1, y1), App (x2, y2)) => Order.join (compare' (x1, x2), fn () => compare' (y1, y2))
+
+val compare = Order.joinL compare'
end
-structure ILM = BinaryMapFn(ILK)
+structure KM = BinaryMapFn(K)
structure IM = IntBinaryMap
+fun skeyIn (e, _) =
+ case e of
+ ENamed n => SOME (Named n)
+ | EApp (e1, e2) =>
+ (case (skeyIn e1, skeyIn e2) of
+ (SOME k1, SOME k2) => SOME (App (k1, k2))
+ | _ => NONE)
+ | _ => NONE
+
+fun skeyOut (k, loc) =
+ case k of
+ Named n => (ENamed n, loc)
+ | App (k1, k2) => (EApp (skeyOut (k1, loc), skeyOut (k2, loc)), loc)
+
type func = {
name : string,
- args : int ILM.map,
+ args : int KM.map,
body : exp,
typ : con,
tag : string
@@ -62,14 +88,21 @@ fun exp (e, st : state) =
fun getApp e =
case e of
ENamed f => SOME (f, [], [])
- | EApp (e1, (ENamed x, _)) =>
- (case getApp (#1 e1) of
- NONE => NONE
- | SOME (f, xs, xs') => SOME (f, xs @ [x], xs'))
| EApp (e1, e2) =>
(case getApp (#1 e1) of
NONE => NONE
- | SOME (f, xs, xs') => SOME (f, xs, xs' @ [e2]))
+ | SOME (f, xs, xs') =>
+ let
+ val k =
+ if List.null xs' then
+ skeyIn e2
+ else
+ NONE
+ in
+ case k of
+ NONE => SOME (f, xs, xs' @ [e2])
+ | SOME k => SOME (f, xs @ [k], xs')
+ end)
| _ => NONE
in
case getApp e of
@@ -77,21 +110,30 @@ fun exp (e, st : state) =
| SOME (_, [], _) => (e, st)
| SOME (f, xs, xs') =>
case IM.find (#funcs st, f) of
- NONE => (e, st)
+ NONE => ((*print "SHOT DOWN!\n";*) (e, st))
| SOME {name, args, body, typ, tag} =>
- case ILM.find (args, xs) of
- SOME f' => (#1 (foldl (fn (e, arg) => (EApp (e, arg), ErrorMsg.dummySpan))
- (ENamed f', ErrorMsg.dummySpan) xs'),
- st)
+ case KM.find (args, xs) of
+ SOME f' => ((*Print.prefaces "Pre-existing" [("e", CorePrint.p_exp CoreEnv.empty (e, ErrorMsg.dummySpan))];*)
+ (#1 (foldl (fn (e, arg) => (EApp (e, arg), ErrorMsg.dummySpan))
+ (ENamed f', ErrorMsg.dummySpan) xs'),
+ st))
| NONE =>
let
+ (*val () = Print.prefaces "New" [("e", CorePrint.p_exp CoreEnv.empty (e, ErrorMsg.dummySpan))]*)
+
fun subBody (body, typ, xs) =
case (#1 body, #1 typ, xs) of
(_, _, []) => SOME (body, typ)
| (EAbs (_, _, _, body'), TFun (_, typ'), x :: xs) =>
- subBody (E.subExpInExp (0, (ENamed x, ErrorMsg.dummySpan)) body',
- typ',
- xs)
+ let
+ val body'' = E.subExpInExp (0, skeyOut (x, #2 body)) body'
+ in
+ (*Print.prefaces "espec" [("body'", CorePrint.p_exp CoreEnv.empty body'),
+ ("body''", CorePrint.p_exp CoreEnv.empty body'')];*)
+ subBody (body'',
+ typ',
+ xs)
+ end
| _ => NONE
in
case subBody (body, typ, xs) of
@@ -99,8 +141,9 @@ fun exp (e, st : state) =
| SOME (body', typ') =>
let
val f' = #maxName st
+ (*val () = print ("f' = " ^ Int.toString f' ^ "\n")*)
val funcs = IM.insert (#funcs st, f, {name = name,
- args = ILM.insert (args, xs, f'),
+ args = KM.insert (args, xs, f'),
body = body,
typ = typ,
tag = tag})
@@ -128,10 +171,27 @@ fun decl (d, st) = (d, st)
val specDecl = U.Decl.foldMap {kind = kind, con = con, exp = exp, decl = decl}
-fun specialize file =
+fun specialize' file =
let
- fun doDecl (d, st) =
+ fun doDecl (d, (st : state, changed)) =
let
+ val funcs = #funcs st
+ val funcs =
+ case #1 d of
+ DValRec vis =>
+ foldl (fn ((x, n, c, e, tag), funcs) =>
+ IM.insert (funcs, n, {name = x,
+ args = KM.empty,
+ body = e,
+ typ = c,
+ tag = tag}))
+ funcs vis
+ | _ => funcs
+
+ val st = {maxName = #maxName st,
+ funcs = funcs,
+ decls = []}
+
val (d', st) = specDecl st d
val funcs = #funcs st
@@ -139,37 +199,42 @@ fun specialize file =
case #1 d of
DVal (x, n, c, e as (EAbs _, _), tag) =>
IM.insert (funcs, n, {name = x,
- args = ILM.empty,
+ args = KM.empty,
body = e,
typ = c,
tag = tag})
- | DValRec vis =>
- foldl (fn ((x, n, c, e, tag), funcs) =>
- IM.insert (funcs, n, {name = x,
- args = ILM.empty,
- body = e,
- typ = c,
- tag = tag}))
- funcs vis
| _ => funcs
- val ds =
+ val (changed, ds) =
case #decls st of
- [] => [d']
- | vis => [(DValRec vis, ErrorMsg.dummySpan), d']
+ [] => (changed, [d'])
+ | vis =>
+ (true, case d' of
+ (DValRec vis', _) => [(DValRec (vis @ vis'), ErrorMsg.dummySpan)]
+ | _ => [(DValRec vis, ErrorMsg.dummySpan), d'])
in
- (ds, {maxName = #maxName st,
- funcs = funcs,
- decls = []})
+ (ds, ({maxName = #maxName st,
+ funcs = funcs,
+ decls = []}, changed))
end
- val (ds, _) = ListUtil.foldlMapConcat doDecl
- {maxName = U.File.maxName file + 1,
- funcs = IM.empty,
- decls = []}
- file
+ val (ds, (_, changed)) = ListUtil.foldlMapConcat doDecl
+ ({maxName = U.File.maxName file + 1,
+ funcs = IM.empty,
+ decls = []}, false)
+ file
+ in
+ (changed, ds)
+ end
+
+fun specialize file =
+ let
+ val (changed, file) = specialize' file
in
- ds
+ if changed then
+ specialize file
+ else
+ file
end
diff --git a/src/expl_print.sml b/src/expl_print.sml
index b19a6eff..aecc3a84 100644
--- a/src/expl_print.sml
+++ b/src/expl_print.sml
@@ -370,6 +370,7 @@ fun p_exp' par env (e, loc) =
string x,
space,
string ":",
+ space,
p_con env t,
space,
string "=",
diff --git a/src/expl_util.sml b/src/expl_util.sml
index e12186b0..337ea8d6 100644
--- a/src/expl_util.sml
+++ b/src/expl_util.sml
@@ -331,7 +331,7 @@ fun mapfoldB {kind = fk, con = fc, exp = fe, bind} =
fn t' =>
S.bind2 (mfe ctx e1,
fn e1' =>
- S.map2 (mfe ctx e2,
+ S.map2 (mfe (bind (ctx, RelE (x, t))) e2,
fn e2' =>
(ELet (x, t', e1', e2'), loc))))
in
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index 3cf2bcd4..b22f053b 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -89,7 +89,7 @@ fun sqlifyFloat n = attrifyFloat n ^ "::float8"
fun sqlifyString s = "E'" ^ String.translate (fn #"'" => "\\'"
| ch => str ch)
(String.toString s) ^ "'::text"
-
+
fun exp e =
case e of
EPrim (Prim.String s) =>
@@ -287,6 +287,19 @@ fun exp e =
{disc = disc,
result = (TRecord [], loc)}), loc)
+ | EApp ((ECase (discE, pes, {disc, ...}), loc), arg as (ERecord [], _)) =>
+ let
+ fun doBody e =
+ case #1 e of
+ EAbs (_, _, _, body) => MonoReduce.subExpInExp (0, arg) body
+ | _ => (EApp (e, arg), loc)
+ in
+ optExp (ECase (discE,
+ map (fn (p, e) => (p, doBody e)) pes,
+ {disc = disc,
+ result = (TRecord [], loc)}), loc)
+ end
+
| EWrite (EQuery {exps, tables, state, query,
initial = (EPrim (Prim.String ""), _),
body = (EStrcat ((EPrim (Prim.String s), _),
diff --git a/src/mono_reduce.sig b/src/mono_reduce.sig
index 3769a0f5..2495c7f9 100644
--- a/src/mono_reduce.sig
+++ b/src/mono_reduce.sig
@@ -30,5 +30,7 @@
signature MONO_REDUCE = sig
val reduce : Mono.file -> Mono.file
-
+
+ val subExpInExp : int * Mono.exp -> Mono.exp -> Mono.exp
+
end
diff --git a/src/shake.sml b/src/shake.sml
index 38d72cc5..4ebd1b0b 100644
--- a/src/shake.sml
+++ b/src/shake.sml
@@ -55,14 +55,19 @@ fun shake file =
val (cdef, edef) = foldl (fn ((DCon (_, n, _, c), _), (cdef, edef)) => (IM.insert (cdef, n, [c]), edef)
| ((DDatatype (_, n, _, xncs), _), (cdef, edef)) =>
(IM.insert (cdef, n, List.mapPartial #3 xncs), edef)
- | ((DVal (_, n, t, e, _), _), (cdef, edef)) => (cdef, IM.insert (edef, n, (t, e)))
+ | ((DVal (_, n, t, e, _), _), (cdef, edef)) => (cdef, IM.insert (edef, n, ([], t, e)))
| ((DValRec vis, _), (cdef, edef)) =>
- (cdef, foldl (fn ((_, n, t, e, _), edef) => IM.insert (edef, n, (t, e))) edef vis)
+ let
+ val all_ns = map (fn (_, n, _, _, _) => n) vis
+ in
+ (cdef, foldl (fn ((_, n, t, e, _), edef) =>
+ IM.insert (edef, n, (all_ns, t, e))) edef vis)
+ end
| ((DExport _, _), acc) => acc
| ((DTable (_, n, c, _), _), (cdef, edef)) =>
- (cdef, IM.insert (edef, n, (c, dummye)))
+ (cdef, IM.insert (edef, n, ([], c, dummye)))
| ((DSequence (_, n, _), _), (cdef, edef)) =>
- (cdef, IM.insert (edef, n, (dummyt, dummye)))
+ (cdef, IM.insert (edef, n, ([], dummyt, dummye)))
| ((DDatabase _, _), acc) => acc)
(IM.empty, IM.empty) file
@@ -96,9 +101,15 @@ fun shake file =
val s' = {exp = IS.add (#exp s, n),
con = #con s}
in
+ (*print ("Need " ^ Int.toString n ^ "\n");*)
case IM.find (edef, n) of
NONE => s'
- | SOME (t, e) => shakeExp (shakeCon s' t) e
+ | SOME (ns, t, e) =>
+ let
+ val s' = shakeExp (shakeCon s' t) e
+ in
+ foldl (fn (n, s') => exp (ENamed n, s')) s' ns
+ end
end
| _ => s
@@ -109,7 +120,12 @@ fun shake file =
val s = foldl (fn (n, s) =>
case IM.find (edef, n) of
NONE => raise Fail "Shake: Couldn't find 'val'"
- | SOME (t, e) => shakeExp (shakeCon s t) e) s page_es
+ | SOME (ns, t, e) =>
+ let
+ val s = shakeExp (shakeCon s t) e
+ in
+ foldl (fn (n, s) => exp (ENamed n, s)) s ns
+ end) s page_es
val s = foldl (fn (c, s) => shakeCon s c) s table_cs
in
diff --git a/src/sources b/src/sources
index 984b5e23..504013d8 100644
--- a/src/sources
+++ b/src/sources
@@ -116,15 +116,15 @@ mono_print.sml
monoize.sig
monoize.sml
+mono_reduce.sig
+mono_reduce.sml
+
mono_opt.sig
mono_opt.sml
untangle.sig
untangle.sml
-mono_reduce.sig
-mono_reduce.sml
-
mono_shake.sig
mono_shake.sml
diff --git a/src/termination.sml b/src/termination.sml
index 6ed4d92f..2db5bb11 100644
--- a/src/termination.sml
+++ b/src/termination.sml
@@ -293,7 +293,15 @@ fun declOk' env (d, loc) =
| EUnif (ref (SOME e)) => exp parent (penv, calls) e
| EUnif (ref NONE) => (Rabble, calls)
- | ELet (_, e) => exp parent (penv, calls) e
+ | ELet (eds, e) =>
+ let
+ fun extPenv ((ed, _), penv) =
+ case ed of
+ EDVal _ => Rabble :: penv
+ | EDValRec vis => foldl (fn (_, penv) => Rabble :: penv) penv vis
+ in
+ exp parent (foldl extPenv penv eds, calls) e
+ end
end
fun doVali (i, (_, f, _, e), calls) =
diff --git a/src/unnest.sml b/src/unnest.sml
index b305b467..f226a678 100644
--- a/src/unnest.sml
+++ b/src/unnest.sml
@@ -124,7 +124,7 @@ fun squishExp (nr, cfv, efv) =
case e of
ERel n =>
if n >= eb then
- ERel (positionOf (n - eb) efv + eb)
+ ERel (positionOf (n - eb) efv + eb)
else
e
| _ => e,
@@ -142,17 +142,21 @@ type state = {
fun kind (k, st) = (k, st)
-fun exp ((ks, ts), e, st : state) =
+fun exp ((ks, ts), e as old, st : state) =
case e of
ELet (eds, e) =>
let
+ (*val () = Print.prefaces "let" [("e", ElabPrint.p_exp E.empty (old, ErrorMsg.dummySpan))]*)
+
val doSubst = foldl (fn (p, e) => E.subExpInExp p e)
- val (eds, (maxName, ds, subs)) =
+ val (eds, (ts, maxName, ds, subs)) =
ListUtil.foldlMapConcat
- (fn (ed, (maxName, ds, subs)) =>
+ (fn (ed, (ts, maxName, ds, subs)) =>
case #1 ed of
- EDVal _ => ([ed], (maxName, ds, map (fn (n, e) => (n + 1, E.liftExpInExp 0 e)) subs))
+ EDVal (x, t, _) => ([ed],
+ ((x, t) :: ts,
+ maxName, ds, map (fn (n, e) => (n + 1, E.liftExpInExp 0 e)) subs))
| EDValRec vis =>
let
val loc = #2 ed
@@ -174,7 +178,10 @@ fun exp ((ks, ts), e, st : state) =
end)
(IS.empty, IS.empty) vis
- (*val () = print ("A: " ^ Int.toString (length ts) ^ ", " ^ Int.toString (length ks) ^ "\n")*)
+ (*val () = print ("A: " ^ Int.toString (length ts) ^ ", " ^ Int.toString (length ks) ^ "\n")
+ val () = app (fn (x, t) =>
+ Print.prefaces "Var" [("x", Print.PD.string x),
+ ("t", ElabPrint.p_con E.empty t)]) ts*)
val cfv = IS.foldl (fn (x, cfv) =>
let
(*val () = print (Int.toString x ^ "\n")*)
@@ -193,11 +200,11 @@ fun exp ((ks, ts), e, st : state) =
fun apply e =
let
- val e = IS.foldl (fn (x, e) =>
+ val e = IS.foldr (fn (x, e) =>
(ECApp (e, (CRel x, loc)), loc))
e cfv
in
- IS.foldl (fn (x, e) =>
+ IS.foldr (fn (x, e) =>
(EApp (e, (ERel x, loc)), loc))
e efv
end
@@ -237,9 +244,9 @@ fun exp ((ks, ts), e, st : state) =
val t = squishCon cfv t
(*val () = Print.prefaces "squishExp"
[("e", ElabPrint.p_exp E.empty e)]*)
- val e = squishExp (nr, cfv, efv) e
+ val e = squishExp (0(*nr*), cfv, efv) e
- val (e, t) = foldr (fn (ex, (e, t)) =>
+ val (e, t) = foldl (fn (ex, (e, t)) =>
let
val (name, t') = List.nth (ts, ex)
in
@@ -252,7 +259,7 @@ fun exp ((ks, ts), e, st : state) =
end)
(e, t) efv
- val (e, t) = foldr (fn (cx, (e, t)) =>
+ val (e, t) = foldl (fn (cx, (e, t)) =>
let
val (name, k) = List.nth (ks, cx)
in
@@ -272,10 +279,12 @@ fun exp ((ks, ts), e, st : state) =
vis
val d = (DValRec vis, #2 ed)
+
+ val ts = map (fn (x, _, t, _) => (x, t)) vis @ ts
in
- ([], (maxName, d :: ds, subs))
+ ([], (ts, maxName, d :: ds, subs))
end)
- (#maxName st, #decls st, []) eds
+ (ts, #maxName st, #decls st, []) eds
in
(ELet (eds, doSubst e subs),
{maxName = maxName,
diff --git a/tests/blog.ur b/tests/blog.ur
new file mode 100644
index 00000000..a3a06cb6
--- /dev/null
+++ b/tests/blog.ur
@@ -0,0 +1,16 @@
+fun main wrap =
+ let
+ fun edit id =
+ let
+ val r = 0
+ fun save () =
+ in
+ wrap (save ())
+ end
+ in
+ edit 0
+ end
+
+fun wrap (inside : xbody) = return
+
+val main () = main wrap
diff --git a/tests/blog.urp b/tests/blog.urp
new file mode 100644
index 00000000..a3f7bfaa
--- /dev/null
+++ b/tests/blog.urp
@@ -0,0 +1,4 @@
+debug
+database dbname=blog
+
+blog
\ No newline at end of file
diff --git a/tests/blog.urs b/tests/blog.urs
new file mode 100644
index 00000000..6ac44e0b
--- /dev/null
+++ b/tests/blog.urs
@@ -0,0 +1 @@
+val main : unit -> transaction page
diff --git a/tests/nest.ur b/tests/nest.ur
index 8da50712..96bfdff4 100644
--- a/tests/nest.ur
+++ b/tests/nest.ur
@@ -45,7 +45,26 @@ fun f (x : int) =
page3
end
-datatype list t = Nil | Cons of t * list t
+fun add2 (x : int) (y : int) =
+ let
+ fun add3 () = x + y
+ in
+ add3
+ end
+
+fun add3 (x : int) =
+ let
+ fun add2 (y : int) =
+ let
+ fun add1 (z : int) = x + y + z
+ in
+ add1
+ end
+ in
+ add2
+ end
+
+(*datatype list t = Nil | Cons of t * list t
fun length (t ::: Type) (ls : list t) =
let
@@ -57,3 +76,4 @@ fun length (t ::: Type) (ls : list t) =
length' ls 0
end
+*)
diff --git a/tests/nest2.ur b/tests/nest2.ur
new file mode 100644
index 00000000..9a1d271a
--- /dev/null
+++ b/tests/nest2.ur
@@ -0,0 +1,15 @@
+fun wooho (wrap : xbody -> transaction page) =
+ let
+ fun subPage n =
+ let
+ fun subberPage () = wrap {[n]}
+ in
+ wrap Go
+ end
+ in
+ subPage 0
+ end
+
+fun wrap x = return {x}
+
+fun main () = wooho wrap
diff --git a/tests/nest2.urp b/tests/nest2.urp
new file mode 100644
index 00000000..2668c65e
--- /dev/null
+++ b/tests/nest2.urp
@@ -0,0 +1,3 @@
+debug
+
+nest2
--
cgit v1.2.3
From 0a10b5b7d2bbdcbfec723176b2a31d6b4c6d34d1 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Thu, 6 Nov 2008 15:37:38 -0500
Subject: Inserted a NULL value
---
CHANGELOG | 9 +++++
include/urweb.h | 6 +++
lib/basis.urs | 5 +++
src/c/urweb.c | 35 ++++++++++++++++++
src/cjr_print.sml | 101 +++++++++++++++++++++++++++++++++++++++++----------
src/elab_env.sml | 31 ++++++++++++++--
src/elaborate.sml | 47 ++++++++++++++++--------
src/mono_opt.sml | 5 +++
src/monoize.sml | 24 ++++++++++--
src/urweb.grm | 5 ++-
src/urweb.lex | 1 +
tests/sql_option.ur | 22 +++++++++++
tests/sql_option.urp | 5 +++
13 files changed, 252 insertions(+), 44 deletions(-)
create mode 100644 tests/sql_option.ur
create mode 100644 tests/sql_option.urp
(limited to 'src/mono_opt.sml')
diff --git a/CHANGELOG b/CHANGELOG
index aca01ea7..0f8d0f09 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,12 @@
+========
+NEXT
+========
+
+- Nested function definitions
+- Primitive "time" type
+- Nullable SQL columns (via "option")
+- Cookies
+
========
20081028
========
diff --git a/include/urweb.h b/include/urweb.h
index 7db66ed4..7e16fd40 100644
--- a/include/urweb.h
+++ b/include/urweb.h
@@ -80,6 +80,12 @@ uw_Basis_string uw_Basis_sqlifyString(uw_context, uw_Basis_string);
uw_Basis_string uw_Basis_sqlifyBool(uw_context, uw_Basis_bool);
uw_Basis_string uw_Basis_sqlifyTime(uw_context, uw_Basis_time);
+uw_Basis_string uw_Basis_sqlifyIntN(uw_context, uw_Basis_int*);
+uw_Basis_string uw_Basis_sqlifyFloatN(uw_context, uw_Basis_float*);
+uw_Basis_string uw_Basis_sqlifyStringN(uw_context, uw_Basis_string);
+uw_Basis_string uw_Basis_sqlifyBoolN(uw_context, uw_Basis_bool*);
+uw_Basis_string uw_Basis_sqlifyTimeN(uw_context, uw_Basis_time*);
+
char *uw_Basis_ensqlBool(uw_Basis_bool);
uw_Basis_string uw_Basis_intToString(uw_context, uw_Basis_int);
diff --git a/lib/basis.urs b/lib/basis.urs
index 84fb4e4c..f68bedee 100644
--- a/lib/basis.urs
+++ b/lib/basis.urs
@@ -188,6 +188,11 @@ val sql_int : sql_injectable int
val sql_float : sql_injectable float
val sql_string : sql_injectable string
val sql_time : sql_injectable time
+val sql_option_bool : sql_injectable (option bool)
+val sql_option_int : sql_injectable (option int)
+val sql_option_float : sql_injectable (option float)
+val sql_option_string : sql_injectable (option string)
+val sql_option_time : sql_injectable (option time)
val sql_inject : tables ::: {{Type}} -> agg ::: {{Type}} -> exps ::: {Type}
-> t ::: Type
-> sql_injectable t -> t -> sql_exp tables agg exps t
diff --git a/src/c/urweb.c b/src/c/urweb.c
index 638fbb16..1530c138 100644
--- a/src/c/urweb.c
+++ b/src/c/urweb.c
@@ -872,6 +872,13 @@ char *uw_Basis_sqlifyInt(uw_context ctx, uw_Basis_int n) {
return r;
}
+char *uw_Basis_sqlifyIntN(uw_context ctx, uw_Basis_int *n) {
+ if (n == NULL)
+ return "NULL";
+ else
+ return uw_Basis_sqlifyInt(ctx, *n);
+}
+
char *uw_Basis_sqlifyFloat(uw_context ctx, uw_Basis_float n) {
int len;
char *r;
@@ -883,6 +890,13 @@ char *uw_Basis_sqlifyFloat(uw_context ctx, uw_Basis_float n) {
return r;
}
+char *uw_Basis_sqlifyFloatN(uw_context ctx, uw_Basis_float *n) {
+ if (n == NULL)
+ return "NULL";
+ else
+ return uw_Basis_sqlifyFloat(ctx, *n);
+}
+
uw_Basis_string uw_Basis_sqlifyString(uw_context ctx, uw_Basis_string s) {
char *r, *s2;
@@ -920,6 +934,13 @@ uw_Basis_string uw_Basis_sqlifyString(uw_context ctx, uw_Basis_string s) {
return r;
}
+uw_Basis_string uw_Basis_sqlifyStringN(uw_context ctx, uw_Basis_string s) {
+ if (s == NULL)
+ return "NULL";
+ else
+ return uw_Basis_sqlifyString(ctx, s);
+}
+
char *uw_Basis_sqlifyBool(uw_context ctx, uw_Basis_bool b) {
if (b == uw_Basis_False)
return "FALSE";
@@ -927,6 +948,13 @@ char *uw_Basis_sqlifyBool(uw_context ctx, uw_Basis_bool b) {
return "TRUE";
}
+char *uw_Basis_sqlifyBoolN(uw_context ctx, uw_Basis_bool *b) {
+ if (b == NULL)
+ return "NULL";
+ else
+ return uw_Basis_sqlifyBool(ctx, *b);
+}
+
char *uw_Basis_sqlifyTime(uw_context ctx, uw_Basis_time t) {
size_t len;
char *r;
@@ -942,6 +970,13 @@ char *uw_Basis_sqlifyTime(uw_context ctx, uw_Basis_time t) {
return "";
}
+char *uw_Basis_sqlifyTimeN(uw_context ctx, uw_Basis_time *t) {
+ if (t == NULL)
+ return "NULL";
+ else
+ return uw_Basis_sqlifyTime(ctx, *t);
+}
+
char *uw_Basis_ensqlBool(uw_Basis_bool b) {
static uw_Basis_int true = 1;
static uw_Basis_int false = 0;
diff --git a/src/cjr_print.sml b/src/cjr_print.sml
index 06154b91..d7e426c3 100644
--- a/src/cjr_print.sml
+++ b/src/cjr_print.sml
@@ -408,24 +408,61 @@ fun p_unsql wontLeakStrings env (tAll as (t, loc)) e =
box [string "uw_Basis_strdup(ctx, ", e, string ")"]
| TFfi ("Basis", "bool") => box [string "uw_Basis_stringToBool_error(ctx, ", e, string ")"]
| TFfi ("Basis", "time") => box [string "uw_Basis_stringToTime_error(ctx, ", e, string ")"]
+
| _ => (ErrorMsg.errorAt loc "Don't know how to unmarshal type from SQL";
Print.eprefaces' [("Type", p_typ env tAll)];
string "ERROR")
+fun p_getcol wontLeakStrings env (tAll as (t, loc)) i =
+ case t of
+ TOption t =>
+ box [string "(PQgetisnull (res, i, ",
+ string (Int.toString i),
+ string ") ? NULL : ",
+ case t of
+ (TFfi ("Basis", "string"), _) => p_getcol wontLeakStrings env t i
+ | _ => box [string "({",
+ newline,
+ p_typ env t,
+ space,
+ string "*tmp = uw_malloc(ctx, sizeof(",
+ p_typ env t,
+ string "));",
+ newline,
+ string "*tmp = ",
+ p_getcol wontLeakStrings env t i,
+ string ";",
+ newline,
+ string "tmp;",
+ newline,
+ string "})"],
+ string ")"]
+
+ | _ =>
+ p_unsql wontLeakStrings env tAll
+ (box [string "PQgetvalue(res, i, ",
+ string (Int.toString i),
+ string ")"])
+
datatype sql_type =
Int
| Float
| String
| Bool
| Time
+ | Nullable of sql_type
+
+fun p_sql_type' t =
+ case t of
+ Int => "uw_Basis_int"
+ | Float => "uw_Basis_float"
+ | String => "uw_Basis_string"
+ | Bool => "uw_Basis_bool"
+ | Time => "uw_Basis_time"
+ | Nullable String => "uw_Basis_string"
+ | Nullable t => p_sql_type' t ^ "*"
-fun p_sql_type t =
- string (case t of
- Int => "uw_Basis_int"
- | Float => "uw_Basis_float"
- | String => "uw_Basis_string"
- | Bool => "uw_Basis_bool"
- | Time => "uw_Basis_time")
+fun p_sql_type t = string (p_sql_type' t)
fun getPargs (e, _) =
case e of
@@ -448,6 +485,12 @@ fun p_ensql t e =
| String => e
| Bool => box [string "(", e, string " ? \"TRUE\" : \"FALSE\")"]
| Time => box [string "uw_Basis_sqlifyTime(ctx, ", e, string ")"]
+ | Nullable String => e
+ | Nullable t => box [string "(",
+ e,
+ string " == NULL ? NULL : ",
+ p_ensql t (box [string "*", e]),
+ string ")"]
fun notLeaky env allowHeapAllocated =
let
@@ -1169,10 +1212,7 @@ fun p_exp' par env (e, loc) =
space,
string "=",
space,
- p_unsql wontLeakStrings env t
- (box [string "PQgetvalue(res, i, ",
- string (Int.toString i),
- string ")"]),
+ p_getcol wontLeakStrings env t i,
string ";",
newline]) outputs,
@@ -1660,7 +1700,10 @@ fun p_decl env (dAll as (d, _) : decl) =
string "}",
newline]
- | DPreparedStatements [] => box []
+ | DPreparedStatements [] =>
+ box [string "static void uw_db_prepare(uw_context ctx) {",
+ newline,
+ string "}"]
| DPreparedStatements ss =>
box [string "static void uw_db_prepare(uw_context ctx) {",
newline,
@@ -1708,7 +1751,7 @@ datatype 'a search =
| NotFound
| Error
-fun p_sqltype' env (tAll as (t, loc)) =
+fun p_sqltype'' env (tAll as (t, loc)) =
case t of
TFfi ("Basis", "int") => "int8"
| TFfi ("Basis", "float") => "float8"
@@ -1719,8 +1762,25 @@ fun p_sqltype' env (tAll as (t, loc)) =
Print.eprefaces' [("Type", p_typ env tAll)];
"ERROR")
+fun p_sqltype' env (tAll as (t, loc)) =
+ case t of
+ (TOption t, _) => p_sqltype'' env t
+ | _ => p_sqltype'' env t ^ " NOT NULL"
+
fun p_sqltype env t = string (p_sqltype' env t)
+fun p_sqltype_base' env t =
+ case t of
+ (TOption t, _) => p_sqltype'' env t
+ | _ => p_sqltype'' env t
+
+fun p_sqltype_base env t = string (p_sqltype_base' env t)
+
+fun is_not_null t =
+ case t of
+ (TOption _, _) => false
+ | _ => true
+
fun p_file env (ds, ps) =
let
val (pds, env) = ListUtil.foldlMap (fn (d, env) =>
@@ -1997,8 +2057,13 @@ fun p_file env (ds, ps) =
Char.toLower (ident x),
"' AND atttypid = (SELECT oid FROM pg_type",
" WHERE typname = '",
- p_sqltype' env t,
- "'))"]) xts),
+ p_sqltype_base' env t,
+ "') AND attnotnull = ",
+ if is_not_null t then
+ "TRUE"
+ else
+ "FALSE",
+ ")"]) xts),
")"]
val q'' = String.concat ["SELECT COUNT(*) FROM pg_attribute WHERE attrelid = (SELECT oid FROM pg_class WHERE relname = '",
@@ -2295,11 +2360,7 @@ fun p_sql env (ds, _) =
box [string "uw_",
string (CharVector.map Char.toLower x),
space,
- p_sqltype env t,
- space,
- string "NOT",
- space,
- string "NULL"]) xts,
+ p_sqltype env (t, ErrorMsg.dummySpan)]) xts,
string ");",
newline,
newline]
diff --git a/src/elab_env.sml b/src/elab_env.sml
index b14cd06c..46f62727 100644
--- a/src/elab_env.sml
+++ b/src/elab_env.sml
@@ -150,12 +150,14 @@ datatype class_key =
CkNamed of int
| CkRel of int
| CkProj of int * string list * string
+ | CkApp of class_key * class_key
fun ck2s ck =
case ck of
CkNamed n => "Named(" ^ Int.toString n ^ ")"
| CkRel n => "Rel(" ^ Int.toString n ^ ")"
| CkProj (m, ms, x) => "Proj(" ^ Int.toString m ^ "," ^ String.concatWith "," ms ^ "," ^ x ^ ")"
+ | CkApp (ck1, ck2) => "App(" ^ ck2s ck1 ^ ", " ^ ck2s ck2 ^ ")"
fun cp2s (cn, ck) = "(" ^ cn2s cn ^ "," ^ ck2s ck ^ ")"
@@ -176,6 +178,12 @@ fun compare x =
join (Int.compare (m1, m2),
fn () => join (joinL String.compare (ms1, ms2),
fn () => String.compare (x1, x2)))
+ | (CkProj _, _) => LESS
+ | (_, CkProj _) => GREATER
+
+ | (CkApp (f1, x1), CkApp (f2, x2)) =>
+ join (compare (f1, f2),
+ fn () => compare (x1, x2))
end
structure KM = BinaryMapFn(KK)
@@ -251,6 +259,7 @@ fun liftClassKey ck =
CkNamed _ => ck
| CkRel n => CkRel (n + 1)
| CkProj _ => ck
+ | CkApp (ck1, ck2) => CkApp (liftClassKey ck1, liftClassKey ck2)
fun pushCRel (env : env) x k =
let
@@ -411,6 +420,10 @@ fun class_key_in (c, _) =
| CNamed n => SOME (CkNamed n)
| CModProj x => SOME (CkProj x)
| CUnif (_, _, _, ref (SOME c)) => class_key_in c
+ | CApp (c1, c2) =>
+ (case (class_key_in c1, class_key_in c2) of
+ (SOME k1, SOME k2) => SOME (CkApp (k1, k2))
+ | _ => NONE)
| _ => NONE
fun class_pair_in (c, _) =
@@ -653,7 +666,7 @@ fun sgnS_con (str, (sgns, strs, cons)) c =
end)
| _ => c
-fun sgnS_con' (m1, ms', (sgns, strs, cons)) c =
+fun sgnS_con' (arg as (m1, ms', (sgns, strs, cons))) c =
case c of
CModProj (m1, ms, x) =>
(case IM.find (strs, m1) of
@@ -663,6 +676,8 @@ fun sgnS_con' (m1, ms', (sgns, strs, cons)) c =
(case IM.find (cons, n) of
NONE => c
| SOME nx => CModProj (m1, ms', nx))
+ | CApp (c1, c2) => CApp ((sgnS_con' arg (#1 c1), #2 c1),
+ (sgnS_con' arg (#1 c2), #2 c2))
| _ => c
fun sgnS_sgn (str, (sgns, strs, cons)) sgn =
@@ -1033,13 +1048,21 @@ fun projectVal env {sgn, str, field} =
ListUtil.search (fn (x, _, to) =>
if x = field then
SOME (let
+ val base = (CNamed n, #2 sgn)
+ val nxs = length xs
+ val base = ListUtil.foldli (fn (i, _, base) =>
+ (CApp (base,
+ (CRel (nxs - i - 1), #2 sgn)),
+ #2 sgn))
+ base xs
+
val t =
case to of
- NONE => (CNamed n, #2 sgn)
- | SOME t => (TFun (t, (CNamed n, #2 sgn)), #2 sgn)
+ NONE => base
+ | SOME t => (TFun (t, base), #2 sgn)
val k = (KType, #2 sgn)
in
- foldr (fn (x, t) => (TCFun (Explicit, x, k, t), #2 sgn))
+ foldr (fn (x, t) => (TCFun (Implicit, x, k, t), #2 sgn))
t xs
end)
else
diff --git a/src/elaborate.sml b/src/elaborate.sml
index 3b70c623..a6edc0ed 100644
--- a/src/elaborate.sml
+++ b/src/elaborate.sml
@@ -1389,17 +1389,32 @@ fun unmodCon env (c, loc) =
end
| _ => (c, loc)
-fun normClassConstraint envs (c, loc) =
+fun normClassKey envs c =
+ let
+ val c = ElabOps.hnormCon envs c
+ in
+ case #1 c of
+ L'.CApp (c1, c2) =>
+ let
+ val c1 = normClassKey envs c1
+ val c2 = normClassKey envs c2
+ in
+ (L'.CApp (c1, c2), #2 c)
+ end
+ | _ => c
+ end
+
+fun normClassConstraint env (c, loc) =
case c of
L'.CApp (f, x) =>
let
- val f = unmodCon (#1 envs) f
- val (x, gs) = hnormCon envs x
+ val f = unmodCon env f
+ val x = normClassKey env x
in
- ((L'.CApp (f, x), loc), gs)
+ (L'.CApp (f, x), loc)
end
- | L'.CUnif (_, _, _, ref (SOME c)) => normClassConstraint envs c
- | _ => ((c, loc), [])
+ | L'.CUnif (_, _, _, ref (SOME c)) => normClassConstraint env c
+ | _ => (c, loc)
val makeInstantiable =
@@ -1491,12 +1506,12 @@ fun elabExp (env, denv) (eAll as (e, loc)) =
checkKind env t' tk ktype;
(t', gs)
end
- val (dom, gs2) = normClassConstraint (env, denv) t'
- val (e', et, gs3) = elabExp (E.pushERel env x dom, denv) e
+ val dom = normClassConstraint env t'
+ val (e', et, gs2) = elabExp (E.pushERel env x dom, denv) e
in
((L'.EAbs (x, t', et, e'), loc),
(L'.TFun (t', et), loc),
- enD gs1 @ enD gs2 @ gs3)
+ enD gs1 @ gs2)
end
| L.ECApp (e, c) =>
let
@@ -1708,11 +1723,11 @@ and elabEdecl denv (dAll as (d, loc), (env, gs : constraint list)) =
val (e', et, gs2) = elabExp (env, denv) e
val gs3 = checkCon (env, denv) e' et c'
- val (c', gs4) = normClassConstraint (env, denv) c'
+ val c' = normClassConstraint env c'
val env' = E.pushERel env x c'
val c' = makeInstantiable c'
in
- ((L'.EDVal (x, c', e'), loc), (env', enD gs1 @ gs2 @ enD gs3 @ enD gs4 @ gs))
+ ((L'.EDVal (x, c', e'), loc), (env', enD gs1 @ gs2 @ enD gs3 @ gs))
end
| L.EDValRec vis =>
let
@@ -1884,12 +1899,12 @@ fun elabSgn_item ((sgi, loc), (env, denv, gs)) =
val (c', ck, gs') = elabCon (env, denv) c
val (env', n) = E.pushENamed env x c'
- val (c', gs'') = normClassConstraint (env, denv) c'
+ val c' = normClassConstraint env c'
in
(unifyKinds ck ktype
handle KUnify ue => strError env (NotType (ck, ue)));
- ([(L'.SgiVal (x, n, c'), loc)], (env', denv, gs' @ gs'' @ gs))
+ ([(L'.SgiVal (x, n, c'), loc)], (env', denv, gs' @ gs))
end
| L.SgiStr (x, sgn) =>
@@ -2875,13 +2890,13 @@ fun elabDecl (dAll as (d, loc), (env, denv, gs : constraint list)) =
val (e', et, gs2) = elabExp (env, denv) e
val gs3 = checkCon (env, denv) e' et c'
- val (c', gs4) = normClassConstraint (env, denv) c'
+ val c = normClassConstraint env c'
val (env', n) = E.pushENamed env x c'
val c' = makeInstantiable c'
in
(*prefaces "DVal" [("x", Print.PD.string x),
("c'", p_con env c')];*)
- ([(L'.DVal (x, n, c', e'), loc)], (env', denv, enD gs1 @ gs2 @ enD gs3 @ enD gs4 @ gs))
+ ([(L'.DVal (x, n, c', e'), loc)], (env', denv, enD gs1 @ gs2 @ enD gs3 @ gs))
end
| L.DValRec vis =>
let
@@ -3404,7 +3419,7 @@ fun elabFile basis topStr topSgn env file =
("Hnormed 2", p_con env (ElabOps.hnormCon env c2))]))
| TypeClass (env, c, r, loc) =>
let
- val c = ElabOps.hnormCon env c
+ val c = normClassKey env c
in
case E.resolveClass env c of
SOME e => r := SOME e
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index b22f053b..93cb888b 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -268,6 +268,11 @@ fun exp e =
| EFfiApp ("Basis", "sqlifyInt", [(EPrim (Prim.Int n), _)]) =>
EPrim (Prim.String (sqlifyInt n))
+ | EFfiApp ("Basis", "sqlifyIntN", [(ENone _, _)]) =>
+ EPrim (Prim.String "NULL")
+ | EFfiApp ("Basis", "sqlifyIntN", [(ESome (_, (EPrim (Prim.Int n), _)), _)]) =>
+ EPrim (Prim.String (sqlifyInt n))
+
| EFfiApp ("Basis", "sqlifyFloat", [(EPrim (Prim.Float n), _)]) =>
EPrim (Prim.String (sqlifyFloat n))
| EFfiApp ("Basis", "sqlifyBool", [b as (_, loc)]) =>
diff --git a/src/monoize.sml b/src/monoize.sml
index c4c296bd..83da382b 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -982,10 +982,8 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
| L.EFfiApp ("Basis", "dml", [e]) =>
let
val (e, fm) = monoExp (env, st, fm) e
- val un = (L'.TRecord [], loc)
in
- ((L'.EAbs ("_", un, un,
- (L'.EDml (liftExpInExp 0 e), loc)), loc),
+ ((L'.EDml (liftExpInExp 0 e), loc),
fm)
end
@@ -1274,6 +1272,26 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
((L'.EAbs ("x", (L'.TFfi ("Basis", "time"), loc), (L'.TFfi ("Basis", "string"), loc),
(L'.EFfiApp ("Basis", "sqlifyTime", [(L'.ERel 0, loc)]), loc)), loc),
fm)
+ | L.EFfi ("Basis", "sql_option_int") =>
+ ((L'.EAbs ("x", (L'.TOption (L'.TFfi ("Basis", "int"), loc), loc), (L'.TFfi ("Basis", "string"), loc),
+ (L'.EFfiApp ("Basis", "sqlifyIntN", [(L'.ERel 0, loc)]), loc)), loc),
+ fm)
+ | L.EFfi ("Basis", "sql_option_float") =>
+ ((L'.EAbs ("x", (L'.TOption (L'.TFfi ("Basis", "float"), loc), loc), (L'.TFfi ("Basis", "string"), loc),
+ (L'.EFfiApp ("Basis", "sqlifyFloatN", [(L'.ERel 0, loc)]), loc)), loc),
+ fm)
+ | L.EFfi ("Basis", "sql_option_bool") =>
+ ((L'.EAbs ("x", (L'.TOption (L'.TFfi ("Basis", "bool"), loc), loc), (L'.TFfi ("Basis", "string"), loc),
+ (L'.EFfiApp ("Basis", "sqlifyBoolN", [(L'.ERel 0, loc)]), loc)), loc),
+ fm)
+ | L.EFfi ("Basis", "sql_option_string") =>
+ ((L'.EAbs ("x", (L'.TOption (L'.TFfi ("Basis", "string"), loc), loc), (L'.TFfi ("Basis", "string"), loc),
+ (L'.EFfiApp ("Basis", "sqlifyStringN", [(L'.ERel 0, loc)]), loc)), loc),
+ fm)
+ | L.EFfi ("Basis", "sql_option_time") =>
+ ((L'.EAbs ("x", (L'.TOption (L'.TFfi ("Basis", "time"), loc), loc), (L'.TFfi ("Basis", "string"), loc),
+ (L'.EFfiApp ("Basis", "sqlifyTimeN", [(L'.ERel 0, loc)]), loc)), loc),
+ fm)
| L.ECApp ((L.EFfi ("Basis", "sql_subset"), _), _) =>
((L'.ERecord [], loc), fm)
diff --git a/src/urweb.grm b/src/urweb.grm
index b2f2d486..2482be1b 100644
--- a/src/urweb.grm
+++ b/src/urweb.grm
@@ -214,7 +214,7 @@ fun tagIn bt =
| TRUE | FALSE | CAND | OR | NOT
| COUNT | AVG | SUM | MIN | MAX
| ASC | DESC
- | INSERT | INTO | VALUES | UPDATE | SET | DELETE
+ | INSERT | INTO | VALUES | UPDATE | SET | DELETE | NULL
| CURRENT_TIMESTAMP
| NE | LT | LE | GT | GE
@@ -1251,6 +1251,9 @@ sqlexp : TRUE (sql_inject (EVar (["Basis"], "True", In
s (LBRACEleft, RBRACEright)))
| LPAREN sqlexp RPAREN (sqlexp)
+ | NULL (sql_inject ((EVar (["Basis"], "None", Infer),
+ s (NULLleft, NULLright))))
+
| COUNT LPAREN STAR RPAREN (let
val loc = s (COUNTleft, RPARENright)
in
diff --git a/src/urweb.lex b/src/urweb.lex
index f5ea558a..f4ae3a85 100644
--- a/src/urweb.lex
+++ b/src/urweb.lex
@@ -357,6 +357,7 @@ notags = [^<{\n]+;
"UPDATE" => (Tokens.UPDATE (pos yypos, pos yypos + size yytext));
"SET" => (Tokens.SET (pos yypos, pos yypos + size yytext));
"DELETE" => (Tokens.DELETE (pos yypos, pos yypos + size yytext));
+ "NULL" => (Tokens.NULL (pos yypos, pos yypos + size yytext));
"CURRENT_TIMESTAMP" => (Tokens.CURRENT_TIMESTAMP (pos yypos, pos yypos + size yytext));
diff --git a/tests/sql_option.ur b/tests/sql_option.ur
new file mode 100644
index 00000000..257f8c55
--- /dev/null
+++ b/tests/sql_option.ur
@@ -0,0 +1,22 @@
+table t : { O : option int }
+
+fun addNull () =
+ dml (INSERT INTO t (O) VALUES (NULL));
+ return Done
+
+(*fun add42 () =
+ dml (INSERT INTO t (O) VALUES (42));
+ return Done*)
+
+fun main () : transaction page =
+ xml <- queryX (SELECT * FROM t)
+ (fn r => case r.T.O of
+ None => Nada
+ | Some n => Num: {[n]} );
+ return
+ {xml}
+
+ Add a null
+
+
+(* Add a 42 *)
diff --git a/tests/sql_option.urp b/tests/sql_option.urp
new file mode 100644
index 00000000..543c32a8
--- /dev/null
+++ b/tests/sql_option.urp
@@ -0,0 +1,5 @@
+debug
+database dbname=option
+sql option.sql
+
+sql_option
--
cgit v1.2.3
From a676c53ffcf88833514d12968ee5b6b28aa8cc8a Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sun, 9 Nov 2008 18:19:47 -0500
Subject: Remove some allocation
---
src/cjr_print.sml | 15 +++++++++------
src/mono_opt.sml | 30 +++++++++++++++++++++++++++++-
src/mono_reduce.sig | 2 ++
src/prepare.sml | 33 ++++++++++++++++++++++++---------
4 files changed, 64 insertions(+), 16 deletions(-)
(limited to 'src/mono_opt.sml')
diff --git a/src/cjr_print.sml b/src/cjr_print.sml
index 7c13fcb5..b1eb04b3 100644
--- a/src/cjr_print.sml
+++ b/src/cjr_print.sml
@@ -1186,10 +1186,6 @@ fun p_exp' par env (e, loc) =
p_exp env initial,
string ";",
newline,
- case prepared of
- NONE => box [string "printf(\"Executing: %s\\n\", query);",
- newline]
- | _ => box [],
string "PGresult *res = ",
case prepared of
NONE => string "PQexecParams(conn, query, 0, NULL, NULL, NULL, NULL, 0);"
@@ -1371,8 +1367,15 @@ fun p_exp' par env (e, loc) =
| ENextval {seq, prepared} =>
let
- val query = (EFfiApp ("Basis", "strcat", [seq, (EPrim (Prim.String "')"), loc)]), loc)
- val query = (EFfiApp ("Basis", "strcat", [(EPrim (Prim.String "SELECT NEXTVAL('"), loc), query]), loc)
+ val query = case seq of
+ (EPrim (Prim.String s), loc) =>
+ (EPrim (Prim.String ("SELECT NEXTVAL('" ^ s ^ "')")), loc)
+ | _ =>
+ let
+ val query = (EFfiApp ("Basis", "strcat", [seq, (EPrim (Prim.String "')"), loc)]), loc)
+ in
+ (EFfiApp ("Basis", "strcat", [(EPrim (Prim.String "SELECT NEXTVAL('"), loc), query]), loc)
+ end
in
box [string "(uw_begin_region(ctx), ",
string "({",
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index 93cb888b..e350db1d 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -319,12 +319,40 @@ fun exp e =
e
| EWrite (EQuery {exps, tables, state, query,
+ initial = (EPrim (Prim.String ""), _),
+ body}, loc) =>
+ let
+ fun passLets (depth, (e', _), lets) =
+ case e' of
+ EStrcat ((ERel x, _), e'') =>
+ if x = depth then
+ let
+ val body = (optExp (EWrite e'', loc), loc)
+ val body = foldl (fn ((x, t, e'), e) =>
+ (ELet (x, t, e', e), loc))
+ body lets
+ in
+ EQuery {exps = exps, tables = tables, query = query,
+ state = (TRecord [], loc),
+ initial = (ERecord [], loc),
+ body = body}
+ end
+ else
+ e
+ | ELet (x, t, e', e'') =>
+ passLets (depth + 1, e'', (x, t, e') :: lets)
+ | _ => e
+ in
+ passLets (0, body, [])
+ end
+
+ (*| EWrite (EQuery {exps, tables, state, query,
initial = (EPrim (Prim.String ""), _),
body = (EStrcat ((ERel 0, _), e'), _)}, loc) =>
EQuery {exps = exps, tables = tables, query = query,
state = (TRecord [], loc),
initial = (ERecord [], loc),
- body = (optExp (EWrite e', loc), loc)}
+ body = (optExp (EWrite e', loc), loc)}*)
| EWrite (ELet (x, t, e1, e2), loc) =>
optExp (ELet (x, t, e1, (EWrite e2, loc)), loc)
diff --git a/src/mono_reduce.sig b/src/mono_reduce.sig
index 2495c7f9..a6b6cc81 100644
--- a/src/mono_reduce.sig
+++ b/src/mono_reduce.sig
@@ -33,4 +33,6 @@ signature MONO_REDUCE = sig
val subExpInExp : int * Mono.exp -> Mono.exp -> Mono.exp
+ val impure : Mono.exp -> bool
+
end
diff --git a/src/prepare.sml b/src/prepare.sml
index b20c7fec..28c14639 100644
--- a/src/prepare.sml
+++ b/src/prepare.sml
@@ -176,13 +176,21 @@ fun prepExp (e as (_, loc), sns) =
end
| EQuery {exps, tables, rnum, state, query, body, initial, ...} =>
- (case prepString (query, [], 0) of
- NONE => (e, sns)
- | SOME (ss, n) =>
- ((EQuery {exps = exps, tables = tables, rnum = rnum,
- state = state, query = query, body = body,
- initial = initial, prepared = SOME (#2 sns)}, loc),
- ((String.concat (rev ss), n) :: #1 sns, #2 sns + 1)))
+ let
+ val (body, sns) = prepExp (body, sns)
+ in
+ case prepString (query, [], 0) of
+ NONE =>
+ ((EQuery {exps = exps, tables = tables, rnum = rnum,
+ state = state, query = query, body = body,
+ initial = initial, prepared = SOME (#2 sns)}, loc),
+ sns)
+ | SOME (ss, n) =>
+ ((EQuery {exps = exps, tables = tables, rnum = rnum,
+ state = state, query = query, body = body,
+ initial = initial, prepared = SOME (#2 sns)}, loc),
+ ((String.concat (rev ss), n) :: #1 sns, #2 sns + 1))
+ end
| EDml {dml, ...} =>
(case prepString (dml, [], 0) of
@@ -193,8 +201,15 @@ fun prepExp (e as (_, loc), sns) =
| ENextval {seq, ...} =>
let
- val s = (EFfiApp ("Basis", "strcat", [seq, (EPrim (Prim.String "')"), loc)]), loc)
- val s = (EFfiApp ("Basis", "strcat", [(EPrim (Prim.String "SELECT NEXTVAL('"), loc), s]), loc)
+ val s = case seq of
+ (EPrim (Prim.String s), loc) =>
+ (EPrim (Prim.String ("SELECT NEXTVAL('" ^ s ^ "')")), loc)
+ | _ =>
+ let
+ val s' = (EFfiApp ("Basis", "strcat", [seq, (EPrim (Prim.String "')"), loc)]), loc)
+ in
+ (EFfiApp ("Basis", "strcat", [(EPrim (Prim.String "SELECT NEXTVAL('"), loc), s']), loc)
+ end
in
case prepString (s, [], 0) of
NONE => (e, sns)
--
cgit v1.2.3
From 0510db82b18aae60ca4e9f5935ad0f18e0b1a1ea Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Tue, 11 Nov 2008 20:24:55 -0500
Subject: Fix type calculation for applying-a-case optimization
---
src/mono_opt.sml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'src/mono_opt.sml')
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index e350db1d..b56372c7 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -292,7 +292,7 @@ fun exp e =
{disc = disc,
result = (TRecord [], loc)}), loc)
- | EApp ((ECase (discE, pes, {disc, ...}), loc), arg as (ERecord [], _)) =>
+ | EApp ((ECase (discE, pes, {disc, result = (TFun (_, ran), _)}), loc), arg as (ERecord [], _)) =>
let
fun doBody e =
case #1 e of
@@ -302,7 +302,7 @@ fun exp e =
optExp (ECase (discE,
map (fn (p, e) => (p, doBody e)) pes,
{disc = disc,
- result = (TRecord [], loc)}), loc)
+ result = ran}), loc)
end
| EWrite (EQuery {exps, tables, state, query,
--
cgit v1.2.3
From 940865b04fa534983982b261386a3b1926bd5531 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Tue, 25 Nov 2008 10:05:44 -0500
Subject: Fusing writes with recursive function calls
---
CHANGELOG | 5 +++
src/compiler.sig | 4 ++
src/compiler.sml | 13 +++++-
src/fuse.sig | 32 ++++++++++++++
src/fuse.sml | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/mono_opt.sig | 1 +
src/mono_opt.sml | 2 +
src/mono_util.sig | 7 +++
src/mono_util.sml | 21 ++++++++-
src/sources | 3 ++
10 files changed, 216 insertions(+), 2 deletions(-)
create mode 100644 src/fuse.sig
create mode 100644 src/fuse.sml
(limited to 'src/mono_opt.sml')
diff --git a/CHANGELOG b/CHANGELOG
index a9cc96db..cbd67118 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,8 @@
+========
+========
+
+- Optimization: Fusing page writes with calls to recursive functions
+
========
20081120
========
diff --git a/src/compiler.sig b/src/compiler.sig
index af086675..8c52ea32 100644
--- a/src/compiler.sig
+++ b/src/compiler.sig
@@ -76,6 +76,7 @@ signature COMPILER = sig
val untangle : (Mono.file, Mono.file) phase
val mono_reduce : (Mono.file, Mono.file) phase
val mono_shake : (Mono.file, Mono.file) phase
+ val fuse : (Mono.file, Mono.file) phase
val pathcheck : (Mono.file, Mono.file) phase
val cjrize : (Mono.file, Cjr.file) phase
val prepare : (Cjr.file, Cjr.file) phase
@@ -104,6 +105,9 @@ signature COMPILER = sig
val toMono_reduce : (string, Mono.file) transform
val toMono_shake : (string, Mono.file) transform
val toMono_opt2 : (string, Mono.file) transform
+ val toFuse : (string, Mono.file) transform
+ val toUntangle2 : (string, Mono.file) transform
+ val toMono_shake2 : (string, Mono.file) transform
val toPathcheck : (string, Mono.file) transform
val toCjrize : (string, Cjr.file) transform
val toPrepare : (string, Cjr.file) transform
diff --git a/src/compiler.sml b/src/compiler.sml
index 6a6c4391..aac4a924 100644
--- a/src/compiler.sml
+++ b/src/compiler.sml
@@ -523,12 +523,23 @@ val toMono_shake = transform mono_shake "mono_shake1" o toMono_reduce
val toMono_opt2 = transform mono_opt "mono_opt2" o toMono_shake
+val fuse = {
+ func = Fuse.fuse,
+ print = MonoPrint.p_file MonoEnv.empty
+}
+
+val toFuse = transform fuse "fuse" o toMono_opt2
+
+val toUntangle2 = transform untangle "untangle2" o toFuse
+
+val toMono_shake2 = transform mono_shake "mono_shake2" o toUntangle2
+
val pathcheck = {
func = (fn file => (PathCheck.check file; file)),
print = MonoPrint.p_file MonoEnv.empty
}
-val toPathcheck = transform pathcheck "pathcheck" o toMono_opt2
+val toPathcheck = transform pathcheck "pathcheck" o toMono_shake2
val cjrize = {
func = Cjrize.cjrize,
diff --git a/src/fuse.sig b/src/fuse.sig
new file mode 100644
index 00000000..3ad45ac9
--- /dev/null
+++ b/src/fuse.sig
@@ -0,0 +1,32 @@
+(* Copyright (c) 2008, 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 FUSE = sig
+
+ val fuse : Mono.file -> Mono.file
+
+end
diff --git a/src/fuse.sml b/src/fuse.sml
new file mode 100644
index 00000000..b6bd6b47
--- /dev/null
+++ b/src/fuse.sml
@@ -0,0 +1,130 @@
+(* Copyright (c) 2008, 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 Fuse :> FUSE = struct
+
+open Mono
+structure U = MonoUtil
+
+structure IM = IntBinaryMap
+
+fun returnsString (t, loc) =
+ let
+ fun rs (t, loc) =
+ case t of
+ TFfi ("Basis", "string") => SOME ([], (TRecord [], loc))
+ | TFun (dom, ran) =>
+ (case rs ran of
+ NONE => NONE
+ | SOME (args, ran') => SOME (dom :: args, (TFun (dom, ran'), loc)))
+ | _ => NONE
+ in
+ case t of
+ TFun (dom, ran) =>
+ (case rs ran of
+ NONE => NONE
+ | SOME (args, ran') => SOME (dom :: args, (TFun (dom, ran'), loc)))
+ | _ => NONE
+ end
+
+fun fuse file =
+ let
+ fun doDecl (d as (_, loc), (funcs, maxName)) =
+ let
+ val (d, funcs, maxName) =
+ case #1 d of
+ DValRec vis =>
+ let
+ val (vis', funcs, maxName) =
+ foldl (fn ((x, n, t, e, s), (vis', funcs, maxName)) =>
+ case returnsString t of
+ NONE => (vis', funcs, maxName)
+ | SOME (args, t') =>
+ let
+ fun getBody (e, args) =
+ case (#1 e, args) of
+ (_, []) => (e, [])
+ | (EAbs (x, t, _, e), _ :: args) =>
+ let
+ val (body, args') = getBody (e, args)
+ in
+ (body, (x, t) :: args')
+ end
+ | _ => raise Fail "Fuse: getBody"
+
+ val (body, args) = getBody (e, args)
+ val body = MonoOpt.optExp (EWrite body, loc)
+ val (body, _) = foldl (fn ((x, dom), (body, ran)) =>
+ ((EAbs (x, dom, ran, body), loc),
+ (TFun (dom, ran), loc)))
+ (body, (TRecord [], loc)) args
+ in
+ ((x, maxName, t', body, s) :: vis',
+ IM.insert (funcs, n, maxName),
+ maxName + 1)
+ end)
+ ([], funcs, maxName) vis
+ in
+ ((DValRec (vis @ vis'), loc), funcs, maxName)
+ end
+ | _ => (d, funcs, maxName)
+
+ fun exp e =
+ case e of
+ EWrite e' =>
+ let
+ fun unravel (e, loc) =
+ case e of
+ ENamed n =>
+ (case IM.find (funcs, n) of
+ NONE => NONE
+ | SOME n' => SOME (ENamed n', loc))
+ | EApp (e1, e2) =>
+ (case unravel e1 of
+ NONE => NONE
+ | SOME e1 => SOME (EApp (e1, e2), loc))
+ | _ => NONE
+ in
+ case unravel e' of
+ NONE => e
+ | SOME (e', _) => e'
+ end
+ | _ => e
+ in
+ (U.Decl.map {typ = fn x => x,
+ exp = exp,
+ decl = fn x => x}
+ d,
+ (funcs, maxName))
+ end
+
+ val (file, _) = ListUtil.foldlMap doDecl (IM.empty, U.File.maxName file + 1) file
+ in
+ file
+ end
+
+end
diff --git a/src/mono_opt.sig b/src/mono_opt.sig
index d147e7bc..d0268087 100644
--- a/src/mono_opt.sig
+++ b/src/mono_opt.sig
@@ -28,5 +28,6 @@
signature MONO_OPT = sig
val optimize : Mono.file -> Mono.file
+ val optExp : Mono.exp -> Mono.exp
end
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index b56372c7..6c0e6e21 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -366,4 +366,6 @@ and optExp e = #1 (U.Exp.map {typ = typ, exp = exp} e)
val optimize = U.File.map {typ = typ, exp = exp, decl = decl}
+val optExp = U.Exp.map {typ = typ, exp = exp}
+
end
diff --git a/src/mono_util.sig b/src/mono_util.sig
index 4e9d5d91..32a83855 100644
--- a/src/mono_util.sig
+++ b/src/mono_util.sig
@@ -90,6 +90,11 @@ structure Decl : sig
exp : Mono.exp' * 'state -> 'state,
decl : Mono.decl' * 'state -> 'state}
-> 'state -> Mono.decl -> 'state
+
+ val map : {typ : Mono.typ' -> Mono.typ',
+ exp : Mono.exp' -> Mono.exp',
+ decl : Mono.decl' -> Mono.decl'}
+ -> Mono.decl -> Mono.decl
end
structure File : sig
@@ -121,6 +126,8 @@ structure File : sig
exp : Mono.exp' * 'state -> 'state,
decl : Mono.decl' * 'state -> 'state}
-> 'state -> Mono.file -> 'state
+
+ val maxName : Mono.file -> int
end
end
diff --git a/src/mono_util.sml b/src/mono_util.sml
index 14ab1674..2b2476e7 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -422,6 +422,13 @@ fun fold {typ, exp, decl} s d =
S.Continue (_, s) => s
| S.Return _ => raise Fail "MonoUtil.Decl.fold: Impossible"
+fun map {typ, exp, decl} e =
+ case mapfold {typ = fn c => fn () => S.Continue (typ c, ()),
+ exp = fn e => fn () => S.Continue (exp e, ()),
+ decl = fn d => fn () => S.Continue (decl d, ())} e () of
+ S.Return () => raise Fail "MonoUtil.Decl.map: Impossible"
+ | S.Continue (e, ()) => e
+
end
structure File = struct
@@ -490,7 +497,7 @@ fun map {typ, exp, decl} e =
case mapfold {typ = fn c => fn () => S.Continue (typ c, ()),
exp = fn e => fn () => S.Continue (exp e, ()),
decl = fn d => fn () => S.Continue (decl d, ())} e () of
- S.Return () => raise Fail "Mono_util.File.map"
+ S.Return () => raise Fail "MonoUtil.File.map: Impossible"
| S.Continue (e, ()) => e
fun fold {typ, exp, decl} s d =
@@ -500,6 +507,18 @@ 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 (_, n, ns) =>
+ foldl (fn ((_, n', _), m) => Int.max (n', m))
+ (Int.max (n, count)) ns
+ | DVal (_, n, _, _, _) => Int.max (n, count)
+ | DValRec vis => foldl (fn ((_, n, _, _, _), count) => Int.max (n, count)) count vis
+ | DExport _ => count
+ | DTable _ => count
+ | DSequence _ => count
+ | DDatabase _ => count) 0
+
end
end
diff --git a/src/sources b/src/sources
index bddcac67..13f505d0 100644
--- a/src/sources
+++ b/src/sources
@@ -140,6 +140,9 @@ mono_shake.sml
pathcheck.sig
pathcheck.sml
+fuse.sig
+fuse.sml
+
cjr.sml
cjr_env.sig
--
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_opt.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 a08075494d9c16a349215fbcaefa3e1d14d2e0f9 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sat, 20 Dec 2008 14:19:21 -0500
Subject: Start of JsComp
---
src/compiler.sig | 2 +
src/compiler.sml | 9 +-
src/jscomp.sig | 32 +++++
src/jscomp.sml | 344 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/mono_env.sig | 1 +
src/mono_env.sml | 11 ++
src/mono_opt.sml | 5 -
src/mono_util.sig | 11 ++
src/mono_util.sml | 15 +++
src/prim.sig | 2 +
src/prim.sml | 6 +
src/sources | 3 +
tests/alert.ur | 2 +-
13 files changed, 436 insertions(+), 7 deletions(-)
create mode 100644 src/jscomp.sig
create mode 100644 src/jscomp.sml
(limited to 'src/mono_opt.sml')
diff --git a/src/compiler.sig b/src/compiler.sig
index 59ad32be..1f1f4973 100644
--- a/src/compiler.sig
+++ b/src/compiler.sig
@@ -75,6 +75,7 @@ signature COMPILER = sig
val untangle : (Mono.file, Mono.file) phase
val mono_reduce : (Mono.file, Mono.file) phase
val mono_shake : (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 cjrize : (Mono.file, Cjr.file) phase
@@ -101,6 +102,7 @@ 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 toFuse : (string, Mono.file) transform
val toUntangle2 : (string, Mono.file) transform
diff --git a/src/compiler.sml b/src/compiler.sml
index 0ff4ee6a..ecee1065 100644
--- a/src/compiler.sml
+++ b/src/compiler.sml
@@ -511,7 +511,14 @@ 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 toMono_opt2 = transform mono_opt "mono_opt2" o toJscomp
val fuse = {
func = Fuse.fuse,
diff --git a/src/jscomp.sig b/src/jscomp.sig
new file mode 100644
index 00000000..929c507d
--- /dev/null
+++ b/src/jscomp.sig
@@ -0,0 +1,32 @@
+(* Copyright (c) 2008, 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 JSCOMP = sig
+
+ val process : Mono.file -> Mono.file
+
+end
diff --git a/src/jscomp.sml b/src/jscomp.sml
new file mode 100644
index 00000000..0dd7882a
--- /dev/null
+++ b/src/jscomp.sml
@@ -0,0 +1,344 @@
+(* Copyright (c) 2008, 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 JsComp :> JSCOMP = struct
+
+open Mono
+
+structure EM = ErrorMsg
+structure E = MonoEnv
+structure U = MonoUtil
+
+type state = {
+ decls : decl list,
+ script : string
+}
+
+fun varDepth (e, _) =
+ case e of
+ EPrim _ => 0
+ | ERel _ => 0
+ | ENamed _ => 0
+ | ECon (_, _, NONE) => 0
+ | ECon (_, _, SOME e) => varDepth e
+ | ENone _ => 0
+ | ESome (_, e) => varDepth e
+ | EFfi _ => 0
+ | EFfiApp (_, _, es) => foldl Int.max 0 (map varDepth es)
+ | EApp (e1, e2) => Int.max (varDepth e1, varDepth e2)
+ | EAbs _ => 0
+ | EUnop (_, e) => varDepth e
+ | EBinop (_, e1, e2) => Int.max (varDepth e1, varDepth e2)
+ | ERecord xes => foldl Int.max 0 (map (fn (_, e, _) => varDepth e) xes)
+ | EField (e, _) => varDepth e
+ | ECase (e, pes, _) =>
+ foldl Int.max (varDepth e)
+ (map (fn (p, e) => E.patBindsN p + varDepth e) pes)
+ | EStrcat (e1, e2) => Int.max (varDepth e1, varDepth e2)
+ | EError (e, _) => varDepth e
+ | EWrite e => varDepth e
+ | ESeq (e1, e2) => Int.max (varDepth e1, varDepth e2)
+ | ELet (_, _, e1, e2) => Int.max (varDepth e1, 1 + varDepth e2)
+ | EClosure _ => 0
+ | EQuery _ => 0
+ | EDml _ => 0
+ | ENextval _ => 0
+ | EUnurlify _ => 0
+ | EJavaScript _ => 0
+
+fun jsExp inAttr outer =
+ let
+ val len = length outer
+
+ fun jsE inner (e as (_, loc), st) =
+ let
+ fun str s = (EPrim (Prim.String s), loc)
+
+ fun var n = Int.toString (len + inner - n - 1)
+
+ fun patCon pc =
+ case pc of
+ 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
+ TOption _ => true
+ | _ => false
+
+ fun unsupported s =
+ (EM.errorAt loc (s ^ " in code to be compiled to JavaScript");
+ (str "ERROR", st))
+ in
+ case #1 e of
+ EPrim (Prim.String s) =>
+ (str ("\""
+ ^ String.translate (fn #"'" =>
+ if inAttr then
+ "\\047"
+ else
+ "'"
+ | #"<" =>
+ if inAttr then
+ "<"
+ else
+ "\\074"
+ | #"\\" => "\\\\"
+ | ch => String.str ch) s
+ ^ "\""), st)
+ | EPrim p => (str (Prim.toString p), st)
+ | ERel n =>
+ if n < inner then
+ (str ("uwr" ^ var n), st)
+ else
+ (str ("uwo" ^ var n), st)
+ | ENamed _ => raise Fail "Named"
+ | ECon (_, pc, NONE) => (patCon pc, st)
+ | ECon (_, pc, SOME e) =>
+ let
+ val (s, st) = jsE inner (e, st)
+ in
+ (strcat [str "{n:",
+ patCon pc,
+ str ",v:",
+ s,
+ str "}"], st)
+ end
+ | ENone _ => (str "null", st)
+ | ESome (t, e) =>
+ let
+ val (e, st) = jsE inner (e, st)
+ in
+ (if isNullable t then
+ strcat [str "{v:", e, str "}"]
+ else
+ e, st)
+ end
+
+ | EFfi (_, s) => (str s, st)
+ | EFfiApp (_, s, []) => (str (s ^ "()"), st)
+ | EFfiApp (_, s, [e]) =>
+ let
+ val (e, st) = jsE inner (e, st)
+
+ in
+ (strcat [str (s ^ "("),
+ e,
+ str ")"], st)
+ end
+ | EFfiApp (_, s, 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 (s ^ "(")
+ :: e
+ :: es
+ @ [str ")"]), st)
+ end
+
+ | EApp (e1, e2) =>
+ let
+ val (e1, st) = jsE inner (e1, st)
+ val (e2, st) = jsE inner (e2, st)
+ in
+ (strcat [e1, str "(", e2, str ")"], st)
+ end
+ | EAbs (_, _, _, e) =>
+ let
+ val locals = List.tabulate
+ (varDepth e,
+ fn i => str ("var uwr" ^ Int.toString (len + inner + i) ^ ";"))
+ val (e, st) = jsE (inner + 1) (e, st)
+ in
+ (strcat (str ("function(uwr"
+ ^ Int.toString (len + inner)
+ ^ "){")
+ :: locals
+ @ [str "return ",
+ e,
+ str "}"]),
+ st)
+ end
+
+ | EUnop (s, e) =>
+ let
+ val (e, st) = jsE inner (e, st)
+ in
+ (strcat [str ("(" ^ s),
+ e,
+ str ")"],
+ st)
+ end
+ | EBinop (s, e1, e2) =>
+ let
+ val (e1, st) = jsE inner (e1, st)
+ val (e2, st) = jsE inner (e2, st)
+ in
+ (strcat [str "(",
+ e1,
+ str s,
+ e2,
+ str ")"],
+ st)
+ end
+
+ | ERecord [] => (str "null", st)
+ | ERecord [(x, e, _)] =>
+ let
+ val (e, st) = jsE inner (e, st)
+ in
+ (strcat [str "{uw_x:", e, str "}"], st)
+ end
+ | ERecord ((x, e, _) :: xes) =>
+ let
+ val (e, st) = jsE inner (e, st)
+
+ val (es, st) =
+ foldr (fn ((x, e, _), (es, st)) =>
+ let
+ val (e, st) = jsE inner (e, st)
+ in
+ (str (",uw_" ^ x ^ ":")
+ :: e
+ :: es,
+ st)
+ end)
+ ([str "}"], st) xes
+ in
+ (strcat (str ("{uw_" ^ x ^ ":")
+ :: e
+ :: es),
+ st)
+ end
+ | EField (e, x) =>
+ let
+ val (e, st) = jsE inner (e, st)
+ in
+ (strcat [e,
+ str ("." ^ x)], st)
+ end
+
+ | ECase _ => raise Fail "Jscomp: ECase"
+
+ | EStrcat (e1, e2) =>
+ let
+ val (e1, st) = jsE inner (e1, st)
+ val (e2, st) = jsE inner (e2, st)
+ in
+ (strcat [str "(", e1, str "+", e2, str ")"], st)
+ end
+
+ | EError (e, _) =>
+ let
+ val (e, st) = jsE inner (e, st)
+ in
+ (strcat [str "alert(\"ERROR: \"+", e, str ")"],
+ st)
+ end
+
+ | EWrite _ => unsupported "EWrite"
+
+ | ESeq (e1, e2) =>
+ let
+ val (e1, st) = jsE inner (e1, st)
+ val (e2, st) = jsE inner (e2, st)
+ in
+ (strcat [str "(", e1, str ",", e2, str ")"], st)
+ end
+ | ELet (_, _, e1, e2) =>
+ let
+ val (e1, st) = jsE inner (e1, st)
+ val (e2, st) = jsE (inner + 1) (e2, st)
+ in
+ (strcat [str ("(uwr" ^ Int.toString (len + inner) ^ "="),
+ e1,
+ str ",",
+ e2,
+ str ")"], st)
+ end
+
+ | EClosure _ => unsupported "EClosure"
+ | EQuery _ => unsupported "Query"
+ | EDml _ => unsupported "DML"
+ | ENextval _ => unsupported "Nextval"
+ | EUnurlify _ => unsupported "EUnurlify"
+ | EJavaScript _ => unsupported "Nested JavaScript"
+ end
+ in
+ jsE
+ end
+
+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),
+ decl = fn (_, e, st) => (e, st),
+ bind = fn (env, U.Decl.RelE (_, t)) => t :: env
+ | (env, _) => env}
+ []
+
+fun process file =
+ let
+ fun doDecl (d, st) =
+ let
+ val (d, st) = decl st d
+ in
+ (List.revAppend (#decls st, [d]),
+ {decls = [],
+ script = #script st})
+ end
+
+ val (ds, st) = ListUtil.foldlMapConcat doDecl
+ {decls = [],
+ script = ""}
+ file
+ in
+ ds
+ end
+
+end
diff --git a/src/mono_env.sig b/src/mono_env.sig
index cb6f2352..c59596ae 100644
--- a/src/mono_env.sig
+++ b/src/mono_env.sig
@@ -47,5 +47,6 @@ signature MONO_ENV = sig
val declBinds : env -> Mono.decl -> env
val patBinds : env -> Mono.pat -> env
+ val patBindsN : Mono.pat -> int
end
diff --git a/src/mono_env.sml b/src/mono_env.sml
index 47ffd28d..cce4a4c4 100644
--- a/src/mono_env.sml
+++ b/src/mono_env.sml
@@ -122,4 +122,15 @@ fun patBinds env (p, loc) =
| PNone _ => env
| PSome (_, p) => patBinds env p
+fun patBindsN (p, loc) =
+ case p of
+ PWild => 0
+ | PVar _ => 1
+ | PPrim _ => 0
+ | PCon (_, _, NONE) => 0
+ | PCon (_, _, SOME p) => patBindsN p
+ | PRecord xps => foldl (fn ((_, p, _), count) => count + patBindsN p) 0 xps
+ | PNone _ => 0
+ | PSome (_, p) => patBindsN p
+
end
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index 7f83c003..6c0e6e21 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -360,11 +360,6 @@ 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_util.sig b/src/mono_util.sig
index 32a83855..2a96211a 100644
--- a/src/mono_util.sig
+++ b/src/mono_util.sig
@@ -71,6 +71,11 @@ structure Exp : sig
val exists : {typ : Mono.typ' -> bool,
exp : Mono.exp' -> bool} -> Mono.exp -> bool
+
+ val foldB : {typ : Mono.typ' * 'state -> 'state,
+ exp : 'context * Mono.exp' * 'state -> 'state,
+ bind : 'context * binder -> 'context}
+ -> 'context -> 'state -> Mono.exp -> 'state
end
structure Decl : sig
@@ -95,6 +100,12 @@ structure Decl : sig
exp : Mono.exp' -> Mono.exp',
decl : Mono.decl' -> Mono.decl'}
-> Mono.decl -> Mono.decl
+
+ val foldMapB : {typ : Mono.typ' * 'state -> Mono.typ' * 'state,
+ exp : 'context * Mono.exp' * 'state -> Mono.exp' * 'state,
+ decl : 'context * Mono.decl' * 'state -> Mono.decl' * 'state,
+ bind : 'context * binder -> 'context}
+ -> 'context -> 'state -> Mono.decl -> Mono.decl * 'state
end
structure File : sig
diff --git a/src/mono_util.sml b/src/mono_util.sml
index 18b5c948..ebc30984 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -357,6 +357,13 @@ fun exists {typ, exp} k =
S.Return _ => true
| S.Continue _ => false
+fun foldB {typ, exp, bind} ctx s e =
+ case mapfoldB {typ = fn t => fn s => S.Continue (t, typ (t, s)),
+ exp = fn ctx => fn e => fn s => S.Continue (e, exp (ctx, e, s)),
+ bind = bind} ctx e s of
+ S.Continue (_, s) => s
+ | S.Return _ => raise Fail "MonoUtil.Exp.foldB: Impossible"
+
end
structure Decl = struct
@@ -433,6 +440,14 @@ fun map {typ, exp, decl} e =
S.Return () => raise Fail "MonoUtil.Decl.map: Impossible"
| S.Continue (e, ()) => e
+fun foldMapB {typ, exp, decl, bind} ctx s d =
+ case mapfoldB {typ = fn c => fn s => S.Continue (typ (c, s)),
+ exp = fn ctx => fn e => fn s => S.Continue (exp (ctx, e, s)),
+ decl = fn ctx => fn d => fn s => S.Continue (decl (ctx, d, s)),
+ bind = bind} ctx d s of
+ S.Continue v => v
+ | S.Return _ => raise Fail "MonoUtil.Decl.foldMapB: Impossible"
+
end
structure File = struct
diff --git a/src/prim.sig b/src/prim.sig
index 3083a26e..54625379 100644
--- a/src/prim.sig
+++ b/src/prim.sig
@@ -38,4 +38,6 @@ signature PRIM = sig
val equal : t * t -> bool
val compare : t * t -> order
+ val toString : t -> string
+
end
diff --git a/src/prim.sml b/src/prim.sml
index daf666e8..468b28d5 100644
--- a/src/prim.sml
+++ b/src/prim.sml
@@ -53,6 +53,12 @@ fun float2s n =
else
Real64.toString n
+fun toString t =
+ case t of
+ Int n => int2s n
+ | Float n => float2s n
+ | String s => s
+
fun p_t_GCC t =
case t of
Int n => string (int2s n)
diff --git a/src/sources b/src/sources
index 6972dc36..05b1cc54 100644
--- a/src/sources
+++ b/src/sources
@@ -137,6 +137,9 @@ untangle.sml
mono_shake.sig
mono_shake.sml
+jscomp.sig
+jscomp.sml
+
pathcheck.sig
pathcheck.sml
diff --git a/tests/alert.ur b/tests/alert.ur
index 7b2eaacf..3fe68d75 100644
--- a/tests/alert.ur
+++ b/tests/alert.ur
@@ -1,3 +1,3 @@
fun main () : transaction page = return
- Click Me!
+ Click Me!
--
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_opt.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 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_opt.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 b8e7b835e7cde4cf374138467da8b16e93a65eb9 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Tue, 10 Mar 2009 15:17:23 -0400
Subject: Batch example
---
demo/batch.ur | 80 +++++++++
demo/batch.urp | 3 +
demo/batch.urs | 1 +
demo/increment.urp | 1 -
demo/prose | 4 +
lib/js/urweb.js | 25 ++-
src/jscomp.sml | 6 +-
src/mono_opt.sml | 2 +
src/rpcify.sml | 506 +++++++++++++++++++++++++++++------------------------
9 files changed, 395 insertions(+), 233 deletions(-)
create mode 100644 demo/batch.ur
create mode 100644 demo/batch.urp
create mode 100644 demo/batch.urs
(limited to 'src/mono_opt.sml')
diff --git a/demo/batch.ur b/demo/batch.ur
new file mode 100644
index 00000000..454ff691
--- /dev/null
+++ b/demo/batch.ur
@@ -0,0 +1,80 @@
+datatype list t = Nil | Cons of t * list t
+
+table t : {Id : int, A : string}
+
+fun allRows () =
+ query (SELECT * FROM t)
+ (fn r acc => return (Cons ((r.T.Id, r.T.A), acc)))
+ Nil
+
+fun doBatch ls =
+ case ls of
+ Nil => return ()
+ | Cons ((id, a), ls') =>
+ dml (INSERT INTO t (Id, A) VALUES ({[id]}, {[a]}));
+ doBatch ls'
+
+fun del id =
+ dml (DELETE FROM t WHERE t.Id = {[id]})
+
+fun show withDel lss =
+ let
+ fun show' ls =
+ case ls of
+ Nil =>
+ | Cons ((id, a), ls) =>
+
{[id]}
{[a]}
{if withDel then
+
+ else
+ }
+ {show' ls}
+
+ in
+
+
Id
A
+ {show' ls}
+
}/>
+ end
+
+fun main () =
+ lss <- source Nil;
+ batched <- source Nil;
+
+ id <- source "";
+ a <- source "";
+
+ let
+ fun add () =
+ id <- get id;
+ a <- get a;
+ ls <- get batched;
+
+ set batched (Cons ((readError id, a), ls))
+
+ fun exec () =
+ ls <- get batched;
+
+ doBatch ls;
+ set batched Nil
+ in
+ return
+
Here's an example where client-side code needs to run more code on the server. We maintain a (server-side) SQL sequence. When the user clicks a button, an AJAX request increments the remote sequence and gets the new value.
+
+batch.urp
+
+
This example shows more of what is possible with mixed client/server code. The application is an editor for a simple database table, where additions of new rows can be batched in the client, before a button is clicked to trigger a mass addition.
diff --git a/lib/js/urweb.js b/lib/js/urweb.js
index 158e574d..08d96040 100644
--- a/lib/js/urweb.js
+++ b/lib/js/urweb.js
@@ -99,7 +99,26 @@ function eh(x) {
function ts(x) { return x.toString() }
function bs(b) { return (b ? "True" : "False") }
-function pf() { alert("Pattern match failure") }
+function pi(s) {
+ var r = parseInt(s);
+ if (r.toString() == s)
+ return r;
+ else
+ throw "Can't parse int: " + s;
+}
+
+function pfl(s) {
+ var r = parseFloat(s);
+ if (r.toString() == s)
+ return r;
+ else
+ throw "Can't parse float: " + s;
+}
+
+function pf() {
+ alert("Pattern match failure");
+ throw "Pattern match failure";
+}
var closures = [];
@@ -145,8 +164,10 @@ function rc(uri, parse, k) {
if (isok)
k(parse(xhr.responseText));
- else
+ else {
alert("Error querying remote server!");
+ throw "Error querying remote server!";
+ }
}
};
diff --git a/src/jscomp.sml b/src/jscomp.sml
index 37bbf79d..adff2fda 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -44,6 +44,8 @@ val funcs = [(("Basis", "alert"), "alert"),
(("Basis", "htmlifyString"), "eh"),
(("Basis", "new_client_source"), "sc"),
(("Basis", "set_client_source"), "sv"),
+ (("Basis", "stringToFloat_error"), "pfl"),
+ (("Basis", "stringToInt_error"), "pi"),
(("Basis", "urlifyInt"), "ts"),
(("Basis", "urlifyFloat"), "ts"),
(("Basis", "urlifyString"), "escape")]
@@ -893,7 +895,7 @@ fun process file =
| EDml _ => unsupported "DML"
| ENextval _ => unsupported "Nextval"
| EUnurlify _ => unsupported "EUnurlify"
- | EJavaScript (_, e as (EAbs _, _), _) =>
+ (*| EJavaScript (_, e as (EAbs _, _), _) =>
let
val (e, st) = jsE inner (e, st)
in
@@ -901,7 +903,7 @@ fun process file =
e,
str ")+\")\""],
st)
- end
+ end*)
| EJavaScript (_, e, _) =>
let
val (e, st) = jsE inner (e, st)
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index 7f23d8b1..469fc0d8 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -365,6 +365,8 @@ fun exp e =
| EJavaScript (_, _, SOME (e, _)) => e
+ | EApp ((e1 as EServerCall _, _), (ERecord [], _)) => e1
+
| _ => e
and optExp e = #1 (U.Exp.map {typ = typ, exp = exp} e)
diff --git a/src/rpcify.sml b/src/rpcify.sml
index 0b336a3d..7e731f63 100644
--- a/src/rpcify.sml
+++ b/src/rpcify.sml
@@ -140,242 +140,292 @@ fun frob file =
IM.empty file
fun exp (e, st) =
- case e of
- EApp (
- (EApp
- ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), loc), _), _), t1), _), t2), _),
- (EFfi ("Basis", "transaction_monad"), _)), _),
- (ECase (ed, pes, {disc, ...}), _)), _),
- trans2) =>
- let
- val e' = (EFfi ("Basis", "bind"), loc)
- val e' = (ECApp (e', (CFfi ("Basis", "transaction"), loc)), loc)
- val e' = (ECApp (e', t1), loc)
- val e' = (ECApp (e', t2), loc)
- val e' = (EApp (e', (EFfi ("Basis", "transaction_monad"), loc)), loc)
-
- val (pes, st) = ListUtil.foldlMap (fn ((p, e), st) =>
- let
- val e' = (EApp (e', e), loc)
- val e' = (EApp (e',
- multiLiftExpInExp (E.patBindsN p)
- trans2), loc)
- val (e', st) = doExp (e', st)
- in
- ((p, e'), st)
- end) st pes
- in
- (ECase (ed, pes, {disc = disc,
- result = (CApp ((CFfi ("Basis", "transaction"), loc), t2), loc)}),
- st)
- end
-
- | EApp (
- (EApp
- ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), loc), _), _), t1), _), t2), _),
- (EFfi ("Basis", "transaction_monad"), _)), _),
- (EServerCall (n, es, ke, t), _)), _),
- trans2) =>
- let
- val e' = (EFfi ("Basis", "bind"), loc)
- val e' = (ECApp (e', (CFfi ("Basis", "transaction"), loc)), loc)
- val e' = (ECApp (e', t), 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", t, t2, e'), loc)
- val e' = (EServerCall (n, es, e', t), loc)
- val (e', st) = doExp (e', st)
- in
- (#1 e', st)
- end
-
- | EApp (
- (EApp
- ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), loc), _), _), _), _), t3), _),
- (EFfi ("Basis", "transaction_monad"), _)), _),
- (EApp ((EApp
- ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), _), _), _), t1), _), t2), _),
- (EFfi ("Basis", "transaction_monad"), _)), _),
- trans1), _), trans2), _)), _),
- trans3) =>
- let
- val e'' = (EFfi ("Basis", "bind"), loc)
- val e'' = (ECApp (e'', (CFfi ("Basis", "transaction"), loc)), loc)
- val e'' = (ECApp (e'', t2), loc)
- val e'' = (ECApp (e'', t3), loc)
- val e'' = (EApp (e'', (EFfi ("Basis", "transaction_monad"), loc)), 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 ("x", t1, (CApp ((CFfi ("Basis", "transaction"), loc), t3), loc), e''), loc)
-
- val e' = (EFfi ("Basis", "bind"), loc)
- val e' = (ECApp (e', (CFfi ("Basis", "transaction"), loc)), loc)
- val e' = (ECApp (e', t1), loc)
- val e' = (ECApp (e', t3), loc)
- val e' = (EApp (e', (EFfi ("Basis", "transaction_monad"), loc)), loc)
- val e' = (EApp (e', trans1), loc)
- val e' = (EApp (e', e''), loc)
- val (e', st) = doExp (e', st)
- in
- (#1 e', st)
- end
-
- | EApp (
- (EApp
- ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), _), _), _), _), _), _), _),
- (EFfi ("Basis", "transaction_monad"), _)), _),
- _), loc),
- (EAbs (_, _, _, (EWrite _, _)), _)) => (e, st)
-
- | EApp (
- (EApp
- ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), _), _), _), t1), _), t2), _),
- (EFfi ("Basis", "transaction_monad"), _)), _),
- trans1), loc),
- trans2) =>
- let
- (*val () = Print.prefaces "Default"
- [("e", CorePrint.p_exp CoreEnv.empty (e, ErrorMsg.dummySpan))]*)
-
- fun getApp (e', args) =
+ let
+ fun getApp (e', args) =
+ let
+ val loc = #2 e'
+ in
case #1 e' of
ENamed n => (n, args)
| EApp (e1, e2) => getApp (e1, e2 :: args)
| _ => (ErrorMsg.errorAt loc "Mixed client/server code doesn't use a named function for server part";
Print.prefaces "Bad" [("e", CorePrint.p_exp CoreEnv.empty (e, ErrorMsg.dummySpan))];
(0, []))
- in
- case (serverSide (#cpsed_range st) trans1, clientSide (#cpsed_range st) trans1,
- serverSide (#cpsed_range st) trans2, clientSide (#cpsed_range st) trans2) of
- (true, false, _, true) =>
- let
- 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,
- cpsed_range = #cpsed_range st,
- cps_decls = #cps_decls st,
-
- exported = exported,
- export_decls = export_decls,
-
- maxName = #maxName st}
-
- val ran =
- case IM.find (tfuncs, n) of
- NONE => (Print.prefaces "BAD" [("e", CorePrint.p_exp CoreEnv.empty (e, loc))];
- raise Fail ("Rpcify: Undetected transaction function " ^ Int.toString n))
- | SOME (_, _, ran, _) => ran
-
- val e' = EServerCall (n, args, trans2, ran)
- in
- (EServerCall (n, args, trans2, ran), st)
- end
- | (true, true, _, _) =>
- let
- val (n, args) = getApp (trans1, [])
-
- fun makeCall n' =
- let
- val e = (ENamed n', loc)
- val e = (EApp (e, trans2), loc)
- in
- #1 (foldl (fn (arg, e) => (EApp (e, arg), loc)) e args)
- end
- in
- case IM.find (#cpsed_range st, n) of
- SOME kdom =>
- (case args of
- [] => raise Fail "Rpcify: cps'd function lacks first argument"
- | ke :: args =>
+ end
+
+ fun newRpc (trans1, trans2, st : state) =
+ let
+ val loc = #2 trans1
+
+ 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,
+ cpsed_range = #cpsed_range st,
+ cps_decls = #cps_decls st,
+
+ exported = exported,
+ export_decls = export_decls,
+
+ maxName = #maxName st}
+
+ val ran =
+ case IM.find (tfuncs, n) of
+ NONE => (Print.prefaces "BAD" [("e", CorePrint.p_exp CoreEnv.empty (e, loc))];
+ raise Fail ("Rpcify: Undetected transaction function " ^ Int.toString n))
+ | SOME (_, _, ran, _) => ran
+
+ val e' = EServerCall (n, args, trans2, ran)
+ in
+ (e', st)
+ end
+ in
+ case e of
+ EApp (
+ (EApp
+ ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), loc), _), _), t1), _), t2), _),
+ (EFfi ("Basis", "transaction_monad"), _)), _),
+ (ECase (ed, pes, {disc, ...}), _)), _),
+ trans2) =>
+ let
+ val e' = (EFfi ("Basis", "bind"), loc)
+ val e' = (ECApp (e', (CFfi ("Basis", "transaction"), loc)), loc)
+ val e' = (ECApp (e', t1), loc)
+ val e' = (ECApp (e', t2), loc)
+ val e' = (EApp (e', (EFfi ("Basis", "transaction_monad"), loc)), loc)
+
+ val (pes, st) = ListUtil.foldlMap (fn ((p, e), st) =>
+ let
+ val e' = (EApp (e', e), loc)
+ val e' = (EApp (e',
+ multiLiftExpInExp (E.patBindsN p)
+ trans2), loc)
+ val (e', st) = doExp (e', st)
+ in
+ ((p, e'), st)
+ end) st pes
+ in
+ (ECase (ed, pes, {disc = disc,
+ result = (CApp ((CFfi ("Basis", "transaction"), loc), t2), loc)}),
+ st)
+ end
+
+ | EApp (
+ (EApp
+ ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), loc), _), _), t1), _), t2), _),
+ (EFfi ("Basis", "transaction_monad"), _)), _),
+ (EServerCall (n, es, ke, t), _)), _),
+ trans2) =>
+ let
+ val e' = (EFfi ("Basis", "bind"), loc)
+ val e' = (ECApp (e', (CFfi ("Basis", "transaction"), loc)), loc)
+ val e' = (ECApp (e', t), 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", t, t2, e'), loc)
+ val e' = (EServerCall (n, es, e', t), loc)
+ val (e', st) = doExp (e', st)
+ in
+ (#1 e', st)
+ end
+
+ | EApp (
+ (EApp
+ ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), loc), _), _), _), _), t3), _),
+ (EFfi ("Basis", "transaction_monad"), _)), _),
+ (EApp ((EApp
+ ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), _), _), _), t1), _), t2), _),
+ (EFfi ("Basis", "transaction_monad"), _)), _),
+ trans1), _), trans2), _)), _),
+ trans3) =>
+ let
+ val e'' = (EFfi ("Basis", "bind"), loc)
+ val e'' = (ECApp (e'', (CFfi ("Basis", "transaction"), loc)), loc)
+ val e'' = (ECApp (e'', t2), loc)
+ val e'' = (ECApp (e'', t3), loc)
+ val e'' = (EApp (e'', (EFfi ("Basis", "transaction_monad"), loc)), 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 ("x", t1, (CApp ((CFfi ("Basis", "transaction"), loc), t3), loc), e''), loc)
+
+ val e' = (EFfi ("Basis", "bind"), loc)
+ val e' = (ECApp (e', (CFfi ("Basis", "transaction"), loc)), loc)
+ val e' = (ECApp (e', t1), loc)
+ val e' = (ECApp (e', t3), loc)
+ val e' = (EApp (e', (EFfi ("Basis", "transaction_monad"), loc)), loc)
+ val e' = (EApp (e', trans1), loc)
+ val e' = (EApp (e', e''), loc)
+ val (e', st) = doExp (e', st)
+ in
+ (#1 e', st)
+ end
+
+ | EApp (
+ (EApp
+ ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), _), _), _), _), _), _), _),
+ (EFfi ("Basis", "transaction_monad"), _)), _),
+ _), loc),
+ (EAbs (_, _, _, (EWrite _, _)), _)) => (e, st)
+
+ | EApp (
+ (EApp
+ ((EApp ((ECApp ((ECApp ((ECApp ((EFfi ("Basis", "bind"), _), _), _), t1), _), t2), _),
+ (EFfi ("Basis", "transaction_monad"), _)), _),
+ trans1), loc),
+ trans2) =>
+ (case (serverSide (#cpsed_range st) trans1, clientSide (#cpsed_range st) trans1,
+ serverSide (#cpsed_range st) trans2, clientSide (#cpsed_range st) trans2) of
+ (true, false, _, true) => newRpc (trans1, trans2, st)
+ | (true, true, _, _) =>
+ let
+ val (n, args) = getApp (trans1, [])
+
+ fun makeCall n' =
+ let
+ val e = (ENamed n', loc)
+ val e = (EApp (e, trans2), loc)
+ in
+ #1 (foldl (fn (arg, e) => (EApp (e, arg), loc)) e args)
+ end
+ in
+ case IM.find (#cpsed_range st, n) of
+ SOME kdom =>
+ (case args of
+ [] => raise Fail "Rpcify: cps'd function lacks first argument"
+ | ke :: args =>
+ let
+ val ke' = (EFfi ("Basis", "bind"), loc)
+ val ke' = (ECApp (ke', (CFfi ("Basis", "transaction"), loc)), loc)
+ val ke' = (ECApp (ke', kdom), loc)
+ val ke' = (ECApp (ke', t2), loc)
+ val ke' = (EApp (ke', (EFfi ("Basis", "transaction_monad"), loc)), loc)
+ val ke' = (EApp (ke', (EApp (E.liftExpInExp 0 ke, (ERel 0, loc)), loc)), loc)
+ val ke' = (EApp (ke', E.liftExpInExp 0 trans2), loc)
+ val ke' = (EAbs ("x", kdom,
+ (CApp ((CFfi ("Basis", "transaction"), loc), t2), loc),
+ ke'), loc)
+
+ val e' = (ENamed n, loc)
+ val e' = (EApp (e', ke'), loc)
+ val e' = foldl (fn (arg, e') => (EApp (e', arg), loc)) e' args
+ val (e', st) = doExp (e', st)
+ in
+ (#1 e', st)
+ end)
+ | NONE =>
+ case IM.find (#cpsed st, n) of
+ SOME n' => (makeCall n', st)
+ | NONE =>
let
- val ke' = (EFfi ("Basis", "bind"), loc)
- val ke' = (ECApp (ke', (CFfi ("Basis", "transaction"), loc)), loc)
- val ke' = (ECApp (ke', kdom), loc)
- val ke' = (ECApp (ke', t2), loc)
- val ke' = (EApp (ke', (EFfi ("Basis", "transaction_monad"), loc)), loc)
- val ke' = (EApp (ke', (EApp (E.liftExpInExp 0 ke, (ERel 0, loc)), loc)), loc)
- val ke' = (EApp (ke', E.liftExpInExp 0 trans2), loc)
- val ke' = (EAbs ("x", kdom,
- (CApp ((CFfi ("Basis", "transaction"), loc), t2), loc),
- ke'), loc)
-
- val e' = (ENamed n, loc)
- val e' = (EApp (e', ke'), loc)
- val e' = foldl (fn (arg, e') => (EApp (e', arg), loc)) e' args
- val (e', st) = doExp (e', st)
+ val (name, fargs, ran, e) =
+ case IM.find (tfuncs, n) of
+ NONE => (Print.prefaces "BAD" [("e",
+ CorePrint.p_exp CoreEnv.empty (e, loc))];
+ raise Fail "Rpcify: Undetected transaction function [2]")
+ | SOME x => x
+
+ val n' = #maxName st
+
+ val st = {cpsed = IM.insert (#cpsed st, n, n'),
+ cpsed_range = IM.insert (#cpsed_range st, n', ran),
+ cps_decls = #cps_decls st,
+ exported = #exported st,
+ export_decls = #export_decls st,
+ maxName = n' + 1}
+
+ val unit = (TRecord (CRecord ((KType, loc), []), loc), loc)
+ val body = (EFfi ("Basis", "bind"), loc)
+ val body = (ECApp (body, (CFfi ("Basis", "transaction"), loc)), loc)
+ val body = (ECApp (body, t1), loc)
+ val body = (ECApp (body, unit), loc)
+ val body = (EApp (body, (EFfi ("Basis", "transaction_monad"), loc)), loc)
+ val body = (EApp (body, e), loc)
+ val body = (EApp (body, (ERel (length args), loc)), loc)
+ val bt = (CApp ((CFfi ("Basis", "transaction"), loc), unit), loc)
+ val (body, bt) = foldr (fn ((x, t), (body, bt)) =>
+ ((EAbs (x, t, bt, body), loc),
+ (TFun (t, bt), loc)))
+ (body, bt) fargs
+ val kt = (TFun (ran, (CApp ((CFfi ("Basis", "transaction"), loc),
+ unit),
+ loc)), loc)
+ val body = (EAbs ("k", kt, bt, body), loc)
+ val bt = (TFun (kt, bt), loc)
+
+ val (body, st) = doExp (body, st)
+
+ val vi = (name ^ "_cps",
+ n',
+ bt,
+ body,
+ "")
+
+ val st = {cpsed = #cpsed st,
+ cpsed_range = #cpsed_range st,
+ cps_decls = vi :: #cps_decls st,
+ exported = #exported st,
+ export_decls = #export_decls st,
+ maxName = #maxName st}
in
- (#1 e', st)
- end)
- | NONE =>
- case IM.find (#cpsed st, n) of
- SOME n' => (makeCall n', st)
- | NONE =>
- let
- val (name, fargs, ran, e) =
- case IM.find (tfuncs, n) of
- NONE => (Print.prefaces "BAD" [("e",
- CorePrint.p_exp CoreEnv.empty (e, loc))];
- raise Fail "Rpcify: Undetected transaction function [2]")
- | SOME x => x
-
- val n' = #maxName st
-
- val st = {cpsed = IM.insert (#cpsed st, n, n'),
- cpsed_range = IM.insert (#cpsed_range st, n', ran),
- cps_decls = #cps_decls st,
- exported = #exported st,
- export_decls = #export_decls st,
- maxName = n' + 1}
-
- val unit = (TRecord (CRecord ((KType, loc), []), loc), loc)
- val body = (EFfi ("Basis", "bind"), loc)
- val body = (ECApp (body, (CFfi ("Basis", "transaction"), loc)), loc)
- val body = (ECApp (body, t1), loc)
- val body = (ECApp (body, unit), loc)
- val body = (EApp (body, (EFfi ("Basis", "transaction_monad"), loc)), loc)
- val body = (EApp (body, e), loc)
- val body = (EApp (body, (ERel (length args), loc)), loc)
- val bt = (CApp ((CFfi ("Basis", "transaction"), loc), unit), loc)
- val (body, bt) = foldr (fn ((x, t), (body, bt)) =>
- ((EAbs (x, t, bt, body), loc),
- (TFun (t, bt), loc)))
- (body, bt) fargs
- val kt = (TFun (ran, (CApp ((CFfi ("Basis", "transaction"), loc),
- unit),
- loc)), loc)
- val body = (EAbs ("k", kt, bt, body), loc)
- val bt = (TFun (kt, bt), loc)
-
- val (body, st) = doExp (body, st)
-
- val vi = (name ^ "_cps",
- n',
- bt,
- body,
- "")
-
- val st = {cpsed = #cpsed st,
- cpsed_range = #cpsed_range st,
- cps_decls = vi :: #cps_decls st,
- exported = #exported st,
- export_decls = #export_decls st,
- maxName = #maxName st}
- in
- (makeCall n', st)
- end
- end
- | _ => (e, st)
- end
- | _ => (e, st)
+ (makeCall n', st)
+ end
+ end
+ | _ => (e, st))
+
+ | ERecord xes =>
+ let
+ val loc = case xes of
+ [] => ErrorMsg.dummySpan
+ | (_, (_, loc), _) :: _ => loc
+
+ fun candidate (x, e) =
+ String.isPrefix "On" x
+ andalso serverSide (#cpsed_range st) e
+ andalso not (clientSide (#cpsed_range st) e)
+ in
+ if List.exists (fn ((CName x, _), e, _) => candidate (x, e)
+ | _ => false) xes then
+ let
+ val unit = (TRecord (CRecord ((KType, loc), []), loc), loc)
+
+ val k = (EFfi ("Basis", "return"), loc)
+ val k = (ECApp (k, (CFfi ("Basis", "transaction"), loc)), loc)
+ val k = (ECApp (k, unit), loc)
+ val k = (EApp (k, (EFfi ("Basis", "transaction_monad"), loc)), loc)
+ val k = (EApp (k, (ERecord [], loc)), loc)
+ val k = (EAbs ("_", unit, unit, k), loc)
+
+ val (xes, st) = ListUtil.foldlMap
+ (fn (y as (nm as (CName x, _), e, t), st) =>
+ if candidate (x, e) then
+ let
+ val (n, args) = getApp (e, [])
+
+ val (e, st) = newRpc (e, k, st)
+ in
+ ((nm, (e, loc), t), st)
+ end
+ else
+ (y, st)
+ | y => y)
+ st xes
+ in
+ (ERecord xes, st)
+ end
+ else
+ (e, st)
+ end
+
+ | _ => (e, st)
+ end
and doExp (e, st) = U.Exp.foldMap {kind = fn x => x,
con = fn x => x,
--
cgit v1.2.3
From 90d6483a54745b4b647b429c018dd49d0797459c Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Tue, 10 Mar 2009 17:29:03 -0400
Subject: Noisy demo
---
demo/noisy.ur | 42 ++++++++++
demo/noisy.urp | 4 +
demo/noisy.urs | 1 +
demo/prose | 4 +
src/jscomp.sml | 13 +--
src/mono_opt.sml | 2 -
src/monoize.sml | 7 +-
src/rpcify.sml | 239 ++++++++++++++++++++++++++++++-------------------------
8 files changed, 188 insertions(+), 124 deletions(-)
create mode 100644 demo/noisy.ur
create mode 100644 demo/noisy.urp
create mode 100644 demo/noisy.urs
(limited to 'src/mono_opt.sml')
diff --git a/demo/noisy.ur b/demo/noisy.ur
new file mode 100644
index 00000000..118af737
--- /dev/null
+++ b/demo/noisy.ur
@@ -0,0 +1,42 @@
+datatype list t = Nil | Cons of t * list t
+
+table t : { Id : int, A : string }
+
+fun add id s =
+ dml (INSERT INTO t (Id, A) VALUES ({[id]}, {[s]}))
+
+fun del id =
+ dml (DELETE FROM t WHERE t.Id = {[id]})
+
+fun lookup id =
+ ro <- oneOrNoRows (SELECT t.A FROM t WHERE t.Id = {[id]});
+ case ro of
+ None => return None
+ | Some r => return (Some r.T.A)
+
+fun check ls =
+ case ls of
+ Nil => return ()
+ | Cons (id, ls') =>
+ ao <- lookup id;
+ alert (case ao of
+ None => "Nada"
+ | Some a => a);
+ check ls'
+
+fun main () =
+ idAdd <- source "";
+ aAdd <- source "";
+
+ idDel <- source "";
+
+ return
+
+
+
+
+
+
+
+
+
diff --git a/demo/noisy.urp b/demo/noisy.urp
new file mode 100644
index 00000000..ea08bf74
--- /dev/null
+++ b/demo/noisy.urp
@@ -0,0 +1,4 @@
+database dbname=test
+sql noisy.sql
+
+noisy
diff --git a/demo/noisy.urs b/demo/noisy.urs
new file mode 100644
index 00000000..6ac44e0b
--- /dev/null
+++ b/demo/noisy.urs
@@ -0,0 +1 @@
+val main : unit -> transaction page
diff --git a/demo/prose b/demo/prose
index 57722a81..11f8c2d9 100644
--- a/demo/prose
+++ b/demo/prose
@@ -210,6 +210,10 @@ increment.urp
Here's an example where client-side code needs to run more code on the server. We maintain a (server-side) SQL sequence. When the user clicks a button, an AJAX request increments the remote sequence and gets the new value.
+noisy.urp
+
+
This example shows how easy it is to make the flow of control "ping pong" back and forth between the client and the server. Clicking a button triggers three queries to the server, with an alert generated after each query.
+
batch.urp
This example shows more of what is possible with mixed client/server code. The application is an editor for a simple database table, where additions of new rows can be batched in the client, before a button is clicked to trigger a mass addition.
diff --git a/src/jscomp.sml b/src/jscomp.sml
index adff2fda..00048458 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -895,15 +895,6 @@ fun process file =
| EDml _ => unsupported "DML"
| ENextval _ => unsupported "Nextval"
| EUnurlify _ => unsupported "EUnurlify"
- (*| EJavaScript (_, e as (EAbs _, _), _) =>
- let
- val (e, st) = jsE inner (e, st)
- in
- (strcat [str "\"cr(\"+ca(",
- e,
- str ")+\")\""],
- st)
- end*)
| EJavaScript (_, e, _) =>
let
val (e, st) = jsE inner (e, st)
@@ -982,9 +973,7 @@ fun process file =
end
in
case e of
- EJavaScript (m, orig as (EAbs (_, t, _, e), _), NONE) =>
- doCode m 1 (t :: env) orig e
- | EJavaScript (m, orig, NONE) =>
+ EJavaScript (m, orig, NONE) =>
doCode m 0 env orig orig
| _ => (e, st)
end,
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index 469fc0d8..7f23d8b1 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -365,8 +365,6 @@ fun exp e =
| EJavaScript (_, _, SOME (e, _)) => e
- | EApp ((e1 as EServerCall _, _), (ERecord [], _)) => e1
-
| _ => e
and optExp e = #1 (U.Exp.map {typ = typ, exp = exp} e)
diff --git a/src/monoize.sml b/src/monoize.sml
index 131bdf67..01f18baf 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -1820,6 +1820,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
| (L'.TFun _, _) =>
let
val s' = " " ^ lowercaseFirst x ^ "='"
+ val e = (L'.EApp (e, (L'.ERecord [], loc)), loc)
in
((L'.EStrcat (s,
(L'.EStrcat (
@@ -2264,8 +2265,12 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L'.ERel 0, loc)), loc),
(L'.ERecord [], loc)), loc)), loc)), loc)
val ek = (L'.EApp (ekf, ek), loc)
+ val e = (L'.EServerCall (call, ek, t), loc)
+ val e = liftExpInExp 0 e
+ val unit = (L'.TRecord [], loc)
+ val e = (L'.EAbs ("_", unit, unit, e), loc)
in
- ((L'.EServerCall (call, ek, t), loc), fm)
+ (e, fm)
end
| L.EKAbs _ => poly ()
diff --git a/src/rpcify.sml b/src/rpcify.sml
index 13d42390..f4db3444 100644
--- a/src/rpcify.sml
+++ b/src/rpcify.sml
@@ -188,6 +188,116 @@ fun frob file =
in
(e', st)
end
+
+ fun newCps (t1, t2, trans1, trans2, st) =
+ let
+ val loc = #2 trans1
+
+ val (n, args) = getApp (trans1, [])
+
+ fun makeCall n' =
+ let
+ val e = (ENamed n', loc)
+ val e = (EApp (e, trans2), loc)
+ in
+ #1 (foldl (fn (arg, e) => (EApp (e, arg), loc)) e args)
+ end
+ in
+ case IM.find (#cpsed_range st, n) of
+ SOME kdom =>
+ (case args of
+ [] => raise Fail "Rpcify: cps'd function lacks first argument"
+ | ke :: args =>
+ let
+ val ke' = (EFfi ("Basis", "bind"), loc)
+ val ke' = (ECApp (ke', (CFfi ("Basis", "transaction"), loc)), loc)
+ val ke' = (ECApp (ke', kdom), loc)
+ val ke' = (ECApp (ke', t2), loc)
+ val ke' = (EApp (ke', (EFfi ("Basis", "transaction_monad"), loc)), loc)
+ val ke' = (EApp (ke', (EApp (E.liftExpInExp 0 ke, (ERel 0, loc)), loc)), loc)
+ val ke' = (EApp (ke', E.liftExpInExp 0 trans2), loc)
+ val ke' = (EAbs ("x", kdom,
+ (CApp ((CFfi ("Basis", "transaction"), loc), t2), loc),
+ ke'), loc)
+
+ val e' = (ENamed n, loc)
+ val e' = (EApp (e', ke'), loc)
+ val e' = foldl (fn (arg, e') => (EApp (e', arg), loc)) e' args
+ val (e', st) = doExp (e', st)
+ in
+ (#1 e', st)
+ end)
+ | NONE =>
+ case IM.find (#cpsed st, n) of
+ SOME n' => (makeCall n', st)
+ | NONE =>
+ let
+ val (name, fargs, ran, e) =
+ case IM.find (tfuncs, n) of
+ NONE => (Print.prefaces "BAD" [("e",
+ CorePrint.p_exp CoreEnv.empty (e, loc))];
+ raise Fail "Rpcify: Undetected transaction function [2]")
+ | SOME x => x
+
+ val n' = #maxName st
+
+ val st = {cpsed = IM.insert (#cpsed st, n, n'),
+ cpsed_range = IM.insert (#cpsed_range st, n', ran),
+ cps_decls = #cps_decls st,
+ exported = #exported st,
+ export_decls = #export_decls st,
+ maxName = n' + 1}
+
+ val unit = (TRecord (CRecord ((KType, loc), []), loc), loc)
+ val body = (EFfi ("Basis", "bind"), loc)
+ val body = (ECApp (body, (CFfi ("Basis", "transaction"), loc)), loc)
+ val body = (ECApp (body, t1), loc)
+ val body = (ECApp (body, unit), loc)
+ val body = (EApp (body, (EFfi ("Basis", "transaction_monad"), loc)), loc)
+ val body = (EApp (body, e), loc)
+ val body = (EApp (body, (ERel (length args), loc)), loc)
+ val bt = (CApp ((CFfi ("Basis", "transaction"), loc), unit), loc)
+ val (body, bt) = foldr (fn ((x, t), (body, bt)) =>
+ ((EAbs (x, t, bt, body), loc),
+ (TFun (t, bt), loc)))
+ (body, bt) fargs
+ val kt = (TFun (ran, (CApp ((CFfi ("Basis", "transaction"), loc),
+ unit),
+ loc)), loc)
+ val body = (EAbs ("k", kt, bt, body), loc)
+ val bt = (TFun (kt, bt), loc)
+
+ val (body, st) = doExp (body, st)
+
+ val vi = (name ^ "_cps",
+ n',
+ bt,
+ body,
+ "")
+
+ val st = {cpsed = #cpsed st,
+ cpsed_range = #cpsed_range st,
+ cps_decls = vi :: #cps_decls st,
+ exported = #exported st,
+ export_decls = #export_decls st,
+ maxName = #maxName st}
+ in
+ (makeCall n', st)
+ end
+ end
+
+ fun dummyK loc =
+ let
+ val unit = (TRecord (CRecord ((KType, loc), []), loc), loc)
+
+ val k = (EFfi ("Basis", "return"), loc)
+ val k = (ECApp (k, (CFfi ("Basis", "transaction"), loc)), loc)
+ val k = (ECApp (k, unit), loc)
+ val k = (EApp (k, (EFfi ("Basis", "transaction_monad"), loc)), loc)
+ val k = (EApp (k, (ERecord [], loc)), loc)
+ in
+ (EAbs ("_", unit, unit, k), loc)
+ end
in
case e of
EApp (
@@ -287,104 +397,26 @@ fun frob file =
(case (serverSide (#cpsed_range st) trans1, clientSide (#cpsed_range st) trans1,
serverSide (#cpsed_range st) trans2, clientSide (#cpsed_range st) trans2) of
(true, false, _, true) => newRpc (trans1, trans2, st)
- | (true, true, _, _) =>
- let
- val (n, args) = getApp (trans1, [])
+ | (_, true, true, false) =>
+ (case #1 trans2 of
+ EAbs (x, dom, ran, trans2) =>
+ let
+ val (trans2, st) = newRpc (trans2, dummyK loc, st)
+ val trans2 = (EAbs (x, dom, ran, (trans2, loc)), loc)
+
+ val e = (EFfi ("Basis", "bind"), loc)
+ val e = (ECApp (e, (CFfi ("Basis", "transaction"), loc)), loc)
+ val e = (ECApp (e, t1), loc)
+ val e = (ECApp (e, t2), loc)
+ val e = (EApp (e, (EFfi ("Basis", "transaction_monad"), loc)), loc)
+ val e = (EApp (e, trans1), loc)
+ val e = EApp (e, trans2)
+ in
+ (e, st)
+ end
+ | _ => (e, st))
+ | (true, true, _, _) => newCps (t1, t2, trans1, trans2, st)
- fun makeCall n' =
- let
- val e = (ENamed n', loc)
- val e = (EApp (e, trans2), loc)
- in
- #1 (foldl (fn (arg, e) => (EApp (e, arg), loc)) e args)
- end
- in
- case IM.find (#cpsed_range st, n) of
- SOME kdom =>
- (case args of
- [] => raise Fail "Rpcify: cps'd function lacks first argument"
- | ke :: args =>
- let
- val ke' = (EFfi ("Basis", "bind"), loc)
- val ke' = (ECApp (ke', (CFfi ("Basis", "transaction"), loc)), loc)
- val ke' = (ECApp (ke', kdom), loc)
- val ke' = (ECApp (ke', t2), loc)
- val ke' = (EApp (ke', (EFfi ("Basis", "transaction_monad"), loc)), loc)
- val ke' = (EApp (ke', (EApp (E.liftExpInExp 0 ke, (ERel 0, loc)), loc)), loc)
- val ke' = (EApp (ke', E.liftExpInExp 0 trans2), loc)
- val ke' = (EAbs ("x", kdom,
- (CApp ((CFfi ("Basis", "transaction"), loc), t2), loc),
- ke'), loc)
-
- val e' = (ENamed n, loc)
- val e' = (EApp (e', ke'), loc)
- val e' = foldl (fn (arg, e') => (EApp (e', arg), loc)) e' args
- val (e', st) = doExp (e', st)
- in
- (#1 e', st)
- end)
- | NONE =>
- case IM.find (#cpsed st, n) of
- SOME n' => (makeCall n', st)
- | NONE =>
- let
- val (name, fargs, ran, e) =
- case IM.find (tfuncs, n) of
- NONE => (Print.prefaces "BAD" [("e",
- CorePrint.p_exp CoreEnv.empty (e, loc))];
- raise Fail "Rpcify: Undetected transaction function [2]")
- | SOME x => x
-
- val () = Print.prefaces "Double true"
- [("trans1", CorePrint.p_exp CoreEnv.empty trans1),
- ("e", CorePrint.p_exp CoreEnv.empty e)]
-
- val n' = #maxName st
-
- val st = {cpsed = IM.insert (#cpsed st, n, n'),
- cpsed_range = IM.insert (#cpsed_range st, n', ran),
- cps_decls = #cps_decls st,
- exported = #exported st,
- export_decls = #export_decls st,
- maxName = n' + 1}
-
- val unit = (TRecord (CRecord ((KType, loc), []), loc), loc)
- val body = (EFfi ("Basis", "bind"), loc)
- val body = (ECApp (body, (CFfi ("Basis", "transaction"), loc)), loc)
- val body = (ECApp (body, t1), loc)
- val body = (ECApp (body, unit), loc)
- val body = (EApp (body, (EFfi ("Basis", "transaction_monad"), loc)), loc)
- val body = (EApp (body, e), loc)
- val body = (EApp (body, (ERel (length args), loc)), loc)
- val bt = (CApp ((CFfi ("Basis", "transaction"), loc), unit), loc)
- val (body, bt) = foldr (fn ((x, t), (body, bt)) =>
- ((EAbs (x, t, bt, body), loc),
- (TFun (t, bt), loc)))
- (body, bt) fargs
- val kt = (TFun (ran, (CApp ((CFfi ("Basis", "transaction"), loc),
- unit),
- loc)), loc)
- val body = (EAbs ("k", kt, bt, body), loc)
- val bt = (TFun (kt, bt), loc)
-
- val (body, st) = doExp (body, st)
-
- val vi = (name ^ "_cps",
- n',
- bt,
- body,
- "")
-
- val st = {cpsed = #cpsed st,
- cpsed_range = #cpsed_range st,
- cps_decls = vi :: #cps_decls st,
- exported = #exported st,
- export_decls = #export_decls st,
- maxName = #maxName st}
- in
- (makeCall n', st)
- end
- end
| _ => (e, st))
| ERecord xes =>
@@ -401,22 +433,11 @@ fun frob file =
if List.exists (fn ((CName x, _), e, _) => candidate (x, e)
| _ => false) xes then
let
- val unit = (TRecord (CRecord ((KType, loc), []), loc), loc)
-
- val k = (EFfi ("Basis", "return"), loc)
- val k = (ECApp (k, (CFfi ("Basis", "transaction"), loc)), loc)
- val k = (ECApp (k, unit), loc)
- val k = (EApp (k, (EFfi ("Basis", "transaction_monad"), loc)), loc)
- val k = (EApp (k, (ERecord [], loc)), loc)
- val k = (EAbs ("_", unit, unit, k), loc)
-
val (xes, st) = ListUtil.foldlMap
(fn (y as (nm as (CName x, _), e, t), st) =>
if candidate (x, e) then
let
- val (n, args) = getApp (e, [])
-
- val (e, st) = newRpc (e, k, st)
+ val (e, st) = newRpc (e, dummyK loc, st)
in
((nm, (e, loc), t), st)
end
--
cgit v1.2.3
From 8f29d5ead0c09b99291f729001e6aabd24d8aa8c Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Thu, 9 Apr 2009 15:30:15 -0400
Subject: CHECK constraints
---
lib/ur/basis.urs | 8 +++++++-
src/elisp/urweb-mode.el | 2 +-
src/mono_opt.sml | 36 +++++++++++++++++++++++++++++++++++-
src/monoize.sml | 11 +++++++++++
src/urweb.grm | 9 ++++++++-
src/urweb.lex | 1 +
tests/cst.ur | 8 ++++++--
7 files changed, 69 insertions(+), 6 deletions(-)
(limited to 'src/mono_opt.sml')
diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs
index 454b10b2..f652165d 100644
--- a/lib/ur/basis.urs
+++ b/lib/ur/basis.urs
@@ -198,12 +198,18 @@ val foreign_key : mine1 ::: Name -> t ::: Type -> mine ::: {Type} -> munused :::
OnUpdate : propagation_mode ([mine1 = t] ++ mine)}
-> sql_constraint ([mine1 = t] ++ mine ++ munused) []
+con sql_exp :: {{Type}} -> {{Type}} -> {Type} -> Type -> Type
+
+val check : fs ::: {Type}
+ -> sql_exp [] [] fs bool
+ -> sql_constraint fs []
+
+
(*** Queries *)
con sql_query :: {{Type}} -> {Type} -> Type
con sql_query1 :: {{Type}} -> {{Type}} -> {Type} -> Type
-con sql_exp :: {{Type}} -> {{Type}} -> {Type} -> Type -> Type
con sql_subset :: {{Type}} -> {{Type}} -> Type
val sql_subset : keep_drop :: {({Type} * {Type})}
diff --git a/src/elisp/urweb-mode.el b/src/elisp/urweb-mode.el
index 545902ac..1f2a52be 100644
--- a/src/elisp/urweb-mode.el
+++ b/src/elisp/urweb-mode.el
@@ -148,7 +148,7 @@ See doc for the variable `urweb-mode-info'."
"HAVING" "LIMIT" "OFFSET" "ALL" "UNION" "INTERSECT" "EXCEPT"
"TRUE" "FALSE" "AND" "OR" "NOT" "COUNT" "AVG" "SUM" "MIN" "MAX"
"ASC" "DESC" "INSERT" "INTO" "VALUES" "UPDATE" "SET" "DELETE"
- "PRIMARY" "KEY" "CONSTRAINT" "UNIQUE"
+ "PRIMARY" "KEY" "CONSTRAINT" "UNIQUE" "CHECK"
"FOREIGN" "REFERENCES" "ON" "NO" "ACTION" "CASCADE" "RESTRICT" "NULL")
"A regexp that matches SQL keywords.")
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index 7f23d8b1..dfa0420c 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -87,7 +87,13 @@ fun sqlifyInt n = attrifyInt n ^ "::int8"
fun sqlifyFloat n = attrifyFloat n ^ "::float8"
fun sqlifyString s = "E'" ^ String.translate (fn #"'" => "\\'"
- | ch => str ch)
+ | #"\\" => "\\\\"
+ | ch =>
+ if Char.isPrint ch then
+ str ch
+ else
+ "\\" ^ StringCvt.padLeft #"0" 3
+ (Int.fmt StringCvt.OCT (ord ch)))
(String.toString s) ^ "'::text"
fun exp e =
@@ -365,6 +371,34 @@ fun exp e =
| EJavaScript (_, _, SOME (e, _)) => e
+ | EFfiApp ("Basis", "checkString", [(EPrim (Prim.String s), loc)]) =>
+ let
+ fun uwify (cs, acc) =
+ case cs of
+ [] => String.concat (rev acc)
+ | #"(" :: #"_" :: cs => uwify (cs, "(uw_" :: acc)
+ | #" " :: #"_" :: cs => uwify (cs, " uw_" :: acc)
+ | #"'" :: cs =>
+ let
+ fun waitItOut (cs, acc) =
+ case cs of
+ [] => raise Fail "MonoOpt: Unterminated SQL string literal"
+ | #"'" :: cs => uwify (cs, "'" :: acc)
+ | #"\\" :: #"'" :: cs => waitItOut (cs, "\\'" :: acc)
+ | #"\\" :: #"\\" :: cs => waitItOut (cs, "\\\\" :: acc)
+ | c :: cs => waitItOut (cs, str c :: acc)
+ in
+ waitItOut (cs, "'" :: acc)
+ end
+ | c :: cs => uwify (cs, str c :: acc)
+
+ val s = case String.explode s of
+ #"_" :: cs => uwify (cs, ["uw_"])
+ | cs => uwify (cs, [])
+ in
+ EPrim (Prim.String s)
+ end
+
| _ => e
and optExp e = #1 (U.Exp.map {typ = typ, exp = exp} e)
diff --git a/src/monoize.sml b/src/monoize.sml
index bc44c550..950de1e1 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -1342,6 +1342,17 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
fm)
end
+ | L.ECApp ((L.EFfi ("Basis", "check"), _), _) =>
+ let
+ val string = (L'.TFfi ("Basis", "string"), loc)
+ in
+ ((L'.EAbs ("e", string, string,
+ (L'.EStrcat ((L'.EPrim (Prim.String "CHECK "), loc),
+ (L'.EFfiApp ("Basis", "checkString",
+ [(L'.ERel 0, loc)]), loc)), loc)), loc),
+ fm)
+ end
+
| L.EFfiApp ("Basis", "dml", [e]) =>
let
val (e, fm) = monoExp (env, st, fm) e
diff --git a/src/urweb.grm b/src/urweb.grm
index 50fb6cb3..7e1f6757 100644
--- a/src/urweb.grm
+++ b/src/urweb.grm
@@ -210,7 +210,7 @@ datatype prop_kind = Delete | Update
| INSERT | INTO | VALUES | UPDATE | SET | DELETE | NULL | IS
| CURRENT_TIMESTAMP
| NE | LT | LE | GT | GE
- | CCONSTRAINT | UNIQUE | PRIMARY | FOREIGN | KEY | ON | NO | ACTION | RESTRICT | CASCADE | REFERENCES
+ | CCONSTRAINT | UNIQUE | CHECK | PRIMARY | FOREIGN | KEY | ON | NO | ACTION | RESTRICT | CASCADE | REFERENCES
%nonterm
file of decl list
@@ -511,6 +511,13 @@ cst : UNIQUE tnames (let
(EDisjointApp e, loc)
end)
+ | CHECK sqlexp (let
+ val loc = s (CHECKleft, sqlexpright)
+ in
+ (EApp ((EVar (["Basis"], "check", Infer), loc),
+ sqlexp), loc)
+ end)
+
| FOREIGN KEY tnames REFERENCES texp LPAREN tnames' RPAREN pmodes
(let
val loc = s (FOREIGNleft, pmodesright)
diff --git a/src/urweb.lex b/src/urweb.lex
index c01f018b..4b3eb2af 100644
--- a/src/urweb.lex
+++ b/src/urweb.lex
@@ -367,6 +367,7 @@ notags = [^<{\n]+;
"CONSTRAINT"=> (Tokens.CCONSTRAINT (pos yypos, pos yypos + size yytext));
"UNIQUE" => (Tokens.UNIQUE (pos yypos, pos yypos + size yytext));
+ "CHECK" => (Tokens.CHECK (pos yypos, pos yypos + size yytext));
"PRIMARY" => (Tokens.PRIMARY (pos yypos, pos yypos + size yytext));
"FOREIGN" => (Tokens.FOREIGN (pos yypos, pos yypos + size yytext));
"KEY" => (Tokens.KEY (pos yypos, pos yypos + size yytext));
diff --git a/tests/cst.ur b/tests/cst.ur
index 2db083f7..a0ccf539 100644
--- a/tests/cst.ur
+++ b/tests/cst.ur
@@ -1,7 +1,11 @@
-table u : {C : int, D : int, E : option int}
+table u : {C : int, D : int, E : option int, F : string}
PRIMARY KEY C,
CONSTRAINT U UNIQUE (C, D),
- CONSTRAINT U2 UNIQUE E
+ CONSTRAINT U2 UNIQUE E,
+
+ CONSTRAINT Pos CHECK D > 0,
+ CONSTRAINT NoNo CHECK C + D <> 2,
+ CONSTRAINT Known CHECK F = "_E = 6"
table t : {A : int, B : int, C : option int}
PRIMARY KEY B,
--
cgit v1.2.3
From 17cb59d373d1a94731d3730b938776b524d9f81c Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Thu, 9 Apr 2009 16:36:50 -0400
Subject: URLs
---
CHANGELOG | 1 +
include/urweb.h | 2 ++
lib/ur/basis.urs | 6 +++++-
src/c/urweb.c | 4 ++++
src/mono_opt.sig | 2 ++
src/mono_opt.sml | 9 +++++++++
src/monoize.sml | 13 +++++++++++--
src/urweb.grm | 14 +++++++++++++-
tests/img.ur | 3 +++
tests/img.urp | 3 +++
tests/url.ur | 13 +++++++++++++
tests/url.urp | 3 +++
tests/url.urs | 1 +
13 files changed, 70 insertions(+), 4 deletions(-)
create mode 100644 tests/img.ur
create mode 100644 tests/img.urp
create mode 100644 tests/url.ur
create mode 100644 tests/url.urp
create mode 100644 tests/url.urs
(limited to 'src/mono_opt.sml')
diff --git a/CHANGELOG b/CHANGELOG
index 51d5b05b..ee860622 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -4,6 +4,7 @@ Next
- Reimplement constructor class resolution to be more general and Prolog-like
- SQL table constraints
+- URLs, with configurable gatekeeper function Basis.bless
========
20090405
diff --git a/include/urweb.h b/include/urweb.h
index 759fc5ac..2154a8ed 100644
--- a/include/urweb.h
+++ b/include/urweb.h
@@ -149,3 +149,5 @@ uw_Basis_channel uw_Basis_new_channel(uw_context, uw_unit);
uw_unit uw_Basis_send(uw_context, uw_Basis_channel, uw_Basis_string);
uw_Basis_client uw_Basis_self(uw_context, uw_unit);
+
+uw_Basis_string uw_Basis_bless(uw_context, uw_Basis_string);
diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs
index f652165d..f2f378ee 100644
--- a/lib/ur/basis.urs
+++ b/lib/ur/basis.urs
@@ -486,7 +486,11 @@ val ul : bodyTag []
val hr : bodyTag []
-val a : bodyTag [Link = transaction page, Onclick = transaction unit]
+type url
+val bless : string -> url
+val a : bodyTag [Link = transaction page, Href = url, Onclick = transaction unit]
+
+val img : bodyTag [Src = url]
val form : ctx ::: {Unit} -> bind ::: {Type}
-> [[Body] ~ ctx] =>
diff --git a/src/c/urweb.c b/src/c/urweb.c
index 67985d35..89358a06 100644
--- a/src/c/urweb.c
+++ b/src/c/urweb.c
@@ -1973,3 +1973,7 @@ failure_kind uw_initialize(uw_context ctx) {
return r;
}
+
+uw_Basis_string uw_Basis_bless(uw_context ctx, uw_Basis_string s) {
+ return s;
+}
diff --git a/src/mono_opt.sig b/src/mono_opt.sig
index d0268087..b1652c71 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 bless : (string -> bool) ref
+
end
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index dfa0420c..205ae3fb 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 bless = ref (fn _ : string => true)
+
fun typ t = t
fun decl d = d
@@ -371,6 +373,13 @@ fun exp e =
| EJavaScript (_, _, SOME (e, _)) => e
+ | EFfiApp ("Basis", "bless", [(se as EPrim (Prim.String s), loc)]) =>
+ (if !bless s then
+ ()
+ else
+ ErrorMsg.errorAt loc "Invalid URL passed to 'bless'";
+ se)
+
| EFfiApp ("Basis", "checkString", [(EPrim (Prim.String s), loc)]) =>
let
fun uwify (cs, acc) =
diff --git a/src/monoize.sml b/src/monoize.sml
index 950de1e1..bf26fda2 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -126,6 +126,7 @@ fun monoType env =
| L.CApp ((L.CFfi ("Basis", "read"), _), t) =>
readType (mt env dtmap t, loc)
+ | L.CFfi ("Basis", "url") => (L'.TFfi ("Basis", "string"), loc)
| L.CApp ((L.CApp ((L.CApp ((L.CFfi ("Basis", "xml"), _), _), _), _), _), _) =>
(L'.TFfi ("Basis", "string"), loc)
| L.CApp ((L.CApp ((L.CFfi ("Basis", "xhtml"), _), _), _), _) =>
@@ -2075,6 +2076,14 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
L'.ERecord xes => xes
| _ => raise Fail "Non-record attributes!"
+ val attrs =
+ if List.exists (fn ("Link", _, _) => true
+ | _ => false) attrs then
+ List.filter (fn ("Href", _, _) => false
+ | _ => true) attrs
+ else
+ attrs
+
fun findOnload (attrs, acc) =
case attrs of
[] => (NONE, acc)
@@ -2137,8 +2146,8 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
let
val fooify =
case x of
- "Href" => urlifyExp
- | "Link" => urlifyExp
+ "Link" => urlifyExp
+ | "Action" => urlifyExp
| _ => attrifyExp
val xp = " " ^ lowercaseFirst x ^ "=\""
diff --git a/src/urweb.grm b/src/urweb.grm
index 7e1f6757..7288359a 100644
--- a/src/urweb.grm
+++ b/src/urweb.grm
@@ -1280,7 +1280,19 @@ tagHead: BEGIN_TAG (let
attrs : ([])
| attr attrs (attr :: attrs)
-attr : SYMBOL EQ attrv ((CName (capitalize SYMBOL), s (SYMBOLleft, SYMBOLright)), attrv)
+attr : SYMBOL EQ attrv ((CName (capitalize SYMBOL), s (SYMBOLleft, SYMBOLright)),
+ if (SYMBOL = "href" orelse SYMBOL = "src")
+ andalso (case #1 attrv of
+ EPrim _ => true
+ | _ => false) then
+ let
+ val loc = s (attrvleft, attrvright)
+ in
+ (EApp ((EVar (["Basis"], "bless", Infer), loc),
+ attrv), loc)
+ end
+ else
+ attrv)
attrv : INT (EPrim (Prim.Int INT), s (INTleft, INTright))
| FLOAT (EPrim (Prim.Float FLOAT), s (FLOATleft, FLOATright))
diff --git a/tests/img.ur b/tests/img.ur
new file mode 100644
index 00000000..70896647
--- /dev/null
+++ b/tests/img.ur
@@ -0,0 +1,3 @@
+fun main () : transaction page = return
+
+
diff --git a/tests/img.urp b/tests/img.urp
new file mode 100644
index 00000000..ff71adee
--- /dev/null
+++ b/tests/img.urp
@@ -0,0 +1,3 @@
+debug
+
+img
diff --git a/tests/url.ur b/tests/url.ur
new file mode 100644
index 00000000..c45681e0
--- /dev/null
+++ b/tests/url.ur
@@ -0,0 +1,13 @@
+val url = "http://www.yahoo.com/"
+
+fun readersChoice r = return
+ Your pick, boss
+
+
+fun main () : transaction page = return
+ Google!
+ Yahoo!
+
+
+
+
diff --git a/tests/url.urp b/tests/url.urp
new file mode 100644
index 00000000..3d4961ef
--- /dev/null
+++ b/tests/url.urp
@@ -0,0 +1,3 @@
+debug
+
+url
diff --git a/tests/url.urs b/tests/url.urs
new file mode 100644
index 00000000..6ac44e0b
--- /dev/null
+++ b/tests/url.urs
@@ -0,0 +1 @@
+val main : unit -> transaction page
--
cgit v1.2.3
From 2f324fc9e868e0775e1401833b74af15652c6732 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sun, 12 Apr 2009 14:19:15 -0400
Subject: Classes as optional arguments to Basis.tag
---
include/types.h | 1 +
include/urweb.h | 1 +
lib/ur/basis.urs | 7 +++---
src/c/urweb.c | 4 ++++
src/corify.sml | 2 +-
src/elab_env.sml | 28 +++++++++++-----------
src/elaborate.sml | 17 +++++++------
src/especialize.sml | 52 +++++++++++++---------------------------
src/mono_opt.sml | 7 ++++++
src/monoize.sml | 24 ++++++++++++++++---
src/reduce_local.sml | 8 +++++++
src/tag.sml | 20 +++++++++-------
src/urweb.grm | 67 ++++++++++++++++++++++++++++++++++------------------
tests/style.ur | 2 +-
14 files changed, 143 insertions(+), 97 deletions(-)
(limited to 'src/mono_opt.sml')
diff --git a/include/types.h b/include/types.h
index ddbff76b..c80653d3 100644
--- a/include/types.h
+++ b/include/types.h
@@ -17,6 +17,7 @@ typedef struct uw_context *uw_context;
typedef uw_Basis_string uw_Basis_xhtml;
typedef uw_Basis_string uw_Basis_page;
+typedef uw_Basis_string uw_Basis_css_class;
typedef unsigned uw_Basis_client;
typedef struct {
diff --git a/include/urweb.h b/include/urweb.h
index 2154a8ed..bbf7515a 100644
--- a/include/urweb.h
+++ b/include/urweb.h
@@ -74,6 +74,7 @@ char *uw_Basis_attrifyString(uw_context, uw_Basis_string);
char *uw_Basis_attrifyTime(uw_context, uw_Basis_time);
char *uw_Basis_attrifyChannel(uw_context, uw_Basis_channel);
char *uw_Basis_attrifyClient(uw_context, uw_Basis_client);
+char *uw_Basis_attrifyCss_class(uw_context, uw_Basis_css_class);
uw_unit uw_Basis_attrifyInt_w(uw_context, uw_Basis_int);
uw_unit uw_Basis_attrifyFloat_w(uw_context, uw_Basis_float);
diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs
index 9eeb4891..50146dde 100644
--- a/lib/ur/basis.urs
+++ b/lib/ur/basis.urs
@@ -405,12 +405,10 @@ val nextval : sql_sequence -> transaction int
(** XML *)
-con css_class :: {Unit} -> Type
-(* The argument lists categories of properties that this class could set usefully. *)
+type css_class
con tag :: {Type} -> {Unit} -> {Unit} -> {Type} -> {Type} -> Type
-
con xml :: {Unit} -> {Type} -> {Type} -> Type
val cdata : ctx ::: {Unit} -> use ::: {Type} -> string -> xml ctx use []
val tag : attrsGiven ::: {Type} -> attrsAbsent ::: {Type}
@@ -420,7 +418,8 @@ val tag : attrsGiven ::: {Type} -> attrsAbsent ::: {Type}
-> [attrsGiven ~ attrsAbsent] =>
[useOuter ~ useInner] =>
[bindOuter ~ bindInner] =>
- $attrsGiven
+ option css_class
+ -> $attrsGiven
-> tag (attrsGiven ++ attrsAbsent)
ctxOuter ctxInner useOuter bindOuter
-> xml ctxInner useInner bindInner
diff --git a/src/c/urweb.c b/src/c/urweb.c
index 89358a06..d3a93af9 100644
--- a/src/c/urweb.c
+++ b/src/c/urweb.c
@@ -922,6 +922,10 @@ char *uw_Basis_attrifyString(uw_context ctx, uw_Basis_string s) {
return result;
}
+char *uw_Basis_attrifyCss_class(uw_context ctx, uw_Basis_css_class s) {
+ return s;
+}
+
static void uw_Basis_attrifyInt_w_unsafe(uw_context ctx, uw_Basis_int n) {
int len;
diff --git a/src/corify.sml b/src/corify.sml
index c8da9df5..c1cd940e 100644
--- a/src/corify.sml
+++ b/src/corify.sml
@@ -1005,7 +1005,7 @@ fun corifyDecl mods (all as (d, loc : EM.span), st) =
| L.DStyle (_, x, n) =>
let
val (st, n) = St.bindVal st x n
- val s = doRestify (mods, x)
+ val s = relify (doRestify (mods, x))
in
([(L'.DStyle (x, n, s), loc)], st)
end
diff --git a/src/elab_env.sml b/src/elab_env.sml
index 6dae1d4b..62a310f2 100644
--- a/src/elab_env.sml
+++ b/src/elab_env.sml
@@ -899,19 +899,19 @@ fun sgnS_con (str, (sgns, strs, cons)) c =
end)
| _ => c
-fun sgnS_con' (arg as (m1, ms', (sgns, strs, cons))) c =
- case c of
- CModProj (m1, ms, x) =>
- (case IM.find (strs, m1) of
- NONE => c
- | SOME m1x => CModProj (m1, ms' @ m1x :: ms, x))
- | CNamed n =>
- (case IM.find (cons, n) of
- NONE => c
- | SOME nx => CModProj (m1, ms', nx))
- | CApp (c1, c2) => CApp ((sgnS_con' arg (#1 c1), #2 c1),
- (sgnS_con' arg (#1 c2), #2 c2))
- | _ => c
+fun sgnS_con' (m1, ms', (sgns, strs, cons)) =
+ U.Con.map {kind = fn x => x,
+ con = fn c =>
+ case c of
+ CModProj (m1, ms, x) =>
+ (case IM.find (strs, m1) of
+ NONE => c
+ | SOME m1x => CModProj (m1, ms' @ m1x :: ms, x))
+ | CNamed n =>
+ (case IM.find (cons, n) of
+ NONE => c
+ | SOME nx => CModProj (m1, ms', nx))
+ | _ => c}
fun sgnS_sgn (str, (sgns, strs, cons)) sgn =
case sgn of
@@ -1026,7 +1026,7 @@ fun enrichClasses env classes (m1, ms) sgn =
| SOME (cn, nvs, cs, c) =>
let
val loc = #2 c
- fun globalize (c, loc) = (sgnS_con' (m1, ms, fmap) c, loc)
+ val globalize = sgnS_con' (m1, ms, fmap)
val nc =
case cn of
diff --git a/src/elaborate.sml b/src/elaborate.sml
index 72b7b8fc..ea4c28bd 100644
--- a/src/elaborate.sml
+++ b/src/elaborate.sml
@@ -1493,26 +1493,28 @@ fun unmodCon env (c, loc) =
end
| _ => (c, loc)
-fun normClassKey envs c =
+fun normClassKey env c =
let
- val c = hnormCon envs c
+ val c = hnormCon env c
in
case #1 c of
L'.CApp (c1, c2) =>
let
- val c1 = normClassKey envs c1
- val c2 = normClassKey envs c2
+ val c1 = normClassKey env c1
+ val c2 = normClassKey env c2
in
(L'.CApp (c1, c2), #2 c)
end
- | _ => c
+ | L'.CRecord (k, xcs) => (L'.CRecord (k, map (fn (x, c) => (normClassKey env x,
+ normClassKey env c)) xcs), #2 c)
+ | _ => unmodCon env c
end
fun normClassConstraint env (c, loc) =
case c of
L'.CApp (f, x) =>
let
- val f = unmodCon env f
+ val f = normClassKey env f
val x = normClassKey env x
in
(L'.CApp (f, x), loc)
@@ -1526,7 +1528,7 @@ fun normClassConstraint env (c, loc) =
end
| L'.TCFun (expl, x, k, c1) => (L'.TCFun (expl, x, k, normClassConstraint env c1), loc)
| L'.CUnif (_, _, _, ref (SOME c)) => normClassConstraint env c
- | _ => (c, loc)
+ | _ => unmodCon env (c, loc)
fun elabExp (env, denv) (eAll as (e, loc)) =
let
@@ -2047,6 +2049,7 @@ fun elabSgn_item ((sgi, loc), (env, denv, gs)) =
let
val (c', ck, gs') = elabCon (env, denv) c
+ val old = c'
val c' = normClassConstraint env c'
val (env', n) = E.pushENamed env x c'
in
diff --git a/src/especialize.sml b/src/especialize.sml
index 6486842b..d1d018ee 100644
--- a/src/especialize.sml
+++ b/src/especialize.sml
@@ -114,35 +114,6 @@ fun default (_, x, st) = (x, st)
fun specialize' file =
let
- fun default' (_, fs) = fs
-
- fun actionableExp (e, fs) =
- case e of
- ERecord xes =>
- foldl (fn (((CName s, _), e, _), fs) =>
- if s = "Action" orelse s = "Link" then
- let
- fun findHead (e, _) =
- case e of
- ENamed n => IS.add (fs, n)
- | EApp (e, _) => findHead e
- | _ => fs
- in
- findHead e
- end
- else
- fs
- | (_, fs) => fs)
- fs xes
- | _ => fs
-
- val actionable =
- U.File.fold {kind = default',
- con = default',
- exp = actionableExp,
- decl = default'}
- IS.empty file
-
fun bind (env, b) =
case b of
U.Decl.RelE xt => xt :: env
@@ -150,6 +121,9 @@ fun specialize' file =
fun exp (env, e, st : state) =
let
+ (*val () = Print.prefaces "exp" [("e", CorePrint.p_exp CoreEnv.empty
+ (e, ErrorMsg.dummySpan))]*)
+
fun getApp e =
case e of
ENamed f => SOME (f, [])
@@ -160,12 +134,17 @@ fun specialize' file =
| _ => NONE
in
case getApp e of
- NONE => (e, st)
+ NONE => ((*Print.prefaces "No" [("e", CorePrint.p_exp CoreEnv.empty
+ (e, ErrorMsg.dummySpan))];*)
+ (e, st))
| SOME (f, xs) =>
case IM.find (#funcs st, f) of
NONE => (e, st)
| SOME {name, args, body, typ, tag} =>
let
+ (*val () = Print.prefaces "Consider" [("e", CorePrint.p_exp CoreEnv.empty
+ (e, ErrorMsg.dummySpan))]*)
+
val functionInside = U.Con.exists {kind = fn _ => false,
con = fn TFun _ => true
| CFfi ("Basis", "transaction") => true
@@ -208,7 +187,7 @@ fun specialize' file =
e xs
in
(*Print.prefaces "Brand new (reuse)"
- [("e'", CorePrint.p_exp env e)];*)
+ [("e'", CorePrint.p_exp CoreEnv.empty e)];*)
(#1 e, st)
end
| NONE =>
@@ -267,9 +246,9 @@ fun specialize' file =
val e' = foldl (fn (arg, e) => (EApp (e, arg), loc))
e' xs
(*val () = Print.prefaces "Brand new"
- [("e'", CorePrint.p_exp env e'),
- ("e", CorePrint.p_exp env (e, loc)),
- ("body'", CorePrint.p_exp env body')]*)
+ [("e'", CorePrint.p_exp CoreEnv.empty e'),
+ ("e", CorePrint.p_exp CoreEnv.empty (e, loc)),
+ ("body'", CorePrint.p_exp CoreEnv.empty body')]*)
in
(#1 e',
{maxName = #maxName st,
@@ -358,7 +337,8 @@ fun specialize' file =
fun specialize file =
let
- (*val () = Print.prefaces "Intermediate" [("file", CorePrint.p_file CoreEnv.empty file)];*)
+ val file = ReduceLocal.reduce file
+ (*val () = Print.prefaces "Intermediate" [("file", CorePrint.p_file CoreEnv.empty file)]*)
(*val file = ReduceLocal.reduce file*)
val (changed, file) = specialize' file
(*val file = ReduceLocal.reduce file
@@ -368,7 +348,7 @@ fun specialize file =
(*print "Round over\n";*)
if changed then
let
- val file = ReduceLocal.reduce file
+ (*val file = ReduceLocal.reduce file*)
val file = CoreUntangle.untangle file
val file = Shake.shake file
in
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index 205ae3fb..670774a2 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -242,6 +242,13 @@ fun exp e =
| EWrite (EFfiApp ("Basis", "attrifyString", [e]), _) =>
EFfiApp ("Basis", "attrifyString_w", [e])
+ | EFfiApp ("Basis", "attrifyCss_class", [(EPrim (Prim.String s), _)]) =>
+ EPrim (Prim.String s)
+ | 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), _)]) =>
EPrim (Prim.String (urlifyInt n))
| EWrite (EFfiApp ("Basis", "urlifyInt", [(EPrim (Prim.Int n), _)]), loc) =>
diff --git a/src/monoize.sml b/src/monoize.sml
index f14b6021..51fae113 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -131,6 +131,7 @@ fun monoType env =
(L'.TFfi ("Basis", "string"), loc)
| L.CApp ((L.CApp ((L.CFfi ("Basis", "xhtml"), _), _), _), _) =>
(L'.TFfi ("Basis", "string"), loc)
+ | L.CFfi ("Basis", "css_class") => (L'.TFfi ("Basis", "string"), loc)
| L.CApp ((L.CFfi ("Basis", "transaction"), _), t) =>
(L'.TFun ((L'.TRecord [], loc), mt env dtmap t), loc)
@@ -2035,7 +2036,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
| L.EApp (
(L.EApp (
(L.EApp (
- (L.ECApp (
+ (L.EApp (
(L.ECApp (
(L.ECApp (
(L.ECApp (
@@ -2043,8 +2044,10 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L.ECApp (
(L.ECApp (
(L.ECApp (
- (L.EFfi ("Basis", "tag"),
- _), _), _), _), _), _), _), _), _), _), _), _), _), _), _), _), _),
+ (L.ECApp (
+ (L.EFfi ("Basis", "tag"),
+ _), _), _), _), _), _), _), _), _), _), _), _), _), _), _), _), _),
+ class), _),
attrs), _),
tag), _),
xml) =>
@@ -2096,9 +2099,24 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
| lowercaseFirst s = String.str (Char.toLower (String.sub (s, 0)))
^ String.extract (s, 1, NONE)
+ val (class, fm) = monoExp (env, st, fm) class
+
fun tagStart tag =
let
+ val t = (L'.TFfi ("Basis", "string"), loc)
val s = (L'.EPrim (Prim.String (String.concat ["<", tag])), loc)
+
+ val s = (L'.ECase (class,
+ [((L'.PNone t, loc),
+ s),
+ ((L'.PSome (t, (L'.PVar ("x", t), loc)), loc),
+ (L'.EStrcat (s,
+ (L'.EStrcat ((L'.EPrim (Prim.String " class=\""), loc),
+ (L'.EStrcat ((L'.ERel 0, loc),
+ (L'.EPrim (Prim.String "\""), loc)),
+ loc)), loc)), loc))],
+ {disc = (L'.TOption t, loc),
+ result = t}), loc)
in
foldl (fn (("Action", _, _), acc) => acc
| (("Source", _, _), acc) => acc
diff --git a/src/reduce_local.sml b/src/reduce_local.sml
index cf602406..265cb2a4 100644
--- a/src/reduce_local.sml
+++ b/src/reduce_local.sml
@@ -72,6 +72,11 @@ fun exp env (all as (e, loc)) =
| EFfi _ => all
| EFfiApp (m, f, es) => (EFfiApp (m, f, map (exp env) es), loc)
+ | EApp ((ECApp ((ECAbs (_, _, (EAbs (_, (CRel 0, _), _,
+ (ECon (dk, pc, [(CRel 0, loc)], SOME (ERel 0, _)), _)), _)), _),
+ t), _), e) =>
+ (ECon (dk, pc, [t], SOME (exp env e)), loc)
+
| EApp (e1, e2) =>
let
val e1 = exp env e1
@@ -84,6 +89,9 @@ fun exp env (all as (e, loc)) =
| EAbs (x, dom, ran, e) => (EAbs (x, dom, ran, exp (Unknown :: env) e), loc)
+ | ECApp ((ECAbs (_, _, (ECon (dk, pc, [(CRel 0, loc)], NONE), _)), _), t) =>
+ (ECon (dk, pc, [t], NONE), loc)
+
| ECApp (e, c) => (ECApp (exp env e, c), loc)
| ECAbs (x, k, e) => (ECAbs (x, k, exp env e), loc)
diff --git a/src/tag.sml b/src/tag.sml
index 715da9ed..7a8fe128 100644
--- a/src/tag.sml
+++ b/src/tag.sml
@@ -46,7 +46,7 @@ fun exp env (e, s) =
EApp (
(EApp (
(EApp (
- (ECApp (
+ (EApp (
(ECApp (
(ECApp (
(ECApp (
@@ -54,9 +54,11 @@ fun exp env (e, s) =
(ECApp (
(ECApp (
(ECApp (
- (EFfi ("Basis", "tag"),
- loc), given), _), absent), _), outer), _), inner), _),
- useOuter), _), useInner), _), bindOuter), _), bindInner), _),
+ (ECApp (
+ (EFfi ("Basis", "tag"),
+ loc), given), _), absent), _), outer), _), inner), _),
+ useOuter), _), useInner), _), bindOuter), _), bindInner), _),
+ class), _),
attrs), _),
tag), _),
xml) =>
@@ -124,7 +126,7 @@ fun exp env (e, s) =
(EApp (
(EApp (
(EApp (
- (ECApp (
+ (EApp (
(ECApp (
(ECApp (
(ECApp (
@@ -132,9 +134,11 @@ fun exp env (e, s) =
(ECApp (
(ECApp (
(ECApp (
- (EFfi ("Basis", "tag"),
- loc), given), loc), absent), loc), outer), loc), inner), loc),
- useOuter), loc), useInner), loc), bindOuter), loc), bindInner), loc),
+ (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)
diff --git a/src/urweb.grm b/src/urweb.grm
index 0251d3f4..d47aaf47 100644
--- a/src/urweb.grm
+++ b/src/urweb.grm
@@ -176,6 +176,8 @@ fun tagIn bt =
datatype prop_kind = Delete | Update
+datatype attr = Class of exp | Normal of con * exp
+
%%
%header (functor UrwebLrValsFn(structure Token : TOKEN))
@@ -296,8 +298,8 @@ datatype prop_kind = Delete | Update
| rpat of (string * pat) list * bool
| ptuple of pat list
- | attrs of (con * exp) list
- | attr of con * exp
+ | attrs of exp option * (con * exp) list
+ | attr of attr
| attrv of exp
| query of exp
@@ -1266,13 +1268,18 @@ xmlOne : NOTAGS (EApp ((EVar (["Basis"], "cdata", Infer)
tag : tagHead attrs (let
val pos = s (tagHeadleft, attrsright)
+
+ val e = (EVar (["Basis"], "tag", Infer), pos)
+ val eo = case #1 attrs of
+ NONE => (EVar (["Basis"], "None", Infer), pos)
+ | SOME e => (EApp ((EVar (["Basis"], "Some", Infer), pos),
+ e), pos)
+ val e = (EApp (e, eo), pos)
+ val e = (EApp (e, (ERecord (#2 attrs), pos)), pos)
+ val e = (EApp (e, (EApp (#2 tagHead,
+ (ERecord [], pos)), pos)), pos)
in
- (#1 tagHead,
- (EApp ((EApp ((EVar (["Basis"], "tag", Infer), pos),
- (ERecord attrs, pos)), pos),
- (EApp (#2 tagHead,
- (ERecord [], pos)), pos)),
- pos))
+ (#1 tagHead, e)
end)
tagHead: BEGIN_TAG (let
@@ -1284,22 +1291,36 @@ tagHead: BEGIN_TAG (let
end)
| tagHead LBRACE cexp RBRACE (#1 tagHead, (ECApp (#2 tagHead, cexp), s (tagHeadleft, RBRACEright)))
-attrs : ([])
- | attr attrs (attr :: attrs)
-
-attr : SYMBOL EQ attrv ((CName (capitalize SYMBOL), s (SYMBOLleft, SYMBOLright)),
- if (SYMBOL = "href" orelse SYMBOL = "src")
- andalso (case #1 attrv of
- EPrim _ => true
- | _ => false) then
- let
- val loc = s (attrvleft, attrvright)
- in
- (EApp ((EVar (["Basis"], "bless", Infer), loc),
- attrv), loc)
- end
+attrs : (NONE, [])
+ | attr attrs (let
+ val loc = s (attrleft, attrsright)
+ in
+ case attr of
+ Class e =>
+ (case #1 attrs of
+ NONE => ()
+ | SOME _ => ErrorMsg.errorAt loc "Multiple classes specified for tag";
+ (SOME e, #2 attrs))
+ | Normal xe =>
+ (#1 attrs, xe :: #2 attrs)
+ end)
+
+attr : SYMBOL EQ attrv (if SYMBOL = "class" then
+ Class attrv
else
- attrv)
+ Normal ((CName (capitalize SYMBOL), s (SYMBOLleft, SYMBOLright)),
+ if (SYMBOL = "href" orelse SYMBOL = "src")
+ andalso (case #1 attrv of
+ EPrim _ => true
+ | _ => false) then
+ let
+ val loc = s (attrvleft, attrvright)
+ in
+ (EApp ((EVar (["Basis"], "bless", Infer), loc),
+ attrv), loc)
+ end
+ else
+ attrv))
attrv : INT (EPrim (Prim.Int INT), s (INTleft, INTright))
| FLOAT (EPrim (Prim.Float FLOAT), s (FLOATleft, FLOATright))
diff --git a/tests/style.ur b/tests/style.ur
index 04b32a64..83f95594 100644
--- a/tests/style.ur
+++ b/tests/style.ur
@@ -2,5 +2,5 @@ style q
style r
fun main () : transaction page = return
- Hi.
+ Hi. And hi again!
--
cgit v1.2.3
From 38507c697c6b5f277cabc5eb61afff14ea02da07 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sun, 26 Apr 2009 09:02:17 -0400
Subject: Returning a blob as page result
---
include/types.h | 2 +-
include/urweb.h | 2 ++
lib/ur/basis.urs | 4 ++++
src/c/driver.c | 4 ++--
src/c/urweb.c | 38 +++++++++++++++++++++++++++++++++++++-
src/cjr.sml | 1 +
src/cjr_print.sml | 18 ++++++++++++++++++
src/cjrize.sml | 8 ++++++++
src/jscomp.sml | 3 +++
src/mono.sml | 1 +
src/mono_opt.sig | 1 +
src/mono_opt.sml | 7 +++++++
src/mono_print.sml | 12 ++++++++++++
src/mono_reduce.sml | 2 ++
src/mono_util.sml | 10 +++++++++-
src/monoize.sml | 15 +++++++++++++++
src/prepare.sml | 8 ++++++++
src/scriptcheck.sml | 1 +
tests/echoBlob.ur | 8 ++++++++
tests/echoBlob.urp | 3 +++
tests/echoBlob.urs | 1 +
21 files changed, 144 insertions(+), 5 deletions(-)
create mode 100644 tests/echoBlob.ur
create mode 100644 tests/echoBlob.urp
create mode 100644 tests/echoBlob.urs
(limited to 'src/mono_opt.sml')
diff --git a/include/types.h b/include/types.h
index 90a9f524..71a5ee0f 100644
--- a/include/types.h
+++ b/include/types.h
@@ -33,7 +33,7 @@ typedef struct uw_Basis_file {
uw_Basis_blob data;
} uw_Basis_file;
-typedef enum { SUCCESS, FATAL, BOUNDED_RETRY, UNLIMITED_RETRY } failure_kind;
+typedef enum { SUCCESS, FATAL, BOUNDED_RETRY, UNLIMITED_RETRY, RETURN_BLOB } failure_kind;
#define INTS_MAX 50
diff --git a/include/urweb.h b/include/urweb.h
index cba746d4..4df7caef 100644
--- a/include/urweb.h
+++ b/include/urweb.h
@@ -157,6 +157,7 @@ uw_unit uw_Basis_send(uw_context, uw_Basis_channel, uw_Basis_string);
uw_Basis_client uw_Basis_self(uw_context, uw_unit);
uw_Basis_string uw_Basis_bless(uw_context, uw_Basis_string);
+uw_Basis_string uw_Basis_blessMime(uw_context, uw_Basis_string);
uw_Basis_string uw_unnull(uw_Basis_string);
uw_Basis_string uw_Basis_makeSigString(uw_context, uw_Basis_string);
@@ -166,3 +167,4 @@ uw_Basis_string uw_Basis_fileName(uw_context, uw_Basis_file);
uw_Basis_string uw_Basis_fileMimeType(uw_context, uw_Basis_file);
uw_Basis_blob uw_Basis_fileData(uw_context, uw_Basis_file);
+__attribute__((noreturn)) void uw_return_blob(uw_context, uw_Basis_blob, uw_Basis_string mimeType);
diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs
index 1068ddb9..6e22ece3 100644
--- a/lib/ur/basis.urs
+++ b/lib/ur/basis.urs
@@ -521,6 +521,10 @@ val fileData : file -> blob
val upload : formTag file [] [Value = string, Size = int]
+type mimeType
+val blessMime : string -> mimeType
+val returnBlob : t ::: Type -> blob -> mimeType -> transaction t
+
con radio = [Body, Radio]
val radio : formTag string radio []
val radioOption : unit -> tag [Value = string] radio [] [] []
diff --git a/src/c/driver.c b/src/c/driver.c
index c95f8886..63a7d224 100644
--- a/src/c/driver.c
+++ b/src/c/driver.c
@@ -194,7 +194,7 @@ static void *worker(void *data) {
if (s = strstr(buf, "\r\n\r\n")) {
failure_kind fk;
- int is_post = 0;
+ int is_post = 0, do_normal_send = 1;
char *boundary = NULL;
size_t boundary_len;
char *cmd, *path, *headers, path_copy[uw_bufsize+1], *inputs, *after_headers;
@@ -433,7 +433,7 @@ static void *worker(void *data) {
strcpy(path_copy, path);
fk = uw_begin(ctx, path_copy);
- if (fk == SUCCESS) {
+ if (fk == SUCCESS || fk == RETURN_BLOB) {
uw_commit(ctx);
break;
} else if (fk == BOUNDED_RETRY) {
diff --git a/src/c/urweb.c b/src/c/urweb.c
index ff4d5c8f..28364f2c 100644
--- a/src/c/urweb.c
+++ b/src/c/urweb.c
@@ -1,4 +1,4 @@
-#define _XOPEN_SOURCE
+#define _XOPEN_SOURCE 500
#include
#include
@@ -8,6 +8,7 @@
#include
#include
#include
+#include
#include
@@ -2104,6 +2105,16 @@ uw_Basis_string uw_Basis_bless(uw_context ctx, uw_Basis_string s) {
return s;
}
+uw_Basis_string uw_Basis_blessMime(uw_context ctx, uw_Basis_string s) {
+ char *s2;
+
+ for (s2 = s; *s2; ++s2)
+ if (!isalnum(*s2) && *s2 != '/' && *s2 != '-' && *s2 != '.')
+ uw_error(ctx, FATAL, "MIME type \"%s\" contains invalid character %c\n", s, *s2);
+
+ return s;
+}
+
uw_Basis_string uw_unnull(uw_Basis_string s) {
return s ? s : "";
}
@@ -2135,3 +2146,28 @@ uw_Basis_string uw_Basis_fileMimeType(uw_context ctx, uw_Basis_file f) {
uw_Basis_blob uw_Basis_fileData(uw_context ctx, uw_Basis_file f) {
return f.data;
}
+
+__attribute__((noreturn)) void uw_return_blob(uw_context ctx, uw_Basis_blob b, uw_Basis_string mimeType) {
+ cleanup *cl;
+ int len;
+
+ buf_reset(&ctx->outHeaders);
+ buf_reset(&ctx->page);
+
+ uw_write_header(ctx, "HTTP/1.1 200 OK\r\nContent-Type: ");
+ uw_write_header(ctx, mimeType);
+ uw_write_header(ctx, "\r\nContent-Length: ");
+ buf_check(&ctx->outHeaders, INTS_MAX);
+ sprintf(ctx->outHeaders.front, "%d%n", b.size, &len);
+ ctx->outHeaders.front += len;
+ uw_write_header(ctx, "\r\n");
+
+ buf_append(&ctx->page, b.data, b.size);
+
+ for (cl = ctx->cleanup; cl < ctx->cleanup_front; ++cl)
+ cl->func(cl->arg);
+
+ ctx->cleanup_front = ctx->cleanup;
+
+ longjmp(ctx->jmp_buf, RETURN_BLOB);
+}
diff --git a/src/cjr.sml b/src/cjr.sml
index 9d43f14a..559b7ada 100644
--- a/src/cjr.sml
+++ b/src/cjr.sml
@@ -75,6 +75,7 @@ datatype exp' =
| ECase of exp * (pat * exp) list * { disc : typ, result : typ }
| EError of exp * typ
+ | EReturnBlob of {blob : exp, mimeType : exp, t : typ}
| EWrite of exp
| ESeq of exp * exp
diff --git a/src/cjr_print.sml b/src/cjr_print.sml
index 07e3931f..3f7ec1e1 100644
--- a/src/cjr_print.sml
+++ b/src/cjr_print.sml
@@ -1276,8 +1276,26 @@ fun p_exp' par env (e, loc) =
string "tmp;",
newline,
string "})"]
+ | EReturnBlob {blob, mimeType, t} =>
+ box [string "({",
+ newline,
+ p_typ env t,
+ space,
+ string "tmp;",
+ newline,
+ string "uw_return_blob(ctx, ",
+ p_exp env blob,
+ string ", ",
+ p_exp env mimeType,
+ 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), _) =>
+ p_exp env (EReturnBlob {blob = blob, mimeType = mimeType, t = ran}, loc)
| EFfiApp (m, x, es) => box [string "uw_",
p_ident m,
diff --git a/src/cjrize.sml b/src/cjrize.sml
index 5e0f9bdb..ee2ecdb6 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -319,6 +319,14 @@ fun cifyExp (eAll as (e, loc), sm) =
in
((L'.EError (e, t), loc), sm)
end
+ | L.EReturnBlob {blob, mimeType, t} =>
+ let
+ val (blob, sm) = cifyExp (blob, sm)
+ val (mimeType, sm) = cifyExp (mimeType, sm)
+ val (t, sm) = cifyTyp (t, sm)
+ in
+ ((L'.EReturnBlob {blob = blob, mimeType = mimeType, t = t}, loc), sm)
+ end
| L.EStrcat (e1, e2) =>
let
diff --git a/src/jscomp.sml b/src/jscomp.sml
index e6da3d4b..0f545987 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -101,6 +101,7 @@ fun varDepth (e, _) =
(map (fn (p, e) => E.patBindsN p + varDepth e) pes)
| EStrcat (e1, e2) => Int.max (varDepth e1, varDepth e2)
| EError (e, _) => varDepth e
+ | EReturnBlob {blob = e1, mimeType = e2, ...} => Int.max (varDepth e1, varDepth e2)
| EWrite e => varDepth e
| ESeq (e1, e2) => Int.max (varDepth e1, varDepth e2)
| ELet (_, _, e1, e2) => Int.max (varDepth e1, 1 + varDepth e2)
@@ -141,6 +142,7 @@ fun closedUpto d =
andalso List.all (fn (p, e) => cu (inner + E.patBindsN p) e) pes
| EStrcat (e1, e2) => cu inner e1 andalso cu inner e2
| EError (e, _) => cu inner e
+ | EReturnBlob {blob = e1, mimeType = e2, ...} => cu inner e1 andalso cu inner e2
| EWrite e => cu inner e
| ESeq (e1, e2) => cu inner e1 andalso cu inner e2
| ELet (_, _, e1, e2) => cu inner e1 andalso cu (inner + 1) e2
@@ -915,6 +917,7 @@ fun process file =
| EDml _ => unsupported "DML"
| ENextval _ => unsupported "Nextval"
| EUnurlify _ => unsupported "EUnurlify"
+ | EReturnBlob _ => unsupported "EUnurlify"
| EJavaScript (_, e, _) =>
let
val (e, st) = jsE inner (e, st)
diff --git a/src/mono.sml b/src/mono.sml
index 94314774..e9d30181 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -88,6 +88,7 @@ datatype exp' =
| EStrcat of exp * exp
| EError of exp * typ
+ | EReturnBlob of {blob : exp, mimeType : exp, t : typ}
| EWrite of exp
| ESeq of exp * exp
diff --git a/src/mono_opt.sig b/src/mono_opt.sig
index b1652c71..905dc53b 100644
--- a/src/mono_opt.sig
+++ b/src/mono_opt.sig
@@ -31,5 +31,6 @@ signature MONO_OPT = sig
val optExp : Mono.exp -> Mono.exp
val bless : (string -> bool) ref
+ val blessMime : (string -> bool) ref
end
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index 670774a2..19244e60 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -31,6 +31,7 @@ open Mono
structure U = MonoUtil
val bless = ref (fn _ : string => true)
+val blessMime = ref (CharVector.all (fn ch => Char.isAlphaNum ch orelse ch = #"-" orelse ch = #"/" orelse ch = #"."))
fun typ t = t
fun decl d = d
@@ -386,6 +387,12 @@ fun exp e =
else
ErrorMsg.errorAt loc "Invalid URL passed to 'bless'";
se)
+ | EFfiApp ("Basis", "blessMime", [(se as EPrim (Prim.String s), loc)]) =>
+ (if !blessMime s then
+ ()
+ else
+ ErrorMsg.errorAt loc "Invalid string passed to 'blessMime'";
+ se)
| EFfiApp ("Basis", "checkString", [(EPrim (Prim.String s), loc)]) =>
let
diff --git a/src/mono_print.sml b/src/mono_print.sml
index b01442e8..ffc1d4fe 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -211,6 +211,18 @@ fun p_exp' par env (e, _) =
space,
p_typ env t,
string ")"]
+ | EReturnBlob {blob, mimeType, t} => box [string "(blob",
+ space,
+ p_exp env blob,
+ space,
+ string "in",
+ space,
+ p_exp env mimeType,
+ 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 c124a7b4..4eee1f79 100644
--- a/src/mono_reduce.sml
+++ b/src/mono_reduce.sml
@@ -79,6 +79,7 @@ fun impure (e, _) =
| ECase (e, pes, _) => impure e orelse List.exists (fn (_, e) => impure e) pes
| EError (e, _) => impure e
+ | EReturnBlob {blob = e1, mimeType = e2, ...} => impure e1 orelse impure e2
| EStrcat (e1, e2) => impure e1 orelse impure e2
@@ -349,6 +350,7 @@ fun reduce file =
| EStrcat (e1, e2) => summarize d e1 @ summarize d e2
| EError (e, _) => summarize d e @ [Unsure]
+ | EReturnBlob {blob = e1, mimeType = e2, ...} => summarize d e1 @ summarize d e2 @ [Unsure]
| EWrite e => summarize d e @ [WritePage]
diff --git a/src/mono_util.sml b/src/mono_util.sml
index 017b86ca..dd848ba6 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -247,7 +247,15 @@ fun mapfoldB {typ = fc, exp = fe, bind} =
S.map2 (mft t,
fn t' =>
(EError (e', t'), loc)))
-
+ | EReturnBlob {blob, mimeType, t} =>
+ S.bind2 (mfe ctx blob,
+ fn blob' =>
+ S.bind2 (mfe ctx mimeType,
+ fn mimeType' =>
+ S.map2 (mft t,
+ fn t' =>
+ (EReturnBlob {blob = blob', mimeType = mimeType', t = t'}, loc))))
+
| EStrcat (e1, e2) =>
S.bind2 (mfe ctx e1,
fn e1' =>
diff --git a/src/monoize.sml b/src/monoize.sml
index 8ccb84fc..90440807 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -128,6 +128,7 @@ fun monoType env =
readType (mt env dtmap t, loc)
| L.CFfi ("Basis", "url") => (L'.TFfi ("Basis", "string"), loc)
+ | L.CFfi ("Basis", "mimeType") => (L'.TFfi ("Basis", "string"), loc)
| L.CApp ((L.CApp ((L.CApp ((L.CFfi ("Basis", "xml"), _), _), _), _), _), _) =>
(L'.TFfi ("Basis", "string"), loc)
| L.CApp ((L.CApp ((L.CFfi ("Basis", "xhtml"), _), _), _), _) =>
@@ -2560,6 +2561,20 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L'.EError ((L'.ERel 0, loc), t), loc)), loc),
fm)
end
+ | L.ECApp ((L.EFfi ("Basis", "returnBlob"), _), t) =>
+ let
+ val t = monoType env t
+ val un = (L'.TRecord [], loc)
+ in
+ ((L'.EAbs ("b", (L'.TFfi ("Basis", "blob"), loc),
+ (L'.TFun ((L'.TFfi ("Basis", "string"), loc), (L'.TFun (un, t), loc)), loc),
+ (L'.EAbs ("mt", (L'.TFfi ("Basis", "string"), loc), (L'.TFun (un, t), loc),
+ (L'.EAbs ("_", un, t,
+ (L'.EReturnBlob {blob = (L'.ERel 2, loc),
+ mimeType = (L'.ERel 1, loc),
+ t = t}, loc)), loc)), loc)), loc),
+ fm)
+ end
| L.EApp (e1, e2) =>
let
diff --git a/src/prepare.sml b/src/prepare.sml
index 52308540..25306e89 100644
--- a/src/prepare.sml
+++ b/src/prepare.sml
@@ -156,6 +156,14 @@ fun prepExp (e as (_, loc), sns) =
((EError (e, t), loc), sns)
end
+ | EReturnBlob {blob, mimeType, t} =>
+ let
+ val (blob, sns) = prepExp (blob, sns)
+ val (mimeType, sns) = prepExp (mimeType, sns)
+ in
+ ((EReturnBlob {blob = blob, mimeType = mimeType, t = t}, loc), sns)
+ end
+
| EWrite e =>
let
val (e, sns) = prepExp (e, sns)
diff --git a/src/scriptcheck.sml b/src/scriptcheck.sml
index 352ef46c..61676dc6 100644
--- a/src/scriptcheck.sml
+++ b/src/scriptcheck.sml
@@ -86,6 +86,7 @@ fun classify (ds, ps) =
| EField (e, _) => hasClient e
| 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
| EWrite e => hasClient e
| ESeq (e1, e2) => hasClient e1 orelse hasClient e2
| ELet (_, _, e1, e2) => hasClient e1 orelse hasClient e2
diff --git a/tests/echoBlob.ur b/tests/echoBlob.ur
new file mode 100644
index 00000000..fc8f8603
--- /dev/null
+++ b/tests/echoBlob.ur
@@ -0,0 +1,8 @@
+fun echo r = returnBlob (fileData r.Data) (blessMime (fileMimeType r.Data))
+
+fun main () = return
+
+
diff --git a/tests/echoBlob.urp b/tests/echoBlob.urp
new file mode 100644
index 00000000..4b94b59c
--- /dev/null
+++ b/tests/echoBlob.urp
@@ -0,0 +1,3 @@
+debug
+
+echoBlob
diff --git a/tests/echoBlob.urs b/tests/echoBlob.urs
new file mode 100644
index 00000000..6ac44e0b
--- /dev/null
+++ b/tests/echoBlob.urs
@@ -0,0 +1 @@
+val main : unit -> transaction page
--
cgit v1.2.3
From 51f2a80dac5c3cd25a27fb5abfdfa50d813ab0b2 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Tue, 28 Apr 2009 15:04:37 -0400
Subject: A view query works
---
src/cjr.sml | 1 +
src/cjr_env.sml | 1 +
src/cjr_print.sml | 20 ++++++++++++
src/cjrize.sml | 28 +++++++++++++++++
src/core.sml | 1 +
src/core_env.sml | 7 +++++
src/core_print.sml | 7 +++++
src/core_util.sml | 15 +++++++++
src/corify.sml | 8 +++++
src/elab.sml | 1 +
src/elab_env.sml | 82 ++++++++++++++++++++++++++++++++-----------------
src/elab_print.sml | 7 +++++
src/elab_util.sml | 14 +++++++++
src/elaborate.sml | 47 ++++++++++++++++++++++------
src/elisp/urweb-mode.el | 2 +-
src/expl.sml | 1 +
src/expl_env.sml | 7 +++++
src/expl_print.sml | 7 +++++
src/explify.sml | 2 ++
src/mono.sml | 1 +
src/mono_env.sml | 1 +
src/mono_opt.sml | 25 +++++++++++++++
src/mono_print.sml | 7 +++++
src/mono_shake.sml | 2 ++
src/mono_util.sml | 6 ++++
src/monoize.sml | 18 +++++++++++
src/prepare.sml | 1 +
src/reduce.sml | 1 +
src/reduce_local.sml | 1 +
src/shake.sml | 5 ++-
src/source.sml | 1 +
src/source_print.sml | 7 +++++
src/unnest.sml | 1 +
src/urweb.grm | 13 +++++++-
src/urweb.lex | 1 +
tests/view.ur | 10 ++++++
tests/view.urp | 5 +++
tests/view.urs | 1 +
38 files changed, 325 insertions(+), 40 deletions(-)
create mode 100644 tests/view.ur
create mode 100644 tests/view.urp
create mode 100644 tests/view.urs
(limited to 'src/mono_opt.sml')
diff --git a/src/cjr.sml b/src/cjr.sml
index 559b7ada..d3fdbc22 100644
--- a/src/cjr.sml
+++ b/src/cjr.sml
@@ -107,6 +107,7 @@ datatype decl' =
| DTable of string * (string * typ) list * string * (string * string) list
| DSequence of string
+ | DView of string * (string * typ) list * string
| DDatabase of {name : string, expunge : int, initialize : int}
| DPreparedStatements of (string * int) list
diff --git a/src/cjr_env.sml b/src/cjr_env.sml
index 7f02a4e9..54dbea17 100644
--- a/src/cjr_env.sml
+++ b/src/cjr_env.sml
@@ -164,6 +164,7 @@ fun declBinds env (d, loc) =
end) env vis
| DTable _ => env
| DSequence _ => env
+ | DView _ => env
| DDatabase _ => env
| DPreparedStatements _ => env
| DJavaScript _ => env
diff --git a/src/cjr_print.sml b/src/cjr_print.sml
index c870c3ed..a09dd7f6 100644
--- a/src/cjr_print.sml
+++ b/src/cjr_print.sml
@@ -2069,6 +2069,15 @@ fun p_decl env (dAll as (d, _) : decl) =
string x,
string " */",
newline]
+ | DView (x, _, s) => box [string "/* SQL view ",
+ string x,
+ space,
+ string "AS",
+ space,
+ string s,
+ space,
+ string " */",
+ newline]
| DDatabase {name, expunge, initialize} =>
box [string "static void uw_db_validate(uw_context);",
newline,
@@ -3089,6 +3098,17 @@ fun p_sql env (ds, _) =
string ";",
newline,
newline]
+ | DView (s, xts, q) =>
+ box [string "CREATE VIEW",
+ space,
+ string s,
+ space,
+ string "AS",
+ space,
+ string q,
+ string ";",
+ newline,
+ newline]
| _ => box []
in
(pp, E.declBinds env dAll)
diff --git a/src/cjrize.sml b/src/cjrize.sml
index ee2ecdb6..19aeee4e 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -562,6 +562,34 @@ fun cifyDecl ((d, loc), sm) =
end
| L.DSequence s =>
(SOME (L'.DSequence s, loc), NONE, sm)
+ | L.DView (s, xts, e) =>
+ let
+ val (xts, sm) = ListUtil.foldlMap (fn ((x, t), sm) =>
+ let
+ val (t, sm) = cifyTyp (t, sm)
+ in
+ ((x, t), sm)
+ end) sm xts
+
+ fun flatten e =
+ case #1 e of
+ L.ERecord [] => []
+ | L.ERecord [(x, (L.EPrim (Prim.String v), _), _)] => [(x, v)]
+ | L.EStrcat (e1, e2) => flatten e1 @ flatten e2
+ | _ => (ErrorMsg.errorAt loc "Constraint has not been fully determined";
+ Print.prefaces "Undetermined constraint"
+ [("e", MonoPrint.p_exp MonoEnv.empty e)];
+ [])
+
+ val e = case #1 e of
+ L.EPrim (Prim.String s) => s
+ | _ => (ErrorMsg.errorAt loc "VIEW query has not been fully determined";
+ Print.prefaces "Undetermined VIEW query"
+ [("e", MonoPrint.p_exp MonoEnv.empty e)];
+ "")
+ in
+ (SOME (L'.DView (s, xts, e), loc), NONE, sm)
+ end
| L.DDatabase s => (SOME (L'.DDatabase s, loc), NONE, sm)
| L.DJavaScript s => (SOME (L'.DJavaScript s, loc), NONE, sm)
| L.DCookie args => (SOME (L'.DCookie args, loc), NONE, sm)
diff --git a/src/core.sml b/src/core.sml
index 01cf4ec7..131bcc6f 100644
--- a/src/core.sml
+++ b/src/core.sml
@@ -130,6 +130,7 @@ datatype decl' =
| DExport of export_kind * int
| DTable of string * int * con * string * exp * con * exp * con
| DSequence of string * int * string
+ | DView of string * int * string * exp * con
| DDatabase of string
| DCookie of string * int * con * string
| DStyle of string * int * string
diff --git a/src/core_env.sml b/src/core_env.sml
index caf30349..0630fef2 100644
--- a/src/core_env.sml
+++ b/src/core_env.sml
@@ -327,6 +327,13 @@ fun declBinds env (d, loc) =
in
pushENamed env x n t NONE s
end
+ | DView (x, n, s, _, c) =>
+ let
+ val ct = (CFfi ("Basis", "sql_view"), loc)
+ val ct = (CApp (ct, c), loc)
+ in
+ pushENamed env x n ct NONE s
+ end
| DDatabase _ => env
| DCookie (x, n, c, s) =>
let
diff --git a/src/core_print.sml b/src/core_print.sml
index 9c1c72cd..f2a42a7b 100644
--- a/src/core_print.sml
+++ b/src/core_print.sml
@@ -566,6 +566,13 @@ fun p_decl env (dAll as (d, _) : decl) =
string "as",
space,
string s]
+ | DView (x, n, s, e, _) => box [string "view",
+ space,
+ p_named x n,
+ space,
+ string "as",
+ space,
+ p_exp env e]
| DDatabase s => box [string "database",
space,
string s]
diff --git a/src/core_util.sml b/src/core_util.sml
index d05aaa72..ae956121 100644
--- a/src/core_util.sml
+++ b/src/core_util.sml
@@ -946,6 +946,12 @@ fun mapfoldB {kind = fk, con = fc, exp = fe, decl = fd, bind} =
fn cc' =>
(DTable (x, n, c', s, pe', pc', ce', cc'), loc))))))
| DSequence _ => S.return2 dAll
+ | DView (x, n, s, e, c) =>
+ S.bind2 (mfe ctx e,
+ fn e' =>
+ S.map2 (mfc ctx c,
+ fn c' =>
+ (DView (x, n, s, e', c'), loc)))
| DDatabase _ => S.return2 dAll
| DCookie (x, n, c, s) =>
S.map2 (mfc ctx c,
@@ -1082,6 +1088,14 @@ fun mapfoldB (all as {bind, ...}) =
in
bind (ctx, NamedE (x, n, t, NONE, s))
end
+ | DView (x, n, s, _, c) =>
+ let
+ val loc = #2 d'
+ val ct = (CFfi ("Basis", "sql_view"), loc)
+ val ct = (CApp (ct, c), loc)
+ in
+ bind (ctx, NamedE (x, n, ct, NONE, s))
+ end
| DDatabase _ => ctx
| DCookie (x, n, c, s) =>
let
@@ -1154,6 +1168,7 @@ val maxName = foldl (fn ((d, _) : decl, count) =>
| DExport _ => count
| DTable (_, n, _, _, _, _, _, _) => Int.max (n, count)
| DSequence (_, n, _) => Int.max (n, count)
+ | DView (_, n, _, _, _) => Int.max (n, count)
| DDatabase _ => count
| DCookie (_, n, _, _) => Int.max (n, count)
| DStyle (_, n, _) => Int.max (n, count)) 0
diff --git a/src/corify.sml b/src/corify.sml
index c1cd940e..f1895e19 100644
--- a/src/corify.sml
+++ b/src/corify.sml
@@ -992,6 +992,13 @@ fun corifyDecl mods (all as (d, loc : EM.span), st) =
in
([(L'.DSequence (x, n, s), loc)], st)
end
+ | L.DView (_, x, n, e, c) =>
+ let
+ val (st, n) = St.bindVal st x n
+ val s = relify (doRestify (mods, x))
+ in
+ ([(L'.DView (x, n, s, corifyExp st e, corifyCon st c), loc)], st)
+ end
| L.DDatabase s => ([(L'.DDatabase s, loc)], st)
@@ -1063,6 +1070,7 @@ fun maxName ds = foldl (fn ((d, _), n) =>
| L.DExport _ => n
| L.DTable (_, _, n', _, _, _, _, _) => Int.max (n, n')
| L.DSequence (_, _, n') => Int.max (n, 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'))
diff --git a/src/elab.sml b/src/elab.sml
index f82a947d..555cc25c 100644
--- a/src/elab.sml
+++ b/src/elab.sml
@@ -165,6 +165,7 @@ datatype decl' =
| DExport of int * sgn * str
| DTable of int * string * int * con * exp * con * exp * con
| DSequence of int * string * int
+ | DView of int * string * int * exp * con
| DClass of string * int * kind * con
| DDatabase of string
| DCookie of int * string * int * con
diff --git a/src/elab_env.sml b/src/elab_env.sml
index 0184d0b1..efc2b74e 100644
--- a/src/elab_env.sml
+++ b/src/elab_env.sml
@@ -591,6 +591,22 @@ fun unifySubst (rs : con list) =
exception Bad of con * con
+val hasUnif = U.Con.exists {kind = fn _ => false,
+ con = fn CUnif (_, _, _, ref NONE) => true
+ | _ => false}
+
+fun startsWithUnif c =
+ let
+ fun firstArg (c, acc) =
+ case #1 c of
+ CApp (f, x) => firstArg (f, SOME x)
+ | _ => acc
+ in
+ case firstArg (c, NONE) of
+ NONE => false
+ | SOME x => hasUnif x
+ end
+
fun resolveClass (hnorm : con -> con) (consEq : con * con -> bool) (env : env) =
let
fun resolve c =
@@ -671,34 +687,37 @@ fun resolveClass (hnorm : con -> con) (consEq : con * con -> bool) (env : env) =
tryGrounds (#ground class)
end
in
- case #1 c of
- TRecord c =>
- (case #1 (hnorm c) of
- CRecord (_, xts) =>
- let
- fun resolver (xts, acc) =
- case xts of
- [] => SOME (ERecord acc, #2 c)
- | (x, t) :: xts =>
- let
- val t = hnorm t
-
- val t = case t of
- (CApp (f, x), loc) => (CApp (hnorm f, hnorm x), loc)
- | _ => t
- in
- case resolve t of
- NONE => NONE
- | SOME e => resolver (xts, (x, e, t) :: acc)
- end
- in
- resolver (xts, [])
- end
- | _ => NONE)
- | _ =>
- case class_head_in c of
- SOME f => doHead f
- | _ => NONE
+ if startsWithUnif c then
+ NONE
+ else
+ case #1 c of
+ TRecord c =>
+ (case #1 (hnorm c) of
+ CRecord (_, xts) =>
+ let
+ fun resolver (xts, acc) =
+ case xts of
+ [] => SOME (ERecord acc, #2 c)
+ | (x, t) :: xts =>
+ let
+ val t = hnorm t
+
+ val t = case t of
+ (CApp (f, x), loc) => (CApp (hnorm f, hnorm x), loc)
+ | _ => t
+ in
+ case resolve t of
+ NONE => NONE
+ | SOME e => resolver (xts, (x, e, t) :: acc)
+ end
+ in
+ resolver (xts, [])
+ end
+ | _ => NONE)
+ | _ =>
+ case class_head_in c of
+ SOME f => doHead f
+ | _ => NONE
end
in
resolve
@@ -1482,6 +1501,13 @@ fun declBinds env (d, loc) =
in
pushENamedAs env x n t
end
+ | DView (tn, x, n, _, c) =>
+ let
+ val ct = (CModProj (tn, [], "sql_view"), loc)
+ val ct = (CApp (ct, c), loc)
+ in
+ pushENamedAs env x n ct
+ end
| DClass (x, n, k, c) =>
let
val k = (KArrow (k, (KType, loc)), loc)
diff --git a/src/elab_print.sml b/src/elab_print.sml
index e6a2cccb..bbbd9f8d 100644
--- a/src/elab_print.sml
+++ b/src/elab_print.sml
@@ -758,6 +758,13 @@ fun p_decl env (dAll as (d, _) : decl) =
| DSequence (_, x, n) => box [string "sequence",
space,
p_named x n]
+ | DView (_, x, n, e, _) => box [string "view",
+ space,
+ p_named x n,
+ space,
+ string "as",
+ space,
+ p_exp env e]
| DClass (x, n, k, c) => box [string "class",
space,
p_named x n,
diff --git a/src/elab_util.sml b/src/elab_util.sml
index 0d78951b..f4cbc951 100644
--- a/src/elab_util.sml
+++ b/src/elab_util.sml
@@ -791,6 +791,13 @@ fun mapfoldB {kind = fk, con = fc, exp = fe, sgn_item = fsgi, sgn = fsg, str = f
end
| DSequence (tn, x, n) =>
bind (ctx, NamedE (x, (CModProj (n, [], "sql_sequence"), loc)))
+ | DView (tn, x, n, _, c) =>
+ let
+ val ct = (CModProj (n, [], "sql_view"), loc)
+ val ct = (CApp (ct, c), loc)
+ in
+ bind (ctx, NamedE (x, ct))
+ end
| DClass (x, n, k, _) =>
bind (ctx, NamedC (x, n, (KArrow (k, (KType, loc)), loc)))
| DDatabase _ => ctx
@@ -899,6 +906,12 @@ fun mapfoldB {kind = fk, con = fc, exp = fe, sgn_item = fsgi, sgn = fsg, str = f
fn cc' =>
(DTable (tn, x, n, c', pe', pc', ce', cc'), loc))))))
| DSequence _ => S.return2 dAll
+ | DView (tn, x, n, e, c) =>
+ S.bind2 (mfe ctx e,
+ fn e' =>
+ S.map2 (mfc ctx c,
+ fn c' =>
+ (DView (tn, x, n, e', c'), loc)))
| DClass (x, n, k, c) =>
S.bind2 (mfk ctx k,
@@ -1051,6 +1064,7 @@ and maxNameDecl (d, _) =
| DExport _ => 0
| DTable (n1, _, n2, _, _, _, _, _) => Int.max (n1, n2)
| DSequence (n1, _, n2) => Int.max (n1, n2)
+ | DView (n1, _, n2, _, _) => Int.max (n1, n2)
| DDatabase _ => 0
| DCookie (n1, _, n2, _) => Int.max (n1, n2)
| DStyle (n1, _, n2) => Int.max (n1, n2)
diff --git a/src/elaborate.sml b/src/elaborate.sml
index 81fcbda1..b9378e1b 100644
--- a/src/elaborate.sml
+++ b/src/elaborate.sml
@@ -803,19 +803,22 @@
handle GuessFailure => false
end
- val (fs1, fs2, others1, others2) =
+ val (fs1, fs2, others1, others2, unifs1, unifs2) =
case (fs1, fs2, others1, others2, unifs1, unifs2) of
([], _, [other1], [], [], _) =>
if isGuessable (other1, fs2, unifs2) then
- ([], [], [], [])
+ ([], [], [], [], [], [])
else
- (fs1, fs2, others1, others2)
+ (fs1, fs2, others1, others2, unifs1, unifs2)
| (_, [], [], [other2], _, []) =>
if isGuessable (other2, fs1, unifs1) then
- ([], [], [], [])
+ ([], [], [], [], [], [])
else
- (fs1, fs2, others1, others2)
- | _ => (fs1, fs2, others1, others2)
+ (prefaces "Not guessable" [("other2", p_con env other2),
+ ("fs1", p_con env (L'.CRecord (k, fs1), loc)),
+ ("#unifs1", PD.string (Int.toString (length unifs1)))];
+ (fs1, fs2, others1, others2, unifs1, unifs2))
+ | _ => (fs1, fs2, others1, others2, unifs1, unifs2)
(*val () = eprefaces "Summaries5" [("#1", p_summary env {fields = fs1, unifs = unifs1, others = others1}),
("#2", p_summary env {fields = fs2, unifs = unifs2, others = others2})]*)
@@ -849,7 +852,7 @@
fun unfold (dom, ran, f, r, c) =
let
fun unfold (r, c) =
- case #1 c of
+ case #1 (hnormCon env c) of
L'.CRecord (_, []) => unifyCons env r (L'.CRecord (dom, []), loc)
| L'.CRecord (_, [(x, v)]) =>
let
@@ -878,8 +881,7 @@
unfold (r2, c2');
unifyCons env r (L'.CConcat (r1, r2), loc)
end
- | L'.CUnif (_, _, _, ref (SOME c)) => unfold (r, c)
- | L'.CUnif (_, _, _, ur as ref NONE) =>
+ | L'.CUnif (_, _, _, ur) =>
let
val ur' = cunif (loc, (L'.KRecord dom, loc))
in
@@ -1935,6 +1937,8 @@ val hnormSgn = E.hnormSgn
fun tableOf () = (L'.CModProj (!basis_r, [], "sql_table"), ErrorMsg.dummySpan)
fun sequenceOf () = (L'.CModProj (!basis_r, [], "sql_sequence"), ErrorMsg.dummySpan)
+fun viewOf () = (L'.CModProj (!basis_r, [], "sql_view"), ErrorMsg.dummySpan)
+fun queryOf () = (L'.CModProj (!basis_r, [], "sql_query"), ErrorMsg.dummySpan)
fun cookieOf () = (L'.CModProj (!basis_r, [], "http_cookie"), ErrorMsg.dummySpan)
fun styleOf () = (L'.CModProj (!basis_r, [], "css_class"), ErrorMsg.dummySpan)
@@ -2434,6 +2438,8 @@ and sgiOfDecl (d, loc) =
[(L'.SgiVal (x, n, (L'.CApp ((L'.CApp (tableOf (), c), loc),
(L'.CConcat (pc, cc), loc)), loc)), loc)]
| L'.DSequence (tn, x, n) => [(L'.SgiVal (x, n, sequenceOf ()), loc)]
+ | L'.DView (tn, x, n, _, c) =>
+ [(L'.SgiVal (x, n, (L'.CApp (viewOf (), c), loc)), loc)]
| L'.DClass (x, n, k, c) => [(L'.SgiClass (x, n, k, c), loc)]
| L'.DDatabase _ => []
| L'.DCookie (tn, x, n, c) => [(L'.SgiVal (x, n, (L'.CApp (cookieOf (), c), loc)), loc)]
@@ -3405,6 +3411,29 @@ and elabDecl (dAll as (d, loc), (env, denv, gs)) =
in
([(L'.DSequence (!basis_r, x, n), loc)], (env, denv, gs))
end
+ | L.DView (x, e) =>
+ let
+ val (e', t, gs') = elabExp (env, denv) e
+
+ val k = (L'.KRecord (L'.KType, loc), loc)
+ val fs = cunif (loc, k)
+ val ts = cunif (loc, (L'.KRecord k, loc))
+ val tf = (L'.CApp ((L'.CMap (k, k), loc),
+ (L'.CAbs ("_", k, (L'.CRecord ((L'.KType, loc), []), loc)), loc)), loc)
+ val ts = (L'.CApp (tf, ts), loc)
+
+ val cv = viewOf ()
+ val cv = (L'.CApp (cv, fs), loc)
+ val (env', n) = E.pushENamed env x cv
+
+ val ct = queryOf ()
+ val ct = (L'.CApp (ct, ts), loc)
+ val ct = (L'.CApp (ct, fs), loc)
+ in
+ checkCon env e' t ct;
+ ([(L'.DView (!basis_r, x, n, e', fs), loc)],
+ (env', denv, gs' @ gs))
+ end
| L.DClass (x, k, c) =>
let
diff --git a/src/elisp/urweb-mode.el b/src/elisp/urweb-mode.el
index 2cd27fcc..7f4b0dee 100644
--- a/src/elisp/urweb-mode.el
+++ b/src/elisp/urweb-mode.el
@@ -137,7 +137,7 @@ See doc for the variable `urweb-mode-info'."
"fun" "functor" "if" "include"
"of" "open" "let" "in"
"rec" "sequence" "sig" "signature" "cookie" "style"
- "struct" "structure" "table" "then" "type" "val" "where"
+ "struct" "structure" "table" "view" "then" "type" "val" "where"
"with"
"Name" "Type" "Unit")
diff --git a/src/expl.sml b/src/expl.sml
index e293c36b..cc40e8b4 100644
--- a/src/expl.sml
+++ b/src/expl.sml
@@ -143,6 +143,7 @@ datatype decl' =
| DExport of int * sgn * str
| DTable of int * string * int * con * exp * con * exp * con
| DSequence of int * string * int
+ | DView of int * string * int * exp * con
| DDatabase of string
| DCookie of int * string * int * con
| DStyle of int * string * int
diff --git a/src/expl_env.sml b/src/expl_env.sml
index 1e99b36b..2bb049a3 100644
--- a/src/expl_env.sml
+++ b/src/expl_env.sml
@@ -312,6 +312,13 @@ fun declBinds env (d, loc) =
in
pushENamed env x n t
end
+ | DView (tn, x, n, _, c) =>
+ let
+ val ct = (CModProj (tn, [], "sql_view"), loc)
+ val ct = (CApp (ct, c), loc)
+ in
+ pushENamed env x n ct
+ end
| DDatabase _ => env
| DCookie (tn, x, n, c) =>
let
diff --git a/src/expl_print.sml b/src/expl_print.sml
index 167c6850..e6b28fea 100644
--- a/src/expl_print.sml
+++ b/src/expl_print.sml
@@ -681,6 +681,13 @@ fun p_decl env (dAll as (d, _) : decl) =
| DSequence (_, x, n) => box [string "sequence",
space,
p_named x n]
+ | DView (_, x, n, e, _) => box [string "view",
+ space,
+ p_named x n,
+ space,
+ string "as",
+ space,
+ p_exp env e]
| DDatabase s => box [string "database",
space,
string s]
diff --git a/src/explify.sml b/src/explify.sml
index 6a33eabc..2e181771 100644
--- a/src/explify.sml
+++ b/src/explify.sml
@@ -182,6 +182,8 @@ fun explifyDecl (d, loc : EM.span) =
SOME (L'.DTable (nt, x, n, explifyCon c,
explifyExp pe, explifyCon pc,
explifyExp ce, explifyCon cc), loc)
+ | L.DView (nt, x, n, e, c) =>
+ SOME (L'.DView (nt, x, n, explifyExp e, explifyCon c), loc)
| L.DSequence (nt, x, n) => SOME (L'.DSequence (nt, x, n), loc)
| L.DClass (x, n, k, c) => SOME (L'.DCon (x, n,
(L'.KArrow (explifyKind k, (L'.KType, loc)), loc), explifyCon c), loc)
diff --git a/src/mono.sml b/src/mono.sml
index e9d30181..7a789e2c 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -127,6 +127,7 @@ datatype decl' =
| DTable of string * (string * typ) list * exp * exp
| DSequence of string
+ | DView of string * (string * typ) list * exp
| DDatabase of {name : string, expunge : int, initialize : int}
| DJavaScript of string
diff --git a/src/mono_env.sml b/src/mono_env.sml
index b3572fbe..739f2f89 100644
--- a/src/mono_env.sml
+++ b/src/mono_env.sml
@@ -109,6 +109,7 @@ fun declBinds env (d, loc) =
| DExport _ => env
| DTable _ => env
| DSequence _ => env
+ | DView _ => env
| DDatabase _ => env
| DJavaScript _ => env
| DCookie _ => env
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index 19244e60..41724eb0 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -422,6 +422,31 @@ fun exp e =
EPrim (Prim.String s)
end
+ | EFfiApp ("Basis", "viewify", [(EPrim (Prim.String s), loc)]) =>
+ let
+ fun uwify (cs, acc) =
+ case cs of
+ [] => String.concat (rev acc)
+ | #"A" :: #"S" :: #" " :: #"_" :: cs => uwify (cs, "AS uw_" :: acc)
+ | #"'" :: cs =>
+ let
+ fun waitItOut (cs, acc) =
+ case cs of
+ [] => raise Fail "MonoOpt: Unterminated SQL string literal"
+ | #"'" :: cs => uwify (cs, "'" :: acc)
+ | #"\\" :: #"'" :: cs => waitItOut (cs, "\\'" :: acc)
+ | #"\\" :: #"\\" :: cs => waitItOut (cs, "\\\\" :: acc)
+ | c :: cs => waitItOut (cs, str c :: acc)
+ in
+ waitItOut (cs, "'" :: acc)
+ end
+ | c :: cs => uwify (cs, str c :: acc)
+
+ val s = uwify (String.explode s, [])
+ in
+ EPrim (Prim.String s)
+ end
+
| _ => 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 ffc1d4fe..a233b400 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -438,6 +438,13 @@ fun p_decl env (dAll as (d, _) : decl) =
| DSequence s => box [string "(* SQL sequence ",
string s,
string "*)"]
+ | DView (s, _, e) => box [string "(* SQL view ",
+ string s,
+ space,
+ string "as",
+ space,
+ p_exp env e,
+ string "*)"]
| DDatabase {name, expunge, initialize} => box [string "database",
space,
string name,
diff --git a/src/mono_shake.sml b/src/mono_shake.sml
index 0060d036..4764feb7 100644
--- a/src/mono_shake.sml
+++ b/src/mono_shake.sml
@@ -57,6 +57,7 @@ fun shake file =
| ((DExport _, _), acc) => acc
| ((DTable _, _), acc) => acc
| ((DSequence _, _), acc) => acc
+ | ((DView _, _), acc) => acc
| ((DDatabase _, _), acc) => acc
| ((DJavaScript _, _), acc) => acc
| ((DCookie _, _), acc) => acc
@@ -116,6 +117,7 @@ fun shake file =
| (DExport _, _) => true
| (DTable _, _) => true
| (DSequence _, _) => true
+ | (DView _, _) => true
| (DDatabase _, _) => true
| (DJavaScript _, _) => true
| (DCookie _, _) => true
diff --git a/src/mono_util.sml b/src/mono_util.sml
index dd848ba6..caf96ac7 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -492,6 +492,10 @@ fun mapfoldB {typ = fc, exp = fe, decl = fd, bind} =
fn ce' =>
(DTable (s, xts, pe', ce'), loc)))
| DSequence _ => S.return2 dAll
+ | DView (s, xts, e) =>
+ S.map2 (mfe ctx e,
+ fn e' =>
+ (DView (s, xts, e'), loc))
| DDatabase _ => S.return2 dAll
| DJavaScript _ => S.return2 dAll
| DCookie _ => S.return2 dAll
@@ -575,6 +579,7 @@ fun mapfoldB (all as {bind, ...}) =
| DExport _ => ctx
| DTable _ => ctx
| DSequence _ => ctx
+ | DView _ => ctx
| DDatabase _ => ctx
| DJavaScript _ => ctx
| DCookie _ => ctx
@@ -626,6 +631,7 @@ val maxName = foldl (fn ((d, _) : decl, count) =>
| DExport _ => count
| DTable _ => count
| DSequence _ => count
+ | DView _ => count
| DDatabase _ => count
| DJavaScript _ => count
| DCookie _ => count
diff --git a/src/monoize.sml b/src/monoize.sml
index ccc5a851..a2048a7d 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -2938,6 +2938,24 @@ fun monoDecl (env, fm) (all as (d, loc)) =
(L'.DVal (x, n, t', e_name, s), loc)])
end
| L.DTable _ => poly ()
+ | L.DView (x, n, s, e, (L.CRecord (_, xts), _)) =>
+ let
+ val t = (L.CFfi ("Basis", "string"), loc)
+ val t' = (L'.TFfi ("Basis", "string"), loc)
+ val s = "uw_" ^ s
+ val e_name = (L'.EPrim (Prim.String s), 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)
+ in
+ SOME (Env.pushENamed env x n t NONE s,
+ fm,
+ [(L'.DView (s, xts, e), loc),
+ (L'.DVal (x, n, t', e_name, s), loc)])
+ end
+ | L.DView _ => poly ()
| L.DSequence (x, n, s) =>
let
val t = (L.CFfi ("Basis", "string"), loc)
diff --git a/src/prepare.sml b/src/prepare.sml
index 25306e89..592b00bc 100644
--- a/src/prepare.sml
+++ b/src/prepare.sml
@@ -266,6 +266,7 @@ fun prepDecl (d as (_, loc), sns) =
| DTable _ => (d, sns)
| DSequence _ => (d, sns)
+ | DView _ => (d, sns)
| DDatabase _ => (d, sns)
| DPreparedStatements _ => (d, sns)
| DJavaScript _ => (d, sns)
diff --git a/src/reduce.sml b/src/reduce.sml
index 914f26c0..665c10b4 100644
--- a/src/reduce.sml
+++ b/src/reduce.sml
@@ -467,6 +467,7 @@ fun reduce file =
exp (namedC, namedE) [] ce,
con namedC [] cc), loc), st)
| DSequence _ => (d, st)
+ | DView (s, n, s', e, c) => ((DView (s, n, s', exp (namedC, namedE) [] e, con namedC [] c), loc), st)
| 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)
diff --git a/src/reduce_local.sml b/src/reduce_local.sml
index 265cb2a4..6c25ebf3 100644
--- a/src/reduce_local.sml
+++ b/src/reduce_local.sml
@@ -158,6 +158,7 @@ fun reduce file =
| DExport _ => d
| DTable _ => d
| DSequence _ => d
+ | DView _ => d
| DDatabase _ => d
| DCookie _ => d
| DStyle _ => d
diff --git a/src/shake.sml b/src/shake.sml
index 787bfd2f..35af7436 100644
--- a/src/shake.sml
+++ b/src/shake.sml
@@ -84,6 +84,8 @@ fun shake file =
(cdef, IM.insert (edef, n, ([], c, dummye)))
| ((DSequence (_, n, _), _), (cdef, edef)) =>
(cdef, IM.insert (edef, n, ([], dummyt, dummye)))
+ | ((DView (_, n, _, _, c), _), (cdef, edef)) =>
+ (cdef, IM.insert (edef, n, ([], c, dummye)))
| ((DDatabase _, _), acc) => acc
| ((DCookie (_, n, c, _), _), (cdef, edef)) =>
(cdef, IM.insert (edef, n, ([], c, dummye)))
@@ -159,8 +161,9 @@ fun shake file =
| (DVal (_, n, _, _, _), _) => IS.member (#exp s, n)
| (DValRec vis, _) => List.exists (fn (_, n, _, _, _) => IS.member (#exp s, n)) vis
| (DExport _, _) => true
- | (DTable _, _) => true
+ | (DView _, _) => true
| (DSequence _, _) => true
+ | (DTable _, _) => true
| (DDatabase _, _) => true
| (DCookie _, _) => true
| (DStyle _, _) => true) file
diff --git a/src/source.sml b/src/source.sml
index 6645ae75..9d3eea79 100644
--- a/src/source.sml
+++ b/src/source.sml
@@ -161,6 +161,7 @@ datatype decl' =
| DExport of str
| DTable of string * con * exp * exp
| DSequence of string
+ | DView of string * exp
| DClass of string * kind * con
| DDatabase of string
| DCookie of string * con
diff --git a/src/source_print.sml b/src/source_print.sml
index 58867f64..0f8b093b 100644
--- a/src/source_print.sml
+++ b/src/source_print.sml
@@ -621,6 +621,13 @@ fun p_decl ((d, _) : decl) =
| DSequence x => box [string "sequence",
space,
string x]
+ | DView (x, e) => box [string "view",
+ space,
+ string x,
+ space,
+ string "=",
+ space,
+ p_exp e]
| DClass (x, k, c) => box [string "class",
space,
string x,
diff --git a/src/unnest.sml b/src/unnest.sml
index c321b34d..51b66aa4 100644
--- a/src/unnest.sml
+++ b/src/unnest.sml
@@ -404,6 +404,7 @@ fun unnest file =
| DExport _ => default ()
| DTable _ => default ()
| DSequence _ => default ()
+ | DView _ => default ()
| DClass _ => default ()
| DDatabase _ => default ()
| DCookie _ => default ()
diff --git a/src/urweb.grm b/src/urweb.grm
index ce078279..da817ab3 100644
--- a/src/urweb.grm
+++ b/src/urweb.grm
@@ -195,7 +195,7 @@ datatype attr = Class of exp | Normal of con * exp
| FN | PLUSPLUS | MINUSMINUS | MINUSMINUSMINUS | DOLLAR | TWIDDLE | CARET
| LET | IN
| STRUCTURE | SIGNATURE | STRUCT | SIG | END | FUNCTOR | WHERE | EXTERN | SQL
- | INCLUDE | OPEN | CONSTRAINT | CONSTRAINTS | EXPORT | TABLE | SEQUENCE
+ | INCLUDE | OPEN | CONSTRAINT | CONSTRAINTS | EXPORT | TABLE | SEQUENCE | VIEW
| COOKIE | STYLE
| CASE | IF | THEN | ELSE
@@ -438,6 +438,10 @@ decl : CON SYMBOL cargl2 kopt EQ cexp (let
| TABLE SYMBOL COLON cterm pkopt commaOpt cstopt([(DTable (SYMBOL, entable cterm, pkopt, cstopt),
s (TABLEleft, cstoptright))])
| SEQUENCE SYMBOL ([(DSequence SYMBOL, s (SEQUENCEleft, SYMBOLright))])
+ | VIEW SYMBOL EQ query ([(DView (SYMBOL, query),
+ s (VIEWleft, queryright))])
+ | VIEW SYMBOL EQ LBRACE eexp RBRACE ([(DView (SYMBOL, eexp),
+ s (VIEWleft, RBRACEright))])
| CLASS SYMBOL EQ cexp (let
val loc = s (CLASSleft, cexpright)
in
@@ -674,6 +678,13 @@ sgi : CON SYMBOL DCOLON kind ((SgiConAbs (SYMBOL, kind), s (CONleft,
in
(SgiVal (SYMBOL, t), loc)
end)
+ | VIEW SYMBOL COLON cexp (let
+ val loc = s (VIEWleft, cexpright)
+ val t = (CVar (["Basis"], "sql_view"), loc)
+ val t = (CApp (t, cexp), loc)
+ in
+ (SgiVal (SYMBOL, t), loc)
+ end)
| CLASS SYMBOL (let
val loc = s (CLASSleft, SYMBOLright)
val k = (KArrow ((KType, loc), (KType, loc)), loc)
diff --git a/src/urweb.lex b/src/urweb.lex
index bb9004a6..85cf3bcf 100644
--- a/src/urweb.lex
+++ b/src/urweb.lex
@@ -317,6 +317,7 @@ notags = [^<{\n]+;
"export" => (Tokens.EXPORT (pos yypos, pos yypos + size yytext));
"table" => (Tokens.TABLE (pos yypos, pos yypos + size yytext));
"sequence" => (Tokens.SEQUENCE (pos yypos, pos yypos + size yytext));
+ "view" => (Tokens.VIEW (pos yypos, pos yypos + size yytext));
"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));
diff --git a/tests/view.ur b/tests/view.ur
new file mode 100644
index 00000000..36d77deb
--- /dev/null
+++ b/tests/view.ur
@@ -0,0 +1,10 @@
+table t : { A : int, B : string }
+
+view v = SELECT t.A AS X FROM t
+
+fun main () =
+ rows <- queryX (SELECT * FROM v)
+ (fn r =>
{[r.V.X]}
);
+ return
+ {rows}
+
diff --git a/tests/view.urp b/tests/view.urp
new file mode 100644
index 00000000..3528ec9d
--- /dev/null
+++ b/tests/view.urp
@@ -0,0 +1,5 @@
+debug
+database dbname=view
+sql view.sql
+
+view
diff --git a/tests/view.urs b/tests/view.urs
new file mode 100644
index 00000000..6ac44e0b
--- /dev/null
+++ b/tests/view.urs
@@ -0,0 +1 @@
+val main : unit -> transaction page
--
cgit v1.2.3
From 20d3fa9974879189544b752e43842a67c1fec0b9 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sat, 2 May 2009 13:37:52 -0400
Subject: allow/deny working in Mono_opt
---
src/compiler.sig | 4 +++-
src/compiler.sml | 45 ++++++++++++++++++++++++++++++++++++++++++++-
src/demo.sml | 4 +++-
src/mono_opt.sig | 3 ---
src/mono_opt.sml | 11 ++++-------
src/settings.sig | 7 +++++++
src/settings.sml | 34 ++++++++++++++++++++++++++++++++++
tests/url.urp | 1 +
8 files changed, 96 insertions(+), 13 deletions(-)
(limited to 'src/mono_opt.sml')
diff --git a/src/compiler.sig b/src/compiler.sig
index 048ca39f..276cb4f2 100644
--- a/src/compiler.sig
+++ b/src/compiler.sig
@@ -47,7 +47,9 @@ signature COMPILER = sig
clientOnly : Settings.ffi list,
serverOnly : Settings.ffi list,
jsFuncs : (Settings.ffi * string) list,
- rewrites : Settings.rewrite list
+ rewrites : Settings.rewrite list,
+ filterUrl : Settings.rule list,
+ filterMime : Settings.rule list
}
val compile : string -> unit
val compileC : {cname : string, oname : string, ename : string, libs : string,
diff --git a/src/compiler.sml b/src/compiler.sml
index 5a0a148a..66e8eda2 100644
--- a/src/compiler.sml
+++ b/src/compiler.sml
@@ -51,7 +51,9 @@ type job = {
clientOnly : Settings.ffi list,
serverOnly : Settings.ffi list,
jsFuncs : (Settings.ffi * string) list,
- rewrites : Settings.rewrite list
+ rewrites : Settings.rewrite list,
+ filterUrl : Settings.rule list,
+ filterMime : Settings.rule list
}
type ('src, 'dst) phase = {
@@ -314,6 +316,8 @@ fun parseUrp' filename =
val serverOnly = ref []
val jsFuncs = ref []
val rewrites = ref []
+ val url = ref []
+ val mime = ref []
val libs = ref []
fun finish sources =
@@ -337,6 +341,8 @@ fun parseUrp' filename =
serverOnly = rev (!serverOnly),
jsFuncs = rev (!jsFuncs),
rewrites = rev (!rewrites),
+ filterUrl = rev (!url),
+ filterMime = rev (!mime),
sources = sources
}
@@ -372,6 +378,8 @@ fun parseUrp' filename =
serverOnly = #serverOnly old @ #serverOnly new,
jsFuncs = #jsFuncs old @ #jsFuncs new,
rewrites = #rewrites old @ #rewrites new,
+ filterUrl = #filterUrl old @ #filterUrl new,
+ filterMime = #filterMime old @ #filterMime new,
sources = #sources old @ #sources new
}
in
@@ -397,6 +405,19 @@ fun parseUrp' filename =
else
(Settings.Exact, s)
+ fun parseFkind s =
+ case s of
+ "url" => url
+ | "mime" => mime
+ | _ => (ErrorMsg.error "Bad filter kind";
+ url)
+
+ fun parsePattern s =
+ if size s > 0 andalso String.sub (s, size s - 1) = #"*" then
+ (Settings.Prefix, String.substring (s, 0, size s - 1))
+ else
+ (Settings.Exact, s)
+
fun read () =
case TextIO.inputLine inf of
NONE => finish []
@@ -475,6 +496,26 @@ fun parseUrp' filename =
| [pkind, from] => doit (pkind, from, "")
| _ => ErrorMsg.error "Bad 'rewrite' syntax"
end
+ | "allow" =>
+ (case String.tokens Char.isSpace arg of
+ [fkind, pattern] =>
+ let
+ val fkind = parseFkind fkind
+ val (kind, pattern) = parsePattern pattern
+ in
+ fkind := {action = Settings.Allow, kind = kind, pattern = pattern} :: !fkind
+ end
+ | _ => ErrorMsg.error "Bad 'allow' syntax")
+ | "deny" =>
+ (case String.tokens Char.isSpace arg of
+ [fkind, pattern] =>
+ let
+ val fkind = parseFkind fkind
+ val (kind, pattern) = parsePattern pattern
+ in
+ fkind := {action = Settings.Deny, kind = kind, pattern = pattern} :: !fkind
+ end
+ | _ => ErrorMsg.error "Bad 'deny' syntax")
| "library" => libs := relify arg :: !libs
| _ => ErrorMsg.error ("Unrecognized command '" ^ cmd ^ "'");
read ()
@@ -493,6 +534,8 @@ fun parseUrp' filename =
Settings.setServerOnly (#serverOnly job);
Settings.setJsFuncs (#jsFuncs job);
Settings.setRewriteRules (#rewrites job);
+ Settings.setUrlRules (#filterUrl job);
+ Settings.setMimeRules (#filterMime job);
job
end
diff --git a/src/demo.sml b/src/demo.sml
index c08ce0fe..dc4715d7 100644
--- a/src/demo.sml
+++ b/src/demo.sml
@@ -104,7 +104,9 @@ fun make {prefix, dirname, guided} =
clientOnly = [],
serverOnly = [],
jsFuncs = [],
- rewrites = []
+ rewrites = [],
+ filterUrl = #filterUrl combined @ #filterUrl urp,
+ filterMime = #filterMime combined @ #filterMime urp
}
val parse = Compiler.run (Compiler.transform Compiler.parseUrp "Demo parseUrp")
diff --git a/src/mono_opt.sig b/src/mono_opt.sig
index 905dc53b..d0268087 100644
--- a/src/mono_opt.sig
+++ b/src/mono_opt.sig
@@ -30,7 +30,4 @@ signature MONO_OPT = sig
val optimize : Mono.file -> Mono.file
val optExp : Mono.exp -> Mono.exp
- val bless : (string -> bool) ref
- val blessMime : (string -> bool) ref
-
end
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index 41724eb0..fefe24e1 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -30,9 +30,6 @@ structure MonoOpt :> MONO_OPT = struct
open Mono
structure U = MonoUtil
-val bless = ref (fn _ : string => true)
-val blessMime = ref (CharVector.all (fn ch => Char.isAlphaNum ch orelse ch = #"-" orelse ch = #"/" orelse ch = #"."))
-
fun typ t = t
fun decl d = d
@@ -382,16 +379,16 @@ fun exp e =
| EJavaScript (_, _, SOME (e, _)) => e
| EFfiApp ("Basis", "bless", [(se as EPrim (Prim.String s), loc)]) =>
- (if !bless s then
+ (if Settings.checkUrl s then
()
else
- ErrorMsg.errorAt loc "Invalid URL passed to 'bless'";
+ ErrorMsg.errorAt loc ("Invalid URL " ^ s ^ " passed to 'bless'");
se)
| EFfiApp ("Basis", "blessMime", [(se as EPrim (Prim.String s), loc)]) =>
- (if !blessMime s then
+ (if Settings.checkMime s then
()
else
- ErrorMsg.errorAt loc "Invalid string passed to 'blessMime'";
+ ErrorMsg.errorAt loc ("Invalid string " ^ s ^ " passed to 'blessMime'");
se)
| EFfiApp ("Basis", "checkString", [(EPrim (Prim.String s), loc)]) =>
diff --git a/src/settings.sig b/src/settings.sig
index e5dd20d8..f750c14a 100644
--- a/src/settings.sig
+++ b/src/settings.sig
@@ -76,4 +76,11 @@ signature SETTINGS = sig
val setRewriteRules : rewrite list -> unit
val rewrite : path_kind -> string -> string
+ (* Validating URLs and MIME types *)
+ val setUrlRules : rule list -> unit
+ val checkUrl : string -> bool
+
+ val setMimeRules : rule list -> unit
+ val checkMime : string -> bool
+
end
diff --git a/src/settings.sml b/src/settings.sml
index 5e97f44b..e7020615 100644
--- a/src/settings.sml
+++ b/src/settings.sml
@@ -191,4 +191,38 @@ fun rewrite pk s =
rew (!rewrites)
end
+val url = ref ([] : rule list)
+val mime = ref ([] : rule list)
+
+fun setUrlRules ls = url := ls
+fun setMimeRules ls = mime := ls
+
+fun check f rules s =
+ let
+ fun chk (ls : rule list) =
+ case ls of
+ [] => false
+ | rule :: ls =>
+ let
+ val matches =
+ case #kind rule of
+ Exact => #pattern rule = s
+ | Prefix => String.isPrefix (#pattern rule) s
+ in
+ if matches then
+ case #action rule of
+ Allow => true
+ | Deny => false
+ else
+ chk ls
+ end
+ in
+ f s andalso chk (!rules)
+ end
+
+val checkUrl = check (fn _ => true) url
+val checkMime = check
+ (CharVector.all (fn ch => Char.isAlphaNum ch orelse ch = #"/" orelse ch = #"-" orelse ch = #"."))
+ mime
+
end
diff --git a/tests/url.urp b/tests/url.urp
index 3d4961ef..ab5ec1b7 100644
--- a/tests/url.urp
+++ b/tests/url.urp
@@ -1,3 +1,4 @@
debug
+allow url http://*
url
--
cgit v1.2.3
From 268a152731498e58f38da0a4f1dc5046ae2fbf3f Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sun, 17 May 2009 18:41:43 -0400
Subject: Redo Jscomp
---
src/cjrize.sml | 2 -
src/jscomp.sml | 374 +++++++++++++++++++++++++++++++++++++++-------------
src/mono.sml | 2 +-
src/mono_opt.sml | 2 -
src/mono_print.sml | 13 +-
src/mono_reduce.sml | 4 +-
src/mono_util.sml | 12 +-
src/monoize.sml | 22 ++--
8 files changed, 305 insertions(+), 126 deletions(-)
(limited to 'src/mono_opt.sml')
diff --git a/src/cjrize.sml b/src/cjrize.sml
index c4d916eb..5f3ea5a8 100644
--- a/src/cjrize.sml
+++ b/src/cjrize.sml
@@ -235,7 +235,6 @@ fun cifyPat ((p, loc), sm) =
((L'.PSome (t, p), loc), sm)
end
-
fun cifyExp (eAll as (e, loc), sm) =
case e of
L.EPrim p => ((L'.EPrim p, loc), sm)
@@ -470,7 +469,6 @@ 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"
diff --git a/src/jscomp.sml b/src/jscomp.sml
index 65a81ea8..4352693f 100644
--- a/src/jscomp.sml
+++ b/src/jscomp.sml
@@ -126,7 +126,7 @@ fun closedUpto d =
| EDml e => cu inner e
| ENextval e => cu inner e
| EUnurlify (e, _) => cu inner e
- | EJavaScript (_, e, _) => cu inner e
+ | EJavaScript (_, e) => cu inner e
| ESignalReturn e => cu inner e
| ESignalBind (e1, e2) => cu inner e1 andalso cu inner e2
| ESignalSource e => cu inner e
@@ -169,21 +169,8 @@ val compact =
U.Exp.RelE _ => inner+1
| _ => inner}
-val desourceify' =
- U.Exp.map {typ = fn t => t,
- exp = fn e =>
- case e of
- EJavaScript (_, e, _) => #1 e
- | _ => e}
-
-val desourceify =
- U.File.map {typ = fn t => t,
- exp = fn e =>
- case e of
- EJavaScript (m, e, eo) => EJavaScript (m, desourceify' e, eo)
- | _ => e,
- decl = fn d => d}
-
+exception CantEmbed of typ
+
fun process file =
let
val (someTs, nameds) =
@@ -387,9 +374,10 @@ fun process file =
((EApp ((ENamed n', loc), e), loc), st)
end)
- | _ => (EM.errorAt loc "Don't know how to embed type in JavaScript";
+ | _ => raise CantEmbed t
+ (*(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", st))
+ (str loc "ERROR", st))*)
fun unurlifyExp loc (t : typ, st) =
case #1 t of
@@ -773,14 +761,6 @@ fun process file =
end
| EFfiApp (m, x, args) =>
let
- val args =
- case (m, x, args) of
- ("Basis", "new_client_source", [(EJavaScript (_, e, _), _)]) =>
- (foundJavaScript := true; [e])
- | ("Basis", "set_client_source", [e1, (EJavaScript (_, e2, _), _)]) =>
- (foundJavaScript := true; [e1, e2])
- | _ => args
-
val name = case Settings.jsFunc (m, x) of
NONE => (EM.errorAt loc ("Unsupported FFI function "
^ x ^ " in JavaScript");
@@ -985,33 +965,27 @@ fun process file =
str ")"], st)
end
- | EJavaScript (Source _, _, SOME _) =>
+ | EJavaScript (Source _, e) =>
(foundJavaScript := true;
- (e, st))
- | EJavaScript (_, _, SOME e) =>
- (foundJavaScript := true;
- (strcat [str "cs(function(){return ",
- compact inner e,
- str "})"],
- st))
-
- | EClosure _ => unsupported "EClosure"
- | EQuery _ => unsupported "Query"
- | EDml _ => unsupported "DML"
- | ENextval _ => unsupported "Nextval"
- | EUnurlify _ => unsupported "EUnurlify"
- | EReturnBlob _ => unsupported "EUnurlify"
- | EJavaScript (_, e, _) =>
+ jsE inner (e, st))
+ | EJavaScript (_, e) =>
let
val (e, st) = jsE inner (e, st)
in
foundJavaScript := true;
(strcat [str "cs(function(){return ",
- e,
+ compact inner e,
str "})"],
st)
end
+ | EClosure _ => unsupported "EClosure"
+ | EQuery _ => unsupported "Query"
+ | EDml _ => unsupported "DML"
+ | ENextval _ => unsupported "Nextval"
+ | EUnurlify _ => unsupported "EUnurlify"
+ | EReturnBlob _ => unsupported "EUnurlify"
+
| ESignalReturn e =>
let
val (e, st) = jsE inner (e, st)
@@ -1094,56 +1068,274 @@ fun process file =
jsE
end
- val decl : state -> decl -> decl * state =
- U.Decl.foldMapB {typ = fn x => x,
- exp = fn (env, 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 _" ^ Int.toString (len + i) ^ ";"))
- val old = e
- val (e, st) = jsExp m env 0 (e, st)
- val e =
- case locals of
- [] => e
- | _ =>
- strcat (#2 e) (str "(function(){"
- :: locals
- @ [str "return ",
- e,
- str "}())"])
- in
- (*Print.prefaces "jsify" [("old", MonoPrint.p_exp MonoEnv.empty old),
- ("new", MonoPrint.p_exp MonoEnv.empty e)];*)
- (EJavaScript (m, old, SOME e), st)
- end
- in
- case e of
- (*EJavaScript (m as Source t, orig, NONE) =>
- let
- val loc = #2 orig
- val (e, st) = doCode m (t :: env) (ERel 0, loc)
- in
- (ELet ("x", t, orig, (e, loc)), st)
- end
- |*) EJavaScript (m, orig, NONE) =>
- (foundJavaScript := true;
- doCode m env orig)
- | _ => (e, st)
- end,
- decl = fn (_, e, st) => (e, st),
- bind = fn (env, U.Decl.RelE (_, t)) => t :: env
- | (env, _) => env}
- []
+
+ fun patBinds ((p, _), env) =
+ case p of
+ PWild => env
+ | PVar (_, t) => t :: env
+ | PPrim _ => env
+ | PCon (_, _, NONE) => env
+ | PCon (_, _, SOME p) => patBinds (p, env)
+ | PRecord xpts => foldl (fn ((_, p, _), env) => patBinds (p, env)) env xpts
+ | PNone _ => env
+ | PSome (_, p) => patBinds (p, env)
+
+ fun exp outer (e as (_, loc), st) =
+ ((*Print.preface ("exp", MonoPrint.p_exp MonoEnv.empty e);*)
+ case #1 e of
+ EPrim _ => (e, st)
+ | ERel _ => (e, st)
+ | ENamed _ => (e, st)
+ | ECon (_, _, NONE) => (e, st)
+ | ECon (dk, pc, SOME e) =>
+ let
+ val (e, st) = exp outer (e, st)
+ in
+ ((ECon (dk, pc, SOME e), loc), st)
+ end
+ | ENone _ => (e, st)
+ | ESome (t, e) =>
+ let
+ val (e, st) = exp outer (e, st)
+ in
+ ((ESome (t, e), loc), st)
+ end
+ | EFfi _ => (e, st)
+ | EFfiApp (m, x, es) =>
+ let
+ val (es, st) = ListUtil.foldlMap (exp outer) st es
+ in
+ ((EFfiApp (m, x, es), loc), st)
+ end
+ | EApp (e1, e2) =>
+ let
+ val (e1, st) = exp outer (e1, st)
+ val (e2, st) = exp outer (e2, st)
+ in
+ ((EApp (e1, e2), loc), st)
+ end
+ | EAbs (x, dom, ran, e) =>
+ let
+ val (e, st) = exp (dom :: outer) (e, st)
+ in
+ ((EAbs (x, dom, ran, e), loc), st)
+ end
+
+ | EUnop (s, e) =>
+ let
+ val (e, st) = exp outer (e, st)
+ in
+ ((EUnop (s, e), loc), st)
+ end
+ | EBinop (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)
+ end
+
+ | ERecord xets =>
+ let
+ val (xets, st) = ListUtil.foldlMap (fn ((x, e, t), st) =>
+ let
+ val (e, st) = exp outer (e, st)
+ in
+ ((x, e, t), st)
+ end) st xets
+ in
+ ((ERecord xets, loc), st)
+ end
+ | EField (e, s) =>
+ let
+ val (e, st) = exp outer (e, st)
+ in
+ ((EField (e, s), loc), st)
+ end
+
+ | ECase (e, pes, ts) =>
+ let
+ val (e, st) = exp outer (e, st)
+ val (pes, st) = ListUtil.foldlMap (fn ((p, e), st) =>
+ let
+ val (e, st) = exp (patBinds (p, outer)) (e, st)
+ in
+ ((p, e), st)
+ end) st pes
+ in
+ ((ECase (e, pes, ts), loc), st)
+ end
+
+ | EStrcat (e1, e2) =>
+ let
+ val (e1, st) = exp outer (e1, st)
+ val (e2, st) = exp outer (e2, st)
+ in
+ ((EStrcat (e1, e2), loc), st)
+ end
+
+ | EError (e, t) =>
+ let
+ val (e, st) = exp outer (e, st)
+ in
+ ((EError (e, t), loc), st)
+ end
+ | EReturnBlob {blob, mimeType, t} =>
+ let
+ val (blob, st) = exp outer (blob, st)
+ val (mimeType, st) = exp outer (mimeType, st)
+ in
+ ((EReturnBlob {blob = blob, mimeType = mimeType, t = t}, loc), st)
+ end
+
+ | EWrite e =>
+ let
+ val (e, st) = exp outer (e, st)
+ in
+ ((EWrite e, loc), st)
+ end
+ | ESeq (e1, e2) =>
+ let
+ val (e1, st) = exp outer (e1, st)
+ val (e2, st) = exp outer (e2, st)
+ in
+ ((ESeq (e1, e2), loc), st)
+ end
+ | ELet (x, t, e1, e2) =>
+ let
+ val (e1, st) = exp outer (e1, st)
+ val (e2, st) = exp (t :: outer) (e2, st)
+ in
+ ((ELet (x, t, e1, e2), loc), st)
+ end
+
+ | EClosure (n, es) =>
+ let
+ val (es, st) = ListUtil.foldlMap (exp outer) st es
+ in
+ ((EClosure (n, es), loc), st)
+ end
+
+ | EQuery {exps, tables, state, query, body, initial} =>
+ let
+ val (query, st) = exp outer (query, st)
+ val (body, st) = exp outer (body, st)
+ val (initial, st) = exp outer (initial, st)
+ in
+ ((EQuery {exps = exps, tables = tables, state = state,
+ query = query, body = body, initial = initial}, loc), st)
+ end
+ | EDml e =>
+ let
+ val (e, st) = exp outer (e, st)
+ in
+ ((EDml e, loc), st)
+ end
+ | ENextval e =>
+ let
+ val (e, st) = exp outer (e, st)
+ in
+ ((ENextval e, loc), st)
+ end
+
+ | EUnurlify (e, t) =>
+ let
+ val (e, st) = exp outer (e, st)
+ in
+ ((EUnurlify (e, t), loc), st)
+ end
+
+ | EJavaScript (m, e') =>
+ (let
+ val len = length outer
+ fun str s = (EPrim (Prim.String s), #2 e')
+
+ val locals = List.tabulate
+ (varDepth e',
+ fn i => str ("var _" ^ Int.toString (len + i) ^ ";"))
+
+ val (e', st) = jsExp m outer 0 (e', st)
+
+ val e' =
+ case locals of
+ [] => e'
+ | _ =>
+ strcat (#2 e') (str "(function(){"
+ :: locals
+ @ [str "return ",
+ e',
+ str "}())"])
+ in
+ (e', st)
+ end handle CantEmbed _ => (e, st))
+
+ | ESignalReturn e =>
+ let
+ val (e, st) = exp outer (e, st)
+ in
+ ((ESignalReturn e, loc), st)
+ end
+ | ESignalBind (e1, e2) =>
+ let
+ val (e1, st) = exp outer (e1, st)
+ val (e2, st) = exp outer (e2, st)
+ in
+ ((ESignalBind (e1, e2), loc), st)
+ end
+ | ESignalSource e =>
+ let
+ val (e, st) = exp outer (e, st)
+ in
+ ((ESignalSource e, loc), st)
+ end
+
+ | EServerCall (e1, e2, 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)
+ end
+ | ERecv (e1, e2, t) =>
+ let
+ val (e1, st) = exp outer (e1, st)
+ val (e2, st) = exp outer (e2, st)
+ in
+ ((ERecv (e1, e2, t), loc), st)
+ end
+ | ESleep (e1, e2) =>
+ let
+ val (e1, st) = exp outer (e1, st)
+ val (e2, st) = exp outer (e2, st)
+ in
+ ((ESleep (e1, e2), loc), st)
+ end)
+
+ fun decl (d as (_, loc), st) =
+ case #1 d of
+ DVal (x, n, t, e, s) =>
+ let
+ val (e, st) = exp [] (e, st)
+ in
+ ((DVal (x, n, t, e, s), loc), st)
+ end
+ | DValRec vis =>
+ let
+ val (vis, st) = ListUtil.foldlMap (fn ((x, n, t, e, s), st) =>
+ let
+ val (e, st) = exp [] (e, st)
+ in
+ ((x, n, t, e, s), st)
+ end) st vis
+ in
+ ((DValRec vis, loc), st)
+ end
+ | _ => (d, st)
fun doDecl (d, st) =
let
- val (d, st) = decl st d
+ (*val () = Print.preface ("doDecl", MonoPrint.p_decl MonoEnv.empty d)*)
+ val (d, st) = decl (d, st)
in
(List.revAppend (#decls st, [d]),
{decls = [],
@@ -1163,7 +1355,7 @@ fun process file =
listInjectors = TM.empty,
decoders = IM.empty,
maxName = U.File.maxName file + 1}
- (desourceify file)
+ file
val inf = TextIO.openIn (OS.Path.joinDirFile {dir = Config.libJs, file = "urweb.js"})
fun lines acc =
diff --git a/src/mono.sml b/src/mono.sml
index 52d24998..64ed448c 100644
--- a/src/mono.sml
+++ b/src/mono.sml
@@ -108,7 +108,7 @@ datatype exp' =
| EUnurlify of exp * typ
- | EJavaScript of javascript_mode * exp * exp option
+ | EJavaScript of javascript_mode * exp
| ESignalReturn of exp
| ESignalBind of exp * exp
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index fefe24e1..97ad1916 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -376,8 +376,6 @@ fun exp e =
| ESignalBind ((ESignalReturn e1, loc), e2) =>
optExp (EApp (e2, e1), loc)
- | EJavaScript (_, _, SOME (e, _)) => e
-
| EFfiApp ("Basis", "bless", [(se as EPrim (Prim.String s), loc)]) =>
(if Settings.checkUrl s then
()
diff --git a/src/mono_print.sml b/src/mono_print.sml
index 0395a063..ae11d3b8 100644
--- a/src/mono_print.sml
+++ b/src/mono_print.sml
@@ -310,13 +310,12 @@ fun p_exp' par env (e, _) =
| EUnurlify (e, _) => box [string "unurlify(",
p_exp env e,
string ")"]
- | EJavaScript (m, e, NONE) => box [string "JavaScript(",
- p_mode env m,
- string ",",
- space,
- p_exp env e,
- string ")"]
- | EJavaScript (_, _, SOME e) => p_exp env e
+ | EJavaScript (m, e) => box [string "JavaScript(",
+ p_mode env m,
+ string ",",
+ space,
+ p_exp env e,
+ string ")"]
| ESignalReturn e => box [string "Return(",
p_exp env e,
diff --git a/src/mono_reduce.sml b/src/mono_reduce.sml
index 77672acc..770aaa2e 100644
--- a/src/mono_reduce.sml
+++ b/src/mono_reduce.sml
@@ -74,7 +74,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
@@ -344,7 +344,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 83621c99..e2bed8eb 100644
--- a/src/mono_util.sml
+++ b/src/mono_util.sml
@@ -340,20 +340,12 @@ fun mapfoldB {typ = fc, exp = fe, bind} =
S.map2 (mft t,
fn t' =>
(EUnurlify (e', t'), loc)))
- | EJavaScript (m, e, NONE) =>
+ | EJavaScript (m, e) =>
S.bind2 (mfmode ctx m,
fn m' =>
S.map2 (mfe ctx e,
fn e' =>
- (EJavaScript (m', e', NONE), loc)))
- | EJavaScript (m, e, SOME e2) =>
- S.bind2 (mfmode ctx m,
- fn m' =>
- S.bind2 (mfe ctx e,
- fn e' =>
- S.map2 (mfe ctx e2,
- fn e2' =>
- (EJavaScript (m, e', SOME e2'), loc))))
+ (EJavaScript (m', e'), loc)))
| ESignalReturn e =>
S.map2 (mfe ctx e,
diff --git a/src/monoize.sml b/src/monoize.sml
index 8ced53bb..6c41de21 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -1173,7 +1173,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'.Source t, (L'.ERel 1, loc), NONE), loc)]),
+ [(L'.EJavaScript (L'.Source t, (L'.ERel 1, loc)), loc)]),
loc)), loc)),
loc),
fm)
@@ -1189,7 +1189,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L'.EFfiApp ("Basis", "set_client_source",
[(L'.ERel 2, loc),
(L'.EJavaScript (L'.Source t,
- (L'.ERel 1, loc), NONE), loc)]),
+ (L'.ERel 1, loc)), loc)]),
loc)), loc)), loc)), loc),
fm)
end
@@ -2410,7 +2410,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, NONE), loc),
+ (L'.EJavaScript (L'.Attribute, e), loc),
(L'.EPrim (Prim.String "'"), loc)), loc)),
loc)), loc),
fm)
@@ -2500,11 +2500,11 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(fn ("Source", _, _) => NONE
| ("Onchange", e, _) =>
SOME (strcat [str "addOnChange(d,",
- (L'.EJavaScript (L'.Script, e, NONE), loc),
+ (L'.EJavaScript (L'.Script, e), loc),
str ")"])
| (x, e, _) =>
SOME (strcat [str ("d." ^ lowercaseFirst x ^ "="),
- (L'.EJavaScript (L'.Script, e, NONE), loc),
+ (L'.EJavaScript (L'.Script, e), loc),
str ";"]))
attrs
in
@@ -2524,7 +2524,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
let
val e = (L'.EApp (e, (L'.ERecord [], loc)), loc)
in
- (L'.EJavaScript (L'.Attribute, e, NONE), loc)
+ (L'.EJavaScript (L'.Attribute, e), loc)
end
in
normal ("body",
@@ -2543,7 +2543,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
|*) [("Signal", e, _)] =>
((L'.EStrcat
((L'.EPrim (Prim.String ""), 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 e22b77776db9f846f5d0fae77dab5a57dfe7e0e8 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sun, 12 Jul 2009 15:05:40 -0400
Subject: MySQL demo/sql succeeds in reading no rows
---
include/urweb.h | 2 +
src/c/urweb.c | 35 ++++++
src/cjr_print.sml | 16 ++-
src/mono_opt.sml | 63 ++++++++--
src/monoize.sml | 14 ++-
src/mysql.sml | 360 ++++++++++++++++++++++++++++++++++++++++++++++++++----
src/postgres.sml | 35 ++++--
src/prepare.sml | 70 ++++++-----
src/settings.sig | 10 +-
src/settings.sml | 14 ++-
10 files changed, 521 insertions(+), 98 deletions(-)
(limited to 'src/mono_opt.sml')
diff --git a/include/urweb.h b/include/urweb.h
index b2cf55c7..c24550f7 100644
--- a/include/urweb.h
+++ b/include/urweb.h
@@ -205,4 +205,6 @@ void uw_check_heap(uw_context, size_t extra);
char *uw_heap_front(uw_context);
void uw_set_heap_front(uw_context, char*);
+uw_Basis_string uw_Basis_unAs(uw_context, uw_Basis_string);
+
#endif
diff --git a/src/c/urweb.c b/src/c/urweb.c
index f088e74d..4b92c2b4 100644
--- a/src/c/urweb.c
+++ b/src/c/urweb.c
@@ -2742,3 +2742,38 @@ __attribute__((noreturn)) void uw_return_blob(uw_context ctx, uw_Basis_blob b, u
longjmp(ctx->jmp_buf, RETURN_BLOB);
}
+
+uw_Basis_string uw_Basis_unAs(uw_context ctx, uw_Basis_string s) {
+ uw_Basis_string r = uw_malloc(ctx, strlen(s) + 1);
+
+ for (; *s; ++s) {
+ if (s[0] == '\'') {
+ *r++ = '\'';
+ for (++s; *s; ++s) {
+ if (s[0] == '\'') {
+ *r++ = '\'';
+ break;
+ } else if (s[0] == '\\') {
+ if (s[1] == '\\') {
+ *r++ = '\\';
+ *r++ = '\\';
+ ++s;
+ } else if (s[1] == '\'') {
+ *r++ = '\\';
+ *r++ = '\'';
+ ++s;
+ } else
+ *r++ = '\'';
+ } else
+ *r++ = s[0];
+ }
+ if (*s == 0) break;
+ } else if (s[0] == 'T' && s[1] == '.')
+ ++s;
+ else
+ *r++ = s[0];
+ }
+
+ return r;
+}
+
diff --git a/src/cjr_print.sml b/src/cjr_print.sml
index fcfa402e..13386f5b 100644
--- a/src/cjr_print.sml
+++ b/src/cjr_print.sml
@@ -2794,11 +2794,17 @@ fun p_sql env (ds, _) =
string s,
string "(",
p_list (fn (x, t) =>
- box [string "uw_",
- string (CharVector.map Char.toLower x),
- space,
- string (#p_sql_type (Settings.currentDbms ())
- (sql_type_in env t))]) xts,
+ let
+ val t = sql_type_in env t
+ in
+ box [string "uw_",
+ string (CharVector.map Char.toLower x),
+ space,
+ string (#p_sql_type (Settings.currentDbms ()) t),
+ case t of
+ Nullable _ => box []
+ | _ => string " NOT NULL"]
+ end) xts,
case (pk, csts) of
("", []) => box []
| _ => string ",",
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index 97ad1916..9288b820 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -83,18 +83,30 @@ val urlifyString = String.translate (fn #" " => "+"
"%" ^ hexIt ch)
-fun sqlifyInt n = attrifyInt n ^ "::int8"
-fun sqlifyFloat n = attrifyFloat n ^ "::float8"
-
-fun sqlifyString s = "E'" ^ String.translate (fn #"'" => "\\'"
- | #"\\" => "\\\\"
- | ch =>
- if Char.isPrint ch then
- str ch
- else
- "\\" ^ StringCvt.padLeft #"0" 3
- (Int.fmt StringCvt.OCT (ord ch)))
- (String.toString s) ^ "'::text"
+fun sqlifyInt n = attrifyInt n ^ "::" ^ #p_sql_type (Settings.currentDbms ()) Settings.Int
+fun sqlifyFloat n = attrifyFloat n ^ "::" ^ #p_sql_type (Settings.currentDbms ()) Settings.Float
+
+fun sqlifyString s = #sqlifyString (Settings.currentDbms ()) s
+
+fun unAs s =
+ let
+ fun doChars (cs, acc) =
+ case cs of
+ #"T" :: #"." :: cs => doChars (cs, acc)
+ | #"'" :: cs => doString (cs, acc)
+ | ch :: cs => doChars (cs, ch :: acc)
+ | [] => String.implode (rev acc)
+
+ and doString (cs, acc) =
+ case cs of
+ #"\\" :: #"\\" :: cs => doString (cs, #"\\" :: #"\\" :: acc)
+ | #"\\" :: #"'" :: cs => doString (cs, #"'" :: #"\\" :: acc)
+ | #"'" :: cs => doChars (cs, #"'" :: acc)
+ | ch :: cs => doString (cs, ch :: acc)
+ | [] => String.implode (rev acc)
+ in
+ doChars (String.explode s, [])
+ end
fun exp e =
case e of
@@ -442,6 +454,33 @@ fun exp e =
EPrim (Prim.String s)
end
+ | EFfiApp ("Basis", "unAs", [(EPrim (Prim.String s), _)]) =>
+ EPrim (Prim.String (unAs s))
+ | EFfiApp ("Basis", "unAs", [e']) =>
+ let
+ fun parts (e as (_, loc)) =
+ case #1 e of
+ EStrcat (s1, s2) =>
+ (case (parts s1, parts s2) of
+ (SOME p1, SOME p2) => SOME (p1 @ p2)
+ | _ => NONE)
+ | EPrim (Prim.String s) => SOME [(EPrim (Prim.String (unAs s)), loc)]
+ | EFfiApp ("Basis", f, [_]) =>
+ if String.isPrefix "sqlify" f then
+ SOME [e]
+ else
+ NONE
+ | _ => NONE
+ in
+ case parts e' of
+ SOME [e] => #1 e
+ | SOME es =>
+ (case rev es of
+ (e as (_, loc)) :: es => #1 (foldl (fn (e, es) => (EStrcat (e, es), loc)) e es)
+ | [] => raise Fail "MonoOpt impossible nil")
+ | NONE => e
+ end
+
| _ => e
and optExp e = #1 (U.Exp.map {typ = typ, exp = exp} e)
diff --git a/src/monoize.sml b/src/monoize.sml
index 91160e02..aab2226b 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -1604,10 +1604,16 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
in
((L'.EAbs ("tab", s, (L'.TFun (s, s), loc),
(L'.EAbs ("e", s, s,
- strcat [sc "DELETE FROM ",
- (L'.ERel 1, loc),
- sc " AS T WHERE ",
- (L'.ERel 0, loc)]), loc)), loc),
+ if #supportsDeleteAs (Settings.currentDbms ()) then
+ strcat [sc "DELETE FROM ",
+ (L'.ERel 1, loc),
+ sc " AS T WHERE ",
+ (L'.ERel 0, loc)]
+ else
+ strcat [sc "DELETE FROM ",
+ (L'.ERel 1, loc),
+ sc " WHERE ",
+ (L'.EFfiApp ("Basis", "unAs", [(L'.ERel 0, loc)]), loc)]), loc)), loc),
fm)
end
diff --git a/src/mysql.sml b/src/mysql.sml
index 2fcdef2d..ebcddc7f 100644
--- a/src/mysql.sml
+++ b/src/mysql.sml
@@ -55,6 +55,278 @@ fun p_buffer_type t =
| Client => "MYSQL_TYPE_LONG"
| Nullable t => p_buffer_type t
+fun p_sql_type_base t =
+ case t of
+ Int => "bigint"
+ | Float => "double"
+ | String => "longtext"
+ | Bool => "tinyint"
+ | Time => "timestamp"
+ | Blob => "longblob"
+ | Channel => "bigint"
+ | Client => "int"
+ | Nullable t => p_sql_type_base t
+
+val ident = String.translate (fn #"'" => "PRIME"
+ | ch => str ch)
+
+fun checkRel (table, checkNullable) (s, xts) =
+ let
+ val sl = CharVector.map Char.toLower s
+
+ val q = "SELECT COUNT(*) FROM information_schema." ^ table ^ " WHERE table_name = '"
+ ^ sl ^ "'"
+
+ val q' = String.concat ["SELECT COUNT(*) FROM information_schema.columns WHERE table_name = '",
+ sl,
+ "' AND (",
+ String.concatWith " OR "
+ (map (fn (x, t) =>
+ String.concat ["(column_name = 'uw_",
+ CharVector.map
+ Char.toLower (ident x),
+ "' AND data_type = '",
+ p_sql_type_base t,
+ "'",
+ if checkNullable then
+ (" AND is_nullable = '"
+ ^ (if isNotNull t then
+ "NO"
+ else
+ "YES")
+ ^ "'")
+ else
+ "",
+ ")"]) xts),
+ ")"]
+
+ val q'' = String.concat ["SELECT COUNT(*) FROM information_schema.columns WHERE table_name = '",
+ sl,
+ "' AND column_name LIKE 'uw_%'"]
+ in
+ box [string "if (mysql_query(conn->conn, \"",
+ string q,
+ string "\")) {",
+ newline,
+ box [string "mysql_close(conn->conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Query failed:\\n",
+ string q,
+ string "\");",
+ newline],
+ string "}",
+ newline,
+ newline,
+
+ string "if ((res = mysql_store_result(conn->conn)) == NULL) {",
+ newline,
+ box [string "mysql_free_result(res);",
+ newline,
+ string "mysql_close(conn->conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Result store failed:\\n",
+ string q,
+ string "\");",
+ newline],
+ string "}",
+ newline,
+ newline,
+
+ string "if (mysql_num_fields(res) != 1) {",
+ newline,
+ box [string "mysql_free_result(res);",
+ newline,
+ string "mysql_close(conn->conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Bad column count:\\n",
+ string q,
+ string "\");",
+ newline],
+ string "}",
+ newline,
+ newline,
+
+ string "if ((row = mysql_fetch_row(res)) == NULL) {",
+ newline,
+ box [string "mysql_free_result(res);",
+ newline,
+ string "mysql_close(conn->conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Row fetch failed:\\n",
+ string q,
+ string "\");",
+ newline],
+ string "}",
+ newline,
+ newline,
+
+ string "if (strcmp(row[0], \"1\")) {",
+ newline,
+ box [string "mysql_free_result(res);",
+ newline,
+ string "mysql_close(conn->conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Table '",
+ string s,
+ string "' does not exist.\");",
+ newline],
+ string "}",
+ newline,
+ newline,
+ string "mysql_free_result(res);",
+ newline,
+ newline,
+
+ string "if (mysql_query(conn->conn, \"",
+ string q',
+ string "\")) {",
+ newline,
+ box [string "mysql_close(conn->conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Query failed:\\n",
+ string q',
+ string "\");",
+ newline],
+ string "}",
+ newline,
+ newline,
+
+ string "if ((res = mysql_store_result(conn->conn)) == NULL) {",
+ newline,
+ box [string "mysql_free_result(res);",
+ newline,
+ string "mysql_close(conn->conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Result store failed:\\n",
+ string q',
+ string "\");",
+ newline],
+ string "}",
+ newline,
+ newline,
+
+ string "if (mysql_num_fields(res) != 1) {",
+ newline,
+ box [string "mysql_free_result(res);",
+ newline,
+ string "mysql_close(conn->conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Bad column count:\\n",
+ string q',
+ string "\");",
+ newline],
+ string "}",
+ newline,
+ newline,
+
+ string "if ((row = mysql_fetch_row(res)) == NULL) {",
+ newline,
+ box [string "mysql_free_result(res);",
+ newline,
+ string "mysql_close(conn->conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Row fetch failed:\\n",
+ string q',
+ string "\");",
+ newline],
+ string "}",
+ newline,
+ newline,
+
+ string "if (strcmp(row[0], \"",
+ string (Int.toString (length xts)),
+ string "\")) {",
+ newline,
+ box [string "mysql_free_result(res);",
+ newline,
+ string "mysql_close(conn->conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Table '",
+ string s,
+ string "' has the wrong column types.\");",
+ newline],
+ string "}",
+ newline,
+ newline,
+ string "mysql_free_result(res);",
+ newline,
+ newline,
+
+ string "if (mysql_query(conn->conn, \"",
+ string q'',
+ string "\")) {",
+ newline,
+ box [string "mysql_close(conn->conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Query failed:\\n",
+ string q'',
+ string "\");",
+ newline],
+ string "}",
+ newline,
+ newline,
+
+ string "if ((res = mysql_store_result(conn->conn)) == NULL) {",
+ newline,
+ box [string "mysql_free_result(res);",
+ newline,
+ string "mysql_close(conn->conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Result store failed:\\n",
+ string q'',
+ string "\");",
+ newline],
+ string "}",
+ newline,
+ newline,
+
+ string "if (mysql_num_fields(res) != 1) {",
+ newline,
+ box [string "mysql_free_result(res);",
+ newline,
+ string "mysql_close(conn->conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Bad column count:\\n",
+ string q'',
+ string "\");",
+ newline],
+ string "}",
+ newline,
+ newline,
+
+ string "if ((row = mysql_fetch_row(res)) == NULL) {",
+ newline,
+ box [string "mysql_free_result(res);",
+ newline,
+ string "mysql_close(conn->conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Row fetch failed:\\n",
+ string q'',
+ string "\");",
+ newline],
+ string "}",
+ newline,
+ newline,
+
+ string "if (strcmp(row[0], \"",
+ string (Int.toString (length xts)),
+ string "\")) {",
+ newline,
+ box [string "mysql_free_result(res);",
+ newline,
+ string "mysql_close(conn->conn);",
+ newline,
+ string "uw_error(ctx, FATAL, \"Table '",
+ string s,
+ string "' has extra columns.\");",
+ newline],
+ string "}",
+ newline,
+ newline,
+ string "mysql_free_result(res);",
+ newline]
+ end
+
fun init {dbstring, prepared = ss, tables, views, sequences} =
let
val host = ref NONE
@@ -102,8 +374,37 @@ fun init {dbstring, prepared = ss, tables, views, sequences} =
newline,
newline,
+ string "void uw_client_init(void) {",
+ newline,
+ box [string "if (mysql_library_init(0, NULL, NULL)) {",
+ newline,
+ box [string "fprintf(stderr, \"Could not initialize MySQL library\\n\");",
+ newline,
+ string "exit(1);",
+ newline],
+ string "}",
+ newline],
+ string "}",
+ newline,
+ newline,
+
if #persistent (currentProtocol ()) then
- box [string "static void uw_db_prepare(uw_context ctx) {",
+ box [string "static void uw_db_validate(uw_context ctx) {",
+ newline,
+ string "uw_conn *conn = uw_get_db(ctx);",
+ newline,
+ string "MYSQL_RES *res;",
+ newline,
+ string "MYSQL_ROW row;",
+ newline,
+ newline,
+ p_list_sep newline (checkRel ("tables", true)) tables,
+ p_list_sep newline (checkRel ("views", false)) views,
+ string "}",
+ newline,
+ newline,
+
+ string "static void uw_db_prepare(uw_context ctx) {",
newline,
string "uw_conn *conn = uw_get_db(ctx);",
newline,
@@ -147,6 +448,10 @@ fun init {dbstring, prepared = ss, tables, views, sequences} =
uhoh false "Out of memory allocating prepared statement" [],
string "}",
newline,
+ string "conn->p",
+ string (Int.toString i),
+ string " = stmt;",
+ newline,
string "if (mysql_stmt_prepare(stmt, \"",
string (String.toString s),
@@ -162,10 +467,6 @@ fun init {dbstring, prepared = ss, tables, views, sequences} =
newline,
uhoh true "Error preparing statement: %s" ["msg"]],
string "}",
- newline,
- string "conn->p",
- string (Int.toString i),
- string " = stmt;",
newline]
end)
ss,
@@ -199,7 +500,7 @@ fun init {dbstring, prepared = ss, tables, views, sequences} =
| SOME n => string (Int.toString n),
string ", ",
stringOf unix_socket,
- string ", 0)) {",
+ string ", 0) == NULL) {",
newline,
box [string "char msg[1024];",
newline,
@@ -214,7 +515,7 @@ fun init {dbstring, prepared = ss, tables, views, sequences} =
newline,
string "}",
newline,
- string "conn = calloc(1, sizeof(conn));",
+ string "conn = calloc(1, sizeof(uw_conn));",
newline,
string "conn->conn = mysql;",
newline,
@@ -471,19 +772,19 @@ fun queryCommon {loc, query, cols, doCols} =
string "if (mysql_stmt_execute(stmt)) uw_error(ctx, FATAL, \"",
string (ErrorMsg.spanToString loc),
- string ": Error executing query\");",
+ string ": Error executing query: %s\", mysql_error(conn->conn));",
newline,
newline,
string "if (mysql_stmt_store_result(stmt)) uw_error(ctx, FATAL, \"",
string (ErrorMsg.spanToString loc),
- string ": Error storing query result\");",
+ string ": Error storing query result: %s\", mysql_error(conn->conn));",
newline,
newline,
string "if (mysql_stmt_bind_result(stmt, out)) uw_error(ctx, FATAL, \"",
string (ErrorMsg.spanToString loc),
- string ": Error binding query result\");",
+ string ": Error binding query result: %s\", mysql_error(conn->conn));",
newline,
newline,
@@ -496,9 +797,9 @@ fun queryCommon {loc, query, cols, doCols} =
newline,
newline,
- string "if (r != MYSQL_NO_DATA) uw_error(ctx, FATAL, \"",
+ string "if (r == 1) uw_error(ctx, FATAL, \"",
string (ErrorMsg.spanToString loc),
- string ": query result fetching failed\");",
+ string ": query result fetching failed (%d): %s\", r, mysql_error(conn->conn));",
newline]
fun query {loc, cols, doCols} =
@@ -514,7 +815,7 @@ fun query {loc, cols, doCols} =
newline,
string "if (mysql_stmt_prepare(stmt, query, strlen(query))) uw_error(ctx, FATAL, \"",
string (ErrorMsg.spanToString loc),
- string "\");",
+ string ": error preparing statement: %s\", mysql_error(conn->conn));",
newline,
newline,
@@ -760,21 +1061,24 @@ fun dmlPrepared _ = box []
fun nextval _ = box []
fun nextvalPrepared _ = box []
+fun sqlifyString s = "CAST('" ^ String.translate (fn #"'" => "\\'"
+ | #"\\" => "\\\\"
+ | ch =>
+ if Char.isPrint ch then
+ str ch
+ else
+ (ErrorMsg.error
+ "Non-printing character found in SQL string literal";
+ ""))
+ (String.toString s) ^ "' AS longtext)"
+
+fun p_cast (s, t) = "CAST(" ^ s ^ " AS " ^ p_sql_type t ^ ")"
+
+fun p_blank _ = "?"
+
val () = addDbms {name = "mysql",
header = "mysql/mysql.h",
link = "-lmysqlclient",
- global_init = box [string "void uw_client_init() {",
- newline,
- box [string "if (mysql_library_init(0, NULL, NULL)) {",
- newline,
- box [string "fprintf(stderr, \"Could not initialize MySQL library\\n\");",
- newline,
- string "exit(1);",
- newline],
- string "}",
- newline],
- string "}",
- newline],
init = init,
p_sql_type = p_sql_type,
query = query,
@@ -782,6 +1086,10 @@ val () = addDbms {name = "mysql",
dml = dml,
dmlPrepared = dmlPrepared,
nextval = nextval,
- nextvalPrepared = nextvalPrepared}
+ nextvalPrepared = nextvalPrepared,
+ sqlifyString = sqlifyString,
+ p_cast = p_cast,
+ p_blank = p_blank,
+ supportsDeleteAs = false}
end
diff --git a/src/postgres.sml b/src/postgres.sml
index ca71798f..0b854efc 100644
--- a/src/postgres.sml
+++ b/src/postgres.sml
@@ -247,7 +247,11 @@ fun checkRel (table, checkNullable) (s, xts) =
fun init {dbstring, prepared = ss, tables, views, sequences} =
box [if #persistent (currentProtocol ()) then
- box [string "static void uw_db_validate(uw_context ctx) {",
+ box [string "void uw_client_init() { }",
+ newline,
+ newline,
+
+ string "static void uw_db_validate(uw_context ctx) {",
newline,
string "PGconn *conn = uw_get_db(ctx);",
newline,
@@ -509,10 +513,10 @@ fun p_getcol {wontLeakStrings, col = i, typ = t} =
String => getter t
| _ => box [string "({",
newline,
- string (p_sql_type t),
+ string (p_sql_ctype t),
space,
string "*tmp = uw_malloc(ctx, sizeof(",
- string (p_sql_type t),
+ string (p_sql_ctype t),
string "));",
newline,
string "*tmp = ",
@@ -528,7 +532,7 @@ fun p_getcol {wontLeakStrings, col = i, typ = t} =
string (Int.toString i),
string ") ? ",
box [string "({",
- string (p_sql_type t),
+ string (p_sql_ctype t),
space,
string "tmp;",
newline,
@@ -828,11 +832,23 @@ fun nextvalPrepared {loc, id, query} =
string (String.toString query),
string "\""]}]
+fun sqlifyString s = "E'" ^ String.translate (fn #"'" => "\\'"
+ | #"\\" => "\\\\"
+ | ch =>
+ if Char.isPrint ch then
+ str ch
+ else
+ "\\" ^ StringCvt.padLeft #"0" 3
+ (Int.fmt StringCvt.OCT (ord ch)))
+ (String.toString s) ^ "'::text"
+
+fun p_cast (s, t) = s ^ "::" ^ p_sql_type t
+
+fun p_blank (n, t) = p_cast ("$" ^ Int.toString n, t)
+
val () = addDbms {name = "postgres",
header = "postgresql/libpq-fe.h",
link = "-lpq",
- global_init = box [string "void uw_client_init() { }",
- newline],
p_sql_type = p_sql_type,
init = init,
query = query,
@@ -840,7 +856,12 @@ val () = addDbms {name = "postgres",
dml = dml,
dmlPrepared = dmlPrepared,
nextval = nextval,
- nextvalPrepared = nextvalPrepared}
+ nextvalPrepared = nextvalPrepared,
+ sqlifyString = sqlifyString,
+ p_cast = p_cast,
+ p_blank = p_blank,
+ supportsDeleteAs = true}
+
val () = setDbms "postgres"
end
diff --git a/src/prepare.sml b/src/prepare.sml
index 89a974db..0a8ca7a2 100644
--- a/src/prepare.sml
+++ b/src/prepare.sml
@@ -28,47 +28,45 @@
structure Prepare :> PREPARE = struct
open Cjr
+open Settings
fun prepString (e, ss, n) =
- case #1 e of
- EPrim (Prim.String s) =>
- SOME (s :: ss, n)
- | EFfiApp ("Basis", "strcat", [e1, e2]) =>
- (case prepString (e1, ss, n) of
- NONE => NONE
- | SOME (ss, n) => prepString (e2, ss, n))
- | EFfiApp ("Basis", "sqlifyInt", [e]) =>
- SOME ("$" ^ Int.toString (n + 1) ^ "::int8" :: ss, n + 1)
- | EFfiApp ("Basis", "sqlifyFloat", [e]) =>
- SOME ("$" ^ Int.toString (n + 1) ^ "::float8" :: ss, n + 1)
- | EFfiApp ("Basis", "sqlifyString", [e]) =>
- SOME ("$" ^ Int.toString (n + 1) ^ "::text" :: ss, n + 1)
- | EFfiApp ("Basis", "sqlifyBool", [e]) =>
- SOME ("$" ^ Int.toString (n + 1) ^ "::bool" :: ss, n + 1)
- | EFfiApp ("Basis", "sqlifyTime", [e]) =>
- SOME ("$" ^ Int.toString (n + 1) ^ "::timestamp" :: ss, n + 1)
- | EFfiApp ("Basis", "sqlifyBlob", [e]) =>
- SOME ("$" ^ Int.toString (n + 1) ^ "::bytea" :: ss, n + 1)
- | EFfiApp ("Basis", "sqlifyChannel", [e]) =>
- SOME ("$" ^ Int.toString (n + 1) ^ "::int8" :: ss, n + 1)
- | EFfiApp ("Basis", "sqlifyClient", [e]) =>
- SOME ("$" ^ Int.toString (n + 1) ^ "::int4" :: ss, n + 1)
+ let
+ fun doOne t =
+ SOME (#p_blank (Settings.currentDbms ()) (n + 1, t) :: ss, n + 1)
+ in
+ case #1 e of
+ EPrim (Prim.String s) =>
+ SOME (s :: ss, n)
+ | 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
- | ECase (e,
- [((PNone _, _),
- (EPrim (Prim.String "NULL"), _)),
- ((PSome (_, (PVar _, _)), _),
- (EFfiApp (m, x, [(ERel 0, _)]), _))],
- _) => prepString ((EFfiApp (m, x, [e]), #2 e), ss, n)
+ | ECase (e,
+ [((PNone _, _),
+ (EPrim (Prim.String "NULL"), _)),
+ ((PSome (_, (PVar _, _)), _),
+ (EFfiApp (m, x, [(ERel 0, _)]), _))],
+ _) => prepString ((EFfiApp (m, x, [e]), #2 e), ss, n)
- | ECase (e,
- [((PCon (_, PConFfi {mod = "Basis", con = "True", ...}, _), _),
- (EPrim (Prim.String "TRUE"), _)),
- ((PCon (_, PConFfi {mod = "Basis", con = "False", ...}, _), _),
- (EPrim (Prim.String "FALSE"), _))],
- _) => SOME ("$" ^ Int.toString (n + 1) ^ "::bool" :: ss, n + 1)
+ | ECase (e,
+ [((PCon (_, PConFfi {mod = "Basis", con = "True", ...}, _), _),
+ (EPrim (Prim.String "TRUE"), _)),
+ ((PCon (_, PConFfi {mod = "Basis", con = "False", ...}, _), _),
+ (EPrim (Prim.String "FALSE"), _))],
+ _) => doOne Bool
- | _ => NONE
+ | _ => NONE
+ end
fun prepExp (e as (_, loc), sns) =
case #1 e of
diff --git a/src/settings.sig b/src/settings.sig
index 14e6338d..bfbc1f82 100644
--- a/src/settings.sig
+++ b/src/settings.sig
@@ -123,15 +123,13 @@ signature SETTINGS = sig
(* Include this C header file *)
link : string,
(* Pass these linker arguments *)
- global_init : Print.PD.pp_desc,
- (* Define uw_client_init() *)
p_sql_type : sql_type -> string,
init : {dbstring : string,
prepared : (string * int) list,
tables : (string * (string * sql_type) list) list,
views : (string * (string * sql_type) list) list,
sequences : string list} -> Print.PD.pp_desc,
- (* Define uw_db_init(), uw_db_close(), uw_db_begin(), uw_db_commit(), and uw_db_rollback() *)
+ (* Define uw_client_init(), uw_db_init(), uw_db_close(), uw_db_begin(), uw_db_commit(), and uw_db_rollback() *)
query : {loc : ErrorMsg.span, cols : sql_type list,
doCols : ({wontLeakStrings : bool, col : int, typ : sql_type} -> Print.PD.pp_desc)
-> Print.PD.pp_desc}
@@ -145,7 +143,11 @@ signature SETTINGS = sig
dmlPrepared : {loc : ErrorMsg.span, id : int, dml : string,
inputs : sql_type list} -> Print.PD.pp_desc,
nextval : ErrorMsg.span -> Print.PD.pp_desc,
- nextvalPrepared : {loc : ErrorMsg.span, id : int, query : string} -> Print.PD.pp_desc
+ nextvalPrepared : {loc : ErrorMsg.span, id : int, query : string} -> Print.PD.pp_desc,
+ sqlifyString : string -> string,
+ p_cast : string * sql_type -> string,
+ p_blank : int * sql_type -> string (* Prepared statement input *),
+ supportsDeleteAs : bool
}
val addDbms : dbms -> unit
diff --git a/src/settings.sml b/src/settings.sml
index f2c2461d..32ab8bcd 100644
--- a/src/settings.sml
+++ b/src/settings.sml
@@ -314,7 +314,6 @@ type dbms = {
name : string,
header : string,
link : string,
- global_init : Print.PD.pp_desc,
p_sql_type : sql_type -> string,
init : {dbstring : string,
prepared : (string * int) list,
@@ -334,14 +333,17 @@ type dbms = {
dmlPrepared : {loc : ErrorMsg.span, id : int, dml : string,
inputs : sql_type list} -> Print.PD.pp_desc,
nextval : ErrorMsg.span -> Print.PD.pp_desc,
- nextvalPrepared : {loc : ErrorMsg.span, id : int, query : string} -> Print.PD.pp_desc
+ nextvalPrepared : {loc : ErrorMsg.span, id : int, query : string} -> Print.PD.pp_desc,
+ sqlifyString : string -> string,
+ p_cast : string * sql_type -> string,
+ p_blank : int * sql_type -> string,
+ supportsDeleteAs : bool
}
val dbmses = ref ([] : dbms list)
val curDb = ref ({name = "",
header = "",
link = "",
- global_init = Print.box [],
p_sql_type = fn _ => "",
init = fn _ => Print.box [],
query = fn _ => Print.box [],
@@ -349,7 +351,11 @@ val curDb = ref ({name = "",
dml = fn _ => Print.box [],
dmlPrepared = fn _ => Print.box [],
nextval = fn _ => Print.box [],
- nextvalPrepared = fn _ => Print.box []} : dbms)
+ nextvalPrepared = fn _ => Print.box [],
+ sqlifyString = fn s => s,
+ p_cast = fn _ => "",
+ p_blank = fn _ => "",
+ supportsDeleteAs = false} : dbms)
fun addDbms v = dbmses := v :: !dbmses
fun setDbms s =
--
cgit v1.2.3
From 7e10920b75383cd953898468385ae29e76bf184d Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Thu, 16 Jul 2009 13:59:30 -0400
Subject: MySQL accepts generated demo DDL
---
src/cjr_print.sml | 3 +--
src/mono_opt.sml | 4 ++--
src/monoize.sml | 46 ++++++++++++++++++++++++++++++++++------------
src/mysql.sml | 28 +++++++++++++++-------------
src/postgres.sml | 4 +++-
src/settings.sig | 4 +++-
src/settings.sml | 8 ++++++--
7 files changed, 64 insertions(+), 33 deletions(-)
(limited to 'src/mono_opt.sml')
diff --git a/src/cjr_print.sml b/src/cjr_print.sml
index 13386f5b..835faad5 100644
--- a/src/cjr_print.sml
+++ b/src/cjr_print.sml
@@ -2836,8 +2836,7 @@ fun p_sql env (ds, _) =
newline,
newline]
| DSequence s =>
- box [string "CREATE SEQUENCE ",
- string s,
+ box [string (#createSequence (Settings.currentDbms ()) s),
string ";",
newline,
newline]
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index 9288b820..bf39b311 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -83,8 +83,8 @@ val urlifyString = String.translate (fn #" " => "+"
"%" ^ hexIt ch)
-fun sqlifyInt n = attrifyInt n ^ "::" ^ #p_sql_type (Settings.currentDbms ()) Settings.Int
-fun sqlifyFloat n = attrifyFloat n ^ "::" ^ #p_sql_type (Settings.currentDbms ()) Settings.Float
+fun sqlifyInt n = #p_cast (Settings.currentDbms ()) (attrifyInt n, Settings.Int)
+fun sqlifyFloat n = #p_cast (Settings.currentDbms ()) (attrifyFloat n, Settings.Float)
fun sqlifyString s = #sqlifyString (Settings.currentDbms ()) s
diff --git a/src/monoize.sml b/src/monoize.sml
index aab2226b..2e9886dd 100644
--- a/src/monoize.sml
+++ b/src/monoize.sml
@@ -65,6 +65,12 @@ fun monoName env (all as (c, loc)) =
| _ => poly ()
end
+fun lowercaseFirst "" = ""
+ | lowercaseFirst s = String.str (Char.toLower (String.sub (s, 0)))
+ ^ String.extract (s, 1, NONE)
+
+fun monoNameLc env c = lowercaseFirst (monoName env c)
+
fun readType' (t, loc) = (L'.TFun ((L'.TFfi ("Basis", "string"), loc),
(L'.TOption t, loc)), loc)
fun readErrType (t, loc) = (L'.TFun ((L'.TFfi ("Basis", "string"), loc),
@@ -630,6 +636,12 @@ fun strcatR loc e xs = strcatComma loc (map (fn (x, _) => (L'.EField (e, x), loc
val readCookie = ref IS.empty
+fun isBlobby (t : L.con) =
+ case #1 t of
+ L.CFfi ("Basis", "string") => true
+ | L.CFfi ("Basis", "blob") => true
+ | _ => false
+
fun monoExp (env, st, fm) (all as (e, loc)) =
let
val strcat = strcat loc
@@ -1368,7 +1380,13 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
((L'.EAbs ("_", witnesses, (L'.TFfi ("Basis", "string"), loc),
(L'.EPrim (Prim.String
(String.concatWith ", "
- (map (fn (x, _) => "uw_" ^ monoName env x) unique))),
+ (map (fn (x, _) =>
+ "uw_" ^ monoNameLc env x
+ ^ (if #textKeysNeedLengths (Settings.currentDbms ())
+ andalso isBlobby t then
+ "(767)"
+ else
+ "")) unique))),
loc)), loc),
fm)
end
@@ -1406,7 +1424,13 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
val unique = (nm, t) :: unique
in
((L'.EPrim (Prim.String ("UNIQUE ("
- ^ String.concatWith ", " (map (fn (x, _) => "uw_" ^ monoName env x) unique)
+ ^ String.concatWith ", "
+ (map (fn (x, t) => "uw_" ^ monoNameLc env x
+ ^ (if #textKeysNeedLengths (Settings.currentDbms ())
+ andalso isBlobby t then
+ "(767)"
+ else
+ "")) unique)
^ ")")), loc),
fm)
end
@@ -1447,18 +1471,20 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
(L'.EAbs ("m", mat, mat,
(L'.ECase ((L'.EField ((L'.ERel 0, loc), "1"), loc),
[((L'.PPrim (Prim.String ""), loc),
- (L'.ERecord [("1", (L'.EPrim (Prim.String ("uw_" ^ nm1)),
+ (L'.ERecord [("1", (L'.EPrim (Prim.String ("uw_" ^ lowercaseFirst nm1)),
loc), string),
- ("2", (L'.EPrim (Prim.String ("uw_" ^ nm2)),
+ ("2", (L'.EPrim (Prim.String ("uw_" ^ lowercaseFirst nm2)),
loc), string)], loc)),
((L'.PWild, loc),
(L'.ERecord [("1", (L'.EStrcat (
- (L'.EPrim (Prim.String ("uw_" ^ nm1 ^ ", ")),
+ (L'.EPrim (Prim.String ("uw_" ^ lowercaseFirst nm1
+ ^ ", ")),
loc),
(L'.EField ((L'.ERel 0, loc), "1"), loc)),
loc), string),
("2", (L'.EStrcat (
- (L'.EPrim (Prim.String ("uw_" ^ nm2 ^ ", ")), loc),
+ (L'.EPrim (Prim.String ("uw_" ^ lowercaseFirst nm2
+ ^ ", ")), loc),
(L'.EField ((L'.ERel 0, loc), "2"), loc)),
loc), string)],
loc))],
@@ -2146,7 +2172,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
_), _),
_), _),
(L.CName tab, _)), _),
- (L.CName field, _)) => ((L'.EPrim (Prim.String (tab ^ ".uw_" ^ field)), loc), fm)
+ (L.CName field, _)) => ((L'.EPrim (Prim.String (tab ^ ".uw_" ^ lowercaseFirst field)), loc), fm)
| L.ECApp (
(L.ECApp (
@@ -2158,7 +2184,7 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
_), _),
_), _),
_), _),
- (L.CName nm, _)) => ((L'.EPrim (Prim.String ("_" ^ nm)), loc), fm)
+ (L.CName nm, _)) => ((L'.EPrim (Prim.String ("_" ^ lowercaseFirst nm)), loc), fm)
| L.ECApp (
(L.ECApp (
@@ -2412,10 +2438,6 @@ fun monoExp (env, st, fm) (all as (e, loc)) =
val (onload, attrs) = findOnload (attrs, [])
- fun lowercaseFirst "" = ""
- | lowercaseFirst s = String.str (Char.toLower (String.sub (s, 0)))
- ^ String.extract (s, 1, NONE)
-
val (class, fm) = monoExp (env, st, fm) class
fun tagStart tag =
diff --git a/src/mysql.sml b/src/mysql.sml
index bada72ed..d8847424 100644
--- a/src/mysql.sml
+++ b/src/mysql.sml
@@ -1283,18 +1283,18 @@ fun dmlPrepared {loc, id, dml, inputs} =
fun nextval _ = box []
fun nextvalPrepared _ = box []
-fun sqlifyString s = "CAST('" ^ String.translate (fn #"'" => "\\'"
- | #"\\" => "\\\\"
- | ch =>
- if Char.isPrint ch then
- str ch
- else
- (ErrorMsg.error
- "Non-printing character found in SQL string literal";
- ""))
- (String.toString s) ^ "' AS longtext)"
-
-fun p_cast (s, t) = "CAST(" ^ s ^ " AS " ^ p_sql_type t ^ ")"
+fun sqlifyString s = "'" ^ String.translate (fn #"'" => "\\'"
+ | #"\\" => "\\\\"
+ | ch =>
+ if Char.isPrint ch then
+ str ch
+ else
+ (ErrorMsg.error
+ "Non-printing character found in SQL string literal";
+ ""))
+ (String.toString s) ^ "'"
+
+fun p_cast (s, _) = s
fun p_blank _ = "?"
@@ -1312,6 +1312,8 @@ val () = addDbms {name = "mysql",
sqlifyString = sqlifyString,
p_cast = p_cast,
p_blank = p_blank,
- supportsDeleteAs = false}
+ supportsDeleteAs = false,
+ createSequence = fn s => "CREATE TABLE " ^ s ^ " (id INTEGER PRIMARY KEY AUTO_INCREMENT)",
+ textKeysNeedLengths = true}
end
diff --git a/src/postgres.sml b/src/postgres.sml
index 7096a5cf..26825363 100644
--- a/src/postgres.sml
+++ b/src/postgres.sml
@@ -860,7 +860,9 @@ val () = addDbms {name = "postgres",
sqlifyString = sqlifyString,
p_cast = p_cast,
p_blank = p_blank,
- supportsDeleteAs = true}
+ supportsDeleteAs = true,
+ createSequence = fn s => "CREATE SEQUENCE " ^ s,
+ textKeysNeedLengths = false}
val () = setDbms "postgres"
diff --git a/src/settings.sig b/src/settings.sig
index bfbc1f82..873bbcb9 100644
--- a/src/settings.sig
+++ b/src/settings.sig
@@ -147,7 +147,9 @@ signature SETTINGS = sig
sqlifyString : string -> string,
p_cast : string * sql_type -> string,
p_blank : int * sql_type -> string (* Prepared statement input *),
- supportsDeleteAs : bool
+ supportsDeleteAs : bool,
+ createSequence : string -> string,
+ textKeysNeedLengths : bool
}
val addDbms : dbms -> unit
diff --git a/src/settings.sml b/src/settings.sml
index 32ab8bcd..99fa748d 100644
--- a/src/settings.sml
+++ b/src/settings.sml
@@ -337,7 +337,9 @@ type dbms = {
sqlifyString : string -> string,
p_cast : string * sql_type -> string,
p_blank : int * sql_type -> string,
- supportsDeleteAs : bool
+ supportsDeleteAs : bool,
+ createSequence : string -> string,
+ textKeysNeedLengths : bool
}
val dbmses = ref ([] : dbms list)
@@ -355,7 +357,9 @@ val curDb = ref ({name = "",
sqlifyString = fn s => s,
p_cast = fn _ => "",
p_blank = fn _ => "",
- supportsDeleteAs = false} : dbms)
+ supportsDeleteAs = false,
+ createSequence = fn _ => "",
+ textKeysNeedLengths = false} : dbms)
fun addDbms v = dbmses := v :: !dbmses
fun setDbms s =
--
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_opt.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_opt.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 4d9fd106dfcd09caedacfbd14f4c76597cc4c5a4 Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Sat, 12 Sep 2009 09:31:50 -0400
Subject: Change string URLification to avoid using the empty string, which
confuses Apache no2slash()
---
lib/js/urweb.js | 7 ++++++-
src/c/urweb.c | 27 ++++++++++++++++++++++++---
src/mono_opt.sml | 18 +++++++++++++-----
3 files changed, 43 insertions(+), 9 deletions(-)
(limited to 'src/mono_opt.sml')
diff --git a/lib/js/urweb.js b/lib/js/urweb.js
index 251f64ba..7349d2bf 100644
--- a/lib/js/urweb.js
+++ b/lib/js/urweb.js
@@ -464,10 +464,15 @@ function pflo(s) {
}
function uf(s) {
- return escape(s).replace(new RegExp ("/", "g"), "%2F").replace(new RegExp ("\\+", "g"), "%2B");
+ if (s.length == 0)
+ return "_";
+ return (s[0] == '_' ? "_" : "")
+ + escape(s).replace(new RegExp ("/", "g"), "%2F").replace(new RegExp ("\\+", "g"), "%2B");
}
function uu(s) {
+ if (s.length > 0 && s[0] == '_')
+ s = s.substring(1);
return unescape(s.replace(new RegExp ("\\+", "g"), " "));
}
diff --git a/src/c/urweb.c b/src/c/urweb.c
index 774c5797..d5005af2 100644
--- a/src/c/urweb.c
+++ b/src/c/urweb.c
@@ -1479,9 +1479,16 @@ char *uw_Basis_urlifyFloat(uw_context ctx, uw_Basis_float n) {
char *uw_Basis_urlifyString(uw_context ctx, uw_Basis_string s) {
char *r, *p;
- uw_check_heap(ctx, strlen(s) * 3 + 1);
+ if (s[0] == '\0')
+ return "_";
- for (r = p = ctx->heap.front; *s; s++) {
+ uw_check_heap(ctx, strlen(s) * 3 + 1 + !!(s[0] == '_'));
+
+ r = p = ctx->heap.front;
+ if (s[0] == '_')
+ *p++ = '_';
+
+ for (; *s; s++) {
char c = *s;
if (c == ' ')
@@ -1547,7 +1554,16 @@ uw_Basis_string uw_Basis_urlifyTime(uw_context ctx, uw_Basis_time t) {
}
uw_unit uw_Basis_urlifyString_w(uw_context ctx, uw_Basis_string s) {
- uw_check(ctx, strlen(s) * 3);
+ if (s[0] == '\0') {
+ uw_check(ctx, 1);
+ uw_writec_unsafe(ctx, '_');
+ return uw_unit_v;
+ }
+
+ uw_check(ctx, strlen(s) * 3 + !!(s[0] == '_'));
+
+ if (s[0] == '_')
+ uw_writec_unsafe(ctx, '_');
for (; *s; s++) {
char c = *s;
@@ -1612,6 +1628,11 @@ static uw_Basis_string uw_unurlifyString_to(uw_context ctx, char *r, char *s) {
char *s1, *s2;
int n;
+ if (*s2 == '_')
+ ++s2;
+ else if (s2[0] == '%' && s2[1] == '5' && (s2[2] == 'f' || s2[2] == 'F'))
+ s2 += 3;
+
for (s1 = r, s2 = s; *s2; ++s1, ++s2) {
char c = *s2;
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index bf39b311..dd04a838 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -76,11 +76,19 @@ fun hexIt ch =
| _ => s
end
-val urlifyString = String.translate (fn #" " => "+"
- | ch => if Char.isAlphaNum ch then
- str ch
- else
- "%" ^ hexIt ch)
+fun urlifyString s =
+ case s of
+ "" => "_"
+ | _ =>
+ (if String.sub (s, 0) = #"_" then
+ "_"
+ else
+ "")
+ ^ String.translate (fn #" " => "+"
+ | ch => if Char.isAlphaNum ch then
+ str ch
+ else
+ "%" ^ hexIt ch) s
fun sqlifyInt n = #p_cast (Settings.currentDbms ()) (attrifyInt n, Settings.Int)
--
cgit v1.2.3
From 84b3615abace2bd06c76e5d0ec6c5a8abe23a4de Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Mon, 12 Oct 2009 18:16:42 -0400
Subject: Fix some MySQL hijinks
---
src/mono_opt.sml | 2 +-
src/mysql.sml | 22 ++++++++++++----------
2 files changed, 13 insertions(+), 11 deletions(-)
(limited to 'src/mono_opt.sml')
diff --git a/src/mono_opt.sml b/src/mono_opt.sml
index dd04a838..9b9308be 100644
--- a/src/mono_opt.sml
+++ b/src/mono_opt.sml
@@ -100,7 +100,7 @@ fun unAs s =
let
fun doChars (cs, acc) =
case cs of
- #"T" :: #"." :: cs => doChars (cs, acc)
+ #"T" :: #"_" :: #"T" :: #"." :: cs => doChars (cs, acc)
| #"'" :: cs => doString (cs, acc)
| ch :: cs => doChars (cs, ch :: acc)
| [] => String.implode (rev acc)
diff --git a/src/mysql.sml b/src/mysql.sml
index eba125c7..2941186c 100644
--- a/src/mysql.sml
+++ b/src/mysql.sml
@@ -73,19 +73,21 @@ val ident = String.translate (fn #"'" => "PRIME"
fun checkRel (table, checkNullable) (s, xts) =
let
val sl = CharVector.map Char.toLower s
+ val both = "table_name IN ('" ^ sl ^ "', '" ^ s ^ "')"
- val q = "SELECT COUNT(*) FROM information_schema." ^ table ^ " WHERE table_name = '"
- ^ sl ^ "'"
+ val q = "SELECT COUNT(*) FROM information_schema." ^ table ^ " WHERE " ^ both
- val q' = String.concat ["SELECT COUNT(*) FROM information_schema.columns WHERE table_name = '",
- sl,
- "' AND (",
+ val q' = String.concat ["SELECT COUNT(*) FROM information_schema.columns WHERE ",
+ both,
+ " AND (",
String.concatWith " OR "
(map (fn (x, t) =>
- String.concat ["(column_name = 'uw_",
+ String.concat ["(column_name IN ('uw_",
CharVector.map
Char.toLower (ident x),
- "' AND data_type = '",
+ "', 'uw_",
+ ident x,
+ "') AND data_type = '",
p_sql_type_base t,
"'",
if checkNullable then
@@ -100,9 +102,9 @@ fun checkRel (table, checkNullable) (s, xts) =
")"]) xts),
")"]
- val q'' = String.concat ["SELECT COUNT(*) FROM information_schema.columns WHERE table_name = '",
- sl,
- "' AND column_name LIKE 'uw_%'"]
+ val q'' = String.concat ["SELECT COUNT(*) FROM information_schema.columns WHERE ",
+ both,
+ " AND column_name LIKE 'uw_%'"]
in
box [string "if (mysql_query(conn->conn, \"",
string q,
--
cgit v1.2.3
From 7e1e019f3fef4c229c06ba2c0c2aa3ec021eedad Mon Sep 17 00:00:00 2001
From: Adam Chlipala
Date: Thu, 22 Oct 2009 16:15:56 -0400
Subject: Initial support for char in SQL
---
demo/more/conference.ur | 26 ++++++++++++-
demo/more/conference.urp | 1 +
demo/more/conference.urs | 1 +
demo/more/conference1.ur | 2 +-
demo/more/conferenceFields.ur | 19 +++++++++
demo/more/conferenceFields.urs | 3 ++
demo/more/meta.ur | 12 ++++++
demo/more/meta.urs | 3 ++
include/urweb.h | 4 ++
lib/ur/basis.urs | 1 +
src/c/urweb.c | 87 ++++++++++++++++++++++++++++++++++++++++++
src/cjr_print.sml | 16 +-------
src/mono_opt.sml | 26 ++++++++++---
src/monoize.sml | 4 ++
src/mysql.sml | 5 +++
src/postgres.sml | 6 +++
src/settings.sig | 1 +
src/settings.sml | 2 +
src/sqlite.sml | 9 +++++
19 files changed, 206 insertions(+), 22 deletions(-)
(limited to 'src/mono_opt.sml')
diff --git a/demo/more/conference.ur b/demo/more/conference.ur
index 8e408d2f..72750248 100644
--- a/demo/more/conference.ur
+++ b/demo/more/conference.ur
@@ -9,6 +9,7 @@ functor Make(M : sig
con review :: {(Type * Type)}
constraint [Paper, User] ~ review
val review : $(map meta review)
+ val reviewFolder : folder review
val submissionDeadline : time
val summarizePaper : $(map fst paper) -> xbody
@@ -26,7 +27,7 @@ functor Make(M : sig
table authorship : {Paper : int, User : int}
PRIMARY KEY (Paper, User),
- CONSTRAINT Paper FOREIGN KEY Paper REFERENCES paper(Id),
+ CONSTRAINT Paper FOREIGN KEY Paper REFERENCES paper(Id) ON DELETE CASCADE,
CONSTRAINT User FOREIGN KEY User REFERENCES user(Id)
con review = [Paper = int, User = int] ++ map fst M.review
@@ -249,6 +250,7 @@ functor Make(M : sig