From b25ecb08bcae8ae34cf46a0d768f0850de93a4b5 Mon Sep 17 00:00:00 2001 From: Jaime Humberto Macias Bustamante Date: Tue, 21 Jan 2025 22:07:41 -0700 Subject: [PATCH] Function Call reimplemented The previous function call system has a serious issue. It can not differentiate between class fields and function argument fields. --- hscript.hxml | 1 - hscript/customclass/CustomClass.hx | 114 ++++++++++----------- hscript/customclass/CustomClassDecl.hx | 30 ++++-- hscript/customclass/utils/FunctionUtils.hx | 43 ++------ 4 files changed, 85 insertions(+), 103 deletions(-) diff --git a/hscript.hxml b/hscript.hxml index 3c99746..e9f3c44 100644 --- a/hscript.hxml +++ b/hscript.hxml @@ -1,3 +1,2 @@ bin/build-each.hxml --D hscriptPos -hl bin/Test.hl \ No newline at end of file diff --git a/hscript/customclass/CustomClass.hx b/hscript/customclass/CustomClass.hx index 90fb360..0fdc3f9 100644 --- a/hscript/customclass/CustomClass.hx +++ b/hscript/customclass/CustomClass.hx @@ -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 = []; - 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) { 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; + } } diff --git a/hscript/customclass/CustomClassDecl.hx b/hscript/customclass/CustomClassDecl.hx index f49c920..d3f9f95 100644 --- a/hscript/customclass/CustomClassDecl.hx +++ b/hscript/customclass/CustomClassDecl.hx @@ -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; public var pkg:Null> = 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) { - var func:FunctionDecl = getFunction(name); + public function callFunction(name:String, ?args:Array):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 { diff --git a/hscript/customclass/utils/FunctionUtils.hx b/hscript/customclass/utils/FunctionUtils.hx index 26f121a..399cf89 100644 --- a/hscript/customclass/utils/FunctionUtils.hx +++ b/hscript/customclass/utils/FunctionUtils.hx @@ -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 = null) { + public static inline function callStaticFunction(name:String, classDecl:CustomClassDecl, interp:Interp, fn:Function, args:Array = null) { var r:Dynamic = null; - var previousValues:Map = []; - 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;