package hscript; import hscript.Interp.DeclaredVar; import hscript.utils.UnsafeReflect; using StringTools; class CustomClassHandler implements IHScriptCustomConstructor { public static var staticHandler = new StaticHandler(); public var ogInterp:Interp; public var name:String; public var fields:Array; public var extend:String; public var interfaces:Array; public var cl:Class; public function new(ogInterp:Interp, name:String, fields:Array, ?extend:String, ?interfaces:Array) { this.ogInterp = ogInterp; this.name = name; this.fields = fields; this.extend = extend; this.interfaces = interfaces; this.cl = extend == null ? TemplateClass : Type.resolveClass('${extend}_HSX'); if(cl == null) ogInterp.error(EInvalidClass(extend)); } public function hnew(args:Array):Dynamic { var interp = new Interp(); interp.errorHandler = ogInterp.errorHandler; var _class:IHScriptCustomClassBehaviour = Type.createInstance(cl, args); var __capturedLocals = ogInterp.duplicate(ogInterp.locals); var capturedLocals:Map = []; for(k=>e in __capturedLocals) if (e != null && e.depth <= 0) capturedLocals.set(k, e); var disallowCopy = Type.getInstanceFields(cl); for (key => value in capturedLocals) { if(!disallowCopy.contains(key)) { interp.locals.set(key, {r: value, depth: -1}); } } for (key => value in ogInterp.variables) { if(!disallowCopy.contains(key)) { interp.variables.set(key, value); } } _class.__custom__variables = interp.variables; for(expr in fields) { @:privateAccess interp.exprReturn(expr); } interp.variables.set("super", staticHandler); _class.__interp = interp; // TODO: Remove interp.scriptObject = _class; for(variable => value in interp.variables) { if(variable == "this") continue; if(variable.startsWith("set_") || variable.startsWith("get_")) { _class.__allowSetGet = false; } } var newFunc = interp.variables.get("new"); if(newFunc != null) { UnsafeReflect.callMethodUnsafe(null, newFunc, args); } return _class; } public function toString():String { return name; } } class TemplateClass implements IHScriptCustomClassBehaviour implements IHScriptCustomBehaviour { public var __interp:Interp; // TODO: Remove public var __custom__variables:Map; public var __allowSetGet:Bool = true; public function hset(name:String, val:Dynamic):Dynamic { if(__allowSetGet && __custom__variables.exists("set_" + name)) return __callSetter(name, val); if (__custom__variables.exists(name)) { __custom__variables.set(name, val); return val; } UnsafeReflect.setProperty(this, name, val); return UnsafeReflect.field(this, name); } public function hget(name:String):Dynamic { 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); } public function __callGetter(name:String):Dynamic { __allowSetGet = false; var v = __custom__variables.get("get_" + name)(); __allowSetGet = true; return v; } public function __callSetter(name:String, val:Dynamic):Dynamic { __allowSetGet = false; var v = __custom__variables.get("set_" + name)(val); __allowSetGet = true; return v; } } class StaticHandler { public function new() {} }