diff src/urweb.grm @ 2009:799be3911ce3

Monadic bind supports patterns
author Adam Chlipala <adam@chlipala.net>
date Fri, 02 May 2014 17:16:02 -0400
parents 93ff76058825
children 403f0cc65b9c
line wrap: on
line diff
--- a/src/urweb.grm	Fri May 02 15:32:10 2014 -0400
+++ b/src/urweb.grm	Fri May 02 17:16:02 2014 -0400
@@ -322,6 +322,39 @@
         (EApp (e', ob), loc)
     end
 
+fun patternOut (e : exp) =
+    case #1 e of
+        EWild => (PWild, #2 e)
+      | EVar ([], x, Infer) =>
+        if Char.isUpper (String.sub (x, 0)) then
+            (PCon ([], x, NONE), #2 e)
+        else
+            (PVar x, #2 e)
+      | EVar (xs, x, Infer) =>
+        if Char.isUpper (String.sub (x, 0)) then
+            (PCon (xs, x, NONE), #2 e)
+        else
+            (ErrorMsg.errorAt (#2 e) "Badly capitalized constructor name in pattern";
+             (PWild, #2 e))
+      | EPrim p => (PPrim p, #2 e)
+      | EApp ((EVar (xs, x, Infer), _), e') =>
+        (PCon (xs, x, SOME (patternOut e')), #2 e)
+      | ERecord (xes, flex) =>
+        (PRecord (map (fn (x, e') =>
+                          let
+                              val x =
+                                  case #1 x of
+                                      CName x => x
+                                    | _ => (ErrorMsg.errorAt (#2 e) "Field name not constant in pattern";
+                                            "")
+                          in
+                              (x, patternOut e')
+                          end) xes, flex), #2 e)
+      | EAnnot (e', t) =>
+        (PAnnot (patternOut e', t), #2 e)
+      | _ => (ErrorMsg.errorAt (#2 e) "This is an expression but not a pattern.";
+              (PWild, #2 e))
+
 %%
 %header (functor UrwebLrValsFn(structure Token : TOKEN))
 
@@ -428,13 +461,13 @@
  | eapps of exp
  | eterm of exp
  | etuple of exp list
- | rexp of (con * exp) list
+ | rexp of (con * exp) list * bool
  | xml of exp
  | xmlOne of exp
  | xmlOpt of exp
  | tag of (string * exp) * exp option * exp option * exp
  | tagHead of string * exp
- | bind of string * con option * exp
+ | bind of pat * con option * exp
  | edecl of edecl
  | edecls of edecl list
 
@@ -730,10 +763,10 @@
                                              val e = (EApp (e, mat), loc)
                                              val e = (EApp (e, texp), loc)
                                          in
-                                             (EApp (e, (ERecord [((CName "OnDelete", loc),
-                                                                  findMode Delete),
-                                                                 ((CName "OnUpdate", loc),
-                                                                  findMode Update)], loc)), loc)
+                                             (EApp (e, (ERecord ([((CName "OnDelete", loc),
+                                                                   findMode Delete),
+                                                                  ((CName "OnUpdate", loc),
+                                                                   findMode Update)], false), loc)), loc)
                                          end)
 
        | LBRACE eexp RBRACE             (eexp)
@@ -779,7 +812,7 @@
                                              val witness = map (fn (c, _) =>
                                                                    (c, (EWild, loc)))
                                                            (#1 tnames :: #2 tnames)
-                                             val witness = (ERecord witness, loc)
+                                             val witness = (ERecord (witness, false), loc)
                                          in
                                              (EApp (e, witness), loc)
                                          end)
@@ -1136,11 +1169,17 @@
                                          end)
        | bind SEMI eexp                 (let
                                              val loc = s (bindleft, eexpright)
-                                             val (v, to, e1) = bind
+                                             val (p, to, e1) = bind
                                              val e = (EVar (["Basis"], "bind", Infer), loc)
                                              val e = (EApp (e, e1), loc)
+
+                                             val f = case #1 p of
+                                                         PVar v => (EAbs (v, to, eexp), loc)
+                                                       | _ => (EAbs ("$x", to,
+                                                                     (ECase ((EVar ([], "$x", Infer), loc),
+                                                                             [(p, eexp)]), loc)), loc)
                                          in
-                                             (EApp (e, (EAbs (v, to, eexp), loc)), loc)
+                                             (EApp (e, f), loc)
                                          end)
        | eexp EQ eexp                   (native_op ("eq", eexp1, eexp2, s (eexp1left, eexp2right)))
        | eexp NE eexp                   (native_op ("ne", eexp1, eexp2, s (eexp1left, eexp2right)))
@@ -1181,17 +1220,17 @@
                                              val loc = s (eappsleft, eexpright)
                                          in
                                              (EApp ((EVar (["Basis"], "Cons", Infer), loc),
-                                                    (ERecord [((CName "1", loc),
-                                                               eapps),
-                                                              ((CName "2", loc),
-                                                               eexp)], loc)), loc)
+                                                    (ERecord ([((CName "1", loc),
+                                                                eapps),
+                                                               ((CName "2", loc),
+                                                                eexp)], false), loc)), loc)
                                          end)
 
-bind   : SYMBOL LARROW eapps            (SYMBOL, NONE, eapps)
+bind   : eapps LARROW eapps             (patternOut eapps1, NONE, eapps2)
        | eapps                          (let
                                              val loc = s (eappsleft, eappsright)
                                          in
-                                             ("_", SOME (TRecord (CRecord [], loc), loc), eapps)
+                                             ((PVar "_", loc), SOME (TRecord (CRecord [], loc), loc), eapps)
                                          end)
 
 eargs  : earg                           (earg)
@@ -1289,7 +1328,7 @@
                                          in
                                              (ERecord (ListUtil.mapi (fn (i, e) =>
                                                                          ((CName (Int.toString (i + 1)), loc),
-                                                                          e)) etuple), loc)
+                                                                          e)) etuple, false), loc)
                                          end)
 
        | path                           (EVar (#1 path, #2 path, Infer), s (pathleft, pathright))
@@ -1299,7 +1338,8 @@
        | AT cpath                       (EVar (#1 cpath, #2 cpath, TypesOnly), s (ATleft, cpathright))
        | AT AT cpath                    (EVar (#1 cpath, #2 cpath, DontInfer), s (AT1left, cpathright))
        | LBRACE rexp RBRACE             (ERecord rexp, s (LBRACEleft, RBRACEright))
-       | UNIT                           (ERecord [], s (UNITleft, UNITright))
+       | LBRACE RBRACE                  (ERecord ([], false), s (LBRACEleft, RBRACEright))
+       | UNIT                           (ERecord ([], false), s (UNITleft, UNITright))
 
        | INT                            (EPrim (Prim.Int INT), s (INTleft, INTright))
        | FLOAT                          (EPrim (Prim.Float FLOAT), s (FLOATleft, FLOATright))
@@ -1386,7 +1426,7 @@
                                                                        ^ " vs. " ^ Int.toString (length sqlexps) ^ ")")
                                              else
                                                  ();
-                                             (EApp (e, (ERecord (ListPair.zip (fields, sqlexps)), loc)), loc)
+                                             (EApp (e, (ERecord (ListPair.zip (fields, sqlexps), false), loc)), loc)
                                          end)
        | LPAREN enterDml UPDATE texp SET fsets CWHERE sqlexp leaveDml RPAREN
                                         (let
@@ -1394,7 +1434,7 @@
 
                                              val e = (EVar (["Basis"], "update", Infer), loc)
                                              val e = (ECApp (e, (CWild (KRecord (KType, loc), loc), loc)), loc)
-                                             val e = (EApp (e, (ERecord fsets, loc)), loc)
+                                             val e = (EApp (e, (ERecord (fsets, false), loc)), loc)
                                              val e = (EApp (e, texp), loc)
                                          in
                                              (EApp (e, sqlexp), loc)
@@ -1486,9 +1526,9 @@
 ptuple : pat COMMA pat                  ([pat1, pat2])
        | pat COMMA ptuple               (pat :: ptuple)
 
-rexp   :                                ([])
-       | ident EQ eexp                  ([(ident, eexp)])
-       | ident EQ eexp COMMA rexp       ((ident, eexp) :: rexp)
+rexp   : DOTDOTDOT                      ([], true)
+       | ident EQ eexp                  ([(ident, eexp)], false)
+       | ident EQ eexp COMMA rexp       ((ident, eexp) :: #1 rexp, #2 rexp)
 
 xml    : xmlOne xml                     (let
                                              val pos = s (xmlOneleft, xmlright)
@@ -1626,9 +1666,9 @@
                                                                 ((CName "Data", pos), datas') :: #6 attrs
                                                             end
 
-                                             val e = (EApp (e, (ERecord atts, pos)), pos)
+                                             val e = (EApp (e, (ERecord (atts, false), pos)), pos)
                                              val e = (EApp (e, (EApp (#2 tagHead,
-                                                                      (ERecord [], pos)), pos)), pos)
+                                                                      (ERecord ([], false), pos)), pos)), pos)
                                          in
                                              (tagHead, #1 attrs, #2 attrs, e)
                                          end)
@@ -1708,14 +1748,14 @@
 query  : query1 obopt lopt ofopt        (let
                                              val loc = s (query1left, query1right)
 
-                                             val re = (ERecord [((CName "Rows", loc),
-                                                                 query1),
-                                                                ((CName "OrderBy", loc),
-                                                                 obopt),
-                                                                ((CName "Limit", loc),
-                                                                 lopt),
-                                                                ((CName "Offset", loc),
-                                                                 ofopt)], loc)
+                                             val re = (ERecord ([((CName "Rows", loc),
+                                                                  query1),
+                                                                 ((CName "OrderBy", loc),
+                                                                  obopt),
+                                                                 ((CName "Limit", loc),
+                                                                  lopt),
+                                                                 ((CName "Offset", loc),
+                                                                  ofopt)], false), loc)
                                          in
                                              (EApp ((EVar (["Basis"], "sql_query", Infer), loc), re), loc)
                                          end)
@@ -1796,21 +1836,21 @@
                                              val e = (EVar (["Basis"], "sql_query1", Infer), loc)
                                              val e = (ECApp (e, (CRecord (map (fn nm => (nm, (CUnit, loc))) empties),
                                                                  loc)), loc)
-                                             val re = (ERecord [((CName "Distinct", loc),
-                                                                 dopt),
-                                                                ((CName "From", loc),
-                                                                 #2 tables),
-                                                                ((CName "Where", loc),
-                                                                 wopt),
-                                                                ((CName "GroupBy", loc),
-                                                                 grp),
-                                                                ((CName "Having", loc),
-                                                                 hopt),
-                                                                ((CName "SelectFields", loc),
-                                                                 (ECApp ((EVar (["Basis"], "sql_subset", Infer), loc),
-                                                                         sel), loc)),
-                                                                ((CName "SelectExps", loc),
-                                                                 (ERecord exps, loc))], loc)
+                                             val re = (ERecord ([((CName "Distinct", loc),
+                                                                  dopt),
+                                                                 ((CName "From", loc),
+                                                                  #2 tables),
+                                                                 ((CName "Where", loc),
+                                                                  wopt),
+                                                                 ((CName "GroupBy", loc),
+                                                                  grp),
+                                                                 ((CName "Having", loc),
+                                                                  hopt),
+                                                                 ((CName "SelectFields", loc),
+                                                                  (ECApp ((EVar (["Basis"], "sql_subset", Infer), loc),
+                                                                          sel), loc)),
+                                                                 ((CName "SelectExps", loc),
+                                                                  (ERecord (exps, false), loc))], false), loc)
 
                                              val e = (EApp (e, re), loc)
                                          in