Tried some fuckery

This commit is contained in:
Yoshman29
2023-04-01 02:23:07 +02:00
parent 995c3b9c8e
commit 558a4c0782
3 changed files with 236 additions and 118 deletions
+228 -109
View File
@@ -18,15 +18,15 @@ class ClassExtendMacro {
public static inline final FUNC_PREFIX = "_HX_SUPER__";
public static inline final CLASS_SUFFIX = "_HSX";
public static var applyOn:Array<String> = ["flixel", "funkin"];
public function new(className:String, usedClass:Class<Dynamic>) {
this.className = className;
this.usedClass = usedClass;
}
public static function init() {
//Compiler.addGlobalMetadata('funkin', '@:build(hscript.ClassExtendMacro.build())');
Compiler.addGlobalMetadata('flixel', '@:build(hscript.ClassExtendMacro.build())');
//Compiler.addGlobalMetadata('openfl.display.BlendMode', '@:build(hscript.UsingHandler.build())');
trace("TEST");
}
@@ -36,131 +36,250 @@ class ClassExtendMacro {
if (clRef == null) return fields;
var cl = clRef.get();
if (cl.isAbstract || cl.isExtern || cl.isFinal || cl.isInterface) return fields;
if (!cl.name.endsWith("_Impl_") && !cl.name.endsWith(CLASS_SUFFIX) && !cl.name.endsWith("__Softcoded")) {//(/* cl.name.startsWith("Flx") && */ cl.name.endsWith("_Impl_") && cl.params.length <= 0 && !cl.meta.has(":multiType")) {
var metas = cl.meta.get();
var hasInterp = false;
if(cl.params.length > 0) {
return fields;
} else if (cl.superClass != null) {
var sClass = cl;
var inModifiedModule = false;
while(sClass != null) {
if (sClass.superClass != null) {
if (sClass.superClass.params != null && sClass.superClass.params.length > 0)
return fields;
if (!inModifiedModule)
for(e in applyOn)
if (sClass.superClass.t.get().module.startsWith(e)) {
inModifiedModule = true;
hasInterp = true;
break;
}
}
if (!hasInterp)
for(f in sClass.fields.get())
if (f.name == "__interp") {
hasInterp = true;
break;
}
sClass = sClass.superClass != null ? sClass.superClass.t.get() : null;
}
if (sClass != null)
return fields;
}
var shadowClass = macro class {
for(f in fields.copy()) {
if (f.name == "new")
continue;
if (f.name.startsWith(FUNC_PREFIX))
continue;
if (f.access.contains(ADynamic) || f.access.contains(AStatic) || f.access.contains(AExtern) || f.access.contains(AInline))
continue;
};
shadowClass.params = switch(cl.params.length) {
case 0:
null;
case 1:
[
{
name: "T",
}
];
default:
[for(k=>e in cl.params) {
name: "T" + Std.int(k+1)
}];
};
shadowClass.name = cl.name + CLASS_SUFFIX; // Hscript Extra
var superClass:haxe.macro.TypePath = {
pack: cl.pack,
name: cl.name,
//params: shadowClass.params
}
shadowClass.kind = TDClass(superClass, [], false, false, false);
var newFuncNames = [];
for(f in fields)
switch(f.kind) {
case FFun(fun):
if (!f.access.contains(AStatic) && f.name != "new" && !f.access.contains(ADynamic)) { /* || !cl.name.endsWith(CLASS_SUFFIX)*/
if (fun.params.length > 0) continue;
if (fun.expr != null) {
//trace(fun.expr);
var newFuncName = FUNC_PREFIX + f.name;
var newAccess = f.access.copy();
var needsOverride = false;
for(cf in fields)
switch(cf.kind) {
case FFun(cfun):
if (!cf.access.contains(AStatic)/* && cf.access.contains(AOverride)*/) {
if(cf.name == newFuncName) {
needsOverride = true;
break;
}
}
default:
}
if(!needsOverride) { // by default contains AOverride, so we remove it if the class doesnt have the same name
newAccess.remove(AOverride);
}
var name = f.name;
//trace("");
///trace(fun.args);
var myFunc:Function = null;
if(fun.ret.match(TPath({name: "Void"}))) {
myFunc = {
expr: macro super.$name(),
ret: fun.ret,
args: fun.args,
params: fun.params,
};
var arguments = myFunc.expr.expr.getParameters()[1];
for(i=>arg in fun.args) {
arguments[i] = macro $i{arg.name};
}
} else {
myFunc = {
expr: macro return super.$name(),
ret: fun.ret,
args: fun.args,
params: fun.params,
};
var aa = myFunc.expr.expr.getParameters();
var aa:ExprDef = cast aa[0].expr;
var arguments = aa.getParameters()[1];
//trace(arguments);
for(i=>arg in fun.args) {
arguments[i] = macro $i{arg.name};
}
}
newFuncNames.push(name);
var newField = {
name: newFuncName,
doc: null,
meta: [],
access: newAccess,
kind: FFun(myFunc),
var expr = fun.expr;
var newExpr = fun.ret.match(TPath({name: "Void"})) ? (macro {
var name = ${{
pos: Context.currentPos(),
expr: EConst(CString(f.name, DoubleQuotes))
}};
var v:Dynamic;
if (__interp != null && (v = __interp.resolve(name, false)) != null && Reflect.isFunction(v)) {
${{
expr: ECall({
pos: Context.currentPos(),
expr: EConst(CIdent("v"))
}, fun.args != null ? [for(a in fun.args) {
pos: Context.currentPos(),
expr: EConst(CIdent(a.name))
}] : []),
pos: Context.currentPos()
};
shadowClass.fields.push(newField);
}}
}
}
default:
}
else {
${{
expr: ECall({
pos: Context.currentPos(),
expr: EConst(CIdent('$FUNC_PREFIX${f.name}'))
}, fun.args != null ? [for(a in fun.args) {
pos: Context.currentPos(),
expr: EConst(CIdent(a.name))
}] : []),
pos: Context.currentPos()
}}
}
}) : (macro {
var name = ${{
pos: Context.currentPos(),
expr: EConst(CString(f.name, DoubleQuotes))
}};
var v:Dynamic;
if (__interp != null && (v = __interp.resolve(name, false)) != null && Reflect.isFunction(v)) {
return ${{
expr: ECall({
pos: Context.currentPos(),
expr: EConst(CIdent("v"))
}, fun.args != null ? [for(a in fun.args) {
pos: Context.currentPos(),
expr: EConst(CIdent(a.name))
}] : []),
pos: Context.currentPos()
}}
}
else {
return ${{
expr: ECall({
pos: Context.currentPos(),
expr: EConst(CIdent('$FUNC_PREFIX${f.name}'))
}, fun.args != null ? [for(a in fun.args) {
pos: Context.currentPos(),
expr: EConst(CIdent(a.name))
}] : []),
pos: Context.currentPos()
}}
}
});
fun.expr = newExpr;
if(shadowClass.fields.length > 0) {
//trace("Defining Class: " + shadowClass.name + " containing " + newFuncNames);
Context.defineModule(cl.module, [shadowClass], Context.getLocalImports());
if (f.access.contains(AOverride) && hasInterp)
cleanExpr(expr, f.name, '$FUNC_PREFIX${f.name}');
var newFunc:Function = {
args: fun.args,
ret: fun.ret,
params: fun.params,
expr: macro {
@:privateAccess
${expr}
}
};
fields.push({
name: '$FUNC_PREFIX${f.name}',
pos: f.pos,
kind: FFun(newFunc),
access: f.access.copy()
});
if (!hasInterp)
fields[fields.length - 1].access.remove(AOverride);
default:
// fuck off >:(
}
}
if (!hasInterp) {
fields.push({
name: "__interp",
pos: Context.currentPos(),
kind: FVar(TPath({
pack: ['hscript'],
name: 'Interp'
}))
});
}
}
return fields;
}
public static function cleanExpr(expr:Expr, oldFunc:String, newFunc:String) {
if (expr == null) return;
if (expr.expr == null) return;
switch(expr.expr) {
case EConst(c):
switch(c) {
case CIdent(s):
if (s == oldFunc)
expr.expr = EConst(CIdent(newFunc));
case CString(s, b):
if (s == oldFunc)
expr.expr = EConst(CString(s, b));
default:
// nothing
}
case EField(e, field):
if (field == oldFunc && e != null) {
switch(e.expr) {
case EConst(c):
switch(c) {
case CIdent(s):
if (s == "super")
expr.expr = EField(e, newFunc);
default:
}
default:
}
}
case EParenthesis(e):
cleanExpr(e, oldFunc, newFunc);
case EObjectDecl(fields):
for(f in fields) {
cleanExpr(f.expr, oldFunc, newFunc);
}
case EArrayDecl(values):
for(a in values) {
cleanExpr(a, oldFunc, newFunc);
}
case ECall(e, params):
cleanExpr(e, oldFunc, newFunc);
case EBlock(exprs):
for(e in exprs)
cleanExpr(e, oldFunc, newFunc);
case EFor(it, expr):
cleanExpr(it, oldFunc, newFunc);
cleanExpr(expr, oldFunc, newFunc);
case EIf(econd, eif, eelse):
cleanExpr(econd, oldFunc, newFunc);
cleanExpr(eif, oldFunc, newFunc);
cleanExpr(eelse, oldFunc, newFunc);
case EWhile(econd, e, normalWhile):
cleanExpr(econd, oldFunc, newFunc);
cleanExpr(e, oldFunc, newFunc);
case ECast(e, t):
cleanExpr(e, oldFunc, newFunc);
case ECheckType(e, t):
cleanExpr(e, oldFunc, newFunc);
case ETry(e, catches):
cleanExpr(e, oldFunc, newFunc);
for(c in catches) {
cleanExpr(c.expr, oldFunc, newFunc);
}
case EThrow(e):
cleanExpr(e, oldFunc, newFunc);
case ETernary(econd, eif, eelse):
cleanExpr(econd, oldFunc, newFunc);
cleanExpr(eif, oldFunc, newFunc);
cleanExpr(eelse, oldFunc, newFunc);
case ESwitch(e, cases, edef):
cleanExpr(e, oldFunc, newFunc);
for(c in cases) {
cleanExpr(c.expr, oldFunc, newFunc);
}
cleanExpr(edef, oldFunc, newFunc);
case EReturn(e):
cleanExpr(e, oldFunc, newFunc);
case EIs(e, t):
cleanExpr(e, oldFunc, newFunc);
case EVars(vars):
for(v in vars) {
cleanExpr(v.expr, oldFunc, newFunc);
}
case ENew(t, params):
for(p in params) {
cleanExpr(p, oldFunc, newFunc);
}
default:
}
}
}
#else
class ClassExtendMacro {
+7 -8
View File
@@ -24,11 +24,10 @@ class CustomClassHandler implements IHScriptCustomConstructor {
interp.execute(expr);
}
var cl = extend == null ? TemplateClass : Type.resolveClass('${name}_HSX');
var cl = extend == null ? TemplateClass : Type.resolveClass('${extend}_HSX');
var _class = Type.createInstance(cl, args);
//interp.variables.set("this", interp.variables);
_class.interp = interp;
_class.__interp = interp;
var newFunc = interp.variables.get("new");
if(newFunc != null) {
@@ -49,23 +48,23 @@ class CustomClassHandler implements IHScriptCustomConstructor {
}
class TemplateClass implements IHScriptCustomBehaviour {
public var interp:Interp;
public var __interp:Interp;
public function hset(name:String, val:Dynamic):Dynamic {
if(Reflect.hasField(this, name)) {
Reflect.setProperty(this, name, val);
return Reflect.getProperty(this, name); // Incase it overwrites the return value
}
if(this.interp.variables.exists("set_" + name)) {
return this.interp.variables.get("set_" + name)(val); // TODO: Prevent recursion from setting it in the function
if(this.__interp.variables.exists("set_" + name)) {
return this.__interp.variables.get("set_" + name)(val); // TODO: Prevent recursion from setting it in the function
}
this.interp.variables.set(name, val);
this.__interp.variables.set(name, val);
return val;
}
public function hget(name:String):Dynamic {
if(Reflect.hasField(this, name)) {
return Reflect.getProperty(this, name);
}
return this.interp.variables.get(name);
return this.__interp.variables.get(name);
}
}
+1 -1
View File
@@ -411,7 +411,7 @@ class Interp {
#end
}
function resolve(id:String, doException:Bool = true):Dynamic {
public function resolve(id:String, doException:Bool = true):Dynamic {
id = StringTools.trim(id);
var l = locals.get(id);
if (l != null)