Classes work more reliably + Optimizations

This commit is contained in:
Ne_Eo
2024-08-20 04:50:20 +02:00
parent f18c7a2210
commit 13bdf30055
7 changed files with 650 additions and 185 deletions
+71 -24
View File
@@ -1,5 +1,7 @@
package hscript;
import hscript.Interp.DeclaredVar;
import hscript.utils.UnsafeReflect;
using StringTools;
class CustomClassHandler implements IHScriptCustomConstructor {
@@ -11,12 +13,18 @@ class CustomClassHandler implements IHScriptCustomConstructor {
public var extend:String;
public var interfaces:Array<String>;
public var cl:Class<Dynamic>;
public function new(ogInterp:Interp, name:String, fields:Array<Expr>, ?extend:String, ?interfaces:Array<String>) {
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>):Dynamic {
@@ -24,14 +32,10 @@ class CustomClassHandler implements IHScriptCustomConstructor {
interp.errorHandler = ogInterp.errorHandler;
var cl = extend == null ? TemplateClass : Type.resolveClass('${extend}_HSX');
if(cl == null)
ogInterp.error(EInvalidClass(extend));
var _class = Type.createInstance(cl, args);
var _class:IHScriptCustomClassBehaviour = Type.createInstance(cl, args);
var __capturedLocals = ogInterp.duplicate(ogInterp.locals);
var capturedLocals:Map<String, {r:Dynamic, depth:Int}> = [];
var capturedLocals:Map<String, DeclaredVar> = [];
for(k=>e in __capturedLocals)
if (e != null && e.depth <= 0)
capturedLocals.set(k, e);
@@ -49,6 +53,15 @@ class CustomClassHandler implements IHScriptCustomConstructor {
}
}
var comparisonMap = new Map();
for(key => value in interp.variables) {
comparisonMap.set(key, value);
}
_class.__custom__variables = interp.variables;
//trace(fields);
for(expr in fields) {
@:privateAccess
interp.exprReturn(expr);
@@ -58,14 +71,33 @@ class CustomClassHandler implements IHScriptCustomConstructor {
_class.__interp = interp;
interp.scriptObject = _class;
var newFunc = interp.variables.get("new");
if(newFunc != null) {
Reflect.callMethod(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") continue;
@:privateAccess
if(!interp.__instanceFields.contains(variable)) {
interp.__instanceFields.push(variable);
}
}
//trace([for(key => value in classVariables) key]);
//@:privateAccess
//trace(interp.__instanceFields);
_class.__allowSetGet = false;
for(variable => value in interp.variables) {
if(variable == "this") continue;
if(variable.startsWith("set_") || variable.startsWith("get_")) {
_class.__allowSetGet = true;
}
}
var newFunc = interp.variables.get("new");
if(newFunc != null) {
UnsafeReflect.callMethodUnsafe(null, newFunc, args);
}
return _class;
@@ -76,29 +108,44 @@ class CustomClassHandler implements IHScriptCustomConstructor {
}
}
class TemplateClass implements IHScriptCustomBehaviour {
class TemplateClass implements IHScriptCustomClassBehaviour implements IHScriptCustomBehaviour {
public var __interp:Interp;
public var __allowSetGet:Bool = true;
public var __custom__variables:Map<String, Dynamic>;
public function hset(name:String, val:Dynamic):Dynamic {
if(this.__interp.variables.exists("set_" + name)) {
return this.__interp.variables.get("set_" + name)(val); // TODO: Prevent recursion from setting it in the function
}
if (this.__interp.variables.exists(name)) {
this.__interp.variables.set(name, val);
if(__allowSetGet && __custom__variables.exists("set_" + name))
return __callSetter(name, val);
if (__custom__variables.exists(name)) {
__custom__variables.set(name, val);
return val;
}
Reflect.setProperty(this, name, val);
return Reflect.field(this, name);
UnsafeReflect.setProperty(this, name, val);
return UnsafeReflect.field(this, name);
}
public function hget(name:String):Dynamic {
if(this.__interp.variables.exists("get_" + name))
return this.__interp.variables.get("get_" + name)();
if (this.__interp.variables.exists(name))
return this.__interp.variables.get(name);
return Reflect.getProperty(this, name);
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 {
final class StaticHandler {
public function new() {}
}
+31 -14
View File
@@ -21,6 +21,16 @@
*/
package hscript;
typedef Int8 = #if cpp cpp.Int8 #else Int #end;
typedef Int16 = #if cpp cpp.Int16 #else Int #end;
typedef Int32 = #if cpp cpp.Int32 #else Int #end;
typedef Int64 = #if cpp cpp.Int64 #else Int #end;
typedef UInt8 = #if cpp cpp.UInt8 #else Int #end;
typedef UInt16 = #if cpp cpp.UInt16 #else Int #end;
typedef UInt32 = #if cpp cpp.UInt32 #else Int #end;
typedef UInt64 = #if cpp cpp.UInt64 #else Int #end;
enum Const {
CInt( v : Int );
CFloat( f : Float );
@@ -31,12 +41,13 @@ enum Const {
}
#if hscriptPos
typedef Expr = {
var e : ExprDef;
var pmin : Int;
var pmax : Int;
var origin : String;
var line : Int;
@:structInit
final class Expr {
public var e : ExprDef;
public var pmin : Int;
public var pmax : Int;
public var origin : String;
public var line : Int;
}
enum ExprDef {
#else
@@ -66,7 +77,7 @@ enum Expr {
ETry( e : Expr, v : String, t : Null<CType>, ecatch : Expr );
EObject( fl : Array<{ name : String, e : Expr }> );
ETernary( cond : Expr, e1 : Expr, e2 : Expr );
ESwitch( e : Expr, cases : Array<{ values : Array<Expr>, expr : Expr }>, ?defaultExpr : Expr );
ESwitch( e : Expr, cases : Array<SwitchCase>, ?defaultExpr : Expr );
EDoWhile( cond : Expr, e : Expr);
EMeta( name : String, args : Array<Expr>, e : Expr );
ECheckType( e : Expr, t : CType );
@@ -75,6 +86,12 @@ enum Expr {
EClass( name:String, fields:Array<Expr>, ?extend:String, interfaces:Array<String> );
}
@:structInit
final class SwitchCase {
public var values : Array<Expr>;
public var expr : Expr;
}
typedef Argument = { name : String, ?t : CType, ?opt : Bool, ?value : Expr };
typedef Metadata = Array<{ name : String, params : Array<Expr> }>;
@@ -157,13 +174,13 @@ typedef FieldDecl = {
var access : Array<FieldAccess>;
}
enum FieldAccess {
APublic;
APrivate;
AInline;
AOverride;
AStatic;
AMacro;
enum abstract FieldAccess(UInt8) {
var APublic;
var APrivate;
var AInline;
var AOverride;
var AStatic;
var AMacro;
}
enum FieldKind {
+14
View File
@@ -0,0 +1,14 @@
package hscript;
interface IHScriptCustomClassBehaviour {
public var __interp:Interp;
public var __custom__variables:Map<String, Dynamic>;
public var __allowSetGet:Bool;
public function hset(name:String, val:Dynamic):Dynamic;
public function hget(name:String):Dynamic;
public function __callGetter(name:String):Dynamic;
public function __callSetter(name:String, val:Dynamic):Dynamic;
}
+227 -108
View File
@@ -28,9 +28,7 @@
*/
package hscript;
import haxe.iterators.StringKeyValueIteratorUnicode;
import haxe.EnumTools;
import haxe.display.Protocol.InitializeResult;
import hscript.utils.UnsafeReflect;
import haxe.PosInfos;
import hscript.Expr;
import haxe.Constraints.IMap;
@@ -43,10 +41,58 @@ private enum Stop {
SReturn;
}
enum abstract ScriptObjectType(UInt8) {
var SClass;
var SObject;
var SStaticClass;
var SCustomClass;
var SBehaviourClass;
var SNull;
}
@:structInit
class DeclaredVar {
public var r:Dynamic;
public var depth:Int;
}
@:structInit
class RedeclaredVar {
public var n:String;
public var old:DeclaredVar;
public var depth:Int;
}
class Interp {
public var scriptObject(default, set):Dynamic;
private var _hasScriptObject(default, null):Bool = false;
private var _scriptObjectType(default, null):ScriptObjectType = SNull;
public function set_scriptObject(v:Dynamic) {
__instanceFields = (v == null) ? [] : Type.getInstanceFields(Type.getClass(v));
switch(Type.typeof(v)) {
case TClass(c): // Class Access
__instanceFields = Type.getInstanceFields(c);
if(c is IHScriptCustomClassBehaviour) {
_scriptObjectType = SCustomClass;
} else if(c is IHScriptCustomBehaviour) {
_scriptObjectType = SBehaviourClass;
} else {
_scriptObjectType = SClass;
}
case TObject: // Object Access or Static Class Access
var cls = Type.getClass(v);
switch(Type.typeof(cls)) {
case TClass(c): // Static Class Access
__instanceFields = Type.getInstanceFields(c);
_scriptObjectType = SStaticClass;
default: // Object Access
__instanceFields = Reflect.fields(v);
_scriptObjectType = SObject;
}
default: // Null or other
__instanceFields = [];
_scriptObjectType = SNull;
}
_hasScriptObject = v != null;
return scriptObject = v;
}
public var errorHandler:Error->Void;
@@ -57,7 +103,7 @@ class Interp {
public var publicVariables:Map<String, Dynamic>;
public var staticVariables:Map<String, Dynamic>;
public var locals:Map<String, {r:Dynamic, depth:Int}>;
public var locals:Map<String, DeclaredVar>;
var binops:Map<String, Expr->Expr->Dynamic>;
#else
public var customClasses:Hash<Dynamic>;
@@ -65,13 +111,13 @@ class Interp {
public var publicVariables:Hash<Dynamic>;
public var staticVariables:Hash<Dynamic>;
public var locals:Hash<{r:Dynamic, depth:Int}>;
public var locals:Hash<DeclaredVar>;
var binops:Hash<Expr->Expr->Dynamic>;
#end
var depth:Int = 0;
var inTry:Bool;
var declared:Array<{n:String, old:{r:Dynamic, depth:Int}, depth:Int}>;
var declared:Array<RedeclaredVar>;
var returnValue:Dynamic;
var isBypassAccessor:Bool = false;
@@ -214,22 +260,34 @@ class Interp {
var v = expr(e2);
switch (Tools.expr(e1)) {
case EIdent(id):
var l = locals.get(id);
if (l == null) {
if (!variables.exists(id) && !staticVariables.exists(id) && !publicVariables.exists(id) && scriptObject != null) {
if (Type.typeof(scriptObject) == TObject) {
Reflect.setField(scriptObject, id, v);
if (!locals.exists(id)) {
if (_hasScriptObject && !variables.exists(id) && !staticVariables.exists(id) && !publicVariables.exists(id)) {
if (_scriptObjectType == SObject) {
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);
}
if (isBypassAccessor) {
if (__instanceFields.contains(id)) {
Reflect.setField(scriptObject, id, v);
UnsafeReflect.setField(scriptObject, id, v);
return v;
}
}
if (__instanceFields.contains(id)) {
Reflect.setProperty(scriptObject, id, v);
UnsafeReflect.setProperty(scriptObject, id, v);
} else if (__instanceFields.contains('set_$id')) { // setter
Reflect.getProperty(scriptObject, 'set_$id')(v);
UnsafeReflect.getProperty(scriptObject, 'set_$id')(v);
} else {
setVar(id, v);
}
@@ -238,6 +296,7 @@ class Interp {
setVar(id, v);
}
} else {
var l = locals.get(id);
l.r = v;
if (l.depth == 0) {
setVar(id, v);
@@ -275,12 +334,38 @@ class Interp {
var l = locals.get(id);
v = fop(expr(e1), expr(e2));
if (l == null) {
if (__instanceFields.contains(id)) {
Reflect.setProperty(scriptObject, id, v);
} else if (__instanceFields.contains('set_$id')) { // setter
Reflect.getProperty(scriptObject, 'set_$id')(v);
} else {
setVar(id, v);
if(_hasScriptObject) {
if(_scriptObjectType == SObject) {
UnsafeReflect.setField(scriptObject, id, v);
return 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);
}
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);
} else {
setVar(id, v);
}
}
}
else
@@ -294,8 +379,10 @@ class Interp {
var arr:Dynamic = expr(e);
var index:Dynamic = expr(index);
if (isMap(arr)) {
v = fop(getMapValue(arr, index), expr(e2));
setMapValue(arr, index, v);
var map = getMap(arr);
v = fop(map.get(index), expr(e2));
map.set(index, v);
} else {
v = fop(arr[index], expr(e2));
arr[index] = v;
@@ -313,19 +400,24 @@ class Interp {
#end
switch (e) {
case EIdent(id):
var l = locals.get(id);
var v:Dynamic = (l == null) ? resolve(id) : l.r;
if (prefix) {
v += delta;
if (l == null)
setVar(id, v)
else
if(locals.exists(id)) {
var l = locals.get(id);
var v:Dynamic = l.r;
if (prefix) {
v += delta;
l.r = v;
} else if (l == null)
setVar(id, v + delta)
else
l.r = v + delta;
return v;
} else
l.r = v + delta;
return v;
} else {
var v:Dynamic = resolve(id);
if (prefix) {
v += delta;
setVar(id, v);
} else
setVar(id, v + delta);
return v;
}
case EField(e, f, s):
var obj = expr(e);
if(s && obj == null) return null;
@@ -340,12 +432,14 @@ class Interp {
var arr:Dynamic = expr(e);
var index:Dynamic = expr(index);
if (isMap(arr)) {
var v = getMapValue(arr, index);
var map = getMap(arr);
var v = map.get(index);
if (prefix) {
v += delta;
setMapValue(arr, index, v);
map.set(index, v);
} else {
setMapValue(arr, index, v + delta);
map.set(index, v + delta);
}
return v;
} else {
@@ -445,32 +539,48 @@ class Interp {
if (id == null)
return null;
id = StringTools.trim(id);
var l = locals.get(id);
if (l != null)
return l.r;
if (locals.exists(id))
return locals.get(id).r;
var v = variables.get(id);
for(map in [variables, publicVariables, staticVariables, customClasses])
if (map.exists(id))
return map[id];
if(variables.exists(id))
return variables.get(id);
if(publicVariables.exists(id))
return publicVariables.get(id);
if(staticVariables.exists(id))
return staticVariables.get(id);
if(customClasses.exists(id))
return customClasses.get(id);
if (scriptObject != null) {
if (_hasScriptObject) {
// search in object
if (id == "this") {
return scriptObject;
} else if ((Type.typeof(scriptObject) == TObject) && Reflect.hasField(scriptObject, id)) {
return Reflect.field(scriptObject, id);
} else {
} else if (_scriptObjectType == SObject && UnsafeReflect.hasField(scriptObject, id)) {
return UnsafeReflect.field(scriptObject, id);
} else if(_scriptObjectType == SCustomClass) {
var obj = cast(scriptObject, IHScriptCustomClassBehaviour);
if(isBypassAccessor) {
obj.__allowSetGet = false;
var res = obj.hget(id);
obj.__allowSetGet = true;
return res;
}
return obj.hget(id);
} else if(_scriptObjectType == SBehaviourClass) {
var obj = cast(scriptObject, IHScriptCustomBehaviour);
return obj.hget(id);
}
else {
if (__instanceFields.contains(id)) {
return Reflect.getProperty(scriptObject, id);
return UnsafeReflect.getProperty(scriptObject, id);
} else if (__instanceFields.contains('get_$id')) { // getter
return Reflect.getProperty(scriptObject, 'get_$id')();
return UnsafeReflect.getProperty(scriptObject, 'get_$id')();
}
}
}
if (doException)
error(EUnknownVariable(id));
return v;
return null;
}
public function expr(e:Expr):Dynamic {
@@ -541,10 +651,10 @@ class Interp {
var enumThingy = {};
for (c in en.getConstructors()) {
try {
Reflect.setField(enumThingy, c, en.createByName(c));
UnsafeReflect.setField(enumThingy, c, en.createByName(c));
} catch(e) {
try {
Reflect.setField(enumThingy, c, Reflect.field(en, c));
UnsafeReflect.setField(enumThingy, c, UnsafeReflect.field(en, c));
} catch(ex) {
throw e;
}
@@ -621,9 +731,7 @@ class Interp {
error(EInvalidOp(op));
}
case ECall(e, params):
var args = new Array();
for (p in params)
args.push(expr(p));
var args:Array<Dynamic> = [for(p in params) expr(p)];
switch (Tools.expr(e)) {
case EField(e, f, s):
@@ -656,7 +764,7 @@ class Interp {
throw SReturn;
case EFunction(params, fexpr, name, _, isPublic, isStatic, isOverride):
var __capturedLocals = duplicate(locals);
var capturedLocals:Map<String, {r:Dynamic, depth:Int}> = [];
var capturedLocals:Map<String, DeclaredVar> = [];
for(k=>e in __capturedLocals)
if (e != null && e.depth > 0)
capturedLocals.set(k, e);
@@ -727,7 +835,7 @@ class Interp {
} else {
// function-in-function is a local function
declared.push({n: name, old: locals.get(name), depth: depth});
var ref = {r: f, depth: depth};
var ref:DeclaredVar = {r: f, depth: depth};
locals.set(name, ref);
capturedLocals.set(name, ref); // allow self-recursion
}
@@ -844,7 +952,7 @@ class Interp {
case EObject(fl):
var o = {};
for (f in fl)
set(o, f.name, expr(f.e));
UnsafeReflect.setField(o, f.name, expr(f.e));
return o;
case ETernary(econd, e1, e2):
return if (expr(econd) == true) expr(e1) else expr(e2);
@@ -945,8 +1053,10 @@ class Interp {
declared.push({n: ithv, old: locals.get(ithv), depth: depth});
declared.push({n: n, old: locals.get(n), depth: depth});
var it = makeIterator(expr(it), isKeyValue);
while (it.hasNext()) {
var next = it.next();
var _hasNext = it.hasNext;
var _next = it.next;
while (_hasNext()) {
var next = _next();
if(isKeyValue)
locals.set(ithv, {r: next.key, depth: depth});
locals.set(n, {r: isKeyValue ? next.value : next, depth: depth});
@@ -969,81 +1079,91 @@ class Interp {
return (o is IMap);
}
inline function getMap(map:Dynamic):IMap<Dynamic, Dynamic> {
return cast(map, IMap<Dynamic, Dynamic>);
}
inline function getMapValue(map:Dynamic, key:Dynamic):Dynamic {
return cast(map, haxe.Constraints.IMap<Dynamic, Dynamic>).get(key);
return cast(map, IMap<Dynamic, Dynamic>).get(key);
}
inline function setMapValue(map:Dynamic, key:Dynamic, value:Dynamic):Void {
cast(map, haxe.Constraints.IMap<Dynamic, Dynamic>).set(key, value);
cast(map, IMap<Dynamic, Dynamic>).set(key, value);
}
public static var getRedirects:Map<String, Dynamic->String->Dynamic> = [];
public static var setRedirects:Map<String, Dynamic->String->Dynamic->Dynamic> = [];
private static var _getRedirect:Dynamic->String->Dynamic;
private static var _setRedirect:Dynamic->String->Dynamic->Dynamic;
public var useRedirects:Bool = false;
static function getClassType(o:Dynamic, ?cls:Class<Any>):Null<String> {
return switch (Type.typeof(o)) {
case TNull: "Null";
case TInt: "Int";
case TFloat: "Float";
case TBool: "Bool";
case _:
if (cls == null)
cls = Type.getClass(o);
cls != null ? Type.getClassName(cls) : null;
};
}
function get(o:Dynamic, f:String):Dynamic {
if (o == null)
error(EInvalidAccess(f));
return {
var redirect:Dynamic->String->Dynamic = null;
var cls = Type.getClass(o);
var cl:Null<String> = switch (Type.typeof(o)) {
case TNull: "Null";
case TInt: "Int";
case TFloat: "Float";
case TBool: "Bool";
case _: cls != null ? Type.getClassName(cls) : null;
};
if (cl != null && getRedirects.exists(cl) && (redirect = getRedirects[cl]) != null) {
return redirect(o, f);
} else if (o is IHScriptCustomBehaviour) {
var obj = cast(o, IHScriptCustomBehaviour);
return obj.hget(f);
} else {
var v = null;
if(isBypassAccessor) {
if ((v = Reflect.field(o, f)) == null)
v = Reflect.field(cls, f);
}
if(v == null) {
if ((v = Reflect.getProperty(o, f)) == null)
v = Reflect.getProperty(cls, f);
}
return v;
}
var cls = Type.getClass(o);
if (useRedirects && {
var cl:Null<String> = getClassType(o, cls);
cl != null && getRedirects.exists(cl) && (_getRedirect = getRedirects[cl]) != null;
}) {
return _getRedirect(o, f);
} else if (o is IHScriptCustomBehaviour) {
var obj = cast(o, IHScriptCustomBehaviour);
return obj.hget(f);
}
var v = null;
if(isBypassAccessor) {
if ((v = UnsafeReflect.field(o, f)) == null)
v = Reflect.field(cls, f);
}
if(v == null) {
if ((v = UnsafeReflect.getProperty(o, f)) == null)
v = Reflect.getProperty(cls, f);
}
return v;
}
function set(o:Dynamic, f:String, v:Dynamic):Dynamic {
if (o == null)
error(EInvalidAccess(f));
var redirect:Dynamic->String->Dynamic->Dynamic = null;
var cls = Type.getClass(o);
var cl:Null<String> = switch (Type.typeof(o)) {
case TNull: "Null";
case TInt: "Int";
case TFloat: "Float";
case TBool: "Bool";
case _: cls != null ? Type.getClassName(cls) : null;
};
if (cl != null && setRedirects.exists(cl) && (redirect = setRedirects[cl]) != null)
return redirect(o, f, v);
if (useRedirects && {
var cl:Null<String> = getClassType(o);
cl != null && setRedirects.exists(cl) && (_setRedirect = setRedirects[cl]) != null;
})
return _setRedirect(o, f, v);
else if (o is IHScriptCustomBehaviour) {
var obj = cast(o, IHScriptCustomBehaviour);
return obj.hset(f, v);
}
// Can use unsafe reflect here, since we checked for null above
if(isBypassAccessor) {
Reflect.setField(o, f, v);
UnsafeReflect.setField(o, f, v);
} else {
Reflect.setProperty(o, f, v);
UnsafeReflect.setProperty(o, f, v);
}
return v;
}
function fcall(o:Dynamic, f:String, args:Array<Dynamic>):Dynamic {
if(o == CustomClassHandler.staticHandler && scriptObject != null) {
return Reflect.callMethod(scriptObject, Reflect.field(scriptObject, "_HX_SUPER__" + f), args);
if(_hasScriptObject && o == CustomClassHandler.staticHandler) {
return UnsafeReflect.callMethodUnsafe(scriptObject, UnsafeReflect.field(scriptObject, "_HX_SUPER__" + f), args);
}
return call(o, get(o, f), args);
}
@@ -1052,11 +1172,10 @@ class Interp {
if(f == CustomClassHandler.staticHandler) {
return null;
}
return Reflect.callMethod(o, f, args);
return UnsafeReflect.callMethodSafe(o, f, args);
}
function cnew(cl:String, args:Array<Dynamic>):Dynamic {
var cl:String = cast cl;
var c:Dynamic = resolve(cl);
if (c == null)
c = Type.resolveClass(cl);
+10 -6
View File
@@ -907,10 +907,12 @@ class Parser {
var fields = [];
ensure(TBrOpen);
while( !maybe(TBrClose) ) {
if(token() == TSemicolon) continue;
var a = parseExpr();
fields.push(a);
while( true ) {
parseFullExpr(fields);
tk = token();
if( tk == TBrClose || (resumeErrors && tk == TEof) )
break;
push(tk);
}
var tk = token();
@@ -964,7 +966,7 @@ class Parser {
var tk = token();
switch( tk ) {
case TId("case"):
var c = { values : [], expr : null };
var c:SwitchCase = { values : [], expr : null };
cases.push(c);
disableOrOp = true;
while( true ) {
@@ -1601,7 +1603,8 @@ class Parser {
return b.toString();
}
function token(?infos : Null<haxe.PosInfos>) {
function token() {
//function token(?infos : Null<haxe.PosInfos>) {
//function ttrace(v:Dynamic, ?infos : Null<haxe.PosInfos>) {
// Sys.print(infos.fileName+":"+infos.lineNumber+": " + Std.string(v));
// Sys.print("\r\n");
@@ -1619,6 +1622,7 @@ class Parser {
oldTokenMax = tokenMax;
tokenMin = (this.char < 0) ? readPos : readPos - 1;
var t = _token();
//trace(t, infos);
//ttrace(t, infos);
tokenMax = (this.char < 0) ? readPos - 1 : readPos - 2;
return t;
+113 -33
View File
@@ -187,10 +187,12 @@ class ClassExtendMacro {
overrideExpr = macro {
var name:String = $v{name};
if (__interp != null) {
var v:Dynamic = null;
if (__interp.variables.exists(name) && Reflect.isFunction(v = __interp.variables.get(name))) {
return v($a{arguments});
if (__custom__variables != null) {
if(__custom__variables.exists(name)) {
var v:Dynamic = null;
if (Reflect.isFunction(v = __custom__variables.get(name))) {
return v($a{arguments});
}
}
}
return super.$name($a{arguments});
@@ -199,11 +201,13 @@ class ClassExtendMacro {
overrideExpr = macro {
var name:String = $v{name};
if (__interp != null) {
var v:Dynamic = null;
if (__interp != null && __interp.variables.exists(name) && Reflect.isFunction(v = __interp.variables.get(name))) {
v($a{arguments});
return;
if (__custom__variables != null) {
if(__custom__variables.exists(name)) {
var v:Dynamic = null;
if (Reflect.isFunction(v = __custom__variables.get(name))) {
v($a{arguments});
return;
}
}
}
super.$name($a{arguments});
@@ -268,11 +272,13 @@ class ClassExtendMacro {
pack: cl.pack.copy(),
name: cl.name
}, [
{name: "IHScriptCustomBehaviour", pack: ["hscript"]}
{name: "IHScriptCustomBehaviour", pack: ["hscript"]},
{name: "IHScriptCustomClassBehaviour", pack: ["hscript"]}
], false, true, false);
shadowClass.name = '${cl.name}$CLASS_SUFFIX';
var imports = Context.getLocalImports().copy();
Utils.setupMetas(shadowClass, imports);
Utils.processImport(imports, "hscript.utils.UnsafeReflect", "UnsafeReflect");
// Adding hscript getters and setters
@@ -282,7 +288,83 @@ class ClassExtendMacro {
kind: FVar(TPath({
pack: ['hscript'],
name: '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: []}))]
})),
access: [APublic]
});
shadowClass.fields.push({
name: "__allowSetGet",
pos: Context.currentPos(),
kind: FVar(TPath({
pack: [],
name: 'Bool',
}), macro true),
access: [APublic]
});
shadowClass.fields.push({
name: "__callGetter",
pos: Context.currentPos(),
kind: FFun({
ret: TPath({name: 'Dynamic', pack: []}),
params: [],
expr: macro {
__allowSetGet = false;
var v = __custom__variables.get("get_" + name)();
__allowSetGet = true;
return v;
},
args: [
{
name: "name",
opt: false,
meta: [],
type: TPath({name: "String", pack: []})
}
]
}),
access: [APublic]
});
shadowClass.fields.push({
name: "__callSetter",
pos: Context.currentPos(),
kind: FFun({
ret: TPath({name: 'Dynamic', pack: []}),
params: [],
expr: macro {
__allowSetGet = false;
var v = __custom__variables.get("set_" + name)(val);
__allowSetGet = true;
return v;
},
args: [
{
name: "name",
opt: false,
meta: [],
type: TPath({name: "String", pack: []})
},
{
name: "val",
opt: false,
meta: [],
type: TPath({name: "Dynamic", pack: []})
}
]
}),
access: [APublic]
});
// Todo: make it possible to override
@@ -327,44 +409,42 @@ class ClassExtendMacro {
var hgetField = if(hasHgetInSuper) {
macro {
if(this.__interp.variables.exists("get_" + name))
return this.__interp.variables.get("get_" + name)();
if (this.__interp.variables.exists(name))
return this.__interp.variables.get(name);
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(this.__interp.variables.exists("get_" + name))
return this.__interp.variables.get("get_" + name)();
if (this.__interp.variables.exists(name))
return this.__interp.variables.get(name);
return Reflect.getProperty(this, name);
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(this.__interp.variables.exists("set_" + name)) {
return this.__interp.variables.get("set_" + name)(val); // TODO: Prevent recursion from setting it in the function
}
if (this.__interp.variables.exists(name)) {
this.__interp.variables.set(name, val);
if(__allowSetGet && __custom__variables.exists("set_" + name))
return __callSetter(name, val);
if (__custom__variables.exists(name)) {
__custom__variables.set(name, val);
return val;
}
return super.hset(name, val);
return super.hset(this, name);
}
} else {
macro {
if(this.__interp.variables.exists("set_" + name)) {
return this.__interp.variables.get("set_" + name)(val); // TODO: Prevent recursion from setting it in the function
}
if (this.__interp.variables.exists(name)) {
this.__interp.variables.set(name, val);
if(__allowSetGet && __custom__variables.exists("set_" + name))
return __callSetter(name, val);
if (__custom__variables.exists(name)) {
__custom__variables.set(name, val);
return val;
}
Reflect.setProperty(this, name, val);
return Reflect.field(this, name);
UnsafeReflect.setProperty(this, name, val);
return UnsafeReflect.field(this, name);
}
}
+184
View File
@@ -0,0 +1,184 @@
package hscript.utils;
#if cpp
import cpp.ObjectType;
#end
@:analyzer(ignore)
class UnsafeReflect {
public #if !cpp inline #end static function hasField(o:Dynamic, field:String):Bool {
#if cpp
untyped {
return o.__HasField(field);
}
#else
return Reflect.hasField(o, field);
#end
}
public #if !cpp inline #end static function field(o:Dynamic, field:String):Dynamic {
#if cpp
untyped {
return o.__Field(field, untyped __cpp__("::hx::paccNever"));
}
#else
return Reflect.field(o, field);
#end
}
public #if !cpp inline #end static function setField(o:Dynamic, field:String, value:Dynamic):Void {
#if cpp
untyped {
o.__SetField(field, value, untyped __cpp__("::hx::paccNever"));
}
#else
return Reflect.setField(o, field, value);
#end
}
public #if !cpp inline #end static function getProperty(o:Dynamic, field:String):Dynamic {
#if cpp
untyped {
return o.__Field(field, untyped __cpp__("::hx::paccAlways"));
}
#else
return Reflect.getProperty(o, field);
#end
}
public #if !cpp inline #end static function setProperty(o:Dynamic, field:String, value:Dynamic):Void {
#if cpp
untyped {
o.__SetField(field, value, untyped __cpp__("::hx::paccAlways"));
}
#else
Reflect.setProperty(o, field);
#end
}
public #if !cpp inline #end static function callFieldUnsafe(o:Dynamic, field:String, args:Array<Dynamic>):Dynamic {
#if cpp
untyped {
var func:Dynamic = o.__Field(field, untyped __cpp__("::hx::paccDynamic"));
untyped func.__SetThis(o);
return untyped func.__Run(args);
}
#else
return Reflect.callMethod(o, func, args);
#end
}
public inline static function callMethod(o:Dynamic, func:haxe.Constraints.Function, args:Array<Dynamic>):Dynamic {
return Reflect.callMethod(o, func, args);
}
public #if !cpp inline #end static function callMethodSafe(o:Dynamic, func:haxe.Constraints.Function, args:Array<Dynamic>):Dynamic {
#if cpp
untyped {
if (func == null)
throw cpp.ErrorConstants.nullFunctionPointer;
untyped func.__SetThis(o);
return untyped func.__Run(args);
}
#else
return Reflect.callMethod(o, func, args);
#end
}
public #if !cpp inline #end static function callMethodUnsafe(o:Dynamic, func:haxe.Constraints.Function, args:Array<Dynamic>):Dynamic {
#if cpp
untyped {
untyped func.__SetThis(o);
return untyped func.__Run(args);
}
#else
return Reflect.callMethod(o, func, args);
#end
}
public inline static function fields(o:Dynamic):Array<String>
return Reflect.fields(o);
/*untyped {
if (o == null)
return new Array();
var a:Array<String> = [];
o.__GetFields(a);
return a;
}*/
public #if !cpp inline #end static function isFunction(f:Dynamic):Bool
#if cpp
untyped {
return f.__GetType() == ObjectType.vtFunction;
}
#else
return Reflect.isFunction(f);
#end
public inline static function compare<T>(a:T, b:T):Int {
return Reflect.compare(a, b);
//return (a == b) ? 0 : (((a : Dynamic) > (b : Dynamic)) ? 1 : -1);
}
public inline static function compareMethods(f1:Dynamic, f2:Dynamic):Bool {
return Reflect.compareMethods(f1, f2);
}
public #if !cpp inline #end static function isObject(v:Dynamic):Bool {
#if cpp
untyped {
var t:Int = v.__GetType();
return t == ObjectType.vtObject || t == ObjectType.vtClass || t == ObjectType.vtString || t == ObjectType.vtArray;
}
#else
return Reflect.isObject(v);
#end
}
public #if !cpp inline #end static function isEnumValue(v:Dynamic):Bool {
#if cpp
untyped {
return v.__GetType() == ObjectType.vtEnum;
}
#else
return Reflect.isEnumValue(v);
#end
}
public #if !cpp inline #end static function deleteField(o:Dynamic, field:String):Bool {
#if cpp
untyped {
return untyped __global__.__hxcpp_anon_remove(o, field);
}
#else
return Reflect.deleteField(o, field);
#end
}
public #if !cpp inline #end static function copy<T>(o:Null<T>):Null<T> {
#if cpp
if (o == null)
return null;
var t:Int = untyped o.__GetType();
if (t == ObjectType.vtString)
return o;
if (t == ObjectType.vtArray)
return untyped o.__Field("copy", untyped __cpp__("::hx::paccDynamic"))();
var o2:Dynamic = {};
for (f in UnsafeReflect.fields(o))
UnsafeReflect.setField(o2, f, UnsafeReflect.field(o, f));
return o2;
#else
return Reflect.copy(o);
#end
}
@:overload(function(f:Array<Dynamic>->Void):Dynamic {})
public static function makeVarArgs(f:Array<Dynamic>->Dynamic):Dynamic {
#if cpp
return untyped __global__.__hxcpp_create_var_args(f);
#else
return inline Reflect.makeVarArgs(f);
#end
}
}