genml.ml 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. (*
  2. * Copyright (C)2005-2018 Haxe Foundation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20. * DEALINGS IN THE SOFTWARE.
  21. *)
  22. open Globals
  23. open Ast
  24. open Type
  25. open Common
  26. type ctx = {
  27. com : Common.context;
  28. mutable ch : out_channel;
  29. mutable buf : Rbuffer.t;
  30. mutable tabs : string;
  31. mutable separator : bool;
  32. dirs : (string list, bool) Hashtbl.t;
  33. mutable vars : (int, bool) Hashtbl.t;
  34. mutable current_module : path;
  35. mutable module_files : string list;
  36. }
  37. type ml_type =
  38. | MUnit
  39. | MInt
  40. | MFloat
  41. | MBool
  42. | MString
  43. | MList of ml_type
  44. | MArray of ml_type
  45. | MOption of ml_type
  46. | MFun of ml_type list
  47. | MInst of path
  48. | MTypeParam of string
  49. | MParams of ml_type * ml_type list
  50. let sprintf = Printf.sprintf
  51. let ident i = i
  52. let is_extern_field f =
  53. not (Type.is_physical_field f) || Meta.has Meta.Extern f.cf_meta
  54. let flush ctx =
  55. Rbuffer.output_buffer ctx.ch ctx.buf;
  56. Rbuffer.clear ctx.buf
  57. let spr ctx s =
  58. ctx.separator <- false;
  59. Rbuffer.add_string ctx.buf s
  60. let print ctx =
  61. ctx.separator <- false;
  62. Printf.kprintf (fun s -> Rbuffer.add_string ctx.buf s)
  63. let newline ctx =
  64. match Rbuffer.nth ctx.buf (Rbuffer.length ctx.buf - 1) with
  65. | '}' | '{' | ':' | ';' -> print ctx "\n%s" ctx.tabs
  66. | _ when ctx.separator -> print ctx "\n%s" ctx.tabs
  67. | _ -> print ctx ";\n%s" ctx.tabs
  68. let dir_path ctx path =
  69. ctx.com.file ^ (match path with [] -> "" | _ -> "/" ^ String.concat "/" path)
  70. let begin_module ctx (path,name) =
  71. if not (Hashtbl.mem ctx.dirs path) then begin
  72. Path.mkdir_recursive ctx.com.file path;
  73. Hashtbl.add ctx.dirs path true;
  74. end;
  75. let file = dir_path ctx path ^ "/" ^ String.uncapitalize name ^ ".ml" in
  76. ctx.ch <- open_out_bin file;
  77. ctx.module_files <- file :: ctx.module_files;
  78. ctx.current_module <- (path,name)
  79. let flush ctx =
  80. Rbuffer.output_buffer ctx.ch ctx.buf;
  81. Rbuffer.clear ctx.buf
  82. let end_module ctx =
  83. flush ctx;
  84. close_out ctx.ch;
  85. ctx.ch <- stdout
  86. let open_block ctx =
  87. let oldt = ctx.tabs in
  88. ctx.tabs <- "\t" ^ ctx.tabs;
  89. (fun() -> ctx.tabs <- oldt)
  90. let rec to_type ctx t p =
  91. match t with
  92. | TMono r ->
  93. (match !r with
  94. | None -> abort "Unbound monomorph" p
  95. | Some t -> to_type ctx t p)
  96. | TLazy f ->
  97. to_type ctx (lazy_type f) p
  98. | TAbstract ({a_path = [],"Null"},[t1]) ->
  99. MOption (to_type ctx t1 p)
  100. | TFun (args, ret) ->
  101. MFun (List.map (fun (_,o,t) -> to_type ctx t p) args @ [to_type ctx ret p])
  102. | TInst ({ cl_path = [],"Array" },_) ->
  103. abort "Array not supported" p
  104. | TInst ({ cl_path = [],"String" },_) ->
  105. MString
  106. | TInst ({ cl_kind = KTypeParameter _; cl_path = _,name },[]) ->
  107. MTypeParam name
  108. | TInst (c,[]) ->
  109. MInst c.cl_path
  110. | TInst (c,pl) ->
  111. MParams (MInst c.cl_path, List.map (fun t -> to_type ctx t p) pl)
  112. | TEnum ({ e_path = ["haxe";"ds"],"ListRepr" },[t]) ->
  113. MList (to_type ctx t p)
  114. | TEnum (e,[]) ->
  115. MInst e.e_path
  116. | TEnum (e,pl) ->
  117. MParams (MInst e.e_path, List.map (fun t -> to_type ctx t p) pl)
  118. | TType (td,tl) ->
  119. to_type ctx (apply_params td.t_params tl td.t_type) p
  120. | TAbstract (a,pl) ->
  121. if Meta.has Meta.CoreType a.a_meta then
  122. (match a.a_path with
  123. | [], "Void" -> MUnit
  124. | [], "Int" | [], "UInt" -> MInt
  125. | [], "Float" -> MFloat
  126. | [], "Bool" -> MBool
  127. | _ -> abort ("Unknown core type " ^ s_type_path a.a_path) p)
  128. else
  129. to_type ctx (Abstract.get_underlying_type a pl) p
  130. | _ ->
  131. abort ("Unsupported type " ^ s_type (print_context()) t) p
  132. let module_path ctx path =
  133. if path = ctx.current_module then
  134. ""
  135. else
  136. snd path ^ "."
  137. let rec type_str ctx = function
  138. | MUnit -> "unit"
  139. | MInt -> "int"
  140. | MFloat -> "float"
  141. | MBool -> "bool"
  142. | MString -> "string"
  143. | MList t -> type_str ctx t ^ " list"
  144. | MArray t -> type_str ctx t ^ " array"
  145. | MOption t -> type_str ctx t ^ " option"
  146. | MFun tl -> String.concat " -> " (List.map (type_str ctx) tl)
  147. | MInst path -> module_path ctx path ^ "t"
  148. | MTypeParam name -> "'" ^ String.lowercase name
  149. | MParams (t,[]) -> type_str ctx t
  150. | MParams (t,[p]) -> type_str ctx p ^ " " ^ type_str ctx t
  151. | MParams (t,pl) -> "(" ^ String.concat ", " (List.map (type_str ctx) pl) ^ ") " ^ type_str ctx t
  152. let rec def_value ctx = function
  153. | MUnit -> "()"
  154. | MInt -> "0"
  155. | MFloat -> "0."
  156. | MBool -> "false"
  157. | MString -> "\"\""
  158. | MArray _ -> "[||]"
  159. | MList _ -> "[]"
  160. | MOption t -> "None"
  161. | MFun tl -> "(fun " ^ String.concat " " (List.map (fun _ -> "_") tl) ^ " -> assert false)"
  162. | MParams (t,_) -> def_value ctx t
  163. | MInst _ | MTypeParam _ -> "Obj.magic 0"
  164. let s_type ctx t p = type_str ctx (to_type ctx t p)
  165. let scan_vars ctx e =
  166. let old = ctx.vars in
  167. ctx.vars <- Hashtbl.create 0;
  168. let rec loop e =
  169. (match e.eexpr with
  170. | TBinop ((OpAssign | OpAssignOp _), { eexpr = TLocal v },_) | TUnop ((Increment|Decrement),_,{ eexpr = TLocal v }) ->
  171. Hashtbl.replace ctx.vars v.v_id true
  172. | _ -> ());
  173. Type.iter loop e
  174. in
  175. loop e;
  176. (fun() -> ctx.vars <- old)
  177. let gen_list ctx sep f list =
  178. let first = ref true in
  179. List.iter (fun e ->
  180. if !first then first := false else spr ctx sep;
  181. f e
  182. ) list
  183. let rec gen_expr ctx e is_final =
  184. match e.eexpr with
  185. | TConst c ->
  186. (match c with
  187. | TInt i -> print ctx "%ld" i
  188. | TFloat s -> print ctx "%s." s
  189. | TString s -> print ctx "\"%s\"" (String.escaped s)
  190. | TBool b -> spr ctx (if b then "true" else "false")
  191. | TNull -> spr ctx "None"
  192. | TThis -> spr ctx "this"
  193. | TSuper -> assert false)
  194. | TLocal v ->
  195. let vid = ident v.v_name in
  196. if Hashtbl.mem ctx.vars v.v_id then print ctx "!%s" vid else spr ctx vid
  197. | TVar (v,init) ->
  198. let mut = Hashtbl.mem ctx.vars v.v_id in
  199. let t = to_type ctx v.v_type e.epos in
  200. print ctx "let %s : %s%s = %s" (ident v.v_name) (type_str ctx t) (if mut then " ref" else "") (if mut then "ref " else "");
  201. (match init with None -> spr ctx (def_value ctx t) | Some e -> gen_expr ctx e false);
  202. spr ctx " in ";
  203. ctx.separator <- true;
  204. | TBlock [] ->
  205. spr ctx "()"
  206. | TBlock el ->
  207. spr ctx "begin";
  208. ctx.separator <- true;
  209. let b = open_block ctx in
  210. let rec loop = function
  211. | [] -> assert false
  212. | [e] ->
  213. newline ctx;
  214. gen_expr ctx e is_final
  215. | e :: el ->
  216. newline ctx;
  217. let ign = (match follow e.etype with TAbstract ({ a_path = [],"Void" },_) -> false | _ -> true) in
  218. if ign then spr ctx "ignore(";
  219. gen_expr ctx e false;
  220. if ign then spr ctx ")";
  221. loop el
  222. in
  223. loop el;
  224. b();
  225. newline ctx;
  226. spr ctx "end";
  227. | TCall ({ eexpr = TField(_,FStatic({cl_path=["haxe";"ds";"_ImmutableList"],_},{cf_name="fromArray"})) },[{ eexpr = TArrayDecl el }]) ->
  228. spr ctx "[";
  229. gen_list ctx "; " (fun e -> gen_expr ctx e false) el;
  230. spr ctx "]";
  231. | TCall ({ eexpr = TField (_,FEnum ({e_path=(["haxe";"ds"],"ListRepr")},_)) }, [a;b]) ->
  232. gen_expr ctx a false;
  233. spr ctx " :: ";
  234. gen_expr ctx b false;
  235. | TCall ({ eexpr = TField (_,FEnum _) } as e, (_ :: _ :: _ as pl)) ->
  236. spr ctx "(";
  237. gen_expr ctx e false;
  238. spr ctx "(";
  239. gen_list ctx ", " (fun e -> gen_expr ctx e false) pl;
  240. spr ctx "))"
  241. | TCall (e, pl) ->
  242. spr ctx "(";
  243. gen_expr ctx e false;
  244. if pl = [] then spr ctx "()";
  245. List.iter (fun e ->
  246. spr ctx " ";
  247. gen_expr ctx e false;
  248. ) pl;
  249. spr ctx ")"
  250. | TField (e, ft) ->
  251. (match ft with
  252. | FInstance (_,_,cf) ->
  253. gen_expr ctx e false;
  254. print ctx ".%s" (ident cf.cf_name)
  255. | FEnum (e,ef) ->
  256. print ctx "%s%s" (module_path ctx e.e_path) (ident ef.ef_name)
  257. | FStatic (c,cf) ->
  258. let rec loop = function
  259. | (Meta.Custom ":mlNative",[EConst (String s),_],_) :: _ ->
  260. spr ctx s
  261. | _ :: l -> loop l
  262. | [] ->
  263. print ctx "%s%s" (module_path ctx c.cl_path) (ident cf.cf_name)
  264. in
  265. loop cf.cf_meta
  266. | FAnon f -> assert false
  267. | FDynamic _ -> assert false
  268. | FClosure _ -> assert false);
  269. | TReturn _ when not is_final ->
  270. abort "Unallowed not final return" e.epos
  271. | TReturn None ->
  272. spr ctx "()"
  273. | TReturn (Some e) ->
  274. gen_expr ctx e is_final
  275. | TMeta (_,e) ->
  276. gen_expr ctx e is_final
  277. (*
  278. | TArrayDecl al ->
  279. spr ctx "[|";
  280. gen_list ctx ", " (fun e -> gen_expr ctx e false) al;
  281. spr ctx "|]";
  282. | TArray (arr,index) ->
  283. gen_expr ctx arr false;
  284. spr ctx ".(";
  285. gen_expr ctx index false;
  286. spr ctx ")"*)
  287. | TBinop (op, e1, e2) ->
  288. (match op with
  289. | OpAssign ->
  290. gen_access ctx e1;
  291. gen_expr ctx e2 false;
  292. | OpAdd ->
  293. (match to_type ctx e.etype e.epos with
  294. | MInt ->
  295. gen_expr ctx e1 false;
  296. spr ctx " + ";
  297. gen_expr ctx e2 false;
  298. | MFloat ->
  299. gen_expr ctx e1 false;
  300. spr ctx " +. ";
  301. gen_expr ctx e2 false;
  302. | MString ->
  303. gen_expr ctx e1 false;
  304. spr ctx " ^ ";
  305. gen_expr ctx e2 false;
  306. | t ->
  307. abort ("Don't know how to add " ^ type_str ctx t) e.epos)
  308. | OpSub | OpMult | OpDiv ->
  309. let is_int = to_type ctx e.etype e.epos = MInt in
  310. gen_expr ctx e1 false;
  311. print ctx " %s%s " (s_binop op) (if is_int then "." else "");
  312. gen_expr ctx e2 false;
  313. | OpLt | OpLte | OpGt | OpGte | OpEq | OpNotEq ->
  314. gen_expr ctx e1 false;
  315. print ctx " %s " (match op with OpEq -> "==" | OpNotEq -> "!=" | _ -> s_binop op);
  316. gen_expr ctx e2 false;
  317. | _ ->
  318. abort ("Unsupported op " ^ s_binop op) e.epos)
  319. | TUnop ((Increment|Decrement) as op,flag,e) ->
  320. spr ctx (if op = Increment then "incr " else "decr ");
  321. gen_expr ctx e false;
  322. | TWhile (cond, e, flag) ->
  323. (match flag with
  324. | NormalWhile ->
  325. spr ctx "while ";
  326. gen_expr ctx cond false;
  327. spr ctx " do ";
  328. gen_expr ctx e false;
  329. spr ctx "done";
  330. | DoWhile ->
  331. abort "Do...while not supported" e.epos)
  332. | TIf (cond,eif,eelse) ->
  333. spr ctx "if ";
  334. gen_expr ctx cond false;
  335. spr ctx " then ";
  336. gen_expr ctx eif is_final;
  337. (match eelse with
  338. | None -> ()
  339. | Some e -> spr ctx " else "; gen_expr ctx e is_final);
  340. | TParenthesis e ->
  341. spr ctx "(";
  342. gen_expr ctx e is_final;
  343. spr ctx ")";
  344. | TCast (e,_) ->
  345. gen_expr ctx e is_final
  346. | _ ->
  347. abort ("Unsupported expr " ^ s_expr_kind e) e.epos
  348. and gen_access ctx e =
  349. match e.eexpr with
  350. | TLocal v ->
  351. print ctx "%s := " (ident v.v_name)
  352. | _ ->
  353. abort ("Unsupported access " ^ s_expr_kind e) e.epos
  354. let make_type_params ctx pl p =
  355. let p_type (_,t) = s_type ctx t p in
  356. match pl with
  357. | [] -> ""
  358. | [t] -> p_type t ^ " "
  359. | _ -> "(" ^ String.concat ", " (List.map p_type pl) ^ ") "
  360. let generate_class ctx c =
  361. if c.cl_super <> None then abort "Inheritance not yet supported" c.cl_pos;
  362. let fields = List.fold_left (fun acc f ->
  363. if is_extern_field f then
  364. acc
  365. else match f.cf_kind with
  366. | Var _ -> f :: acc
  367. | _ -> acc
  368. ) [] c.cl_ordered_fields in
  369. if fields <> [] then begin
  370. print ctx "type %st = {" (make_type_params ctx c.cl_params c.cl_pos);
  371. let b = open_block ctx in
  372. List.iter (fun f ->
  373. newline ctx;
  374. print ctx "mutable %s : %s" (ident f.cf_name) (s_type ctx f.cf_type f.cf_pos);
  375. ) (List.rev fields);
  376. b();
  377. newline ctx;
  378. print ctx "}";
  379. newline ctx;
  380. spr ctx "\n\n"
  381. end;
  382. List.iter (fun f ->
  383. match f.cf_kind with
  384. | Var v -> assert false
  385. | Method _ ->
  386. let args, ret = (match follow f.cf_type with TFun (args, ret) -> args, ret | _ -> assert false) in
  387. let tret = to_type ctx ret f.cf_pos in
  388. print ctx "let %s %s : %s = " (ident f.cf_name) (if args = [] then "()" else String.concat " " (List.map (fun (n,o,t) ->
  389. if o then abort "Unsupported optional arg" f.cf_pos;
  390. sprintf "(%s:%s)" (ident n) (s_type ctx t f.cf_pos)
  391. ) args)) (type_str ctx tret);
  392. (match f.cf_expr with
  393. | Some { eexpr = TFunction f } ->
  394. let e = f.tf_expr in
  395. let old = scan_vars ctx e in
  396. let ign = tret = MUnit && to_type ctx e.etype e.epos <> MUnit in
  397. if ign then spr ctx "ignore (";
  398. gen_expr ctx e true;
  399. if ign then spr ctx ")";
  400. old()
  401. | _ -> assert false);
  402. spr ctx "\n"
  403. ) c.cl_ordered_statics
  404. let generate_enum ctx e =
  405. print ctx "type %st =" (make_type_params ctx e.e_params e.e_pos);
  406. List.iter (fun n ->
  407. let c = PMap.find n e.e_constrs in
  408. print ctx "\n\t| %s" (ident n);
  409. (match follow c.ef_type with
  410. | TFun (args,_) -> print ctx " of %s" (String.concat " * " (List.map (fun (n,o,t) -> s_type ctx t c.ef_pos) args))
  411. | _ -> ())
  412. ) e.e_names;
  413. spr ctx "\n\n"
  414. let generate_type ctx t =
  415. match t with
  416. | TClassDecl { cl_extern = true } ->
  417. ()
  418. | TClassDecl c ->
  419. begin_module ctx c.cl_path;
  420. generate_class ctx c;
  421. end_module ctx;
  422. | TTypeDecl td ->
  423. begin_module ctx td.t_path;
  424. spr ctx "(*TODO:TTypeDecl*)";
  425. end_module ctx;
  426. | TEnumDecl e ->
  427. begin_module ctx e.e_path;
  428. generate_enum ctx e;
  429. end_module ctx;
  430. | TAbstractDecl _ ->
  431. ()
  432. let generate com =
  433. let ctx = {
  434. com = com;
  435. ch = stdout;
  436. tabs = "";
  437. separator = false;
  438. dirs = Hashtbl.create 0;
  439. buf = Rbuffer.create 65536;
  440. vars = Hashtbl.create 0;
  441. current_module = [],"";
  442. module_files = [];
  443. } in
  444. (try Unix.mkdir ctx.com.file 0o755 with _ -> ());
  445. (match com.main with
  446. | None -> ()
  447. | Some e ->
  448. begin_module ctx ([],"MlBoot");
  449. gen_expr ctx e true;
  450. newline ctx;
  451. end_module ctx);
  452. List.iter (generate_type ctx) com.types;
  453. let dirs = Hashtbl.fold (fun path _ acc -> dir_path ctx path :: acc) ctx.dirs [] in
  454. let command = sprintf "ocamlopt -o %s %s %s" (ctx.com.file ^ "/out.exe") (String.concat " " (List.map (fun d -> "-I " ^ d) dirs)) (String.concat " " ctx.module_files) in
  455. print_string command;
  456. let code = Sys.command command in
  457. if code <> 0 then failwith ("Exit with code " ^ string_of_int code)