changeset 693:655bcc9b77e0

_Really_ implement embedded closure GC; extend Scriptcheck to figure out when client IDs must be assigned
author Adam Chlipala <adamc@hcoop.net>
date Sat, 04 Apr 2009 14:03:39 -0400
parents 09df0c85f306
children 7ea0df9e56b6
files include/urweb.h lib/js/urweb.js src/c/urweb.c src/cjr.sml src/cjr_print.sml src/cjrize.sml src/jscomp.sml src/scriptcheck.sml
diffstat 8 files changed, 100 insertions(+), 53 deletions(-) [+]
line wrap: on
line diff
--- a/include/urweb.h	Sat Apr 04 12:54:39 2009 -0400
+++ b/include/urweb.h	Sat Apr 04 14:03:39 2009 -0400
@@ -52,6 +52,8 @@
 const char *uw_Basis_get_settings(uw_context, uw_Basis_string);
 const char *uw_Basis_get_script(uw_context, uw_unit);
 
+void uw_set_needs_push(uw_context, int);
+
 char *uw_Basis_htmlifyInt(uw_context, uw_Basis_int);
 char *uw_Basis_htmlifyFloat(uw_context, uw_Basis_float);
 char *uw_Basis_htmlifyString(uw_context, uw_Basis_string);
--- a/lib/js/urweb.js	Sat Apr 04 12:54:39 2009 -0400
+++ b/lib/js/urweb.js	Sat Apr 04 14:03:39 2009 -0400
@@ -22,11 +22,19 @@
 
 // Embedding closures in XML strings
 
+function cs(f) {
+  return {closure: f};
+}
+
+function isWeird(v) {
+  return v.closure != null || v.cat1 != null;
+}
+
 function cat(s1, s2) {
-  if (s1.length && s2.length)
+  if (isWeird(s1) || isWeird(s2))
+    return {cat1: s1, cat2: s2};
+  else
     return s1 + s2;
-  else
-    return {_1: s1, _2: s2};
 }
 
 var closures = [];
@@ -42,12 +50,12 @@
 }
 
 function flatten(tr) {
-  if (tr.length)
+  if (tr.cat1 != null)
+    return flatten(tr.cat1) + flatten(tr.cat2);
+  else if (tr.closure != null)
+    return "cr(" + newClosure(tr.closure) + ")";
+  else
     return tr;
-  else if (tr._1)
-    return cs(tr._1) + cs(tr._2);
-  else
-    return "cr(" + newClosure(tr) + ")";
 }
 
 function clearClosures() {
@@ -157,7 +165,7 @@
         ls.data.dyns = remove(span, ls.data.dyns);
     }
 
-    x.innerHTML = v;
+    x.innerHTML = flatten(v);
     runScripts(x);
 
     if (--dynDepth == 0)
@@ -412,3 +420,7 @@
     k(parse(msg))(null);
   }
 }
+
+
+// App-specific code
+
--- a/src/c/urweb.c	Sat Apr 04 12:54:39 2009 -0400
+++ b/src/c/urweb.c	Sat Apr 04 14:03:39 2009 -0400
@@ -300,6 +300,8 @@
 
   const char *script_header, *url_prefix;
 
+  int needs_push;
+
   size_t n_deltas, used_deltas;
   delta *deltas;
 
@@ -333,6 +335,7 @@
 
   ctx->script_header = "";
   ctx->url_prefix = "/";
+  ctx->needs_push = 0;
   
   ctx->error_message[0] = 0;
 
