Browse Source

Add buildSaveLoad() macro

ShiroSmith 5 years ago
parent
commit
a8eaec7ac8
1 changed files with 134 additions and 0 deletions
  1. 134 0
      hide/tools/Macros.hx

+ 134 - 0
hide/tools/Macros.hx

@@ -22,6 +22,140 @@ class Macros {
 			if( StringTools.endsWith(f,".hx") )
 				Context.addResource("shader/" + f.substr(0, -3), sys.io.File.getBytes(dir + "/" + f));
 	}
+
+	public static function buildSaveLoad() {
+
+		inline function isSerialized( field : haxe.macro.Field ) : Bool {
+			return Lambda.find(field.meta, m -> m.name == ":s") != null;
+		}
+
+		inline function isOpt( field : haxe.macro.Field ) : Bool {
+			return Lambda.find(field.meta, m -> m.name == ":opt") != null;
+		}
+		
+		var fields = haxe.macro.Context.getBuildFields();
+
+		// Add the call of _save and _load
+		if( haxe.macro.Context.getLocalClass().get().name == "Prefab" ) {
+
+			var loadField : Field = null;
+			var saveField : Field = null;
+			for( f in fields ) {
+				if( f.name == "save" && f.kind.match(FFun(_)) )
+					saveField = f;
+				else if( f.name == "load" && f.kind.match(FFun(_)) )
+					loadField = f;
+				if( loadField != null && saveField != null )
+					break;
+			}
+
+			var loadFunction = switch loadField.kind {
+				case FFun(f): f;
+				default: null;
+			}
+			loadFunction.expr = macro _load(v);
+
+			var saveFunction = switch saveField.kind {
+				case FFun(f): f;
+				default: null;
+			}
+			saveFunction.expr = macro return _save();
+
+			fields.push({
+				name: "_load",
+				access: [APrivate],
+				pos: haxe.macro.Context.currentPos(),
+				kind: FFun({
+					args: [{ name : "obj", type : (macro:Dynamic) }],
+					expr: macro return,
+					params: [],
+					ret: null
+				})
+			});
+
+			fields.push({
+				name: "_save",
+				access: [APrivate],
+				pos: haxe.macro.Context.currentPos(),
+				kind: FFun({
+					args: [],
+					expr: macro return {},
+					params: [],
+					ret: (macro:Dynamic)
+				})
+			});
+
+			return fields;
+		}
+
+		// Generate code for every field with :s metadata
+		var saveExpr : Array<haxe.macro.Expr> = [];
+		var loadExpr : Array<haxe.macro.Expr> = [];
+		for( f in fields ) {
+			if( !isSerialized(f) )
+				continue;
+			var name = f.name;
+			switch f.kind {
+				case FVar(t, e):
+					// Don't save a field with his default value
+					if( e != null )
+						saveExpr.push(macro if( this.$name != $e ) obj.$name = this.$name); 
+					else {
+						switch t {
+							// Basic types default values : https://haxe.org/manual/types-nullability.html 					
+							case TPath(p):
+								if( p.name == "Bool" )
+									saveExpr.push(macro if( this.$name != false) obj.$name = this.$name);
+								else if( p.name == "Float" )
+									saveExpr.push(macro if( this.$name != #if flash NaN #else 0.0 #end ) obj.$name = this.$name);
+								else if( p.name == "Int" )
+									saveExpr.push(macro if( this.$name != 0 ) obj.$name = this.$name);
+								else 
+									saveExpr.push(macro if( this.$name != null ) obj.$name = this.$name);
+							default:
+								saveExpr.push(macro if( this.$name != null ) obj.$name = this.$name);
+						}
+					}
+				case FFun(f): saveExpr.push(macro obj.$name = this.$name );
+				case FProp(get, set, t, e): saveExpr.push(macro obj.$name = this.$name );
+			}
+			loadExpr.push(macro if( obj.$name != null ) this.$name = obj.$name );
+		}
+
+		// Generate the functions if not empty
+		if( saveExpr.length > 0 ) {
+			saveExpr.insert(0, macro var obj : Dynamic = super._save());
+			saveExpr.push(macro return obj );
+			fields.push({
+				name: "_save",
+				access: [AOverride, APrivate],
+				pos: haxe.macro.Context.currentPos(),
+				kind: FFun({
+					args: [],
+					expr: macro $b{saveExpr},
+					params: [],
+					ret: (macro:Dynamic)
+				})
+			});
+		}
+
+		if( loadExpr.length > 0 ) {
+			loadExpr.insert(0, macro super._load(obj));
+			fields.push({
+				name: "_load",
+				access: [AOverride, APrivate],
+				pos: haxe.macro.Context.currentPos(),
+				kind: FFun({
+					args: [{ name : "obj", type : (macro:Dynamic) }],
+					expr: macro $b{loadExpr},
+					params: [],
+					ret: null
+				})
+			});
+		}
+
+		return fields;
+	}
 	#end
 
 }