From 634d819cc2d9c4292c3c4ad268436c610bfdf9d2 Mon Sep 17 00:00:00 2001 From: Jaime Humberto Macias Bustamante Date: Thu, 30 Apr 2026 11:02:47 -0700 Subject: [PATCH] Refactor property fields Now you can call directly the getter/setter functions without triggering them again. --- hscript/Interp.hx | 69 ++++++++++++++++++++++++--------------------- hscript/Property.hx | 47 ++++++++++++++++++++++++++---- 2 files changed, 78 insertions(+), 38 deletions(-) diff --git a/hscript/Interp.hx b/hscript/Interp.hx index f50bdf0..daefe4d 100644 --- a/hscript/Interp.hx +++ b/hscript/Interp.hx @@ -28,6 +28,7 @@ */ package hscript; +import haxe.Exception; import haxe.ds.StringMap; import hscript.HEnum.HEnumValue; import haxe.CallStack; @@ -167,8 +168,12 @@ class Interp { var usingHandler:UsingHandler; - var varLocationCache:Map = new Map(); - var cacheValid:Bool = true; + // TODO: separate cache into a class + var varLocationCache:Map = []; + public var cacheValid(default, set):Bool = true; + function set_cacheValid(valid:Bool):Bool { + return cacheValid = valid; + } #if hscriptPos var curExpr:Expr; @@ -291,14 +296,16 @@ class Interp { var obj = resolve(id, false, false); if (obj != null && obj is Property) { var prop:Property = cast obj; - return prop.callSetter(id, v); + prop.__callingProperty = true; + return prop.callSetter(v); } varLocationCache.remove(id); setVar(id, v); } } else if (l.r is Property) { var prop:Property = cast l.r; - return prop.callSetter(id, v); + prop.__callingProperty = true; + return prop.callSetter(v); } else { l.r = v; if (l.depth == 0) { @@ -372,7 +379,8 @@ class Interp { var obj = resolve(id, true, false); if (obj != null && obj is Property) { var prop:Property = cast obj; - return prop.callSetter(id, v); + prop.__callingProperty = true; + return prop.callSetter(v); } varLocationCache.remove(id); setVar(id, v); @@ -382,7 +390,8 @@ class Interp { var l = locals.get(id); if (l.r is Property) { var prop:Property = cast l.r; - return prop.callSetter(id, v); + prop.__callingProperty = true; + return prop.callSetter(v); } l.r = v; if (l.depth == 0) { @@ -426,18 +435,19 @@ class Interp { var prop:Property = null; if (v is Property) { prop = cast v; - v = prop.callGetter(id); + prop.__callingProperty = true; + v = prop.callGetter(); } if (prefix) { v += delta; if (prop != null) - prop.callSetter(id, v); + prop.callSetter(v); else l.r = v; } else { if (prop != null) - prop.callSetter(id, v + delta); + prop.callSetter(v + delta); else l.r = v + delta; } @@ -448,20 +458,21 @@ class Interp { var prop:Property = null; if (v is Property) { prop = cast v; - v = prop.callGetter(id); + prop.__callingProperty = true; + v = prop.callGetter(); } if (prefix) { v += delta; if (prop != null) - prop.callSetter(id, v); + prop.callSetter(v); else { varLocationCache.remove(id); setVar(id, v); } } else { if (prop != null) - prop.callSetter(id, v + delta); + prop.callSetter(v + delta); else { varLocationCache.remove(id); setVar(id, v + delta); @@ -601,8 +612,11 @@ class Interp { } inline function getProperty(o:Null, n:String, allowProperty:Bool = true):Dynamic { - if(allowProperty && o != null && o is Property) - return cast(o, Property).callGetter(n); + if(allowProperty && o != null && o is Property) { + var prop:Property = cast o; + prop.__callingProperty = true; + return cast(o, Property).callGetter(); + } else return o; } @@ -725,14 +739,10 @@ class Interp { } public function invalidateCache():Void { - varLocationCache = new Map(); + varLocationCache.clear(); cacheValid = true; } - public function setCacheValid(valid:Bool):Void { - cacheValid = valid; - } - public static var importRedirects:Map = new Map(); public static function getImportRedirect(className:String):String { return importRedirects.exists(className) ? importRedirects.get(className) : className; @@ -748,6 +758,7 @@ class Interp { return className; } + // TODO: separate large declarations (EClass, EEnum, etc...) into inline functions public function expr(e:Expr):Dynamic { #if hscriptPos curExpr = e; @@ -1001,20 +1012,14 @@ class Interp { return null; } declared.push({n: n, old: locals.get(n), depth: depth}); - var r:Dynamic = (e == null) ? null : expr(e); - var declProp:Property = null; - if (hasGetSet) { - declProp = { - r: r, - getter: getter, - setter: setter, - isVar: isVar, - isStatic: isStatic, - interp: this, - } - } + var v:Dynamic = (e == null) ? null : expr(e); + var r:Dynamic = null; + if (hasGetSet) + r = new Property(n, v, getter, setter, isVar, isStatic, this); + else + r = v; var declVar:DeclaredVar = { - r: (!hasGetSet) ? r : declProp, + r: r, depth: depth }; locals.set(n, declVar); diff --git a/hscript/Property.hx b/hscript/Property.hx index 85dd576..641d665 100644 --- a/hscript/Property.hx +++ b/hscript/Property.hx @@ -26,11 +26,11 @@ import hscript.Expr.FieldPropertyAccess; * @see https://haxe.org/manual/class-field-property.html */ @:access(hscript.Interp) -@:structInit class Property { private static inline var GET = 'get_'; private static inline var SET = 'set_'; + public var name:String; public var r:Dynamic; public var getter:FieldPropertyAccess; public var setter:FieldPropertyAccess; @@ -43,24 +43,54 @@ class Property { var isVar:Bool; var interp:Interp; - public function new(r:Dynamic, getter:FieldPropertyAccess, setter:FieldPropertyAccess, isVar:Bool, isStatic:Bool, interp:Interp) { + @:allow(hscript.Interp) + private var getterFunc(get, never):String; + private function get_getterFunc():String { + return '$GET$name'; + } + + @:allow(hscript.Interp) + private var setterFunc(get, never):String; + private function get_setterFunc():String { + return '$SET$name'; + } + + public function new(name:String, r:Dynamic, getter:FieldPropertyAccess, setter:FieldPropertyAccess, isVar:Bool, isStatic:Bool, interp:Interp) { + this.name = name; this.r = r; this.getter = getter; this.setter = setter; this.isVar = isVar; this.__isStatic = isStatic; this.interp = interp; + + setLookup(); + } + + private inline function setLookup() { + /* + if(getter == AGet) + interp.propertyLookup.set(getterFunc, {isStatic: isStatic, func: () -> return callGetter()}); + if(setter == ASet) + interp.propertyLookup.set(setterFunc, {isStatic: isStatic, func: (v) -> return callSetter(v)}); + */ } var __allowReadAccess:Bool = false; var __allowWriteAccess:Bool = false; var __allowSetGet:Null = null; + + @:allow(hscript.Interp) + var __callingProperty:Bool = false; // flag to check if the get/set function hasn't been called directly + final __isStatic:Bool = false; - public function callGetter(name:String) { + public function callGetter():Dynamic { switch (getter) { case AGet | ADynamic: - var fName:String = '$GET$name'; + var fName:String = getterFunc;//'$GET$name'; + if(!__callingProperty) + __allowReadAccess = true; if (!__allowReadAccess && (__allowSetGet != null && __allowSetGet || !interp.isBypassAccessor)) { if (varExists(fName)) { return callAccessor(fName); @@ -80,10 +110,12 @@ class Property { return r; } - public function callSetter(name:String, val:Dynamic) { + public function callSetter(val:Dynamic):Dynamic { switch (setter) { case ASet | ADynamic: - var fName:String = '$SET$name'; + var fName:String = setterFunc;//'$SET$name'; + if(!__callingProperty) + __allowWriteAccess = true; if (!__allowWriteAccess && (__allowSetGet != null && __allowSetGet || !interp.isBypassAccessor)) { if (varExists(fName)) return callAccessor(fName, [val], true); @@ -115,6 +147,9 @@ class Property { if (isWrite) __allowWriteAccess = false; else __allowReadAccess = false; + if(__callingProperty) + __callingProperty = false; + return rt; } else interp.error(ECustom('Method $f required by property ${f.substr(3)} is missing'));