codegen.ml 46 KB

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