solved possible issues + field check improved

This commit is contained in:
Jaime Humberto Macias Bustamante
2025-05-13 20:47:14 -07:00
parent a3b153eb99
commit 122fd03a29
2 changed files with 108 additions and 69 deletions
+39 -32
View File
@@ -275,18 +275,21 @@ class Interp {
public function setVar(name:String, v:Dynamic):Void {
if (_inCustomClass && _proxy.superClass != null) {
if (_proxy.superIsCustomClass) {
var oldPrivate = _proxy.__allowPrivateAccess;
_proxy.__allowPrivateAccess = true;
cast(_proxy.superClass, CustomClass).hset(name, v);
_proxy.__allowPrivateAccess = oldPrivate;
return;
}
else if (_proxy.superHasField(name)) {
if (_proxy.superHasField(name)) {
if (_proxy.superIsCustomClass) {
var oldPrivate = _proxy.__allowPrivateAccess;
_proxy.__allowPrivateAccess = true;
cast(_proxy.superClass, CustomClass).hset(name, v);
_proxy.__allowPrivateAccess = oldPrivate;
return;
}
Reflect.setProperty(_proxy.superClass, name, v);
return;
}
}
// Fallback to setting in local scope.
if (allowStaticVariables && staticVariables.exists(name))
staticVariables.set(name, v);
@@ -300,7 +303,6 @@ class Interp {
var v = expr(e2);
switch (Tools.expr(e1)) {
case EIdent(id):
// TODO: redo field check
// Make sure setting superclass/static fields directly works.
// Also ensures property functions are accounted for.
if (_inCustomClass) {
@@ -312,13 +314,14 @@ class Interp {
_proxy.__class.__allowPrivateAccess = oldPrivate;
return v;
}
if (_proxy.superClass == null && _proxy.__class.classDecl.extend != null && !_proxy.hasVar(id)) {
// Caches the declaration to set it once superClass is created
var v = expr(e2);
_proxy.cacheSuperField(id, v);
return v;
}
else {
else if(_proxy.hasField(id) || _proxy.superHasField(id)){
var oldPrivate = _proxy.__allowPrivateAccess;
try {
var v = expr(e2);
@@ -333,6 +336,7 @@ class Interp {
}
}
}
// Fallback, which calls set()
var l = locals.get(id);
if (l == null) {
if (_hasScriptObject && !varExists(id)) {
@@ -398,7 +402,7 @@ class Interp {
_proxy.cacheSuperField(f, v);
return v;
}
else {
else if (_proxy.hasField(f) || _proxy.superHasField(f)) {
var oldPrivate = _proxy.__allowPrivateAccess;
try {
var v = expr(e2);
@@ -455,21 +459,12 @@ class Interp {
_proxy.__class.__allowPrivateAccess = oldPrivate;
return v;
}
/*
else if (_proxy.superClass != null && _proxy.superHasField(id)) {
Reflect.setProperty(_proxy.superClass, id, v);
return v;
}
else if (_proxy.hasVar(id)) {
_proxy.hset(id, v);
return v;
}
*/
else if ((_proxy.superClass == null && _proxy.__class.classDecl.extend != null && !_proxy.hasVar(id))) {
_proxy.cacheSuperField(id, v);
return v;
}
else {
else if (_proxy.hasField(id) || _proxy.superHasField(id)) {
var oldPrivate = _proxy.__allowPrivateAccess;
try {
_proxy.__allowPrivateAccess = true;
@@ -552,7 +547,7 @@ class Interp {
_proxy.cacheSuperField(f, v);
return v;
}
else {
else if (_proxy.hasField(f) || _proxy.superHasField(f)) {
var oldPrivate = _proxy.__allowPrivateAccess;
try {
v = fop(get(obj, f), expr(e2));
@@ -787,13 +782,14 @@ class Interp {
return r;
}
// We are calling a LOCAL function from the same module.
// TODO: optimize this
if (_proxy.hasFunction(id)) {
_nextCallObject = _proxy;
return _proxy.hget(id);
}
if (_proxy.superHasField(id)) {
_nextCallObject = _proxy.superClass;
return Reflect.getProperty(_proxy.superClass, id);
return !_proxy.superIsCustomClass ? Reflect.getProperty(_proxy.superClass, id) : _proxy.hget(id);
} else {
var oldPrivate = _proxy.__allowPrivateAccess;
try {
@@ -803,9 +799,9 @@ class Interp {
_proxy.__allowPrivateAccess = oldPrivate;
return r;
} catch (e:Dynamic) {
_proxy.__allowPrivateAccess = oldPrivate;
if(doException)
error(EUnknownVariable(id));
_proxy.__allowPrivateAccess = oldPrivate;
}
}
}
@@ -1729,13 +1725,21 @@ class Interp {
return _setRedirect(o, f, v);
if (o is IHScriptCustomAccessBehaviour) {
var obj:IHScriptCustomAccessBehaviour = cast o;
if(isBypassAccessor) {
var oldAccessor = obj.__allowSetGet;
var oldPrivate = obj.__allowPrivateAccess;
if(isBypassAccessor)
obj.__allowSetGet = false;
var res = obj.hset(f, v);
obj.__allowSetGet = true;
return res;
}
return obj.hset(f, v);
if(isPrivateAccess)
obj.__allowPrivateAccess = true;
var res = obj.hset(f, v);
obj.__allowSetGet = oldAccessor;
obj.__allowPrivateAccess = oldPrivate;
return res;
}
if (o is IHScriptCustomBehaviour) {
@@ -1866,7 +1870,7 @@ class Interp {
// Force call super function.
if(o == _proxy.superClass) {
if(_proxy.superIsCustomClass)
cast(_proxy.superClass, CustomClass).callFunction(f, args);
return cast(_proxy.superClass, CustomClass).callFunction(f, args);
else
return call(o, Reflect.field(_proxy.superClass, '_HX_SUPER__${f}'), args);
}
@@ -1898,12 +1902,15 @@ class Interp {
function call(o:Dynamic, f:Dynamic, args:Array<Dynamic>):Dynamic {
if (_inCustomClass) {
// Calling fn() in hscript won't resolve an object first. Thus, we need to change it to use this.fn() instead.
if (o == null && _nextCallObject != null) {
o = _nextCallObject;
}
if (f == null) {
error(EInvalidAccess(f));
}
if (o == _proxy) {
// If we are calling this.fn(), special handling is needed to prevent the local scope from being destroyed.
// By checking `o == _proxy`, we handle BOTH fn() and this.fn().
+69 -37
View File
@@ -278,15 +278,36 @@ class CustomClass implements IHScriptCustomAccessBehaviour {
}
var __superClassFieldList:Array<String> = null;
// ONLY FOR REAL CLASSES. CUSTOM CLASSES CHECKS FOR THEIR FIELDS ON `hget/hset`
public function superHasField(name:String):Bool {
if (superClass == null)
return false;
// Reflect.hasField(this, name) is REALLY expensive so we use a cache.
if (__superClassFieldList == null) {
var realFields = Reflect.fields(superClass).concat(Type.getInstanceFields(Type.getClass(superClass)));
__superClassFieldList = realFields;
__superClassFieldList = [];
if(superClass is CustomClass) {
var cls:Null<Dynamic> = superClass;
while(cls != null && cls is CustomClass) {
var currentClass = cast(cls, CustomClass);
var fields = [for(f in currentClass.__cachedFieldDecls.keys()) f];
__superClassFieldList.concat(fields);
var next = currentClass.superClass;
if(next == null)
break;
cls = next;
}
// The last fetched class is a real class
if(!(cls is CustomClass))
__superClassFieldList.concat(Reflect.fields(cls).concat(Type.getInstanceFields(Type.getClass(cls))));
}
else {
var realFields = Reflect.fields(superClass).concat(Type.getInstanceFields(Type.getClass(superClass)));
__superClassFieldList.concat(realFields);
}
}
return __superClassFieldList.indexOf(name) != -1;
@@ -348,25 +369,30 @@ class CustomClass implements IHScriptCustomAccessBehaviour {
}
if (this.superClass != null) {
if (Type.getClass(this.superClass) == null) {
// Anonymous structure
if (Reflect.hasField(this.superClass, name))
return Reflect.field(this.superClass, name);
else
throw "field '" + name + "' does not exist in custom class '" + this.className + "' or super class '[ANONYMOUS STRUCTURE]'";
}
if (superHasField(name)) {
if (Type.getClass(this.superClass) == null) {
// Anonymous structure
if (Reflect.hasField(this.superClass, name))
return Reflect.field(this.superClass, name);
else
throw "field '" + name + "' does not exist in custom class '" + this.className + "' or super class '[ANONYMOUS STRUCTURE]'";
}
if (this.superClass is CustomClass) {
var superCustomClass:CustomClass = cast(this.superClass, CustomClass);
superCustomClass.__allowSetGet = this.__allowSetGet;
return superCustomClass.hget(name);
if (this.superClass is CustomClass) {
var superCustomClass:CustomClass = cast(this.superClass, CustomClass);
superCustomClass.__allowSetGet = this.__allowSetGet;
superCustomClass.__allowPrivateAccess = this.__allowPrivateAccess;
return superCustomClass.hget(name);
}
// Real Class
if (__allowSetGet)
Reflect.getProperty(this.superClass, name);
else
Reflect.field(this.superClass, name);
}
// Real Class
var fields = Type.getInstanceFields(Type.getClass(this.superClass));
if (fields.contains(name))
return __allowSetGet ? Reflect.getProperty(this.superClass, name) : Reflect.field(this.superClass, name);
else
else
throw "field '" + name + "' does not exist in custom class '" + this.className + "' or super class '" + Type.getClassName(Type.getClass(this.superClass)) + "'";
}
else
@@ -393,27 +419,33 @@ class CustomClass implements IHScriptCustomAccessBehaviour {
}
this.interp.variables.set(name, val);
} else if (this.superClass != null) {
if (this.superClass is CustomClass) {
var superCustomClass:CustomClass = cast(this.superClass, CustomClass);
superCustomClass.__allowSetGet = this.__allowSetGet;
return superCustomClass.hset(name, val);
}
// Real Class
if (Type.getClass(this.superClass) == null) {
// Anonymous structure
if (Reflect.hasField(this.superClass, name))
Reflect.setField(this.superClass, name, val);
return val;
}
else if (superHasField(name)) {
}
else if (this.superClass != null) {
if (superHasField(name)) {
if (Type.getClass(this.superClass) == null) {
// Anonymous structure
if (Reflect.hasField(this.superClass, name)) {
Reflect.setField(this.superClass, name, val);
return val;
}
else
throw "field '" + name + "' does not exist in custom class '" + this.className + "' or super class '[ANONYMOUS STRUCTURE]'";
}
if (this.superClass is CustomClass) {
var superCustomClass:CustomClass = cast(this.superClass, CustomClass);
superCustomClass.__allowSetGet = this.__allowSetGet;
superCustomClass.__allowPrivateAccess = this.__allowPrivateAccess;
return superCustomClass.hset(name, val);
}
// Real Class
if (__allowSetGet)
Reflect.setProperty(this.superClass, name, val);
else
Reflect.setField(this.superClass, name, val);
}
}
else
throw "field '" + name + "' does not exist in custom class '" + this.className + "' or super class '" + Type.getClassName(Type.getClass(this.superClass)) + "'";
}