From f8a930cd48fb6b4f68a475d51a34b6b5ecefd7f8 Mon Sep 17 00:00:00 2001 From: Jaime Humberto Macias Bustamante Date: Sat, 12 Jul 2025 16:13:59 -0700 Subject: [PATCH] upcasting --- hscript/CustomClass.hx | 21 +++++- hscript/Interp.hx | 4 ++ hscript/macros/ClassExtendMacro.hx | 100 ++++++++++++++++++++++------- 3 files changed, 101 insertions(+), 24 deletions(-) diff --git a/hscript/CustomClass.hx b/hscript/CustomClass.hx index 4796a64..64ea7eb 100644 --- a/hscript/CustomClass.hx +++ b/hscript/CustomClass.hx @@ -28,6 +28,7 @@ class CustomClass implements IHScriptCustomClassBehaviour { var __class:CustomClassHandler; var __superClass:IHScriptCustomClassBehaviour; + var __upperClass:IHScriptCustomClassBehaviour; var __constructor:Function; var __overrideFields:Array = []; @@ -116,6 +117,7 @@ class CustomClass implements IHScriptCustomClassBehaviour { customClass.overrideField(field, func); } } + customClass.__upperClass = this; __superClass = customClass; @:privateAccess __interp.__instanceFields = __interp.__instanceFields.concat(getSuperFields()); } else { @@ -154,7 +156,7 @@ class CustomClass implements IHScriptCustomClassBehaviour { function getField(name:String, allowProperty:Bool = true):Dynamic { var f = __interp.variables.get(name); - if (allowProperty && f is Property) { + if (f != null && allowProperty && f is Property) { var prop:Property = cast f; prop.__allowSetGet = this.__allowSetGet; var r = prop.callGetter(name); @@ -166,7 +168,7 @@ class CustomClass implements IHScriptCustomClassBehaviour { function setField(name:String, val:Dynamic):Dynamic { var f = getField(name, false); - if (f is Property) { + if (f != null && f is Property) { var prop:Property = cast f; prop.__allowSetGet = this.__allowSetGet; var r = prop.callSetter(name, val); @@ -317,6 +319,21 @@ class CustomClass implements IHScriptCustomClassBehaviour { break; // Return the Custom Class itself cls = next; } + return cls is CustomClass ? this : cls; + } + + // TODO: scripted safe cast for custom classes + public function getUpperclass():IHScriptCustomClassBehaviour { + if(__upperClass == null) return this; + + var cls:CustomClass = cast __upperClass; + + while (cls != null) { + var prev:CustomClass = cast cls.__upperClass; + if(prev == null) + break; + cls = prev; + } return cls; } diff --git a/hscript/Interp.hx b/hscript/Interp.hx index 800c41b..8b5d462 100644 --- a/hscript/Interp.hx +++ b/hscript/Interp.hx @@ -116,6 +116,10 @@ class Interp { private function get_inCustomClass():Bool return hasScriptObject && _scriptObjectType == SCustomClass; + var __customClass(get, never):CustomClass; + private function get___customClass():CustomClass + return inCustomClass ? cast scriptObject : null; + public var errorHandler:Error->Void; public var importFailedCallback:Array->Bool; diff --git a/hscript/macros/ClassExtendMacro.hx b/hscript/macros/ClassExtendMacro.hx index 19556e3..bb915e7 100644 --- a/hscript/macros/ClassExtendMacro.hx +++ b/hscript/macros/ClassExtendMacro.hx @@ -480,22 +480,50 @@ class ClassExtendMacro { var hgetField = if(hasHgetInSuper) { macro { - if (__interp != null && __class__fields.contains(name)) { - var v:Dynamic = __interp.variables.get(name); - if(v != null && v is hscript.Property) - return cast(v, hscript.Property).callGetter(name); - return v; + if (__interp != null) { + if(__class__fields.contains(name)) { + var v:Dynamic = __interp.variables.get(name); + if(v != null && v is hscript.Property) + return cast(v, hscript.Property).callGetter(name); + return v; + } + else @:privateAccess { + var cls:hscript.CustomClass = cast __interp.__customClass.__upperClass; + while(cls != null) { + if(cls.hasField(name)) + return cls.getField(name); + + var prev:hscript.CustomClass = cast cls.__upperClass; + if(prev == null) + break; + cls = prev; + } + } } return super.hget(name); } } else { macro { - if (__interp != null && __class__fields.contains(name)) { - var v:Dynamic = __interp.variables.get(name); - if(v != null && v is hscript.Property) - return cast(v, hscript.Property).callGetter(name); - return v; + if (__interp != null) { + if(__class__fields.contains(name)) { + var v:Dynamic = __interp.variables.get(name); + if(v != null && v is hscript.Property) + return cast(v, hscript.Property).callGetter(name); + return v; + } + else @:privateAccess { + var cls:hscript.CustomClass = cast __interp.__customClass.__upperClass; + while(cls != null) { + if(cls.hasField(name)) + return cls.getField(name); + + var prev:hscript.CustomClass = cast cls.__upperClass; + if(prev == null) + break; + cls = prev; + } + } } return UnsafeReflect.getProperty(this, name); @@ -504,12 +532,26 @@ class ClassExtendMacro { var hsetField = if(hasHsetInSuper) { macro { - if (__interp != null && __class__fields.contains(name)) { - var v:Dynamic = __interp.variables.get(name); - if(v != null && v is hscript.Property) - return cast(v, hscript.Property).callSetter(name, val); - __interp.variables.set(name, val); - return val; + if (__interp != null) { + if(__class__fields.contains(name)) { + var v:Dynamic = __interp.variables.get(name); + if(v != null && v is hscript.Property) + return cast(v, hscript.Property).callSetter(name, val); + __interp.variables.set(name, val); + return val; + } + else @:privateAccess { + var cls:hscript.CustomClass = cast __interp.__customClass.__upperClass; + while(cls != null) { + if(cls.hasField(name)) + return cls.setField(name, val); + + var prev:hscript.CustomClass = cast cls.__upperClass; + if(prev == null) + break; + cls = prev; + } + } } if(__real_fields.contains(name)) { @@ -520,12 +562,26 @@ class ClassExtendMacro { } } else { macro { - if (__interp != null && __class__fields.contains(name)) { - var v:Dynamic = __interp.variables.get(name); - if(v != null && v is hscript.Property) - return cast(v, hscript.Property).callSetter(name, val); - __interp.variables.set(name, val); - return val; + if (__interp != null) { + if(__class__fields.contains(name)) { + var v:Dynamic = __interp.variables.get(name); + if(v != null && v is hscript.Property) + return cast(v, hscript.Property).callSetter(name, val); + __interp.variables.set(name, val); + return val; + } + else @:privateAccess { + var cls:hscript.CustomClass = cast __interp.__customClass.__upperClass; + while(cls != null) { + if(cls.hasField(name)) + return cls.setField(name, val); + + var prev:hscript.CustomClass = cast cls.__upperClass; + if(prev == null) + break; + cls = prev; + } + } } if(__real_fields.contains(name)) {