changeset 1360:02fc16faecf3

[De]serialization of times in JavaScript; proper integer division in JavaScript; Basis.crypt; Top.mkRead'; more aggressive Mono-level inlining, for values of function-y types
author Adam Chlipala <adam@chlipala.net>
date Thu, 23 Dec 2010 17:46:40 -0500
parents e525ad571e15
children 7a436b6267ab
files include/urweb.h lib/js/urweb.js lib/ur/basis.urs lib/ur/top.ur lib/ur/top.urs src/c/urweb.c src/cjr_print.sml src/cjrize.sml src/iflow.sml src/jscomp.sml src/mono.sml src/mono_opt.sml src/mono_print.sml src/mono_reduce.sml src/mono_util.sml src/monoize.sml src/settings.sml src/urweb.grm
diffstat 18 files changed, 108 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- a/include/urweb.h	Thu Dec 23 11:23:31 2010 -0500
+++ b/include/urweb.h	Thu Dec 23 17:46:40 2010 -0500
@@ -169,6 +169,7 @@
 char *uw_Basis_jsifyString(uw_context, uw_Basis_string);
 char *uw_Basis_jsifyChar(uw_context, uw_Basis_char);
 char *uw_Basis_jsifyChannel(uw_context, uw_Basis_channel);
+char *uw_Basis_jsifyTime(uw_context, uw_Basis_time);
 
 uw_Basis_string uw_Basis_intToString(uw_context, uw_Basis_int);
 uw_Basis_string uw_Basis_floatToString(uw_context, uw_Basis_float);
@@ -301,4 +302,6 @@
 uw_Basis_time uw_Basis_stringToTimef(uw_context, const char *fmt, uw_Basis_string);
 uw_Basis_time uw_Basis_stringToTimef_error(uw_context, const char *fmt, uw_Basis_string);
 
+uw_Basis_string uw_Basis_crypt(uw_context, uw_Basis_string key, uw_Basis_string salt);
+
 #endif
--- a/lib/js/urweb.js	Thu Dec 23 11:23:31 2010 -0500
+++ b/lib/js/urweb.js	Thu Dec 23 17:46:40 2010 -0500
@@ -19,7 +19,9 @@
 function minus(x, y) { return x - y; }
 function times(x, y) { return x * y; }
 function div(x, y) { return x / y; }
+function divInt(x, y) { var n = x / y; return n < 0 ? Math.ceil(n) : Math.floor(n); }
 function mod(x, y) { return x % y; }
+function modInt(x, y) { var n = x % y; return n < 0 ? Math.ceil(n) : Math.floor(n); }
 function lt(x, y) { return x < y; }
 function le(x, y) { return x <= y; }
 
--- a/lib/ur/basis.urs	Thu Dec 23 11:23:31 2010 -0500
+++ b/lib/ur/basis.urs	Thu Dec 23 17:46:40 2010 -0500
@@ -146,6 +146,11 @@
 val timef : string -> time -> string (* Uses strftime() format string *)
 
 
+(** * Encryption *)
+
+val crypt : string -> string -> string
+
+
 (** HTTP operations *)
 
 con http_cookie :: Type -> Type
--- a/lib/ur/top.ur	Thu Dec 23 11:23:31 2010 -0500
+++ b/lib/ur/top.ur	Thu Dec 23 17:46:40 2010 -0500
@@ -89,7 +89,7 @@
                             None => None
                           | v => Some v)
 
-fun txt [t] [ctx ::: {Unit}] [use ::: {Type}] (_ : show t) (v : t) =
+fun txt [t] [ctx ::: {Unit}] [use ::: {Type}] (_ : show t) (v : t) : xml ctx use [] =
     cdata (show v)
 
 fun map0 [K] [tf :: K -> Type] (f : t :: K -> tf t) [r ::: {K}] (fl : folder r) =
@@ -343,3 +343,8 @@
     case e2 of
         None => (SQL {e1} IS NULL)
       | Some _ => sql_binary sql_eq e1 (sql_inject e2)
