1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296 |
- (*
- * Copyright (C)2005-2013 Haxe Foundation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *)
- open Ast
- open Type
- open Common
- open Typecore
- (* -------------------------------------------------------------------------- *)
- (* TOOLS *)
- let field e name t p =
- mk (TField (e,try quick_field e.etype name with Not_found -> assert false)) t p
- let fcall e name el ret p =
- let ft = tfun (List.map (fun e -> e.etype) el) ret in
- mk (TCall (field e name ft p,el)) ret p
- let mk_parent e =
- mk (TParenthesis e) e.etype e.epos
- let string com str p =
- mk (TConst (TString str)) com.basic.tstring p
- let binop op a b t p =
- mk (TBinop (op,a,b)) t p
- let index com e index t p =
- mk (TArray (e,mk (TConst (TInt (Int32.of_int index))) com.basic.tint p)) t p
- let concat e1 e2 =
- let e = (match e1.eexpr, e2.eexpr with
- | TBlock el1, TBlock el2 -> TBlock (el1@el2)
- | TBlock el, _ -> TBlock (el @ [e2])
- | _, TBlock el -> TBlock (e1 :: el)
- | _ , _ -> TBlock [e1;e2]
- ) in
- mk e e2.etype (punion e1.epos e2.epos)
- let type_constant com c p =
- let t = com.basic in
- match c with
- | Int s ->
- if String.length s > 10 && String.sub s 0 2 = "0x" then error "Invalid hexadecimal integer" p;
- (try mk (TConst (TInt (Int32.of_string s))) t.tint p
- with _ -> mk (TConst (TFloat s)) t.tfloat p)
- | Float f -> mk (TConst (TFloat f)) t.tfloat p
- | String s -> mk (TConst (TString s)) t.tstring p
- | Ident "true" -> mk (TConst (TBool true)) t.tbool p
- | Ident "false" -> mk (TConst (TBool false)) t.tbool p
- | Ident "null" -> mk (TConst TNull) (t.tnull (mk_mono())) p
- | Ident t -> error ("Invalid constant : " ^ t) p
- | Regexp _ -> error "Invalid constant" p
- let rec type_constant_value com (e,p) =
- match e with
- | EConst c ->
- type_constant com c p
- | EParenthesis e ->
- type_constant_value com e
- | EObjectDecl el ->
- mk (TObjectDecl (List.map (fun (n,e) -> n, type_constant_value com e) el)) (TAnon { a_fields = PMap.empty; a_status = ref Closed }) p
- | EArrayDecl el ->
- mk (TArrayDecl (List.map (type_constant_value com) el)) (com.basic.tarray t_dynamic) p
- | _ ->
- error "Constant value expected" p
- let rec has_properties c =
- List.exists (fun f ->
- match f.cf_kind with
- | Var { v_read = AccCall } -> true
- | Var { v_write = AccCall } -> true
- | _ -> false
- ) c.cl_ordered_fields || (match c.cl_super with Some (c,_) -> has_properties c | _ -> false)
- let get_properties fields =
- List.fold_left (fun acc f ->
- let acc = (match f.cf_kind with
- | Var { v_read = AccCall } -> ("get_" ^ f.cf_name , "get_" ^ f.cf_name) :: acc
- | _ -> acc) in
- match f.cf_kind with
- | Var { v_write = AccCall } -> ("set_" ^ f.cf_name , "set_" ^ f.cf_name) :: acc
- | _ -> acc
- ) [] fields
- let add_property_field com c =
- let p = c.cl_pos in
- let props = get_properties (c.cl_ordered_statics @ c.cl_ordered_fields) in
- match props with
- | [] -> ()
- | _ ->
- let fields,values = List.fold_left (fun (fields,values) (n,v) ->
- let cf = mk_field n com.basic.tstring p in
- PMap.add n cf fields,(n, string com v p) :: values
- ) (PMap.empty,[]) props in
- let t = mk_anon fields in
- let e = mk (TObjectDecl values) t p in
- let cf = mk_field "__properties__" t p in
- cf.cf_expr <- Some e;
- c.cl_statics <- PMap.add cf.cf_name cf c.cl_statics;
- c.cl_ordered_statics <- cf :: c.cl_ordered_statics
- (* -------------------------------------------------------------------------- *)
- (* REMOTING PROXYS *)
- let extend_remoting ctx c t p async prot =
- if c.cl_super <> None then error "Cannot extend several classes" p;
- (* remove forbidden packages *)
- let rules = ctx.com.package_rules in
- ctx.com.package_rules <- PMap.foldi (fun key r acc -> match r with Forbidden -> acc | _ -> PMap.add key r acc) rules PMap.empty;
- (* parse module *)
- let path = (t.tpackage,t.tname) in
- let new_name = (if async then "Async_" else "Remoting_") ^ t.tname in
- (* check if the proxy already exists *)
- let t = (try
- Typeload.load_type_def ctx p { tpackage = fst path; tname = new_name; tparams = []; tsub = None }
- with
- Error (Module_not_found _,p2) when p == p2 ->
- (* build it *)
- Common.log ctx.com ("Building proxy for " ^ s_type_path path);
- let file, decls = (try
- Typeload.parse_module ctx path p
- with
- | 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
- | e -> ctx.com.package_rules <- rules; raise e) in
- ctx.com.package_rules <- rules;
- let base_fields = [
- { 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) };
- { 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 = [] } };
- ] in
- let tvoid = CTPath { tpackage = []; tname = "Void"; tparams = []; tsub = None } in
- let build_field is_public acc f =
- if f.cff_name = "new" then
- acc
- else match f.cff_kind with
- | FFun fd when (is_public || List.mem APublic f.cff_access) && not (List.mem AStatic f.cff_access) ->
- 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;
- let eargs = [EArrayDecl (List.map (fun (a,_,_,_) -> (EConst (Ident a),p)) fd.f_args),p] in
- let ftype = (match fd.f_type with Some (CTPath { tpackage = []; tname = "Void" }) -> None | _ -> fd.f_type) in
- let fargs, eargs = if async then match ftype with
- | Some tret -> fd.f_args @ ["__callb",true,Some (CTFunction ([tret],tvoid)),None], eargs @ [EConst (Ident "__callb"),p]
- | _ -> fd.f_args, eargs @ [EConst (Ident "null"),p]
- else
- fd.f_args, eargs
- in
- let id = (EConst (String f.cff_name), p) in
- let id = if prot then id else ECall ((EConst (Ident "__unprotect__"),p),[id]),p in
- let expr = ECall (
- (EField (
- (ECall ((EField ((EConst (Ident "__cnx"),p),"resolve"),p),[id]),p),
- "call")
- ,p),eargs),p
- in
- let expr = if async || ftype = None then expr else (EReturn (Some expr),p) in
- let fd = {
- f_params = fd.f_params;
- f_args = fargs;
- f_type = if async then None else ftype;
- f_expr = Some (EBlock [expr],p);
- } in
- { cff_name = f.cff_name; cff_pos = p; cff_doc = None; cff_meta = []; cff_access = [APublic]; cff_kind = FFun fd } :: acc
- | _ -> acc
- in
- let decls = List.map (fun d ->
- match d with
- | EClass c, p when c.d_name = t.tname ->
- let is_public = List.mem HExtern c.d_flags || List.mem HInterface c.d_flags in
- let fields = List.rev (List.fold_left (build_field is_public) base_fields c.d_data) in
- (EClass { c with d_flags = []; d_name = new_name; d_data = fields },p)
- | _ -> d
- ) decls in
- let m = Typeload.type_module ctx (t.tpackage,new_name) file decls p in
- add_dependency ctx.m.curmod m;
- try
- List.find (fun tdecl -> snd (t_path tdecl) = new_name) m.m_types
- with Not_found ->
- error ("Module " ^ s_type_path path ^ " does not define type " ^ t.tname) p
- ) in
- match t with
- | TClassDecl c2 when c2.cl_types = [] -> c2.cl_build(); c.cl_super <- Some (c2,[]);
- | _ -> error "Remoting proxy must be a class without parameters" p
- (* -------------------------------------------------------------------------- *)
- (* HAXE.RTTI.GENERIC *)
- exception Generic_Exception of string * Ast.pos
- type generic_context = {
- ctx : typer;
- subst : (t * t) list;
- name : string;
- p : pos;
- mutable mg : module_def option;
- }
- let make_generic ctx ps pt p =
- let rec loop l1 l2 =
- match l1, l2 with
- | [] , [] -> []
- | (x,TLazy f) :: l1, _ -> loop ((x,(!f)()) :: l1) l2
- | (_,t1) :: l1 , t2 :: l2 -> (t1,t2) :: loop l1 l2
- | _ -> assert false
- in
- let name =
- String.concat "_" (List.map2 (fun (s,_) t ->
- let path = (match follow t with
- | TInst (ct,_) -> ct.cl_path
- | TEnum (e,_) -> e.e_path
- | TAbstract (a,_) when Meta.has Meta.RuntimeValue a.a_meta -> a.a_path
- | TMono _ -> raise (Generic_Exception (("Could not determine type for parameter " ^ s), p))
- | t -> raise (Generic_Exception (("Type parameter must be a class or enum instance (found " ^ (s_type (print_context()) t) ^ ")"), p))
- ) in
- match path with
- | [] , name -> name
- | l , name -> String.concat "_" l ^ "_" ^ name
- ) ps pt)
- in
- {
- ctx = ctx;
- subst = loop ps pt;
- name = name;
- p = p;
- mg = None;
- }
- let rec generic_substitute_type gctx t =
- match t with
- | TInst ({ cl_kind = KGeneric } as c2,tl2) ->
- (* maybe loop, or generate cascading generics *)
- let _, _, f = gctx.ctx.g.do_build_instance gctx.ctx (TClassDecl c2) gctx.p in
- let t = f (List.map (generic_substitute_type gctx) tl2) in
- (match follow t,gctx.mg with TInst(c,_), Some m -> add_dependency m c.cl_module | _ -> ());
- t
- | _ ->
- try List.assq t gctx.subst with Not_found -> Type.map (generic_substitute_type gctx) t
- let generic_substitute_expr gctx e =
- let vars = Hashtbl.create 0 in
- let build_var v =
- try
- Hashtbl.find vars v.v_id
- with Not_found ->
- let v2 = alloc_var v.v_name (generic_substitute_type gctx v.v_type) in
- Hashtbl.add vars v.v_id v2;
- v2
- in
- let rec build_expr e =
- match e.eexpr with
- | TField(e1, FInstance({cl_kind = KGeneric},cf)) ->
- build_expr {e with eexpr = TField(e1,quick_field_dynamic (generic_substitute_type gctx (e1.etype)) cf.cf_name)}
- | _ -> map_expr_type build_expr (generic_substitute_type gctx) build_var e
- in
- build_expr e
- let has_ctor_constraint c = match c.cl_kind with
- | KTypeParameter tl ->
- List.exists (fun t -> match follow t with
- | TAnon a when PMap.mem "new" a.a_fields -> true
- | _ -> false
- ) tl;
- | _ -> false
- let rec build_generic ctx c p tl =
- let pack = fst c.cl_path in
- let recurse = ref false in
- let rec check_recursive t =
- match follow t with
- | TInst (c2,tl) ->
- (match c2.cl_kind with
- | KTypeParameter tl ->
- if not (Typeload.is_generic_parameter ctx c2) && has_ctor_constraint c2 then
- error "Type parameters with a constructor cannot be used non-generically" p;
- recurse := true
- | _ -> ());
- List.iter check_recursive tl;
- | _ ->
- ()
- in
- List.iter check_recursive tl;
- let gctx = try make_generic ctx c.cl_types tl p with Generic_Exception (msg,p) -> error msg p in
- let name = (snd c.cl_path) ^ "_" ^ gctx.name in
- if !recurse then begin
- TInst (c,tl) (* build a normal instance *)
- end else try
- Typeload.load_instance ctx { tpackage = pack; tname = name; tparams = []; tsub = None } p false
- with Error(Module_not_found path,_) when path = (pack,name) ->
- let m = (try Hashtbl.find ctx.g.modules (Hashtbl.find ctx.g.types_module c.cl_path) with Not_found -> assert false) in
- let ctx = { ctx with m = { ctx.m with module_types = m.m_types @ ctx.m.module_types } } in
- c.cl_build(); (* make sure the super class is already setup *)
- let mg = {
- m_id = alloc_mid();
- m_path = (pack,name);
- m_types = [];
- m_extra = module_extra (s_type_path (pack,name)) m.m_extra.m_sign 0. MFake;
- } in
- gctx.mg <- Some mg;
- let cg = mk_class mg (pack,name) c.cl_pos in
- mg.m_types <- [TClassDecl cg];
- Hashtbl.add ctx.g.modules mg.m_path mg;
- add_dependency mg m;
- add_dependency ctx.m.curmod mg;
- (* ensure that type parameters are set in dependencies *)
- let dep_stack = ref [] in
- let rec loop t =
- if not (List.memq t !dep_stack) then begin
- dep_stack := t :: !dep_stack;
- match t with
- | TInst (c,tl) -> add_dep c.cl_module tl
- | TEnum (e,tl) -> add_dep e.e_module tl
- | TType (t,tl) -> add_dep t.t_module tl
- | TAbstract (a,tl) -> add_dep a.a_module tl
- | TMono r ->
- (match !r with
- | None -> ()
- | Some t -> loop t)
- | TLazy f ->
- loop ((!f)());
- | TDynamic t2 ->
- if t == t2 then () else loop t2
- | TAnon a ->
- PMap.iter (fun _ f -> loop f.cf_type) a.a_fields
- | TFun (args,ret) ->
- List.iter (fun (_,_,t) -> loop t) args;
- loop ret
- end
- and add_dep m tl =
- add_dependency mg m;
- List.iter loop tl
- in
- List.iter loop tl;
- let delays = ref [] in
- let build_field f =
- let t = generic_substitute_type gctx f.cf_type in
- let f = { f with cf_type = t} in
- (* delay the expression mapping to make sure all cf_type fields are set correctly first *)
- (delays := (fun () ->
- try (match f.cf_expr with None -> () | Some e -> f.cf_expr <- Some (generic_substitute_expr gctx e))
- with Unify_error l -> error (error_msg (Unify l)) f.cf_pos) :: !delays);
- f
- in
- if c.cl_init <> None || c.cl_dynamic <> None then error "This class can't be generic" p;
- if c.cl_ordered_statics <> [] then error "A generic class can't have static fields" p;
- cg.cl_super <- (match c.cl_super with
- | None -> None
- | Some (cs,pl) ->
- let find_class subst =
- let rec loop subst = match subst with
- | (TInst(c,[]),t) :: subst when c == cs -> t
- | _ :: subst -> loop subst
- | [] -> raise Not_found
- in
- try
- if pl <> [] then raise Not_found;
- let t = loop subst in
- (* extended type parameter: concrete type must have a constructor, but generic base class must not have one *)
- begin match follow t,c.cl_constructor with
- | TInst({cl_constructor = None} as cs,_),None -> error ("Cannot use " ^ (s_type_path cs.cl_path) ^ " as type parameter because it is extended and has no constructor") p
- | _,Some cf -> error "Generics extending type parameters cannot have constructors" cf.cf_pos
- | _ -> ()
- end;
- t
- with Not_found ->
- apply_params c.cl_types tl (TInst(cs,pl))
- in
- let ts = follow (find_class gctx.subst) in
- let cs,pl = Typeload.check_extends ctx c ts p in
- match cs.cl_kind with
- | KGeneric ->
- (match build_generic ctx cs p pl with
- | TInst (cs,pl) -> Some (cs,pl)
- | _ -> assert false)
- | _ -> Some(cs,pl)
- );
- Typeload.add_constructor ctx cg p;
- cg.cl_kind <- KGenericInstance (c,tl);
- cg.cl_interface <- c.cl_interface;
- cg.cl_constructor <- (match cg.cl_constructor, c.cl_constructor, c.cl_super with
- | Some ctor, _, _ -> Some ctor
- | None, None, None -> None
- | None, Some c, _ -> Some (build_field c)
- | _ -> error "Please define a constructor for this class in order to use it as generic" c.cl_pos
- );
- cg.cl_implements <- List.map (fun (i,tl) ->
- (match follow (generic_substitute_type gctx (TInst (i, List.map (generic_substitute_type gctx) tl))) with
- | TInst (i,tl) -> i, tl
- | _ -> assert false)
- ) c.cl_implements;
- cg.cl_ordered_fields <- List.map (fun f ->
- let f = build_field f in
- cg.cl_fields <- PMap.add f.cf_name f cg.cl_fields;
- f
- ) c.cl_ordered_fields;
- List.iter (fun f -> f()) !delays;
- TInst (cg,[])
- (* -------------------------------------------------------------------------- *)
- (* HAXE.XML.PROXY *)
- let extend_xml_proxy ctx c t file p =
- let t = Typeload.load_complex_type ctx p t in
- let file = (try Common.find_file ctx.com file with Not_found -> file) in
- add_dependency c.cl_module (create_fake_module ctx file);
- let used = ref PMap.empty in
- let print_results() =
- PMap.iter (fun id used ->
- if not used then ctx.com.warning (id ^ " is not used") p;
- ) (!used)
- in
- let check_used = Common.defined ctx.com Define.CheckXmlProxy in
- if check_used then ctx.g.hook_generate <- print_results :: ctx.g.hook_generate;
- try
- let rec loop = function
- | Xml.Element (_,attrs,childs) ->
- (try
- let id = List.assoc "id" attrs in
- if PMap.mem id c.cl_fields then error ("Duplicate id " ^ id) p;
- let t = if not check_used then t else begin
- used := PMap.add id false (!used);
- let ft() = used := PMap.add id true (!used); t in
- TLazy (ref ft)
- end in
- let f = {
- cf_name = id;
- cf_type = t;
- cf_public = true;
- cf_pos = p;
- cf_doc = None;
- cf_meta = no_meta;
- cf_kind = Var { v_read = AccResolve; v_write = AccNo };
- cf_params = [];
- cf_expr = None;
- cf_overloads = [];
- } in
- c.cl_fields <- PMap.add id f c.cl_fields;
- with
- Not_found -> ());
- List.iter loop childs;
- | Xml.PCData _ -> ()
- in
- loop (Xml.parse_file file)
- with
- | Xml.Error e -> error ("XML error " ^ Xml.error e) p
- | Xml.File_not_found f -> error ("XML File not found : " ^ f) p
- (* -------------------------------------------------------------------------- *)
- (* BUILD META DATA OBJECT *)
- let build_metadata com t =
- let api = com.basic in
- let p, meta, fields, statics = (match t with
- | TClassDecl c ->
- 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
- let statics = List.map (fun f -> f.cf_name,f.cf_meta) c.cl_ordered_statics in
- (c.cl_pos, ["",c.cl_meta],fields,statics)
- | TEnumDecl e ->
- (e.e_pos, ["",e.e_meta],List.map (fun n -> n, (PMap.find n e.e_constrs).ef_meta) e.e_names, [])
- | TTypeDecl t ->
- (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 [] | _ -> []),[])
- | TAbstractDecl a ->
- (a.a_pos, ["",a.a_meta],[],[])
- ) in
- let filter l =
- let l = List.map (fun (n,ml) -> n, ExtList.List.filter_map (fun (m,el,p) -> match m with Meta.Custom s when String.length s > 0 && s.[0] <> ':' -> Some (s,el,p) | _ -> None) ml) l in
- List.filter (fun (_,ml) -> ml <> []) l
- in
- let meta, fields, statics = filter meta, filter fields, filter statics in
- let make_meta_field ml =
- let h = Hashtbl.create 0 in
- mk (TObjectDecl (List.map (fun (f,el,p) ->
- if Hashtbl.mem h f then error ("Duplicate metadata '" ^ f ^ "'") p;
- Hashtbl.add h f ();
- f, mk (match el with [] -> TConst TNull | _ -> TArrayDecl (List.map (type_constant_value com) el)) (api.tarray t_dynamic) p
- ) ml)) (api.tarray t_dynamic) p
- in
- let make_meta l =
- mk (TObjectDecl (List.map (fun (f,ml) -> f,make_meta_field ml) l)) t_dynamic p
- in
- if meta = [] && fields = [] && statics = [] then
- None
- else
- let meta_obj = [] in
- let meta_obj = (if fields = [] then meta_obj else ("fields",make_meta fields) :: meta_obj) in
- let meta_obj = (if statics = [] then meta_obj else ("statics",make_meta statics) :: meta_obj) in
- let meta_obj = (try ("obj", make_meta_field (List.assoc "" meta)) :: meta_obj with Not_found -> meta_obj) in
- Some (mk (TObjectDecl meta_obj) t_dynamic p)
- (* -------------------------------------------------------------------------- *)
- (* MACRO TYPE *)
- let build_macro_type ctx pl p =
- let path, field, args = (match pl with
- | [TInst ({ cl_kind = KExpr (ECall (e,args),_) },_)]
- | [TInst ({ cl_kind = KExpr (EArrayDecl [ECall (e,args),_],_) },_)] ->
- let rec loop e =
- match fst e with
- | EField (e,f) -> f :: loop e
- | EConst (Ident i) -> [i]
- | _ -> error "Invalid macro call" p
- in
- (match loop e with
- | meth :: cl :: path -> (List.rev path,cl), meth, args
- | _ -> error "Invalid macro call" p)
- | _ ->
- error "MacroType require a single expression call parameter" p
- ) in
- let old = ctx.ret in
- let t = (match ctx.g.do_macro ctx MMacroType path field args p with
- | None -> mk_mono()
- | Some _ -> ctx.ret
- ) in
- ctx.ret <- old;
- t
- (* -------------------------------------------------------------------------- *)
- (* API EVENTS *)
- let build_instance ctx mtype p =
- match mtype with
- | TClassDecl c ->
- if ctx.pass > PBuildClass then c.cl_build();
- let ft = (fun pl ->
- match c.cl_kind with
- | KGeneric ->
- let r = exc_protect ctx (fun r ->
- let t = mk_mono() in
- r := (fun() -> t);
- unify_raise ctx (build_generic ctx c p pl) t p;
- t
- ) "build_generic" in
- delay ctx PForce (fun() -> ignore ((!r)()));
- TLazy r
- | KMacroType ->
- let r = exc_protect ctx (fun r ->
- let t = mk_mono() in
- r := (fun() -> t);
- unify_raise ctx (build_macro_type ctx pl p) t p;
- t
- ) "macro_type" in
- delay ctx PForce (fun() -> ignore ((!r)()));
- TLazy r
- | _ ->
- TInst (c,pl)
- ) in
- c.cl_types , c.cl_path , ft
- | TEnumDecl e ->
- e.e_types , e.e_path , (fun t -> TEnum (e,t))
- | TTypeDecl t ->
- t.t_types , t.t_path , (fun tl -> TType(t,tl))
- | TAbstractDecl a ->
- a.a_types, a.a_path, (fun tl -> TAbstract(a,tl))
- let on_inherit ctx c p h =
- match h with
- | HExtends { tpackage = ["haxe";"remoting"]; tname = "Proxy"; tparams = [TPType(CTPath t)] } ->
- extend_remoting ctx c t p false true;
- false
- | HExtends { tpackage = ["haxe";"remoting"]; tname = "AsyncProxy"; tparams = [TPType(CTPath t)] } ->
- extend_remoting ctx c t p true true;
- false
- | HExtends { tpackage = ["mt"]; tname = "AsyncProxy"; tparams = [TPType(CTPath t)] } ->
- extend_remoting ctx c t p true false;
- false
- | HExtends { tpackage = ["haxe";"xml"]; tname = "Proxy"; tparams = [TPExpr(EConst (String file),p);TPType t] } ->
- extend_xml_proxy ctx c t file p;
- true
- | _ ->
- true
- (* -------------------------------------------------------------------------- *)
- (* FINAL GENERATION *)
- (* Saves a class state so it can be restored later, e.g. after DCE or native path rewrite *)
- let save_class_state ctx t = match t with
- | TClassDecl c ->
- let meta = c.cl_meta and path = c.cl_path and ext = c.cl_extern in
- let fl = c.cl_fields and ofl = c.cl_ordered_fields and st = c.cl_statics and ost = c.cl_ordered_statics in
- let cst = c.cl_constructor and over = c.cl_overrides in
- let oflk = List.map (fun f -> f.cf_kind,f.cf_expr,f.cf_type) ofl in
- let ostk = List.map (fun f -> f.cf_kind,f.cf_expr,f.cf_type) ost in
- c.cl_restore <- (fun() ->
- c.cl_meta <- meta;
- c.cl_extern <- ext;
- c.cl_path <- path;
- c.cl_fields <- fl;
- c.cl_ordered_fields <- ofl;
- c.cl_statics <- st;
- c.cl_ordered_statics <- ost;
- c.cl_constructor <- cst;
- c.cl_overrides <- over;
- (* DCE might modify the cf_kind, so let's restore it as well *)
- List.iter2 (fun f (k,e,t) -> f.cf_kind <- k; f.cf_expr <- e; f.cf_type <- t;) ofl oflk;
- List.iter2 (fun f (k,e,t) -> f.cf_kind <- k; f.cf_expr <- e; f.cf_type <- t;) ost ostk;
- )
- | _ ->
- ()
- (* Checks if a private class' path clashes with another path *)
- let check_private_path ctx t = match t with
- | TClassDecl c when c.cl_private ->
- let rpath = (fst c.cl_module.m_path,"_" ^ snd c.cl_module.m_path) in
- if Hashtbl.mem ctx.g.types_module rpath then error ("This private class name will clash with " ^ s_type_path rpath) c.cl_pos;
- | _ ->
- ()
- (* Removes generic base classes *)
- let is_removable_class c = c.cl_kind = KGeneric && (has_ctor_constraint c || Meta.has Meta.Remove c.cl_meta)
- let remove_generic_base ctx t = match t with
- | TClassDecl c when is_removable_class c ->
- c.cl_extern <- true
- | _ ->
- ()
- (* Rewrites class or enum paths if @:native metadata is set *)
- let apply_native_paths ctx t =
- let get_real_path meta path =
- let (_,e,mp) = Meta.get Meta.Native meta in
- match e with
- | [Ast.EConst (Ast.String name),p] ->
- (Meta.RealPath,[Ast.EConst (Ast.String (s_type_path path)),p],mp),parse_path name
- | _ ->
- error "String expected" mp
- in
- try
- (match t with
- | TClassDecl c ->
- let meta,path = get_real_path c.cl_meta c.cl_path in
- c.cl_meta <- meta :: c.cl_meta;
- c.cl_path <- path;
- | TEnumDecl e ->
- let meta,path = get_real_path e.e_meta e.e_path in
- e.e_meta <- meta :: e.e_meta;
- e.e_path <- path;
- | TAbstractDecl a ->
- let meta,path = get_real_path a.a_meta a.a_path in
- a.a_meta <- meta :: a.a_meta;
- a.a_path <- path;
- | _ ->
- ())
- with Not_found ->
- ()
- (* Adds the __rtti field if required *)
- let add_rtti ctx t =
- let rec has_rtti c =
- Meta.has Meta.Rtti c.cl_meta || match c.cl_super with None -> false | Some (csup,_) -> has_rtti csup
- in
- match t with
- | TClassDecl c when has_rtti c && not (PMap.mem "__rtti" c.cl_statics) ->
- let f = mk_field "__rtti" ctx.t.tstring c.cl_pos in
- let str = Genxml.gen_type_string ctx.com t in
- f.cf_expr <- Some (mk (TConst (TString str)) f.cf_type c.cl_pos);
- c.cl_ordered_statics <- f :: c.cl_ordered_statics;
- c.cl_statics <- PMap.add f.cf_name f c.cl_statics;
- | _ ->
- ()
- (* Removes extern and macro fields, also checks for Void fields *)
- let is_removable_field ctx f =
- Meta.has Meta.Extern f.cf_meta || Meta.has Meta.Generic f.cf_meta
- || (match f.cf_kind with
- | Var {v_read = AccRequire (s,_)} -> true
- | Method MethMacro -> not ctx.in_macro
- | _ -> false)
- let remove_extern_fields ctx t = match t with
- | TClassDecl c ->
- if not (Common.defined ctx.com Define.DocGen) then begin
- c.cl_ordered_fields <- List.filter (fun f ->
- let b = is_removable_field ctx f in
- if b then c.cl_fields <- PMap.remove f.cf_name c.cl_fields;
- not b
- ) c.cl_ordered_fields;
- c.cl_ordered_statics <- List.filter (fun f ->
- let b = is_removable_field ctx f in
- if b then c.cl_statics <- PMap.remove f.cf_name c.cl_statics;
- not b
- ) c.cl_ordered_statics;
- end
- | _ ->
- ()
- (* Adds member field initializations as assignments to the constructor *)
- let add_field_inits ctx t =
- let apply c =
- let ethis = mk (TConst TThis) (TInst (c,List.map snd c.cl_types)) c.cl_pos in
- (* TODO: we have to find a variable name which is not used in any of the functions *)
- let v = alloc_var "_g" ethis.etype in
- let need_this = ref false in
- let inits,fields = List.fold_left (fun (inits,fields) cf ->
- match cf.cf_kind,cf.cf_expr with
- | Var _, Some _ ->
- if ctx.com.config.pf_can_init_member cf then (inits, cf :: fields) else (cf :: inits, cf :: fields)
- | Method MethDynamic, Some e when Common.defined ctx.com Define.As3 ->
- (* TODO : this would have a better place in genSWF9 I think - NC *)
- (* we move the initialization of dynamic functions to the constructor and also solve the
- 'this' problem along the way *)
- let rec use_this v e = match e.eexpr with
- | TConst TThis ->
- need_this := true;
- mk (TLocal v) v.v_type e.epos
- | _ -> Type.map_expr (use_this v) e
- in
- let e = Type.map_expr (use_this v) e in
- let cf2 = {cf with cf_expr = Some e} in
- (* if the method is an override, we have to remove the class field to not get invalid overrides *)
- let fields = if List.memq cf c.cl_overrides then begin
- c.cl_fields <- PMap.remove cf.cf_name c.cl_fields;
- fields
- end else
- cf2 :: fields
- in
- (cf2 :: inits, fields)
- | _ -> (inits, cf :: fields)
- ) ([],[]) c.cl_ordered_fields in
- c.cl_ordered_fields <- (List.rev fields);
- match inits with
- | [] -> ()
- | _ ->
- let el = List.map (fun cf ->
- match cf.cf_expr with
- | None -> assert false
- | Some e ->
- let lhs = mk (TField(ethis,FInstance (c,cf))) cf.cf_type e.epos in
- cf.cf_expr <- None;
- let eassign = mk (TBinop(OpAssign,lhs,e)) e.etype e.epos in
- if Common.defined ctx.com Define.As3 then begin
- let echeck = mk (TBinop(OpEq,lhs,(mk (TConst TNull) lhs.etype e.epos))) ctx.com.basic.tbool e.epos in
- mk (TIf(echeck,eassign,None)) eassign.etype e.epos
- end else
- eassign;
- ) inits in
- let el = if !need_this then (mk (TVars([v, Some ethis])) ethis.etype ethis.epos) :: el else el in
- match c.cl_constructor with
- | None ->
- let ct = TFun([],ctx.com.basic.tvoid) in
- let ce = mk (TFunction {
- tf_args = [];
- tf_type = ctx.com.basic.tvoid;
- tf_expr = mk (TBlock el) ctx.com.basic.tvoid c.cl_pos;
- }) ct c.cl_pos in
- let ctor = mk_field "new" ct c.cl_pos in
- ctor.cf_kind <- Method MethNormal;
- c.cl_constructor <- Some { ctor with cf_expr = Some ce };
- | Some cf ->
- match cf.cf_expr with
- | Some { eexpr = TFunction f } ->
- let bl = match f.tf_expr with {eexpr = TBlock b } -> b | x -> [x] in
- let ce = mk (TFunction {f with tf_expr = mk (TBlock (el @ bl)) ctx.com.basic.tvoid c.cl_pos }) cf.cf_type cf.cf_pos in
- c.cl_constructor <- Some {cf with cf_expr = Some ce }
- | _ ->
- assert false
- in
- match t with
- | TClassDecl c ->
- apply c
- | _ ->
- ()
- (* Adds the __meta__ field if required *)
- let add_meta_field ctx t = match t with
- | TClassDecl c ->
- (match build_metadata ctx.com t with
- | None -> ()
- | Some e ->
- let f = mk_field "__meta__" t_dynamic c.cl_pos in
- f.cf_expr <- Some e;
- c.cl_ordered_statics <- f :: c.cl_ordered_statics;
- c.cl_statics <- PMap.add f.cf_name f c.cl_statics)
- | _ ->
- ()
- (* Removes interfaces tagged with @:remove metadata *)
- let check_remove_metadata ctx t = match t with
- | TClassDecl c ->
- c.cl_implements <- List.filter (fun (c,_) -> not (Meta.has Meta.Remove c.cl_meta)) c.cl_implements;
- | _ ->
- ()
- (* Checks for Void class fields *)
- let check_void_field ctx t = match t with
- | TClassDecl c ->
- let check f =
- match follow f.cf_type with TAbstract({a_path=[],"Void"},_) -> error "Fields of type Void are not allowed" f.cf_pos | _ -> ();
- in
- List.iter check c.cl_ordered_fields;
- List.iter check c.cl_ordered_statics;
- | _ ->
- ()
- (* Promotes type parameters of abstracts to their implementation fields *)
- let promote_abstract_parameters ctx t = match t with
- | TClassDecl ({cl_kind = KAbstractImpl a} as c) when a.a_types <> [] ->
- List.iter (fun f ->
- List.iter (fun (n,t) -> match t with
- | TInst({cl_kind = KTypeParameter _; cl_path=p,n} as cp,[]) when not (List.mem_assoc n f.cf_params) ->
- let path = List.rev ((snd c.cl_path) :: List.rev (fst c.cl_path)),n in
- f.cf_params <- (n,TInst({cp with cl_path = path},[])) :: f.cf_params
- | _ ->
- ()
- ) a.a_types;
- ) c.cl_ordered_statics;
- | _ ->
- ()
- (*
- Pushes complex right-hand side expression inwards.
- return { exprs; value; } -> { exprs; return value; }
- x = { exprs; value; } -> { exprs; x = value; }
- var x = { exprs; value; } -> { var x; exprs; x = value; }
- *)
- let promote_complex_rhs ctx e =
- let rec is_complex e = match e.eexpr with
- | TBlock _ | TSwitch _ | TIf _ | TTry _ -> true
- | TBinop(_,e1,e2) -> is_complex e1 || is_complex e2
- | TParenthesis e | TMeta(_,e) -> is_complex e
- | _ -> false
- in
- let rec loop f e = match e.eexpr with
- | TBlock(el) ->
- begin match List.rev el with
- | elast :: el -> {e with eexpr = TBlock(block (List.rev ((loop f elast) :: el)))}
- | [] -> e
- end
- | TSwitch(es,cases,edef) ->
- {e with eexpr = TSwitch(es,List.map (fun (el,e) -> List.map find el,loop f e) cases,match edef with None -> None | Some e -> Some (loop f e))}
- | TIf(eif,ethen,eelse) ->
- {e with eexpr = TIf(find eif, loop f ethen, match eelse with None -> None | Some e -> Some (loop f e))}
- | TTry(e1,el) ->
- {e with eexpr = TTry(loop f e1, List.map (fun (el,e) -> el,loop f e) el)}
- | TParenthesis e1 when not (Common.defined ctx Define.As3) ->
- {e with eexpr = TParenthesis(loop f e1)}
- | TMeta(m,e1) ->
- { e with eexpr = TMeta(m,loop f e1)}
- | TReturn _ | TThrow _ ->
- find e
- | TCast(e1,None) when ctx.config.pf_ignore_unsafe_cast ->
- loop f e1
- | _ ->
- f (find e)
- and block el =
- let r = ref [] in
- List.iter (fun e ->
- match e.eexpr with
- | TVars(vl) ->
- List.iter (fun (v,eo) ->
- match eo with
- | Some e when is_complex e ->
- r := (loop (fun e -> mk (TBinop(OpAssign,mk (TLocal v) v.v_type e.epos,e)) v.v_type e.epos) e)
- :: ((mk (TVars [v,None]) ctx.basic.tvoid e.epos))
- :: !r
- | Some e ->
- r := (mk (TVars [v,Some (find e)]) ctx.basic.tvoid e.epos) :: !r
- | None -> r := (mk (TVars [v,None]) ctx.basic.tvoid e.epos) :: !r
- ) vl
- | _ -> r := (find e) :: !r
- ) el;
- List.rev !r
- and find e = match e.eexpr with
- | TReturn (Some e1) -> loop (fun e -> {e with eexpr = TReturn (Some e)}) e1
- | TBinop(OpAssign, ({eexpr = TLocal _ | TField _ | TArray _} as e1), e2) -> loop (fun er -> {e with eexpr = TBinop(OpAssign, e1, er)}) e2
- | TBlock(el) -> {e with eexpr = TBlock (block el)}
- | _ -> Type.map_expr find e
- in
- find e
- (* -------------------------------------------------------------------------- *)
- (* LOCAL VARIABLES USAGE *)
- type usage =
- | Block of ((usage -> unit) -> unit)
- | Loop of ((usage -> unit) -> unit)
- | Function of ((usage -> unit) -> unit)
- | Declare of tvar
- | Use of tvar
- let rec local_usage f e =
- match e.eexpr with
- | TLocal v ->
- f (Use v)
- | TVars l ->
- List.iter (fun (v,e) ->
- (match e with None -> () | Some e -> local_usage f e);
- f (Declare v);
- ) l
- | TFunction tf ->
- let cc f =
- List.iter (fun (v,_) -> f (Declare v)) tf.tf_args;
- local_usage f tf.tf_expr;
- in
- f (Function cc)
- | TBlock l ->
- f (Block (fun f -> List.iter (local_usage f) l))
- | TFor (v,it,e) ->
- local_usage f it;
- f (Loop (fun f ->
- f (Declare v);
- local_usage f e;
- ))
- | TWhile _ ->
- f (Loop (fun f ->
- iter (local_usage f) e
- ))
- | TTry (e,catchs) ->
- local_usage f e;
- List.iter (fun (v,e) ->
- f (Block (fun f ->
- f (Declare v);
- local_usage f e;
- ))
- ) catchs;
- | TPatMatch dt ->
- List.iter (fun (v,eo) ->
- f (Declare v);
- match eo with None -> () | Some e -> local_usage f e
- ) dt.dt_var_init;
- let rec fdt dt = match dt with
- | DTBind(bl,dt) ->
- List.iter (fun ((v,_),e) ->
- f (Declare v);
- local_usage f e
- ) bl;
- fdt dt
- | DTExpr e -> local_usage f e
- | DTGuard(e,dt1,dt2) ->
- local_usage f e;
- fdt dt1;
- (match dt2 with None -> () | Some dt -> fdt dt)
- | DTSwitch(e,cl,dto) ->
- local_usage f e;
- List.iter (fun (e,dt) ->
- local_usage f e;
- fdt dt
- ) cl;
- (match dto with None -> () | Some dt -> fdt dt)
- | DTGoto _ -> ()
- in
- Array.iter fdt dt.dt_dt_lookup
- | _ ->
- iter (local_usage f) e
- (* -------------------------------------------------------------------------- *)
- (* BLOCK VARIABLES CAPTURE *)
- (*
- For some platforms, it will simply mark the variables which are used in closures
- using the v_capture flag so it can be processed in a more optimized
- For Flash/JS platforms, it will ensure that variables used in loop sub-functions
- have an unique scope. It transforms the following expression :
- for( x in array )
- funs.push(function() return x++);
- Into the following :
- for( _x in array ) {
- var x = [_x];
- funs.push(function(x) { function() return x[0]++; }(x));
- }
- *)
- let captured_vars com e =
- let t = com.basic in
- let rec mk_init av v pos =
- mk (TVars [av,Some (mk (TArrayDecl [mk (TLocal v) v.v_type pos]) av.v_type pos)]) t.tvoid pos
- and mk_var v used =
- alloc_var v.v_name (PMap.find v.v_id used)
- and wrap used e =
- match e.eexpr with
- | TVars vl ->
- let vl = List.map (fun (v,ve) ->
- if PMap.mem v.v_id used then
- v, Some (mk (TArrayDecl (match ve with None -> [] | Some e -> [wrap used e])) v.v_type e.epos)
- else
- v, (match ve with None -> None | Some e -> Some (wrap used e))
- ) vl in
- { e with eexpr = TVars vl }
- | TLocal v when PMap.mem v.v_id used ->
- mk (TArray ({ e with etype = v.v_type },mk (TConst (TInt 0l)) t.tint e.epos)) e.etype e.epos
- | TFor (v,it,expr) when PMap.mem v.v_id used ->
- let vtmp = mk_var v used in
- let it = wrap used it in
- let expr = wrap used expr in
- mk (TFor (vtmp,it,concat (mk_init v vtmp e.epos) expr)) e.etype e.epos
- | TTry (expr,catchs) ->
- let catchs = List.map (fun (v,e) ->
- let e = wrap used e in
- try
- let vtmp = mk_var v used in
- vtmp, concat (mk_init v vtmp e.epos) e
- with Not_found ->
- v, e
- ) catchs in
- mk (TTry (wrap used expr,catchs)) e.etype e.epos
- (* TODO: find out this does *)
- (* | TMatch (expr,enum,cases,def) ->
- let cases = List.map (fun (il,vars,e) ->
- let pos = e.epos in
- let e = ref (wrap used e) in
- let vars = match vars with
- | None -> None
- | Some l ->
- Some (List.map (fun v ->
- match v with
- | Some v when PMap.mem v.v_id used ->
- let vtmp = mk_var v used in
- e := concat (mk_init v vtmp pos) !e;
- Some vtmp
- | _ -> v
- ) l)
- in
- il, vars, !e
- ) cases in
- let def = match def with None -> None | Some e -> Some (wrap used e) in
- mk (TMatch (wrap used expr,enum,cases,def)) e.etype e.epos *)
- | TFunction f ->
- (*
- list variables that are marked as used, but also used in that
- function and which are not declared inside it !
- *)
- let fused = ref PMap.empty in
- let tmp_used = ref used in
- let rec browse = function
- | Block f | Loop f | Function f -> f browse
- | Use v ->
- if PMap.mem v.v_id !tmp_used then fused := PMap.add v.v_id v !fused;
- | Declare v ->
- tmp_used := PMap.remove v.v_id !tmp_used
- in
- local_usage browse e;
- let vars = PMap.fold (fun v acc -> v :: acc) !fused [] in
- (* in case the variable has been marked as used in a parallel scope... *)
- let fexpr = ref (wrap used f.tf_expr) in
- let fargs = List.map (fun (v,o) ->
- if PMap.mem v.v_id used then
- let vtmp = mk_var v used in
- fexpr := concat (mk_init v vtmp e.epos) !fexpr;
- vtmp, o
- else
- v, o
- ) f.tf_args in
- let e = { e with eexpr = TFunction { f with tf_args = fargs; tf_expr = !fexpr } } in
- (*
- Create a new function scope to make sure that the captured loop variable
- will not be overwritten in next loop iteration
- *)
- if com.config.pf_capture_policy = CPLoopVars then
- mk (TCall (
- mk_parent (mk (TFunction {
- tf_args = List.map (fun v -> v, None) vars;
- tf_type = e.etype;
- tf_expr = mk_block (mk (TReturn (Some e)) e.etype e.epos);
- }) (TFun (List.map (fun v -> v.v_name,false,v.v_type) vars,e.etype)) e.epos),
- List.map (fun v -> mk (TLocal v) v.v_type e.epos) vars)
- ) e.etype e.epos
- else
- e
- | _ ->
- map_expr (wrap used) e
- and do_wrap used e =
- if PMap.is_empty used then
- e
- else
- let used = PMap.map (fun v ->
- let vt = v.v_type in
- v.v_type <- t.tarray vt;
- v.v_capture <- true;
- vt
- ) used in
- wrap used e
- and out_loop e =
- match e.eexpr with
- | TFor _ | TWhile _ ->
- (*
- collect variables that are declared in loop but used in subfunctions
- *)
- let vars = ref PMap.empty in
- let used = ref PMap.empty in
- let depth = ref 0 in
- let rec collect_vars in_loop = function
- | Block f ->
- let old = !vars in
- f (collect_vars in_loop);
- vars := old;
- | Loop f ->
- let old = !vars in
- f (collect_vars true);
- vars := old;
- | Function f ->
- incr depth;
- f (collect_vars false);
- decr depth;
- | Declare v ->
- if in_loop then vars := PMap.add v.v_id !depth !vars;
- | Use v ->
- try
- let d = PMap.find v.v_id !vars in
- if d <> !depth then used := PMap.add v.v_id v !used;
- with Not_found ->
- ()
- in
- local_usage (collect_vars false) e;
- do_wrap !used e
- | _ ->
- map_expr out_loop e
- and all_vars e =
- let vars = ref PMap.empty in
- let used = ref PMap.empty in
- let depth = ref 0 in
- let rec collect_vars = function
- | Block f ->
- let old = !vars in
- f collect_vars;
- vars := old;
- | Loop f ->
- let old = !vars in
- f collect_vars;
- vars := old;
- | Function f ->
- incr depth;
- f collect_vars;
- decr depth;
- | Declare v ->
- vars := PMap.add v.v_id !depth !vars;
- | Use v ->
- try
- let d = PMap.find v.v_id !vars in
- if d <> !depth then used := PMap.add v.v_id v !used;
- with Not_found -> ()
- in
- local_usage collect_vars e;
- !used
- in
- (* mark all capture variables - also used in rename_local_vars at later stage *)
- let captured = all_vars e in
- PMap.iter (fun _ v -> v.v_capture <- true) captured;
- match com.config.pf_capture_policy with
- | CPNone -> e
- | CPWrapRef -> do_wrap captured e
- | CPLoopVars -> out_loop e
- (* -------------------------------------------------------------------------- *)
- (* RENAME LOCAL VARS *)
- let rename_local_vars com e =
- let cfg = com.config in
- let all_scope = (not cfg.pf_captured_scope) || (not cfg.pf_locals_scope) in
- let vars = ref PMap.empty in
- let all_vars = ref PMap.empty in
- let vtemp = alloc_var "~" t_dynamic in
- let rebuild_vars = ref false in
- let rebuild m =
- PMap.fold (fun v acc -> PMap.add v.v_name v acc) m PMap.empty
- in
- let save() =
- let old = !vars in
- if cfg.pf_unique_locals then (fun() -> ()) else (fun() -> vars := if !rebuild_vars then rebuild old else old)
- in
- let rename vars v =
- let count = ref 1 in
- while PMap.mem (v.v_name ^ string_of_int !count) vars do
- incr count;
- done;
- v.v_name <- v.v_name ^ string_of_int !count;
- in
- let declare v p =
- (match follow v.v_type with
- | TAbstract ({a_path = [],"Void"},_) -> error "Arguments and variables of type Void are not allowed" p
- | _ -> ());
- (* chop escape char for all local variables generated *)
- 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);
- let look_vars = (if not cfg.pf_captured_scope && v.v_capture then !all_vars else !vars) in
- (try
- let v2 = PMap.find v.v_name look_vars in
- (*
- block_vars will create some wrapper-functions that are declaring
- the same variable twice. In that case do not perform a rename since
- we are sure it's actually the same variable
- *)
- if v == v2 then raise Not_found;
- rename look_vars v;
- with Not_found ->
- ());
- vars := PMap.add v.v_name v !vars;
- if all_scope then all_vars := PMap.add v.v_name v !all_vars;
- in
- (*
- This is quite a rare case, when a local variable would otherwise prevent
- accessing a type because it masks the type value or the package name.
- *)
- let check t =
- match (t_infos t).mt_path with
- | [], name | name :: _, _ ->
- let vars = if cfg.pf_locals_scope then vars else all_vars in
- (try
- let v = PMap.find name !vars in
- if v == vtemp then raise Not_found; (* ignore *)
- rename (!vars) v;
- rebuild_vars := true;
- vars := PMap.add v.v_name v !vars
- with Not_found ->
- ());
- vars := PMap.add name vtemp !vars
- in
- let check_type t =
- match follow t with
- | TInst (c,_) -> check (TClassDecl c)
- | TEnum (e,_) -> check (TEnumDecl e)
- | TType (t,_) -> check (TTypeDecl t)
- | TAbstract (a,_) -> check (TAbstractDecl a)
- | TMono _ | TLazy _ | TAnon _ | TDynamic _ | TFun _ -> ()
- in
- let rec loop e =
- match e.eexpr with
- | TVars l ->
- List.iter (fun (v,eo) ->
- if not cfg.pf_locals_scope then declare v e.epos;
- (match eo with None -> () | Some e -> loop e);
- if cfg.pf_locals_scope then declare v e.epos;
- ) l
- | TFunction tf ->
- let old = save() in
- List.iter (fun (v,_) -> declare v e.epos) tf.tf_args;
- loop tf.tf_expr;
- old()
- | TBlock el ->
- let old = save() in
- List.iter loop el;
- old()
- | TFor (v,it,e1) ->
- loop it;
- let old = save() in
- declare v e.epos;
- loop e1;
- old()
- | TTry (e,catchs) ->
- loop e;
- List.iter (fun (v,e) ->
- let old = save() in
- declare v e.epos;
- check_type v.v_type;
- loop e;
- old()
- ) catchs;
- | TPatMatch dt ->
- let rec fdt dt = match dt with
- | DTSwitch(e,cl,dto) ->
- loop e;
- List.iter (fun (_,dt) ->
- let old = save() in
- fdt dt;
- old();
- ) cl;
- (match dto with None -> () | Some dt ->
- let old = save() in
- fdt dt;
- old())
- | DTBind(bl,dt) ->
- List.iter (fun ((v,p),e) ->
- declare v e.epos
- ) bl;
- fdt dt
- | DTExpr e -> loop e;
- | DTGuard(e,dt1,dt2) ->
- loop e;
- fdt dt1;
- (match dt2 with None -> () | Some dt -> fdt dt)
- | DTGoto _ ->
- ()
- in
- Array.iter fdt dt.dt_dt_lookup
- | TTypeExpr t ->
- check t
- | TNew (c,_,_) ->
- Type.iter loop e;
- check (TClassDecl c);
- | TCast (e,Some t) ->
- loop e;
- check t;
- | _ ->
- Type.iter loop e
- in
- declare (alloc_var "this" t_dynamic) Ast.null_pos; (* force renaming of 'this' vars in abstract *)
- loop e;
- e
- (* -------------------------------------------------------------------------- *)
- (* CHECK LOCAL VARS INIT *)
- let check_local_vars_init e =
- let intersect vl1 vl2 =
- PMap.mapi (fun v t -> t && PMap.find v vl2) vl1
- in
- let join vars cvars =
- List.iter (fun v -> vars := intersect !vars v) cvars
- in
- let restore vars old_vars declared =
- (* restore variables declared in this block to their previous state *)
- vars := List.fold_left (fun acc v ->
- try PMap.add v (PMap.find v old_vars) acc with Not_found -> PMap.remove v acc
- ) !vars declared;
- in
- let declared = ref [] in
- let rec loop vars e =
- match e.eexpr with
- | TLocal v ->
- let init = (try PMap.find v.v_id !vars with Not_found -> true) in
- if not init then begin
- if v.v_name = "this" then error "Missing this = value" e.epos
- else error ("Local variable " ^ v.v_name ^ " used without being initialized") e.epos
- end
- | TVars vl ->
- List.iter (fun (v,eo) ->
- match eo with
- | None ->
- declared := v.v_id :: !declared;
- vars := PMap.add v.v_id false !vars
- | Some e ->
- loop vars e
- ) vl
- | TBlock el ->
- let old = !declared in
- let old_vars = !vars in
- declared := [];
- List.iter (loop vars) el;
- restore vars old_vars (List.rev !declared);
- declared := old;
- | TBinop (OpAssign,{ eexpr = TLocal v },e) when PMap.mem v.v_id !vars ->
- loop vars e;
- vars := PMap.add v.v_id true !vars
- | TIf (e1,e2,eo) ->
- loop vars e1;
- let vbase = !vars in
- loop vars e2;
- (match eo with
- | None -> vars := vbase
- | Some e ->
- let v1 = !vars in
- vars := vbase;
- loop vars e;
- vars := intersect !vars v1)
- | TWhile (cond,e,flag) ->
- (match flag with
- | NormalWhile ->
- loop vars cond;
- let old = !vars in
- loop vars e;
- vars := old;
- | DoWhile ->
- loop vars e;
- loop vars cond)
- | TTry (e,catches) ->
- let cvars = List.map (fun (v,e) ->
- let old = !vars in
- loop vars e;
- let v = !vars in
- vars := old;
- v
- ) catches in
- loop vars e;
- join vars cvars;
- | TSwitch (e,cases,def) ->
- loop vars e;
- let cvars = List.map (fun (ec,e) ->
- let old = !vars in
- List.iter (loop vars) ec;
- vars := old;
- loop vars e;
- let v = !vars in
- vars := old;
- v
- ) cases in
- (match def with
- | None when (match e.eexpr with TMeta((Meta.Exhaustive,_,_),_) | TParenthesis({eexpr = TMeta((Meta.Exhaustive,_,_),_)}) -> true | _ -> false) ->
- (match cvars with
- | cv :: cvars ->
- PMap.iter (fun i b -> if b then vars := PMap.add i b !vars) cv;
- join vars cvars
- | [] -> ())
- | None -> ()
- | Some e ->
- loop vars e;
- join vars cvars)
- | TPatMatch dt ->
- let cvars = ref [] in
- let rec fdt dt = match dt with
- | DTExpr e ->
- let old = !vars in
- loop vars e;
- restore vars old [];
- cvars := !vars :: !cvars
- | DTSwitch(e,cl,dto) ->
- loop vars e;
- List.iter (fun (_,dt) -> fdt dt) cl;
- (match dto with None -> () | Some dt -> fdt dt)
- | DTGuard(e,dt1,dt2) ->
- fdt dt1;
- (match dt2 with None -> () | Some dt -> fdt dt)
- | DTBind(_,dt) -> fdt dt
- | DTGoto _ -> ()
- in
- Array.iter fdt dt.dt_dt_lookup;
- join vars !cvars
- (* mark all reachable vars as initialized, since we don't exit the block *)
- | TBreak | TContinue | TReturn None ->
- vars := PMap.map (fun _ -> true) !vars
- | TThrow e | TReturn (Some e) ->
- loop vars e;
- vars := PMap.map (fun _ -> true) !vars
- | _ ->
- Type.iter (loop vars) e
- in
- loop (ref PMap.empty) e;
- e
- (* -------------------------------------------------------------------------- *)
- (* ABSTRACT CASTS *)
- module Abstract = struct
- let find_to ab pl b = List.find (Type.unify_to_field ab pl b) ab.a_to
- let find_from ab pl a b = List.find (Type.unify_from_field ab pl a b) ab.a_from
- let cast_stack = ref []
- let get_underlying_type a pl =
- try
- if not (Meta.has Meta.MultiType a.a_meta) then raise Not_found;
- let m = mk_mono() in
- let _ = find_to a pl m in
- follow m
- with Not_found ->
- apply_params a.a_types pl a.a_this
- let make_static_call ctx c cf a pl args t p =
- let ta = TAnon { a_fields = c.cl_statics; a_status = ref (Statics c) } in
- let ethis = mk (TTypeExpr (TClassDecl c)) ta p in
- let monos = List.map (fun _ -> mk_mono()) cf.cf_params in
- let map t = apply_params a.a_types pl (apply_params cf.cf_params monos t) in
- let ef = mk (TField (ethis,(FStatic (c,cf)))) (map cf.cf_type) p in
- make_call ctx ef args (map t) p
- let rec do_check_cast ctx tleft eright p =
- let tright = follow eright.etype in
- let tleft = follow tleft in
- if tleft == tright then eright else
- let recurse cf f =
- if cf == ctx.curfield || List.mem cf !cast_stack then error "Recursive implicit cast" p;
- cast_stack := cf :: !cast_stack;
- let r = f() in
- cast_stack := List.tl !cast_stack;
- r
- in
- try (match tright,tleft with
- | (TAbstract({a_impl = Some c1} as a1,pl1) as t1),(TAbstract({a_impl = Some c2} as a2,pl2) as t2) ->
- if a1 == a2 then
- eright
- else begin
- let c,cfo,a,pl = try
- if Meta.has Meta.MultiType a1.a_meta then raise Not_found;
- c1,snd (find_to a1 pl1 t2),a1,pl1
- with Not_found ->
- if Meta.has Meta.MultiType a2.a_meta then raise Not_found;
- c2,snd (find_from a2 pl2 t1 t2),a2,pl2
- in
- match cfo with
- | None -> eright
- | Some cf ->
- recurse cf (fun () -> make_static_call ctx c cf a pl [eright] tleft p)
- end
- | TDynamic _,_ | _,TDynamic _ | _, TMono _ | TMono _, _ ->
- eright
- | TAbstract({a_impl = Some c} as a,pl),t2 when not (Meta.has Meta.MultiType a.a_meta) ->
- begin match find_to a pl t2 with
- | tcf,None ->
- let tcf = apply_params a.a_types pl tcf in
- if type_iseq tcf tleft then eright else do_check_cast ctx tcf eright p
- | _,Some cf ->
- recurse cf (fun () -> make_static_call ctx c cf a pl [eright] tleft p)
- end
- | t1,(TAbstract({a_impl = Some c} as a,pl) as t2) when not (Meta.has Meta.MultiType a.a_meta) ->
- begin match find_from a pl t1 t2 with
- | tcf,None ->
- let tcf = apply_params a.a_types pl tcf in
- if type_iseq tcf tleft then eright else do_check_cast ctx tcf eright p
- | _,Some cf ->
- recurse cf (fun () -> make_static_call ctx c cf a pl [eright] tleft p)
- end
- | _ ->
- eright)
- with Not_found ->
- eright
- let check_cast ctx tleft eright p =
- if ctx.com.display then eright else do_check_cast ctx tleft eright p
- let find_multitype_specialization a pl p =
- let m = mk_mono() in
- let at = apply_params a.a_types pl a.a_this in
- let _,cfo =
- try find_to a pl m
- with Not_found ->
- let st = s_type (print_context()) at in
- if has_mono at then
- error ("Type parameters of multi type abstracts must be known (for " ^ st ^ ")") p
- else
- error ("Abstract " ^ (s_type_path a.a_path) ^ " has no @:to function that accepts " ^ st) p;
- in
- match cfo with
- | None -> assert false
- | Some cf -> cf, follow m
- let handle_abstract_casts ctx e =
- let rec loop ctx e = match e.eexpr with
- | TNew({cl_kind = KAbstractImpl a} as c,pl,el) ->
- (* a TNew of an abstract implementation is only generated if it is a multi type abstract *)
- let cf,m = find_multitype_specialization a pl e.epos in
- let e = make_static_call ctx c cf a pl ((mk (TConst TNull) (TAbstract(a,pl)) e.epos) :: el) m e.epos in
- {e with etype = m}
- | TCall(e1, el) ->
- begin try
- begin match e1.eexpr with
- | TField(e2,fa) ->
- begin match follow e2.etype with
- | TAbstract(a,pl) when Meta.has Meta.MultiType a.a_meta ->
- let m = get_underlying_type a pl in
- let fname = field_name fa in
- let el = List.map (loop ctx) el in
- begin try
- let ef = mk (TField({e2 with etype = m},quick_field m fname)) e1.etype e2.epos in
- make_call ctx ef el e.etype e.epos
- with Not_found ->
- (* quick_field raises Not_found if m is an abstract, we have to replicate the 'using' call here *)
- match follow m with
- | TAbstract({a_impl = Some c} as a,pl) ->
- let cf = PMap.find fname c.cl_statics in
- make_static_call ctx c cf a pl (e2 :: el) e.etype e.epos
- | _ -> raise Not_found
- end
- | _ -> raise Not_found
- end
- | _ ->
- raise Not_found
- end
- with Not_found ->
- Type.map_expr (loop ctx) e
- end
- | _ ->
- Type.map_expr (loop ctx) e
- in
- loop ctx e
- end
- module PatternMatchConversion = struct
- type cctx = {
- ctx : typer;
- mutable eval_stack : ((tvar * pos) * texpr) list list;
- dt_lookup : dt array;
- }
- let is_declared cctx v =
- let rec loop sl = match sl with
- | stack :: sl ->
- List.exists (fun ((v2,_),_) -> v == v2) stack || loop sl
- | [] ->
- false
- in
- loop cctx.eval_stack
- let group_cases cases =
- let dt_eq dt1 dt2 = match dt1,dt2 with
- | DTGoto i1, DTGoto i2 when i1 = i2 -> true
- (* TODO equal bindings *)
- | _ -> false
- in
- match List.rev cases with
- | [] -> []
- | [con,dt] -> [[con],dt]
- | (con,dt) :: cases ->
- let tmp,ldt,cases = List.fold_left (fun (tmp,ldt,acc) (con,dt) ->
- if dt_eq dt ldt then
- (con :: tmp,dt,acc)
- else
- ([con],dt,(tmp,ldt) :: acc)
- ) ([con],dt,[]) cases in
- match tmp with
- | [] -> cases
- | tmp -> ((tmp,ldt) :: cases)
- let rec convert_dt cctx dt =
- match dt with
- | DTBind (bl,dt) ->
- cctx.eval_stack <- bl :: cctx.eval_stack;
- let e = convert_dt cctx dt in
- cctx.eval_stack <- List.tl cctx.eval_stack;
- let vl,el = List.fold_left (fun (vl,el) ((v,p),e) ->
- if is_declared cctx v then
- vl, (mk (TBinop(OpAssign,mk (TLocal v) v.v_type p,e)) e.etype e.epos) :: el
- else
- ((v,Some e) :: vl), el
- ) ([],[e]) bl in
- mk (TBlock
- ((mk (TVars (vl)) cctx.ctx.t.tvoid e.epos)
- :: el)
- ) e.etype e.epos
- | DTGoto i ->
- convert_dt cctx (cctx.dt_lookup.(i))
- | DTExpr e ->
- e
- | DTGuard(e,dt1,dt2) ->
- let ethen = convert_dt cctx dt1 in
- mk (TIf(e,ethen,match dt2 with None -> None | Some dt -> Some (convert_dt cctx dt))) ethen.etype (punion e.epos ethen.epos)
- | DTSwitch({eexpr = TMeta((Meta.Exhaustive,_,_),_)},[_,dt],None) ->
- convert_dt cctx dt
- | DTSwitch(e_st,cl,dto) ->
- let def = match dto with None -> None | Some dt -> Some (convert_dt cctx dt) in
- let cases = group_cases cl in
- let cases = List.map (fun (cl,dt) -> cl,convert_dt cctx dt) cases in
- mk (TSwitch(e_st,cases,def)) (mk_mono()) e_st.epos
- let to_typed_ast ctx dt p =
- let first = dt.dt_dt_lookup.(dt.dt_first) in
- let cctx = {
- ctx = ctx;
- dt_lookup = dt.dt_dt_lookup;
- eval_stack = [];
- } in
- let e = convert_dt cctx first in
- let e = { e with epos = p; etype = dt.dt_type} in
- if dt.dt_var_init = [] then
- e
- else begin
- mk (TBlock [
- mk (TVars dt.dt_var_init) t_dynamic e.epos;
- e;
- ]) dt.dt_type e.epos
- end
- end
- (* -------------------------------------------------------------------------- *)
- (* USAGE *)
- let detect_usage com =
- let usage = ref [] in
- List.iter (fun t -> match t with
- | TClassDecl c ->
- let rec expr e = match e.eexpr with
- | TField(_,fa) ->
- (match extract_field fa with
- | Some cf when Meta.has Meta.Usage cf.cf_meta ->
- let p = {e.epos with pmin = e.epos.pmax - (String.length cf.cf_name)} in
- usage := p :: !usage;
- | _ -> ());
- Type.iter expr e
- | _ -> Type.iter expr e
- in
- let field cf = match cf.cf_expr with None -> () | Some e -> expr e in
- (match c.cl_constructor with None -> () | Some cf -> field cf);
- (match c.cl_init with None -> () | Some e -> expr e);
- List.iter field c.cl_ordered_statics;
- List.iter field c.cl_ordered_fields;
- | _ -> ()
- ) com.types;
- let usage = List.sort (fun p1 p2 ->
- let c = compare p1.pfile p2.pfile in
- if c <> 0 then c else compare p1.pmin p2.pmin
- ) !usage in
- raise (Typecore.DisplayPosition usage)
- (* -------------------------------------------------------------------------- *)
- (* POST PROCESS *)
- let pp_counter = ref 1
- let post_process ctx filters t =
- (* ensure that we don't process twice the same (cached) module *)
- let m = (t_infos t).mt_module.m_extra in
- if m.m_processed = 0 then m.m_processed <- !pp_counter;
- if m.m_processed = !pp_counter then
- match t with
- | TClassDecl c when is_removable_class c -> ()
- | TClassDecl c ->
- let process_field f =
- match f.cf_expr with
- | Some e when not (is_removable_field ctx f) ->
- Abstract.cast_stack := f :: !Abstract.cast_stack;
- f.cf_expr <- Some (List.fold_left (fun e f -> f e) e filters);
- Abstract.cast_stack := List.tl !Abstract.cast_stack;
- | _ -> ()
- in
- List.iter process_field c.cl_ordered_fields;
- List.iter process_field c.cl_ordered_statics;
- (match c.cl_constructor with
- | None -> ()
- | Some f -> process_field f);
- (match c.cl_init with
- | None -> ()
- | Some e ->
- c.cl_init <- Some (List.fold_left (fun e f -> f e) e filters));
- | TEnumDecl _ -> ()
- | TTypeDecl _ -> ()
- | TAbstractDecl _ -> ()
- let post_process_end() =
- incr pp_counter
- (* -------------------------------------------------------------------------- *)
- (* STACK MANAGEMENT EMULATION *)
- type stack_context = {
- stack_var : string;
- stack_exc_var : string;
- stack_pos_var : string;
- stack_pos : pos;
- stack_expr : texpr;
- stack_pop : texpr;
- stack_save_pos : texpr;
- stack_restore : texpr list;
- stack_push : tclass -> string -> texpr;
- stack_return : texpr -> texpr;
- }
- let stack_context_init com stack_var exc_var pos_var tmp_var use_add p =
- let t = com.basic in
- let st = t.tarray t.tstring in
- let stack_var = alloc_var stack_var st in
- let exc_var = alloc_var exc_var st in
- let pos_var = alloc_var pos_var t.tint in
- let stack_e = mk (TLocal stack_var) st p in
- let exc_e = mk (TLocal exc_var) st p in
- let stack_pop = fcall stack_e "pop" [] t.tstring p in
- let stack_push c m =
- fcall stack_e "push" [
- if use_add then
- binop OpAdd (string com (s_type_path c.cl_path ^ "::") p) (string com m p) t.tstring p
- else
- string com (s_type_path c.cl_path ^ "::" ^ m) p
- ] t.tvoid p
- in
- let stack_return e =
- let tmp = alloc_var tmp_var e.etype in
- mk (TBlock [
- mk (TVars [tmp, Some e]) t.tvoid e.epos;
- stack_pop;
- mk (TReturn (Some (mk (TLocal tmp) e.etype e.epos))) e.etype e.epos
- ]) e.etype e.epos
- in
- {
- stack_var = stack_var.v_name;
- stack_exc_var = exc_var.v_name;
- stack_pos_var = pos_var.v_name;
- stack_pos = p;
- stack_expr = stack_e;
- stack_pop = stack_pop;
- stack_save_pos = mk (TVars [pos_var, Some (field stack_e "length" t.tint p)]) t.tvoid p;
- stack_push = stack_push;
- stack_return = stack_return;
- stack_restore = [
- binop OpAssign exc_e (mk (TArrayDecl []) st p) st p;
- mk (TWhile (
- mk_parent (binop OpGte (field stack_e "length" t.tint p) (mk (TLocal pos_var) t.tint p) t.tbool p),
- fcall exc_e "unshift" [fcall stack_e "pop" [] t.tstring p] t.tvoid p,
- NormalWhile
- )) t.tvoid p;
- fcall stack_e "push" [index com exc_e 0 t.tstring p] t.tvoid p
- ];
- }
- let stack_init com use_add =
- stack_context_init com "$s" "$e" "$spos" "$tmp" use_add null_pos
- let rec stack_block_loop ctx e =
- match e.eexpr with
- | TFunction _ ->
- e
- | TReturn None | TReturn (Some { eexpr = TConst _ }) | TReturn (Some { eexpr = TLocal _ }) ->
- mk (TBlock [
- ctx.stack_pop;
- e;
- ]) e.etype e.epos
- | TReturn (Some e) ->
- ctx.stack_return (stack_block_loop ctx e)
- | TTry (v,cases) ->
- let v = stack_block_loop ctx v in
- let cases = List.map (fun (v,e) ->
- let e = stack_block_loop ctx e in
- let e = (match (mk_block e).eexpr with
- | TBlock l -> mk (TBlock (ctx.stack_restore @ l)) e.etype e.epos
- | _ -> assert false
- ) in
- v , e
- ) cases in
- mk (TTry (v,cases)) e.etype e.epos
- | _ ->
- map_expr (stack_block_loop ctx) e
- let stack_block ctx c m e =
- match (mk_block e).eexpr with
- | TBlock l ->
- mk (TBlock (
- ctx.stack_push c m ::
- ctx.stack_save_pos ::
- List.map (stack_block_loop ctx) l
- @ [ctx.stack_pop]
- )) e.etype e.epos
- | _ ->
- assert false
- (* -------------------------------------------------------------------------- *)
- (* FIX OVERRIDES *)
- (*
- on some platforms which doesn't support type parameters, we must have the
- exact same type for overriden/implemented function as the original one
- *)
- let rec find_field c f =
- try
- (match c.cl_super with
- | None ->
- raise Not_found
- | Some ( {cl_path = (["cpp"],"FastIterator")}, _ ) ->
- raise Not_found (* This is a strongly typed 'extern' and the usual rules don't apply *)
- | Some (c,_) ->
- find_field c f)
- with Not_found -> try
- let rec loop = function
- | [] ->
- raise Not_found
- | (c,_) :: l ->
- try
- find_field c f
- with
- Not_found -> loop l
- in
- loop c.cl_implements
- with Not_found ->
- let f = PMap.find f.cf_name c.cl_fields in
- (match f.cf_kind with Var { v_read = AccRequire _ } -> raise Not_found | _ -> ());
- f
- let fix_override com c f fd =
- let f2 = (try Some (find_field c f) with Not_found -> None) in
- match f2,fd with
- | Some (f2), Some(fd) ->
- let targs, tret = (match follow f2.cf_type with TFun (args,ret) -> args, ret | _ -> assert false) in
- let changed_args = ref [] in
- let prefix = "_tmp_" in
- let nargs = List.map2 (fun ((v,c) as cur) (_,_,t2) ->
- try
- type_eq EqStrict v.v_type t2;
- cur
- with Unify_error _ ->
- let v2 = alloc_var (prefix ^ v.v_name) t2 in
- changed_args := (v,v2) :: !changed_args;
- v2,c
- ) fd.tf_args targs in
- let fd2 = {
- tf_args = nargs;
- tf_type = tret;
- tf_expr = (match List.rev !changed_args with
- | [] -> fd.tf_expr
- | args ->
- let e = fd.tf_expr in
- let el = (match e.eexpr with TBlock el -> el | _ -> [e]) in
- let p = (match el with [] -> e.epos | e :: _ -> e.epos) in
- let v = mk (TVars (List.map (fun (v,v2) ->
- (v,Some (mk (TCast (mk (TLocal v2) v2.v_type p,None)) v.v_type p))
- ) args)) com.basic.tvoid p in
- { e with eexpr = TBlock (v :: el) }
- );
- } in
- (* as3 does not allow wider visibility, so the base method has to be made public *)
- if Common.defined com Define.As3 && f.cf_public then f2.cf_public <- true;
- let targs = List.map (fun(v,c) -> (v.v_name, Option.is_some c, v.v_type)) nargs in
- let fde = (match f.cf_expr with None -> assert false | Some e -> e) in
- f.cf_expr <- Some { fde with eexpr = TFunction fd2 };
- f.cf_type <- TFun(targs,tret);
- | Some(f2), None when c.cl_interface ->
- let targs, tret = (match follow f2.cf_type with TFun (args,ret) -> args, ret | _ -> assert false) in
- f.cf_type <- TFun(targs,tret)
- | _ ->
- ()
- let fix_overrides com t =
- match t with
- | TClassDecl c ->
- (* overrides can be removed from interfaces *)
- if c.cl_interface then
- c.cl_ordered_fields <- List.filter (fun f ->
- try
- if find_field c f == f then raise Not_found;
- c.cl_fields <- PMap.remove f.cf_name c.cl_fields;
- false;
- with Not_found ->
- true
- ) c.cl_ordered_fields;
- List.iter (fun f ->
- match f.cf_expr, f.cf_kind with
- | Some { eexpr = TFunction fd }, Method (MethNormal | MethInline) ->
- fix_override com c f (Some fd)
- | None, Method (MethNormal | MethInline) when c.cl_interface ->
- fix_override com c f None
- | _ ->
- ()
- ) c.cl_ordered_fields
- | _ ->
- ()
- (*
- PHP does not allow abstract classes extending other abstract classes to override any fields, so these duplicates
- must be removed from the child interface
- *)
- let fix_abstract_inheritance com t =
- match t with
- | TClassDecl c when c.cl_interface ->
- c.cl_ordered_fields <- List.filter (fun f ->
- let b = try (find_field c f) == f
- with Not_found -> false in
- if not b then c.cl_fields <- PMap.remove f.cf_name c.cl_fields;
- b;
- ) c.cl_ordered_fields
- | _ -> ()
- (* -------------------------------------------------------------------------- *)
- (* MISC FEATURES *)
- let rec is_volatile t =
- match t with
- | TMono r ->
- (match !r with
- | Some t -> is_volatile t
- | _ -> false)
- | TLazy f ->
- is_volatile (!f())
- | TType (t,tl) ->
- (match t.t_path with
- | ["mt";"flash"],"Volatile" -> true
- | _ -> is_volatile (apply_params t.t_types tl t.t_type))
- | _ ->
- false
- let set_default ctx a c p =
- let t = a.v_type in
- let ve = mk (TLocal a) t p in
- let cond = TBinop (OpEq,ve,mk (TConst TNull) t p) in
- 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
- let bytes_serialize data =
- let b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789%:" in
- let tbl = Array.init (String.length b64) (fun i -> String.get b64 i) in
- let str = Base64.str_encode ~tbl data in
- "s" ^ string_of_int (String.length str) ^ ":" ^ str
- (*
- Tells if the constructor might be called without any issue whatever its parameters
- *)
- let rec constructor_side_effects e =
- match e.eexpr with
- | TBinop (op,_,_) when op <> OpAssign ->
- true
- | TField (_,FEnum _) ->
- false
- | TUnop _ | TArray _ | TField _ | TEnumParameter _ | TCall _ | TNew _ | TFor _ | TWhile _ | TSwitch _ | TPatMatch _ | TReturn _ | TThrow _ ->
- true
- | TBinop _ | TTry _ | TIf _ | TBlock _ | TVars _
- | TFunction _ | TArrayDecl _ | TObjectDecl _
- | TParenthesis _ | TTypeExpr _ | TLocal _ | TMeta _
- | TConst _ | TContinue | TBreak | TCast _ ->
- try
- Type.iter (fun e -> if constructor_side_effects e then raise Exit) e;
- false;
- with Exit ->
- true
- (*
- Make a dump of the full typed AST of all types
- *)
- let rec create_dumpfile acc = function
- | [] -> assert false
- | d :: [] ->
- let ch = open_out (String.concat "/" (List.rev (d :: acc)) ^ ".dump") in
- let buf = Buffer.create 0 in
- buf, (fun () ->
- output_string ch (Buffer.contents buf);
- close_out ch)
- | d :: l ->
- let dir = String.concat "/" (List.rev (d :: acc)) in
- if not (Sys.file_exists dir) then Unix.mkdir dir 0o755;
- create_dumpfile (d :: acc) l
- let dump_types com =
- let s_type = s_type (Type.print_context()) in
- let params = function [] -> "" | l -> Printf.sprintf "<%s>" (String.concat "," (List.map (fun (n,t) -> n ^ " : " ^ s_type t) l)) in
- let s_expr = try if Common.defined_value com Define.Dump = "pretty" then Type.s_expr_pretty "\t" else Type.s_expr with Not_found -> Type.s_expr in
- List.iter (fun mt ->
- let path = Type.t_path mt in
- let buf,close = create_dumpfile [] ("dump" :: (Common.platform_name com.platform) :: fst path @ [snd path]) in
- let print fmt = Printf.kprintf (fun s -> Buffer.add_string buf s) fmt in
- (match mt with
- | Type.TClassDecl c ->
- let rec print_field stat f =
- 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);
- print "(%s) : %s" (s_kind f.cf_kind) (s_type f.cf_type);
- (match f.cf_expr with
- | None -> ()
- | Some e -> print "\n\n\t = %s" (s_expr s_type e));
- print ";\n\n";
- List.iter (fun f -> print_field stat f) f.cf_overloads
- in
- 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);
- (match c.cl_super with None -> () | Some (c,pl) -> print " extends %s" (s_type (TInst (c,pl))));
- List.iter (fun (c,pl) -> print " implements %s" (s_type (TInst (c,pl)))) c.cl_implements;
- (match c.cl_dynamic with None -> () | Some t -> print " implements Dynamic<%s>" (s_type t));
- (match c.cl_array_access with None -> () | Some t -> print " implements ArrayAccess<%s>" (s_type t));
- print "{\n";
- (match c.cl_constructor with
- | None -> ()
- | Some f -> print_field false f);
- List.iter (print_field false) c.cl_ordered_fields;
- List.iter (print_field true) c.cl_ordered_statics;
- print "}";
- | Type.TEnumDecl e ->
- 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);
- List.iter (fun n ->
- let f = PMap.find n e.e_constrs in
- print "\t%s : %s;\n" f.ef_name (s_type f.ef_type);
- ) e.e_names;
- print "}"
- | Type.TTypeDecl t ->
- 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);
- | Type.TAbstractDecl a ->
- print "%sabstract %s%s {}" (if a.a_private then "private " else "") (s_type_path path) (params a.a_types);
- );
- close();
- ) com.types
- let dump_dependencies com =
- let buf,close = create_dumpfile [] ["dump";Common.platform_name com.platform;".dependencies"] in
- let print fmt = Printf.kprintf (fun s -> Buffer.add_string buf s) fmt in
- let dep = Hashtbl.create 0 in
- List.iter (fun m ->
- print "%s:\n" m.m_extra.m_file;
- PMap.iter (fun _ m2 ->
- print "\t%s\n" (m2.m_extra.m_file);
- let l = try Hashtbl.find dep m2.m_extra.m_file with Not_found -> [] in
- Hashtbl.replace dep m2.m_extra.m_file (m :: l)
- ) m.m_extra.m_deps;
- ) com.Common.modules;
- close();
- let buf,close = create_dumpfile [] ["dump";Common.platform_name com.platform;".dependants"] in
- let print fmt = Printf.kprintf (fun s -> Buffer.add_string buf s) fmt in
- Hashtbl.iter (fun n ml ->
- print "%s:\n" n;
- List.iter (fun m ->
- print "\t%s\n" (m.m_extra.m_file);
- ) ml;
- ) dep;
- close()
- (*
- Build a default safe-cast expression :
- { var $t = <e>; if( Std.is($t,<t>) ) $t else throw "Class cast error"; }
- *)
- let default_cast ?(vtmp="$t") com e texpr t p =
- let api = com.basic in
- let mk_texpr = function
- | TClassDecl c -> TAnon { a_fields = PMap.empty; a_status = ref (Statics c) }
- | TEnumDecl e -> TAnon { a_fields = PMap.empty; a_status = ref (EnumStatics e) }
- | TAbstractDecl a -> TAnon { a_fields = PMap.empty; a_status = ref (AbstractStatics a) }
- | TTypeDecl _ -> assert false
- in
- let vtmp = alloc_var vtmp e.etype in
- let var = mk (TVars [vtmp,Some e]) api.tvoid p in
- let vexpr = mk (TLocal vtmp) e.etype p in
- let texpr = mk (TTypeExpr texpr) (mk_texpr texpr) p in
- let std = (try List.find (fun t -> t_path t = ([],"Std")) com.types with Not_found -> assert false) in
- let fis = (try
- let c = (match std with TClassDecl c -> c | _ -> assert false) in
- FStatic (c, PMap.find "is" c.cl_statics)
- with Not_found ->
- assert false
- ) in
- let std = mk (TTypeExpr std) (mk_texpr std) p in
- let is = mk (TField (std,fis)) (tfun [t_dynamic;t_dynamic] api.tbool) p in
- let is = mk (TCall (is,[vexpr;texpr])) api.tbool p in
- let exc = mk (TThrow (mk (TConst (TString "Class cast error")) api.tstring p)) t p in
- let check = mk (TIf (mk_parent is,mk (TCast (vexpr,None)) t p,Some exc)) t p in
- mk (TBlock [var;check;vexpr]) t p
- (** Overload resolution **)
- module Overloads =
- struct
- let rec simplify_t t = match t with
- | TInst _ | TEnum _ | TAbstract({ a_impl = None }, _) ->
- t
- | TAbstract(a,tl) -> simplify_t (Abstract.get_underlying_type a tl)
- | TType(({ t_path = [],"Null" } as t), [t2]) -> (match simplify_t t2 with
- | (TAbstract({ a_impl = None }, _) | TEnum _ as t2) -> TType(t, [simplify_t t2])
- | t2 -> t2)
- | TType(t, tl) ->
- simplify_t (apply_params t.t_types tl t.t_type)
- | TMono r -> (match !r with
- | Some t -> simplify_t t
- | None -> t_dynamic)
- | TAnon _ -> t_dynamic
- | TDynamic _ -> t
- | TLazy f -> simplify_t (!f())
- | TFun _ -> t
- (* rate type parameters *)
- let rate_tp tlfun tlarg =
- let acc = ref 0 in
- List.iter2 (fun f a -> if not (type_iseq f a) then incr acc) tlfun tlarg;
- !acc
- let rec rate_conv cacc tfun targ =
- match simplify_t tfun, simplify_t targ with
- | TInst({ cl_interface = true } as cf, tlf), TInst(ca, tla) ->
- (* breadth-first *)
- let stack = ref [0,ca,tla] in
- let cur = ref (0, ca,tla) in
- let rec loop () =
- match !stack with
- | [] -> (let acc, ca, tla = !cur in match ca.cl_super with
- | None -> raise Not_found
- | Some (sup,tls) ->
- cur := (acc+1,sup,List.map (apply_params ca.cl_types tla) tls);
- stack := [!cur];
- loop())
- | (acc,ca,tla) :: _ when ca == cf ->
- acc,tla
- | (acc,ca,tla) :: s ->
- stack := s @ List.map (fun (c,tl) -> (acc+1,c,List.map (apply_params ca.cl_types tla) tl)) ca.cl_implements;
- loop()
- in
- let acc, tla = loop() in
- (cacc + acc, rate_tp tlf tla)
- | TInst(cf,tlf), TInst(ca,tla) ->
- let rec loop acc ca tla =
- if cf == ca then
- acc, tla
- else match ca.cl_super with
- | None -> raise Not_found
- | Some(sup,stl) ->
- loop (acc+1) sup (List.map (apply_params ca.cl_types tla) stl)
- in
- let acc, tla = loop 0 ca tla in
- (cacc + acc, rate_tp tlf tla)
- | TEnum(ef,tlf), TEnum(ea, tla) ->
- if ef != ea then raise Not_found;
- (cacc, rate_tp tlf tla)
- | TDynamic _, TDynamic _ ->
- (cacc, 0)
- | TDynamic _, _ ->
- (max_int, 0) (* a function with dynamic will always be worst of all *)
- | TAbstract({ a_impl = None }, _), TDynamic _ ->
- (cacc + 2, 0) (* a dynamic to a basic type will have an "unboxing" penalty *)
- | _, TDynamic _ ->
- (cacc + 1, 0)
- | TAbstract(af,tlf), TAbstract(aa,tla) ->
- (if af == aa then
- (cacc, rate_tp tlf tla)
- else
- let ret = ref None in
- if List.exists (fun (t,_) -> try
- ret := Some (rate_conv (cacc+1) (apply_params af.a_types tlf t) targ);
- true
- with | Not_found ->
- false
- ) af.a_from then
- Option.get !ret
- else
- if List.exists (fun (t,_) -> try
- ret := Some (rate_conv (cacc+1) tfun (apply_params aa.a_types tla t));
- true
- with | Not_found ->
- false
- ) aa.a_to then
- Option.get !ret
- else
- raise Not_found)
- | TType({ t_path = [], "Null" }, [tf]), TType({ t_path = [], "Null" }, [ta]) ->
- rate_conv (cacc+0) tf ta
- | TType({ t_path = [], "Null" }, [tf]), ta ->
- rate_conv (cacc+1) tf ta
- | tf, TType({ t_path = [], "Null" }, [ta]) ->
- rate_conv (cacc+1) tf ta
- | TFun _, TFun _ -> (* unify will make sure they are compatible *)
- cacc,0
- | tfun,targ ->
- raise Not_found
- let is_best arg1 arg2 =
- (List.for_all2 (fun v1 v2 ->
- v1 <= v2)
- arg1 arg2) && (List.exists2 (fun v1 v2 ->
- v1 < v2)
- arg1 arg2)
- let rec rm_duplicates acc ret = match ret with
- | [] -> acc
- | ( el, t ) :: ret when List.exists (fun (_,t2) -> type_iseq t t2) acc ->
- rm_duplicates acc ret
- | r :: ret ->
- rm_duplicates (r :: acc) ret
- let s_options rated =
- String.concat ",\n" (List.map (fun ((_,t),rate) ->
- "( " ^ (String.concat "," (List.map (fun (i,i2) -> string_of_int i ^ ":" ^ string_of_int i2) rate)) ^ " ) => " ^ (s_type (print_context()) t)
- ) rated)
- let count_optionals elist =
- List.fold_left (fun acc (_,is_optional) -> if is_optional then acc + 1 else acc) 0 elist
- let rec fewer_optionals acc compatible = match acc, compatible with
- | _, [] -> acc
- | [], c :: comp -> fewer_optionals [c] comp
- | (elist_acc, _) :: _, ((elist, _) as cur) :: comp ->
- let acc_opt = count_optionals elist_acc in
- let comp_opt = count_optionals elist in
- if acc_opt = comp_opt then
- fewer_optionals (cur :: acc) comp
- else if acc_opt < comp_opt then
- fewer_optionals acc comp
- else
- fewer_optionals [cur] comp
- let reduce_compatible compatible = match fewer_optionals [] (rm_duplicates [] compatible) with
- | [] -> [] | [v] -> [v]
- | compatible ->
- (* convert compatible into ( rate * compatible_type ) list *)
- let rec mk_rate acc elist args = match elist, args with
- | [], [] -> acc
- | (_,true) :: elist, _ :: args -> mk_rate acc elist args
- | (e,false) :: elist, (n,o,t) :: args ->
- mk_rate (rate_conv 0 t e.etype :: acc) elist args
- | _ -> assert false
- in
- let rated = ref [] in
- List.iter (function
- | (elist,TFun(args,ret)) -> (try
- rated := ( (elist,TFun(args,ret)), mk_rate [] elist args ) :: !rated
- with | Not_found -> ())
- | _ -> assert false
- ) compatible;
- let rec loop best rem = match best, rem with
- | _, [] -> best
- | [], r1 :: rem -> loop [r1] rem
- | (bover, bargs) :: b1, (rover, rargs) :: rem ->
- if is_best bargs rargs then
- loop best rem
- else if is_best rargs bargs then
- loop (loop b1 [rover,rargs]) rem
- else (* equally specific *)
- loop ( (rover,rargs) :: best ) rem
- in
- List.map fst (loop [] !rated)
- end;;
|