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

Gabriel Riba gabriel at xarxaire.com
Wed Jun 17 13:37:55 EDT 2015


I have worked out the feasibility of Haskell's Hamlet style xml.

(https://hackage.haskell.org/package/hamlet)

<ixml>
<body>
   <h3> title
      $if {null item_list_expr}
         <p> Sorry, no items
      $else
         <ul>
            $for {item} <- {item_list_expr}
               <li> <b>{[item]}</b>
</ixml>

Are you interested?


I made it work.

Other logic control statements are harder to work out.

(* ----- *)

Here are some details:

Auto-closing of line-beginning tags is done on the lexer, emitting 
closing tags for precedent lines with same or deeper indentation.

To emit extra tokens on a specific input the rule can be re-executed by 
rewinding the next character pointer (yybufpos) to the precedent position:
   yybufpos := (!yybufpos) - size yytext

New lexer states:
   1.IXML state between <ixml></ixml> accepting XML state like inputs.
   2.IXML_TAG similar to XMLTAG where to distinguish indented tags to 
close from empty tags. (pending)
   3.IXML_LOGIC where to look for logic parameters

A new stack variable of indented Tags/Logic.
   Every new indented line will emit closing tokens
   for deeper or equal indented items on the stack
   (variable ixml_indents: (int * ixml_item) list)

Prevent nesting of IXML states, with an isIXML variable.

(pending)

To distinguish indented empty tags,
a tag to close must be pushed at the first only '>' IXML_TAG state 
input, iif there is no precedent '/'.
   (variable ixml_candidate_tag_to_push: string option)

The STRING state finalisation must take on account an extra state where 
to return (INITIAL, XMLTAG, IXML_TAG).

-----

Grammar additions:

  * terminals

  | IXML_FOR  | IXML_END_FOR
  | IXML_IFTHEN | IXML_END_IFTHEN | IXML_ELSE | IXML_END_ELSE

  * extra xml production rules:

(* $if $else rule:
*)

    | IXML_IFTHEN LBRACE eexp RBRACE xml IXML_END_IFTHEN
            IXML_ELSE xmlOpt IXML_END_ELSE

         (let
                 val loc = s (IXML_IFTHENleft, IXML_END_ELSEright)
         in
         (ECase (eexp, [((PCon (["Basis"], "True", NONE), loc), xml),
                         ((PCon (["Basis"], "False", NONE), loc), 
xmlOpt)]), loc)

         end)

(* $for rule:

    List.foldr join <xml/> (List.mp (fn item_patt => xml) items_expr)
*)

    | IXML_FOR LBRACE eargs RBRACE LARROW LBRACE eexp RBRACE xml 
IXML_END_FOR
         (let
         val loc = s (IXML_FORleft, IXML_END_FORright)

         val fn_item_pattern_to_xml = #1 (eargs (xml, (CWild (KType, 
loc), loc)))
         val list_map = (EVar (["List"], "mp", Infer), loc)
         val list_foldr = (EVar (["List"], "foldr", Infer), loc)
         val basis_join = (EVar (["Basis"], "join", Infer), loc)
         val xmlEmpty = (EApp ((EVar (["Basis"], "cdata", Infer), loc),
                              (EPrim (Prim.String (Prim.Html, "")), loc))
                         , loc)
         val e = (EApp (list_map, fn_item_pattern_to_xml), loc)
         val e1 = (EApp (e, eexp), loc)

         val e = (EApp (list_foldr, basis_join), loc)
         val e = (EApp (e, xmlEmpty), loc)

         in
                 (EApp (e, e1), loc)
         end
         )










More information about the Ur mailing list