@@ -476,7 +479,7 @@
 }
 
 void uw_login(uw_context ctx) {
-  if (ctx->script_header[0]) {
+  if (ctx->needs_push) {
     char *id_s, *pass_s;
 
     if ((id_s = uw_Basis_requestHeader(ctx, "UrWeb-Client"))
@@ -578,6 +581,10 @@
   ctx->url_prefix = s;
 }
 
+void uw_set_needs_push(uw_context ctx, int n) {
+  ctx->needs_push = n;
+}
+
 
 static void buf_check_ctx(uw_context ctx, buf *b, size_t extra, const char *desc) {
   if (b->back - b->front < extra) {
--- a/src/cjr.sml	Sat Apr 04 12:54:39 2009 -0400
+++ b/src/cjr.sml	Sat Apr 04 14:03:39 2009 -0400
@@ -115,7 +115,8 @@
 
 datatype sidedness =
          ServerOnly
-       | ServerAndClient
+       | ServerAndPull
+       | ServerAndPullAndPush
 
 type file = decl list * (Core.export_kind * string * int * typ list * typ * sidedness) list
 
--- a/src/cjr_print.sml	Sat Apr 04 12:54:39 2009 -0400
+++ b/src/cjr_print.sml	Sat Apr 04 14:03:39 2009 -0400
@@ -2391,12 +2391,19 @@
                                     newline,
                                     string "uw_set_script_header(ctx, \"",
                                     string (case side of
-                                                ServerAndClient => "<script src=\\\""
-                                                                   ^ OS.Path.joinDirFile {dir = !Monoize.urlPrefix,
-                                                                                          file = "app.js"}
-                                                                   ^ "\\\"></script>\\n"
-                                              | ServerOnly => ""),
+                                                ServerOnly => ""
+                                              | _ => "<script src=\\\""
+                                                     ^ OS.Path.joinDirFile {dir = !Monoize.urlPrefix,
+                                                                            file = "app.js"}
+                                                     ^ "\\\"></script>\\n"),
                                     string "\");",
+                                    newline,
+                                    string "uw_set_needs_push(ctx, ",
+                                    string (case side of
+                                                ServerAndPullAndPush => "1"
+                                              | _ => "0"),
+                                    string ");",
+                                    newline,
                                     string "uw_set_url_prefix(ctx, \"",
                                     string (!Monoize.urlPrefix),
                                     string "\");",
--- a/src/cjrize.sml	Sat Apr 04 12:54:39 2009 -0400
+++ b/src/cjrize.sml	Sat Apr 04 14:03:39 2009 -0400
@@ -520,7 +520,7 @@
             val (ts, sm) = ListUtil.foldlMap cifyTyp sm ts
             val (t, sm) = cifyTyp (t, sm)
         in
-            (NONE, SOME (ek, "/" ^ s, n, ts, t, L'.ServerAndClient), sm)
+            (NONE, SOME (ek, "/" ^ s, n, ts, t, L'.ServerAndPullAndPush), sm)
         end
 
       | L.DTable (s, xts) =>
--- a/src/jscomp.sml	Sat Apr 04 12:54:39 2009 -0400
+++ b/src/jscomp.sml	Sat Apr 04 14:03:39 2009 -0400
@@ -850,7 +850,7 @@
                                 val (e1, st) = jsE inner (e1, st)
                                 val (e2, st) = jsE inner (e2, st)
                             in
-                                (strcat [str "(", e1, str "+", e2, str ")"], st)
+                                (strcat [str "cat(", e1, str ",", e2, str ")"], st)
                             end
 
                           | EError (e, _) =>
@@ -891,9 +891,9 @@
 
                           | EJavaScript (Source _, _, SOME _) => (e, st)
                           | EJavaScript (_, _, SOME e) =>
-                            (strcat [str "function(){return ",
+                            (strcat [str "cs(function(){return ",
                                      e,
-                                     str "}"],
+                                     str "})"],
                              st)
 
                           | EClosure _ => unsupported "EClosure"
@@ -905,9 +905,9 @@
                             let
                                 val (e, st) = jsE inner (e, st)
                             in
-                                (strcat [str "function(){return ",
+                                (strcat [str "cs(function(){return ",
                                          e,
-                                         str "}"],
+                                         str "})"],
                                  st)
                             end
 
--- a/src/scriptcheck.sml	Sat Apr 04 12:54:39 2009 -0400
+++ b/src/scriptcheck.sml	Sat Apr 04 14:03:39 2009 -0400
@@ -35,19 +35,21 @@
                            end)
 structure IS = IntBinarySet
 
-val csBasis = SS.addList (SS.empty,
-                          ["new_client_source",
-                           "get_client_source",
-                           "set_client_source",
-                           "new_channel",
-                           "subscribe",
-                           "send",
-                           "recv"])
+val pullBasis = SS.addList (SS.empty,
+                            ["new_client_source",
+                             "get_client_source",
+                             "set_client_source"])
 
+val pushBasis = SS.addList (SS.empty,
+                            ["new_channel",
+                             "self"])
+                
 val scriptWords = ["<script",
                    " onclick=",
                    " onload="]
 
+val pushWords = ["rv("]
+
 fun classify (ds, ps) =
     let
         fun inString {needle, haystack} =
@@ -57,11 +59,11 @@
                 not (Substring.isEmpty suffix)
             end
 
-        fun hasClient csids =
+        fun hasClient {basis, words} csids =
             let
                 fun hasClient e =
                     case #1 e of
-                        EPrim (Prim.String s) => List.exists (fn n => inString {needle = n, haystack = s}) scriptWords
+                        EPrim (Prim.String s) => List.exists (fn n => inString {needle = n, haystack = s}) words
                       | EPrim _ => false
                       | ERel _ => false
                       | ENamed n => IS.member (csids, n)
@@ -69,9 +71,9 @@
                       | ECon (_, _, SOME e) => hasClient e
                       | ENone _ => false
                       | ESome (_, e) => hasClient e
-                      | EFfi ("Basis", x) => SS.member (csBasis, x)
+                      | EFfi ("Basis", x) => SS.member (basis, x)
                       | EFfi _ => false
-                      | EFfiApp ("Basis", x, es) => SS.member (csBasis, x)
+                      | EFfiApp ("Basis", x, es) => SS.member (basis, x)
                                                     orelse List.exists hasClient es
                       | EFfiApp (_, _, es) => List.exists hasClient es
                       | EApp (e, es) => hasClient e orelse List.exists hasClient es
@@ -93,33 +95,49 @@
                 hasClient
             end
 
-        fun decl ((d, _), csids) =
+        fun decl ((d, _), (pull_ids, push_ids)) =
             let
-                val hasClient = hasClient csids
+                val hasClientPull = hasClient {basis = pullBasis, words = scriptWords} pull_ids
+                val hasClientPush = hasClient {basis = pushBasis, words = pushWords} push_ids
             in
                 case d of
-                    DVal (_, n, _, e) => if hasClient e then
-                                             IS.add (csids, n)
-                                         else
-                                             csids
-                  | DFun (_, n, _, _, e) => if hasClient e then
-                                                IS.add (csids, n)
-                                            else
-                                                csids
-                  | DFunRec xes => if List.exists (fn (_, _, _, _, e) => hasClient e) xes then
-                                       foldl (fn ((_, n, _, _, _), csids) => IS.add (csids, n))
-                                             csids xes
-                                   else
-                                       csids
-                  | _ => csids
+                    DVal (_, n, _, e) => (if hasClientPull e then
+                                             IS.add (pull_ids, n)
+                                          else
+                                              pull_ids,
+                                          if hasClientPush e then
+                                              IS.add (push_ids, n)
+                                          else
+                                              push_ids)
+                  | DFun (_, n, _, _, e) => (if hasClientPull e then
+                                                 IS.add (pull_ids, n)
+                                             else
+                                                 pull_ids,
+                                             if hasClientPush e then
+                                                 IS.add (push_ids, n)
+                                             else
+                                                 push_ids)
+                  | DFunRec xes => (if List.exists (fn (_, _, _, _, e) => hasClientPull e) xes then
+                                       foldl (fn ((_, n, _, _, _), pull_ids) => IS.add (pull_ids, n))
+                                             pull_ids xes
+                                    else
+                                        pull_ids,
+                                    if List.exists (fn (_, _, _, _, e) => hasClientPush e) xes then
+                                        foldl (fn ((_, n, _, _, _), push_ids) => IS.add (push_ids, n))
+                                              push_ids xes
+                                    else
+                                        push_ids)
+                  | _ => (pull_ids, push_ids)
             end
 
-        val csids = foldl decl IS.empty ds
+        val (pull_ids, push_ids) = foldl decl (IS.empty, IS.empty) ds
 
         val ps = map (fn (ek, x, n, ts, t, _) =>
                          (ek, x, n, ts, t,
-                          if IS.member (csids, n) then
-                              ServerAndClient
+                          if IS.member (push_ids, n) then
+                              ServerAndPullAndPush
+                          else if IS.member (pull_ids, n) then
+                              ServerAndPull
                           else
                               ServerOnly)) ps
     in