Function Call reimplemented

The previous function call system has a serious issue. It can not differentiate between class fields and function argument fields.
This commit is contained in:
Jaime Humberto Macias Bustamante
2025-01-21 22:07:41 -07:00
parent c45373aa55
commit b25ecb08bc
4 changed files with 85 additions and 103 deletions
-1
View File
@@ -1,3 +1,2 @@
bin/build-each.hxml
-D hscriptPos
-hl bin/Test.hl
+54 -60
View File
@@ -84,6 +84,19 @@ class CustomClass implements IHScriptCustomAccessBehaviour{
switch (f.kind) {
case KFunction(fn):
_cachedFunctionDecls.set(f.name, fn);
#if hscriptPos
var fexpr:Expr = {
e: ExprDef.EFunction(fn.args, fn.body, f.name, fn.ret, false, false),
pmin: fn.body.pmin,
pmax: fn.body.pmax,
line: fn.body.line,
origin: fn.body.origin
};
#else
var fexpr = Expr.EFunction(fn.args, fn.body, f.name, fn.ret, false, false);
#end
var f0 = this.interp.expr(fexpr);
this.interp.variables.set(f.name, f0);
case KVar(v):
_cachedVarDecls.set(f.name, v);
if (v.expr != null) {
@@ -166,52 +179,30 @@ class CustomClass implements IHScriptCustomAccessBehaviour{
if (hasField(name)) {
var fn = getFunction(name);
var previousValues:Map<String, Dynamic> = [];
var i = 0;
for (a in fn.args) {
var value:Dynamic = null;
try {
if (fn == null)
interp.error(ECustom('${name} is not a function'));
if (args != null && i < args.length) {
value = args[i];
} else if (a.value != null) {
value = interp.expr(a.value);
}
// NOTE: We assign these as variables rather than locals because those get wiped when we enter the function.
if (interp.variables.exists(a.name)) {
previousValues.set(a.name, interp.variables.get(a.name));
}
interp.variables.set(a.name, value);
i++;
}
try{
r = interp.execute(fn.body);
}
catch(e:hscript.Expr.Error){
// A script error occurred while executing the script function.
r = UnsafeReflect.callMethodUnsafe(null, fn, args);
} catch (e:hscript.Expr.Error) {
// A script error occurred while executing the custom class function.
// Purge the function from the cache so it is not called again.
purgeFunction(name);
}
for (a in fn.args) {
if (previousValues.exists(a.name)) {
interp.variables.set(a.name, previousValues.get(a.name));
} else {
interp.variables.remove(a.name);
}
}
} else {
var fixedArgs = [];
// OVERRIDE CHANGE: Use _HX_SUPER__ when calling superclass
var fixedName = '_HX_SUPER__${name}';
for (a in args) {
if ((a is CustomClass)) {
fixedArgs.push(cast(a, CustomClass).superClass);
var customClass:CustomClass = cast(a, CustomClass).superClass;
fixedArgs.push(customClass.superClass != null ? customClass.superClass : customClass);
} else {
fixedArgs.push(a);
}
}
var superFn = Reflect.field(superClass, fixedName);
if(superFn == null) {
if (superFn == null) {
this.interp.error(ECustom('Error while calling function super.${name}(): EInvalidAccess'
+ '\n'
+ 'InvalidAccess error: Super function "${name}" does not exist! Define it or call the correct superclass function.'));
@@ -221,6 +212,8 @@ class CustomClass implements IHScriptCustomAccessBehaviour{
return r;
}
// Field check
private function hasField(name:String):Bool {
return _cachedFieldDecls != null ? _cachedFieldDecls.exists(name) : false;
}
@@ -241,10 +234,13 @@ class CustomClass implements IHScriptCustomAccessBehaviour{
return _cachedFunctionDecls != null ? _cachedFunctionDecls.exists(name) : false;
}
private function getFunction(name:String):FunctionDecl {
return _cachedFunctionDecls != null ? _cachedFunctionDecls.get(name) : null;
private function getFunction(name:String):Function {
var fn = this.interp.variables.get(name);
return Reflect.isFunction(fn) ? fn : null;
}
// SuperClass field check
private function cacheSuperField(name:String, value:Dynamic) {
if(_cachedSuperFields != null) {
_cachedSuperFields.set(name, value);
@@ -337,9 +333,9 @@ class CustomClass implements IHScriptCustomAccessBehaviour{
return r;
}
private function resolveField(name:String):Dynamic {
switch (name) {
case "superClass":
private function resolveField(name:String):Dynamic {
switch (name) {
case "superClass":
return this.superClass;
case "createSuperClass":
return this.createSuperClass;
@@ -347,7 +343,7 @@ class CustomClass implements IHScriptCustomAccessBehaviour{
return this.hasFunction;
case "callFunction":
return this.callFunction;
default:
default:
if (hasFunction(name)) {
var fn:Function = Reflect.makeVarArgs(function(args:Array<Dynamic>) {
return this.callFunction(name, args);
@@ -359,10 +355,9 @@ class CustomClass implements IHScriptCustomAccessBehaviour{
if (hasVar(name)) {
var value:Dynamic = null;
if(__allowSetGet && hasFunction('get_${name}')) {
value = __callGetter(name);
}
else if (this.interp.variables.exists(name)) {
if (__allowSetGet && hasFunction('get_${name}')) {
value = __callGetter(name);
} else if (this.interp.variables.exists(name)) {
value = this.interp.variables.get(name);
} else {
var v = getVar(name);
@@ -376,37 +371,36 @@ class CustomClass implements IHScriptCustomAccessBehaviour{
return value;
}
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 '"
+ Type.getClassName(Type.getClass(this.superClass)) + "'";
}
}
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 '"
+ Type.getClassName(Type.getClass(this.superClass)) + "'";
}
}
if (this.superClass is CustomClass) {
var superCustomClass:CustomClass = cast(this.superClass, CustomClass);
try {
superCustomClass.__allowSetGet = this.__allowSetGet;
superCustomClass.__allowSetGet = this.__allowSetGet;
return superCustomClass.hget(name);
} catch (e:Dynamic) {}
}
var fields = Type.getInstanceFields(Type.getClass(this.superClass));
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 {
throw "field '" + name + "' does not exist in custom class '" + this.className + "' or super class '"
+ Type.getClassName(Type.getClass(this.superClass)) + "'";
}
}
else {
throw "field '" + name + "' does not exist in custom class '" + this.className + "'";
}
}
return null;
}
} else {
throw "field '" + name + "' does not exist in custom class '" + this.className + "'";
}
}
return null;
}
}
+20 -10
View File
@@ -8,7 +8,7 @@ import hscript.Expr.FunctionDecl;
@:structInit
class CustomClassDecl implements IHScriptCustomAccessBehaviour {
public var classDecl:Expr.ClassDecl;
public var classDecl:Expr.ClassDecl; //This holds the class instantiation info
public var imports:Map<String, CustomClassImport>;
public var pkg:Null<Array<String>> = null;
@@ -27,6 +27,19 @@ class CustomClassDecl implements IHScriptCustomAccessBehaviour {
switch (f.kind) {
case KFunction(fn):
_cachedStaticFunctions.set(f.name, fn);
#if hscriptPos
var fexpr:Expr = {
e: ExprDef.EFunction(fn.args, fn.body, f.name, fn.ret, false, false),
pmin: fn.body.pmin,
pmax: fn.body.pmax,
line: fn.body.line,
origin: fn.body.origin
};
#else
var fexpr = Expr.EFunction(fn.args, fn.body, f.name, fn.ret, false, false);
#end
var f0 = this.staticInterp.expr(fexpr);
this.staticInterp.variables.set(f.name, f0);
case KVar(v):
_cachedStaticVariables.set(f.name, v);
if (v.expr != null) {
@@ -38,14 +51,10 @@ class CustomClassDecl implements IHScriptCustomAccessBehaviour {
}
}
public function callFunction(name:String, ?args:Array<Dynamic>) {
var func:FunctionDecl = getFunction(name);
public function callFunction(name:String, ?args:Array<Dynamic>):Dynamic {
var func:Function = getFunction(name);
if(func != null) {
return FunctionUtils.callStaticFunction(name, this, staticInterp, func, args != null ? args : []);
}
return null;
return FunctionUtils.callStaticFunction(name, this, staticInterp, func, args != null ? args : []);
}
public function hasField(name:String):Bool {
@@ -56,8 +65,9 @@ class CustomClassDecl implements IHScriptCustomAccessBehaviour {
return _cachedStaticFunctions.exists(name);
}
private function getFunction(name:String):FunctionDecl {
return _cachedStaticFunctions.get(name);
private function getFunction(name:String):Function {
var fn = this.staticInterp.variables.get(name);
return Reflect.isFunction(fn) ? fn : null;
}
private function hasVar(name:String):Bool {
+11 -32
View File
@@ -1,44 +1,23 @@
package hscript.customclass.utils;
import hscript.Expr.FunctionDecl;
import hscript.utils.UnsafeReflect;
import haxe.Constraints.Function;
@:access(hscript.customclass.CustomClassDecl)
class FunctionUtils {
public static function callStaticFunction(name:String, classDecl:CustomClassDecl, interp:Interp, fn:FunctionDecl, args:Array<Dynamic> = null) {
public static inline function callStaticFunction(name:String, classDecl:CustomClassDecl, interp:Interp, fn:Function, args:Array<Dynamic> = null) {
var r:Dynamic = null;
var previousValues:Map<String, Dynamic> = [];
var i = 0;
for (a in fn.args) {
var value:Dynamic = null;
if (args != null && i < args.length) {
value = args[i];
} else if (a.value != null) {
value = interp.expr(a.value);
}
// NOTE: We assign these as variables rather than locals because those get wiped when we enter the function.
if (interp.variables.exists(a.name)) {
previousValues.set(a.name, interp.variables.get(a.name));
}
interp.variables.set(a.name, value);
i++;
}
try {
r = interp.execute(fn.body);
} catch (e:hscript.Expr.Error) {
// A script error occurred while executing the script function.
// Purge the function from the cache so it is not called again.
classDecl.purgeFunction(name);
interp.error(#if hscriptPos e.e #else e #end);
}
if (fn == null)
interp.error(ECustom('${name} is not a function'));
for (a in fn.args) {
if (previousValues.exists(a.name)) {
interp.variables.set(a.name, previousValues.get(a.name));
} else {
interp.variables.remove(a.name);
}
r = UnsafeReflect.callMethodUnsafe(null, fn, args);
} catch (e:hscript.Expr.Error) {
// A script error occurred while executing the custom class function.
// Purge the function from the cache so it is not called again.
classDecl.purgeFunction(name);
interp.error(#if hscriptPos e.e #else e #end);
}
return r;