Bug fix on custom classes + Better performance with custom classes

Also made the custom class generated code use less code
This commit is contained in:
NeeEoo
2024-04-23 17:47:30 +02:00
parent a727148447
commit 9288a9df10
5 changed files with 209 additions and 63 deletions
+47 -24
View File
@@ -1,5 +1,6 @@
package hscript;
import hscript.Interp.DeclaredVar;
import hscript.utils.UnsafeReflect;
using StringTools;
@@ -13,27 +14,28 @@ class CustomClassHandler implements IHScriptCustomConstructor {
public var extend:String;
public var interfaces:Array<String>;
public var cl:Class<Dynamic>;
public function new(ogInterp:Interp, name:String, fields:Array<Expr>, ?extend:String, ?interfaces:Array<String>) {
this.ogInterp = ogInterp;
this.name = name;
this.fields = fields;
this.extend = extend;
this.interfaces = interfaces;
this.cl = extend == null ? TemplateClass : Type.resolveClass('${extend}_HSX');
if(cl == null)
ogInterp.error(EInvalidClass(extend));
}
public function hnew(args:Array<Dynamic>):Dynamic {
var interp = new Interp();
interp.errorHandler = ogInterp.errorHandler;
var cl = extend == null ? TemplateClass : Type.resolveClass('${extend}_HSX');
if(cl == null)
ogInterp.error(EInvalidClass(extend));
var _class = Type.createInstance(cl, args);
var _class:IHScriptCustomClassBehaviour = Type.createInstance(cl, args);
var __capturedLocals = ogInterp.duplicate(ogInterp.locals);
var capturedLocals:Map<String, {r:Dynamic, depth:Int}> = [];
var capturedLocals:Map<String, DeclaredVar> = [];
for(k=>e in __capturedLocals)
if (e != null && e.depth <= 0)
capturedLocals.set(k, e);
@@ -51,6 +53,8 @@ class CustomClassHandler implements IHScriptCustomConstructor {
}
}
_class.__custom__variables = interp.variables;
for(expr in fields) {
@:privateAccess
interp.exprReturn(expr);
@@ -58,16 +62,20 @@ class CustomClassHandler implements IHScriptCustomConstructor {
interp.variables.set("super", staticHandler);
_class.__interp = interp;
_class.__interp = interp; // TODO: Remove
interp.scriptObject = _class;
var newFunc = interp.variables.get("new");
if(newFunc != null) {
Reflect.callMethod(null, newFunc, args);
}
for(variable => value in interp.variables) {
if(variable == "this") continue;
if(variable.startsWith("set_") || variable.startsWith("get_")) {
_class.__allowSetGet = false;
}
}
var newFunc = interp.variables.get("new");
if(newFunc != null) {
UnsafeReflect.callMethodUnsafe(null, newFunc, args);
}
return _class;
@@ -78,27 +86,42 @@ class CustomClassHandler implements IHScriptCustomConstructor {
}
}
class TemplateClass implements IHScriptCustomBehaviour {
public var __interp:Interp;
class TemplateClass implements IHScriptCustomClassBehaviour implements IHScriptCustomBehaviour {
public var __interp:Interp; // TODO: Remove
public var __custom__variables:Map<String, Dynamic>;
public var __allowSetGet:Bool = true;
public function hset(name:String, val:Dynamic):Dynamic {
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(name)) {
this.__interp.variables.set(name, val);
if(__allowSetGet && __custom__variables.exists("set_" + name))
return __callSetter(name, val);
if (__custom__variables.exists(name)) {
__custom__variables.set(name, val);
return val;
}
UnsafeReflect.setProperty(this, name, val);
return UnsafeReflect.field(this, name);
}
public function hget(name:String):Dynamic {
if(this.__interp.variables.exists("get_" + name))
return this.__interp.variables.get("get_" + name)();
if (this.__interp.variables.exists(name))
return this.__interp.variables.get(name);
if(__allowSetGet && __custom__variables.exists("get_" + name))
return __callGetter(name);
if (__custom__variables.exists(name))
return __custom__variables.get(name);
return UnsafeReflect.getProperty(this, name);
}
public function __callGetter(name:String):Dynamic {
__allowSetGet = false;
var v = __custom__variables.get("get_" + name)();
__allowSetGet = true;
return v;
}
public function __callSetter(name:String, val:Dynamic):Dynamic {
__allowSetGet = false;
var v = __custom__variables.get("set_" + name)(val);
__allowSetGet = true;
return v;
}
}
class StaticHandler {
+16
View File
@@ -0,0 +1,16 @@
package hscript;
import hscript.Interp;
interface IHScriptCustomClassBehaviour {
public var __interp:Interp; // TODO: Remove
public var __custom__variables:Map<String, Dynamic>;
public var __allowSetGet:Bool;
public function hset(name:String, val:Dynamic):Dynamic;
public function hget(name:String):Dynamic;
public function __callGetter(name:String):Dynamic;
public function __callSetter(name:String, val:Dynamic):Dynamic;
}
+2 -2
View File
@@ -1144,7 +1144,7 @@ class Interp {
function fcall(o:Dynamic, f:String, args:Array<Dynamic>):Dynamic {
if(o == CustomClassHandler.staticHandler && _hasScriptObject) {
return UnsafeReflect.callMethod(scriptObject, UnsafeReflect.field(scriptObject, "_HX_SUPER__" + f), args);
return UnsafeReflect.callMethodUnsafe(scriptObject, UnsafeReflect.field(scriptObject, "_HX_SUPER__" + f), args);
}
return call(o, get(o, f), args);
}
@@ -1153,7 +1153,7 @@ class Interp {
if(f == CustomClassHandler.staticHandler) {
return null;
}
return Reflect.callMethod(o, f, args);
return UnsafeReflect.callMethodSafe(o, f, args);
}
function cnew(cl:String, args:Array<Dynamic>):Dynamic {
+107 -27
View File
@@ -184,9 +184,11 @@ class ClassExtendMacro {
var name:String = $v{name};
if (__interp != null) {
var v:Dynamic = null;
if (__interp.variables.exists(name) && Reflect.isFunction(v = __interp.variables.get(name))) {
return v($a{arguments});
if (__custom__variables.exists(name)) {
var v:Dynamic = null;
if(Reflect.isFunction(v = __custom__variables.get(name))) {
return v($a{arguments});
}
}
}
return super.$name($a{arguments});
@@ -196,10 +198,12 @@ class ClassExtendMacro {
var name:String = $v{name};
if (__interp != null) {
var v:Dynamic = null;
if (__interp != null && __interp.variables.exists(name) && Reflect.isFunction(v = __interp.variables.get(name))) {
v($a{arguments});
return;
if (__custom__variables.exists(name)) {
var v:Dynamic = null;
if(Reflect.isFunction(v = __custom__variables.get(name))) {
v($a{arguments});
return;
}
}
}
super.$name($a{arguments});
@@ -257,7 +261,8 @@ class ClassExtendMacro {
pack: cl.pack.copy(),
name: cl.name
}, [
{name: "IHScriptCustomBehaviour", pack: ["hscript"]}
{name: "IHScriptCustomBehaviour", pack: ["hscript"]},
{name: "IHScriptCustomClassBehaviour", pack: ["hscript"]}
], false, true, false);
shadowClass.name = '${cl.name}$CLASS_SUFFIX';
var imports = Context.getLocalImports().copy();
@@ -266,13 +271,90 @@ class ClassExtendMacro {
// Adding hscript getters and setters
// TODO: Remove
shadowClass.fields.push({
name: "__interp",
pos: Context.currentPos(),
kind: FVar(TPath({
pack: ['hscript'],
name: 'Interp'
}))
})),
access: [APublic]
});
shadowClass.fields.push({
name: "__custom__variables",
pos: Context.currentPos(),
kind: FVar(TPath({
pack: [],
name: 'Map',
params: [TPType(TPath({name: "String", pack: []})), TPType(TPath({name: "Dynamic", pack: []}))]
})),
access: [APublic]
});
shadowClass.fields.push({
name: "__allowSetGet",
pos: Context.currentPos(),
kind: FVar(TPath({
pack: [],
name: 'Bool',
}), macro true),
access: [APublic]
});
shadowClass.fields.push({
name: "__callGetter",
pos: Context.currentPos(),
kind: FFun({
ret: TPath({name: 'Dynamic', pack: []}),
params: [],
expr: macro {
__allowSetGet = false;
var v = __custom__variables.get("get_" + name)();
__allowSetGet = true;
return v;
},
args: [
{
name: "name",
opt: false,
meta: [],
type: TPath({name: "String", pack: []})
}
]
}),
access: [APublic]
});
shadowClass.fields.push({
name: "__callSetter",
pos: Context.currentPos(),
kind: FFun({
ret: TPath({name: 'Dynamic', pack: []}),
params: [],
expr: macro {
__allowSetGet = false;
var v = __custom__variables.get("set_" + name)(val);
__allowSetGet = true;
return v;
},
args: [
{
name: "name",
opt: false,
meta: [],
type: TPath({name: "String", pack: []})
},
{
name: "val",
opt: false,
meta: [],
type: TPath({name: "Dynamic", pack: []})
}
]
}),
access: [APublic]
});
// Todo: make it possible to override
@@ -317,40 +399,38 @@ class ClassExtendMacro {
var hgetField = if(hasHgetInSuper) {
macro {
if(this.__interp.variables.exists("get_" + name))
return this.__interp.variables.get("get_" + name)();
if (this.__interp.variables.exists(name))
return this.__interp.variables.get(name);
if(__allowSetGet && __custom__variables.exists("get_" + name))
return __callGetter(name);
if (__custom__variables.exists(name))
return __custom__variables.get(name);
return super.hget(name);
}
} else {
macro {
if(this.__interp.variables.exists("get_" + name))
return this.__interp.variables.get("get_" + name)();
if (this.__interp.variables.exists(name))
return this.__interp.variables.get(name);
if(__allowSetGet && __custom__variables.exists("get_" + name))
return __callGetter(name);
if (__custom__variables.exists(name))
return __custom__variables.get(name);
return UnsafeReflect.getProperty(this, name);
}
}
var hsetField = if(hasHsetInSuper) {
macro {
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(name)) {
this.__interp.variables.set(name, val);
if(__allowSetGet && __custom__variables.exists("set_" + name))
return __callSetter(name, val);
if (__custom__variables.exists(name)) {
__custom__variables.set(name, val);
return val;
}
return super.hset(this, name);
}
} else {
macro {
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(name)) {
this.__interp.variables.set(name, val);
if(__allowSetGet && __custom__variables.exists("set_" + name))
return __callSetter(name, val);
if (__custom__variables.exists(name)) {
__custom__variables.set(name, val);
return val;
}
UnsafeReflect.setProperty(this, name, val);
+37 -10
View File
@@ -56,19 +56,45 @@ class UnsafeReflect {
#end
}
public inline static function callMethod(o:Dynamic, func:haxe.Constraints.Function, args:Array<Dynamic>):Dynamic
public #if !cpp inline #end static function callFieldUnsafe(o:Dynamic, field:String, args:Array<Dynamic>):Dynamic {
#if cpp
untyped {
var func:Dynamic = o.__Field(field, untyped __cpp__("::hx::paccDynamic"));
untyped func.__SetThis(o);
return untyped func.__Run(args);
}
#else
return Reflect.callMethod(o, func, args);
/*untyped {
if (func != null && func.__GetType() == ObjectType.vtString) {
if (o == null)
throw cpp.ErrorConstants.invalidObject;
func = o.__Field(func, untyped __cpp__("::hx::paccDynamic"));
}
#end
}
public inline static function callMethod(o:Dynamic, func:haxe.Constraints.Function, args:Array<Dynamic>):Dynamic {
return Reflect.callMethod(o, func, args);
}
public #if !cpp inline #end static function callMethodSafe(o:Dynamic, func:haxe.Constraints.Function, args:Array<Dynamic>):Dynamic {
#if cpp
untyped {
if (func == null)
throw cpp.ErrorConstants.nullFunctionPointer;
untyped func.__SetThis(o);
return untyped func.__Run(args);
}*/
}
#else
return Reflect.callMethod(o, func, args);
#end
}
public #if !cpp inline #end static function callMethodUnsafe(o:Dynamic, func:haxe.Constraints.Function, args:Array<Dynamic>):Dynamic {
#if cpp
untyped {
untyped func.__SetThis(o);
return untyped func.__Run(args);
}
#else
return Reflect.callMethod(o, func, args);
#end
}
public inline static function fields(o:Dynamic):Array<String>
return Reflect.fields(o);
@@ -133,9 +159,10 @@ class UnsafeReflect {
#if cpp
if (o == null)
return null;
if (untyped o.__GetType() == ObjectType.vtString)
var t:Int = untyped o.__GetType();
if (t == ObjectType.vtString)
return o;
if (untyped o.__GetType() == ObjectType.vtArray)
if (t == ObjectType.vtArray)
return untyped o.__Field("copy", untyped __cpp__("::hx::paccDynamic"))();
var o2:Dynamic = {};
for (f in UnsafeReflect.fields(o))