+
+fun mkRead' [t ::: Type] (f : string -> option t) (name : string) : read t =
+    mkRead (fn s => case f s of
+                        None => error <xml>Invalid {txt name}: {txt s}</xml>
+                      | Some v => v) f
--- a/lib/ur/top.urs	Thu Dec 23 11:23:31 2010 -0500
+++ b/lib/ur/top.urs	Thu Dec 23 17:46:40 2010 -0500
@@ -231,3 +231,5 @@
                   -> sql_exp tables agg exps (option t)
                   -> option t
                   -> sql_exp tables agg exps bool
+
+val mkRead' : t ::: Type -> (string -> option t) -> string -> read t
--- a/src/c/urweb.c	Thu Dec 23 11:23:31 2010 -0500
+++ b/src/c/urweb.c	Thu Dec 23 17:46:40 2010 -0500
@@ -13,6 +13,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <crypt.h>
 
 #include <pthread.h>
 
@@ -2006,6 +2007,27 @@
   return uw_unit_v;
 }
 
+char *uw_Basis_jsifyTime(uw_context ctx, uw_Basis_time n) {
+  int len;
+  char *r;
+
+  uw_check_heap(ctx, INTS_MAX);
+  r = ctx->heap.front;
+  sprintf(r, "%lld%n", (uw_Basis_int)n, &len);
+  ctx->heap.front += len+1;
+  return r;
+}
+
+uw_unit uw_Basis_jsifyInt_w(uw_context ctx, uw_Basis_time n) {
+  int len;
+
+  uw_check(ctx, INTS_MAX);
+  sprintf(ctx->page.front, "%lld%n", (uw_Basis_int)n, &len);
+  ctx->page.front += len;
+  
+  return uw_unit_v;
+}
+
 char *uw_Basis_htmlifyString(uw_context ctx, uw_Basis_string s) {
   char *r, *s2;
 
@@ -3568,3 +3590,15 @@
 
   return r;
 }
