Better access context (IN PROGRESS)
Also, throws an error if a variable with "(get, set)" doesn't have a type or a default value.
This commit is contained in:
@@ -237,3 +237,8 @@ enum abstract FieldPropertyAccess(UInt8) {
|
||||
var AGet;
|
||||
var ASet;
|
||||
}
|
||||
|
||||
enum AccessContext {
|
||||
CInner(cl:String);
|
||||
COuter;
|
||||
}
|
||||
|
||||
+5
-2
@@ -168,7 +168,7 @@ class Interp {
|
||||
var curExpr:Expr;
|
||||
#end
|
||||
|
||||
var _proxy(default, null):Null<CustomClass> = null;
|
||||
var _proxy(default, null):Null<CustomClass> = null; // Like "scriptObject" but for Custom Classes
|
||||
var _nextCallObject(default, null):Dynamic = null;
|
||||
var _inCustomClass(get, never):Bool;
|
||||
|
||||
@@ -743,7 +743,6 @@ class Interp {
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
if (_proxy.hasVar(id)) {
|
||||
var r = _proxy.hget(id);
|
||||
return r;
|
||||
@@ -1625,6 +1624,8 @@ class Interp {
|
||||
var clsName:String = cast(o, CustomClass).className;
|
||||
error(ECustom('The field ${clsName}.${f} should be accessed in a static way.'));
|
||||
}
|
||||
|
||||
cast(o, CustomClass).accessContext = _inCustomClass ? CInner(_proxy.className) : COuter;
|
||||
}
|
||||
|
||||
var cls = Type.getClass(o);
|
||||
@@ -1679,6 +1680,8 @@ class Interp {
|
||||
var clsName:String = cast(o, CustomClass).className;
|
||||
error(ECustom('The field ${clsName}.${f} should be accessed in a static way.'));
|
||||
}
|
||||
|
||||
cast(o, CustomClass).accessContext = _inCustomClass ? CInner(_proxy.className) : COuter;
|
||||
}
|
||||
|
||||
if (useRedirects && {
|
||||
|
||||
+15
-5
@@ -856,9 +856,9 @@ class Parser {
|
||||
}
|
||||
var ident = getIdent();
|
||||
var get = ADefault, set = ADefault;
|
||||
var hasGetSet:Bool = false;
|
||||
var tk = token();
|
||||
// TODO: throw "Missing ;" if tried to use (get, set) on final
|
||||
// and "Property requires type-hint or initialization" on missing type.
|
||||
if( tk == TPOpen && id != "final" ) {
|
||||
var getId = getIdent();
|
||||
switch (getId) {
|
||||
@@ -879,6 +879,8 @@ class Parser {
|
||||
}
|
||||
ensure(TPClose);
|
||||
|
||||
hasGetSet = true;
|
||||
|
||||
tk = token();
|
||||
}
|
||||
|
||||
@@ -895,6 +897,10 @@ class Parser {
|
||||
e = parseExpr();
|
||||
else
|
||||
push(tk);
|
||||
|
||||
if(hasGetSet && (e == null || (allowTypes && t == null)))
|
||||
error(ECustom("Property requires type-hint or initialization"), p1, tokenMax);
|
||||
|
||||
nextType = null;
|
||||
mk(EVar(ident, t, e, nextIsPublic, nextIsStatic, nextIsPrivate, id == "final", nextIsInline), p1, (e == null) ? tokenMax : pmax(e));
|
||||
case "while":
|
||||
@@ -1119,10 +1125,10 @@ class Parser {
|
||||
mk(EIgnore(true));
|
||||
case CTPath(path, params):
|
||||
if (params != null && params.length > 1)
|
||||
error(ECustom("Typedefs can't have parameters"), tokenMin, tokenMax);
|
||||
error(ECustom("Typedefs can't have parameters"), p1, tokenMax);
|
||||
|
||||
if (path.length == 0)
|
||||
error(ECustom("Typedefs can't be empty"), tokenMin, tokenMax);
|
||||
error(ECustom("Typedefs can't be empty"), p1, tokenMax);
|
||||
|
||||
var className = path.join(".");
|
||||
var cl = Tools.getClass(className);
|
||||
@@ -1137,7 +1143,7 @@ class Parser {
|
||||
// todo? add import to the beginning of the file?
|
||||
mk(EVar(name, null, expr));
|
||||
default:
|
||||
error(ECustom("Typedef, unknown type " + t), tokenMin, tokenMax);
|
||||
error(ECustom("Typedef, unknown type " + t), p1, tokenMax);
|
||||
null;
|
||||
}
|
||||
case "using":
|
||||
@@ -1805,8 +1811,8 @@ class Parser {
|
||||
case "var" | "final":
|
||||
var name = getIdent();
|
||||
var get = ADefault, set = ADefault;
|
||||
var hasGetSet:Bool = false;
|
||||
// TODO: throw "Missing ;" if tried to use (get, set) on final
|
||||
// and "Property requires type-hint or initialization" on missing type.
|
||||
if(maybe(TPOpen) && id != "final") {
|
||||
var getId = getIdent();
|
||||
switch(getId) {
|
||||
@@ -1826,10 +1832,14 @@ class Parser {
|
||||
default: unexpected(TId(getId));
|
||||
}
|
||||
ensure(TPClose);
|
||||
hasGetSet = true;
|
||||
}
|
||||
var type = maybe(TDoubleDot) ? parseType() : null;
|
||||
var expr = maybe(TOp("=")) ? parseExpr() : null;
|
||||
|
||||
if(hasGetSet && (expr == null || type == null))
|
||||
error(ECustom("Property requires type-hint or initialization"), p1, tokenMax);
|
||||
|
||||
if( expr != null ) {
|
||||
if( isBlock(expr) )
|
||||
maybe(TSemicolon);
|
||||
|
||||
@@ -44,6 +44,7 @@ class CustomClass implements IHScriptCustomAccessBehaviour {
|
||||
private var __cachedFunctionDecls:Map<String, FunctionDecl> = [];
|
||||
private var __cachedVarDecls:Map<String, VarDecl> = [];
|
||||
|
||||
public var accessContext:AccessContext = COuter;
|
||||
public var __allowSetGet:Bool = false;
|
||||
public var __allowPrivateAccess:Bool = false;
|
||||
|
||||
@@ -344,10 +345,14 @@ class CustomClass implements IHScriptCustomAccessBehaviour {
|
||||
if (hasVar(name)) {
|
||||
var v = getVar(name);
|
||||
var getter = v.get;
|
||||
var isInner = switch (accessContext) {
|
||||
case CInner(cl): return cl == this.className;
|
||||
default: false;
|
||||
}
|
||||
|
||||
var value:Dynamic = null;
|
||||
|
||||
if(getter == ANever || getter == ANull && !__allowPrivateAccess)
|
||||
if(getter == ANever || getter == ANull && (!isInner || !__allowPrivateAccess))
|
||||
throw 'field $name cannot be accessed for reading';
|
||||
|
||||
if (__allowSetGet && getter == AGet) {
|
||||
@@ -370,6 +375,7 @@ class CustomClass implements IHScriptCustomAccessBehaviour {
|
||||
|
||||
if (this.superClass != null) {
|
||||
if (superHasField(name)) {
|
||||
// Anonymous structure as a super class???
|
||||
if (Type.getClass(this.superClass) == null) {
|
||||
// Anonymous structure
|
||||
if (Reflect.hasField(this.superClass, name))
|
||||
@@ -383,6 +389,10 @@ class CustomClass implements IHScriptCustomAccessBehaviour {
|
||||
|
||||
superCustomClass.__allowSetGet = this.__allowSetGet;
|
||||
superCustomClass.__allowPrivateAccess = this.__allowPrivateAccess;
|
||||
superCustomClass.accessContext = switch (accessContext) {
|
||||
case CInner(_): CInner(superCustomClass.className);
|
||||
default: COuter;
|
||||
}
|
||||
return superCustomClass.hget(name);
|
||||
}
|
||||
|
||||
@@ -407,8 +417,12 @@ class CustomClass implements IHScriptCustomAccessBehaviour {
|
||||
if (hasVar(name)) {
|
||||
var v = getVar(name);
|
||||
var setter = v.set;
|
||||
var isInner = switch (accessContext) {
|
||||
case CInner(cl): return cl == this.className;
|
||||
default: false;
|
||||
}
|
||||
|
||||
if (setter == ANever || setter == ANull && !__allowPrivateAccess || (v.isFinal && !initializing))
|
||||
if (setter == ANever || setter == ANull && (!isInner || !__allowPrivateAccess) || (v.isFinal && !initializing))
|
||||
throw 'field $name cannot be accessed for writing';
|
||||
|
||||
if (__allowSetGet && setter == ASet) {
|
||||
@@ -437,6 +451,10 @@ class CustomClass implements IHScriptCustomAccessBehaviour {
|
||||
|
||||
superCustomClass.__allowSetGet = this.__allowSetGet;
|
||||
superCustomClass.__allowPrivateAccess = this.__allowPrivateAccess;
|
||||
superCustomClass.accessContext = switch (accessContext) {
|
||||
case CInner(_): CInner(superCustomClass.className);
|
||||
default: COuter;
|
||||
}
|
||||
return superCustomClass.hset(name, val);
|
||||
}
|
||||
// Real Class
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package hscript.customclass;
|
||||
|
||||
import hscript.Expr.AccessContext;
|
||||
import hscript.proxy.ProxyType;
|
||||
import hscript.customclass.utils.FunctionUtils;
|
||||
import haxe.Constraints.Function;
|
||||
@@ -33,6 +34,10 @@ class CustomClassDecl implements IHScriptCustomAccessBehaviour {
|
||||
|
||||
public var __allowPrivateAccess:Bool = false;
|
||||
|
||||
public var accessContext:AccessContext = COuter;
|
||||
|
||||
public final name:String;
|
||||
|
||||
public function new(classDecl:Expr.ClassDecl, imports:Map<String, CustomClassImport>, usings:Array<String>, ?pkg:Array<String>, ?ogInterp:Interp, ?isInline:Bool) {
|
||||
this.classDecl = classDecl;
|
||||
this.imports = imports;
|
||||
@@ -41,6 +46,11 @@ class CustomClassDecl implements IHScriptCustomAccessBehaviour {
|
||||
this.ogInterp = ogInterp;
|
||||
this.isInline = isInline;
|
||||
|
||||
// Cache the classname
|
||||
var pkg = pkg != null ? '${pkg.join(".")}.' : "";
|
||||
var className = classDecl.name;
|
||||
this.name = '$pkg$className';
|
||||
|
||||
if(ogInterp != null) {
|
||||
staticInterp.importFailedCallback = ogInterp.importFailedCallback;
|
||||
staticInterp.errorHandler = ogInterp.errorHandler;
|
||||
@@ -189,10 +199,14 @@ class CustomClassDecl implements IHScriptCustomAccessBehaviour {
|
||||
if(hasVar(name)) {
|
||||
var v = getVar(name);
|
||||
var getter = v.get;
|
||||
var isInner = switch (accessContext) {
|
||||
case CInner(cl): return cl == this.toString();
|
||||
default: false;
|
||||
}
|
||||
|
||||
var r:Dynamic = null;
|
||||
|
||||
if (getter == ANever || getter == ANull && !__allowPrivateAccess)
|
||||
if (getter == ANever || getter == ANull && (!isInner || !__allowPrivateAccess))
|
||||
throw 'field $name cannot be accessed for reading';
|
||||
|
||||
if(__allowSetGet && getter == AGet){
|
||||
@@ -226,8 +240,12 @@ class CustomClassDecl implements IHScriptCustomAccessBehaviour {
|
||||
if (hasVar(name)) {
|
||||
var v = getVar(name);
|
||||
var setter = v.set;
|
||||
var isInner = switch (accessContext) {
|
||||
case CInner(cl): return cl == this.toString();
|
||||
default: false;
|
||||
}
|
||||
|
||||
if (setter == ANever || setter == ANull && !__allowPrivateAccess || v.isFinal)
|
||||
if (setter == ANever || setter == ANull && (!isInner || !__allowPrivateAccess) || v.isFinal)
|
||||
throw 'field $name cannot be accessed for writing';
|
||||
|
||||
if (__allowSetGet && setter == ASet) {
|
||||
@@ -260,9 +278,7 @@ class CustomClassDecl implements IHScriptCustomAccessBehaviour {
|
||||
}
|
||||
|
||||
public function toString():String {
|
||||
var pkg = pkg != null ? '${pkg.join(".")}.' : "";
|
||||
var name = classDecl.name;
|
||||
return '$pkg$name';
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user