浏览代码

change @:build again (returns Array<Field>, added haxe.macro.Context.getBuildFields())

Nicolas Cannasse 14 年之前
父节点
当前提交
6b19423132
共有 6 个文件被更改,包括 57 次插入21 次删除
  1. 4 0
      interp.ml
  2. 7 0
      std/haxe/macro/Context.hx
  3. 3 3
      std/neko/db/SpodData.hx
  4. 6 1
      typecore.ml
  5. 11 8
      typeload.ml
  6. 26 9
      typer.ml

+ 4 - 0
interp.ml

@@ -99,6 +99,7 @@ type extern_api = {
 	meta_patch : string -> string -> string option -> bool -> unit;
 	set_js_generator : (value -> unit) -> unit;
 	get_cur_class : unit -> tclass option;
+	get_build_fields : unit -> value;
 }
 
 type context = {
@@ -1730,6 +1731,9 @@ let macro_lib =
 			in
 			encode_type (match once with VNull | VBool false -> follow t | VBool true -> follow_once t | _ -> error())
 		);
+		"build_fields", Fun0 (fun() ->
+			(get_ctx()).curapi.get_build_fields()
+		);
 	]
 
 (* ---------------------------------------------------------------------- *)

+ 7 - 0
std/haxe/macro/Context.hx

