util.ml 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. open Printf
  2. open Types
  3. (** Operators *)
  4. let (|>) a b = b a
  5. (** List utilities *)
  6. let rec filter_none = function
  7. | [] -> []
  8. | None :: tl -> filter_none tl
  9. | Some hd :: tl -> hd :: filter_none tl
  10. (** Reading input from file/stdin *)
  11. let input_all ic =
  12. let n = in_channel_length ic in
  13. let buf = String.create n in
  14. really_input ic buf 0 n;
  15. close_in ic;
  16. buf
  17. let input_buffered ic chunksize =
  18. let rec read_all buf bufsize pos =
  19. match input ic buf pos (bufsize - pos) with
  20. | 0 -> (close_in ic; buf)
  21. | nread when nread = bufsize - pos ->
  22. let bufsize = bufsize + chunksize in
  23. let pos = pos + nread in
  24. read_all (buf ^ String.create chunksize) bufsize pos
  25. | nread ->
  26. read_all buf bufsize (pos + nread)
  27. in
  28. read_all (String.create chunksize) chunksize 0
  29. (** Error printing *)
  30. let noloc = ("", 0, 0, 0, 0)
  31. let tabwidth = 4
  32. let count_tabs str upto =
  33. let rec count n = function
  34. | 0 -> n
  35. | i -> count (if String.get str (i - 1) = '\t' then n + 1 else n) (i - 1)
  36. in
  37. count 0 upto
  38. let rec repeat s n = if n < 1 then "" else s ^ (repeat s (n - 1))
  39. let retab str = Str.global_replace (Str.regexp "\t") (repeat " " tabwidth) str
  40. let indent n = repeat (repeat " " (tabwidth - 1)) n
  41. let prerr_loc (fname, ystart, yend, xstart, xend) =
  42. let file = open_in fname in
  43. (* skip lines until the first matched line *)
  44. for i = 1 to ystart - 1 do ignore (input_line file) done;
  45. (* for each line in `loc`, print the source line with an underline *)
  46. for l = ystart to yend do
  47. let line = input_line file in
  48. let linewidth = String.length line in
  49. let left = if l = ystart then xstart else 1 in
  50. let right = if l = yend then xend else linewidth in
  51. if linewidth > 0 then begin
  52. prerr_endline (retab line);
  53. prerr_string (indent (count_tabs line right));
  54. for i = 1 to left - 1 do prerr_char ' ' done;
  55. for i = left to right do prerr_char '^' done;
  56. prerr_endline "";
  57. end
  58. done
  59. let prerr_loc_msg verbose loc msg =
  60. if verbose then begin
  61. let (fname, ystart, yend, xstart, xend) = loc in
  62. if loc != noloc then begin
  63. let line_s = if yend != ystart
  64. then sprintf "lines %d-%d" ystart yend
  65. else sprintf "line %d" ystart
  66. in
  67. let char_s = if xend != xstart || yend != ystart
  68. then sprintf "characters %d-%d" xstart xend
  69. else sprintf "character %d" xstart
  70. in
  71. eprintf "File \"%s\", %s, %s:\n" fname line_s char_s;
  72. end;
  73. eprintf "%s\n" msg;
  74. if verbose && loc != noloc then
  75. try prerr_loc loc
  76. with Sys_error _ -> ()
  77. end
  78. (** AST traversal *)
  79. #define TRAV_ALL(id, constructor) \
  80. trav_all_##id l = \
  81. let rec filter_clear = function \
  82. | [] -> [] \
  83. | Clear :: tl -> filter_clear tl \
  84. | constructor hd :: tl -> hd :: filter_clear tl \
  85. | _ -> failwith ("expected " ^ #constructor ^ " or Clear") \
  86. in \
  87. filter_clear (List.map trav_##id l)
  88. #define EXPECT(id, constructor) \
  89. expect_##id value = \
  90. match trav_##id value with \
  91. | constructor decl -> decl \
  92. | _ -> failwith ("expected " ^ #constructor)
  93. let transform_stylesheet f stylesheet =
  94. let rec trav_expr = function
  95. | Concat terms -> f (Expr (Concat (trav_all_expr terms)))
  96. | Function (name, arg) -> f (Expr (Function (name, expect_expr arg)))
  97. | Unary (op, opnd) -> f (Expr (Unary (op, expect_expr opnd)))
  98. | Nary (op, opnds) -> f (Expr (Nary (op, trav_all_expr opnds)))
  99. | value -> f (Expr value)
  100. and EXPECT(expr, Expr)
  101. and TRAV_ALL(expr, Expr) in
  102. let trav_declaration (name, value, important) =
  103. f (Declaration (name, expect_expr value, important))
  104. in
  105. let TRAV_ALL(declaration, Declaration) in
  106. let trav_selector = function
  107. | Simple _ as s -> f (Selector s)
  108. | Combinator (left, com, right) ->
  109. f (Selector (Combinator (left, com, right)))
  110. in
  111. let TRAV_ALL(selector, Selector) in
  112. let trav_media_expr = function
  113. | (_, None) as value ->
  114. f (Media_expr value)
  115. | (name, Some value) ->
  116. let value =
  117. match trav_expr value with
  118. | Expr value -> Some value
  119. | Clear -> None
  120. | _ -> failwith "expected Expr or Clear"
  121. in
  122. f (Media_expr (name, value))
  123. in
  124. let TRAV_ALL(media_expr, Media_expr) in
  125. let trav_media_query (prefix, mtype, queries) =
  126. f (Media_query (prefix, mtype, trav_all_media_expr queries))
  127. in
  128. let TRAV_ALL(media_query, Media_query) in
  129. let trav_descriptor_declaration (name, value) =
  130. f (Descriptor_declaration (name, expect_expr value))
  131. in
  132. let TRAV_ALL(descriptor_declaration, Descriptor_declaration) in
  133. let trav_keyframe_ruleset (selector, decls) =
  134. f (Keyframe_ruleset (expect_expr selector, trav_all_declaration decls))
  135. in
  136. let TRAV_ALL(keyframe_ruleset, Keyframe_ruleset) in
  137. let trav_supports_declaration (name, value) =
  138. f (Supports_declaration (name, expect_expr value))
  139. in
  140. let EXPECT(supports_declaration, Supports_declaration) in
  141. let rec trav_condition = function
  142. | Not c -> f (Condition (Not (expect_condition c)))
  143. | And l -> f (Condition (And (trav_all_condition l)))
  144. | Or l -> f (Condition (Or (trav_all_condition l)))
  145. | Decl d -> f (Condition (Decl (expect_supports_declaration d)))
  146. and EXPECT(condition, Condition)
  147. and TRAV_ALL(condition, Condition) in
  148. let rec trav_statement = function
  149. | Ruleset (selectors, decls) ->
  150. let selectors = trav_all_selector selectors in
  151. let decls = trav_all_declaration decls in
  152. f (Statement (Ruleset (selectors, decls)))
  153. | Media (queries, rulesets) ->
  154. let queries = trav_all_media_query queries in
  155. let rulesets = trav_all_statement rulesets in
  156. f (Statement (Media (queries, rulesets)))
  157. | Import (target, queries) ->
  158. let target = expect_expr target in
  159. let queries = trav_all_media_query queries in
  160. f (Statement (Import (target, queries)))
  161. | Page (pseudo, decls) ->
  162. let decls = trav_all_declaration decls in
  163. f (Statement (Page (pseudo, decls)))
  164. | Font_face decls ->
  165. let decls = trav_all_descriptor_declaration decls in
  166. f (Statement (Font_face decls))
  167. | Namespace (prefix, uri) ->
  168. let uri = expect_expr uri in
  169. f (Statement (Namespace (prefix, uri)))
  170. | Keyframes (id, rules) ->
  171. let rules = trav_all_keyframe_ruleset rules in
  172. f (Statement (Keyframes (id, rules)))
  173. | Supports (condition, statements) ->
  174. let condition = expect_condition condition in
  175. let statements = trav_all_statement statements in
  176. f (Statement (Supports (condition, statements)))
  177. | s ->
  178. f (Statement s)
  179. and TRAV_ALL(statement, Statement) in
  180. trav_all_statement stylesheet