From a4d2d4c788257cb6c0d6b8ad4afc33b7e9405036 Mon Sep 17 00:00:00 2001 From: Jaime Humberto Macias Bustamante Date: Mon, 16 Jun 2025 22:24:22 -0700 Subject: [PATCH] Custom Classes rework progress - 2 --- hscript/CustomClass.hx | 271 ++++++++++++++++-------- hscript/CustomClassHandler.hx | 79 +++++-- hscript/IHScriptCustomClassBehaviour.hx | 1 - hscript/Interp.hx | 61 ++++-- hscript/Parser.hx | 14 +- hscript/Property.hx | 5 +- hscript/macros/ClassExtendMacro.hx | 79 ++++--- 7 files changed, 357 insertions(+), 153 deletions(-) diff --git a/hscript/CustomClass.hx b/hscript/CustomClass.hx index 63162e0..c02a4f9 100644 --- a/hscript/CustomClass.hx +++ b/hscript/CustomClass.hx @@ -2,9 +2,11 @@ package hscript; import hscript.utils.UnsafeReflect; import haxe.Constraints.Function; + using Lambda; // TODO + /** * The Custom Class core. * @@ -13,117 +15,214 @@ using Lambda; * @author Jamextreme140 */ @:access(hscript.CustomClassHandler) -class CustomClass implements IHScriptCustomClassBehaviour{ +@:access(hscript.Property) +class CustomClass implements IHScriptCustomClassBehaviour { + public var className(get, never):String; - public var className(get, never):String; - private function get_className():String - return __class.name; + private function get_className():String + return __class.name; - public var __interp:Interp; - public var __custom__variables:Map; // TODO: remove this - public var __real_fields:Array; - public var __class__fields:Array; // Declared fields + public var __interp:Interp; + public var __real_fields:Array = []; // UNUSED + public var __class__fields:Array = []; // Declared fields - public var __allowSetGet:Bool = true; + public var __allowSetGet:Bool = true; - var __class:CustomClassHandler; - var __superClass:IHScriptCustomClassBehaviour; - var __constructor:Function; - var fields:Array; - - public function new(__class:CustomClassHandler, args:Array) { - this.__class = __class; + var __class:CustomClassHandler; + var __superClass:IHScriptCustomClassBehaviour; + var __constructor:Function; + var fields:Array; - __interp = new Interp(); - __interp.errorHandler = __class.staticInterp.errorHandler; - __interp.importFailedCallback = __class.staticInterp.importFailedCallback; + public function new(__class:CustomClassHandler, args:Array) { + this.__class = __class; - __interp.variables = __class.staticInterp.variables; // This will access to static fields - __interp.allowPublicVariables = __class.ogInterp.allowPublicVariables; - __interp.publicVariables = __class.ogInterp.publicVariables; - __interp.allowStaticVariables = __class.ogInterp.allowStaticVariables; - __interp.staticVariables = __class.ogInterp.staticVariables; + __interp = new Interp(); + __interp.errorHandler = __class.staticInterp.errorHandler; + __interp.importFailedCallback = __class.staticInterp.importFailedCallback; - __interp.scriptObject = this; + __interp.variables = __class.staticInterp.variables; // This will access to static fields + __interp.publicVariables = __class.ogInterp.publicVariables; + __interp.staticVariables = __class.ogInterp.staticVariables; - this.fields = __class.fields; - for(f in fields) { - switch(Tools.expr(f)) { - case EVar(n): - __class__fields.push(n); - case EFunction(_, _, n): - __class__fields.push(n); - default: - } - @:privateAccess __interp.exprReturn(f); - } + this.fields = __class.fields; + for (f in fields) { + switch (Tools.expr(f)) { + case EVar(n): + __class__fields.push(n); + case EFunction(_, _, n): + __class__fields.push(n); + default: + } + @:privateAccess __interp.exprReturn(f); + } - if(hasField('new')) { - buildConstructor(); - call('new', args); + __interp.scriptObject = this; - if(this.__superClass == null && __class.extend != null) - __interp.error(ECustom("super() not called")); - } - else if(__class.extend != null) { - buildSuperClass(args); - } - - } + if (hasField('new')) { + buildConstructor(); + call('new', args); - function buildConstructor() { - __constructor = Reflect.makeVarArgs(buildSuperClass); - } + if (this.__superClass == null && __class.extend != null) + __interp.error(ECustom("super() not called")); + } else if (__class.extend != null) { + buildSuperClass(args); + } + } - function buildSuperClass(?args:Array) { - if(args == null) - args = []; + function buildConstructor() { + __constructor = Reflect.makeVarArgs(buildSuperClass); + } - if(__class.cl == null) __interp.error(ECustom('Current class does not have a super')); + function buildSuperClass(?args:Array) { + if (args == null) + args = []; + + if (__class.cl == null) { + __interp.error(ECustom('Current class does not have a super')); + return; + } if (__class.cl == CustomClassHandler) { __superClass = new CustomClass(__class.cl, args); + @:privateAccess + __interp.__instanceFields.concat(__superClass.__class__fields); } else { var disallowCopy = Type.getInstanceFields(__class.cl); __superClass = Type.createInstance(__class.cl, args); __superClass.__real_fields = disallowCopy; - __superClass.__interp = this.__interp; + __superClass.__class__fields = this.__class__fields; + __superClass.__interp = this.__interp; } - } + } - function call(name:String, ?args:Array):Dynamic { - var fn = __interp.variables.get(name); - if(fn != null && Reflect.isFunction(fn)) - return UnsafeReflect.callMethodUnsafe(null, fn, (args == null) ? [] : args); - - __interp.error(ECustom('$name is not a function')); - return null; - } + public function call(name:String, ?args:Array):Dynamic { + var fn = __interp.variables.get(name); + if (fn != null && Reflect.isFunction(fn)) + return UnsafeReflect.callMethodUnsafe(null, fn, (args == null) ? [] : args); + else + __interp.error(ECustom('$name is not a function')); + return null; + } - function hasField(name:String) { - return __interp.variables.exists(name); - } + function hasField(name:String) { + // return __interp.variables.exists(name); + return __class__fields.contains(name); + } - public function hget(name:String):Dynamic { - switch (name) { - case 'superClass': return __superClass; - case 'superConstructor': return __constructor; - } - return null; - } + function getField(name:String, allowProperty:Bool = true):Dynamic { + var f = __interp.variables.get(name); + if (allowProperty && f is Property) { + var prop:Property = cast f; + prop.__allowSetGet = this.__allowSetGet; + var r = prop.callGetter(name); + prop.__allowSetGet = null; + return r; + } + return f; + } - public function __callGetter(name:String):Dynamic { - return null; - } + function setField(name:String, val:Dynamic):Dynamic { + var f = getField(name, false); + if (f is Property) { + var prop:Property = cast f; + prop.__allowSetGet = this.__allowSetGet; + var r = prop.callSetter(name, val); + prop.__allowSetGet = null; + return r; + } + __interp.variables.set(name, val); + return val; + } - public function hset(name:String, val:Dynamic):Dynamic { - return null; - } + function superHasField(name:String) { + if (__superClass == null) + return false; - public function __callSetter(name:String, val:Dynamic):Dynamic { - return null; - } + var realFieldExists = __superClass.__real_fields != null && __superClass.__real_fields.contains(name); + var classFieldExists = __superClass.__class__fields != null && __superClass.__class__fields.contains(name); - public function toString():String - return className; -} \ No newline at end of file + return realFieldExists || classFieldExists; + } + + public function hget(name:String):Dynamic { + switch (name) { + case 'superClass': return __superClass; + case 'superConstructor': return __constructor; + default: + if (hasField(name)) + return getField(name); + + if (__superClass != null) { + if (superHasField(name)) { + __superClass.__allowSetGet = this.__allowSetGet; + return __superClass.hget(name); + } + } + + throw "field '" + + name + + "' does not exist in custom class '" + + this.className + + "'" + + (__superClass != null ? "' or super class '" + Type.getClassName(Type.getClass(this.__superClass)) + "'" : ""); + } + return null; + } + + public function hset(name:String, val:Dynamic):Dynamic { + if (hasField(name)) { + return setField(name, val); + } + + if (__superClass != null) { + if (superHasField(name)) { + __superClass.__allowSetGet = this.__allowSetGet; + return __superClass.hset(name, val); + } + } + + throw "field '" + + name + + "' does not exist in custom class '" + + this.className + + "'" + + (__superClass != null ? "' or super class '" + Type.getClassName(Type.getClass(this.__superClass)) + "'" : ""); + + return null; + } + + // UNUSED + public function __callGetter(name:String):Dynamic { + return null; + } + + public function __callSetter(name:String, val:Dynamic):Dynamic { + return null; + } + + /** + * Returns the real superClass if the Custom Class + * extends another Custom Class, and so on until + * it reaches a real class, otherwise it will + * return the last fetched Custom Class + * @return Null + */ + public function getSuperclass():IHScriptCustomClassBehaviour { + var cls:Null = this.__superClass; + + // Check if the superClass is another custom class, + // so it will find for a real class, otherwise + // returns the last super CustomClass parent. + while (cls != null && cls is CustomClass) { + var next = cast(cls, CustomClass).__superClass; + if (next == null) + break; // Return the Custom Class itself + cls = next; + } + + return cls; + } + + public function toString():String + return className; +} diff --git a/hscript/CustomClassHandler.hx b/hscript/CustomClassHandler.hx index 4beaa82..11b79f8 100644 --- a/hscript/CustomClassHandler.hx +++ b/hscript/CustomClassHandler.hx @@ -8,7 +8,8 @@ using StringTools; /** * Provides handlers for static custom class fields and instantiation. */ -class CustomClassHandler implements IHScriptCustomConstructor implements IHScriptCustomBehaviour{ +@:access(hscript.Property) +class CustomClassHandler implements IHScriptCustomConstructor implements IHScriptCustomAccessBehaviour{ public static var staticHandler = new StaticHandler(); public var __allowSetGet:Bool = true; @@ -36,10 +37,11 @@ class CustomClassHandler implements IHScriptCustomConstructor implements IHScrip this.cl = ogInterp.customClasses.get(extend); else this.cl = Type.resolveClass('${extend}_HSX'); + + if(cl == null) + ogInterp.error(EInvalidClass(extend)); } //this.cl = extend == null ? CustomTemplateClass : Type.resolveClass('${extend}_HSX'); - //if(cl == null) - // ogInterp.error(EInvalidClass(extend)); initStatic(); } @@ -51,28 +53,30 @@ class CustomClassHandler implements IHScriptCustomConstructor implements IHScrip staticInterp.importFailedCallback = ogInterp.importFailedCallback; staticInterp.variables = ogInterp.variables; - staticInterp.allowPublicVariables = ogInterp.allowPublicVariables; staticInterp.publicVariables = ogInterp.publicVariables; - staticInterp.allowStaticVariables = ogInterp.allowStaticVariables; staticInterp.staticVariables = ogInterp.staticVariables; - // TODO: optimize this for(ex in fields) { + var varOrFunction:Int = -1; // 0 - variable | 1 - function + var staticField:Bool = false; + var fieldName:String = ""; switch (Tools.expr(ex)) { case EVar(n, _, _, _, isStatic, _, _, _, _, _, _): - if(isStatic) { - staticInterp.exprReturn(ex); - staticFields.push(n); - fields.remove(ex); - } + varOrFunction = 0; + staticField = isStatic; + fieldName = n; case EFunction(_, _, n, _, _, isStatic, _, _, _, _): - if(isStatic) { - staticInterp.exprReturn(ex); - staticFields.push(n); - fields.remove(ex); - } + varOrFunction = 1; + staticField = isStatic; + fieldName = n; default: } + + if(staticField && varOrFunction > -1) { + staticInterp.exprReturn(ex); + staticFields.push(fieldName); + fields.remove(ex); + } } } @@ -195,19 +199,58 @@ class CustomClassHandler implements IHScriptCustomConstructor implements IHScrip } */ + // I can't believe all these lines of code above got reduced to this sentence. var _class = new CustomClass(this, args); return _class; } + function hasField(name:String) { + return staticFields.contains(name); + } + + function getField(name:String, allowProperty:Bool = true):Dynamic { + var f = staticInterp.variables.get(name); + if(f is Property && allowProperty) { + var prop:Property = cast f; + prop.__allowSetGet = this.__allowSetGet; + var r = prop.callGetter(name); + prop.__allowSetGet = null; + return r; + } + return f; + } + + function setField(name:String, val:Dynamic):Dynamic { + var f = getField(name, false); + if(f is Property) { + var prop:Property = cast f; + prop.__allowSetGet = this.__allowSetGet; + var r = prop.callSetter(name, val); + prop.__allowSetGet = null; + return r; + } + staticInterp.variables.set(name, val); + return val; + } + public function hget(name:String):Dynamic { + if(hasField(name)) { + return getField(name); + } + throw "field '"+ name+ "' does not exist in class '"+ this.name+ "'"; return null; } public function hset(name:String, val:Dynamic):Dynamic { + if(hasField(name)) + return setField(name, val); + + throw "field '"+ name+ "' does not exist in class '"+ this.name+ "'"; return null; } + // UNUSED public function __callGetter(name:String):Dynamic { return null; } @@ -220,7 +263,7 @@ class CustomClassHandler implements IHScriptCustomConstructor implements IHScrip return name; } } - +/* class CustomTemplateClass implements IHScriptCustomClassBehaviour { public var __interp:Interp; public var __allowSetGet:Bool = true; @@ -265,7 +308,7 @@ class CustomTemplateClass implements IHScriptCustomClassBehaviour { return v; } } - +*/ /** * This is for backwards compatibility with old hscript-improved, since some scripts use it diff --git a/hscript/IHScriptCustomClassBehaviour.hx b/hscript/IHScriptCustomClassBehaviour.hx index c8ee98a..9a2711e 100644 --- a/hscript/IHScriptCustomClassBehaviour.hx +++ b/hscript/IHScriptCustomClassBehaviour.hx @@ -2,7 +2,6 @@ package hscript; interface IHScriptCustomClassBehaviour extends IHScriptCustomAccessBehaviour{ public var __interp:Interp; - public var __custom__variables:Map; public var __real_fields:Array; public var __class__fields:Array; diff --git a/hscript/Interp.hx b/hscript/Interp.hx index 41d3237..fe59f28 100644 --- a/hscript/Interp.hx +++ b/hscript/Interp.hx @@ -65,6 +65,7 @@ class RedeclaredVar { public var depth:Int; } +@:access(hscript.CustomClass) @:analyzer(optimize, local_dce, fusion, user_var_fusion) class Interp { private var hasScriptObject(get, never):Bool; @@ -117,7 +118,7 @@ class Interp { public var errorHandler:Error->Void; public var importFailedCallback:Array->Bool; - public var customClasses:Map; // make this static ??? + public var customClasses:Map; public var variables:Map; public var publicVariables:Map; public var staticVariables:Map; @@ -587,7 +588,7 @@ class Interp { #end } - public function resolve(id:String, doException:Bool = true, getProperty:Bool = true):Dynamic { + public function resolve(id:String, doException:Bool = true, allowProperty:Bool = true):Dynamic { if (id == null) return null; id = StringTools.trim(id); @@ -601,7 +602,7 @@ class Interp { if (locals.exists(id)) { var l = locals.get(id); if(l != null) { - if(l.r != null && l.r is Property && getProperty) + if(l.r != null && l.r is Property && allowProperty) return cast(l.r, Property).callGetter(id); else return l.r; @@ -618,7 +619,7 @@ class Interp { r = staticVariables.get(id); if(r != null) { - if(r is Property && getProperty) + if(r is Property && allowProperty) return cast(r, Property).callGetter(id); else return r; @@ -846,7 +847,7 @@ class Interp { error(EInvalidOp(op)); } case ECall(e, params): - var args:Array = [for(p in params) expr(p)]; + var args:Array = makeArgs(params); switch (Tools.expr(e)) { case EField(e, f, s): @@ -1063,10 +1064,7 @@ class Interp { return arr[index]; } case ENew(cl, params): - var a = []; - for (e in params) - a.push(expr(e)); - return cnew(cl, a); + return cnew(cl, makeArgs(params)); case EThrow(e): throw expr(e); case ETry(e, n, _, ecatch): @@ -1189,6 +1187,26 @@ class Interp { return v; } + function makeArgs(params:Array):Array { + var args:Array = []; + for (p in params) { + switch (Tools.expr(p)) { + case EIdent(id): + var ident = resolve(id); + if (ident is CustomClass) { + var customClass:CustomClass = cast ident; // Pass the underlying superclass if exist + args.push(customClass.__superClass != null ? customClass.getSuperclass() : customClass); + } else { + args.push(ident); + } + default: + args.push(expr(p)); + } + } + + return args; + } + function forLoop(n:String, it:Expr, e:Expr, ?ithv:String):Void { var isKeyValue = ithv != null; var old = declared.length; @@ -1333,16 +1351,29 @@ class Interp { } function fcall(o:Dynamic, f:String, args:Array):Dynamic { - if(hasScriptObject && o == CustomClassHandler.staticHandler) { - return UnsafeReflect.callMethodUnsafe(scriptObject, UnsafeReflect.field(scriptObject, "_HX_SUPER__" + f), args); + // Custom logic to handle super calls to prevent infinite recursion + if(inCustomClass) { + if (o == scriptObject.__superClass) { + if (scriptObject.__superClass is CustomClass) + return cast(scriptObject.__superClass, CustomClass).call(f, args); + else + return return UnsafeReflect.callMethodUnsafe(scriptObject.__superClass, UnsafeReflect.field(scriptObject.__superClass, '_HX_SUPER__$f'), args); + } } - return call(o, get(o, f), args); + + var func = get(o, f); + // Workaround for an HTML5-specific issue. + // https://github.com/HaxeFoundation/haxe/issues/11298 + #if js + if (func == null && f == "contains") { + func = get(o, "includes"); + } + #end + + return call(o, func, args); } function call(o:Dynamic, f:Dynamic, args:Array):Dynamic { - if(f == CustomClassHandler.staticHandler) { - return null; - } return UnsafeReflect.callMethodSafe(o, f, args); } diff --git a/hscript/Parser.hx b/hscript/Parser.hx index a4e301c..58b5bb7 100644 --- a/hscript/Parser.hx +++ b/hscript/Parser.hx @@ -465,15 +465,25 @@ class Parser { case TBkOpen: var a = []; tk = token(); + var first = true; while( tk != TBkClose && (!resumeErrors || tk != TEof) ) { + if (!first) { + if (tk != TComma) + unexpected(tk); + else { + tk = token(); + if (tk == TBkClose) + break; + } + + } + first = false; push(tk); var oldoo = disableOrOp; disableOrOp = false; a.push(parseExpr()); disableOrOp = oldoo; tk = token(); - if( tk == TComma ) - tk = token(); } if( a.length == 1 && a[0] != null ) // What is this for??? switch( expr(a[0]) ) { diff --git a/hscript/Property.hx b/hscript/Property.hx index c01d40a..074ba10 100644 --- a/hscript/Property.hx +++ b/hscript/Property.hx @@ -16,12 +16,13 @@ class Property { var __allowReadAccess:Bool = false; var __allowWriteAccess:Bool = false; + var __allowSetGet:Null = null; public function callGetter(name:String) { switch (getter) { case AGet | ADynamic: var fName:String = 'get_$name'; - if (!__allowReadAccess && !interp.isBypassAccessor) { + if (!__allowReadAccess && (__allowSetGet != null && __allowSetGet || !interp.isBypassAccessor)) { if (interp.varExists(fName)) { return callAccessor(fName); } else @@ -44,7 +45,7 @@ class Property { switch (setter) { case ASet | ADynamic: var fName:String = 'set_$name'; - if (!__allowWriteAccess && !interp.isBypassAccessor) { + if (!__allowWriteAccess && (__allowSetGet != null && __allowSetGet || !interp.isBypassAccessor)) { if (interp.varExists(fName)) return callAccessor(fName, [val], true); else diff --git a/hscript/macros/ClassExtendMacro.hx b/hscript/macros/ClassExtendMacro.hx index 18e5c59..c5d2088 100644 --- a/hscript/macros/ClassExtendMacro.hx +++ b/hscript/macros/ClassExtendMacro.hx @@ -61,6 +61,7 @@ class ClassExtendMacro { if(key == "away3d.tools.commands.Weld") return fields; // Error: Unknown identifier if(fkey == "hscript.CustomClassHandler.TemplateClass") return fields; // Error: Redefined if(fkey == "hscript.CustomClassHandler.CustomTemplateClass") return fields; // Error: Redefined + if(fkey == "hscript.CustomClass") return fields; // Error: Redefined if(key == "sys.thread.EventLoop") return fields; // Error: cant override force inlined if(Config.DISALLOW_CUSTOM_CLASSES.contains(cl.module) || Config.DISALLOW_CUSTOM_CLASSES.contains(fkey)) return fields; if(cl.module.contains("_")) return fields; // Weird issue, sorry @@ -210,7 +211,15 @@ class ClassExtendMacro { if (f == null) continue; if (f.name == "new") { - hasNew = true; + switch (f.kind) { + case FFun(fn): + var constructor:Field = buildConstructor(fn.args); + + shadowClass.fields.push(constructor); + definedFields.push(f.name); + default: + continue; + } continue; } if (f.name.startsWith(FUNC_PREFIX)) @@ -245,7 +254,7 @@ class ClassExtendMacro { if (returns) { overrideExpr = macro { var name:String = $v{name}; - + /* if (__custom__variables != null) { if(__custom__variables.exists(name)) { var v:Dynamic = null; @@ -254,12 +263,20 @@ class ClassExtendMacro { } } } + */ + if (__interp != null && __class__fields.contains(name)) { + var v:Dynamic = null; + if (Reflect.isFunction(v = __interp.variables.get(name))) { + return v($a{arguments}); + } + } + return super.$name($a{arguments}); }; } else { overrideExpr = macro { var name:String = $v{name}; - + /* if (__custom__variables != null) { if(__custom__variables.exists(name)) { var v:Dynamic = null; @@ -269,6 +286,14 @@ class ClassExtendMacro { } } } + */ + if (__interp != null && __class__fields.contains(name)) { + var v:Dynamic = null; + if (Reflect.isFunction(v = __interp.variables.get(name))) { + v($a{arguments}); + return; + } + } super.$name($a{arguments}); }; } @@ -331,7 +356,6 @@ class ClassExtendMacro { pack: cl.pack.copy(), name: cl.name }, [ - {name: "IHScriptCustomAccessBehaviour", pack: ["hscript"]}, {name: "IHScriptCustomClassBehaviour", pack: ["hscript"]} ], false, true, false); shadowClass.name = '${cl.name}$CLASS_SUFFIX'; @@ -347,14 +371,14 @@ class ClassExtendMacro { kind: FVar(macro: hscript.Interp), access: [APublic] }); - + /* shadowClass.fields.push({ name: "__custom__variables", pos: Context.currentPos(), kind: FVar(macro: Map), access: [APublic] }); - + */ shadowClass.fields.push({ name: "__allowSetGet", pos: Context.currentPos(), @@ -384,7 +408,7 @@ class ClassExtendMacro { params: [], expr: macro { __allowSetGet = false; - var v = __custom__variables.get("get_" + name)(); + //var v = __custom__variables.get("get_" + name)(); __allowSetGet = true; return v; }, @@ -408,7 +432,7 @@ class ClassExtendMacro { params: [], expr: macro { __allowSetGet = false; - var v = __custom__variables.get("set_" + name)(val); + //var v = __custom__variables.get("set_" + name)(val); __allowSetGet = true; return v; }, @@ -472,30 +496,16 @@ class ClassExtendMacro { var hgetField = if(hasHgetInSuper) { macro { - if(__allowSetGet && __custom__variables.exists("get_" + name)) - return __callGetter(name); - if (__custom__variables.exists(name)) - return __custom__variables.get(name); return super.hget(name); } } else { macro { - if(__allowSetGet && __custom__variables.exists("get_" + name)) - return __callGetter(name); - if (__custom__variables.exists(name)) - return __custom__variables.get(name); return UnsafeReflect.getProperty(this, name); } } var hsetField = if(hasHsetInSuper) { macro { - if(__allowSetGet && __custom__variables.exists("set_" + name)) - return __callSetter(name, val); - if (__custom__variables.exists(name)) { - __custom__variables.set(name, val); - return val; - } if(__real_fields.contains(name)) { UnsafeReflect.setProperty(this, name, val); return UnsafeReflect.field(this, name); @@ -504,17 +514,11 @@ class ClassExtendMacro { } } else { macro { - if(__allowSetGet && __custom__variables.exists("set_" + name)) - return __callSetter(name, val); - if (__custom__variables.exists(name)) { - __custom__variables.set(name, val); - return val; - } if(__real_fields.contains(name)) { UnsafeReflect.setProperty(this, name, val); return UnsafeReflect.field(this, name); } - __custom__variables.set(name, val); + //__custom__variables.set(name, val); return val; } } @@ -579,6 +583,23 @@ class ClassExtendMacro { return fields; } + + static function buildConstructor(constArgs:Array):Field { + var superCallArgs:Array = [for (arg in constArgs) macro $i{arg.name}]; + + return { + name: 'new', + access: [APublic], + pos: Context.currentPos(), + kind: FFun({ + args: constArgs, + expr: macro { + // Call the super constructor with appropriate args + super($a{superCallArgs}); + } + }), + }; + } } #else class ClassExtendMacro {