changeset 91:4327abd52997

Basic XML stuff
author Adam Chlipala <adamc@hcoop.net>
date Thu, 03 Jul 2008 16:26:28 -0400
parents 94ef20a31550
children 1a4c51fa615c
files lib/basis.lig src/elaborate.sml src/lacweb.grm src/lacweb.lex tests/html.lac
diffstat 5 files changed, 441 insertions(+), 176 deletions(-) [+]
line wrap: on
line diff
--- a/lib/basis.lig	Thu Jul 03 11:04:25 2008 -0400
+++ b/lib/basis.lig	Thu Jul 03 16:26:28 2008 -0400
@@ -1,3 +1,22 @@
 type int
 type float
 type string
+
+
+con tag :: {Unit} -> {Unit} -> Type
+
+
+con xml :: {Unit} -> Type
+val cdata : ctx ::: {Unit} -> string -> xml ctx
+val tag : outer ::: {Unit} -> inner ::: {Unit}
+        -> tag outer inner
+        -> xml inner
+        -> xml outer
+val join : shared :: {Unit}
+        -> ctx1 ::: {Unit} -> ctx1 ~ shared
+        -> ctx2 ::: {Unit} -> ctx2 ~ shared
+        -> xml (shared ++ ctx1) -> xml (shared ++ ctx2) -> xml shared
+
+
+val head : tag [Html] [Head]
+val title : tag [Head] []
--- a/src/elaborate.sml	Thu Jul 03 11:04:25 2008 -0400
+++ b/src/elaborate.sml	Thu Jul 03 16:26:28 2008 -0400
@@ -906,205 +906,316 @@
     end
 
 fun elabExp (env, denv) (e, loc) =
