Browse Source

added Context.onMacroContextReused (fixed issue #1627)

Nicolas Cannasse 12 years ago
parent
commit
26c592dab2
5 changed files with 55 additions and 7 deletions
  1. 34 5
      interp.ml
  2. 9 0
      std/haxe/macro/Context.hx
  3. 9 0
      std/sys/db/RecordMacros.hx
  4. 1 1
      std/sys/db/Transaction.hx
  5. 2 1
      typer.ml

+ 34 - 5
interp.ml

@@ -149,6 +149,8 @@ type context = {
 	mutable venv : value array;
 	(* context *)
 	mutable curapi : extern_api;
+	mutable on_reused : (unit -> bool) list;
+	mutable is_reused : bool;
 	(* eval *)
 	mutable locals_map : (string, int) PMap.t;
 	mutable locals_count : int;
@@ -2420,6 +2422,14 @@ let macro_lib =
 			PMap.iter (fun n v -> Hashtbl.replace h (VString n) (encode_type v.v_type)) loc;
 			enc_hash h
 		);
+		"macro_context_reused", Fun1 (fun c ->
+			match c with
+			| VFunction (Fun0 _) ->
+				let ctx = get_ctx() in
+				ctx.on_reused <- (fun() -> catch_errors ctx (fun() -> ctx.do_call VNull c [] null_pos) = Some (VBool true)) :: ctx.on_reused;
+				VNull
+			| _ -> error()
+		);
 	]
 
 (* ---------------------------------------------------------------------- *)
@@ -3300,6 +3310,8 @@ let create com api =
 		(* context *)
 		curapi = api;
 		loader = VObject loader;
+		on_reused = [];
+		is_reused = true;
 		exports = VObject { ofields = [||]; oproto = None };
 	} in
 	ctx.do_call <- call ctx;
@@ -3310,12 +3322,29 @@ let create com api =
 	List.iter (fun e -> ignore((eval ctx e)())) (Genneko.header());
 	ctx
 
-let has_old_version ctx t =
-	let inf = Type.t_infos t in
-	try
-		Hashtbl.find ctx.types inf.mt_path <> inf.mt_module.m_id
-	with Not_found ->
+	
+
+let do_reuse ctx =
+	ctx.is_reused <- false
+	
+let can_reuse ctx types =
+	let has_old_version t =
+		let inf = Type.t_infos t in
+		try
+			Hashtbl.find ctx.types inf.mt_path <> inf.mt_module.m_id
+		with Not_found ->
+			false
+	in
+	if List.exists has_old_version types then
+		false
+	else if ctx.is_reused then
+		true
+	else if not (List.for_all (fun f -> f()) ctx.on_reused) then
 		false
+	else begin
+		ctx.is_reused <- true;
+		true;
+	end
 
 let add_types ctx types ready =
 	let types = List.filter (fun t ->

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

@@ -269,6 +269,15 @@ class Context {
 	public static function registerModuleReuseCall( modulePath : String, macroCall : String ) {
 		load("module_reuse_call", 2)(untyped modulePath.__s,untyped macroCall.__s);
 	}
+	
+	/**
+		Register a callback function that will be called everytime the macro context cached is reused with a new
+		compilation. This enable to reset some static vars since the code might have been changed. If the callback
+		returns false, the macro context is discarded and another one is created.
+	**/
+	public static function onMacroContextReused( callb : Void -> Bool ) {
+		load("macro_context_reused", 1)(callb);
+	}
 
 	@:allow(haxe.macro.TypeTools)
 	static function load( f, nargs ) : Dynamic {

+ 9 - 0
std/sys/db/RecordMacros.hx

@@ -1010,10 +1010,19 @@ class RecordMacros {
 
 	#if macro
 	static var RTTI = false;
+	static var FIRST_COMPILATION = true;
 
 	public static function addRtti() : Array<Field> {
 		if( RTTI ) return null;
 		RTTI = true;
+		if( FIRST_COMPILATION ) {
+			FIRST_COMPILATION = false;
+			Context.onMacroContextReused(function() {
+				RTTI = false;
+				GLOBAL = null;
+				return true;
+			});
+		}
 		Context.getType("sys.db.RecordInfos");
 		Context.onGenerate(function(types) {
 			for( t in types )

+ 1 - 1
std/sys/db/Transaction.hx

@@ -50,7 +50,7 @@ class Transaction {
 		}
 	}
 
-	public static function main( cnx, mainFun : Void -> Void, logError : Dynamic -> Void ) {
+	public static function main( cnx, mainFun : Void -> Void, ?logError : Dynamic -> Void ) {
 		Manager.initialize();
 		Manager.cnx = cnx;
 		Manager.cnx.startTransaction();

+ 2 - 1
typer.ml

@@ -3596,7 +3596,7 @@ and flush_macro_context mint ctx =
 	mctx.com.types <- types;
 	mctx.com.Common.modules <- modules;
 	(* if one of the type we are using has been modified, we need to create a new macro context from scratch *)
-	let mint = if List.exists (Interp.has_old_version mint) types then begin
+	let mint = if not (Interp.can_reuse mint types) then begin
 		let com2 = mctx.com in
 		let mint = Interp.create com2 (make_macro_api ctx Ast.null_pos) in
 		let macro = ((fun() -> Interp.select mint), mctx) in
@@ -3617,6 +3617,7 @@ let create_macro_interp ctx mctx =
 			let mint = Interp.create com2 (make_macro_api ctx Ast.null_pos) in
 			mint, (fun() -> init_macro_interp ctx mctx mint)
 		| Some mint ->
+			Interp.do_reuse mint;
 			mint, (fun() -> ())
 	) in
 	let on_error = com2.error in