Browse Source

changed Ast.class_field format
added metadata patches

Nicolas Cannasse 14 năm trước cách đây
mục cha
commit
51b3f13d52
10 tập tin đã thay đổi với 318 bổ sung176 xóa
  1. 15 6
      ast.ml
  2. 15 15
      codegen.ml
  3. 52 27
      genswf.ml
  4. 59 10
      genxml.ml
  5. 12 3
      interp.ml
  6. 17 8
      parser.ml
  7. 15 0
      std/haxe/macro/Compiler.hx
  8. 7 1
      typecore.ml
  9. 71 79
      typeload.ml
  10. 55 27
      typer.ml

+ 15 - 6
ast.ml

@@ -209,10 +209,19 @@ type access =
 	| ADynamic
 	| AInline
 
-type class_field =
-	| FVar of string * documentation * metadata * access list * complex_type option * expr option
-	| FFun of string * documentation * metadata * access list * type_param list * func
-	| FProp of string * documentation * metadata * access list * string * string * complex_type
+type class_field_kind =
+	| FVar of complex_type option * expr option
+	| FFun of type_param list * func
+	| FProp of string * string * complex_type
+
+type class_field = {
+	cff_name : string;
+	cff_doc : documentation;
+	cff_pos : pos;
+	mutable cff_meta : metadata;
+	mutable cff_access : access list;
+	mutable cff_kind : class_field_kind;
+}
 
 type enum_flag =
 	| EPrivate
@@ -237,7 +246,7 @@ type ('a,'b) definition = {
 }
 
 type type_def =
-	| EClass of (class_flag, (class_field * pos) list) definition
+	| EClass of (class_flag, class_field list) definition
 	| EEnum of (enum_flag, enum_constructor list) definition
 	| ETypedef of (enum_flag, complex_type) definition
 	| EImport of type_path
@@ -270,7 +279,7 @@ let punion p p2 =
 
 let s_type_path (p,s) = match p with [] -> s | _ -> String.concat "." p ^ "." ^ s
 
-let parse_path s = 
+let parse_path s =
 	match List.rev (ExtString.String.nsplit s ".") with
 	| [] -> failwith "Invalid empty path"
 	| x :: l -> List.rev l, x

+ 15 - 15
codegen.ml

@@ -88,25 +88,25 @@ let extend_remoting ctx c t p async prot =
 	let decls = (try Typeload.parse_module ctx path p with e -> ctx.com.package_rules <- rules; raise e) in
 	ctx.com.package_rules <- rules;
 	let base_fields = [
-		(FVar ("__cnx",None,[],[],Some (CTPath { tpackage = ["haxe";"remoting"]; tname = if async then "AsyncConnection" else "Connection"; tparams = []; tsub = None }),None),p);
-		(FFun ("new",None,[],[APublic],[],{ f_args = ["c",false,None,None]; f_type = None; f_expr = (EBinop (OpAssign,(EConst (Ident "__cnx"),p),(EConst (Ident "c"),p)),p) }),p);
+		{ 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 = (EBinop (OpAssign,(EConst (Ident "__cnx"),p),(EConst (Ident "c"),p)),p) }) };
 	] in
 	let tvoid = CTPath { tpackage = []; tname = "Void"; tparams = []; tsub = None } in
-	let build_field is_public acc (f,p) =
-		match f with
-		| FFun ("new",_,_,_,_,_) ->
+	let build_field is_public acc f =
+		if f.cff_name = "new" then
 			acc
-		| FFun (name,doc,meta,acl,pl,f) when (is_public || List.mem APublic acl) && not (List.mem AStatic acl) ->
-			if List.exists (fun (_,_,t,_) -> t = None) f.f_args then error ("Field " ^ name ^ " type is not complete and cannot be used by RemotingProxy") p;
-			let eargs = [EArrayDecl (List.map (fun (a,_,_,_) -> (EConst (Ident a),p)) f.f_args),p] in
-			let ftype = (match f.f_type with Some (CTPath { tpackage = []; tname = "Void" }) -> None | _ -> f.f_type) in
+		else match f.cff_kind with
+		| FFun (pl,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 -> f.f_args @ ["__callb",true,Some (CTFunction ([tret],tvoid)),None], eargs @ [EConst (Ident "__callb"),p]
-				| _ -> f.f_args, eargs @ [EConst (Ident "null"),p]
+				| 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
-				f.f_args, eargs
+				fd.f_args, eargs
 			in
-			let id = (EConst (String name), p) 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 (
@@ -115,12 +115,12 @@ let extend_remoting ctx c t p async prot =
 				,p),eargs),p
 			in
 			let expr = if async || ftype = None then expr else (EReturn (Some expr),p) in