-    case e of
-        L.EAnnot (e, t) =>
-        let
-            val (e', et, gs1) = elabExp (env, denv) e
-            val (t', _, gs2) = elabCon (env, denv) t
-            val gs3 = checkCon (env, denv) e' et t'
-        in
-            (e', t', gs1 @ gs2 @ gs3)
-        end
+    let
+        fun doApp (e1, e2) =
+            let
+                val (e1', t1, gs1) = elabExp (env, denv) e1
+                val (e1', t1, gs2) = elabHead (env, denv) e1' t1
+                val (e2', t2, gs3) = elabExp (env, denv) e2
 
-      | L.EPrim p => ((L'.EPrim p, loc), primType env p, [])
-      | L.EVar ([], s) =>
-        (case E.lookupE env s of
-             E.NotBound =>
-             (expError env (UnboundExp (loc, s));
-              (eerror, cerror, []))
-           | E.Rel (n, t) => ((L'.ERel n, loc), t, [])
-           | E.Named (n, t) => ((L'.ENamed n, loc), t, []))
-      | L.EVar (m1 :: ms, s) =>
-        (case E.lookupStr env m1 of
-             NONE => (expError env (UnboundStrInExp (loc, m1));
-                      (eerror, cerror, []))
-           | SOME (n, sgn) =>
-             let
-                 val (str, sgn) = foldl (fn (m, (str, sgn)) =>
-                                     case E.projectStr env {sgn = sgn, str = str, field = m} of
-                                         NONE => (conError env (UnboundStrInCon (loc, m));
-                                                  (strerror, sgnerror))
-                                       | SOME sgn => ((L'.StrProj (str, m), loc), sgn))
-                                  ((L'.StrVar n, loc), sgn) ms
+                val dom = cunif (loc, ktype)
+                val ran = cunif (loc, ktype)
+                val t = (L'.TFun (dom, ran), dummy)
 
-                 val t = case E.projectVal env {sgn = sgn, str = str, field = s} of
-                             NONE => (expError env (UnboundExp (loc, s));
-                                      cerror)
-                           | SOME t => t
-             in
-                 ((L'.EModProj (n, ms, s), loc), t, [])
-             end)
+                val gs4 = checkCon (env, denv) e1' t1 t
+                val gs5 = checkCon (env, denv) e2' t2 dom
+            in
+                ((L'.EApp (e1', e2'), loc), ran, gs1 @ gs2 @ gs3 @ gs4 @ gs5)
+            end
+    in
+        case e of
+            L.EAnnot (e, t) =>
+            let
+                val (e', et, gs1) = elabExp (env, denv) e
+                val (t', _, gs2) = elabCon (env, denv) t
+                val gs3 = checkCon (env, denv) e' et t'
+            in
+                (e', t', gs1 @ gs2 @ gs3)
+            end
 
-      | L.EApp (e1, e2) =>
-        let
-            val (e1', t1, gs1) = elabExp (env, denv) e1
-            val (e1', t1, gs2) = elabHead (env, denv) e1' t1
-            val (e2', t2, gs3) = elabExp (env, denv) e2
+          | L.EPrim p => ((L'.EPrim p, loc), primType env p, [])
+          | L.EVar ([], s) =>
+            (case E.lookupE env s of
+                 E.NotBound =>
+                 (expError env (UnboundExp (loc, s));
+                  (eerror, cerror, []))
+               | E.Rel (n, t) => ((L'.ERel n, loc), t, [])
+               | E.Named (n, t) => ((L'.ENamed n, loc), t, []))
+          | L.EVar (m1 :: ms, s) =>
+            (case E.lookupStr env m1 of
+                 NONE => (expError env (UnboundStrInExp (loc, m1));
+                          (eerror, cerror, []))
+               | SOME (n, sgn) =>
+                 let
+                     val (str, sgn) = foldl (fn (m, (str, sgn)) =>
+                                                case E.projectStr env {sgn = sgn, str = str, field = m} of
+                                                    NONE => (conError env (UnboundStrInCon (loc, m));
+                                                             (strerror, sgnerror))
+                                                  | SOME sgn => ((L'.StrProj (str, m), loc), sgn))
+                                            ((L'.StrVar n, loc), sgn) ms
 
-            val dom = cunif (loc, ktype)
-            val ran = cunif (loc, ktype)
-            val t = (L'.TFun (dom, ran), dummy)
+                     val t = case E.projectVal env {sgn = sgn, str = str, field = s} of
+                                 NONE => (expError env (UnboundExp (loc, s));
+                                          cerror)
+                               | SOME t => t
+                 in
+                     ((L'.EModProj (n, ms, s), loc), t, [])
+                 end)
 
-            val gs4 = checkCon (env, denv) e1' t1 t
-            val gs5 = checkCon (env, denv) e2' t2 dom
-        in
-            ((L'.EApp (e1', e2'), loc), ran, gs1 @ gs2 @ gs3 @ gs4 @ gs5)
-        end
-      | L.EAbs (x, to, e) =>
-        let
-            val (t', gs1) = case to of
-                                NONE => (cunif (loc, ktype), [])
-                              | SOME t =>
-                                let
-                                    val (t', tk, gs) = elabCon (env, denv) t
-                                in
-                                    checkKind env t' tk ktype;
-                                    (t', gs)
-                                end
-            val (e', et, gs2) = elabExp (E.pushERel env x t', denv) e
-        in
-            ((L'.EAbs (x, t', et, e'), loc),
-             (L'.TFun (t', et), loc),
-             gs1 @ gs2)
-        end
-      | L.ECApp (e, c) =>
-        let
-            val (e', et, gs1) = elabExp (env, denv) e
-            val (e', et, gs2) = elabHead (env, denv) e' et
-            val (c', ck, gs3) = elabCon (env, denv) c
-            val ((et', _), gs4) = hnormCon (env, denv) et
-        in
-            case et' of
-                L'.CError => (eerror, cerror, [])
-              | L'.TCFun (_, _, k, eb) =>
-                let
-                    val () = checkKind env c' ck k
-                    val eb' = subConInCon (0, c') eb
-                              handle SynUnif => (expError env (Unif ("substitution", eb));
-                                                 cerror)
-                in
-                    ((L'.ECApp (e', c'), loc), eb', gs1 @ gs2 @ gs3 @ gs4)
-                end
+          | L.EApp (arg as ((L.EApp ((L.ECApp ((L.EVar (["Basis"], "join"), _), (L.CWild _, _)), _), xml1), _), xml2)) =>
+            let
+                val (xml1', t1, gs1) = elabExp (env, denv) xml1
+                val (xml2', t2, gs2) = elabExp (env, denv) xml2
 
-              | L'.CUnif _ =>
-                (expError env (Unif ("application", et));
-                 (eerror, cerror, []))
+                val kunit = (L'.KUnit, loc)
+                val k = (L'.KRecord kunit, loc)
 
-              | _ =>
-                (expError env (WrongForm ("constructor function", e', et));
-                 (eerror, cerror, []))
-        end
-      | L.ECAbs (expl, x, k, e) =>
-        let
-            val expl' = elabExplicitness expl
-            val k' = elabKind k
-            val (e', et, gs) = elabExp (E.pushCRel env x k', D.enter denv) e
-        in
-            ((L'.ECAbs (expl', x, k', e'), loc),
-             (L'.TCFun (expl', x, k', et), loc),
-             gs)
-        end
+                val basis =
+                    case E.lookupStr env "Basis" of
+                        NONE => raise Fail "elabExp: Unbound Basis"
+                      | SOME (n, _) => n
 
-      | L.EDisjoint (c1, c2, e) =>
-        let
-            val (c1', k1, gs1) = elabCon (env, denv) c1
-            val (c2', k2, gs2) = elabCon (env, denv) c2
+                fun xml () =
+                    let
+                        val ns = cunif (loc, k)
+                    in
+                        (ns, (L'.CApp ((L'.CModProj (basis, [], "xml"), loc), ns), loc))
+                    end
 
-            val ku1 = kunif loc
-            val ku2 = kunif loc
+                val (ns1, c1) = xml ()
+                val (ns2, c2) = xml ()
 
-            val (denv', gs3) = D.assert env denv (c1', c2')
-            val (e', t, gs4) = elabExp (env, denv') e
-        in
-            checkKind env c1' k1 (L'.KRecord ku1, loc);
-            checkKind env c2' k2 (L'.KRecord ku2, loc);
+                val gs3 = checkCon (env, denv) xml1' t1 c1
+                val gs4 = checkCon (env, denv) xml2' t2 c2
 
-            (e', (L'.TDisjoint (c1', c2', t), loc), gs1 @ gs2 @ gs3 @ gs4)
-        end
+                val (ns1, gs5) = hnormCon (env, denv) ns1
+                val (ns2, gs6) = hnormCon (env, denv) ns2
 
-      | L.ERecord xes =>
-        let
-            val (xes', gs) = ListUtil.foldlMap (fn ((x, e), gs) =>
-                                                   let
-                                                       val (x', xk, gs1) = elabCon (env, denv) x
-                                                       val (e', et, gs2) = elabExp (env, denv) e
-                                                   in
-                                                       checkKind env x' xk kname;
-                                                       ((x', e', et), gs1 @ gs2 @ gs)
-                                                   end)
-                                               [] xes
+                val cemp = (L'.CRecord (kunit, []), loc)
 
-            val k = (L'.KType, loc)
+                val (shared, ctx1, ctx2) =
+                    case (#1 ns1, #1 ns2) of
+                        (L'.CRecord (_, ns1), L'.CRecord (_, ns2)) =>
+                        let
+                            val ns = List.filter (fn ((nm, _), _) =>
+                                                     case nm of
+                                                         L'.CName s =>
+                                                         List.exists (fn ((L'.CName s', _), _) => s' = s
+                                                                       | _ => false) ns2
+                                                       | _ => false) ns1
+                        in
+                            ((L'.CRecord (kunit, ns), loc), cunif (loc, k), cunif (loc, k))
+                        end
+                      | (_, L'.CRecord _) => (ns2, cemp, cemp)
+                      | _ => (ns1, cemp, cemp)
 
-            fun prove (xets, gs) =
-                case xets of
-                    [] => gs
-                  | (x, _, t) :: rest =>
+                val ns1' = (L'.CConcat (shared, ctx1), loc)
+                val ns2' = (L'.CConcat (shared, ctx2), loc)
+
+                val e = (L'.EModProj (basis, [], "join"), loc)
+                val e = (L'.ECApp (e, shared), loc)
+                val e = (L'.ECApp (e, ctx1), loc)
+                val e = (L'.ECApp (e, ctx2), loc)
+                val e = (L'.EApp (e, xml1'), loc)
+                val e = (L'.EApp (e, xml2'), loc)
+
+                val t = (L'.CApp ((L'.CModProj (basis, [], "xml"), loc), shared), loc)
+
+                fun doUnify (ns, ns') =
                     let
-                        val xc = (x, t)
-                        val r1 = (L'.CRecord (k, [xc]), loc)
-                        val gs = foldl (fn ((x', _, t'), gs) =>
-                                           let
-                                               val xc' = (x', t')
-                                               val r2 = (L'.CRecord (k, [xc']), loc)
-                                           in
-                                               D.prove env denv (r1, r2, loc) @ gs
-                                           end)
-                                 gs rest
+                        fun setEmpty c =
+                            let
+                                val ((c, _), gs) = hnormCon (env, denv) c
+                            in
+                                case c of
+                                    L'.CUnif (_, _, _, r) =>
+                                    (r := SOME cemp;
+                                     gs)
+                                  | L'.CConcat (_, c') => setEmpty c' @ gs
+                                  | _ => gs
+                            end
+
+                        val gs1 = unifyCons (env, denv) ns ns'
+                        val gs2 = setEmpty ns'
+                        val gs3 = unifyCons (env, denv) ns ns'
                     in
-                        prove (rest, gs)
+                        gs1 @ gs2 @ gs3
                     end
-        in
-            ((L'.ERecord xes', loc),
-             (L'.TRecord (L'.CRecord (ktype, map (fn (x', _, et) => (x', et)) xes'), loc), loc),
-             prove (xes', gs))
-        end
 
-      | L.EField (e, c) =>
-        let
-            val (e', et, gs1) = elabExp (env, denv) e
-            val (c', ck, gs2) = elabCon (env, denv) c
+                val gs7 = doUnify (ns1, ns1')
+                val gs8 = doUnify (ns2, ns2')
+            in
+                (e, t, (loc, env, denv, shared, ctx1)
+                       :: (loc, env, denv, shared, ctx2)
+                       :: gs1 @ gs2 @ gs3 @ gs4 @ gs5 @ gs6 @ gs7 @ gs8)
+            end
 
-            val ft = cunif (loc, ktype)
-            val rest = cunif (loc, ktype_record)
-            val first = (L'.CRecord (ktype, [(c', ft)]), loc)
-                       
-            val gs3 =
-                checkCon (env, denv) e' et
-                         (L'.TRecord (L'.CConcat (first, rest), loc), loc)
-            val gs4 = D.prove env denv (first, rest, loc)
-        in
-            ((L'.EField (e', c', {field = ft, rest = rest}), loc), ft, gs1 @ gs2 @ gs3 @ gs4)
-        end
+          | L.EApp (e1, e2) =>
+            let
+                val (e1', t1, gs1) = elabExp (env, denv) e1
+                val (e1', t1, gs2) = elabHead (env, denv) e1' t1
+                val (e2', t2, gs3) = elabExp (env, denv) e2
 
-      | L.EFold =>
-        let
-            val dom = kunif loc
-        in
-            ((L'.EFold dom, loc), foldType (dom, loc), [])
-        end
+                val dom = cunif (loc, ktype)
+                val ran = cunif (loc, ktype)
+                val t = (L'.TFun (dom, ran), dummy)
+
+                val gs4 = checkCon (env, denv) e1' t1 t
+                val gs5 = checkCon (env, denv) e2' t2 dom
+            in
+                ((L'.EApp (e1', e2'), loc), ran, gs1 @ gs2 @ gs3 @ gs4 @ gs5)
+            end
+          | L.EAbs (x, to, e) =>
+            let
+                val (t', gs1) = case to of
+                                    NONE => (cunif (loc, ktype), [])
+                                  | SOME t =>
+                                    let
+                                        val (t', tk, gs) = elabCon (env, denv) t
+                                    in
+                                        checkKind env t' tk ktype;
+                                        (t', gs)
+                                    end
+                val (e', et, gs2) = elabExp (E.pushERel env x t', denv) e
+            in
+                ((L'.EAbs (x, t', et, e'), loc),
+                 (L'.TFun (t', et), loc),
+                 gs1 @ gs2)
+            end
+          | L.ECApp (e, c) =>
+            let
+                val (e', et, gs1) = elabExp (env, denv) e
+                val (e', et, gs2) = elabHead (env, denv) e' et
+                val (c', ck, gs3) = elabCon (env, denv) c
+                val ((et', _), gs4) = hnormCon (env, denv) et
+            in
+                case et' of
+                    L'.CError => (eerror, cerror, [])
+                  | L'.TCFun (_, _, k, eb) =>
+                    let
+                        val () = checkKind env c' ck k
+                        val eb' = subConInCon (0, c') eb
+                            handle SynUnif => (expError env (Unif ("substitution", eb));
+                                               cerror)
+                    in
+                        ((L'.ECApp (e', c'), loc), eb', gs1 @ gs2 @ gs3 @ gs4)
+                    end
+
+                  | L'.CUnif _ =>
+                    (expError env (Unif ("application", et));
+                     (eerror, cerror, []))
+
+                  | _ =>
+                    (expError env (WrongForm ("constructor function", e', et));
+                     (eerror, cerror, []))
+            end
+          | L.ECAbs (expl, x, k, e) =>
+            let
+                val expl' = elabExplicitness expl
+                val k' = elabKind k
+                val (e', et, gs) = elabExp (E.pushCRel env x k', D.enter denv) e
+            in
+                ((L'.ECAbs (expl', x, k', e'), loc),
+                 (L'.TCFun (expl', x, k', et), loc),
+                 gs)
+            end
+
+          | L.EDisjoint (c1, c2, e) =>
+            let
+                val (c1', k1, gs1) = elabCon (env, denv) c1
+                val (c2', k2, gs2) = elabCon (env, denv) c2
+
+                val ku1 = kunif loc
+                val ku2 = kunif loc
+
+                val (denv', gs3) = D.assert env denv (c1', c2')
+                val (e', t, gs4) = elabExp (env, denv') e
+            in
+                checkKind env c1' k1 (L'.KRecord ku1, loc);
+                checkKind env c2' k2 (L'.KRecord ku2, loc);
+
+                (e', (L'.TDisjoint (c1', c2', t), loc), gs1 @ gs2 @ gs3 @ gs4)
+            end
+
+          | L.ERecord xes =>
+            let
+                val (xes', gs) = ListUtil.foldlMap (fn ((x, e), gs) =>
+                                                       let
+                                                           val (x', xk, gs1) = elabCon (env, denv) x
+                                                           val (e', et, gs2) = elabExp (env, denv) e
+                                                       in
+                                                           checkKind env x' xk kname;
+                                                           ((x', e', et), gs1 @ gs2 @ gs)
+                                                       end)
+                                                   [] xes
+
+                val k = (L'.KType, loc)
+
+                fun prove (xets, gs) =
+                    case xets of
+                        [] => gs
+                      | (x, _, t) :: rest =>
+                        let
+                            val xc = (x, t)
+                            val r1 = (L'.CRecord (k, [xc]), loc)
+                            val gs = foldl (fn ((x', _, t'), gs) =>
+                                               let
+                                                   val xc' = (x', t')
+                                                   val r2 = (L'.CRecord (k, [xc']), loc)
+                                               in
+                                                   D.prove env denv (r1, r2, loc) @ gs
+                                               end)
+                                           gs rest
+                        in
+                            prove (rest, gs)
+                        end
+            in
+                ((L'.ERecord xes', loc),
+                 (L'.TRecord (L'.CRecord (ktype, map (fn (x', _, et) => (x', et)) xes'), loc), loc),
+                 prove (xes', gs))
+            end
+
+          | L.EField (e, c) =>
+            let
+                val (e', et, gs1) = elabExp (env, denv) e
+                val (c', ck, gs2) = elabCon (env, denv) c
+
+                val ft = cunif (loc, ktype)
+                val rest = cunif (loc, ktype_record)
+                val first = (L'.CRecord (ktype, [(c', ft)]), loc)
+                            
+                val gs3 =
+                    checkCon (env, denv) e' et
+                             (L'.TRecord (L'.CConcat (first, rest), loc), loc)
+                val gs4 = D.prove env denv (first, rest, loc)
+            in
+                ((L'.EField (e', c', {field = ft, rest = rest}), loc), ft, gs1 @ gs2 @ gs3 @ gs4)
+            end
+
+          | L.EFold =>
+            let
+                val dom = kunif loc
+            in
+                ((L'.EFold dom, loc), foldType (dom, loc), [])
+            end
+    end
             
 
 datatype decl_error =
-         KunifsRemain of ErrorMsg.span
-       | CunifsRemain of ErrorMsg.span
+         KunifsRemain of L'.decl list
+       | CunifsRemain of L'.decl list
+
+fun lspan [] = ErrorMsg.dummySpan
+  | lspan ((_, loc) :: _) = loc
 
 fun declError env err =
     case err of
-        KunifsRemain loc =>
-        ErrorMsg.errorAt loc "Some kind unification variables are undetermined in declaration"
-      | CunifsRemain loc =>
-        ErrorMsg.errorAt loc "Some constructor unification variables are undetermined in declaration"
+        KunifsRemain ds =>
+        (ErrorMsg.errorAt (lspan ds) "Some kind unification variables are undetermined in declaration";
+         eprefaces' [("Decl", p_list_sep PD.newline (p_decl env) ds)])
+      | CunifsRemain ds =>
+        (ErrorMsg.errorAt (lspan ds) "Some constructor unification variables are undetermined in declaration";
+         eprefaces' [("Decl", p_list_sep PD.newline (p_decl env) ds)])
 
 datatype sgn_error =
          UnboundSgn of ErrorMsg.span * string
@@ -1964,14 +2075,14 @@
                     ()
                 else (
                     if List.exists kunifsInDecl ds then
-                        declError env (KunifsRemain (#2 d))
+                        declError env (KunifsRemain ds)
                     else
                         ();
                     
                     case ListUtil.search cunifsInDecl ds of
                         NONE => ()
                       | SOME loc =>
-                        declError env (CunifsRemain loc)
+                        declError env (CunifsRemain ds)
                     );
 
                 (ds, (env, gs))
--- a/src/lacweb.grm	Thu Jul 03 11:04:25 2008 -0400
+++ b/src/lacweb.grm	Thu Jul 03 16:26:28 2008 -0400
@@ -40,6 +40,7 @@
  | SYMBOL of string | CSYMBOL of string
  | LPAREN | RPAREN | LBRACK | RBRACK | LBRACE | RBRACE
  | EQ | COMMA | COLON | DCOLON | TCOLON | DOT | HASH | UNDER | UNDERUNDER
+ | DIVIDE | GT
  | CON | LTYPE | VAL | FOLD | UNIT | KUNIT
  | TYPE | NAME
  | ARROW | LARROW | DARROW
@@ -47,6 +48,10 @@
  | STRUCTURE | SIGNATURE | STRUCT | SIG | END | FUNCTOR | WHERE | EXTERN
  | INCLUDE | OPEN | CONSTRAINT | CONSTRAINTS
 
+ | XML_BEGIN of string | XML_END
+ | NOTAGS of string 
+ | BEGIN_TAG of string | END_TAG of string
+
 %nonterm
    file of decl list
  | decls of decl list
@@ -78,6 +83,8 @@
  | eapps of exp
  | eterm of exp
  | rexp of (con * exp) list
+ | xml of exp
+ | xmlOne of exp
 
 %verbose                                (* print summary of errors *)
 %pos int                                (* positions *)
@@ -268,6 +275,32 @@
 
        | FOLD                           (EFold, s (FOLDleft, FOLDright))
 
+       | XML_BEGIN xml XML_END          (xml)
+       | XML_BEGIN XML_END              (EApp ((EVar (["Basis"], "cdata"), s (XML_BEGINleft, XML_ENDright)),
+                                               (EPrim (Prim.String ""), s (XML_BEGINleft, XML_ENDright))),
+                                         s (XML_BEGINleft, XML_ENDright))
+
 rexp   :                                ([])
        | ident EQ eexp                  ([(ident, eexp)])
        | ident EQ eexp COMMA rexp       ((ident, eexp) :: rexp)
+
+xml    : xmlOne xml                  (let
+                                          val pos = s (xmlOneleft, xmlright)
+                                      in
+                                          (EApp ((EApp (
+                                                  (ECApp ((EVar (["Basis"], "join"), pos),
+                                                          (CWild (KRecord (KUnit, pos), pos), pos)), pos),
+                                                  xmlOne), pos),
+                                                  xml), pos)
+                                      end)
+       | xmlOne                      (xmlOne)
+
+xmlOne : NOTAGS                      (EApp ((EVar (["Basis"], "cdata"), s (NOTAGSleft, NOTAGSright)),
+                                            (EPrim (Prim.String NOTAGS), s (NOTAGSleft, NOTAGSright))),
+                                      s (NOTAGSleft, NOTAGSright))
+       | BEGIN_TAG DIVIDE GT         (EApp ((EApp ((EVar (["Basis"], "tag"), s (BEGIN_TAGleft, GTright)),
+                                                   (EVar ([], BEGIN_TAG), s (BEGIN_TAGleft, GTright))),
+                                             s (BEGIN_TAGleft, GTright)),
+                                            (EApp ((EVar (["Basis"], "cdata"), s (BEGIN_TAGleft, GTright)),
+                                                   (EPrim (Prim.String ""), s (BEGIN_TAGleft, GTright))),
+                                             s (BEGIN_TAGleft, GTright))), s (BEGIN_TAGleft, GTright))
--- a/src/lacweb.lex	Thu Jul 03 11:04:25 2008 -0400
+++ b/src/lacweb.lex	Thu Jul 03 16:26:28 2008 -0400
@@ -80,17 +80,42 @@
 
 end
 
+val xmlTag = ref ([] : string list)
+val xmlString = ref true
+val braceLevels = ref ([] : ((unit -> unit) * int) list)
+
+fun pushLevel s = braceLevels := (s, 1) :: (!braceLevels)
+
+fun enterBrace () =
+    case !braceLevels of
+	(s, i) :: rest => braceLevels := (s, i+1) :: rest
+      | _ => ()
+
+fun exitBrace () =
+    case !braceLevels of
+	(s, i) :: rest =>
+	if i = 1 then
+	    (braceLevels := rest;
+	     s ())
+	else
+	    braceLevels := (s, i-1) :: rest
+      | _ => ()
+
+fun initialize () = (xmlTag := [];
+		     xmlString := false)
+
 
 %%
 %header (functor LacwebLexFn(structure Tokens : Lacweb_TOKENS));
 %full
-%s COMMENT STRING;
+%s COMMENT STRING XML XMLTAG;
 
 id = [a-z_][A-Za-z0-9_']*;
 cid = [A-Z][A-Za-z0-9_']*;
 ws = [\ \t\012];
 intconst = [0-9]+;
 realconst = [0-9]+\.[0-9]*;
+notags = [^<{\n]+;
 
 %%
 
@@ -98,6 +123,10 @@
                           continue ());
 <COMMENT> \n          => (newline yypos;
                           continue ());
+<XMLTAG> \n           => (newline yypos;
+                          continue ());
+<XML> \n              => (newline yypos;
+                          Tokens.NOTAGS (yytext, yypos, yypos + size yytext));
 
 <INITIAL> {ws}+       => (lex ());
 
@@ -120,6 +149,76 @@
 			  str := #"\n" :: !str; continue());
 <STRING> .            => (str := String.sub (yytext, 0) :: !str; continue());
 
+<INITIAL> "<" {id} ">"=> (let
+			      val tag = String.substring (yytext, 1, size yytext - 2)
+			  in
+			      YYBEGIN XML;
+			      xmlTag := tag :: (!xmlTag);
+			      Tokens.XML_BEGIN (tag, yypos, yypos + size yytext)
+			  end);
+<XML> "</" {id} ">"   => (let
+			      val id = String.substring (yytext, 2, size yytext - 3)
+			  in
+			      case !xmlTag of
+			          id' :: rest =>
+			          if id = id' then
+				      (YYBEGIN INITIAL;
+				       xmlTag := rest;
+				       Tokens.XML_END (yypos, yypos + size yytext))
+			          else
+				      Tokens.END_TAG (id, yypos, yypos + size yytext)
+			        | _ => 
+			          Tokens.END_TAG (id, yypos, yypos + size yytext)
+			  end);
+
+<XML> "<" {id}        => (YYBEGIN XMLTAG;
+			  Tokens.BEGIN_TAG (String.extract (yytext, 1, NONE),
+					    yypos, yypos + size yytext));
+
+<XMLTAG> "/"          => (Tokens.DIVIDE (yypos, yypos + size yytext));
+<XMLTAG> ">"          => (YYBEGIN XML;
+			  Tokens.GT (yypos, yypos + size yytext));
+
+<XMLTAG> {ws}+        => (lex ());
+
+<XMLTAG> {id}         => (Tokens.SYMBOL (yytext, yypos, yypos + size yytext));
+<XMLTAG> "="          => (Tokens.EQ (yypos, yypos + size yytext));
+
+<XMLTAG> {intconst}   => (case Int64.fromString yytext of
+                            SOME x => Tokens.INT (x, yypos, yypos + size yytext)
+                          | NONE   => (ErrorMsg.errorAt' (yypos, yypos)
+                                       ("Expected int, received: " ^ yytext);
+                                       continue ()));
+<XMLTAG> {realconst}  => (case Real.fromString yytext of
+                            SOME x => Tokens.FLOAT (x, yypos, yypos + size yytext)
+                          | NONE   => (ErrorMsg.errorAt' (yypos, yypos)
+                                       ("Expected float, received: " ^ yytext);
+                                       continue ()));
+<XMLTAG> "\""         => (YYBEGIN STRING;
+			  xmlString := true;
+			  strStart := yypos; str := []; continue());
+
+<XMLTAG> "{"          => (YYBEGIN INITIAL;
+			  pushLevel (fn () => YYBEGIN XMLTAG);
+			  Tokens.LBRACE (yypos, yypos + 1));
+<XMLTAG> "("          => (YYBEGIN INITIAL;
+			  pushLevel (fn () => YYBEGIN XMLTAG);
+			  Tokens.LPAREN (yypos, yypos + 1));
+
+<XMLTAG> .            => (ErrorMsg.errorAt' (yypos, yypos)
+                          ("illegal XML tag character: \"" ^ yytext ^ "\"");
+                          continue ());
+
+<XML> "{"             => (YYBEGIN INITIAL;
+			  pushLevel (fn () => YYBEGIN XML);
+			  Tokens.LBRACE (yypos, yypos + 1));
+
+<XML> {notags}        => (Tokens.NOTAGS (yytext, yypos, yypos + size yytext));
+
+<XML> .               => (ErrorMsg.errorAt' (yypos, yypos)
+                          ("illegal XML character: \"" ^ yytext ^ "\"");
+                          continue ());
+
 <INITIAL> "()"        => (Tokens.UNIT (pos yypos, pos yypos + size yytext));
 <INITIAL> "("         => (Tokens.LPAREN (pos yypos, pos yypos + size yytext));
 <INITIAL> ")"         => (Tokens.RPAREN (pos yypos, pos yypos + size yytext));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/html.lac	Thu Jul 03 16:26:28 2008 -0400
@@ -0,0 +1,3 @@
+val text : xml[Html] = <html>
+        <head/>
+</html>