Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions polymod/Polymod.hx
Original file line number Diff line number Diff line change
Expand Up @@ -1314,6 +1314,35 @@ class Polymod

PolymodScriptClass.bumpBlacklistGeneration();
}

/**
* When a scripted class defines an import for another scripted class, you can blacklist it from being imported.
* @param importPath The full import path to blacklist, as a string.
*/
public static function blacklistScriptClassImport(importPath:String):Void
{
PolymodScriptClass.blacklistedScriptClasses.push(importPath);
}

/**
* When an instance field from a script calss is being called, you can blacklist it from being called.
* @param cls The class type with the fields.
* @param fields The instance fields you want to blacklist.
*/
public static function blacklistScriptClassInstanceFields(cls:String, fields:Array<String>):Void
{
PolymodScriptClass.blacklistedScriptClassInstanceFields.set(cls, fields);
}

/**
* When a static field from a script class is being called, you can blacklist it from being used.
* @param cls The class type with the fields.
* @param fields The static fields you want to blacklist.
*/
public static function blacklistScriptClassStaticFields(cls:String, fields:Array<String>):Void
{
PolymodScriptClass.blacklistedScriptClassStaticFields.set(cls, fields);
}
}

/**
Expand Down
81 changes: 76 additions & 5 deletions polymod/hscript/_internal/Interp.hx
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,16 @@ class Interp
}
#end

else if (Std.isOfType(o, PolymodStaticAbstractReference))
// Check for script class blacklisted fields.
var oScriptCls:Null<String> = Util.getScriptClassName(o);
if (oScriptCls != null && ((PolymodScriptClass.blacklistedScriptClassStaticFields.get(oScriptCls)?.contains(f) ?? false)
|| (PolymodScriptClass.blacklistedScriptClassInstanceFields.get(oScriptCls)?.contains(f) ?? false)))
{
error(EBlacklistedField(f));
return null;
}

if (Std.isOfType(o, PolymodStaticAbstractReference))
{
var ref:PolymodStaticAbstractReference = cast(o, PolymodStaticAbstractReference);
return ref.callFunction(f, args);
Expand Down Expand Up @@ -574,6 +583,31 @@ class Interp
}
}


/**
* Given a class declaration, fetches all fields with the `@:blacklisted` metadata and adds it to the script class blacklist.
* @param cls The class declaration.
*/
static function registerScriptClassBlacklist(cls:ClassDecl):Void
{
var clsName:String = Util.getFullClassName(cls);
if (cls.meta.length > 0 && cls.meta.findIndex((m) -> return m.name == ':blacklisted') != -1)
{
Polymod.blacklistScriptClassImport(clsName);
}

// Filter fields to see which have the `@:blacklisted` metadata.
var staticFields:Array<String> = [for (field in cls.staticFields.filter((f) -> f.meta.length > 0 && f.meta.findIndex((m) -> return m.name == ':blacklisted') != -1)) field.name];
var instanceFields:Array<String> = [for (field in cls.fields.filter((f) -> f.meta.length > 0 && f.meta.findIndex((m) -> return m.name == ':blacklisted') != -1)) field.name];

if (staticFields.length > 0)
Polymod.blacklistScriptClassStaticFields(clsName, staticFields);

if (instanceFields.length > 0)
Polymod.blacklistScriptClassInstanceFields(clsName, instanceFields);
}


static function registerScriptClass(c:ClassDecl)
{
var name = Util.getFullClassName(c);
Expand Down Expand Up @@ -2612,6 +2646,15 @@ class Interp
return null;
}

// Check for script class blacklisted fields.
var oScriptCls:Null<String> = Util.getScriptClassName(o);
if (oScriptCls != null && ((PolymodScriptClass.blacklistedScriptClassStaticFields.get(oScriptCls)?.contains(f) ?? false)
|| (PolymodScriptClass.blacklistedScriptClassInstanceFields.get(oScriptCls)?.contains(f) ?? false)))
{
error(EBlacklistedField(f));
return null;
}

// If not, check if it is a blacklisted instance field.
if (oCls.length > 0 && oCls != 'Object')
{
Expand Down Expand Up @@ -2746,6 +2789,15 @@ class Interp
}
}

// Check for script class blacklisted.
var oScriptCls:Null<String> = Util.getScriptClassName(o);
if (oScriptCls != null && ((PolymodScriptClass.blacklistedScriptClassStaticFields.get(oScriptCls)?.contains(f) ?? false)
|| (PolymodScriptClass.blacklistedScriptClassInstanceFields.get(oScriptCls)?.contains(f) ?? false)))
{
error(EBlacklistedField(f));
return null;
}

// Otherwise, we assume the field is fine to use.
if (Std.isOfType(o, PolymodStaticAbstractReference))
{
Expand Down Expand Up @@ -3024,6 +3076,7 @@ class Interp
isExtern: c.isExtern,
staticFields: staticFields,
};
registerScriptClassBlacklist(classDecl);
registerScriptClass(classDecl);
case DEnum(e):
if (isImportFile) continue;
Expand Down Expand Up @@ -3064,6 +3117,19 @@ class Interp

