diff --git a/hscript/CustomClassHandler.hx b/hscript/CustomClassHandler.hx index 9ad9624..9961603 100644 --- a/hscript/CustomClassHandler.hx +++ b/hscript/CustomClassHandler.hx @@ -28,32 +28,41 @@ class CustomClassHandler implements IHScriptCustomConstructor { } public function hnew(args:Array):Dynamic { + // TODO: clean this up, it sucks, i hate it 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 __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}); - } - } + _class.__real_fields = disallowCopy; + + // todo: make it so you can use variables from the same scope as where the class was defined + + //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); } } - var comparisonMap = new Map(); + //trace("Before: " + [for(key => value in interp.variables) key]); + + interp.variables.set("super", staticHandler); + + var comparisonMap:Map = []; for(key => value in interp.variables) { comparisonMap.set(key, value); } @@ -61,34 +70,39 @@ class CustomClassHandler implements IHScriptCustomConstructor { _class.__custom__variables = interp.variables; //trace(fields); - for(expr in fields) { @:privateAccess interp.exprReturn(expr); } - interp.variables.set("super", staticHandler); + //trace("After: " + [for(key => value in interp.variables) key]); - _class.__interp = interp; - interp.scriptObject = _class; // get only variables that were not set before - var classVariables = [for(key => value in interp.variables) if(!comparisonMap.exists(key) || comparisonMap[key] != value) key => value]; - for(variable => value in classVariables) { - if(variable == "this" || variable == "super") continue; - @:privateAccess - if(!interp.__instanceFields.contains(variable)) { - interp.__instanceFields.push(variable); - } - } + var classVariables = [ + for(key => value in interp.variables) + if(!comparisonMap.exists(key) || comparisonMap[key] != value) + key => value + ]; + //for(variable => value in classVariables) { + // if(variable == "this" || variable == "super" || variable == "new") continue; + // @:privateAccess + // if(!interp.__instanceFields.contains(variable)) { + // interp.__instanceFields.push(variable); + // } + //} - //trace([for(key => value in classVariables) key]); + _class.__class__fields = [for(key => value in classVariables) key]; + + //trace(_class.__class__fields); //@:privateAccess //trace(interp.__instanceFields); + _class.__interp = interp; _class.__allowSetGet = false; + interp.scriptObject = _class; for(variable => value in interp.variables) { - if(variable == "this") continue; + if(variable == "this" || variable == "super" || variable == "new") continue; if(variable.startsWith("set_") || variable.startsWith("get_")) { _class.__allowSetGet = true; @@ -97,9 +111,32 @@ class CustomClassHandler implements IHScriptCustomConstructor { var newFunc = interp.variables.get("new"); if(newFunc != null) { + var comparisonMap:Map = []; + for(key => value in interp.variables) { + comparisonMap.set(key, value); + } + UnsafeReflect.callMethodUnsafe(null, newFunc, args); + + // get only variables that were not set before + var classVariables = [ + for(key => value in interp.variables) + if(!comparisonMap.exists(key) || comparisonMap[key] != value) + key => value + ]; + for(variable => value in classVariables) { + if(variable == "this" || variable == "super" || variable == "new") continue; + @:privateAccess + if(!interp.__instanceFields.contains(variable)) { + interp.__instanceFields.push(variable); + } + if(!_class.__class__fields.contains(variable)) { + _class.__class__fields.push(variable); + } + } } + return _class; } @@ -112,6 +149,8 @@ class TemplateClass implements IHScriptCustomClassBehaviour implements IHScriptC public var __interp:Interp; public var __allowSetGet:Bool = true; public var __custom__variables:Map; + public var __real_fields:Array; + public var __class__fields:Array; public function hset(name:String, val:Dynamic):Dynamic { if(__allowSetGet && __custom__variables.exists("set_" + name)) @@ -120,14 +159,19 @@ class TemplateClass implements IHScriptCustomClassBehaviour implements IHScriptC __custom__variables.set(name, val); return val; } - UnsafeReflect.setProperty(this, name, val); - return UnsafeReflect.field(this, name); + if(__real_fields.contains(name)) { + UnsafeReflect.setProperty(this, name, val); + return UnsafeReflect.field(this, name); + } + __custom__variables.set(name, val); + return val; } 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); } diff --git a/hscript/IHScriptCustomClassBehaviour.hx b/hscript/IHScriptCustomClassBehaviour.hx index a291a1e..11d24fd 100644 --- a/hscript/IHScriptCustomClassBehaviour.hx +++ b/hscript/IHScriptCustomClassBehaviour.hx @@ -4,6 +4,8 @@ interface IHScriptCustomClassBehaviour { public var __interp:Interp; public var __custom__variables:Map; public var __allowSetGet:Bool; + public var __real_fields:Array; + public var __class__fields:Array; public function hset(name:String, val:Dynamic):Dynamic; public function hget(name:String):Dynamic; diff --git a/hscript/Interp.hx b/hscript/Interp.hx index 8d73614..71225e2 100644 --- a/hscript/Interp.hx +++ b/hscript/Interp.hx @@ -28,6 +28,7 @@ */ package hscript; +import haxe.CallStack; import hscript.utils.UnsafeReflect; import haxe.PosInfos; import hscript.Expr; @@ -45,8 +46,8 @@ enum abstract ScriptObjectType(UInt8) { var SClass; var SObject; var SStaticClass; - var SCustomClass; - var SBehaviourClass; + var SCustomClass; // custom classes + var SBehaviourClass; // hget and hset var SNull; } @@ -71,9 +72,12 @@ class Interp { switch(Type.typeof(v)) { case TClass(c): // Class Access __instanceFields = Type.getInstanceFields(c); - if(c is IHScriptCustomClassBehaviour) { + if(v is IHScriptCustomClassBehaviour) { + var v = cast(v, IHScriptCustomClassBehaviour); + if(v.__class__fields != null) + __instanceFields = __instanceFields.concat(v.__class__fields); _scriptObjectType = SCustomClass; - } else if(c is IHScriptCustomBehaviour) { + } else if(v is IHScriptCustomBehaviour) { _scriptObjectType = SBehaviourClass; } else { _scriptObjectType = SClass; @@ -266,35 +270,36 @@ class Interp { case EIdent(id): if (!locals.exists(id)) { if (_hasScriptObject && !varExists(id)) { - if (_scriptObjectType == SObject) { + var instanceHasField = __instanceFields.contains(id); + + if (_scriptObjectType == SObject && instanceHasField) { UnsafeReflect.setField(scriptObject, id, v); - } else { - if (_scriptObjectType == SCustomClass) { - var obj = cast(scriptObject, IHScriptCustomClassBehaviour); - if(isBypassAccessor) { - obj.__allowSetGet = false; - var res = obj.hset(id, v); - obj.__allowSetGet = true; - return res; - } - return obj.hset(id, v); - } else if (_scriptObjectType == SBehaviourClass) { - var obj = cast(scriptObject, IHScriptCustomBehaviour); - return obj.hset(id, v); + } else if (_scriptObjectType == SCustomClass && instanceHasField) { + var obj = cast(scriptObject, IHScriptCustomClassBehaviour); + if(isBypassAccessor) { + obj.__allowSetGet = false; + var res = obj.hset(id, v); + obj.__allowSetGet = true; + return res; } - if (isBypassAccessor) { - if (__instanceFields.contains(id)) { - UnsafeReflect.setField(scriptObject, id, v); - return v; - } - } - if (__instanceFields.contains(id)) { - UnsafeReflect.setProperty(scriptObject, id, v); - } else if (__instanceFields.contains('set_$id')) { // setter - UnsafeReflect.getProperty(scriptObject, 'set_$id')(v); + return obj.hset(id, v); + } else if (_scriptObjectType == SBehaviourClass) { + var obj = cast(scriptObject, IHScriptCustomBehaviour); + return obj.hset(id, v); + } + + if (instanceHasField) { + if(isBypassAccessor) { + UnsafeReflect.setField(scriptObject, id, v); + return v; } else { - setVar(id, v); + UnsafeReflect.setProperty(scriptObject, id, v); + return UnsafeReflect.field(scriptObject, id); } + } else if (__instanceFields.contains('set_$id')) { // setter + return UnsafeReflect.getProperty(scriptObject, 'set_$id')(v); + } else { + setVar(id, v); } } else { setVar(id, v); @@ -339,10 +344,12 @@ class Interp { v = fop(expr(e1), expr(e2)); if (l == null) { if(_hasScriptObject) { - if(_scriptObjectType == SObject) { + var instanceHasField = __instanceFields.contains(id); + + if(_scriptObjectType == SObject && instanceHasField) { UnsafeReflect.setField(scriptObject, id, v); return v; - } else if (_scriptObjectType == SCustomClass) { + } else if (_scriptObjectType == SCustomClass && instanceHasField) { var obj = cast(scriptObject, IHScriptCustomClassBehaviour); if(isBypassAccessor) { obj.__allowSetGet = false; @@ -356,17 +363,16 @@ class Interp { return obj.hset(id, v); } - if (isBypassAccessor) { - if (__instanceFields.contains(id)) { + if (instanceHasField) { + if(isBypassAccessor) { UnsafeReflect.setField(scriptObject, id, v); return v; + } else { + UnsafeReflect.setProperty(scriptObject, id, v); + return UnsafeReflect.field(scriptObject, id); } - } - - if (__instanceFields.contains(id)) { - UnsafeReflect.setProperty(scriptObject, id, v); } else if (__instanceFields.contains('set_$id')) { // setter - UnsafeReflect.getProperty(scriptObject, 'set_$id')(v); + return UnsafeReflect.getProperty(scriptObject, 'set_$id')(v); } else { setVar(id, v); } @@ -559,9 +565,12 @@ class Interp { // search in object if (id == "this") { return scriptObject; - } else if (_scriptObjectType == SObject && UnsafeReflect.hasField(scriptObject, id)) { + } + var instanceHasField = __instanceFields.contains(id); + + if (_scriptObjectType == SObject && instanceHasField) { return UnsafeReflect.field(scriptObject, id); - } else if(_scriptObjectType == SCustomClass) { + } else if(_scriptObjectType == SCustomClass && instanceHasField) { var obj = cast(scriptObject, IHScriptCustomClassBehaviour); if(isBypassAccessor) { obj.__allowSetGet = false; @@ -574,12 +583,11 @@ class Interp { var obj = cast(scriptObject, IHScriptCustomBehaviour); return obj.hget(id); } - else { - if (__instanceFields.contains(id)) { - return UnsafeReflect.getProperty(scriptObject, id); - } else if (__instanceFields.contains('get_$id')) { // getter - return UnsafeReflect.getProperty(scriptObject, 'get_$id')(); - } + + if (instanceHasField) { + return UnsafeReflect.getProperty(scriptObject, id); + } else if (__instanceFields.contains('get_$id')) { // getter + return UnsafeReflect.getProperty(scriptObject, 'get_$id')(); } } if (doException) @@ -687,13 +695,14 @@ class Interp { declared.push({n: n, old: locals.get(n), depth: depth}); locals.set(n, {r: (e == null) ? null : expr(e), depth: depth}); if (depth == 0) { - if(isStatic == true) { - if(!staticVariables.exists(n)) { + if(allowStaticVariables && isStatic == true) { + if(!staticVariables.exists(n)) // make it so it only sets it once staticVariables.set(n, locals[n].r); - } - return null; + } else if(allowPublicVariables && isPublic == true) { + publicVariables.set(n, locals[n].r); + } else { + variables.set(n, locals[n].r); } - (isPublic ? publicVariables : variables).set(n, locals[n].r); } return null; case EParent(e): @@ -835,7 +844,13 @@ class Interp { if (name != null) { if (depth == 0) { // global function - ((isStatic && allowStaticVariables) ? staticVariables : ((isPublic && allowPublicVariables) ? publicVariables : variables)).set(name, f); + if(isStatic && allowStaticVariables) { + staticVariables.set(name, f); + } else if(isPublic && allowPublicVariables) { + publicVariables.set(name, f); + } else { + variables.set(name, f); + } } else { // function-in-function is a local function declared.push({n: name, old: locals.get(name), depth: depth}); @@ -1126,7 +1141,20 @@ class Interp { cl != null && getRedirects.exists(cl) && (_getRedirect = getRedirects[cl]) != null; }) { return _getRedirect(o, f); - } else if (o is IHScriptCustomBehaviour) { + } + + if(o is IHScriptCustomClassBehaviour) { + var obj = cast(o, IHScriptCustomClassBehaviour); + if(isBypassAccessor) { + obj.__allowSetGet = false; + var res = obj.hget(f); + obj.__allowSetGet = true; + return res; + } + return obj.hget(f); + } + + if (o is IHScriptCustomBehaviour) { var obj = cast(o, IHScriptCustomBehaviour); return obj.hget(f); } @@ -1152,7 +1180,19 @@ class Interp { cl != null && setRedirects.exists(cl) && (_setRedirect = setRedirects[cl]) != null; }) return _setRedirect(o, f, v); - else if (o is IHScriptCustomBehaviour) { + + if(o is IHScriptCustomClassBehaviour) { + var obj = cast(o, IHScriptCustomClassBehaviour); + if(isBypassAccessor) { + obj.__allowSetGet = false; + var res = obj.hset(f, v); + obj.__allowSetGet = true; + return res; + } + return obj.hset(f, v); + } + + if (o is IHScriptCustomBehaviour) { var obj = cast(o, IHScriptCustomBehaviour); return obj.hset(f, v); } diff --git a/hscript/macros/ClassExtendMacro.hx b/hscript/macros/ClassExtendMacro.hx index f9a933f..34e29d5 100644 --- a/hscript/macros/ClassExtendMacro.hx +++ b/hscript/macros/ClassExtendMacro.hx @@ -285,31 +285,35 @@ class ClassExtendMacro { shadowClass.fields.push({ name: "__interp", pos: Context.currentPos(), - kind: FVar(TPath({ - pack: ['hscript'], - name: 'Interp' - })), + kind: FVar(macro: hscript.Interp), access: [APublic] }); shadowClass.fields.push({ name: "__custom__variables", pos: Context.currentPos(), - kind: FVar(TPath({ - pack: [], - name: 'Map', - params: [TPType(TPath({name: "String", pack: []})), TPType(TPath({name: "Dynamic", pack: []}))] - })), + kind: FVar(macro: Map), access: [APublic] }); shadowClass.fields.push({ name: "__allowSetGet", pos: Context.currentPos(), - kind: FVar(TPath({ - pack: [], - name: 'Bool', - }), macro true), + kind: FVar(macro: Bool, macro true), + access: [APublic] + }); + + shadowClass.fields.push({ + name: "__real_fields", + pos: Context.currentPos(), + kind: FVar(macro: Array), + access: [APublic] + }); + + shadowClass.fields.push({ + name: "__class__fields", + pos: Context.currentPos(), + kind: FVar(macro: Array), access: [APublic] }); @@ -317,7 +321,7 @@ class ClassExtendMacro { name: "__callGetter", pos: Context.currentPos(), kind: FFun({ - ret: TPath({name: 'Dynamic', pack: []}), + ret: macro: Dynamic, params: [], expr: macro { __allowSetGet = false; @@ -330,7 +334,7 @@ class ClassExtendMacro { name: "name", opt: false, meta: [], - type: TPath({name: "String", pack: []}) + type: macro: String } ] }), @@ -341,7 +345,7 @@ class ClassExtendMacro { name: "__callSetter", pos: Context.currentPos(), kind: FFun({ - ret: TPath({name: 'Dynamic', pack: []}), + ret: macro: Dynamic, params: [], expr: macro { __allowSetGet = false; @@ -354,13 +358,13 @@ class ClassExtendMacro { name: "name", opt: false, meta: [], - type: TPath({name: "String", pack: []}) + type: macro: String }, { name: "val", opt: false, meta: [], - type: TPath({name: "Dynamic", pack: []}) + type: macro: Dynamic } ] }), @@ -433,6 +437,10 @@ class ClassExtendMacro { __custom__variables.set(name, val); return val; } + if(__real_fields.contains(name)) { + UnsafeReflect.setProperty(this, name, val); + return UnsafeReflect.field(this, name); + } return super.hset(name, val); } } else { @@ -443,8 +451,12 @@ class ClassExtendMacro { __custom__variables.set(name, val); return val; } - UnsafeReflect.setProperty(this, name, val); - return UnsafeReflect.field(this, name); + if(__real_fields.contains(name)) { + UnsafeReflect.setProperty(this, name, val); + return UnsafeReflect.field(this, name); + } + __custom__variables.set(name, val); + return val; } } @@ -457,7 +469,7 @@ class ClassExtendMacro { pos: Context.currentPos(), access: hasHsetInSuper ? [AOverride, APublic] : [APublic], kind: FFun({ - ret: TPath({name: 'Dynamic', pack: []}), + ret: macro: Dynamic, params: [], expr: hsetField, args: [ @@ -465,13 +477,13 @@ class ClassExtendMacro { name: "name", opt: false, meta: [], - type: TPath({name: "String", pack: []}) + type: macro: String }, { name: "val", opt: false, meta: [], - type: TPath({name: "Dynamic", pack: []}) + type: macro: Dynamic } ] }) @@ -482,7 +494,7 @@ class ClassExtendMacro { pos: Context.currentPos(), access: hasHgetInSuper ? [AOverride, APublic] : [APublic], kind: FFun({ - ret: TPath({name: 'Dynamic', pack: []}), + ret: macro: Dynamic, params: [], expr: hgetField, args: [ @@ -490,7 +502,7 @@ class ClassExtendMacro { name: "name", opt: false, meta: [], - type: TPath({name: "String", pack: []}) + type: macro: String } ] })