codegen.ml 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. (*
  2. The Haxe Compiler
  3. Copyright (C) 2005-2019 Haxe Foundation
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  15. *)
  16. open Ast
  17. open Type
  18. open Common
  19. open Error
  20. open Globals
  21. (* -------------------------------------------------------------------------- *)
  22. (* TOOLS *)
  23. let rec has_properties c =
  24. List.exists (fun f ->
  25. match f.cf_kind with
  26. | Var { v_read = AccCall } -> true
  27. | Var { v_write = AccCall } -> true
  28. | _ when Meta.has Meta.Accessor f.cf_meta -> true
  29. | _ -> false
  30. ) c.cl_ordered_fields || (match c.cl_super with Some (c,_) -> has_properties c | _ -> false)
  31. let get_properties fields =
  32. List.fold_left (fun acc f ->
  33. if Meta.has Meta.Accessor f.cf_meta then
  34. (f.cf_name, f.cf_name) :: acc
  35. else
  36. let acc = (match f.cf_kind with
  37. | Var { v_read = AccCall } -> ("get_" ^ f.cf_name , "get_" ^ f.cf_name) :: acc
  38. | _ -> acc) in
  39. match f.cf_kind with
  40. | Var { v_write = AccCall } -> ("set_" ^ f.cf_name , "set_" ^ f.cf_name) :: acc
  41. | _ -> acc
  42. ) [] fields
  43. let add_property_field com c =
  44. let p = c.cl_pos in
  45. let props = get_properties (c.cl_ordered_statics @ c.cl_ordered_fields) in
  46. match props with
  47. | [] -> ()
  48. | _ ->
  49. let fields,values = List.fold_left (fun (fields,values) (n,v) ->
  50. let cf = mk_field n com.basic.tstring p null_pos in
  51. PMap.add n cf fields,((n,null_pos,NoQuotes),Texpr.Builder.make_string com.basic v p) :: values
  52. ) (PMap.empty,[]) props in
  53. let t = mk_anon fields in
  54. let e = mk (TObjectDecl values) t p in
  55. let cf = mk_field "__properties__" t p null_pos in
  56. cf.cf_expr <- Some e;
  57. c.cl_statics <- PMap.add cf.cf_name cf c.cl_statics;
  58. c.cl_ordered_statics <- cf :: c.cl_ordered_statics
  59. let escape_res_name name allow_dirs =
  60. ExtString.String.replace_chars (fun chr ->
  61. if (chr >= 'a' && chr <= 'z') || (chr >= 'A' && chr <= 'Z') || (chr >= '0' && chr <= '9') || chr = '_' || chr = '.' then
  62. Char.escaped chr
  63. else if chr = '/' && allow_dirs then
  64. "/"
  65. else
  66. "-x" ^ (string_of_int (Char.code chr))) name
  67. let update_cache_dependencies t =
  68. let rec check_t m t = match t with
  69. | TInst(c,tl) ->
  70. add_dependency m c.cl_module;
  71. List.iter (check_t m) tl;
  72. | TEnum(en,tl) ->
  73. add_dependency m en.e_module;
  74. List.iter (check_t m) tl;
  75. | TType(t,tl) ->
  76. add_dependency m t.t_module;
  77. List.iter (check_t m) tl;
  78. | TAbstract(a,tl) ->
  79. add_dependency m a.a_module;
  80. List.iter (check_t m) tl;
  81. | TFun(targs,tret) ->
  82. List.iter (fun (_,_,t) -> check_t m t) targs;
  83. check_t m tret;
  84. | TAnon an ->
  85. PMap.iter (fun _ cf -> check_field m cf) an.a_fields
  86. | TMono r ->
  87. (match !r with
  88. | Some t -> check_t m t
  89. | _ -> ())
  90. | TLazy f ->
  91. check_t m (lazy_type f)
  92. | TDynamic t ->
  93. if t == t_dynamic then
  94. ()
  95. else
  96. check_t m t
  97. and check_field m cf =
  98. check_t m cf.cf_type
  99. in
  100. match t with
  101. | TClassDecl c ->
  102. List.iter (check_field c.cl_module) c.cl_ordered_statics;
  103. List.iter (check_field c.cl_module) c.cl_ordered_fields;
  104. (match c.cl_constructor with None -> () | Some cf -> check_field c.cl_module cf);
  105. | _ ->
  106. ()
  107. (* -------------------------------------------------------------------------- *)
  108. (* FIX OVERRIDES *)
  109. (*
  110. on some platforms which doesn't support type parameters, we must have the
  111. exact same type for overridden/implemented function as the original one
  112. *)
  113. let rec find_field com c f =
  114. try
  115. (match c.cl_super with
  116. | None ->
  117. raise Not_found
  118. | Some ( {cl_path = (["cpp"],"FastIterator")}, _ ) ->
  119. raise Not_found (* This is a strongly typed 'extern' and the usual rules don't apply *)
  120. | Some (c,_) ->
  121. find_field com c f)
  122. with Not_found -> try
  123. if com.platform = Cpp || com.platform = Hl then (* uses delegation for interfaces *)
  124. raise Not_found;
  125. let rec loop = function
  126. | [] ->
  127. raise Not_found
  128. | (c,_) :: l ->
  129. try
  130. find_field com c f
  131. with
  132. Not_found -> loop l
  133. in
  134. loop c.cl_implements
  135. with Not_found ->
  136. let f = PMap.find f.cf_name c.cl_fields in
  137. (match f.cf_kind with Var { v_read = AccRequire _ } -> raise Not_found | _ -> ());
  138. f
  139. let fix_override com c f fd =
  140. let f2 = (try Some (find_field com c f) with Not_found -> None) in
  141. match f2,fd with
  142. | Some (f2), Some(fd) ->
  143. let targs, tret = (match follow f2.cf_type with TFun (args,ret) -> args, ret | _ -> assert false) in
  144. let changed_args = ref [] in
  145. let prefix = "_tmp_" in
  146. let nargs = List.map2 (fun ((v,ct) as cur) (_,_,t2) ->
  147. try
  148. type_eq EqStrict (monomorphs c.cl_params (monomorphs f.cf_params v.v_type)) t2;
  149. (* Flash generates type parameters with a single constraint as that constraint type, so we
  150. have to detect this case and change the variable (issue #2712). *)
  151. begin match follow v.v_type with
  152. | TInst({cl_kind = KTypeParameter [tc]} as cp,_) when com.platform = Flash ->
  153. if List.mem_assoc (snd cp.cl_path) c.cl_params then raise (Unify_error [])
  154. | _ ->
  155. ()
  156. end;
  157. cur
  158. with Unify_error _ ->
  159. let v2 = alloc_var VGenerated (prefix ^ v.v_name) t2 v.v_pos in
  160. changed_args := (v,v2) :: !changed_args;
  161. v2,ct
  162. ) fd.tf_args targs in
  163. let fd2 = {
  164. tf_args = nargs;
  165. tf_type = tret;
  166. tf_expr = (match List.rev !changed_args with
  167. | [] -> fd.tf_expr
  168. | args ->
  169. let e = fd.tf_expr in
  170. let el = (match e.eexpr with TBlock el -> el | _ -> [e]) in
  171. let p = (match el with [] -> e.epos | e :: _ -> e.epos) in
  172. let el_v = List.map (fun (v,v2) ->
  173. mk (TVar (v,Some (mk (TCast (mk (TLocal v2) v2.v_type p,None)) v.v_type p))) com.basic.tvoid p
  174. ) args in
  175. { e with eexpr = TBlock (el_v @ el) }
  176. );
  177. } in
  178. (* as3 does not allow wider visibility, so the base method has to be made public *)
  179. if Common.defined com Define.As3 && has_class_field_flag f CfPublic then add_class_field_flag f2 CfPublic;
  180. let targs = List.map (fun(v,c) -> (v.v_name, Option.is_some c, v.v_type)) nargs in
  181. let fde = (match f.cf_expr with None -> assert false | Some e -> e) in
  182. f.cf_expr <- Some { fde with eexpr = TFunction fd2 };
  183. f.cf_type <- TFun(targs,tret);
  184. | Some(f2), None when c.cl_interface ->
  185. let targs, tret = (match follow f2.cf_type with TFun (args,ret) -> args, ret | _ -> assert false) in
  186. f.cf_type <- TFun(targs,tret)
  187. | _ ->
  188. ()
  189. let fix_overrides com t =
  190. match t with
  191. | TClassDecl c ->
  192. (* overrides can be removed from interfaces *)
  193. if c.cl_interface then
  194. c.cl_ordered_fields <- List.filter (fun f ->
  195. try
  196. if find_field com c f == f then raise Not_found;
  197. c.cl_fields <- PMap.remove f.cf_name c.cl_fields;
  198. false;
  199. with Not_found ->
  200. true
  201. ) c.cl_ordered_fields;
  202. List.iter (fun f ->
  203. match f.cf_expr, f.cf_kind with
  204. | Some { eexpr = TFunction fd }, Method (MethNormal | MethInline) ->
  205. fix_override com c f (Some fd)
  206. | None, Method (MethNormal | MethInline) when c.cl_interface ->
  207. fix_override com c f None
  208. | _ ->
  209. ()
  210. ) c.cl_ordered_fields
  211. | _ ->
  212. ()
  213. (*
  214. PHP does not allow abstract classes extending other abstract classes to override any fields, so these duplicates
  215. must be removed from the child interface
  216. *)
  217. let fix_abstract_inheritance com t =
  218. match t with
  219. | TClassDecl c when c.cl_interface ->
  220. c.cl_ordered_fields <- List.filter (fun f ->
  221. let b = try (find_field com c f) == f
  222. with Not_found -> false in
  223. if not b then c.cl_fields <- PMap.remove f.cf_name c.cl_fields;
  224. b;
  225. ) c.cl_ordered_fields
  226. | _ -> ()
  227. (* -------------------------------------------------------------------------- *)
  228. (* MISC FEATURES *)
  229. let rec is_volatile t =
  230. match t with
  231. | TMono r ->
  232. (match !r with
  233. | Some t -> is_volatile t
  234. | _ -> false)
  235. | TLazy f ->
  236. is_volatile (lazy_type f)
  237. | TType (t,tl) ->
  238. (match t.t_path with
  239. | _ -> is_volatile (apply_params t.t_params tl t.t_type))
  240. | _ ->
  241. false
  242. let bytes_serialize data =
  243. let b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" in
  244. let tbl = Array.init (String.length b64) (fun i -> String.get b64 i) in
  245. Bytes.unsafe_to_string (Base64.str_encode ~tbl data)
  246. module Dump = struct
  247. (*
  248. Make a dump of the full typed AST of all types
  249. *)
  250. let create_dumpfile acc l =
  251. let ch = Path.create_file false ".dump" acc l in
  252. let buf = Buffer.create 0 in
  253. buf, (fun () ->
  254. output_string ch (Buffer.contents buf);
  255. close_out ch)
  256. let create_dumpfile_from_path com path =
  257. let buf,close = create_dumpfile [] ("dump" :: (platform_name_macro com) :: fst path @ [snd path]) in
  258. buf,close
  259. let dump_types com s_expr =
  260. let s_type = s_type (Type.print_context()) in
  261. let params tl = match tl with [] -> "" | l -> Printf.sprintf "<%s>" (String.concat "," (List.map (fun (n,t) -> n ^ " : " ^ s_type t) l)) in
  262. List.iter (fun mt ->
  263. let path = Type.t_path mt in
  264. let buf,close = create_dumpfile_from_path com path in
  265. let print fmt = Printf.kprintf (fun s -> Buffer.add_string buf s) fmt in
  266. let s_metas ml tabs =
  267. let args el =
  268. match el with
  269. | [] -> ""
  270. | el -> Printf.sprintf "(%s)" (String.concat ", " (List.map (fun e -> Ast.s_expr e) el)) in
  271. match ml with
  272. | [] -> ""
  273. | ml -> String.concat " " (List.map (fun me -> match me with (m,el,_) -> "@" ^ Meta.to_string m ^ args el) ml) ^ "\n" ^ tabs in
  274. (match mt with
  275. | Type.TClassDecl c ->
  276. let s_cf_expr f =
  277. match f.cf_expr with
  278. | None -> ""
  279. | Some e -> Printf.sprintf "%s" (s_expr s_type e) in
  280. let is_inline_var v : bool = v = Var { v_read = AccInline; v_write = AccNever } in
  281. let rec print_field stat f =
  282. print "\n\t%s%s%s%s%s %s%s"
  283. (s_metas f.cf_meta "\t")
  284. (if (has_class_field_flag f CfPublic && not (c.cl_extern || c.cl_interface)) then "public " else "")
  285. (if stat then "static " else "")
  286. (match f.cf_kind with
  287. | Var v when (is_inline_var f.cf_kind) -> "inline "
  288. | Var v -> ""
  289. | Method m ->
  290. match m with
  291. | MethNormal -> ""
  292. | MethDynamic -> "dynamic "
  293. | MethInline -> "inline "
  294. | MethMacro -> "macro ")
  295. (match f.cf_kind with Var v -> "var" | Method m -> "function")
  296. (f.cf_name ^ match f.cf_kind with
  297. | Var { v_read = AccNormal; v_write = AccNormal } -> ""
  298. | Var v when (is_inline_var f.cf_kind) -> ""
  299. | Var v -> "(" ^ s_access true v.v_read ^ "," ^ s_access false v.v_write ^ ")"
  300. | _ -> "")
  301. (params f.cf_params);
  302. (match f.cf_kind with
  303. | Var v -> print ":%s%s;" (s_type f.cf_type)
  304. (match f.cf_expr with
  305. | None -> ""
  306. | Some e -> " = " ^ (s_cf_expr f));
  307. | Method m -> if (c.cl_extern || c.cl_interface) then (
  308. match f.cf_type with
  309. | TFun(al,t) -> print "(%s):%s;" (String.concat ", " (
  310. List.map (fun (n,o,t) -> n ^ ":" ^ (s_type t)) al))
  311. (s_type t)
  312. | _ -> ()
  313. ) else print "%s" (s_cf_expr f));
  314. print "\n";
  315. List.iter (fun f -> print_field stat f) f.cf_overloads
  316. in
  317. print "%s%s%s%s %s%s" (s_metas c.cl_meta "") (if c.cl_private then "private " else "") (if c.cl_extern then "extern " else "") (if c.cl_interface then "interface" else "class") (s_type_path path) (params c.cl_params);
  318. (match c.cl_super with None -> () | Some (c,pl) -> print " extends %s" (s_type (TInst (c,pl))));
  319. List.iter (fun (c,pl) -> print " implements %s" (s_type (TInst (c,pl)))) c.cl_implements;
  320. (match c.cl_array_access with None -> () | Some t -> print " implements ArrayAccess<%s>" (s_type t));
  321. print " {\n";
  322. (match c.cl_constructor with
  323. | None -> ()
  324. | Some f -> print_field false f);
  325. List.iter (print_field false) c.cl_ordered_fields;
  326. List.iter (print_field true) c.cl_ordered_statics;
  327. (match c.cl_init with
  328. | None -> ()
  329. | Some e ->
  330. print "\n\tstatic function __init__() ";
  331. print "%s" (s_expr s_type e);
  332. print "\n");
  333. print "}";
  334. | Type.TEnumDecl e ->
  335. print "%s%s%senum %s%s {\n" (s_metas e.e_meta "") (if e.e_private then "private " else "") (if e.e_extern then "extern " else "") (s_type_path path) (params e.e_params);
  336. List.iter (fun n ->
  337. let f = PMap.find n e.e_constrs in
  338. print "\t%s%s;\n" f.ef_name (
  339. match f.ef_type with
  340. | TFun (al,t) -> Printf.sprintf "(%s)" (String.concat ", "
  341. (List.map (fun (n,o,t) -> (if o then "?" else "") ^ n ^ ":" ^ (s_type t)) al))
  342. | _ -> "")
  343. ) e.e_names;
  344. print "}"
  345. | Type.TTypeDecl t ->
  346. print "%s%stypedef %s%s = %s" (s_metas t.t_meta "") (if t.t_private then "private " else "") (s_type_path path) (params t.t_params) (s_type t.t_type);
  347. | Type.TAbstractDecl a ->
  348. print "%s%sabstract %s%s%s%s {}" (s_metas a.a_meta "") (if a.a_private then "private " else "") (s_type_path path) (params a.a_params)
  349. (String.concat " " (List.map (fun t -> " from " ^ s_type t) a.a_from))
  350. (String.concat " " (List.map (fun t -> " to " ^ s_type t) a.a_to));
  351. );
  352. close();
  353. ) com.types
  354. let dump_record com =
  355. List.iter (fun mt ->
  356. let buf,close = create_dumpfile_from_path com (t_path mt) in
  357. let s = match mt with
  358. | TClassDecl c -> Printer.s_tclass "" c
  359. | TEnumDecl en -> Printer.s_tenum "" en
  360. | TTypeDecl t -> Printer.s_tdef "" t
  361. | TAbstractDecl a -> Printer.s_tabstract "" a
  362. in
  363. Buffer.add_string buf s;
  364. close();
  365. ) com.types
  366. let dump_position com =
  367. List.iter (fun mt ->
  368. match mt with
  369. | TClassDecl c ->
  370. let buf,close = create_dumpfile_from_path com (t_path mt) in
  371. Printf.bprintf buf "%s\n" (s_type_path c.cl_path);
  372. let field cf =
  373. Printf.bprintf buf "\t%s\n" cf.cf_name;
  374. begin match cf.cf_expr with
  375. | None -> ()
  376. | Some e ->
  377. Printf.bprintf buf "%s\n" (Texpr.dump_with_pos "\t" e);
  378. end
  379. in
  380. Option.may field c.cl_constructor;
  381. List.iter field c.cl_ordered_statics;
  382. List.iter field c.cl_ordered_fields;
  383. close();
  384. | _ ->
  385. ()
  386. ) com.types
  387. let dump_types com =
  388. match Common.defined_value_safe com Define.Dump with
  389. | "pretty" -> dump_types com (Type.s_expr_pretty false "\t" true)
  390. | "legacy" -> dump_types com Type.s_expr
  391. | "record" -> dump_record com
  392. | "position" -> dump_position com
  393. | _ -> dump_types com (Type.s_expr_ast (not (Common.defined com Define.DumpIgnoreVarIds)) "\t")
  394. let dump_dependencies ?(target_override=None) com =
  395. let target_name = match target_override with
  396. | None -> platform_name_macro com
  397. | Some s -> s
  398. in
  399. let buf,close = create_dumpfile [] ["dump";target_name;".dependencies"] in
  400. let print fmt = Printf.kprintf (fun s -> Buffer.add_string buf s) fmt in
  401. let dep = Hashtbl.create 0 in
  402. List.iter (fun m ->
  403. print "%s:\n" m.m_extra.m_file;
  404. PMap.iter (fun _ m2 ->
  405. print "\t%s\n" (m2.m_extra.m_file);
  406. let l = try Hashtbl.find dep m2.m_extra.m_file with Not_found -> [] in
  407. Hashtbl.replace dep m2.m_extra.m_file (m :: l)
  408. ) m.m_extra.m_deps;
  409. ) com.Common.modules;
  410. close();
  411. let buf,close = create_dumpfile [] ["dump";target_name;".dependants"] in
  412. let print fmt = Printf.kprintf (fun s -> Buffer.add_string buf s) fmt in
  413. Hashtbl.iter (fun n ml ->
  414. print "%s:\n" n;
  415. List.iter (fun m ->
  416. print "\t%s\n" (m.m_extra.m_file);
  417. ) ml;
  418. ) dep;
  419. close()
  420. end
  421. (*
  422. Build a default safe-cast expression :
  423. { var $t = <e>; if( Std.is($t,<t>) ) $t else throw "Class cast error"; }
  424. *)
  425. let default_cast ?(vtmp="$t") com e texpr t p =
  426. let api = com.basic in
  427. let mk_texpr = function
  428. | TClassDecl c -> TAnon { a_fields = PMap.empty; a_status = ref (Statics c) }
  429. | TEnumDecl e -> TAnon { a_fields = PMap.empty; a_status = ref (EnumStatics e) }
  430. | TAbstractDecl a -> TAnon { a_fields = PMap.empty; a_status = ref (AbstractStatics a) }
  431. | TTypeDecl _ -> assert false
  432. in
  433. let vtmp = alloc_var VGenerated vtmp e.etype e.epos in
  434. let var = mk (TVar (vtmp,Some e)) api.tvoid p in
  435. let vexpr = mk (TLocal vtmp) e.etype p in
  436. let texpr = mk (TTypeExpr texpr) (mk_texpr texpr) p in
  437. let std = (try List.find (fun t -> t_path t = ([],"Std")) com.types with Not_found -> assert false) in
  438. let fis = (try
  439. let c = (match std with TClassDecl c -> c | _ -> assert false) in
  440. FStatic (c, PMap.find "is" c.cl_statics)
  441. with Not_found ->
  442. assert false
  443. ) in
  444. let std = mk (TTypeExpr std) (mk_texpr std) p in
  445. let is = mk (TField (std,fis)) (tfun [t_dynamic;t_dynamic] api.tbool) p in
  446. let is = mk (TCall (is,[vexpr;texpr])) api.tbool p in
  447. let enull = Texpr.Builder.make_null vexpr.etype p in
  448. let eop = Texpr.Builder.binop OpEq vexpr enull api.tbool p in
  449. let echeck = Texpr.Builder.binop OpBoolOr is eop api.tbool p in
  450. let exc = mk (TThrow (mk (TConst (TString "Class cast error")) api.tstring p)) t p in
  451. let check = mk (TIf (Texpr.Builder.mk_parent echeck,mk (TCast (vexpr,None)) t p,Some exc)) t p in
  452. mk (TBlock [var;check;vexpr]) t p
  453. module UnificationCallback = struct
  454. let tf_stack = new_rec_stack()
  455. let check_call_params f el tl =
  456. let rec loop acc el tl = match el,tl with
  457. | e :: el, (n,_,t) :: tl ->
  458. loop ((f e t) :: acc) el tl
  459. | [], [] ->
  460. acc
  461. | [],_ ->
  462. acc
  463. | e :: el, [] ->
  464. loop (e :: acc) el []
  465. in
  466. List.rev (loop [] el tl)
  467. let check_call f el t = match follow t with
  468. | TFun(args,_) ->
  469. check_call_params f el args
  470. | _ ->
  471. List.map (fun e -> f e t_dynamic) el
  472. let rec run ff e =
  473. let f e t =
  474. if not (type_iseq e.etype t) then
  475. ff e t
  476. else
  477. e
  478. in
  479. let check e = match e.eexpr with
  480. | TBinop((OpAssign | OpAssignOp _),e1,e2) ->
  481. assert false; (* this trigger #4347, to be fixed before enabling
  482. let e2 = f e2 e1.etype in
  483. {e with eexpr = TBinop(op,e1,e2)} *)
  484. | TVar(v,Some ev) ->
  485. let eo = Some (f ev v.v_type) in
  486. { e with eexpr = TVar(v,eo) }
  487. | TCall(e1,el) ->
  488. let el = check_call f el e1.etype in
  489. {e with eexpr = TCall(e1,el)}
  490. | TNew(c,tl,el) ->
  491. begin try
  492. let tcf,_ = get_constructor (fun cf -> apply_params c.cl_params tl cf.cf_type) c in
  493. let el = check_call f el tcf in
  494. {e with eexpr = TNew(c,tl,el)}
  495. with Not_found ->
  496. e
  497. end
  498. | TArrayDecl el ->
  499. begin match follow e.etype with
  500. | TInst({cl_path=[],"Array"},[t]) -> {e with eexpr = TArrayDecl(List.map (fun e -> f e t) el)}
  501. | _ -> e
  502. end
  503. | TObjectDecl fl ->
  504. begin match follow e.etype with
  505. | TAnon an ->
  506. let fl = List.map (fun ((n,p,qs),e) ->
  507. let e = try
  508. let t = (PMap.find n an.a_fields).cf_type in
  509. f e t
  510. with Not_found ->
  511. e
  512. in
  513. (n,p,qs),e
  514. ) fl in
  515. { e with eexpr = TObjectDecl fl }
  516. | _ -> e
  517. end
  518. | TReturn (Some e1) ->
  519. begin match tf_stack.rec_stack with
  520. | tf :: _ -> { e with eexpr = TReturn (Some (f e1 tf.tf_type))}
  521. | _ -> e
  522. end
  523. | _ ->
  524. e
  525. in
  526. match e.eexpr with
  527. | TFunction tf ->
  528. rec_stack_loop tf_stack tf (fun() -> {e with eexpr = TFunction({tf with tf_expr = run f tf.tf_expr})}) ()
  529. | _ ->
  530. check (Type.map_expr (run ff) e)
  531. end;;
  532. let interpolate_code com code tl f_string f_expr p =
  533. let exprs = Array.of_list tl in
  534. let i = ref 0 in
  535. let err msg =
  536. let pos = { p with pmin = p.pmin + !i } in
  537. com.error msg pos
  538. in
  539. let regex = Str.regexp "[{}]" in
  540. let rec loop m = match m with
  541. | [] ->
  542. ()
  543. | Str.Text txt :: tl ->
  544. i := !i + String.length txt;
  545. f_string txt;
  546. loop tl
  547. | Str.Delim a :: Str.Delim b :: tl when a = b ->
  548. i := !i + 2;
  549. f_string a;
  550. loop tl
  551. | Str.Delim "{" :: Str.Text n :: Str.Delim "}" :: tl ->
  552. begin try
  553. let expr = Array.get exprs (int_of_string n) in
  554. f_expr expr;
  555. with
  556. | Failure _ ->
  557. f_string ("{" ^ n ^ "}");
  558. | Invalid_argument _ ->
  559. err ("Out-of-bounds special parameter: " ^ n)
  560. end;
  561. i := !i + 2 + String.length n;
  562. loop tl
  563. | Str.Delim x :: tl ->
  564. f_string x;
  565. incr i;
  566. loop tl
  567. in
  568. loop (Str.full_split regex code)
  569. let map_source_header com f =
  570. match Common.defined_value_safe com Define.SourceHeader with
  571. | "" -> ()
  572. | s -> f s
  573. (* Static extensions for classes *)
  574. module ExtClass = struct
  575. let add_cl_init c e = match c.cl_init with
  576. | None -> c.cl_init <- Some e
  577. | Some e' -> c.cl_init <- Some (concat e' e)
  578. let add_static_init c cf e p =
  579. let ethis = Texpr.Builder.make_static_this c p in
  580. let ef1 = mk (TField(ethis,FStatic(c,cf))) cf.cf_type p in
  581. let e_assign = mk (TBinop(OpAssign,ef1,e)) e.etype p in
  582. add_cl_init c e_assign
  583. end