"null" access handling + get/set for variables

- It handles "null" allowing access only inside of the class.

- "final" variables can be initialized in the constructor if they doesn't have a default value.

- "var a(get, set):Int" is parsed outside of Custom Class, but for now it doesn't call their accessors.

almost finished :3
This commit is contained in:
Jaime Humberto Macias Bustamante
2025-05-13 00:38:11 -07:00
parent 19b5b2b049
commit 8dce40354a
5 changed files with 158 additions and 54 deletions
+26 -12
View File
@@ -3,6 +3,7 @@ package hscript.customclass;
import hscript.utils.UnsafeReflect;
import haxe.Constraints.Function;
import hscript.Expr;
import hscript.Expr.FieldPropertyAccess;
import hscript.Expr.VarDecl;
import hscript.Expr.FunctionDecl;
import hscript.Expr.FieldDecl;
@@ -44,9 +45,11 @@ class CustomClass implements IHScriptCustomAccessBehaviour {
private var __cachedVarDecls:Map<String, VarDecl> = [];
public var __allowSetGet:Bool = false;
public var __allowInnerAccess:Bool = false;
private var isInline(default, null):Bool = false;
private var ogVariables(default, null):Map<String, Dynamic>;
private var initializing(default, null):Bool = false; // Allows final variables to be initialized
public function new(__class:CustomClassDecl, args:Array<Dynamic>, ?extendFieldDecl:Map<String, Dynamic>, ?ogInterp:Interp, ?callNew:Bool = true) {
this.__class = __class;
@@ -76,7 +79,10 @@ class CustomClass implements IHScriptCustomAccessBehaviour {
if (hasFunction('new') && callNew) {
buildSuperConstructor();
initializing = true;
callFunction('new', args);
initializing = false;
if (this.superClass == null && this.__class.classDecl.extend != null)
this.interp.error(ECustom("super() not called"));
} else if (__class.classDecl.extend != null) {
@@ -94,8 +100,6 @@ class CustomClass implements IHScriptCustomAccessBehaviour {
__cachedFieldDecls.set(f.name, f);
switch (f.kind) {
case KFunction(fn):
if(f.name.startsWith('set_') || f.name.startsWith('get_'))
__allowSetGet = true;
__cachedFunctionDecls.set(f.name, fn);
#if hscriptPos
var fexpr:Expr = {
@@ -111,6 +115,8 @@ class CustomClass implements IHScriptCustomAccessBehaviour {
var func:Function = this.interp.expr(fexpr);
this.interp.variables.set(f.name, func);
case KVar(v):
if(v.get != ADefault || v.set != ADefault)
__allowSetGet = true;
__cachedVarDecls.set(f.name, v);
if (v.expr != null) {
var varValue = this.interp.expr(v.expr);
@@ -316,15 +322,19 @@ class CustomClass implements IHScriptCustomAccessBehaviour {
if (hasVar(name)) {
var v = getVar(name);
var getter = v.get != null ? v.get : 'default';
var getter = v.get;
var value:Dynamic = null;
if(getter == "never")
if(getter == ANever || getter == ANull && !__allowInnerAccess)
throw 'field $name cannot be accessed for reading';
if (__allowSetGet && getter == "get" && hasFunction('get_${name}'))
value = __callGetter(name);
if (__allowSetGet && getter == AGet) {
if (hasFunction('get_$name'))
value = __callGetter(name);
else
throw 'Method get_$name required by property $name is missing';
}
else if (this.interp.variables.exists(name))
value = this.interp.variables.get(name);
else {
@@ -370,13 +380,17 @@ class CustomClass implements IHScriptCustomAccessBehaviour {
default:
if (hasVar(name)) {
var v = getVar(name);
var setter = v.set != null ? v.set : 'default';
var setter = v.set;
if (setter == "never" || (v.isFinal != null && v.isFinal))
if (setter == ANever || setter == ANull && !__allowInnerAccess || (v.isFinal && !initializing))
throw 'field $name cannot be accessed for writing';
if (__allowSetGet && setter == "set" && hasFunction('set_${name}'))
return __callSetter(name, val);
if (__allowSetGet && setter == ASet) {
if (hasFunction('set_$name'))
return __callSetter(name, val);
else
throw 'Method set_$name required by property $name is missing';
}
this.interp.variables.set(name, val);
} else if (this.superClass != null) {
@@ -411,14 +425,14 @@ class CustomClass implements IHScriptCustomAccessBehaviour {
public function __callGetter(name:String):Dynamic {
__allowSetGet = false;
var r = callFunction('get_${name}');
var r = callFunction('get_$name');
__allowSetGet = true;
return r;
}
public function __callSetter(name:String, val:Dynamic):Dynamic {
__allowSetGet = false;
var r = callFunction('set_${name}', [val]);
var r = callFunction('set_$name', [val]);
__allowSetGet = true;
return r;
}
+41 -26
View File
@@ -31,6 +31,8 @@ class CustomClassDecl implements IHScriptCustomAccessBehaviour {
public var __allowSetGet:Bool = true;
public var __allowInnerAccess:Bool = false;
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;
@@ -111,6 +113,8 @@ class CustomClassDecl implements IHScriptCustomAccessBehaviour {
var func:Function = this.staticInterp.expr(fexpr);
this.staticInterp.variables.set(f.name, func);
case KVar(v):
if(v.get != ADefault || v.set != ADefault)
__allowSetGet = true;
_cachedStaticVariables.set(f.name, v);
if (v.expr != null) {
var varValue = this.staticInterp.expr(v.expr);
@@ -166,24 +170,8 @@ class CustomClassDecl implements IHScriptCustomAccessBehaviour {
return _cachedStaticVariables.exists(name);
}
private function getVar(name:String):Dynamic {
var staticVar = _cachedStaticVariables.get(name);
if(staticVar != null) {
var varValue:Dynamic = null;
if(!this.staticInterp.variables.exists(name)) {
if(staticVar.expr != null) {
varValue = this.staticInterp.expr(staticVar.expr);
this.staticInterp.variables.set(name, varValue);
}
}
else {
varValue = this.staticInterp.variables.get(name);
}
return varValue;
}
return null;
private function getVar(name:String):VarDecl {
return _cachedStaticVariables.get(name);
}
/**
@@ -198,16 +186,33 @@ class CustomClassDecl implements IHScriptCustomAccessBehaviour {
}
public function hget(name:String):Dynamic {
var r:Dynamic = null;
if(hasVar(name)) {
if(__allowSetGet && hasFunction('get_${name}'))
r = __callGetter(name);
else
r = getVar(name);
var v = getVar(name);
var getter = v.get;
var r:Dynamic = null;
if (getter == ANever || getter == ANull && !__allowInnerAccess)
throw 'field $name cannot be accessed for reading';
if(__allowSetGet && getter == AGet){
if(hasFunction('get_$name'))
r = __callGetter(name);
else
throw 'Method get_$name required by property $name is missing';
}
else if (this.staticInterp.variables.exists(name))
r = this.staticInterp.variables.get(name);
else {
if(v.expr != null) {
r = this.staticInterp.expr(v.expr);
this.staticInterp.variables.set(name, r);
}
}
return r;
}
if(hasFunction(name)) {
// TODO: optimize this
var fn:Function = Reflect.makeVarArgs(function(args:Array<Dynamic>) {
return this.callFunction(name, args);
});
@@ -219,8 +224,18 @@ class CustomClassDecl implements IHScriptCustomAccessBehaviour {
public function hset(name:String, val:Dynamic):Dynamic {
if (hasVar(name)) {
if (__allowSetGet && hasFunction('set_${name}'))
return __callSetter(name, val);
var v = getVar(name);
var setter = v.set;
if (setter == ANever || setter == ANull && !__allowInnerAccess || v.isFinal)
throw 'field $name cannot be accessed for writing';
if (__allowSetGet && setter == ASet) {
if (hasFunction('set_$name'))
return __callSetter(name, val);
else
throw 'Method set_$name required by property $name is missing';
}
else {
this.staticInterp.variables.set(name, val);
return val;