codegen.ml 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527
  1. (*
  2. * Haxe Compiler
  3. * Copyright (c)2005-2008 Nicolas Cannasse
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18. *)
  19. open Ast
  20. open Type
  21. open Common
  22. open Typecore
  23. (* -------------------------------------------------------------------------- *)
  24. (* TOOLS *)
  25. let field e name t p =
  26. mk (TField (e,name)) t p
  27. let fcall e name el ret p =
  28. let ft = tfun (List.map (fun e -> e.etype) el) ret in
  29. mk (TCall (field e name ft p,el)) ret p
  30. let mk_parent e =
  31. mk (TParenthesis e) e.etype e.epos
  32. let string com str p =
  33. mk (TConst (TString str)) com.basic.tstring p
  34. let binop op a b t p =
  35. mk (TBinop (op,a,b)) t p
  36. let index com e index t p =
  37. mk (TArray (e,mk (TConst (TInt (Int32.of_int index))) com.basic.tint p)) t p
  38. let concat e1 e2 =
  39. let e = (match e1.eexpr, e2.eexpr with
  40. | TBlock el1, TBlock el2 -> TBlock (el1@el2)
  41. | TBlock el, _ -> TBlock (el @ [e2])
  42. | _, TBlock el -> TBlock (e1 :: el)
  43. | _ , _ -> TBlock [e1;e2]
  44. ) in
  45. mk e e2.etype (punion e1.epos e2.epos)
  46. let type_constant com c p =
  47. let t = com.basic in
  48. match c with
  49. | Int s ->
  50. if String.length s > 10 && String.sub s 0 2 = "0x" then error "Invalid hexadecimal integer" p;
  51. (try
  52. mk (TConst (TInt (Int32.of_string s))) t.tint p
  53. with
  54. _ -> mk (TConst (TFloat s)) t.tfloat p)
  55. | Float f -> mk (TConst (TFloat f)) t.tfloat p
  56. | String s -> mk (TConst (TString s)) t.tstring p
  57. | Ident "true" -> mk (TConst (TBool true)) t.tbool p
  58. | Ident "false" -> mk (TConst (TBool false)) t.tbool p
  59. | Ident "null" -> mk (TConst TNull) (t.tnull (mk_mono())) p
  60. | Ident t -> error ("Invalid constant : " ^ t) p
  61. | Regexp _ -> error "Invalid constant" p
  62. let rec type_constant_value com (e,p) =
  63. match e with
  64. | EConst c ->
  65. type_constant com c p
  66. | EParenthesis e ->
  67. type_constant_value com e
  68. | EObjectDecl el ->
  69. mk (TObjectDecl (List.map (fun (n,e) -> n, type_constant_value com e) el)) (TAnon { a_fields = PMap.empty; a_status = ref Closed }) p
  70. | EArrayDecl el ->
  71. mk (TArrayDecl (List.map (type_constant_value com) el)) (com.basic.tarray t_dynamic) p
  72. | _ ->
  73. error "Constant value expected" p
  74. let rec has_properties c =
  75. List.exists (fun f ->
  76. match f.cf_kind with
  77. | Var { v_read = AccCall _ } -> true
  78. | Var { v_write = AccCall _ } -> true
  79. | _ -> false
  80. ) c.cl_ordered_fields || (match c.cl_super with Some (c,_) -> has_properties c | _ -> false)
  81. let get_properties fields =
  82. List.fold_left (fun acc f ->
  83. let acc = (match f.cf_kind with
  84. | Var { v_read = AccCall getter } -> ("get_" ^ f.cf_name , getter) :: acc
  85. | _ -> acc) in
  86. match f.cf_kind with
  87. | Var { v_write = AccCall setter } -> ("set_" ^ f.cf_name , setter) :: acc
  88. | _ -> acc
  89. ) [] fields
  90. let add_property_field com c =
  91. let p = c.cl_pos in
  92. let props = get_properties (c.cl_ordered_statics @ c.cl_ordered_fields) in
  93. match props with
  94. | [] -> ()
  95. | _ ->
  96. let fields,values = List.fold_left (fun (fields,values) (n,v) ->
  97. let cf = mk_field n com.basic.tstring p in
  98. PMap.add n cf fields,(n, string com v p) :: values
  99. ) (PMap.empty,[]) props in
  100. let t = mk_anon fields in
  101. let e = mk (TObjectDecl values) t p in
  102. let cf = mk_field "__properties__" t p in
  103. cf.cf_expr <- Some e;
  104. c.cl_statics <- PMap.add cf.cf_name cf c.cl_statics;
  105. c.cl_ordered_statics <- cf :: c.cl_ordered_statics
  106. (* -------------------------------------------------------------------------- *)
  107. (* REMOTING PROXYS *)
  108. let extend_remoting ctx c t p async prot =
  109. if c.cl_super <> None then error "Cannot extend several classes" p;
  110. (* remove forbidden packages *)
  111. let rules = ctx.com.package_rules in
  112. ctx.com.package_rules <- PMap.foldi (fun key r acc -> match r with Forbidden -> acc | _ -> PMap.add key r acc) rules PMap.empty;
  113. (* parse module *)
  114. let path = (t.tpackage,t.tname) in
  115. let new_name = (if async then "Async_" else "Remoting_") ^ t.tname in
  116. (* check if the proxy already exists *)
  117. let t = (try
  118. Typeload.load_type_def ctx p { tpackage = fst path; tname = new_name; tparams = []; tsub = None }
  119. with
  120. Error (Module_not_found _,p2) when p == p2 ->
  121. (* build it *)
  122. Common.log ctx.com ("Building proxy for " ^ s_type_path path);
  123. let file, decls = (try
  124. Typeload.parse_module ctx path p
  125. with
  126. | Not_found -> ctx.com.package_rules <- rules; error ("Could not load proxy module " ^ s_type_path path ^ (if fst path = [] then " (try using absolute path)" else "")) p
  127. | e -> ctx.com.package_rules <- rules; raise e) in
  128. ctx.com.package_rules <- rules;
  129. let base_fields = [
  130. { cff_name = "__cnx"; cff_pos = p; cff_doc = None; cff_meta = []; cff_access = []; cff_kind = FVar (Some (CTPath { tpackage = ["haxe";"remoting"]; tname = if async then "AsyncConnection" else "Connection"; tparams = []; tsub = None }),None) };
  131. { cff_name = "new"; cff_pos = p; cff_doc = None; cff_meta = []; cff_access = [APublic]; cff_kind = FFun { f_args = ["c",false,None,None]; f_type = None; f_expr = Some (EBinop (OpAssign,(EConst (Ident "__cnx"),p),(EConst (Ident "c"),p)),p); f_params = [] } };
  132. ] in
  133. let tvoid = CTPath { tpackage = []; tname = "Void"; tparams = []; tsub = None } in
  134. let build_field is_public acc f =
  135. if f.cff_name = "new" then
  136. acc
  137. else match f.cff_kind with
  138. | FFun fd when (is_public || List.mem APublic f.cff_access) && not (List.mem AStatic f.cff_access) ->
  139. if List.exists (fun (_,_,t,_) -> t = None) fd.f_args then error ("Field " ^ f.cff_name ^ " type is not complete and cannot be used by RemotingProxy") p;
  140. let eargs = [EArrayDecl (List.map (fun (a,_,_,_) -> (EConst (Ident a),p)) fd.f_args),p] in
  141. let ftype = (match fd.f_type with Some (CTPath { tpackage = []; tname = "Void" }) -> None | _ -> fd.f_type) in
  142. let fargs, eargs = if async then match ftype with
  143. | Some tret -> fd.f_args @ ["__callb",true,Some (CTFunction ([tret],tvoid)),None], eargs @ [EConst (Ident "__callb"),p]
  144. | _ -> fd.f_args, eargs @ [EConst (Ident "null"),p]
  145. else
  146. fd.f_args, eargs
  147. in
  148. let id = (EConst (String f.cff_name), p) in
  149. let id = if prot then id else ECall ((EConst (Ident "__unprotect__"),p),[id]),p in
  150. let expr = ECall (
  151. (EField (
  152. (ECall ((EField ((EConst (Ident "__cnx"),p),"resolve"),p),[id]),p),
  153. "call")
  154. ,p),eargs),p
  155. in
  156. let expr = if async || ftype = None then expr else (EReturn (Some expr),p) in
  157. let fd = {
  158. f_params = fd.f_params;
  159. f_args = fargs;
  160. f_type = if async then None else ftype;
  161. f_expr = Some (EBlock [expr],p);
  162. } in
  163. { cff_name = f.cff_name; cff_pos = p; cff_doc = None; cff_meta = []; cff_access = [APublic]; cff_kind = FFun fd } :: acc
  164. | _ -> acc
  165. in
  166. let decls = List.map (fun d ->
  167. match d with
  168. | EClass c, p when c.d_name = t.tname ->
  169. let is_public = List.mem HExtern c.d_flags || List.mem HInterface c.d_flags in
  170. let fields = List.rev (List.fold_left (build_field is_public) base_fields c.d_data) in
  171. (EClass { c with d_flags = []; d_name = new_name; d_data = fields },p)
  172. | _ -> d
  173. ) decls in
  174. let m = Typeload.type_module ctx (t.tpackage,new_name) file decls p in
  175. add_dependency ctx.current m;
  176. try
  177. List.find (fun tdecl -> snd (t_path tdecl) = new_name) m.m_types
  178. with Not_found ->
  179. error ("Module " ^ s_type_path path ^ " does not define type " ^ t.tname) p
  180. ) in
  181. match t with
  182. | TClassDecl c2 when c2.cl_types = [] -> c.cl_super <- Some (c2,[]);
  183. | _ -> error "Remoting proxy must be a class without parameters" p
  184. (* -------------------------------------------------------------------------- *)
  185. (* HAXE.RTTI.GENERIC *)
  186. let rec build_generic ctx c p tl =
  187. let pack = fst c.cl_path in
  188. let recurse = ref false in
  189. let rec check_recursive t =
  190. match follow t with
  191. | TInst (c,tl) ->
  192. if c.cl_kind = KTypeParameter then recurse := true;
  193. List.iter check_recursive tl;
  194. | _ ->
  195. ()
  196. in
  197. let name = String.concat "_" (snd c.cl_path :: (List.map (fun t ->
  198. check_recursive t;
  199. let path = (match follow t with
  200. | TInst (c,_) -> c.cl_path
  201. | TEnum (e,_) -> e.e_path
  202. | TMono _ -> error "Type parameter must be explicit when creating a generic instance" p
  203. | _ -> error "Type parameter must be a class or enum instance" p
  204. ) in
  205. match path with
  206. | [] , name -> name
  207. | l , name -> String.concat "_" l ^ "_" ^ name
  208. ) tl)) in
  209. if !recurse then
  210. TInst (c,tl) (* build a normal instance *)
  211. else try
  212. Typeload.load_instance ctx { tpackage = pack; tname = name; tparams = []; tsub = None } p false
  213. with Error(Module_not_found path,_) when path = (pack,name) ->
  214. let m = (try Hashtbl.find ctx.g.modules (Hashtbl.find ctx.g.types_module c.cl_path) with Not_found -> assert false) in
  215. let ctx = { ctx with local_types = m.m_types @ ctx.local_types } in
  216. let mg = {
  217. m_id = alloc_mid();
  218. m_path = (pack,name);
  219. m_types = [];
  220. m_extra = module_extra (s_type_path (pack,name)) m.m_extra.m_sign 0. MFake;
  221. } in
  222. let cg = mk_class mg (pack,name) c.cl_pos in
  223. mg.m_types <- [TClassDecl cg];
  224. Hashtbl.add ctx.g.modules mg.m_path mg;
  225. add_dependency mg m;
  226. add_dependency ctx.current mg;
  227. let rec loop l1 l2 =
  228. match l1, l2 with
  229. | [] , [] -> []
  230. | (x,TLazy f) :: l1, _ -> loop ((x,(!f)()) :: l1) l2
  231. | (_,t1) :: l1 , t2 :: l2 -> (t1,t2) :: loop l1 l2
  232. | _ -> assert false
  233. in
  234. let subst = loop c.cl_types tl in
  235. let rec build_type t =
  236. match t with
  237. | TInst ({ cl_kind = KGeneric } as c2,tl2) ->
  238. (* maybe loop, or generate cascading generics *)
  239. let _, _, f = ctx.g.do_build_instance ctx (TClassDecl c2) p in
  240. f (List.map build_type tl2)
  241. | _ ->
  242. try List.assq t subst with Not_found -> Type.map build_type t
  243. in
  244. let vars = Hashtbl.create 0 in
  245. let build_var v =
  246. try
  247. Hashtbl.find vars v.v_id
  248. with Not_found ->
  249. let v2 = alloc_var v.v_name (build_type v.v_type) in
  250. Hashtbl.add vars v.v_id v2;
  251. v2
  252. in
  253. let rec build_expr e = map_expr_type build_expr build_type build_var e in
  254. let build_field f =
  255. let t = build_type f.cf_type in
  256. { f with cf_type = t; cf_expr = (match f.cf_expr with None -> None | Some e -> Some (build_expr e)) }
  257. in
  258. if c.cl_init <> None || c.cl_dynamic <> None then error "This class can't be generic" p;
  259. if c.cl_ordered_statics <> [] then error "A generic class can't have static fields" p;
  260. cg.cl_super <- (match c.cl_super with
  261. | None -> None
  262. | Some (cs,pl) ->
  263. (match apply_params c.cl_types tl (TInst (cs,pl)) with
  264. | TInst (cs,pl) when cs.cl_kind = KGeneric ->
  265. (match build_generic ctx cs p pl with
  266. | TInst (cs,pl) -> Some (cs,pl)
  267. | _ -> assert false)
  268. | TInst (cs,pl) -> Some (cs,pl)
  269. | _ -> assert false)
  270. );
  271. cg.cl_kind <- KGenericInstance (c,tl);
  272. cg.cl_interface <- c.cl_interface;
  273. cg.cl_constructor <- (match c.cl_constructor, c.cl_super with
  274. | None, None -> None
  275. | Some c, _ -> Some (build_field c)
  276. | _ -> error "Please define a constructor for this class in order to use it as generic" c.cl_pos
  277. );
  278. cg.cl_implements <- List.map (fun (i,tl) ->
  279. (match follow (build_type (TInst (i, List.map build_type tl))) with
  280. | TInst (i,tl) -> i, tl
  281. | _ -> assert false)
  282. ) c.cl_implements;
  283. cg.cl_ordered_fields <- List.map (fun f ->
  284. let f = build_field f in
  285. cg.cl_fields <- PMap.add f.cf_name f cg.cl_fields;
  286. f
  287. ) c.cl_ordered_fields;
  288. TInst (cg,[])
  289. (* -------------------------------------------------------------------------- *)
  290. (* HAXE.XML.PROXY *)
  291. let extend_xml_proxy ctx c t file p =
  292. let t = Typeload.load_complex_type ctx p t in
  293. let file = (try Common.find_file ctx.com file with Not_found -> file) in
  294. add_dependency c.cl_module (create_fake_module ctx file);
  295. let used = ref PMap.empty in
  296. let print_results() =
  297. PMap.iter (fun id used ->
  298. if not used then ctx.com.warning (id ^ " is not used") p;
  299. ) (!used)
  300. in
  301. let check_used = Common.defined ctx.com "check-xml-proxy" in
  302. if check_used then ctx.g.hook_generate <- print_results :: ctx.g.hook_generate;
  303. try
  304. let rec loop = function
  305. | Xml.Element (_,attrs,childs) ->
  306. (try
  307. let id = List.assoc "id" attrs in
  308. if PMap.mem id c.cl_fields then error ("Duplicate id " ^ id) p;
  309. let t = if not check_used then t else begin
  310. used := PMap.add id false (!used);
  311. let ft() = used := PMap.add id true (!used); t in
  312. TLazy (ref ft)
  313. end in
  314. let f = {
  315. cf_name = id;
  316. cf_type = t;
  317. cf_public = true;
  318. cf_pos = p;
  319. cf_doc = None;
  320. cf_meta = no_meta;
  321. cf_kind = Var { v_read = AccResolve; v_write = AccNo };
  322. cf_params = [];
  323. cf_expr = None;
  324. cf_overloads = [];
  325. } in
  326. c.cl_fields <- PMap.add id f c.cl_fields;
  327. with
  328. Not_found -> ());
  329. List.iter loop childs;
  330. | Xml.PCData _ -> ()
  331. in
  332. loop (Xml.parse_file file)
  333. with
  334. | Xml.Error e -> error ("XML error " ^ Xml.error e) p
  335. | Xml.File_not_found f -> error ("XML File not found : " ^ f) p
  336. (* -------------------------------------------------------------------------- *)
  337. (* BUILD META DATA OBJECT *)
  338. let build_metadata com t =
  339. let api = com.basic in
  340. let p, meta, fields, statics = (match t with
  341. | TClassDecl c ->
  342. let fields = List.map (fun f -> f.cf_name,f.cf_meta) (c.cl_ordered_fields @ (match c.cl_constructor with None -> [] | Some f -> [{ f with cf_name = "_" }])) in
  343. let statics = List.map (fun f -> f.cf_name,f.cf_meta) c.cl_ordered_statics in
  344. (c.cl_pos, ["",c.cl_meta],fields,statics)
  345. | TEnumDecl e ->
  346. (e.e_pos, ["",e.e_meta],List.map (fun n -> n, (PMap.find n e.e_constrs).ef_meta) e.e_names, [])
  347. | TTypeDecl t ->
  348. (t.t_pos, ["",t.t_meta],(match follow t.t_type with TAnon a -> PMap.fold (fun f acc -> (f.cf_name,f.cf_meta) :: acc) a.a_fields [] | _ -> []),[])
  349. ) in
  350. let filter l =
  351. let l = List.map (fun (n,ml) -> n, List.filter (fun (m,_,_) -> m.[0] <> ':') ml) l in
  352. List.filter (fun (_,ml) -> ml <> []) l
  353. in
  354. let meta, fields, statics = filter meta, filter fields, filter statics in
  355. let make_meta_field ml =
  356. let h = Hashtbl.create 0 in
  357. mk (TObjectDecl (List.map (fun (f,el,p) ->
  358. if Hashtbl.mem h f then error ("Duplicate metadata '" ^ f ^ "'") p;
  359. Hashtbl.add h f ();
  360. f, mk (match el with [] -> TConst TNull | _ -> TArrayDecl (List.map (type_constant_value com) el)) (api.tarray t_dynamic) p
  361. ) ml)) (api.tarray t_dynamic) p
  362. in
  363. let make_meta l =
  364. mk (TObjectDecl (List.map (fun (f,ml) -> f,make_meta_field ml) l)) t_dynamic p
  365. in
  366. if meta = [] && fields = [] && statics = [] then
  367. None
  368. else
  369. let meta_obj = [] in
  370. let meta_obj = (if fields = [] then meta_obj else ("fields",make_meta fields) :: meta_obj) in
  371. let meta_obj = (if statics = [] then meta_obj else ("statics",make_meta statics) :: meta_obj) in
  372. let meta_obj = (try ("obj", make_meta_field (List.assoc "" meta)) :: meta_obj with Not_found -> meta_obj) in
  373. Some (mk (TObjectDecl meta_obj) t_dynamic p)
  374. (* -------------------------------------------------------------------------- *)
  375. (* MACRO TYPE *)
  376. let build_macro_type ctx pl p =
  377. let path, field, args = (match pl with
  378. | [TInst ({ cl_kind = KExpr (ECall (e,args),_) },_)]
  379. | [TInst ({ cl_kind = KExpr (EArrayDecl [ECall (e,args),_],_) },_)] ->
  380. let rec loop e =
  381. match fst e with
  382. | EField (e,f) -> f :: loop e
  383. | EConst (Ident i) -> [i]
  384. | _ -> error "Invalid macro call" p
  385. in
  386. (match loop e with
  387. | meth :: cl :: path -> (List.rev path,cl), meth, args
  388. | _ -> error "Invalid macro call" p)
  389. | _ ->
  390. error "MacroType require a single expression call parameter" p
  391. ) in
  392. let old = ctx.ret in
  393. let t = (match ctx.g.do_macro ctx MMacroType path field args p with
  394. | None -> mk_mono()
  395. | Some _ -> ctx.ret
  396. ) in
  397. ctx.ret <- old;
  398. t
  399. (* -------------------------------------------------------------------------- *)
  400. (* API EVENTS *)
  401. let build_instance ctx mtype p =
  402. match mtype with
  403. | TClassDecl c ->
  404. let ft = (fun pl ->
  405. match c.cl_kind with
  406. | KGeneric ->
  407. let r = exc_protect ctx (fun r ->
  408. let t = mk_mono() in
  409. r := (fun() -> t);
  410. unify_raise ctx (build_generic ctx c p pl) t p;
  411. t
  412. ) in
  413. delay ctx (fun() -> ignore ((!r)()));
  414. TLazy r
  415. | KMacroType ->
  416. let r = exc_protect ctx (fun r ->
  417. let t = mk_mono() in
  418. r := (fun() -> t);
  419. unify_raise ctx (build_macro_type ctx pl p) t p;
  420. t
  421. ) in
  422. delay ctx (fun() -> ignore ((!r)()));
  423. TLazy r
  424. | _ ->
  425. TInst (c,pl)
  426. ) in
  427. c.cl_types , c.cl_path , ft
  428. | TEnumDecl e ->
  429. e.e_types , e.e_path , (fun t -> TEnum (e,t))
  430. | TTypeDecl t ->
  431. t.t_types , t.t_path , (fun tl -> TType(t,tl))
  432. let on_inherit ctx c p h =
  433. match h with
  434. | HExtends { tpackage = ["haxe";"remoting"]; tname = "Proxy"; tparams = [TPType(CTPath t)] } ->
  435. extend_remoting ctx c t p false true;
  436. false
  437. | HExtends { tpackage = ["haxe";"remoting"]; tname = "AsyncProxy"; tparams = [TPType(CTPath t)] } ->
  438. extend_remoting ctx c t p true true;
  439. false
  440. | HExtends { tpackage = ["mt"]; tname = "AsyncProxy"; tparams = [TPType(CTPath t)] } ->
  441. extend_remoting ctx c t p true false;
  442. false
  443. | HImplements { tpackage = ["haxe";"rtti"]; tname = "Generic"; tparams = [] } ->
  444. if Common.defined ctx.com "haxe3" then error ("Implementing haxe.rtti.Generic is deprecated in haxe 3, please use @:generic instead") c.cl_pos;
  445. if c.cl_types <> [] then c.cl_kind <- KGeneric;
  446. false
  447. | HExtends { tpackage = ["haxe";"xml"]; tname = "Proxy"; tparams = [TPExpr(EConst (String file),p);TPType t] } ->
  448. extend_xml_proxy ctx c t file p;
  449. true
  450. | _ ->
  451. true
  452. (* -------------------------------------------------------------------------- *)
  453. (* FINAL GENERATION *)
  454. (*
  455. Adds member field initializations as assignments to the constructor
  456. *)
  457. let add_field_inits com c =
  458. let ethis = mk (TConst TThis) (TInst (c,List.map snd c.cl_types)) c.cl_pos in
  459. (* TODO: we have to find a variable name which is not used in any of the functions *)
  460. let v = alloc_var "_g" ethis.etype in
  461. let rec can_init_inline cf e = match com.platform,e.eexpr with
  462. | Flash8,_ -> true
  463. | Flash,_ when Common.defined com "as3" && (match cf.cf_kind with Var _ -> true | Method _ -> false) -> true
  464. | Php, TTypeExpr _ -> false
  465. | Php,_ ->
  466. (match cf.cf_kind with Var({v_write = AccCall _}) -> false | _ -> true)
  467. | _ -> false
  468. in
  469. let need_this = ref false in
  470. let inits,fields = List.fold_left (fun (inits,fields) cf ->
  471. match cf.cf_kind,cf.cf_expr with
  472. | Var _, Some e when can_init_inline cf e -> (inits, cf :: fields)
  473. | Var _, Some _ -> (cf :: inits, cf :: fields)
  474. | Method MethDynamic, Some e when Common.defined com "as3" ->
  475. (* we move the initialization of dynamic functions to the constructor and also solve the
  476. 'this' problem along the way *)
  477. let rec use_this v e = match e.eexpr with
  478. | TConst TThis ->
  479. need_this := true;
  480. mk (TLocal v) v.v_type e.epos
  481. | _ -> Type.map_expr (use_this v) e
  482. in
  483. let e = Type.map_expr (use_this v) e in
  484. let cf = {cf with cf_expr = Some e} in
  485. (* if the method is an override, we have to remove the class field to not get invalid overrides *)
  486. let fields = if List.mem cf.cf_name c.cl_overrides then begin
  487. c.cl_fields <- PMap.remove cf.cf_name c.cl_fields;
  488. fields
  489. end else
  490. cf :: fields
  491. in
  492. (cf :: inits, fields)
  493. | _ -> (inits, cf :: fields)
  494. ) ([],[]) c.cl_ordered_fields in
  495. c.cl_ordered_fields <- fields;
  496. match inits with
  497. | [] -> ()
  498. | _ ->
  499. let el = List.map (fun cf ->
  500. match cf.cf_expr with
  501. | None -> assert false
  502. | Some e ->
  503. let lhs = mk (TField(ethis,cf.cf_name)) e.etype e.epos in
  504. cf.cf_expr <- None;
  505. let eassign = mk (TBinop(OpAssign,lhs,e)) lhs.etype e.epos in
  506. if Common.defined com "as3" then begin
  507. let echeck = mk (TBinop(OpEq,lhs,(mk (TConst TNull) lhs.etype e.epos))) com.basic.tbool e.epos in
  508. mk (TIf(echeck,eassign,None)) eassign.etype e.epos
  509. end else
  510. eassign;
  511. ) inits in
  512. let el = if !need_this then (mk (TVars([v, Some ethis])) ethis.etype ethis.epos) :: el else el in
  513. match c.cl_constructor with
  514. | None ->
  515. let ct = TFun([],com.basic.tvoid) in
  516. let ce = mk (TFunction {
  517. tf_args = [];
  518. tf_type = com.basic.tvoid;
  519. tf_expr = mk (TBlock el) com.basic.tvoid c.cl_pos;
  520. }) ct c.cl_pos in
  521. let ctor = mk_field "new" ct c.cl_pos in
  522. ctor.cf_kind <- Method MethNormal;
  523. c.cl_constructor <- Some { ctor with cf_expr = Some ce };
  524. | Some cf ->
  525. match cf.cf_expr with
  526. | Some { eexpr = TFunction f } ->
  527. let bl = match f.tf_expr with {eexpr = TBlock b } -> b | x -> [x] in
  528. let ce = mk (TFunction {f with tf_expr = mk (TBlock (el @ bl)) com.basic.tvoid c.cl_pos }) cf.cf_type cf.cf_pos in
  529. c.cl_constructor <- Some {cf with cf_expr = Some ce }
  530. | _ ->
  531. assert false
  532. let has_rtti ctx c =
  533. let rec has_rtti_new c =
  534. has_meta ":rttiInfos" c.cl_meta || match c.cl_super with None -> false | Some (csup,_) -> has_rtti_new csup
  535. in
  536. let rec has_rtti_old c =
  537. List.exists (function (t,pl) ->
  538. match t, pl with
  539. | { cl_path = ["haxe";"rtti"],"Infos" },[] -> true
  540. | _ -> false
  541. ) c.cl_implements || (match c.cl_super with None -> false | Some (c,_) -> has_rtti_old c)
  542. in
  543. if Common.defined ctx.com "haxe3" then begin
  544. if has_rtti_old c then error ("Implementing haxe.rtti.Infos is deprecated in haxe 3, please use @:rttiInfos instead") c.cl_pos;
  545. has_rtti_new c
  546. end else
  547. has_rtti_old c || has_rtti_new c
  548. let restore c =
  549. let meta = c.cl_meta and path = c.cl_path and ext = c.cl_extern in
  550. let fl = c.cl_fields and ofl = c.cl_ordered_fields and st = c.cl_statics and ost = c.cl_ordered_statics in
  551. (fun() ->
  552. c.cl_meta <- meta;
  553. c.cl_extern <- ext;
  554. c.cl_path <- path;
  555. c.cl_fields <- fl;
  556. c.cl_ordered_fields <- ofl;
  557. c.cl_statics <- st;
  558. c.cl_ordered_statics <- ost;
  559. )
  560. let on_generate ctx t =
  561. match t with
  562. | TClassDecl c ->
  563. if c.cl_private then begin
  564. let rpath = (fst c.cl_module.m_path,"_" ^ snd c.cl_module.m_path) in
  565. if Hashtbl.mem ctx.g.types_module rpath then error ("This private class name will clash with " ^ s_type_path rpath) c.cl_pos;
  566. end;
  567. c.cl_restore <- restore c;
  568. List.iter (fun m ->
  569. match m with
  570. | ":native",[Ast.EConst (Ast.String name),p],mp ->
  571. c.cl_meta <- (":realPath",[Ast.EConst (Ast.String (s_type_path c.cl_path)),p],mp) :: c.cl_meta;
  572. c.cl_path <- parse_path name;
  573. | _ -> ()
  574. ) c.cl_meta;
  575. if has_rtti ctx c && not (PMap.mem "__rtti" c.cl_statics) then begin
  576. let f = mk_field "__rtti" ctx.t.tstring c.cl_pos in
  577. let str = Genxml.gen_type_string ctx.com t in
  578. f.cf_expr <- Some (mk (TConst (TString str)) f.cf_type c.cl_pos);
  579. c.cl_ordered_statics <- f :: c.cl_ordered_statics;
  580. c.cl_statics <- PMap.add f.cf_name f c.cl_statics;
  581. end;
  582. let do_remove f =
  583. (not ctx.in_macro && f.cf_kind = Method MethMacro) || has_meta ":extern" f.cf_meta
  584. in
  585. List.iter (fun f ->
  586. if do_remove f then begin
  587. c.cl_statics <- PMap.remove f.cf_name c.cl_statics;
  588. c.cl_ordered_statics <- List.filter (fun f2 -> f != f2) c.cl_ordered_statics;
  589. end
  590. ) c.cl_ordered_statics;
  591. List.iter (fun f ->
  592. if do_remove f then begin
  593. c.cl_fields <- PMap.remove f.cf_name c.cl_fields;
  594. c.cl_ordered_fields <- List.filter (fun f2 -> f != f2) c.cl_ordered_fields;
  595. end
  596. ) c.cl_ordered_fields;
  597. if not c.cl_extern then add_field_inits ctx.com c;
  598. (match build_metadata ctx.com t with
  599. | None -> ()
  600. | Some e ->
  601. let f = mk_field "__meta__" t_dynamic c.cl_pos in
  602. f.cf_expr <- Some e;
  603. c.cl_ordered_statics <- f :: c.cl_ordered_statics;
  604. c.cl_statics <- PMap.add f.cf_name f c.cl_statics);
  605. c.cl_implements <- List.filter (fun (c,_) -> not (has_meta ":remove" c.cl_meta)) c.cl_implements;
  606. | TEnumDecl e ->
  607. List.iter (fun m ->
  608. match m with
  609. | ":native",[Ast.EConst (Ast.String name),p],mp ->
  610. e.e_meta <- (":realPath",[Ast.EConst (Ast.String (s_type_path e.e_path)),p],mp) :: e.e_meta;
  611. e.e_path <- parse_path name;
  612. | _ -> ()
  613. ) e.e_meta;
  614. | _ ->
  615. ()
  616. (* -------------------------------------------------------------------------- *)
  617. (* LOCAL VARIABLES USAGE *)
  618. type usage =
  619. | Block of ((usage -> unit) -> unit)
  620. | Loop of ((usage -> unit) -> unit)
  621. | Function of ((usage -> unit) -> unit)
  622. | Declare of tvar
  623. | Use of tvar
  624. let rec local_usage f e =
  625. match e.eexpr with
  626. | TLocal v ->
  627. f (Use v)
  628. | TVars l ->
  629. List.iter (fun (v,e) ->
  630. (match e with None -> () | Some e -> local_usage f e);
  631. f (Declare v);
  632. ) l
  633. | TFunction tf ->
  634. let cc f =
  635. List.iter (fun (v,_) -> f (Declare v)) tf.tf_args;
  636. local_usage f tf.tf_expr;
  637. in
  638. f (Function cc)
  639. | TBlock l ->
  640. f (Block (fun f -> List.iter (local_usage f) l))
  641. | TFor (v,it,e) ->
  642. local_usage f it;
  643. f (Loop (fun f ->
  644. f (Declare v);
  645. local_usage f e;
  646. ))
  647. | TWhile _ ->
  648. f (Loop (fun f ->
  649. iter (local_usage f) e
  650. ))
  651. | TTry (e,catchs) ->
  652. local_usage f e;
  653. List.iter (fun (v,e) ->
  654. f (Block (fun f ->
  655. f (Declare v);
  656. local_usage f e;
  657. ))
  658. ) catchs;
  659. | TMatch (e,_,cases,def) ->
  660. local_usage f e;
  661. List.iter (fun (_,vars,e) ->
  662. let cc f =
  663. (match vars with
  664. | None -> ()
  665. | Some l -> List.iter (function None -> () | Some v -> f (Declare v)) l);
  666. local_usage f e;
  667. in
  668. f (Block cc)
  669. ) cases;
  670. (match def with None -> () | Some e -> local_usage f e);
  671. | _ ->
  672. iter (local_usage f) e
  673. (* -------------------------------------------------------------------------- *)
  674. (* BLOCK VARIABLES CAPTURE *)
  675. (*
  676. For some platforms, it will simply mark the variables which are used in closures
  677. using the v_capture flag so it can be processed in a more optimized
  678. For Flash/JS platforms, it will ensure that variables used in loop sub-functions
  679. have an unique scope. It transforms the following expression :
  680. for( x in array )
  681. funs.push(function() return x++);
  682. Into the following :
  683. for( _x in array ) {
  684. var x = [_x];
  685. funs.push(function(x) { function() return x[0]++; }(x));
  686. }
  687. *)
  688. let captured_vars com e =
  689. let t = com.basic in
  690. let rec mk_init av v pos =
  691. mk (TVars [av,Some (mk (TArrayDecl [mk (TLocal v) v.v_type pos]) av.v_type pos)]) t.tvoid pos
  692. and mk_var v used =
  693. alloc_var v.v_name (PMap.find v.v_id used)
  694. and wrap used e =
  695. match e.eexpr with
  696. | TVars vl ->
  697. let vl = List.map (fun (v,ve) ->
  698. if PMap.mem v.v_id used then
  699. v, Some (mk (TArrayDecl (match ve with None -> [] | Some e -> [wrap used e])) v.v_type e.epos)
  700. else
  701. v, (match ve with None -> None | Some e -> Some (wrap used e))
  702. ) vl in
  703. { e with eexpr = TVars vl }
  704. | TLocal v when PMap.mem v.v_id used ->
  705. mk (TArray ({ e with etype = v.v_type },mk (TConst (TInt 0l)) t.tint e.epos)) e.etype e.epos
  706. | TFor (v,it,expr) when PMap.mem v.v_id used ->
  707. let vtmp = mk_var v used in
  708. let it = wrap used it in
  709. let expr = wrap used expr in
  710. mk (TFor (vtmp,it,concat (mk_init v vtmp e.epos) expr)) e.etype e.epos
  711. | TTry (expr,catchs) ->
  712. let catchs = List.map (fun (v,e) ->
  713. let e = wrap used e in
  714. try
  715. let vtmp = mk_var v used in
  716. vtmp, concat (mk_init v vtmp e.epos) e
  717. with Not_found ->
  718. v, e
  719. ) catchs in
  720. mk (TTry (wrap used expr,catchs)) e.etype e.epos
  721. | TMatch (expr,enum,cases,def) ->
  722. let cases = List.map (fun (il,vars,e) ->
  723. let pos = e.epos in
  724. let e = ref (wrap used e) in
  725. let vars = match vars with
  726. | None -> None
  727. | Some l ->
  728. Some (List.map (fun v ->
  729. match v with
  730. | Some v when PMap.mem v.v_id used ->
  731. let vtmp = mk_var v used in
  732. e := concat (mk_init v vtmp pos) !e;
  733. Some vtmp
  734. | _ -> v
  735. ) l)
  736. in
  737. il, vars, !e
  738. ) cases in
  739. let def = match def with None -> None | Some e -> Some (wrap used e) in
  740. mk (TMatch (wrap used expr,enum,cases,def)) e.etype e.epos
  741. | TFunction f ->
  742. (*
  743. list variables that are marked as used, but also used in that
  744. function and which are not declared inside it !
  745. *)
  746. let fused = ref PMap.empty in
  747. let tmp_used = ref used in
  748. let rec browse = function
  749. | Block f | Loop f | Function f -> f browse
  750. | Use v ->
  751. if PMap.mem v.v_id !tmp_used then fused := PMap.add v.v_id v !fused;
  752. | Declare v ->
  753. tmp_used := PMap.remove v.v_id !tmp_used
  754. in
  755. local_usage browse e;
  756. let vars = PMap.fold (fun v acc -> v :: acc) !fused [] in
  757. (* in case the variable has been marked as used in a parallel scope... *)
  758. let fexpr = ref (wrap used f.tf_expr) in
  759. let fargs = List.map (fun (v,o) ->
  760. if PMap.mem v.v_id used then
  761. let vtmp = mk_var v used in
  762. fexpr := concat (mk_init v vtmp e.epos) !fexpr;
  763. vtmp, o
  764. else
  765. v, o
  766. ) f.tf_args in
  767. let e = { e with eexpr = TFunction { f with tf_args = fargs; tf_expr = !fexpr } } in
  768. (match com.platform with
  769. | Cpp | Java | Cs -> e
  770. | _ ->
  771. mk (TCall (
  772. mk_parent (mk (TFunction {
  773. tf_args = List.map (fun v -> v, None) vars;
  774. tf_type = e.etype;
  775. tf_expr = mk_block (mk (TReturn (Some e)) e.etype e.epos);
  776. }) (TFun (List.map (fun v -> v.v_name,false,v.v_type) vars,e.etype)) e.epos),
  777. List.map (fun v -> mk (TLocal v) v.v_type e.epos) vars)
  778. ) e.etype e.epos)
  779. | _ ->
  780. map_expr (wrap used) e
  781. and do_wrap used e =
  782. if PMap.is_empty used then
  783. e
  784. else
  785. let used = PMap.map (fun v ->
  786. let vt = v.v_type in
  787. v.v_type <- t.tarray vt;
  788. v.v_capture <- true;
  789. vt
  790. ) used in
  791. wrap used e
  792. and out_loop e =
  793. match e.eexpr with
  794. | TFor _ | TWhile _ ->
  795. (*
  796. collect variables that are declared in loop but used in subfunctions
  797. *)
  798. let vars = ref PMap.empty in
  799. let used = ref PMap.empty in
  800. let depth = ref 0 in
  801. let rec collect_vars in_loop = function
  802. | Block f ->
  803. let old = !vars in
  804. f (collect_vars in_loop);
  805. vars := old;
  806. | Loop f ->
  807. let old = !vars in
  808. f (collect_vars true);
  809. vars := old;
  810. | Function f ->
  811. incr depth;
  812. f (collect_vars false);
  813. decr depth;
  814. | Declare v ->
  815. if in_loop then vars := PMap.add v.v_id !depth !vars;
  816. | Use v ->
  817. try
  818. let d = PMap.find v.v_id !vars in
  819. if d <> !depth then used := PMap.add v.v_id v !used;
  820. with Not_found ->
  821. ()
  822. in
  823. local_usage (collect_vars false) e;
  824. do_wrap !used e
  825. | _ ->
  826. map_expr out_loop e
  827. and all_vars e =
  828. let vars = ref PMap.empty in
  829. let used = ref PMap.empty in
  830. let depth = ref 0 in
  831. let rec collect_vars = function
  832. | Block f ->
  833. let old = !vars in
  834. f collect_vars;
  835. vars := old;
  836. | Loop f ->
  837. let old = !vars in
  838. f collect_vars;
  839. vars := old;
  840. | Function f ->
  841. incr depth;
  842. f collect_vars;
  843. decr depth;
  844. | Declare v ->
  845. vars := PMap.add v.v_id !depth !vars;
  846. | Use v ->
  847. try
  848. let d = PMap.find v.v_id !vars in
  849. if d <> !depth then used := PMap.add v.v_id v !used;
  850. with Not_found -> ()
  851. in
  852. local_usage collect_vars e;
  853. !used
  854. in
  855. match com.platform with
  856. | Php | Cross ->
  857. e
  858. | Neko ->
  859. (*
  860. this could be optimized to take into account only vars
  861. that are actually modified in closures or *after* closure
  862. declaration.
  863. *)
  864. let used = all_vars e in
  865. PMap.iter (fun _ v -> v.v_capture <- true) used;
  866. e
  867. | Cs | Java ->
  868. let used = all_vars e in
  869. PMap.iter (fun _ v -> v.v_capture <- true) used;
  870. do_wrap used e
  871. | Cpp ->
  872. do_wrap (all_vars e) e
  873. | Flash8 | Flash ->
  874. let used = all_vars e in
  875. PMap.iter (fun _ v -> v.v_capture <- true) used;
  876. out_loop e
  877. | Js ->
  878. out_loop e
  879. (* -------------------------------------------------------------------------- *)
  880. (* RENAME LOCAL VARS *)
  881. let rename_local_vars com e =
  882. let as3 = Common.defined com "as3" || com.platform = Cs in (* C# demands a similar behavior than AS3 *)
  883. let no_scope = com.platform = Js || com.platform = Java || as3 in
  884. let vars = ref PMap.empty in
  885. let all_vars = ref PMap.empty in
  886. let vtemp = alloc_var "~" t_dynamic in
  887. let rebuild_vars = ref false in
  888. let rebuild m =
  889. PMap.fold (fun v acc -> PMap.add v.v_name v acc) m PMap.empty
  890. in
  891. let save() =
  892. let old = !vars in
  893. if as3 then (fun() -> ()) else (fun() -> vars := if !rebuild_vars then rebuild old else old)
  894. in
  895. let rename v =
  896. let count = ref 1 in
  897. while PMap.mem (v.v_name ^ string_of_int !count) (!vars) do
  898. incr count;
  899. done;
  900. v.v_name <- v.v_name ^ string_of_int !count;
  901. in
  902. let declare v =
  903. (* chop escape char for all local variables generated *)
  904. if String.unsafe_get v.v_name 0 = String.unsafe_get gen_local_prefix 0 then v.v_name <- "_g" ^ String.sub v.v_name 1 (String.length v.v_name - 1);
  905. (try
  906. let v2 = PMap.find v.v_name (!vars) in
  907. (*
  908. block_vars will create some wrapper-functions that are declaring
  909. the same variable twice. In that case do not perform a rename since
  910. we are sure it's actually the same variable
  911. *)
  912. if v == v2 then raise Not_found;
  913. rename v;
  914. with Not_found ->
  915. ());
  916. vars := PMap.add v.v_name v !vars;
  917. if no_scope then all_vars := PMap.add v.v_name v !all_vars;
  918. in
  919. let check t =
  920. match (t_infos t).mt_path with
  921. | [], name | name :: _, _ ->
  922. let vars = if no_scope then all_vars else vars in
  923. (try
  924. let v = PMap.find name !vars in
  925. if v == vtemp then raise Not_found; (* ignore *)
  926. rename v;
  927. rebuild_vars := true;
  928. vars := PMap.add v.v_name v !vars
  929. with Not_found ->
  930. ());
  931. vars := PMap.add name vtemp !vars
  932. in
  933. let check_type t =
  934. match follow t with
  935. | TInst (c,_) -> check (TClassDecl c)
  936. | TEnum (e,_) -> check (TEnumDecl e)
  937. | TType (t,_) -> check (TTypeDecl t)
  938. | TMono _ | TLazy _ | TAnon _ | TDynamic _ | TFun _ -> ()
  939. in
  940. let rec loop e =
  941. match e.eexpr with
  942. | TVars l ->
  943. List.iter (fun (v,e) ->
  944. if no_scope then declare v;
  945. (match e with None -> () | Some e -> loop e);
  946. if not no_scope then declare v;
  947. ) l
  948. | TFunction tf ->
  949. let old = save() in
  950. List.iter (fun (v,_) -> declare v) tf.tf_args;
  951. loop tf.tf_expr;
  952. old()
  953. | TBlock el ->
  954. let old = save() in
  955. List.iter loop el;
  956. old()
  957. | TFor (v,it,e) ->
  958. loop it;
  959. let old = save() in
  960. declare v;
  961. loop e;
  962. old()
  963. | TTry (e,catchs) ->
  964. loop e;
  965. List.iter (fun (v,e) ->
  966. let old = save() in
  967. declare v;
  968. check_type v.v_type;
  969. loop e;
  970. old()
  971. ) catchs;
  972. | TMatch (e,_,cases,def) ->
  973. loop e;
  974. List.iter (fun (_,vars,e) ->
  975. let old = save() in
  976. (match vars with
  977. | None -> ()
  978. | Some l -> List.iter (function None -> () | Some v -> declare v) l);
  979. loop e;
  980. old();
  981. ) cases;
  982. (match def with None -> () | Some e -> loop e);
  983. | TTypeExpr t ->
  984. check t
  985. | TEnumField (e,_) ->
  986. check (TEnumDecl e)
  987. | TNew (c,_,_) ->
  988. Type.iter loop e;
  989. check (TClassDecl c);
  990. | TCast (e,Some t) ->
  991. loop e;
  992. check t;
  993. | _ ->
  994. Type.iter loop e
  995. in
  996. loop e;
  997. e
  998. (* -------------------------------------------------------------------------- *)
  999. (* CHECK LOCAL VARS INIT *)
  1000. let check_local_vars_init e =
  1001. let intersect vl1 vl2 =
  1002. PMap.mapi (fun v t -> t && PMap.find v vl2) vl1
  1003. in
  1004. let join vars cvars =
  1005. List.iter (fun v -> vars := intersect !vars v) cvars
  1006. in
  1007. let restore vars old_vars declared =
  1008. (* restore variables declared in this block to their previous state *)
  1009. vars := List.fold_left (fun acc v ->
  1010. try PMap.add v (PMap.find v old_vars) acc with Not_found -> PMap.remove v acc
  1011. ) !vars declared;
  1012. in
  1013. let declared = ref [] in
  1014. let rec loop vars e =
  1015. match e.eexpr with
  1016. | TLocal v ->
  1017. let init = (try PMap.find v.v_id !vars with Not_found -> true) in
  1018. if not init then error ("Local variable " ^ v.v_name ^ " used without being initialized") e.epos;
  1019. | TVars vl ->
  1020. List.iter (fun (v,eo) ->
  1021. match eo with
  1022. | None ->
  1023. declared := v.v_id :: !declared;
  1024. vars := PMap.add v.v_id false !vars
  1025. | Some e ->
  1026. loop vars e
  1027. ) vl
  1028. | TBlock el ->
  1029. let old = !declared in
  1030. let old_vars = !vars in
  1031. declared := [];
  1032. List.iter (loop vars) el;
  1033. restore vars old_vars (List.rev !declared);
  1034. declared := old;
  1035. | TBinop (OpAssign,{ eexpr = TLocal v },e) when PMap.mem v.v_id !vars ->
  1036. loop vars e;
  1037. vars := PMap.add v.v_id true !vars
  1038. | TIf (e1,e2,eo) ->
  1039. loop vars e1;
  1040. let vbase = !vars in
  1041. loop vars e2;
  1042. (match eo with
  1043. | None -> vars := vbase
  1044. | Some e ->
  1045. let v1 = !vars in
  1046. vars := vbase;
  1047. loop vars e;
  1048. vars := intersect !vars v1)
  1049. | TWhile (cond,e,flag) ->
  1050. (match flag with
  1051. | NormalWhile ->
  1052. loop vars cond;
  1053. let old = !vars in
  1054. loop vars e;
  1055. vars := old;
  1056. | DoWhile ->
  1057. loop vars e;
  1058. loop vars cond)
  1059. | TTry (e,catches) ->
  1060. let cvars = List.map (fun (v,e) ->
  1061. let old = !vars in
  1062. loop vars e;
  1063. let v = !vars in
  1064. vars := old;
  1065. v
  1066. ) catches in
  1067. loop vars e;
  1068. join vars cvars;
  1069. | TSwitch (e,cases,def) ->
  1070. loop vars e;
  1071. let cvars = List.map (fun (ec,e) ->
  1072. let old = !vars in
  1073. List.iter (loop vars) ec;
  1074. vars := old;
  1075. loop vars e;
  1076. let v = !vars in
  1077. vars := old;
  1078. v
  1079. ) cases in
  1080. (match def with
  1081. | None -> ()
  1082. | Some e ->
  1083. loop vars e;
  1084. join vars cvars)
  1085. | TMatch (e,_,cases,def) ->
  1086. loop vars e;
  1087. let old = !vars in
  1088. let cvars = List.map (fun (_,vl,e) ->
  1089. vars := old;
  1090. loop vars e;
  1091. restore vars old [];
  1092. !vars
  1093. ) cases in
  1094. (match def with None -> () | Some e -> vars := old; loop vars e);
  1095. join vars cvars
  1096. (* mark all reachable vars as initialized, since we don't exit the block *)
  1097. | TBreak | TContinue | TReturn None ->
  1098. vars := PMap.map (fun _ -> true) !vars
  1099. | TThrow e | TReturn (Some e) ->
  1100. loop vars e;
  1101. vars := PMap.map (fun _ -> true) !vars
  1102. | _ ->
  1103. Type.iter (loop vars) e
  1104. in
  1105. loop (ref PMap.empty) e;
  1106. e
  1107. (* -------------------------------------------------------------------------- *)
  1108. (* POST PROCESS *)
  1109. let pp_counter = ref 1
  1110. let post_process types filters =
  1111. (* ensure that we don't process twice the same (cached) module *)
  1112. List.iter (fun t ->
  1113. let m = (t_infos t).mt_module.m_extra in
  1114. if m.m_processed = 0 then m.m_processed <- !pp_counter;
  1115. if m.m_processed = !pp_counter then
  1116. match t with
  1117. | TClassDecl c ->
  1118. let process_field f =
  1119. match f.cf_expr with
  1120. | None -> ()
  1121. | Some e ->
  1122. f.cf_expr <- Some (List.fold_left (fun e f -> f e) e filters)
  1123. in
  1124. List.iter process_field c.cl_ordered_fields;
  1125. List.iter process_field c.cl_ordered_statics;
  1126. (match c.cl_constructor with
  1127. | None -> ()
  1128. | Some f -> process_field f);
  1129. (match c.cl_init with
  1130. | None -> ()
  1131. | Some e ->
  1132. c.cl_init <- Some (List.fold_left (fun e f -> f e) e filters));
  1133. | TEnumDecl _ -> ()
  1134. | TTypeDecl _ -> ()
  1135. ) types;
  1136. incr pp_counter
  1137. (* -------------------------------------------------------------------------- *)
  1138. (* STACK MANAGEMENT EMULATION *)
  1139. type stack_context = {
  1140. stack_var : string;
  1141. stack_exc_var : string;
  1142. stack_pos_var : string;
  1143. stack_pos : pos;
  1144. stack_expr : texpr;
  1145. stack_pop : texpr;
  1146. stack_save_pos : texpr;
  1147. stack_restore : texpr list;
  1148. stack_push : tclass -> string -> texpr;
  1149. stack_return : texpr -> texpr;
  1150. }
  1151. let stack_context_init com stack_var exc_var pos_var tmp_var use_add p =
  1152. let t = com.basic in
  1153. let st = t.tarray t.tstring in
  1154. let stack_var = alloc_var stack_var st in
  1155. let exc_var = alloc_var exc_var st in
  1156. let pos_var = alloc_var pos_var t.tint in
  1157. let stack_e = mk (TLocal stack_var) st p in
  1158. let exc_e = mk (TLocal exc_var) st p in
  1159. let stack_pop = fcall stack_e "pop" [] t.tstring p in
  1160. let stack_push c m =
  1161. fcall stack_e "push" [
  1162. if use_add then
  1163. binop OpAdd (string com (s_type_path c.cl_path ^ "::") p) (string com m p) t.tstring p
  1164. else
  1165. string com (s_type_path c.cl_path ^ "::" ^ m) p
  1166. ] t.tvoid p
  1167. in
  1168. let stack_return e =
  1169. let tmp = alloc_var tmp_var e.etype in
  1170. mk (TBlock [
  1171. mk (TVars [tmp, Some e]) t.tvoid e.epos;
  1172. stack_pop;
  1173. mk (TReturn (Some (mk (TLocal tmp) e.etype e.epos))) e.etype e.epos
  1174. ]) e.etype e.epos
  1175. in
  1176. {
  1177. stack_var = stack_var.v_name;
  1178. stack_exc_var = exc_var.v_name;
  1179. stack_pos_var = pos_var.v_name;
  1180. stack_pos = p;
  1181. stack_expr = stack_e;
  1182. stack_pop = stack_pop;
  1183. stack_save_pos = mk (TVars [pos_var, Some (field stack_e "length" t.tint p)]) t.tvoid p;
  1184. stack_push = stack_push;
  1185. stack_return = stack_return;
  1186. stack_restore = [
  1187. binop OpAssign exc_e (mk (TArrayDecl []) st p) st p;
  1188. mk (TWhile (
  1189. mk_parent (binop OpGte (field stack_e "length" t.tint p) (mk (TLocal pos_var) t.tint p) t.tbool p),
  1190. fcall exc_e "unshift" [fcall stack_e "pop" [] t.tstring p] t.tvoid p,
  1191. NormalWhile
  1192. )) t.tvoid p;
  1193. fcall stack_e "push" [index com exc_e 0 t.tstring p] t.tvoid p
  1194. ];
  1195. }
  1196. let stack_init com use_add =
  1197. stack_context_init com "$s" "$e" "$spos" "$tmp" use_add null_pos
  1198. let rec stack_block_loop ctx e =
  1199. match e.eexpr with
  1200. | TFunction _ ->
  1201. e
  1202. | TReturn None | TReturn (Some { eexpr = TConst _ }) | TReturn (Some { eexpr = TLocal _ }) ->
  1203. mk (TBlock [
  1204. ctx.stack_pop;
  1205. e;
  1206. ]) e.etype e.epos
  1207. | TReturn (Some e) ->
  1208. ctx.stack_return (stack_block_loop ctx e)
  1209. | TTry (v,cases) ->
  1210. let v = stack_block_loop ctx v in
  1211. let cases = List.map (fun (v,e) ->
  1212. let e = stack_block_loop ctx e in
  1213. let e = (match (mk_block e).eexpr with
  1214. | TBlock l -> mk (TBlock (ctx.stack_restore @ l)) e.etype e.epos
  1215. | _ -> assert false
  1216. ) in
  1217. v , e
  1218. ) cases in
  1219. mk (TTry (v,cases)) e.etype e.epos
  1220. | _ ->
  1221. map_expr (stack_block_loop ctx) e
  1222. let stack_block ctx c m e =
  1223. match (mk_block e).eexpr with
  1224. | TBlock l ->
  1225. mk (TBlock (
  1226. ctx.stack_push c m ::
  1227. ctx.stack_save_pos ::
  1228. List.map (stack_block_loop ctx) l
  1229. @ [ctx.stack_pop]
  1230. )) e.etype e.epos
  1231. | _ ->
  1232. assert false
  1233. (* -------------------------------------------------------------------------- *)
  1234. (* FIX OVERRIDES *)
  1235. (*
  1236. on some platforms which doesn't support type parameters, we must have the
  1237. exact same type for overriden/implemented function as the original one
  1238. *)
  1239. let rec find_field c f =
  1240. try
  1241. (match c.cl_super with
  1242. | None ->
  1243. raise Not_found
  1244. | Some (c,_) ->
  1245. find_field c f)
  1246. with Not_found -> try
  1247. let rec loop = function
  1248. | [] ->
  1249. raise Not_found
  1250. | (c,_) :: l ->
  1251. try
  1252. find_field c f
  1253. with
  1254. Not_found -> loop l
  1255. in
  1256. loop c.cl_implements
  1257. with Not_found ->
  1258. let f = PMap.find f.cf_name c.cl_fields in
  1259. (match f.cf_kind with Var { v_read = AccRequire _ } -> raise Not_found | _ -> ());
  1260. f
  1261. let fix_override com c f fd =
  1262. c.cl_fields <- PMap.remove f.cf_name c.cl_fields;
  1263. let f2 = (try Some (find_field c f) with Not_found -> None) in
  1264. let f = (match f2,fd with
  1265. | Some (f2), Some(fd) ->
  1266. let targs, tret = (match follow f2.cf_type with TFun (args,ret) -> args, ret | _ -> assert false) in
  1267. let changed_args = ref [] in
  1268. let prefix = "_tmp_" in
  1269. let nargs = List.map2 (fun ((v,c) as cur) (_,_,t2) ->
  1270. try
  1271. type_eq EqStrict v.v_type t2;
  1272. cur
  1273. with Unify_error _ ->
  1274. let v2 = alloc_var (prefix ^ v.v_name) t2 in
  1275. changed_args := (v,v2) :: !changed_args;
  1276. v2,c
  1277. ) fd.tf_args targs in
  1278. let fd2 = {
  1279. tf_args = nargs;
  1280. tf_type = tret;
  1281. tf_expr = (match List.rev !changed_args with
  1282. | [] -> fd.tf_expr
  1283. | args ->
  1284. let e = fd.tf_expr in
  1285. let el = (match e.eexpr with TBlock el -> el | _ -> [e]) in
  1286. let p = (match el with [] -> e.epos | e :: _ -> e.epos) in
  1287. let v = mk (TVars (List.map (fun (v,v2) ->
  1288. (v,Some (mk (TCast (mk (TLocal v2) v2.v_type p,None)) v.v_type p))
  1289. ) args)) com.basic.tvoid p in
  1290. { e with eexpr = TBlock (v :: el) }
  1291. );
  1292. } in
  1293. let targs = List.map (fun(v,c) -> (v.v_name, Option.is_some c, v.v_type)) nargs in
  1294. let fde = (match f.cf_expr with None -> assert false | Some e -> e) in
  1295. { f with cf_expr = Some { fde with eexpr = TFunction fd2 }; cf_type = TFun(targs,tret) }
  1296. | Some(f2), None when c.cl_interface ->
  1297. let targs, tret = (match follow f2.cf_type with TFun (args,ret) -> args, ret | _ -> assert false) in
  1298. { f with cf_type = TFun(targs,tret) }
  1299. | _ ->
  1300. f
  1301. ) in
  1302. c.cl_fields <- PMap.add f.cf_name f c.cl_fields;
  1303. f
  1304. let fix_overrides com t =
  1305. match t with
  1306. | TClassDecl c ->
  1307. c.cl_ordered_fields <- List.map (fun f ->
  1308. match f.cf_expr, f.cf_kind with
  1309. | Some { eexpr = TFunction fd }, Method (MethNormal | MethInline) ->
  1310. fix_override com c f (Some fd)
  1311. | None, Method (MethNormal | MethInline) when c.cl_interface ->
  1312. fix_override com c f None
  1313. | _ ->
  1314. f
  1315. ) c.cl_ordered_fields
  1316. | _ ->
  1317. ()
  1318. (*
  1319. PHP does not allow abstract classes extending other abstract classes to override any fields, so these duplicates
  1320. must be removed from the child interface
  1321. *)
  1322. let fix_abstract_inheritance com t =
  1323. match t with
  1324. | TClassDecl c when c.cl_interface ->
  1325. c.cl_ordered_fields <- List.filter (fun f ->
  1326. let b = try (find_field c f) == f
  1327. with Not_found -> false in
  1328. if not b then c.cl_fields <- PMap.remove f.cf_name c.cl_fields;
  1329. b;
  1330. ) c.cl_ordered_fields
  1331. | _ -> ()
  1332. (* -------------------------------------------------------------------------- *)
  1333. (* MISC FEATURES *)
  1334. let rec is_volatile t =
  1335. match t with
  1336. | TMono r ->
  1337. (match !r with
  1338. | Some t -> is_volatile t
  1339. | _ -> false)
  1340. | TLazy f ->
  1341. is_volatile (!f())
  1342. | TType (t,tl) ->
  1343. (match t.t_path with
  1344. | ["mt";"flash"],"Volatile" -> true
  1345. | _ -> is_volatile (apply_params t.t_types tl t.t_type))
  1346. | _ ->
  1347. false
  1348. let set_default ctx a c p =
  1349. let t = a.v_type in
  1350. let ve = mk (TLocal a) t p in
  1351. let cond = TBinop (OpEq,ve,mk (TConst TNull) t p) in
  1352. mk (TIf (mk_parent (mk cond ctx.basic.tbool p), mk (TBinop (OpAssign,ve,mk (TConst c) t p)) t p,None)) ctx.basic.tvoid p
  1353. let bytes_serialize data =
  1354. let b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789%:" in
  1355. let tbl = Array.init (String.length b64) (fun i -> String.get b64 i) in
  1356. let str = Base64.str_encode ~tbl data in
  1357. "s" ^ string_of_int (String.length str) ^ ":" ^ str
  1358. (*
  1359. Tells if the constructor might be called without any issue whatever its parameters
  1360. *)
  1361. let rec constructor_side_effects e =
  1362. match e.eexpr with
  1363. | TBinop (op,_,_) when op <> OpAssign ->
  1364. true
  1365. | TUnop _ | TArray _ | TField _ | TCall _ | TNew _ | TFor _ | TWhile _ | TSwitch _ | TMatch _ | TReturn _ | TThrow _ | TClosure _ ->
  1366. true
  1367. | TBinop _ | TTry _ | TIf _ | TBlock _ | TVars _
  1368. | TFunction _ | TArrayDecl _ | TObjectDecl _
  1369. | TParenthesis _ | TTypeExpr _ | TEnumField _ | TLocal _
  1370. | TConst _ | TContinue | TBreak | TCast _ ->
  1371. try
  1372. Type.iter (fun e -> if constructor_side_effects e then raise Exit) e;
  1373. false;
  1374. with Exit ->
  1375. true
  1376. (*
  1377. Make a dump of the full typed AST of all types
  1378. *)
  1379. let dump_types com =
  1380. let s_type = s_type (Type.print_context()) in
  1381. let params = function [] -> "" | l -> Printf.sprintf "<%s>" (String.concat "," (List.map (fun (n,t) -> n ^ " : " ^ s_type t) l)) in
  1382. let rec create acc = function
  1383. | [] -> ()
  1384. | d :: l ->
  1385. let dir = String.concat "/" (List.rev (d :: acc)) in
  1386. if not (Sys.file_exists dir) then Unix.mkdir dir 0o755;
  1387. create (d :: acc) l
  1388. in
  1389. List.iter (fun mt ->
  1390. let path = Type.t_path mt in
  1391. let dir = "dump" :: fst path in
  1392. create [] dir;
  1393. let ch = open_out (String.concat "/" dir ^ "/" ^ snd path ^ ".dump") in
  1394. let buf = Buffer.create 0 in
  1395. let print fmt = Printf.kprintf (fun s -> Buffer.add_string buf s) fmt in
  1396. (match mt with
  1397. | Type.TClassDecl c ->
  1398. let print_field stat f =
  1399. print "\t%s%s%s%s" (if stat then "static " else "") (if f.cf_public then "public " else "") f.cf_name (params f.cf_params);
  1400. print "(%s) : %s" (s_kind f.cf_kind) (s_type f.cf_type);
  1401. (match f.cf_expr with
  1402. | None -> ()
  1403. | Some e -> print "\n\n\t = %s" (Type.s_expr s_type e));
  1404. print ";\n\n";
  1405. in
  1406. print "%s%s%s %s%s" (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_types);
  1407. (match c.cl_super with None -> () | Some (c,pl) -> print " extends %s" (s_type (TInst (c,pl))));
  1408. List.iter (fun (c,pl) -> print " implements %s" (s_type (TInst (c,pl)))) c.cl_implements;
  1409. (match c.cl_dynamic with None -> () | Some t -> print " implements Dynamic<%s>" (s_type t));
  1410. (match c.cl_array_access with None -> () | Some t -> print " implements ArrayAccess<%s>" (s_type t));
  1411. print "{\n";
  1412. (match c.cl_constructor with
  1413. | None -> ()
  1414. | Some f -> print_field false f);
  1415. List.iter (print_field false) c.cl_ordered_fields;
  1416. List.iter (print_field true) c.cl_ordered_statics;
  1417. print "}";
  1418. | Type.TEnumDecl e ->
  1419. print "%s%senum %s%s {\n" (if e.e_private then "private " else "") (if e.e_extern then "extern " else "") (s_type_path path) (params e.e_types);
  1420. List.iter (fun n ->
  1421. let f = PMap.find n e.e_constrs in
  1422. print "\t%s : %s;\n" f.ef_name (s_type f.ef_type);
  1423. ) e.e_names;
  1424. print "}"
  1425. | Type.TTypeDecl t ->
  1426. print "%stype %s%s = %s" (if t.t_private then "private " else "") (s_type_path path) (params t.t_types) (s_type t.t_type);
  1427. );
  1428. output_string ch (Buffer.contents buf);
  1429. close_out ch
  1430. ) com.types
  1431. (*
  1432. Build a default safe-cast expression :
  1433. { var $t = <e>; if( Std.is($t,<t>) ) $t else throw "Class cast error"; }
  1434. *)
  1435. let default_cast ?(vtmp="$t") com e texpr t p =
  1436. let api = com.basic in
  1437. let mk_texpr = function
  1438. | TClassDecl c -> TAnon { a_fields = PMap.empty; a_status = ref (Statics c) }
  1439. | TEnumDecl e -> TAnon { a_fields = PMap.empty; a_status = ref (EnumStatics e) }
  1440. | TTypeDecl _ -> assert false
  1441. in
  1442. let vtmp = alloc_var vtmp e.etype in
  1443. let var = mk (TVars [vtmp,Some e]) api.tvoid p in
  1444. let vexpr = mk (TLocal vtmp) e.etype p in
  1445. let texpr = mk (TTypeExpr texpr) (mk_texpr texpr) p in
  1446. let std = (try List.find (fun t -> t_path t = ([],"Std")) com.types with Not_found -> assert false) in
  1447. let std = mk (TTypeExpr std) (mk_texpr std) p in
  1448. let is = mk (TField (std,"is")) (tfun [t_dynamic;t_dynamic] api.tbool) p in
  1449. let is = mk (TCall (is,[vexpr;texpr])) api.tbool p in
  1450. let exc = mk (TThrow (mk (TConst (TString "Class cast error")) api.tstring p)) t p in
  1451. let check = mk (TIf (mk_parent is,mk (TCast (vexpr,None)) t p,Some exc)) t p in
  1452. mk (TBlock [var;check;vexpr]) t p