From 932e643dc99a34b794c6295361385692c9280990 Mon Sep 17 00:00:00 2001 From: Jaime Humberto Macias Bustamante Date: Thu, 15 May 2025 01:07:29 -0700 Subject: [PATCH] Better access context (IN PROGRESS) Also, throws an error if a variable with "(get, set)" doesn't have a type or a default value. --- hscript/Expr.hx | 5 +++++ hscript/Interp.hx | 7 +++++-- hscript/Parser.hx | 20 +++++++++++++++----- hscript/customclass/CustomClass.hx | 22 ++++++++++++++++++++-- hscript/customclass/CustomClassDecl.hx | 26 +++++++++++++++++++++----- 5 files changed, 66 insertions(+), 14 deletions(-) diff --git a/hscript/Expr.hx b/hscript/Expr.hx index 0fc23a1..dd638c6 100644 --- a/hscript/Expr.hx +++ b/hscript/Expr.hx @@ -237,3 +237,8 @@ enum abstract FieldPropertyAccess(UInt8) { var AGet; var ASet; } + +enum AccessContext { + CInner(cl:String); + COuter; +} diff --git a/hscript/Interp.hx b/hscript/Interp.hx index 995b73d..270de08 100644 --- a/hscript/Interp.hx +++ b/hscript/Interp.hx @@ -168,7 +168,7 @@ class Interp { var curExpr:Expr; #end - var _proxy(default, null):Null = null; + var _proxy(default, null):Null = 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 && { diff --git a/hscript/Parser.hx b/hscript/Parser.hx index d674ad7..e647560 100644 --- a/hscript/Parser.hx +++ b/hscript/Parser.hx @@ -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); diff --git a/hscript/customclass/CustomClass.hx b/hscript/customclass/CustomClass.hx index 2de9600..cb9b10d 100644 --- a/hscript/customclass/CustomClass.hx +++ b/hscript/customclass/CustomClass.hx @@ -44,6 +44,7 @@ class CustomClass implements IHScriptCustomAccessBehaviour { private var __cachedFunctionDecls:Map = []; private var __cachedVarDecls:Map = []; + 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 diff --git a/hscript/customclass/CustomClassDecl.hx b/hscript/customclass/CustomClassDecl.hx index e48556e..6ce021b 100644 --- a/hscript/customclass/CustomClassDecl.hx +++ b/hscript/customclass/CustomClassDecl.hx @@ -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, usings:Array, ?pkg:Array, ?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; } }