public static function validateImports():Void
{
function tryImport(cls:ClassDecl, clsImport:ClassImport):Void
{
if (PolymodScriptClass.blacklistedScriptClasses.contains(clsImport.fullPath))
{
// Set as `null` so it's registered as blacklisted.
cls.imports.set(clsImport.name, null);
}
else
{
cls.imports.set(clsImport.name, clsImport);
}
}

for (cls in _scriptClassDescriptors)
{
var clsPath = Util.getFullClassName(cls);
Expand All @@ -3081,15 +3147,15 @@ class Interp

if ((imp.pkg?.length ?? 0) == 0)
{
cls.imports.set(imp.name, classImport);
tryImport(cls, classImport);
continue;
}

var hasPackage:Bool = cls.pkg != null && cls.pkg.length > 0;
var fullPackage:String = hasPackage ? cls.pkg.join(".") + "." : "";
if (hasPackage && clsPath.indexOf(fullPackage) == 0)
{
cls.imports.set(imp.name, classImport);
tryImport(cls, classImport);
}
}

Expand All @@ -3105,7 +3171,7 @@ class Interp
if (imp.wildcard)
importWildcard(cls, imp);
else
cls.imports.set(imp.name, imp);
tryImport(cls, imp);
}
}

Expand All @@ -3127,7 +3193,7 @@ class Interp

if (_scriptClassDescriptors.exists(imp.fullPath))
{
cls.imports.set(key, imp);
tryImport(cls, imp);
continue;
}

Expand Down Expand Up @@ -3247,6 +3313,11 @@ class Interp
// Check if this is a scripted class.
if (_scriptClassDescriptors.exists(classImport.fullPath) || _scriptEnumDescriptors.exists(classImport.fullPath))
{
if (PolymodScriptClass.blacklistedScriptClasses.contains(classImport.fullPath) && !_scriptEnumDescriptors.exists(classImport.fullPath))
{
cls.imports.set(classImport.name, null);
continue;
}
cls.imports.set(classImport.name, classImport);
continue;
}
Expand Down
22 changes: 22 additions & 0 deletions polymod/hscript/_internal/PolymodScriptClass.hx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,24 @@ class PolymodScriptClass
*/
public static final blacklistedInstanceFields:Map<String, Array<String>> = new Map<String, Array<String>>();

/*
* List of blacklisted full package script classes that aren't able to be imported.
* Cleared everytime scripts are reset.
*/
public static var blacklistedScriptClasses:Array<String> = [];

/**
* Provide a scripted class with an array of its static fields to blacklist them.
* Blacklisted fields cannot be gotten or set.
*/
public static final blacklistedScriptClassStaticFields:Map<String, Array<String>> = new Map<String, Array<String>>();

/**
* Provide a scripted class with an array of its static fields to blacklist them.
* Blacklisted fields cannot be gotten or set.
*/
public static final blacklistedScriptClassInstanceFields:Map<String, Array<String>> = new Map<String, Array<String>>();

/**
* Field names that may not be reached even through a receiver whose type is not known.
*/
Expand Down Expand Up @@ -460,6 +478,10 @@ class PolymodScriptClass
public static function clearScriptedClasses():Void
{
scriptInterp.clearScriptClassDescriptors();

blacklistedScriptClasses = [];
blacklistedScriptClassStaticFields.clear();
blacklistedScriptClassInstanceFields.clear();
}

/**
Expand Down
2 changes: 1 addition & 1 deletion polymod/hscript/_internal/PolymodStaticClassReference.hx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class PolymodStaticClassReference
#end

@:privateAccess {
if (Interp._scriptClassDescriptors.exists(clsName))
if (Interp._scriptClassDescriptors.exists(clsName) && !PolymodScriptClass.blacklistedScriptClasses.contains(clsName))
{
return new PolymodStaticClassReference(Interp._scriptClassDescriptors.get(clsName));
}
Expand Down
21 changes: 21 additions & 0 deletions polymod/util/Util.hx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import polymod.format.BaseParseFormat;
import polymod.format.ParseRules;
import polymod.fs.PolymodFileSystem.IFileSystem;
import polymod.hscript._internal.Expr;
import polymod.hscript._internal.Interp;
import polymod.hscript._internal.PolymodScriptClass;
import polymod.hscript._internal.PolymodStaticClassReference;
#if unifill
import unifill.Unifill;
#end
Expand Down Expand Up @@ -780,6 +783,24 @@ class Util
}
}

public static function getScriptClassName(cls:Dynamic):Null<String>
{
var clsName:Null<String> = null;
if (Std.isOfType(cls, PolymodStaticClassReference))
{
clsName = cast(cls, PolymodStaticClassReference).getFullyQualifiedName();
}
else if (Std.isOfType(cls, PolymodScriptClass))
{
clsName = cast(cls, PolymodScriptClass).fullyQualifiedName;
}
else if (Std.isOfType(cls, String))
{
clsName = getFullClassName(Interp.findScriptClassDescriptor(cast cls));
}
return clsName;
}

/**
* Retrieves the full qualified name of a class declaration.
* @param clsDecl The class declaration.
Expand Down