html.ur 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. open Parse
  2. con attribute = fn t => {Nam : string,
  3. Parse : string -> option t}
  4. con tag = fn ts => {Nam : string,
  5. Attributes : $(map attribute ts),
  6. Folder : folder ts,
  7. Construct : ctx ::: {Unit} -> [[Body] ~ ctx] => $ts
  8. -> xml ([Body] ++ ctx) [] [] -> xml ([Body] ++ ctx) [] []}
  9. fun tag [use] [ignore] [use ~ ignore] (fl : folder use) (name : string) (attrs : $(map attribute use))
  10. (construct : ctx ::: {Unit} -> [[Body] ~ ctx] => Basis.tag (use ++ ignore) ([Body] ++ ctx) ([Body] ++ ctx) [] []) =
  11. {Nam = name,
  12. Attributes = attrs,
  13. Folder = fl,
  14. Construct = fn [ctx] [[Body] ~ ctx] (ats : $use) (inner : xml ([Body] ++ ctx) [] []) =>
  15. Basis.tag null None noStyle None ats construct inner}
  16. fun simpleTag [ignore] name (bt : bodyTag ignore) : tag [] =
  17. @@tag [[]] [ignore] ! _ name {} (fn [ctx] [[Body] ~ ctx] => bt ())
  18. fun simpleTag' [use] [ignore] [use ~ ignore] (fl : folder use)
  19. name (bt : bodyTag (use ++ ignore)) (ats : $(map attribute use)) : tag use =
  20. @@tag [use] [ignore] ! fl name ats (fn [ctx] [[Body] ~ ctx] => bt ())
  21. fun url name = {Nam = name,
  22. Parse = checkUrl}
  23. datatype error a =
  24. Good of a
  25. | Bad of string
  26. fun format [tags] (fl : folder tags) (tags : $(map tag tags)) [ctx] [[Body] ~ ctx] s =
  27. let
  28. fun loop s : error (xml ([Body] ++ ctx) [] [] * string) =
  29. case String.msplit {Haystack = s, Needle = "&<"} of
  30. None => Good (cdata s, "")
  31. | Some (pre, ch, post) =>
  32. case ch of
  33. #"&" =>
  34. (case String.split post #";" of
  35. None => Bad "No ';' after '&'"
  36. | Some (code, post) =>
  37. let
  38. val xml =
  39. case code of
  40. "lt" => <xml>&lt;</xml>
  41. | "gt" => <xml>&gt;</xml>
  42. | "amp" => <xml>&amp;</xml>
  43. | _ => <xml/>
  44. in
  45. case loop post of
  46. Good (after, post) => Good (<xml>{[pre]}{xml}{after}</xml>, post)
  47. | x => x
  48. end)
  49. | _ =>
  50. if String.length post > 0 && String.sub post 0 = #"/" then
  51. case String.split post #"\x3E" of
  52. None => Bad "No '>' after '</'"
  53. | Some (_, post) => Good (<xml>{[pre]}</xml>, post)
  54. else
  55. case String.msplit {Haystack = post, Needle = " >"} of
  56. None => Bad "No '>' after '<'"
  57. | Some (tname, ch, post) =>
  58. @foldR [tag] [fn _ => unit -> error (xml ([Body] ++ ctx) [] [] * string)]
  59. (fn [nm :: Name] [ts :: {Type}] [r :: {{Type}}] [[nm] ~ r] (meta : tag ts) acc () =>
  60. if meta.Nam = tname then
  61. let
  62. fun doAttrs (ch, post, ats : $(map option ts)) =
  63. if String.length post > 0 && Char.isSpace (String.sub post 0) then
  64. doAttrs (ch, String.substring post {Start = 1,
  65. Len = String.length post - 1},
  66. ats)
  67. else
  68. case ch of
  69. #"\x3E" => Good (ats, post)
  70. | _ =>
  71. case String.split post #"=" of
  72. None =>
  73. (case String.split post #"\x3E" of
  74. None => Bad "No tag ender '\x3E'"
  75. | Some (_, post) => Good (ats, post))
  76. | Some (aname, post) =>
  77. if String.length post >= 1 && String.sub post 0 = #"\"" then
  78. case String.split (String.substring post
  79. {Start = 1,
  80. Len = String.length post
  81. - 1})
  82. #"\"" of
  83. None => Bad "No '\"' to end attribute value"
  84. | Some (aval, post) =>
  85. let
  86. val ats =
  87. @map2 [attribute] [option] [option]
  88. (fn [t] meta v =>
  89. if aname = meta.Nam then
  90. meta.Parse aval
  91. else
  92. v)
  93. meta.Folder meta.Attributes ats
  94. in
  95. doAttrs (#" ", post, ats)
  96. end
  97. else
  98. Bad "Attribute value doesn't begin with quote"
  99. in
  100. case doAttrs (ch, post, @map0 [option] (fn [t :: Type] => None)
  101. meta.Folder) of
  102. Good (ats, post) =>
  103. let
  104. val ats =
  105. @map2 [attribute] [option] [ident]
  106. (fn [t] meta v =>
  107. case v of
  108. None => error <xml>Missing attribute {[meta.Nam]}
  109. for {[tname]}</xml>
  110. | Some v => v)
  111. meta.Folder meta.Attributes ats
  112. in
  113. case loop post of
  114. Good (inner, post) =>
  115. (case loop post of
  116. Good (after, post) =>
  117. Good (<xml>{[pre]}{meta.Construct [ctx] !
  118. ats inner}{after}</xml>, post)
  119. | x => x)
  120. | x => x
  121. end
  122. | Bad s => Bad s
  123. end
  124. else
  125. acc ())
  126. (fn () => Bad ("Unknown HTML tag " ^ tname)) fl tags ()
  127. in
  128. case loop s of
  129. Bad msg => Failure msg
  130. | Good (xml, _) => Success xml
  131. end
  132. val b = simpleTag "b" @@b
  133. val i = simpleTag "i" @@i
  134. val a = simpleTag' "a" @@a {Href = url "href"}