+
+uw_Basis_string uw_Basis_crypt(uw_context ctx, uw_Basis_string key, uw_Basis_string salt) {
+  struct crypt_data *data;
+
+  if ((data = uw_get_global(ctx, "crypt")) == NULL) {
+    data = malloc(sizeof(struct crypt_data));
+    data->initialized = 0;
+    uw_set_global(ctx, "crypt", data, free);
+  }
+
+  return uw_strdup(ctx, crypt_r(key, salt, data));
+}
--- a/src/cjr_print.sml	Thu Dec 23 11:23:31 2010 -0500
+++ b/src/cjr_print.sml	Thu Dec 23 17:46:40 2010 -0500
@@ -635,7 +635,9 @@
                                  string (Int.toString (size x')),
                                  string "] == 0 || request[",
                                  string (Int.toString (size x')),
-                                 string ("] == '/')) ? __uwc_" ^ ident x' ^ "_" ^ Int.toString n),
+                                 string "] == '/')) ? (request += ",
+                                 string (Int.toString (size x')),
+                                 string (", (*request == '/' ? ++request : NULL), __uwc_" ^ ident x' ^ "_" ^ Int.toString n ^ ")"),
                                  space,
                                  string ":",
                                  space,
--- a/src/cjrize.sml	Thu Dec 23 11:23:31 2010 -0500
+++ b/src/cjrize.sml	Thu Dec 23 17:46:40 2010 -0500
@@ -300,7 +300,7 @@
         in
             ((L'.EUnop (s, e1), loc), sm)
         end
-      | L.EBinop (s, e1, e2) =>
+      | L.EBinop (_, s, e1, e2) =>
         let
             val (e1, sm) = cifyExp (e1, sm)
             val (e2, sm) = cifyExp (e2, sm)
--- a/src/iflow.sml	Thu Dec 23 11:23:31 2010 -0500
+++ b/src/iflow.sml	Thu Dec 23 17:46:40 2010 -0500
@@ -1965,7 +1965,7 @@
 
           | EAbs _ => default ()
           | EUnop (s, e1) => evalExp env e1 (fn e1 => k (Func (Other s, [e1])))
-          | EBinop (s, e1, e2) => evalExp env e1 (fn e1 => evalExp env e2 (fn e2 => k (Func (Other s, [e1, e2]))))
+          | EBinop (_, s, e1, e2) => evalExp env e1 (fn e1 => evalExp env e2 (fn e2 => k (Func (Other s, [e1, e2]))))
           | ERecord xets =>
             let
                 fun doFields (xes, acc) =
@@ -2352,7 +2352,7 @@
                             end
                           | EAbs (x, t1, t2, e) => (EAbs (x, t1, t2, doExp (Unknown :: env) e), loc)
                           | EUnop (uo, e1) => (EUnop (uo, doExp env e1), loc)
-                          | EBinop (bo, e1, e2) => (EBinop (bo, doExp env e1, doExp env e2), loc)
+                          | EBinop (bi, bo, e1, e2) => (EBinop (bi, bo, doExp env e1, doExp env e2), loc)
                           | ERecord xets => (ERecord (map (fn (x, e, t) => (x, doExp env e, t)) xets), loc)
                           | EField (e1, f) => (EField (doExp env e1, f), loc)
                           | ECase (e, pes, ts) =>
--- a/src/jscomp.sml	Thu Dec 23 11:23:31 2010 -0500
+++ b/src/jscomp.sml	Thu Dec 23 17:46:40 2010 -0500
@@ -126,6 +126,7 @@
               | TFfi ("Basis", "int") => ((EFfiApp ("Basis", "htmlifyInt", [e]), loc), st)
               | TFfi ("Basis", "float") => ((EFfiApp ("Basis", "htmlifyFloat", [e]), loc), st)
               | TFfi ("Basis", "channel") => ((EFfiApp ("Basis", "jsifyChannel", [e]), loc), st)
+              | TFfi ("Basis", "time") => ((EFfiApp ("Basis", "jsifyTime", [e]), loc), st)
 
               | TFfi ("Basis", "bool") => ((ECase (e,
                                                    [((PCon (Enum, PConFfi {mod = "Basis",
@@ -701,7 +702,7 @@
                                          str ",null)}"],
                                  st)
                             end
-                          | EBinop (s, e1, e2) =>
+                          | EBinop (bi, s, e1, e2) =>
                             let
                                 val name = case s of
                                                "==" => "eq"
@@ -709,8 +710,8 @@
                                              | "+" => "plus"
                                              | "-" => "minus"
                                              | "*" => "times"
-                                             | "/" => "div"
-                                             | "%" => "mod"
+                                             | "/" => (case bi of Int => "divInt" | NotInt => "div")
+                                             | "%" => (case bi of Int => "modInt" | NotInt => "mod")
                                              | "<" => "lt"
                                              | "<=" => "le"
                                              | "strcmp" => "strcmp"
@@ -1039,12 +1040,12 @@
                  in
                      ((EUnop (s, e), loc), st)
                  end
-               | EBinop (s, e1, e2) =>
+               | EBinop (bi, s, e1, e2) =>
                  let
                      val (e1, st) = exp outer (e1, st)
                      val (e2, st) = exp outer (e2, st)
                  in
-                     ((EBinop (s, e1, e2), loc), st)
+                     ((EBinop (bi, s, e1, e2), loc), st)
                  end
                  
                | ERecord xets =>
--- a/src/mono.sml	Thu Dec 23 11:23:31 2010 -0500
+++ b/src/mono.sml	Thu Dec 23 17:46:40 2010 -0500
@@ -68,6 +68,8 @@
 
 datatype failure_mode = datatype Settings.failure_mode
 
+datatype binop_intness = Int | NotInt
+
 datatype exp' =
          EPrim of Prim.t
        | ERel of int
@@ -81,7 +83,7 @@
        | EAbs of string * typ * typ * exp
 
        | EUnop of string * exp
-       | EBinop of string * exp * exp
+       | EBinop of binop_intness * string * exp * exp
 
        | ERecord of (string * exp * typ) list
        | EField of exp * string
--- a/src/mono_opt.sml	Thu Dec 23 11:23:31 2010 -0500
+++ b/src/mono_opt.sml	Thu Dec 23 17:46:40 2010 -0500
@@ -536,7 +536,7 @@
       | EFfiApp ("Basis", "attrifyString_w", [(EFfiApp ("Basis", "str1", [e]), _)]) =>
         EFfiApp ("Basis", "attrifyChar_w", [e])
 
-      | EBinop ("+", (EPrim (Prim.Int n1), _), (EPrim (Prim.Int n2), _)) => EPrim (Prim.Int (Int64.+ (n1, n2)))
+      | EBinop (_, "+", (EPrim (Prim.Int n1), _), (EPrim (Prim.Int n2), _)) => EPrim (Prim.Int (Int64.+ (n1, n2)))
         
       | _ => e
 
--- a/src/mono_print.sml	Thu Dec 23 11:23:31 2010 -0500
+++ b/src/mono_print.sml	Thu Dec 23 17:46:40 2010 -0500
@@ -187,11 +187,11 @@
       | EUnop (s, e) => parenIf true (box [string s,
                                            space,
                                            p_exp' true env e])
-      | EBinop (s, e1, e2) => parenIf true (box [p_exp' true env e1,
-                                                 space,
-                                                 string s,
-                                                 space,
-                                                 p_exp' true env e2])
+      | EBinop (_, s, e1, e2) => parenIf true (box [p_exp' true env e1,
+                                                    space,
+                                                    string s,
+                                                    space,
+                                                    p_exp' true env e2])
 
       | ERecord xes => box [string "{",
                             p_list (fn (x, e, _) =>
--- a/src/mono_reduce.sml	Thu Dec 23 11:23:31 2010 -0500
+++ b/src/mono_reduce.sml	Thu Dec 23 17:46:40 2010 -0500
@@ -92,7 +92,7 @@
       | EApp _ => true
 
       | EUnop (_, e) => impure e
-      | EBinop (_, e1, e2) => impure e1 orelse impure e2
+      | EBinop (_, _, e1, e2) => impure e1 orelse impure e2
 
       | ERecord xes => List.exists (fn (_, e, _) => impure e) xes
       | EField (e, _) => impure e
@@ -365,11 +365,21 @@
         val size = U.Exp.fold {typ = fn (_, n) => n,
                                exp = fn (_, n) => n + 1} 0
 
-        fun mayInline (n, e) =
+        val functionInside' = U.Typ.exists (fn c => case c of
+                                                        TFun _ => true
+                                                      | _ => false)
+                              
+        fun functionInside t =
+            case #1 t of
+                TFun (t1, t2) => functionInside' t1 orelse functionInside t2
+              | _ => functionInside' t
+
+        fun mayInline (n, e, t) =
             case IM.find (uses, n) of
                 NONE => false
               | SOME count => count <= 1
                               orelse size e <= Settings.getMonoInline ()
+                              orelse functionInside t
 
         fun summarize d (e, _) =
             let
@@ -426,7 +436,7 @@
                       | EAbs _ => []
 
                       | EUnop (_, e) => summarize d e
-                      | EBinop (_, e1, e2) => summarize d e1 @ summarize d e2
+                      | EBinop (_, _, e1, e2) => summarize d e1 @ summarize d e2
 
                       | ERecord xets => List.concat (map (summarize d o #2) xets)
                       | EField (e, _) => summarize d e
@@ -701,7 +711,7 @@
                 let
                     val eo = case eo of
                                  NONE => NONE
-                               | SOME e => if mayInline (n, e) then
+                               | SOME e => if mayInline (n, e, t) then
                                                SOME e
                                            else
                                                NONE
--- a/src/mono_util.sml	Thu Dec 23 11:23:31 2010 -0500
+++ b/src/mono_util.sml	Thu Dec 23 17:46:40 2010 -0500
@@ -200,12 +200,12 @@
                 S.map2 (mfe ctx e,
                      fn e' =>
                         (EUnop (s, e'), loc))
-              | EBinop (s, e1, e2) =>
+              | EBinop (bi, s, e1, e2) =>
                 S.bind2 (mfe ctx e1,
                       fn e1' =>
                          S.map2 (mfe ctx e2,
                               fn e2' =>
-                                 (EBinop (s, e1', e2'), loc)))
+                                 (EBinop (bi, s, e1', e2'), loc)))
 
               | ERecord xes =>
                 S.map2 (ListUtil.mapfold (fn (x, e, t) =>
--- a/src/monoize.sml	Thu Dec 23 11:23:31 2010 -0500
+++ b/src/monoize.sml	Thu Dec 23 17:46:40 2010 -0500
@@ -895,42 +895,42 @@
                        (L'.TFun ((L'.TFfi ("Basis", "int"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc),
                        (L'.EAbs ("y", (L'.TFfi ("Basis", "int"), loc),
                                  (L'.TFfi ("Basis", "bool"), loc),
-                                 (L'.EBinop ("==", (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc),
+                                 (L'.EBinop (L'.Int, "==", (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc),
              fm)
           | L.EFfi ("Basis", "eq_float") =>
             ((L'.EAbs ("x", (L'.TFfi ("Basis", "float"), loc),
                        (L'.TFun ((L'.TFfi ("Basis", "float"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc),
                        (L'.EAbs ("y", (L'.TFfi ("Basis", "float"), loc),
                                  (L'.TFfi ("Basis", "bool"), loc),
-                                 (L'.EBinop ("==", (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc),
+                                 (L'.EBinop (L'.NotInt, "==", (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc),
              fm)
           | L.EFfi ("Basis", "eq_bool") =>
             ((L'.EAbs ("x", (L'.TFfi ("Basis", "bool"), loc),
                        (L'.TFun ((L'.TFfi ("Basis", "bool"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc),
                        (L'.EAbs ("y", (L'.TFfi ("Basis", "bool"), loc),
                                  (L'.TFfi ("Basis", "bool"), loc),
-                                 (L'.EBinop ("==", (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc),
+                                 (L'.EBinop (L'.NotInt, "==", (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc),
              fm)
           | L.EFfi ("Basis", "eq_string") =>
             ((L'.EAbs ("x", (L'.TFfi ("Basis", "string"), loc),
                        (L'.TFun ((L'.TFfi ("Basis", "string"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc),
                        (L'.EAbs ("y", (L'.TFfi ("Basis", "string"), loc),
                                  (L'.TFfi ("Basis", "bool"), loc),
-                                 (L'.EBinop ("!strcmp", (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc),
+                                 (L'.EBinop (L'.NotInt, "!strcmp", (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc),
              fm)
           | L.EFfi ("Basis", "eq_char") =>
             ((L'.EAbs ("x", (L'.TFfi ("Basis", "char"), loc),
                        (L'.TFun ((L'.TFfi ("Basis", "char"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc),
                        (L'.EAbs ("y", (L'.TFfi ("Basis", "char"), loc),
                                  (L'.TFfi ("Basis", "bool"), loc),
-                                 (L'.EBinop ("==", (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc),
+                                 (L'.EBinop (L'.NotInt, "==", (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc),
              fm)
           | L.EFfi ("Basis", "eq_time") =>
             ((L'.EAbs ("x", (L'.TFfi ("Basis", "time"), loc),
                        (L'.TFun ((L'.TFfi ("Basis", "time"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc),
                        (L'.EAbs ("y", (L'.TFfi ("Basis", "time"), loc),
                                  (L'.TFfi ("Basis", "bool"), loc),
-                                 (L'.EBinop ("==", (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc),
+                                 (L'.EBinop (L'.NotInt, "==", (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc),
              fm)
 
           | L.ECApp ((L.EFfi ("Basis", "mkEq"), _), t) =>
@@ -999,7 +999,7 @@
                               (L'.TFun ((L'.TFfi ("Basis", "int"), loc), (L'.TFfi ("Basis", "int"), loc)), loc),
                               (L'.EAbs ("y", (L'.TFfi ("Basis", "int"), loc),
                                         (L'.TFfi ("Basis", "int"), loc),
-                                        (L'.EBinop (s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
+                                        (L'.EBinop (L'.Int, s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
             in
                 numEx ((L'.TFfi ("Basis", "int"), loc),
                        Prim.Int (Int64.fromInt 0),
@@ -1019,7 +1019,7 @@
                               (L'.TFun ((L'.TFfi ("Basis", "float"), loc), (L'.TFfi ("Basis", "float"), loc)), loc),
                               (L'.EAbs ("y", (L'.TFfi ("Basis", "float"), loc),
                                         (L'.TFfi ("Basis", "float"), loc),
-                                        (L'.EBinop (s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
+                                        (L'.EBinop (L'.NotInt, s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
             in
                 numEx ((L'.TFfi ("Basis", "float"), loc),
                        Prim.Float 0.0,
@@ -1086,7 +1086,7 @@
                               (L'.TFun ((L'.TFfi ("Basis", "int"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc),
                               (L'.EAbs ("y", (L'.TFfi ("Basis", "int"), loc),
                                         (L'.TFfi ("Basis", "bool"), loc),
-                                        (L'.EBinop (s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
+                                        (L'.EBinop (L'.Int, s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
             in
                 ordEx ((L'.TFfi ("Basis", "int"), loc),
                        intBin "<",
@@ -1099,7 +1099,7 @@
                               (L'.TFun ((L'.TFfi ("Basis", "float"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc),
                               (L'.EAbs ("y", (L'.TFfi ("Basis", "float"), loc),
                                         (L'.TFfi ("Basis", "bool"), loc),
-                                        (L'.EBinop (s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
+                                        (L'.EBinop (L'.NotInt, s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
             in
                 ordEx ((L'.TFfi ("Basis", "float"), loc),
                        floatBin "<",
@@ -1112,7 +1112,7 @@
                               (L'.TFun ((L'.TFfi ("Basis", "bool"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc),
                               (L'.EAbs ("y", (L'.TFfi ("Basis", "bool"), loc),
                                         (L'.TFfi ("Basis", "bool"), loc),
-                                        (L'.EBinop (s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
+                                        (L'.EBinop (L'.NotInt, s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
             in
                 ordEx ((L'.TFfi ("Basis", "bool"), loc),
                        boolBin "<",
@@ -1125,8 +1125,8 @@
                               (L'.TFun ((L'.TFfi ("Basis", "string"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc),
                               (L'.EAbs ("y", (L'.TFfi ("Basis", "string"), loc),
                                         (L'.TFfi ("Basis", "bool"), loc),
-                                        (L'.EBinop (s,
-                                                    (L'.EBinop ("strcmp",
+                                        (L'.EBinop (L'.NotInt, s,
+                                                    (L'.EBinop (L'.NotInt, "strcmp",
                                                                 (L'.ERel 1, loc),
                                                                 (L'.ERel 0, loc)), loc),
                                                     (L'.EPrim (Prim.Int (Int64.fromInt 0)), loc)), loc)), loc)), loc)
@@ -1142,7 +1142,7 @@
                               (L'.TFun ((L'.TFfi ("Basis", "char"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc),
                               (L'.EAbs ("y", (L'.TFfi ("Basis", "char"), loc),
                                         (L'.TFfi ("Basis", "bool"), loc),
-                                        (L'.EBinop (s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
+                                        (L'.EBinop (L'.NotInt, s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
             in
                 ordEx ((L'.TFfi ("Basis", "char"), loc),
                        charBin "<",
@@ -1155,7 +1155,7 @@
                               (L'.TFun ((L'.TFfi ("Basis", "time"), loc), (L'.TFfi ("Basis", "bool"), loc)), loc),
                               (L'.EAbs ("y", (L'.TFfi ("Basis", "time"), loc),
                                         (L'.TFfi ("Basis", "bool"), loc),
-                                        (L'.EBinop (s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
+                                        (L'.EBinop (L'.NotInt, s, (L'.ERel 1, loc), (L'.ERel 0, loc)), loc)), loc)), loc)
             in
                 ordEx ((L'.TFfi ("Basis", "time"), loc),
                        boolBin "<",
--- a/src/settings.sml	Thu Dec 23 11:23:31 2010 -0500
+++ b/src/settings.sml	Thu Dec 23 17:46:40 2010 -0500
@@ -171,6 +171,7 @@
                           ("stringToInt_error", "pi"),
                           ("urlifyInt", "ts"),
                           ("urlifyFloat", "ts"),
+                          ("urlifyTime", "ts"),
                           ("urlifyString", "uf"),
                           ("urlifyBool", "ub"),
                           ("recv", "rv"),
--- a/src/urweb.grm	Thu Dec 23 11:23:31 2010 -0500
+++ b/src/urweb.grm	Thu Dec 23 17:46:40 2010 -0500
@@ -1232,7 +1232,9 @@
                                              val e = (EApp (e, texp), loc)
                                          in
                                              if length fields <> length sqlexps then
-                                                 ErrorMsg.errorAt loc "Length mismatch in INSERT field specification"
+                                                 ErrorMsg.errorAt loc ("Length mismatch in INSERT field specification ("
+                                                                       ^ Int.toString (length fields)
+                                                                       ^ " vs. " ^ Int.toString (length sqlexps) ^ ")")
                                              else
                                                  ();
                                              (EApp (e, (ERecord (ListPair.zip (fields, sqlexps)), loc)), loc)