[Ur] Hamlet like XML, structured by indentation with tag autoclosing

Gabriel Riba gabriel at xarxaire.com
Mon Jun 29 10:34:23 EDT 2015


El 26/06/15 a les 18:12, Adam Chlipala ha escrit:
> I appreciate your ongoing efforts to improve the usability of Ur/Web.
> Based on discussion here so far, I'm leaning towards not adopting your
> additional syntax extensions.  Subjectively to me, they don't make the
> code more readable, while they do introduce more independent notations
> to be understood.

I bring here some documentation and a mercurial patch of the trial 
worked, for the case anyone wanted to try it.

Summary Documentation of the Indented XML, with lines' first tag 
autoclosing and logic

(* Example with $foldlmapx, $if/$elsif/$else alternatives *)

val testl : list int = 1 :: 2 :: 3 :: 4 :: []

fun main (): transaction page = return <ixml>
<body>
     $foldlmapx {testl} <| {x}
         $if {x = 1}
           <p>1
         $elsif {x = 2}
           <p>2
         $elsif {x = 3}
           <p>3
         $else
           <p>other
</ixml>

(* Example with $foldlmapx, $case/$of alternatives *)

val testOpts : list (option int) = Some 3 :: None :: []

fun main (): transaction page = return <ixml>
<body>
     $foldlmapx {testOpts} <| {x}
       $case {x}
       $of {Some v}
           <p>Some {[v]}
       $of {None}
           <p>None
</ixml>

(* Example derived from the web demo "Sql" with $foldrmapx *)

table t : { A : int, B : float, C : string, D : bool }
   PRIMARY KEY A

type t_qry_item = {T: { A : int, B : float, C : string, D : bool }}

fun main () =
     rows <- queryL (SELECT * FROM t) ;

     return <ixml>
<body>
     <table>
         <tr> <th>A</th> <th>B</th> <th>C</th> <th>D</th>
         $foldrmapx {rows} <| {row : t_qry_item}
              <tr>
                  <td>{[row.T.A]}
                  <td>{[row.T.B]}
                  <td>{[row.T.C]}
                  <td>{[row.T.D]}
</ixml>

(* 
-------------------------------------------------------------------------------------- 
*)

Grammar productions added (BNF):

xmlOne: ...
        | IXML_FOLDRMAP LBRACE eexp RBRACE FWDAPP LBRACE eargs RBRACE 
xml IXML_END_FOLDRMAP

        | IXML_FOLDLMAP LBRACE eexp RBRACE FWDAPP LBRACE eargs RBRACE 
xml IXML_END_FOLDLMAP

        | IXML_IFTHEN LBRACE eexp RBRACE xml IXML_END_IFTHEN ixml_elsifs 
IXML_ELSE xmlOpt IXML_END_ELSE

        | IXML_CASE_EXPR LBRACE eexp RBRACE IXML_END_CASE_EXPR ixml_caseOfs

(* --- *)

ixml_elsif : IXML_ELSIF LBRACE eexp RBRACE xml IXML_END_ELSIF

ixml_elsifs : (* empty *)
             | ixml_elsifs ixml_elsif


ixml_caseOf : IXML_CASE_OF LBRACE pat RBRACE xml IXML_END_CASE_OF

ixml_caseOfs : ixml_caseOf
             | ixml_caseOfs ixml_caseOf

(* --- terminals *)

%term
  | IXML_FOLDRMAP  | IXML_END_FOLDRMAP | IXML_FOLDLMAP  | IXML_END_FOLDLMAP
  | IXML_IFTHEN | IXML_END_IFTHEN | IXML_ELSE | IXML_END_ELSE | 
IXML_ELSIF | IXML_END_ELSIF
  | IXML_CASE_EXPR | IXML_END_CASE_EXPR | IXML_CASE_OF | IXML_END_CASE_OF

(* --- non-terminals *)

%nonterm

  | ixml_elsif of (exp * exp)
  | ixml_elsifs of (exp * exp) list
  | ixml_caseOf of pat * exp
  | ixml_caseOfs of (pat * exp) list

(* ----------------------------------------------------------------- *)

Lexer:

new lexer states: IXML IXMLTAG IXML_LOGIC

datatype xmlStringContext = SC_XMLTAG | SC_IXMLTAG

val xmlString = ref (NONE : xmlStringContext option)

val isIXML = ref false
val ixml_candidate_tag_to_push = ref (NONE: (int * string) option)

datatype ixml_logic = IXL_FoldrMap | IXL_FoldlMap
                       | IXL_IfThen | IXL_Else | IXL_Elsif
                       | IXL_CaseExpr | IXL_CaseOf

datatype ixml_item = IX_Tag of string | IX_Logic of ixml_logic

val ixml_indents = ref ([] : (int * ixml_item) list)

val ixml_pop_deeper_or_same_level_items: int -> ixml_item option = fn 
indent =>
    case !ixml_indents of
      [] => NONE
      | (lastIndent, item) :: _ => if lastIndent >= indent then
                                      (ixml_indents := tl 
(!ixml_indents) ; SOME item)
                                   else NONE

val ixml_emit_item_closing_and_rewind: (ixml_item * int ref * string * 
int) -> (svalue,pos) Tokens.token =
    fn (item, yybufpos, yytext, yypos) =>
    ((* rewind yybufpos *) yybufpos := (!yybufpos) - size yytext ;
    case item of
           (IX_Tag tag_to_close) => Tokens.END_TAG (tag_to_close, yypos, 
yypos + size yytext)
         | (IX_Logic ixl) => (case ixl of
                   IXL_FoldrMap => Tokens.IXML_END_FOLDRMAP (yypos, 
yypos + size yytext)
                 | IXL_FoldlMap => Tokens.IXML_END_FOLDLMAP (yypos, 
yypos + size yytext)
                 | IXL_IfThen => Tokens.IXML_END_IFTHEN (yypos, yypos + 
size yytext)
                 | IXL_Else => Tokens.IXML_END_ELSE (yypos, yypos + size 
yytext)
                 | IXL_Elsif => Tokens.IXML_END_ELSIF (yypos, yypos + 
size yytext)
                 | IXL_CaseExpr => Tokens.IXML_END_CASE_EXPR (yypos, 
yypos + size yytext)
                 | IXL_CaseOf => Tokens.IXML_END_CASE_OF (yypos, yypos + 
size yytext)
                 )
    )

(* ---- definitions *)

%%
indent = \n(\ )*;
spcs = (\ )*;

...

More in the attached patch.







More information about the Ur mailing list