-			let f = {
+			let fd = {
 				f_args = fargs;
 				f_type = if async then None else ftype;
 				f_expr = (EBlock [expr],p);
 			} in
-			(FFun (name,None,[],[APublic],pl,f),p) :: acc
+			{ cff_name = f.cff_name; cff_pos = p; cff_doc = None; cff_meta = []; cff_access = [APublic]; cff_kind = FFun (pl,fd) } :: acc
 		| _ -> acc
 	in
 	let decls = List.map (fun d ->

+ 52 - 27
genswf.ml

@@ -208,9 +208,9 @@ let build_class com c file =
 		| None | Some (HMPath ([],"Object")) -> flags
 		| Some s -> HExtends (make_tpath s) :: flags
 	) in
-	let flags = List.map (fun i -> 
+	let flags = List.map (fun i ->
 		let i = (match i with
-			| HMMultiName (Some id,ns) -> 
+			| HMMultiName (Some id,ns) ->
 				let rec loop = function
 					| [] -> assert false
 					| HNPublic (Some ns) :: _ -> HMPath (ExtString.String.nsplit ns ".",id)
@@ -227,6 +227,10 @@ let build_class com c file =
 	let getters = Hashtbl.create 0 in
 	let setters = Hashtbl.create 0 in
 	let as3_native = Common.defined com "as3_native" in
+	let is_xml = (match path.tpackage, path.tname with
+		| ["flash";"xml"], ("XML" | "XMLList") -> true
+		| _ -> false
+	) in
 	let make_field stat acc f =
 		let meta = ref [] in
 		let flags = (match f.hlf_name with
@@ -235,7 +239,7 @@ let build_class com c file =
 				(match ns with
 				| HNPrivate _ | HNNamespace "http://www.adobe.com/2006/flex/mx/internal" -> []
 				| HNNamespace ns ->
-					meta := (":ns",[String ns]) :: !meta;
+					if not (c.hlc_interface || is_xml) then meta := (":ns",[String ns]) :: !meta;
 					[APublic]
 				| HNExplicit _ | HNInternal _ | HNPublic _ ->
 					[APublic]
@@ -246,18 +250,25 @@ let build_class com c file =
 		) in
 		if flags = [] then acc else
 		let flags = if stat then AStatic :: flags else flags in
+		let name = (make_tpath f.hlf_name).tname in
 		let mk_meta() =
 			List.map (fun (s,cl) -> s, List.map (fun c -> EConst c,pos) cl) (!meta)
 		in
-		let name = (make_tpath f.hlf_name).tname in
+		let cf = {
+			cff_name = name;
+			cff_doc = None;
+			cff_pos = pos;
+			cff_meta = mk_meta();
+			cff_access = flags;
+			cff_kind = FVar (None,None);
+		} in
 		match f.hlf_kind with
 		| HFVar v ->
-			let v = if v.hlv_const then
-				FProp (name,None,mk_meta(),flags,"default","never",make_type v.hlv_type)
+			if v.hlv_const then
+				cf.cff_kind <- FProp ("default","never",make_type v.hlv_type)
 			else
-				FVar (name,None,mk_meta(),flags,Some (make_type v.hlv_type),None)
-			in
-			v :: acc
+				cf.cff_kind <- FVar (Some (make_type v.hlv_type),None);
+			cf :: acc
 		| HFMethod m when not m.hlm_override ->
 			(match m.hlm_kind with
 			| MK3Normal ->
@@ -279,29 +290,29 @@ let build_class com c file =
 							with
 								_ -> None
 					) in
-					incr p;					
+					incr p;
 					let t = make_type at in
 					let def_val = match opt_val with
 						| None -> None
-						| Some v ->							
+						| Some v ->
 							let v = (match v with
 							| HVNone | HVNull | HVNamespace _ | HVString _ -> None
-							| HVBool b ->								
+							| HVBool b ->
 								Some (Ident (if b then "true" else "false"))
-							| HVInt i | HVUInt i -> 
+							| HVInt i | HVUInt i ->
 								Some (Int (Int32.to_string i))
-							| HVFloat f -> 
+							| HVFloat f ->
 								Some (Float (string_of_float f))
 							) in
 							match v with
 							| None -> None
-							| Some v -> 
+							| Some v ->
 								meta := (":defparam",[String aname;v]) :: !meta;
 								Some (EConst v,pos)
 					in
-					(aname,opt_val <> None,Some t,def_val)					
+					(aname,opt_val <> None,Some t,def_val)
 				) t.hlmt_args in
-				let args = if t.hlmt_var_args then 
+				let args = if t.hlmt_var_args then
 					args @ List.map (fun _ -> incr pn; ("p" ^ string_of_int !pn,true,Some (make_type None),None)) [1;2;3;4;5]
 				else args in
 				let f = {
@@ -309,7 +320,9 @@ let build_class com c file =
 					f_type = Some (make_type t.hlmt_ret);
 					f_expr = (EBlock [],pos)
 				} in
-				FFun (name,None,mk_meta(),flags,[],f) :: acc
+				cf.cff_meta <- mk_meta();
+				cf.cff_kind <- FFun ([],f);
+				cf :: acc
 			| MK3Getter ->
 				Hashtbl.add getters (name,stat) m.hlm_type.hlmt_ret;
 				acc
@@ -341,7 +354,14 @@ let build_class com c file =
 		) in
 		let flags = [APublic] in
 		let flags = if stat then AStatic :: flags else flags in
-		FProp (name,None,[],flags,(if get then "default" else "never"),(if set then "default" else "never"),make_type t)
+		{
+			cff_name = name;
+			cff_pos = pos;
+			cff_doc = None;
+			cff_access = flags;
+			cff_meta = [];
+			cff_kind = FProp ((if get then "default" else "never"),(if set then "default" else "never"),make_type t);
+		}
 	in
 	let fields = Hashtbl.fold (fun (name,stat) t acc ->
 		make_get_set name stat (Some t) (try Some (Hashtbl.find setters (name,stat)) with Not_found -> None) :: acc
@@ -359,14 +379,19 @@ let build_class com c file =
 		let rec loop = function
 			| [] -> []
 			| f :: l ->
-				match f with
-				| FVar (name,doc,_,access,Some (CTPath { tpackage = []; tname = "String" | "Int" | "UInt" }),None) when List.mem AStatic access -> (name,doc,[],[],pos) :: loop l
-				| FFun ("new",_,_,_,_,{ f_args = [] }) -> loop l
+				match f.cff_kind with
+				| FVar (Some (CTPath { tpackage = []; tname = "String" | "Int" | "UInt" }),None) when List.mem AStatic f.cff_access -> (f.cff_name,None,[],[],pos) :: loop l
+				| FFun (_,{ f_args = [] }) when f.cff_name = "new" -> loop l
 				| _ -> raise Exit
 		in
-		if fields = [] then raise Exit;
-		List.iter (function HExtends _ | HImplements _ -> raise Exit | _ -> ()) flags;			
+		(match path.tpackage, path.tname with
+		| ["flash";"net"], "URLRequestMethod"
+		| ["flash";"filters"], "BitmapFilterQuality"
+		| ["flash";"display"], ("BitmapDataChannel" | "GraphicsPathCommand")  -> raise Exit
+		| _ -> ());
+		List.iter (function HExtends _ | HImplements _ -> raise Exit | _ -> ()) flags;
 		let constr = loop fields in
+		if constr = [] then raise Exit;
 		let enum_data = {
 			d_name = path.tname;
 			d_doc = None;
@@ -381,9 +406,9 @@ let build_class com c file =
 		d_name = path.tname;
 		d_doc = None;
 		d_params = [];
-		d_meta = [];
+		d_meta = if c.hlc_final && List.exists (fun f -> f.cff_name <> "new" && not (List.mem AStatic f.cff_access)) fields then [":final",[]] else [];
 		d_flags = flags;
-		d_data = List.map (fun f -> f, pos) fields;
+		d_data = fields;
 	} in
 	(path.tpackage, [(EClass class_data,pos)])
 
@@ -811,7 +836,7 @@ let merge com file priority (h1,tags1) (h2,tags2) =
 			let el = List.filter (fun e ->
 				let path = parse_path e.exp_name in
 				let b = List.exists (fun t -> t_path t = path) com.types in
-				if not b && fst path = [] then List.iter (fun t -> 
+				if not b && fst path = [] then List.iter (fun t ->
 					if snd (t_path t) = snd path then error ("Linkage name '" ^ snd path ^ "' in '" ^ file ^  "' should be '" ^ s_type_path (t_path t) ^"'") (t_pos t);
 				) com.types;
 				b

+ 59 - 10
genxml.ml

@@ -210,6 +210,10 @@ let generate_type com t =
 	let base_path = "hxclasses" in
 	let pack , name = t_path t in
 	create_dir "." (base_path :: pack);
+	match pack, name with
+	| ["flash";"filters"], "BitmapFilterQuality"
+	| ["flash";"display"], ("BitmapDataChannel" | "GraphicsPathCommand")  -> ()
+	| _ ->
 	let f = open_out_bin (base_path ^ "/" ^ (match pack with [] -> "" | l -> String.concat "/" l ^ "/") ^ name ^ ".hx") in
 	let ch = IO.output_channel f in
 	let p fmt = IO.printf ch fmt in
@@ -235,6 +239,8 @@ let generate_type com t =
 			(match !r with
 			| None -> "Unknown"
 			| Some t -> stype t)
+		| TInst ({ cl_kind = KTypeParameter } as c,tl) ->
+			path ([],snd c.cl_path) tl
 		| TInst (c,tl) ->
 			path c.cl_path tl
 		| TEnum (e,tl) ->
@@ -250,7 +256,7 @@ let generate_type com t =
 			if t == t2 then "Dynamic" else "Dynamic<" ^ stype t2 ^ ">"
 		| TFun (args,ret) ->
 			String.concat " -> " (List.map (fun (_,_,t) -> ftype t) args) ^ " -> " ^ ftype ret
-	and ftype t = 
+	and ftype t =
 		match t with
 		| TMono r ->
 			(match !r with
@@ -263,6 +269,11 @@ let generate_type com t =
 		| _ ->
 			stype t
 	in
+	let sexpr (e,_) =
+		match e with
+		| EConst c -> s_constant c
+		| _ -> "'???'"
+	in
 	let sparam (n,v,t) =
 		match v with
 		| None ->
@@ -272,41 +283,77 @@ let generate_type com t =
 		| Some v ->
 			n ^ " : " ^ stype t ^ " = " ^ (s_constant v)
 	in
+	let print_meta ml =
+		List.iter (fun (m,pl) ->
+			match m with
+			| ":defparam" -> ()
+			| _ ->
+			match pl with
+			| [] -> p "@%s " m
+			| l -> p "@%s(%s) " m (String.concat "," (List.map sexpr pl))
+		) ml
+	in
+	let access a =
+		match a, pack with
+		| AccNever, "flash" :: _ -> "null"
+		| _ -> s_access a
+	in
 	let print_field stat f =
 		p "\t";
+		print_meta f.cf_meta;
 		if stat then p "static ";
 		(match f.cf_kind with
 		| Var v ->
 			p "var %s" f.cf_name;
-			if v.v_read <> AccNormal || v.v_write <> AccNormal then p "(%s,%s)" (s_access v.v_read) (s_access (if v.v_write = AccNever && (match pack with "flash" :: _ -> true | _ -> false) then AccNo else v.v_write));
+			if v.v_read <> AccNormal || v.v_write <> AccNormal then p "(%s,%s)" (access v.v_read) (access v.v_write);
 			p " : %s" (stype f.cf_type);
 		| Method m ->
 			let params, ret = (match follow f.cf_type with
-				| TFun (args,ret) -> 
+				| TFun (args,ret) ->
 					List.map (fun (a,o,t) ->
 						let rec loop = function
 							| [] -> Ident "null"
-							| (":defparam",[(EConst (String p),_);(EConst v,_)]) :: _ when p = a -> v
+							| (":defparam",[(EConst (String p),_);(EConst v,_)]) :: _ when p = a ->
+								(match v with
+								| Float "4294967295." -> Int "0xFFFFFFFF"
+								| Int "16777215" -> Int "0xFFFFFF"
+								| _ -> v)
 							| _ :: l -> loop l
 						in
 						a,(if o then Some (loop f.cf_meta) else None ),t
 					) args, ret
-				| _ -> 
+				| _ ->
 					assert false
-			) in				
+			) in
 			p "function %s(%s) : %s" f.cf_name (String.concat ", " (List.map sparam params)) (stype ret);
 		);
 		p ";\n"
 	in
 	(match t with
 	| TClassDecl c ->
+		print_meta c.cl_meta;
 		p "extern %s %s" (if c.cl_interface then "interface" else "class") (stype (TInst (c,List.map snd c.cl_types)));
 		let ext = (match c.cl_super with
 		| None -> []
 		| Some (c,pl) -> [" extends " ^ stype (TInst (c,pl))]
 		) in
 		let ext = List.fold_left (fun acc (i,pl) -> (" implements " ^ stype (TInst (i,pl))) :: acc) ext c.cl_implements in
-		let ext = (match c.cl_dynamic with None -> ext | Some t -> (" implements " ^ stype t) :: ext) in
+		let ext = (match c.cl_dynamic with
+			| None -> ext
+			| Some t ->
+				(match c.cl_path with
+				| ["flash";"display"],"MovieClip"
+				| ["flash";"errors"], "Error" -> (" #if !flash_strict implements " ^ stype t ^ " #end") :: ext
+				| ["flash";"errors"], _ -> ext
+				| _ -> (" implements " ^ stype t) :: ext)
+		) in
+		let ext = (match c.cl_path with
+			| ["flash";"utils"], "ByteArray" -> " implements ArrayAccess<Int>" :: ext
+			| ["flash";"utils"], "Dictionnary" -> [" implements ArrayAccess<Dynamic>"]
+			| ["flash";"xml"], "XML" -> [" implements Dynamic<XMLList>"]
+			| ["flash";"xml"], "XMLList" -> [" implements ArrayAccess<XML>"]
+			| _ -> ext
+		) in
 		p "%s" (String.concat "," (List.rev ext));
 		p " {\n";
 		let sort l =
@@ -324,8 +371,9 @@ let generate_type com t =
 		List.iter (print_field true) (sort c.cl_ordered_statics);
 		p "}\n";
 	| TEnumDecl e ->
+		print_meta e.e_meta;
 		p "extern enum %s {\n" (stype (TEnum(e,List.map snd e.e_types)));
-		let sort l = 
+		let sort l =
 			let a = Array.of_list l in
 			Array.sort compare a;
 			Array.to_list a
@@ -340,12 +388,13 @@ let generate_type com t =
 		) (sort e.e_names);
 		p "}\n"
 	| TTypeDecl t ->
+		print_meta t.t_meta;
 		p "extern typedef %s = " (stype (TType (t,List.map snd t.t_types)));
 		p "%s" (stype t.t_type);
 		p "\n";
 	);
 	IO.close_out ch
-	
+
 let generate_hx com =
 	List.iter (generate_type com) com.types
-	
+

+ 12 - 3
interp.ml

@@ -90,6 +90,7 @@ type extern_api = {
 	parse_string : string -> Ast.pos -> Ast.expr;
 	typeof : Ast.expr -> Type.t;
 	type_patch : string -> string -> bool -> string option -> unit;
+	meta_patch : string -> string -> string option -> bool -> unit;
 }
 
 type context = {
@@ -486,7 +487,7 @@ let builtins =
 		"hcount", Fun1 (fun h -> VInt (Hashtbl.length (vhash h)));
 		"hsize", Fun1 (fun h -> VInt (Hashtbl.length (vhash h)));
 	(* misc *)
-		"print", FunVar (fun vl -> List.iter (fun v -> 
+		"print", FunVar (fun vl -> List.iter (fun v ->
 			let ctx = get_ctx() in
 			ctx.curapi.print (ctx.do_string v)
 		) vl; VNull);
@@ -1597,6 +1598,14 @@ let macro_lib =
 			| _ -> error());
 			VNull
 		);
+		"meta_patch", Fun4 (fun m t f s ->
+			let p = (get_ctx()).curapi.meta_patch in
+			(match m, t, f, s with
+			| VString m, VString t, VString f, VBool s -> p m t (Some f) s
+			| VString m, VString t, VNull, VBool s -> p m t None s
+			| _ -> error());
+			VNull
+		);
 	]
 
 (* ---------------------------------------------------------------------- *)
@@ -2752,12 +2761,12 @@ let encode_pmap convert m =
 	let h = Hashtbl.create 0 in
 	PMap.iter (fun k v -> Hashtbl.add h (VString k) (convert v)) m;
 	enc_hash h
-	
+
 let encode_pmap_array convert m =
 	let l = ref [] in
 	PMap.iter (fun _ v -> l := !l @ [(convert v)]) m;
 	enc_array !l
-	
+
 let encode_array convert l =
 	enc_array (List.map convert l)
 

+ 17 - 8
parser.ml

@@ -248,7 +248,7 @@ and parse_common_flags = parser
 	| [< >] -> []
 
 and parse_meta = parser
-	| [< '(At,_); name = meta_name; s >] ->		
+	| [< '(At,_); name = meta_name; s >] ->
 		(match s with parser
 		| [< '(POpen,_); params = psep Comma expr; '(PClose,_); s >] -> (name,params) :: parse_meta s
 		| [< >] -> (name,[]) :: parse_meta s)
@@ -360,19 +360,19 @@ and parse_enum_param = parser
 and parse_class_field s =
 	doc := None;
 	match s with parser
-	| [< meta = parse_meta; l = parse_cf_rights true []; doc = get_doc; s >] ->
-		match s with parser
+	| [< meta = parse_meta; al = parse_cf_rights true []; doc = get_doc; s >] ->
+		let name, pos, k = (match s with parser
 		| [< '(Kwd Var,p1); name = any_ident; s >] ->
 			(match s with parser
 			| [< '(POpen,_); i1 = property_ident; '(Comma,_); i2 = property_ident; '(PClose,_); '(DblDot,_); t = parse_complex_type; p2 = semicolon >] ->
-				(FProp (name,doc,meta,l,i1,i2,t),punion p1 p2)
+				name, punion p1 p2, FProp (i1,i2,t)
 			| [< t = parse_type_opt; s >] ->
 				let e , p2 = (match s with parser
-				| [< '(Binop OpAssign,_) when List.mem AStatic l; e = toplevel_expr; p2 = semicolon >] -> Some e , p2
+				| [< '(Binop OpAssign,_) when List.mem AStatic al; e = toplevel_expr; p2 = semicolon >] -> Some e , p2
 				| [< '(Semicolon,p2) >] -> None , p2
 				| [< >] -> serror()
 				) in
-				(FVar (name,doc,meta,l,t,e),punion p1 p2))
+				name, punion p1 p2, FVar (t,e))
 		| [< '(Kwd Function,p1); name = parse_fun_name; pl = parse_constraint_params; '(POpen,_); al = psep Comma parse_fun_param; '(PClose,_); t = parse_type_opt; s >] ->
 			let e = (match s with parser
 				| [< e = toplevel_expr >] -> e
@@ -384,9 +384,18 @@ and parse_class_field s =
 				f_type = t;
 				f_expr = e;
 			} in
-			(FFun (name,doc,meta,l,pl,f),punion p1 (pos e))
+			name, punion p1 (pos e), FFun (pl,f)
 		| [< >] ->
-			if l = [] then raise Stream.Failure else serror()
+			if al = [] then raise Stream.Failure else serror()
+		) in
+		{
+			cff_name = name;
+			cff_doc = doc;
+			cff_meta = meta;
+			cff_access = al;
+			cff_pos = pos;
+			cff_kind = k;
+		}
 
 and parse_signature_field flag = parser
 	| [< '(Kwd Var,p1); name = any_ident; s >] ->

+ 15 - 0
std/haxe/macro/Compiler.hx

@@ -40,6 +40,10 @@ class Compiler {
 		untyped load("type_patch",4)(className.__s,field.__s,isStatic == true,type.__s);
 	}
 
+	public static function addMetadata( meta : String, className : String, ?field : String, ?isStatic : Bool ) {
+		untyped load("meta_patch",4)(meta.__s,className.__s,(field == null)?null:field.__s,isStatic == true);
+	}
+
 	/**
 		Evaluate the type a given expression would have in the context of the current macro call.
 	**/
@@ -60,6 +64,17 @@ class Compiler {
 					removeField(p.join("."),field,isStatic);
 					continue;
 				}
+				if( r.charAt(0) == "@" ) {
+					var rp = r.split(" ");
+					var type = rp.pop();
+					var isStatic = rp[rp.length - 1] == "static";
+					if( isStatic ) rp.pop();
+					var meta = rp.join(" ");
+					var p = type.split(".");
+					var field = if( p.length > 1 && p[p.length-2].charAt(0) >= "a" ) null else p.pop();
+					addMetadata(meta,p.join("."),field,isStatic);
+					continue;
+				}
 				var rp = r.split(" : ");
 				if( rp.length > 1 ) {
 					r = rp.shift();

+ 7 - 1
typecore.ml

@@ -19,6 +19,12 @@
 open Common
 open Type
 
+type type_patch = {
+	mutable tp_type : Ast.complex_type option;
+	mutable tp_remove : bool;
+	mutable tp_meta : Ast.metadata;
+}
+
 type typer_globals = {
 	types_module : (path, path) Hashtbl.t;
 	modules : (path , module_def) Hashtbl.t;
@@ -29,7 +35,7 @@ type typer_globals = {
 	mutable macros : ((unit -> unit) * typer) option;
 	mutable std : module_def;
 	mutable hook_generate : (unit -> unit) list;
-	type_patches : (path, (string * bool, Ast.complex_type option) Hashtbl.t) Hashtbl.t;
+	type_patches : (path, (string * bool, type_patch) Hashtbl.t * type_patch) Hashtbl.t;
 	(* api *)
 	do_inherit : typer -> Type.tclass -> Ast.pos -> Ast.class_flag -> bool;
 	do_create : Common.context -> typer;

+ 71 - 79
typeload.ml

@@ -529,9 +529,6 @@ let type_function ctx args ret static constr f p =
 	ctx.opened <- old_opened;
 	e , fargs
 
-(* nothing *)
-let type_meta ctx meta = meta
-
 let init_core_api ctx c =
 	let ctx2 = (match ctx.g.core_api with
 		| None ->
@@ -590,38 +587,33 @@ let patch_class ctx c fields =
 	let h = (try Some (Hashtbl.find ctx.g.type_patches c.cl_path) with Not_found -> None) in
 	match h with
 	| None -> fields
-	| Some h ->
+	| Some (h,hcl) ->
+		c.cl_meta <- c.cl_meta @ hcl.tp_meta;
 		let rec loop acc = function
 			| [] -> List.rev acc
-			| (f,p) :: l ->
-				let acc = (try
-					match f with
-					| FVar (name,doc,meta,access,t,e) ->
-						(match Hashtbl.find h (name,List.mem AStatic access) with
-						| None -> acc
-						| Some t -> (FVar (name,doc,meta,access,Some t,e),p) :: acc)
-					| FProp (name,doc,meta,access,get,set,t) ->
-						(match Hashtbl.find h (name,List.mem AStatic access) with
-						| None -> acc
-						| Some t -> (FProp (name,doc,meta,access,get,set,t),p) :: acc)
-					| FFun (name,doc,meta,access,pl,f) ->
-						(match Hashtbl.find h (name,List.mem AStatic access) with
-						| None -> acc
-						| Some t -> (FFun (name,doc,meta,access,pl,{ f with f_type = Some t }),p) :: acc)
-				with Not_found ->
-					let f = (match f with
-					| FFun (name,doc,meta,access,params,f) ->
-						let param ((n,opt,t,e) as p) =
-							try
-								n, opt, Hashtbl.find h (("$" ^ n),false), e
-							with Not_found ->
-								p
-						in
-						FFun (name,doc,meta,access,params,{ f with f_args = List.map param f.f_args })
-					| _ -> f) in
-					(f,p) :: acc
-				) in
-				loop acc l
+			| f :: l ->
+				(* patch arguments types *)
+				(match f.cff_kind with
+				| FFun (pl,ff) ->
+					let param ((n,opt,t,e) as p) =
+						try n, opt, (Hashtbl.find h (("$" ^ n),false)).tp_type, e with Not_found -> p
+					in
+					f.cff_kind <- FFun (pl,{ ff with f_args = List.map param ff.f_args })
+				| _ -> ());
+				(* other patches *)
+				match (try Some (Hashtbl.find h (f.cff_name,List.mem AStatic f.cff_access)) with Not_found -> None) with
+				| None -> loop (f :: acc) l
+				| Some { tp_remove = true } -> loop acc l
+				| Some p ->
+					f.cff_meta <- f.cff_meta @ p.tp_meta;
+					(match p.tp_type with
+					| None -> ()
+					| Some t ->
+						f.cff_kind <- match f.cff_kind with
+						| FVar (_,e) -> FVar (Some t,e)
+						| FProp (get,set,_) -> FProp (get,set,t)
+						| FFun (pl,f) -> FFun (pl,{ f with f_type = Some t }));
+					loop (f :: acc) l
 		in
 		List.rev (loop [] fields)
 
@@ -635,7 +627,7 @@ let init_class ctx c p herits fields meta =
 	let is_macro = has_meta ":macro" meta in
 	let fields, herits = if is_macro && not ctx.in_macro then begin
 		c.cl_extern <- true;
-		List.filter (function (FFun (_,_,_,acc,_,_),_) -> List.mem AStatic acc | _ -> false) fields, []
+		List.filter (fun f -> List.mem AStatic f.cff_access) fields, []
 	end else fields, herits in
 	if core_api then delay ctx ((fun() -> init_core_api ctx c));
 	let tthis = TInst (c,List.map snd c.cl_types) in
@@ -680,11 +672,13 @@ let init_class ctx c p herits fields meta =
 		| Some (c,_) ->
 			PMap.exists f c.cl_fields || has_field f c.cl_super || List.exists (fun i -> has_field f (Some i)) c.cl_implements
 	in
-	let loop_cf f p =
-		match f with
-		| FVar (name,doc,meta,access,t,e) ->
-			let stat = List.mem AStatic access in
-			let inline = List.mem AInline access in
+	let loop_cf f =
+		let name = f.cff_name in
+		let p = f.cff_pos in
+		let stat = List.mem AStatic f.cff_access in
+		let inline = List.mem AInline f.cff_access in
+		match f.cff_kind with
+		| FVar (t,e) ->
 			if not stat && has_field name c.cl_super then error ("Redefinition of variable " ^ name ^ " in subclass is not allowed") p;
 			if inline && not stat then error "Inline variable must be static" p;
 			if inline && e = None then error "Inline variable must be initialized" p;
@@ -701,12 +695,12 @@ let init_class ctx c p herits fields meta =
 			) in
 			let cf = {
 				cf_name = name;
-				cf_doc = doc;
-				cf_meta = type_meta ctx meta;
+				cf_doc = f.cff_doc;
+				cf_meta = f.cff_meta;
 				cf_type = t;
 				cf_kind = Var (if inline then { v_read = AccInline ; v_write = AccNever } else { v_read = AccNormal; v_write = AccNormal });
 				cf_expr = None;
-				cf_public = is_public access None;
+				cf_public = is_public f.cff_access None;
 				cf_params = [];
 			} in
 			let delay = (match e with
@@ -722,38 +716,36 @@ let init_class ctx c p herits fields meta =
 					cf.cf_type <- TLazy r;
 					(fun () -> ignore(!r()))
 			) in
-			access, false, cf, delay
-		| FFun (name,doc,meta,access,params,f) ->
+			f, false, cf, delay
+		| FFun (params,fd) ->
 			let params = List.map (fun (n,flags) ->
 				match flags with
 				| [] ->
 					type_type_params ctx ([],name) p (n,[])
 				| _ -> error "This notation is not allowed because it can't be checked" p
 			) params in
-			let stat = List.mem AStatic access in
-			let inline = List.mem AInline access in
 			if inline && c.cl_interface then error "You can't declare inline methods in interfaces" p;
 			let is_macro = (is_macro && stat) || has_meta ":macro" meta in
 			if is_macro && not stat then error "Only static methods can be macros" p;
-			let f = if not is_macro then
-				f
+			let fd = if not is_macro then
+				fd
 			else if ctx.in_macro then
 				let texpr = CTPath { tpackage = ["haxe";"macro"]; tname = "Expr"; tparams = []; tsub = None } in
 				{
-					f_type = (match f.f_type with None -> Some texpr | t -> t);
-					f_args = List.map (fun (a,o,t,e) -> a,o,(match t with None -> Some texpr | _ -> t),e) f.f_args;
-					f_expr = f.f_expr;
+					f_type = (match fd.f_type with None -> Some texpr | t -> t);
+					f_args = List.map (fun (a,o,t,e) -> a,o,(match t with None -> Some texpr | _ -> t),e) fd.f_args;
+					f_expr = fd.f_expr;
 				}
 			else
 				let tdyn = Some (CTPath { tpackage = []; tname = "Dynamic"; tparams = []; tsub = None }) in
 				{
 					f_type = tdyn;
-					f_args = List.map (fun (a,o,_,_) -> a,o,tdyn,None) f.f_args;
+					f_args = List.map (fun (a,o,_,_) -> a,o,tdyn,None) fd.f_args;
 					f_expr = (EBlock [],p)
 				}
 			in
 			let parent = (if not stat then get_parent c name else None) in
-			let dynamic = List.mem ADynamic access || (match parent with Some { cf_kind = Method MethDynamic } -> true | _ -> false) in
+			let dynamic = List.mem ADynamic f.cff_access || (match parent with Some { cf_kind = Method MethDynamic } -> true | _ -> false) in
 			if inline && dynamic then error "You can't have both 'inline' and 'dynamic'" p;
 			let ctx = { ctx with
 				curclass = c;
@@ -761,33 +753,33 @@ let init_class ctx c p herits fields meta =
 				tthis = tthis;
 				type_params = if stat then params else params @ ctx.type_params;
 			} in
-			let ret = type_opt ctx p f.f_type in
+			let ret = type_opt ctx p fd.f_type in
 			let args = List.map (fun (name,opt,t,c) ->
 				let t, c = type_function_param ctx (type_opt ctx p t) c opt p in
 				name, c, t
-			) f.f_args in
+			) fd.f_args in
 			let t = TFun (fun_args args,ret) in
 			let constr = (name = "new") in
 			if constr && c.cl_interface then error "An interface cannot have a constructor" p;
-			if c.cl_interface && not stat && (match f.f_expr with EBlock [] , _ -> false | _ -> true) then error "An interface method cannot have a body" p;
-			if constr then (match f.f_type with
+			if c.cl_interface && not stat && (match fd.f_expr with EBlock [] , _ -> false | _ -> true) then error "An interface method cannot have a body" p;
+			if constr then (match fd.f_type with
 				| None | Some (CTPath { tpackage = []; tname = "Void" }) -> ()
 				| _ -> error "A class constructor can't have a return value" p
 			);
 			let cf = {
 				cf_name = name;
-				cf_doc = doc;
-				cf_meta = type_meta ctx meta;
+				cf_doc = f.cff_doc;
+				cf_meta = f.cff_meta;
 				cf_type = t;
 				cf_kind = Method (if is_macro then MethMacro else if inline then MethInline else if dynamic then MethDynamic else MethNormal);
 				cf_expr = None;
-				cf_public = is_public access parent;
+				cf_public = is_public f.cff_access parent;
 				cf_params = params;
 			} in
 			let r = exc_protect (fun r ->
 				r := (fun() -> t);
 				if ctx.com.verbose then print_endline ("Typing " ^ s_type_path c.cl_path ^ "." ^ name);
-				let e , fargs = type_function ctx args ret stat constr f p in
+				let e , fargs = type_function ctx args ret stat constr fd p in
 				let f = {
 					tf_args = fargs;
 					tf_type = ret;
@@ -808,14 +800,14 @@ let init_class ctx c p herits fields meta =
 					(fun() -> ignore((!r)()))
 				end
 			) in
-			access, constr, cf, delay
-		| FProp (name,doc,meta,access,get,set,t) ->
+			f, constr, cf, delay
+		| FProp (get,set,t) ->
 			let ret = load_complex_type ctx p t in
 			let check_get = ref (fun() -> ()) in
 			let check_set = ref (fun() -> ()) in
 			let check_method m t () =
 				try
-					let t2 = (if List.mem AStatic access then (PMap.find m c.cl_statics).cf_type else fst (class_field c m)) in
+					let t2 = (if stat then (PMap.find m c.cl_statics).cf_type else fst (class_field c m)) in
 					unify_raise ctx t2 t p;
 				with
 					| Error (Unify l,_) -> raise (Error (Stack (Custom ("In method " ^ m ^ " required by property " ^ name),Unify l),p))
@@ -847,19 +839,19 @@ let init_class ctx c p herits fields meta =
 			if set = AccNormal && (match get with AccCall _ -> true | _ -> false) then error "Unsupported property combination" p;
 			let cf = {
 				cf_name = name;
-				cf_doc = doc;
-				cf_meta = type_meta ctx meta;
+				cf_doc = f.cff_doc;
+				cf_meta = f.cff_meta;
 				cf_kind = Var { v_read = get; v_write = set };
 				cf_expr = None;
 				cf_type = ret;
-				cf_public = is_public access None;
+				cf_public = is_public f.cff_access None;
 				cf_params = [];
 			} in
-			access, false, cf, (fun() -> (!check_get)(); (!check_set)())
+			f, false, cf, (fun() -> (!check_get)(); (!check_set)())
 	in
-	let fl = List.map (fun (f,p) ->
-		let access , constr, f , delayed = loop_cf f p in
-		let is_static = List.mem AStatic access in
+	let fl = List.map (fun f ->
+		let fd , constr, f , delayed = loop_cf f in
+		let is_static = List.mem AStatic fd.cff_access in
 		if is_static && f.cf_name = "name" && Common.defined ctx.com "js" then error "This identifier cannot be used in Javascript for statics" p;
 		if (is_static || constr) && c.cl_interface && f.cf_name <> "__init__" then error "You can't declare static fields in interfaces" p;
 		if constr then begin
@@ -874,7 +866,7 @@ let init_class ctx c p herits fields meta =
 			end else begin
 				c.cl_fields <- PMap.add f.cf_name f c.cl_fields;
 				c.cl_ordered_fields <- f :: c.cl_ordered_fields;
-				if List.mem AOverride access then c.cl_overrides <- f.cf_name :: c.cl_overrides;
+				if List.mem AOverride fd.cff_access then c.cl_overrides <- f.cf_name :: c.cl_overrides;
 			end;
 		end;
 		delayed
@@ -933,7 +925,7 @@ let init_class ctx c p herits fields meta =
 						) in
 						a,opt,t,def
 					) f.f_args } in
-					let _, _, cf, delayed = loop_cf (FFun ("new",None,[],acc,pl,fnew)) p in
+					let _, _, cf, delayed = loop_cf { cff_name = "new"; cff_pos = p; cff_doc = None; cff_meta = []; cff_access = acc; cff_kind = FFun (pl,fnew) } in
 					c.cl_constructor <- Some cf;
 					Hashtbl.add ctx.g.constructs c.cl_path (acc,pl,f);
 					delay ctx delayed;
@@ -978,11 +970,11 @@ let type_module ctx m tdecls loadp =
 			let c = mk_class path p in
 			c.cl_private <- priv;
 			c.cl_doc <- d.d_doc;
-			c.cl_meta <- type_meta ctx d.d_meta;
+			c.cl_meta <- d.d_meta;
 			(* store the constructor for later usage *)
-			List.iter (fun (cf,_) ->
+			List.iter (fun cf ->
 				match cf with
-				| FFun ("new",_,_,acc,pl,f) -> Hashtbl.add ctx.g.constructs path (acc,pl,f)
+				| { cff_name = "new"; cff_kind = FFun (pl,f) } -> Hashtbl.add ctx.g.constructs path (cf.cff_access,pl,f)
 				| _ -> ()
 			) d.d_data;
 			decls := TClassDecl c :: !decls
@@ -993,7 +985,7 @@ let type_module ctx m tdecls loadp =
 				e_path = path;
 				e_pos = p;
 				e_doc = d.d_doc;
-				e_meta = type_meta ctx d.d_meta;
+				e_meta = d.d_meta;
 				e_types = [];
 				e_private = priv;
 				e_extern = List.mem EExtern d.d_flags;
@@ -1011,7 +1003,7 @@ let type_module ctx m tdecls loadp =
 				t_private = priv;
 				t_types = [];
 				t_type = mk_mono();
-				t_meta = type_meta ctx d.d_meta;
+				t_meta = d.d_meta;
 			} in
 			decls := TTypeDecl t :: !decls
 	) tdecls;
@@ -1147,7 +1139,7 @@ let type_module ctx m tdecls loadp =
 					ef_pos = p;
 					ef_doc = doc;
 					ef_index = !index;
-					ef_meta = type_meta ctx meta;
+					ef_meta = meta;
 				} e.e_constrs;
 				incr index;
 				names := c :: !names;

+ 55 - 27
typer.ml

@@ -1806,6 +1806,44 @@ let generate ctx main excludes =
 (* ---------------------------------------------------------------------- *)
 (* MACROS *)
 
+let get_type_patch ctx t sub =
+	let new_patch() =
+		{ tp_type = None; tp_remove = false; tp_meta = [] }
+	in
+	let path = Ast.parse_path t in
+	let h, tp = (try
+		Hashtbl.find ctx.g.type_patches path
+	with Not_found ->
+		let h = Hashtbl.create 0 in
+		let tp = new_patch() in
+		Hashtbl.add ctx.g.type_patches path (h,tp);
+		h, tp
+	) in
+	match sub with
+	| None -> tp
+	| Some k ->
+		try
+			Hashtbl.find h k
+		with Not_found ->
+			let tp = new_patch() in
+			Hashtbl.add h k tp;
+			tp
+
+let parse_string ctx s p =
+	let old = Lexer.save() in
+	Lexer.init p.pfile;
+	let _, decls = try
+		Parser.parse ctx.com (Lexing.from_string s)
+	with Parser.Error (e,_) ->
+		failwith (Parser.error_msg e)
+	| Lexer.Error (e,_) ->
+		failwith (Lexer.error_msg e)
+	in
+	Lexer.restore old;
+	match decls with
+	| [(d,_)] -> d
+	| _ -> assert false
+
 let make_macro_api ctx p =
 	{
 		Interp.pos = p;
@@ -1819,19 +1857,8 @@ let make_macro_api ctx p =
 		Interp.parse_string = (fun s p ->
 			let head = "class X{static function main() " in
 			let head = (if p.pmin > String.length head then head ^ String.make (p.pmin - String.length head) ' ' else head) in
-			let s = head ^ s ^ "}" in
-			let old = Lexer.save() in
-			Lexer.init p.pfile;
-			let _, decls = try
-				Parser.parse ctx.com (Lexing.from_string s)
-			with Parser.Error (e,_) ->
-				failwith (Parser.error_msg e)
-			| Lexer.Error (e,_) ->
-				failwith (Lexer.error_msg e)
-			in
-			Lexer.restore old;
-			match decls with
-			| [EClass { d_data = [FFun ("main",_,_,_,_,{ f_expr = e }),_] },_] -> e
+			match parse_string ctx (head ^ s ^ "}") p with
+			| EClass { d_data = [{ cff_name = "main"; cff_kind = FFun (_,{ f_expr = e }) }]} -> e
 			| _ -> assert false
 		);
 		Interp.typeof = (fun e ->
@@ -1839,22 +1866,23 @@ let make_macro_api ctx p =
 			e.etype
 		);
 		Interp.type_patch = (fun t f s v ->
-			let v = (match v with None -> None | Some s -> 
-				let old = Lexer.save() in
-				let head = "typedef T = " in
-				let _, decls = Parser.parse ctx.com (Lexing.from_string (head ^ s)) in
-				Lexer.restore old;
-				match decls with
-				| [ETypedef { d_data = ct },_] -> Some ct
+			let v = (match v with None -> None | Some s ->
+				match parse_string ctx ("typedef T = " ^ s) null_pos with
+				| ETypedef { d_data = ct } -> Some ct
 				| _ -> assert false
 			) in
-			let path = Ast.parse_path t in
-			let h = (try Hashtbl.find ctx.g.type_patches path with Not_found ->
-				let h = Hashtbl.create 0 in
-				Hashtbl.add ctx.g.type_patches path h;
-				h
+			let tp = get_type_patch ctx t (Some (f,s)) in
+			match v with
+			| None -> tp.tp_remove <- true
+			| Some _ -> tp.tp_type <- v
+		);
+		Interp.meta_patch = (fun m t f s ->
+			let m = (match parse_string ctx (m ^ " typedef T = T") null_pos with
+				| ETypedef t -> t.d_meta
+				| _ -> assert false
 			) in
-			Hashtbl.replace h (f,s) v			
+			let tp = get_type_patch ctx t (match f with None -> None | Some f -> Some (f,s)) in
+			tp.tp_meta <- tp.tp_meta @ m;
 		);
 		Interp.print = (fun s ->
 			if not !Common.display then print_string s
@@ -1913,7 +1941,7 @@ let load_macro ctx cpath f p =
 		let r = Interp.call_path mctx ((fst cpath) @ [snd cpath]) f args api in
 		if not in_macro then t();
 		r
-	in	
+	in
 	ctx2, meth, call
 
 let type_macro ctx cpath f el p =