# HG changeset patch # User Adam Chlipala # Date 1224016663 14400 # Node ID c1e96b387115f3efa8f69faf7de05f7875c4ed19 # Parent 465593c024ca5a26e5c4ca9530268163a7be8a3c Syntax highlighting for embedded XML diff -r 465593c024ca -r c1e96b387115 lib/top.ur --- a/lib/top.ur Mon Oct 13 15:31:02 2008 -0400 +++ b/lib/top.ur Tue Oct 14 16:37:43 2008 -0400 @@ -74,7 +74,7 @@ foldTR [tf] [fn _ => xml ctx [] []] (fn (nm :: Name) (t :: Type) (rest :: {Type}) [[nm] ~ rest] r acc => {f [nm] [t] [rest] r}{acc}) - + fun foldT2RX (tf :: (Type * Type) -> Type) (ctx :: {Unit}) (f : nm :: Name -> t :: (Type * Type) -> rest :: {(Type * Type)} @@ -84,7 +84,7 @@ (fn (nm :: Name) (t :: (Type * Type)) (rest :: {(Type * Type)}) [[nm] ~ rest] r acc => {f [nm] [t] [rest] r}{acc}) - + fun foldTRX2 (tf1 :: Type -> Type) (tf2 :: Type -> Type) (ctx :: {Unit}) (f : nm :: Name -> t :: Type -> rest :: {Type} @@ -94,7 +94,7 @@ (fn (nm :: Name) (t :: Type) (rest :: {Type}) [[nm] ~ rest] r1 r2 acc => {f [nm] [t] [rest] r1 r2}{acc}) - + fun foldT2RX2 (tf1 :: (Type * Type) -> Type) (tf2 :: (Type * Type) -> Type) (ctx :: {Unit}) @@ -105,7 +105,7 @@ (fn (nm :: Name) (t :: (Type * Type)) (rest :: {(Type * Type)}) [[nm] ~ rest] r1 r2 acc => {f [nm] [t] [rest] r1 r2}{acc}) - + fun queryX (tables ::: {{Type}}) (exps ::: {Type}) (ctx ::: {Unit}) (q : sql_query tables exps) [tables ~ exps] @@ -114,7 +114,7 @@ -> xml ctx [] []) = query q (fn fs acc => return {acc}{f fs}) - + fun oneOrNoRows (tables ::: {{Type}}) (exps ::: {Type}) (q : sql_query tables exps) [tables ~ exps] = diff -r 465593c024ca -r c1e96b387115 src/elisp/urweb-mode.el --- a/src/elisp/urweb-mode.el Mon Oct 13 15:31:02 2008 -0400 +++ b/src/elisp/urweb-mode.el Tue Oct 14 16:37:43 2008 -0400 @@ -160,24 +160,40 @@ ;; The font lock regular expressions. -(defun inXml (depth) - (and - (re-search-backward "[<>{}]" nil t) - (cond - ((looking-at "{") - (and (> depth 0) - (inXml (- depth 1)))) - ((looking-at "}") - (inXml (+ depth 1))) - ((save-excursion (backward-char 1) (or (looking-at "=>") (looking-at "->"))) - (inXml depth)) - ((looking-at "<") - nil) - ((looking-at ">") - (if (> depth 0) - (and (re-search-backward "<" nil t) - (inXml depth)) - (progn (backward-char 5) (not (looking-at "/html")))))))) +(defun inXml () + (save-excursion + (let ( + (depth 0) + (finished nil) + (answer nil) + ) + (while (and (not finished) (re-search-backward "[<>{}]" nil t)) + (cond + ((looking-at "{") + (if (> depth 0) + (setq depth (- depth 1)) + (setq finished t))) + ((looking-at "}") + (setq depth (+ depth 1))) + ((save-excursion (backward-char 1) (or (looking-at "=>") (looking-at "->"))) + nil) + ((looking-at "<") + (setq finished t)) + ((looking-at ">") + (if (> depth 0) + (if (not (re-search-backward "<" nil t)) + (setq finished t)) + (progn (backward-char 4) + (setq answer (not (or + (looking-at "/xml") + (looking-at "xml/")))) + (setq finished t)))))) + answer))) + +(defun amAttribute (face) + (if (ignore-errors (save-excursion (backward-word 2) (backward-char 1) (looking-at "<"))) + nil + face)) (defconst urweb-font-lock-keywords `(;;(urweb-font-comments-and-strings) @@ -187,25 +203,25 @@ ("\\(\\)" (1 font-lock-tag-face)) ("\\([^<>{}]+\\)" - (1 (if (save-excursion (inXml 0)) + (1 (if (inXml) font-lock-string-face nil))) ("\\<\\(fun\\|and\\)\\s-+\\(\\sw+\\)\\s-+[^ \t\n=]" (1 font-lock-keyword-face) - (2 font-lock-function-name-face)) + (2 (amAttribute font-lock-function-name-face))) ("\\<\\(\\(data\\)?type\\|con\\|class\\)\\s-+\\(\\sw+\\)" (1 font-lock-keyword-face) - (3 font-lock-type-def-face)) + (3 (amAttribute font-lock-type-def-face))) ("\\<\\(val\\|table\\|sequence\\)\\s-+\\(\\sw+\\>\\s-*\\)?\\(\\sw+\\)\\s-*[=:]" (1 font-lock-keyword-face) - (3 font-lock-variable-name-face)) + (3 (amAttribute font-lock-variable-name-face))) ("\\<\\(structure\\|functor\\)\\s-+\\(\\sw+\\)" (1 font-lock-keyword-face) - (2 font-lock-module-def-face)) + (2 (amAttribute font-lock-module-def-face))) ("\\<\\(signature\\)\\s-+\\(\\sw+\\)" (1 font-lock-keyword-face) - (2 font-lock-interface-def-face)) + (2 (amAttribute font-lock-interface-def-face))) (,urweb-keywords-regexp . font-lock-keyword-face) (,urweb-sql-keywords-regexp . font-lock-sql-face) @@ -336,12 +352,6 @@ ;;;###autoload (add-to-list 'auto-mode-alist '("\\.s\\(ml\\|ig\\)\\'" . urweb-mode)) -;(mmm-add-classes -; '((urweb-html -; :submode html-mode -; :front "" -; :back ""))) - ;;;###autoload (define-derived-mode urweb-mode fundamental-mode "Ur/Web" "\\Major mode for editing Ur/Web code. @@ -363,14 +373,10 @@ ;; For XEmacs (easy-menu-add urweb-mode-menu) -; (setq mmm-classes '(urweb-html)) - ;; Compatibility. FIXME: we should use `-' in Emacs-CVS. (unless (boundp 'skeleton-positions) (set (make-local-variable '@) nil)) - (urweb-mode-variables) -; (mmm-mode-on) - ) + (urweb-mode-variables)) (defun urweb-mode-variables () (set-syntax-table urweb-mode-syntax-table) diff -r 465593c024ca -r c1e96b387115 src/urweb.grm --- a/src/urweb.grm Mon Oct 13 15:31:02 2008 -0400 +++ b/src/urweb.grm Tue Oct 14 16:37:43 2008 -0400 @@ -193,7 +193,7 @@ | INCLUDE | OPEN | CONSTRAINT | CONSTRAINTS | EXPORT | TABLE | SEQUENCE | CASE | IF | THEN | ELSE - | XML_BEGIN of string | XML_END + | XML_BEGIN of string | XML_END | XML_BEGIN_END of string | NOTAGS of string | BEGIN_TAG of string | END_TAG of string @@ -801,10 +801,37 @@ end) | 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)) + | XML_BEGIN xml XML_END (let + val loc = s (XML_BEGINleft, XML_ENDright) + in + if XML_BEGIN = "xml" then + () + else + ErrorMsg.errorAt loc "Initial XML tag pair aren't both tagged \"xml\"."; + xml + end) + | XML_BEGIN XML_END (let + val loc = s (XML_BEGINleft, XML_ENDright) + in + if XML_BEGIN = "xml" then + () + else + ErrorMsg.errorAt loc "Initial XML tag pair aren't both tagged \"xml\"."; + (EApp ((EVar (["Basis"], "cdata"), loc), + (EPrim (Prim.String ""), loc)), + loc) + end) + | XML_BEGIN_END (let + val loc = s (XML_BEGIN_ENDleft, XML_BEGIN_ENDright) + in + if XML_BEGIN_END = "xml" then + () + else + ErrorMsg.errorAt loc "Initial XML tag pair aren't both tagged \"xml\"."; + (EApp ((EVar (["Basis"], "cdata"), loc), + (EPrim (Prim.String ""), loc)), + loc) + end) | LPAREN query RPAREN (query) | LPAREN CWHERE sqlexp RPAREN (sqlexp) diff -r 465593c024ca -r c1e96b387115 src/urweb.lex --- a/src/urweb.lex Mon Oct 13 15:31:02 2008 -0400 +++ b/src/urweb.lex Tue Oct 14 16:37:43 2008 -0400 @@ -162,6 +162,11 @@ continue ()) end); + "<" {id} "/>"=>(let + val tag = String.substring (yytext, 1, size yytext - 3) + in + Tokens.XML_BEGIN_END (tag, yypos, yypos + size yytext) + end); "<" {id} ">"=> (let val tag = String.substring (yytext, 1, size yytext - 2) in diff -r 465593c024ca -r c1e96b387115 tests/crud.ur --- a/tests/crud.ur Mon Oct 13 15:31:02 2008 -0400 +++ b/tests/crud.ur Tue Oct 14 16:37:43 2008 -0400 @@ -28,74 +28,74 @@ () <- dml (insert tab (foldT2R2 [sndTT] [colMeta] [fn cols => $(mapT2T (fn t :: (Type * Type) => sql_exp [] [] [] t.1) cols)] - (fn (nm :: Name) (t :: (Type * Type)) (rest :: {(Type * Type)}) => - [[nm] ~ rest] => - fn input col acc => acc with nm = sql_inject col.Inject (col.Parse input)) + (fn (nm :: Name) (t :: (Type * Type)) (rest :: {(Type * Type)}) + [[nm] ~ rest] => + fn input col acc => acc with nm = sql_inject col.Inject (col.Parse input)) {} [M.cols] inputs M.cols with #Id = (SQL {id}))); - return + return Inserted with ID {txt _ id}. - + fun save (id : int) (inputs : $(mapT2T sndTT M.cols)) = () <- dml (update [mapT2T fstTT M.cols] (foldT2R2 [sndTT] [colMeta] [fn cols => $(mapT2T (fn t :: (Type * Type) => sql_exp [T = [Id = int] ++ mapT2T fstTT M.cols] [] [] t.1) cols)] - (fn (nm :: Name) (t :: (Type * Type)) (rest :: {(Type * Type)}) => - [[nm] ~ rest] => - fn input col acc => acc with nm = sql_inject col.Inject (col.Parse input)) + (fn (nm :: Name) (t :: (Type * Type)) (rest :: {(Type * Type)}) + [[nm] ~ rest] => + fn input col acc => acc with nm = sql_inject col.Inject (col.Parse input)) {} [M.cols] inputs M.cols) tab (WHERE T.Id = {id})); - return + return Saved! - + fun update (id : int) = fso <- oneOrNoRows (SELECT tab.{{mapT2T fstTT M.cols}} FROM tab WHERE tab.Id = {id}); case fso : (Basis.option {Tab : $(mapT2T fstTT M.cols)}) of - None => return Not found! - | Some fs => return + None => return Not found! + | Some fs => return {foldT2R2 [fstTT] [colMeta] [fn cols :: {(Type * Type)} => xml form [] (mapT2T sndTT cols)] - (fn (nm :: Name) (t :: (Type * Type)) (rest :: {(Type * Type)}) => - [[nm] ~ rest] => - fn (v : t.1) (col : colMeta t) (acc : xml form [] (mapT2T sndTT rest)) => -
  • {cdata col.Nam}: {col.WidgetPopulated [nm] v}
  • - {useMore acc} -
    ) - + (fn (nm :: Name) (t :: (Type * Type)) (rest :: {(Type * Type)}) + [[nm] ~ rest] (v : t.1) (col : colMeta t) + (acc : xml form [] (mapT2T sndTT rest)) => + +
  • {cdata col.Nam}: {col.WidgetPopulated [nm] v}
  • + {useMore acc} +
    ) + [M.cols] fs.Tab M.cols} -
    +
    fun delete (id : int) = () <- dml (DELETE FROM tab WHERE Id = {id}); - return + return The deed is done. - + -fun confirm (id : int) = return +fun confirm (id : int) = return

    Are you sure you want to delete ID #{txt _ id}?

    I was born sure!

    - +
    fun main () = rows <- queryX (SELECT * FROM tab AS T) - (fn (fs : {T : $([Id = int] ++ mapT2T fstTT M.cols)}) => + (fn (fs : {T : $([Id = int] ++ mapT2T fstTT M.cols)}) => {txt _ fs.T.Id} {foldT2RX2 [fstTT] [colMeta] [tr] - (fn (nm :: Name) (t :: (Type * Type)) (rest :: {(Type * Type)}) => - [[nm] ~ rest] => - fn v col => + (fn (nm :: Name) (t :: (Type * Type)) (rest :: {(Type * Type)}) + [[nm] ~ rest] v col => {col.Show v} - ) + ) [M.cols] (fs.T -- #Id) M.cols} [Update] [Delete] - ); - return + ); + return {cdata M.title} @@ -106,11 +106,10 @@ ID {foldT2RX [colMeta] [tr] - (fn (nm :: Name) (t :: (Type * Type)) (rest :: {(Type * Type)}) => - [[nm] ~ rest] => - fn col => + (fn (nm :: Name) (t :: (Type * Type)) (rest :: {(Type * Type)}) + [[nm] ~ rest] col => {cdata col.Nam} - ) + ) [M.cols] M.cols} {rows} @@ -120,17 +119,16 @@ {foldT2R [colMeta] [fn cols :: {(Type * Type)} => xml form [] (mapT2T sndTT cols)] - (fn (nm :: Name) (t :: (Type * Type)) (rest :: {(Type * Type)}) => - [[nm] ~ rest] => - fn (col : colMeta t) (acc : xml form [] (mapT2T sndTT rest)) => + (fn (nm :: Name) (t :: (Type * Type)) (rest :: {(Type * Type)}) + [[nm] ~ rest] (col : colMeta t) (acc : xml form [] (mapT2T sndTT rest)) =>
  • {cdata col.Nam}: {col.Widget [nm]}
  • {useMore acc} -
    ) - +
    ) + [M.cols] M.cols} - + end diff -r 465593c024ca -r c1e96b387115 tests/crud1.ur --- a/tests/crud1.ur Mon Oct 13 15:31:02 2008 -0400 +++ b/tests/crud1.ur Tue Oct 14 16:37:43 2008 -0400 @@ -2,33 +2,33 @@ val a = {Nam = "A", Show = txt _, - Widget = fn nm :: Name => , + Widget = fn nm :: Name => , WidgetPopulated = fn (nm :: Name) n => - , + , Parse = readError _, Inject = _} val b = {Nam = "B", Show = txt _, - Widget = fn nm :: Name => , + Widget = fn nm :: Name => , WidgetPopulated = fn (nm :: Name) s => - , + , Parse = readError _, Inject = _} val c = {Nam = "C", Show = txt _, - Widget = fn nm :: Name => , + Widget = fn nm :: Name => , WidgetPopulated = fn (nm :: Name) n => - , + , Parse = readError _, Inject = _} val d = {Nam = "D", Show = txt _, - Widget = fn nm :: Name => , + Widget = fn nm :: Name => , WidgetPopulated = fn (nm :: Name) b => - , + , Parse = fn x => x, Inject = _}