From b48a3ee9ed7e30d8f02ce1c81cf9efc520f2a28b Mon Sep 17 00:00:00 2001 From: Jaime Humberto Macias Bustamante Date: Fri, 20 Jun 2025 14:45:06 -0700 Subject: [PATCH] Allow for setting fields before super also improved fetching superclass fields --- hscript/CustomClass.hx | 65 +++++++++++++++++++++++++++--- hscript/macros/ClassExtendMacro.hx | 16 ++++++++ 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/hscript/CustomClass.hx b/hscript/CustomClass.hx index fbfcea2..bd81652 100644 --- a/hscript/CustomClass.hx +++ b/hscript/CustomClass.hx @@ -33,8 +33,10 @@ class CustomClass implements IHScriptCustomClassBehaviour { var __constructor:Function; var __overrideFields:Array = []; + var __cachedFieldSet:Map = null; + var initializing:Bool = false; - public function new(__class:CustomClassHandler, ?args:Array) { + public function new(__class:CustomClassHandler, ?args:Array, ?cachedFieldSet:Map) { this.__class = __class; __interp = new Interp(); @@ -64,15 +66,34 @@ class CustomClass implements IHScriptCustomClassBehaviour { __interp.scriptObject = this; + initializing = true; + + if(cachedFieldSet != null) + for(f => v in cachedFieldSet) + this.hset(f, v); + if (hasField('new')) { buildConstructor(); call('new', args); + if(__cachedFieldSet != null) { + __cachedFieldSet.clear(); + __cachedFieldSet = null; + } + if (this.__superClass == null && __class.extend != null) __interp.error(ECustom("super() not called")); } else if (__class.extend != null) { buildSuperClass(args); } + + initializing = false; + } + + function cacheFieldSet(name:String, val:Dynamic) { + if(!initializing) return; + if(__cachedFieldSet == null) __cachedFieldSet = []; + __cachedFieldSet.set(name, val); } function buildConstructor() { @@ -89,7 +110,7 @@ class CustomClass implements IHScriptCustomClassBehaviour { } if (__class.cl is CustomClassHandler) { - var customClass = new CustomClass(__class.cl, args); + var customClass = new CustomClass(__class.cl, args, __cachedFieldSet); if(__overrideFields.length > 0) { for (field in __overrideFields) { var func = __interp.variables.get(field); @@ -97,9 +118,11 @@ class CustomClass implements IHScriptCustomClassBehaviour { } } __superClass = customClass; - @:privateAccess - __interp.__instanceFields.concat(__superClass.__class__fields); + @:privateAccess __interp.__instanceFields = __interp.__instanceFields.concat(getSuperFields()); } else { + if(__cachedFieldSet != null) + UnsafeReflect.setField(__class.cl, "__cachedFieldSet", __cachedFieldSet); + var disallowCopy = Type.getInstanceFields(__class.cl); __superClass = Type.createInstance(__class.cl, args); __superClass.__real_fields = disallowCopy; @@ -115,7 +138,7 @@ class CustomClass implements IHScriptCustomClassBehaviour { if (fn != null && Reflect.isFunction(fn)) return UnsafeReflect.callMethodUnsafe(null, fn, (args == null) ? [] : args); else - __interp.error(ECustom('$name is not a function')); + __interp.error(ECustom('$name doesn\'t exists or is not a function')); return null; } @@ -167,7 +190,7 @@ class CustomClass implements IHScriptCustomClassBehaviour { cast(__superClass, CustomClass).overrideField(name, func); } } - // TODO: make this iterate over other extended Custom Classes + function superHasField(name:String) { if (__superClass == null) return false; @@ -175,9 +198,33 @@ class CustomClass implements IHScriptCustomClassBehaviour { var realFieldExists = __superClass.__real_fields != null && __superClass.__real_fields.contains(name); var classFieldExists = __superClass.__class__fields != null && __superClass.__class__fields.contains(name); + if(!realFieldExists && !classFieldExists && __superClass is CustomClass) + return cast(__superClass, CustomClass).superHasField(name); + return realFieldExists || classFieldExists; } + function getSuperFields():Array { + if(__superClass == null) return []; + + var classFields:Map = []; // Prevents duplicated values + var cls:Null = __superClass; + + while (cls != null) { + for(fieldSet in [cls.__class__fields, cls.__real_fields]) + for(f in fieldSet) + classFields.set(f, f); + var next:IHScriptCustomClassBehaviour = null; + if(cls is CustomClass) + next = cast(cls, CustomClass).__superClass; + if (next == null) + break; + cls = next; + } + + return [for(f in classFields) f]; + } + public function hget(name:String):Dynamic { switch (name) { case 'superClass': return __superClass; @@ -223,6 +270,10 @@ class CustomClass implements IHScriptCustomClassBehaviour { return __superClass.hset(name, val); } } + else if(__class.extend != null && initializing) { + cacheFieldSet(name, val); + return val; + } throw "field '" + name @@ -251,6 +302,8 @@ class CustomClass implements IHScriptCustomClassBehaviour { * @return Null */ public function getSuperclass():IHScriptCustomClassBehaviour { + if(__superClass == null) return null; + var cls:Null = __superClass; // Check if the superClass is another custom class, diff --git a/hscript/macros/ClassExtendMacro.hx b/hscript/macros/ClassExtendMacro.hx index d28575c..24fe6ba 100644 --- a/hscript/macros/ClassExtendMacro.hx +++ b/hscript/macros/ClassExtendMacro.hx @@ -348,6 +348,13 @@ class ClassExtendMacro { // Adding hscript getters and setters + shadowClass.fields.push({ + name: "__cachedFieldSet", + pos: Context.currentPos(), + kind: FVar(macro: Map), + access: [APublic, AStatic] + }); + shadowClass.fields.push({ name: "__interp", pos: Context.currentPos(), @@ -573,6 +580,15 @@ class ClassExtendMacro { expr: macro { // Call the super constructor with appropriate args super($a{superCallArgs}); + + if(__cachedFieldSet != null) { + for(k => v in __cachedFieldSet) { + Reflect.setProperty(this, k, v); + trace(k); + } + __cachedFieldSet.clear(); + __cachedFieldSet = null; + } } }), };