ast_coffee.ml 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. open Util
  2. (* AST nodes *)
  3. type ast = block
  4. and block = stmt list
  5. and stmt =
  6. | Return of value option
  7. | Comment of string
  8. | Expr_stmt of value
  9. and value =
  10. | Fun of value list * block * bool
  11. | Call of value * value list
  12. | Object of (string * value) list
  13. | Array of value list
  14. | Index of value * value
  15. | Range of value option * value option * bool
  16. | Try of block * block * block
  17. | Throw of value
  18. | New of value * value list
  19. | Class of string option * value option * class_body
  20. | Binop of binop * value * value
  21. | Monop of monop * value
  22. | Chainop of value * (binop * value) list
  23. | If of value * block * block
  24. | For of value * value option * binop * value * block
  25. | While of value * block
  26. | Switch of value * (value list * block) list * block
  27. | Assign of value * value
  28. | Property of value * string
  29. | Regex of string * string
  30. | Number of float
  31. | String of string
  32. | Var of string
  33. | Js of string
  34. | This
  35. | Null
  36. | Undefined
  37. | True
  38. | False
  39. | Param of string
  40. | Default of value * value
  41. | Splat of value option
  42. and class_body = class_stmt list
  43. and class_stmt =
  44. | Unnamed_expr of value
  45. | Prototype_property of string * value
  46. and binop =
  47. | Eq | Ne | Gt | Ge | Lt | Le
  48. | And | Or
  49. | In | Of
  50. | Plus | Minus | Times | Div | Mod
  51. | Div_trunc | Pow | Mod_math
  52. and monop =
  53. | Not | Exists
  54. | Neg | Pos
  55. (* Stringification *)
  56. let rec string_of_ast tree = string_of_block tree ^ "\n"
  57. and string_of_block block = cat "\n" string_of_stmt block
  58. and string_of_stmt = function
  59. | Return None -> "return"
  60. | Return (Some value) -> "return " ^ string_of_value value
  61. | Comment comment -> prefix_lines "# " comment
  62. | Expr_stmt value -> string_of_value value
  63. and string_of_value = function
  64. | Fun (params, body, is_bound) ->
  65. let params =
  66. match params with
  67. | [] -> ""
  68. | _ -> "(" ^ cat ", " string_of_value params ^ ") "
  69. in
  70. let glyph = if is_bound then "=>" else "->" in
  71. params ^ glyph ^ inline_block "" body
  72. | Call (fn, args) ->
  73. string_of_value fn ^ "(" ^ cat ", " string_of_value args ^ ")"
  74. | Object key_value_pairs ->
  75. let string_of_pair (key, value) = key ^ string_of_value value in
  76. "{" ^ cat ", " string_of_pair key_value_pairs ^ "}"
  77. | Array elements ->
  78. "[" ^ cat ", " string_of_value elements ^ "]"
  79. | Index (arr, (Range _ as range)) ->
  80. string_of_value arr ^ string_of_value range
  81. | Index (arr, idx) ->
  82. string_of_value arr ^ "[" ^ string_of_value idx ^ "]"
  83. | Range (lbnd, ubnd, inclusive) ->
  84. let splat = if inclusive then ".." else "..." in
  85. let s = function None -> "" | Some v -> string_of_value v in
  86. "[" ^ s lbnd ^ splat ^ s ubnd ^ "]"
  87. | Try (body, catch, finally) ->
  88. let s pre = function [] -> "" | b -> pre ^ indent_block b in
  89. "try" ^ indent_block body ^ "\n" ^
  90. s "catch" catch ^ "\n" ^
  91. s "finally" finally
  92. | Throw value ->
  93. "throw " ^ string_of_value value
  94. | New (cls, args) ->
  95. "new " ^ string_of_value cls ^ "(" ^ cat ", " string_of_value args ^ ")"
  96. | Class (name, parent, body) ->
  97. let cls =
  98. match name with
  99. | None -> "class"
  100. | Some name -> "class " ^ name
  101. in
  102. let extends =
  103. match parent with
  104. | None -> ""
  105. | Some parent -> " extends " ^ string_of_value parent
  106. in
  107. let body =
  108. let string_of_class_stmt = function
  109. | Unnamed_expr value ->
  110. string_of_value value
  111. | Prototype_property (name, value) ->
  112. name ^ ": " ^ string_of_value value
  113. in
  114. match body with
  115. | [] -> failwith "empty body"
  116. | body -> "\n" ^ indent (cat "\n" string_of_class_stmt body)
  117. in
  118. cls ^ extends ^ body
  119. | Binop (op, left, right) ->
  120. "(" ^ string_of_value left ^
  121. " " ^ string_of_binop op ^ " " ^
  122. string_of_value right ^ ")"
  123. | Monop (Exists, opnd) ->
  124. string_of_value opnd ^ "?"
  125. | Monop (op, opnd) ->
  126. let op =
  127. match op with
  128. | Not -> "not"
  129. | Neg -> "-"
  130. | Pos -> "+"
  131. | _ -> failwith "this cannot happen"
  132. in
  133. op ^ string_of_value opnd
  134. | Chainop (hd, tl) ->
  135. let rec s = function
  136. | [] ->
  137. failwith "invalid chained operator"
  138. | [(op, opnd)] ->
  139. string_of_binop op ^ " " ^ string_of_value opnd
  140. | (op, opnd) :: tl ->
  141. string_of_binop op ^ " " ^ string_of_value opnd ^ " " ^ s tl
  142. in
  143. string_of_value hd ^ " " ^ s tl
  144. | If (cond, [], _) ->
  145. failwith "empty if-body"
  146. (*
  147. | If (cond, [if_expr], []) ->
  148. "if " ^ string_of_value cond ^ " then " ^ string_of_value if_expr
  149. | If (cond, [if_expr], [else_expr]) ->
  150. "if " ^ string_of_value cond ^ " then " ^ string_of_value if_expr ^
  151. " else " ^ string_of_value else_expr
  152. *)
  153. | If (cond, if_body, []) ->
  154. "if " ^ string_of_value cond ^ indent_block if_body
  155. | If (cond, if_body, else_body) ->
  156. "if " ^ string_of_value cond ^ indent_block if_body ^
  157. "\nelse" ^ indent_block else_body
  158. | For (value, index, op, arr, body) ->
  159. let preamble =
  160. let iterator =
  161. let value = string_of_value value in
  162. match index with
  163. | None -> value
  164. | Some index -> value ^ ", " ^ string_of_value index
  165. in
  166. "for " ^ iterator ^ " " ^ string_of_binop op ^ " " ^ string_of_value arr
  167. in
  168. begin
  169. match body with
  170. | [] -> failwith "empty loop body"
  171. | [stmt] -> string_of_stmt stmt ^ preamble
  172. | _ -> preamble ^ indent_block body
  173. end
  174. | While (cond, body) ->
  175. "while " ^ string_of_value cond ^ indent_block body
  176. | Switch (value, when_cases, default_case) ->
  177. let string_of_when (match_values, body) =
  178. "\nwhen " ^ cat ", " string_of_value match_values ^
  179. inline_block "then" body
  180. in
  181. "switch " ^ string_of_value value ^
  182. indent (cat "" string_of_when when_cases) ^
  183. inline_block "else" default_case
  184. | Assign (left, right) ->
  185. string_of_value left ^ " = " ^ string_of_value right
  186. | Property (obj, prop) ->
  187. string_of_value obj ^ "." ^ prop
  188. | Regex (pattern, modifiers) ->
  189. "/" ^ pattern ^ "/" ^ modifiers
  190. | Number n -> string_of_number n
  191. | String s -> "\"" ^ s ^ "\""
  192. | Var name -> name
  193. | Js js -> "`" ^ js ^ "`"
  194. | This -> "this"
  195. | Null -> "null"
  196. | Undefined -> "undefined"
  197. | True -> "true"
  198. | False -> "false"
  199. | Param name -> name
  200. | Default (Param name, value) ->
  201. name ^ "=" ^ string_of_value value
  202. | Default _ ->
  203. failwith "Default can only have Param as first child"
  204. | Splat None ->
  205. "..."
  206. | Splat (Some value) ->
  207. string_of_value value ^ "..."
  208. and string_of_number n = string_of_float n (* FIXME *)
  209. and string_of_binop = function
  210. | Eq -> "is"
  211. | Ne -> "isnt"
  212. | Gt -> ">"
  213. | Ge -> ">="
  214. | Lt -> "<"
  215. | Le -> "<="
  216. | And -> "and"
  217. | Or -> "or"
  218. | In -> "in"
  219. | Of -> "of"
  220. | Plus -> "+"
  221. | Minus -> "-"
  222. | Times -> "*"
  223. | Div -> "/"
  224. | Mod -> "%"
  225. | Div_trunc -> "//"
  226. | Pow -> "**"
  227. | Mod_math -> "%%"
  228. and indent_block = function
  229. | [] -> failwith "empty block"
  230. | stmts -> "\n" ^ indent (string_of_block stmts)
  231. and inline_block prefix = function
  232. | [] -> ""
  233. | [stmt] -> prefix ^ " " ^ string_of_stmt stmt
  234. | stmts -> indent_block stmts