@@ -160,6 +160,13 @@ class Context {
 	public static function addResource( name : String, data : haxe.io.Bytes ) {
 		return load("add_resource",2)(untyped name.__s,data.getData());
 	}
+	
+	/**
+		Returns the list of fields for the current type inside the build macro.
+	**/
+	public static function getBuildFields() : Array<Field> {
+		return load("build_fields", 0)();
+	}
 
 	static function load( f, nargs ) : Dynamic {
 		#if macro

+ 3 - 3
std/neko/db/SpodData.hx

@@ -827,8 +827,8 @@ class SpodData {
 	#if macro
 	static var RTTI = false;
 
-	public static function addRtti( fields ) {
-		if( RTTI ) return fields;
+	public static function addRtti() : Array<Field> {
+		if( RTTI ) return null;
 		RTTI = true;
 		Context.getType("neko.db.SpodInfos");
 		Context.onGenerate(function(types) {
@@ -853,7 +853,7 @@ class SpodData {
 				default:
 				}
 		});
-		return fields;
+		return null;
 	}
 
 	static function getManagerInfos( t : haxe.macro.Type ) {

+ 6 - 1
typecore.ml

@@ -25,6 +25,10 @@ type type_patch = {
 	mutable tp_meta : Ast.metadata;
 }
 
+type macro_mode =
+	| MExpr
+	| MBuild
+
 type typer_globals = {
 	types_module : (path, path) Hashtbl.t;
 	modules : (path , module_def) Hashtbl.t;
@@ -36,10 +40,11 @@ type typer_globals = {
 	mutable std : module_def;
 	mutable hook_generate : (unit -> unit) list;
 	type_patches : (path, (string * bool, type_patch) Hashtbl.t * type_patch) Hashtbl.t;
+	mutable get_build_fields : unit -> Ast.class_field list;
 	(* api *)
 	do_inherit : typer -> Type.tclass -> Ast.pos -> Ast.class_flag -> bool;
 	do_create : Common.context -> typer;
-	do_macro : typer -> path -> string -> Ast.expr list -> Ast.pos -> Ast.expr option;
+	do_macro : typer -> macro_mode -> path -> string -> Ast.expr list -> Ast.pos -> Ast.expr option;
 	do_load_module : typer -> path -> pos -> module_def;
 	do_optimize : typer -> texpr -> texpr;
 	do_build_instance : typer -> module_type -> pos -> ((string * t) list * path * (t list -> t));

+ 11 - 8
typeload.ml

@@ -37,12 +37,12 @@ let type_static_var ctx t e p =
 	| TType ({ t_path = ([],"UInt") },[]) -> { e with etype = t }
 	| _ -> e
 
-let apply_macro ctx path el p =
+let apply_macro ctx mode path el p =
 	let cpath, meth = (match List.rev (ExtString.String.nsplit path ".") with
 		| meth :: name :: pack -> (List.rev pack,name), meth
 		| _ -> error "Invalid macro path" p
 	) in
-	ctx.g.do_macro ctx cpath meth el p
+	ctx.g.do_macro ctx mode cpath meth el p
 
 (** since load_type_def and load_instance are used in PASS2, they should not access the structure of a type **)
 
@@ -682,7 +682,11 @@ let build_module_def ctx meta fvars fbuild =
 			in
 			let s = String.concat "." (List.rev (getpath epath)) in
 			if ctx.in_macro then error "You cannot used :build inside a macro : make sure that your enum is not used in macro" p;
-			(match apply_macro ctx s (fvars() :: el) p with
+			let old = ctx.g.get_build_fields in
+			ctx.g.get_build_fields <- fvars;
+			let r = try apply_macro ctx MBuild s el p with e -> ctx.g.get_build_fields <- old; raise e in
+			ctx.g.get_build_fields <- old;
+			(match r with
 			| None -> error "Build failure" p
 			| Some e -> fbuild e; loop l)
 		| _ :: l -> loop l
@@ -700,7 +704,7 @@ let init_class ctx c p herits fields =
 	c.cl_interface <- List.mem HInterface herits;
 	set_heritance ctx c herits p;
 	let fields = ref fields in
-	let get_fields() = (EVars ["fields",Some (CTAnonymous !fields),None],p) in
+	let get_fields() = !fields in
 	build_module_def { ctx with curclass = c } c.cl_meta get_fields (fun (e,p) ->
 		match e with
 		| EVars [_,Some (CTAnonymous f),None] -> fields := f
@@ -810,7 +814,7 @@ let init_class ctx c p herits fields =
 			if display_file && (cp.pmin = 0 || (p.pmin <= cp.pmin && p.pmax >= cp.pmax)) then begin
 				if macro && not ctx.in_macro then
 					(* force macro system loading of this class in order to get completion *)
-					(fun() -> ignore(ctx.g.do_macro ctx c.cl_path cf.cf_name [] p))
+					(fun() -> ignore(ctx.g.do_macro ctx MExpr c.cl_path cf.cf_name [] p))
 				else begin
 					cf.cf_type <- TLazy r;
 					(fun() -> ignore((!r)()))
@@ -1340,7 +1344,7 @@ let type_module ctx m tdecls loadp =
 			let ctx = { ctx with type_params = e.e_types } in
 			let constructs = ref d.d_data in
 			let get_constructs() =
-				let cl = List.map (fun (c,doc,meta,pl,p) ->
+				List.map (fun (c,doc,meta,pl,p) ->
 					{
 						cff_name = c;
 						cff_doc = doc;
@@ -1351,8 +1355,7 @@ let type_module ctx m tdecls loadp =
 							| [] -> FVar (None,None)
 							| _ -> FFun { f_params = []; f_type = None; f_expr = None; f_args = List.map (fun (n,o,t) -> n,o,Some t,None) pl });
 					}
-				) (!constructs) in
-				(EVars ["constructs",Some (CTAnonymous cl),None],p) 
+				) (!constructs)
 			in
 			build_module_def ctx e.e_meta get_constructs (fun (e,p) ->
 				match e with

+ 26 - 9
typer.ml

@@ -1697,7 +1697,7 @@ and type_call ctx e el p =
 							| EConst (Ident f | Type f) -> if f <> ef.cf_name then assert false; (EConst (Ident "this"),snd e)
 							| _ -> error "Unsupported" (snd e)
 						) in
-						(match ctx.g.do_macro ctx c.cl_path ef.cf_name (e :: el) p with
+						(match ctx.g.do_macro ctx MExpr c.cl_path ef.cf_name (e :: el) p with
 						| None -> type_expr ctx (EConst (Ident "null"),p)
 						| Some e -> type_expr ctx e)
 					| _ -> assert false)
@@ -1712,7 +1712,7 @@ and type_call ctx e el p =
 		| AKMacro (ethis,f) ->
 			(match ethis.eexpr with
 			| TTypeExpr (TClassDecl c) ->
-				(match ctx.g.do_macro ctx c.cl_path f.cf_name el p with
+				(match ctx.g.do_macro ctx MExpr c.cl_path f.cf_name el p with
 				| None -> type_expr ctx (EConst (Ident "null"),p)
 				| Some e -> type_expr ctx e)
 			| _ ->
@@ -1721,7 +1721,7 @@ and type_call ctx e el p =
 				| TInst (c,_) ->					
 					let rec loop c =
 						if PMap.mem f.cf_name c.cl_fields then
-							match ctx.g.do_macro ctx c.cl_path f.cf_name (Interp.make_ast ethis :: el) p with
+							match ctx.g.do_macro ctx MExpr c.cl_path f.cf_name (Interp.make_ast ethis :: el) p with
 							| None -> type_expr ctx (EConst (Ident "null"),p)
 							| Some e -> type_expr ctx e
 						else
@@ -2049,6 +2049,9 @@ let make_macro_api ctx p =
 			);
 		);
 		Interp.get_cur_class = (fun() -> Some ctx.curclass);
+		Interp.get_build_fields = (fun() -> 
+			Interp.enc_array (List.map Interp.encode_field (ctx.g.get_build_fields()))
+		)
 	}
 
 let load_macro ctx cpath f p =
@@ -2098,7 +2101,7 @@ let load_macro ctx cpath f p =
 		| TInst (c,_) -> (try PMap.find f c.cl_statics with Not_found -> error ("Method " ^ f ^ " not found on class " ^ s_type_path cpath) p)
 		| _ -> error "Macro should be called on a class" p
 	) in
-	let meth = (match follow meth.cf_type with TFun (args,ret) -> args,ret | _ -> error "Macro call should be a method" p) in
+	let meth = (match follow meth.cf_type with TFun (args,ret) -> args,ret,meth.cf_pos | _ -> error "Macro call should be a method" p) in
 	let in_macro = ctx.in_macro in
 	if not in_macro then begin
 		finalize ctx2;
@@ -2114,11 +2117,18 @@ let load_macro ctx cpath f p =
 	in
 	ctx2, meth, call
 
-let type_macro ctx cpath f (el:Ast.expr list) p =
-	let ctx2, (margs,mret), call_macro = load_macro ctx cpath f p in
+let type_macro ctx mode cpath f (el:Ast.expr list) p =
+	let ctx2, (margs,mret,mpos), call_macro = load_macro ctx cpath f p in
 	let ctexpr = { tpackage = ["haxe";"macro"]; tname = "Expr"; tparams = []; tsub = None } in
 	let expr = Typeload.load_instance ctx2 ctexpr p false in
-	unify ctx2 mret expr p;
+	let ctfields = { tpackage = []; tname = "Array"; tparams = [TPType (CTPath { tpackage = ["haxe";"macro"]; tname = "Expr"; tparams = []; tsub = Some "Field" })]; tsub = None } in
+	(match mode with
+	| MExpr ->
+		unify ctx2 mret expr mpos;
+	| MBuild _ ->
+		let tfields = Typeload.load_instance ctx2 ctfields p false in
+		unify ctx2 mret tfields mpos
+	);
 	let args = (try
 		(*
 			force default parameter types to haxe.macro.Expr, and if success allow to pass any value type since it will be encoded
@@ -2169,7 +2179,13 @@ let type_macro ctx cpath f (el:Ast.expr list) p =
 	let call() =
 		match call_macro args with
 		| None -> None
-		| Some v -> Some (try Interp.decode_expr v with Interp.Invalid_expr -> error "The macro didn't return a valid expression" p)
+		| Some v -> 
+			try
+				Some (match mode with
+				| MExpr -> Interp.decode_expr v
+				| MBuild _ -> (EVars ["fields",Some (CTAnonymous (match v with Interp.VNull -> ctx.g.get_build_fields() | _ -> List.map Interp.decode_field (Interp.dec_array v))),None],p))
+			with Interp.Invalid_expr ->
+				error "The macro didn't return a valid result" p
 	in
 	let e = (if ctx.in_macro then begin
 		(*
@@ -2199,7 +2215,7 @@ let type_macro ctx cpath f (el:Ast.expr list) p =
 	e
 
 let call_macro ctx path meth args p =
-	let ctx2, (margs,_), call = load_macro ctx path meth p in
+	let ctx2, (margs,_,_), call = load_macro ctx path meth p in
 	let el = unify_call_params ctx2 (Some (meth,[])) args margs p false in
 	call (List.map (fun e -> try Interp.make_const e with Exit -> error "Parameter should be a constant" e.epos) el)
 
@@ -2244,6 +2260,7 @@ let rec create com =
 			delayed = [];
 			doinline = not (Common.defined com "no_inline" || com.display);
 			hook_generate = [];
+			get_build_fields = (fun() -> []);
 			std = empty;
 			do_inherit = Codegen.on_inherit;
 			do_create = create;