Improve the Custom Field Macro

This commit is contained in:
Ne_Eo
2024-11-11 17:33:39 +01:00
parent 2f71bf4426
commit b28f79cc36
@@ -1,22 +1,51 @@
package macros;
#if macro
import haxe.macro.Compiler;
import haxe.macro.Context;
import haxe.macro.Expr;
import haxe.macro.Compiler;
using StringTools;
typedef Injection = {
var access:Array<Access>;
var type:ComplexType;
var ?expr:Expr;
}
/**
* Macro used to add custom fields to classes without having to override the entire file.
*/
class CustomFieldMacro {
public static function init() {
Compiler.addGlobalMetadata("lime.utils", '@:build(macros.CustomFieldMacro.build("lime.utils.AssetLibrary", "tag", "funkin.backend.assets.AssetSource"))');
var injections:Map<String, Map<String, Injection>> = [
"lime.utils.AssetLibrary" => [
"tag" => {
access: [APublic],
type: macro: funkin.backend.assets.AssetSource,
expr: macro null
}
],
];
for(lib => injection in injections) {
for(key => value in injection) {
var params:Array<String> = [
'"$lib"', '"$key"',
'"' + MacroSerializer.run(value.access) + '"',
'"' + MacroSerializer.run(value.type) + '"',
];
if(value.expr != null)
params.push('"' + MacroSerializer.run(value.expr) + '"');
var build = '@:build(macros.CustomFieldMacro.build(${params.join(", ")}))';
//Sys.println('Injecting $build into $lib');
Compiler.addGlobalMetadata(lib, build);
}
}
}
// TODO: Add support for default values
public static function build(lib:String, fieldName:String, type:String) {
public static function build(lib:String, fieldName:String, access:String, type:String, ?defaultValue:String) {
var fields = Context.getBuildFields();
var clRef = Context.getLocalClass();
if (clRef == null) return fields;
@@ -29,12 +58,16 @@ class CustomFieldMacro {
return fields;
}
var access:Array<Access> = MacroUnserializer.run(access);
var type:ComplexType = MacroUnserializer.run(type);
var defaultValue:Expr = MacroUnserializer.run(defaultValue);
var fields = Context.getBuildFields();
fields.push({
name: fieldName,
access: [APublic],
kind: FVar(getTPath(type)),
access: access,
kind: FVar(type, defaultValue),
pos: Context.currentPos()
});
@@ -49,4 +82,55 @@ class CustomFieldMacro {
});
}
}
class MacroSerializer extends haxe.Serializer {
public static function run(v:Dynamic) {
var s = new MacroSerializer();
s.useEnumIndex = true;
s.serialize(v);
return s.toString();
}
public override function serialize(v:Dynamic) {
switch (Type.typeof(v)) {
case TClass(c):
if (!(#if neko untyped c.__is_String #else c == String #end)) {
switch (#if (neko || cs || python) Type.getClassName(c) #else c #end) {
case #if (neko || cs || python) "haxe.macro.Position" #else c if(Type.getClassName(c) == "haxe.macro.Position") #end:
buf.add("P");
var info = Context.getPosInfos(v);
serialize(info.min);
serialize(info.max);
serialize(info.file);
return;
default:
}
}
default:
}
super.serialize(v);
}
}
class MacroUnserializer extends haxe.Unserializer {
public static function run(s:String):Dynamic {
var u = new MacroUnserializer(s);
return u.unserialize();
}
public override function unserialize():Dynamic {
var c = get(pos++);
switch (c) {
case "P".code:
var min = unserialize();
var max = unserialize();
var file = unserialize();
var o = Context.makePosition({min: min, max: max, file: file});
return o;
}
pos--;
return super.unserialize();
}
}
#end