Skip to content

Commit 1364298

Browse files
committed
enums
1 parent 958b916 commit 1364298

File tree

5 files changed

+254
-1
lines changed

5 files changed

+254
-1
lines changed

polymod/Polymod.hx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,7 @@ class Polymod
655655
#if hscript
656656
@:privateAccess
657657
polymod.hscript._internal.PolymodScriptClass.clearScriptedClasses();
658+
polymod.hscript._internal.PolymodEnum.clearScriptedEnums();
658659
polymod.hscript.HScriptable.ScriptRunner.clearScripts();
659660
#else
660661
Polymod.warning(SCRIPT_HSCRIPT_NOT_INSTALLED, "Cannot register script classes, HScript is not available.");
@@ -691,6 +692,8 @@ class Polymod
691692
polymod.hscript._internal.PolymodScriptClass.registerScriptClassByPath(path);
692693
}
693694
}
695+
696+
polymod.hscript._internal.PolymodInterpEx.validateImports();
694697
}
695698
#else
696699
Polymod.warning(SCRIPT_HSCRIPT_NOT_INSTALLED, "Cannot register script classes, HScript is not available.");
@@ -1324,6 +1327,13 @@ enum abstract PolymodErrorCode(String) from String to String
13241327
*/
13251328
var SCRIPT_CLASS_MODULE_BLACKLISTED:String = 'script_class_module_blacklisted';
13261329

1330+
/**
1331+
* You attempted to register a new enum with a name that is already in use.
1332+
* - Rename the enum to one that is unique and will not conflict with other enums.
1333+
* - If you need to clear all existing enum descriptors, call `Polymod.clearScripts()`.
1334+
*/
1335+
var SCRIPT_ENUM_ALREADY_REGISTERED:String = 'script_enum_already_registered';
1336+
13271337
/**
13281338
* One or more scripts are about to be parsed.
13291339
* - This is an info message. You can log it or ignore it if you like.

polymod/hscript/_internal/PolymodClassDeclEx.hx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ typedef PolymodClassDeclEx =
1414
* Save performance and improve sandboxing by resolving imports at interpretation time.
1515
*/
1616
@:optional var imports:Map<String, PolymodClassImport>;
17+
@:optional var importsToValidate:Map<String, PolymodClassImport>;
1718
@:optional var pkg:Array<String>;
1819

1920
@:optional var staticFields:Array<FieldDecl>;
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package polymod.hscript._internal;
2+
3+
#if hscript
4+
import hscript.Expr;
5+
6+
@:access(hscript.Interp)
7+
@:allow(polymod.Polymod)
8+
class PolymodEnum
9+
{
10+
private static final scriptInterp = new PolymodInterpEx(null, null);
11+
12+
private var _e:PolymodEnumDeclEx;
13+
14+
private var _value:String;
15+
16+
private var _args:Array<Dynamic>;
17+
18+
public function new(e:PolymodEnumDeclEx, value:String, args:Array<Dynamic>)
19+
{
20+
this._e = e;
21+
22+
var field = getField(value);
23+
24+
if (field == null)
25+
{
26+
Polymod.error(SCRIPT_PARSE_ERROR, '${e.name}.${value} does not exist.');
27+
return;
28+
}
29+
30+
this._value = value;
31+
32+
if (args.length != field.args.length)
33+
{
34+
Polymod.error(SCRIPT_PARSE_ERROR, '${e.name}.${value} got the wrong number of arguments.');
35+
return;
36+
}
37+
38+
this._args = args;
39+
}
40+
41+
public static function clearScriptedEnums():Void
42+
{
43+
scriptInterp.clearScriptEnumDescriptors();
44+
}
45+
46+
private function getField(name:String):Null<EnumFieldDecl>
47+
{
48+
for (field in _e.fields)
49+
{
50+
if (field.name == name)
51+
{
52+
return field;
53+
}
54+
}
55+
return null;
56+
}
57+
}
58+
#end
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package polymod.hscript._internal;
2+
3+
#if hscript
4+
import hscript.Expr;
5+
6+
typedef PolymodEnumDeclEx =
7+
{
8+
> EnumDecl,
9+
10+
@:optional var pkg:Array<String>;
11+
}
12+
13+
#end

polymod/hscript/_internal/PolymodInterpEx.hx

Lines changed: 172 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import polymod.hscript._internal.PolymodClassDeclEx.PolymodStaticClassReference;
1414
*/
1515
@:access(polymod.hscript._internal.PolymodScriptClass)
1616
@:access(polymod.hscript._internal.PolymodAbstractScriptClass)
17+
@:access(polymod.hscript._internal.PolymodEnum)
1718
class PolymodInterpEx extends Interp
1819
{
1920
var targetCls:Class<Dynamic>;
@@ -194,6 +195,53 @@ class PolymodInterpEx extends Interp
194195
return _scriptClassDescriptors.get(name);
195196
}
196197

198+
private static var _scriptEnumDescriptors:Map<String, PolymodEnumDeclEx> = new Map<String, PolymodEnumDeclEx>();
199+
200+
private static function registerScriptEnum(e:PolymodEnumDeclEx)
201+
{
202+
var name = e.name;
203+
if (e.pkg != null)
204+
{
205+
name = e.pkg.join(".") + "." + name;
206+
}
207+
208+
if (_scriptEnumDescriptors.exists(name)) {
209+
Polymod.error(SCRIPT_ENUM_ALREADY_REGISTERED, 'An enum with the fully qualified name "$name" has already been defined. Please change the enum name to ensure a unique name.');
210+
return;
211+
} else {
212+
Polymod.debug('Registering enum $name');
213+
_scriptEnumDescriptors.set(name, e);
214+
}
215+
}
216+
217+
public function clearScriptEnumDescriptors():Void {
218+
// Clear the script enum descriptors.
219+
_scriptEnumDescriptors.clear();
220+
221+
// Also destroy local variable scope.
222+
this.resetVariables();
223+
}
224+
225+
private static function validateImports():Void
226+
{
227+
for (cls in _scriptClassDescriptors)
228+
{
229+
var clsPath = cls.pkg != null ? (cls.pkg.join(".") + ".") : "";
230+
clsPath += cls.name;
231+
232+
for (key => imp in cls.importsToValidate)
233+
{
234+
if (_scriptEnumDescriptors.exists(imp.fullPath))
235+
{
236+
cls.imports.set(key, imp);
237+
continue;
238+
}
239+
240+
Polymod.error(SCRIPT_CLASS_MODULE_NOT_FOUND, 'Could not import ${imp.fullPath}', clsPath);
241+
}
242+
}
243+
}
244+
197245
override function setVar(id:String, v:Dynamic)
198246
{
199247
if (_proxy != null && _proxy.superClass != null)
@@ -463,6 +511,89 @@ class PolymodInterpEx extends Interp
463511
// If there is a try/catch block, the error will be caught.
464512
// If there is no try/catch block, the error will be reported.
465513
errorEx(EScriptThrow(str));
514+
515+
// Enums
516+
case EField(e,f):
517+
var name = getIdent(e);
518+
name = getClassDecl().imports.get(name)?.fullPath ?? name;
519+
if (name != null && _scriptEnumDescriptors.exists(name))
520+
{
521+
return new PolymodEnum(_scriptEnumDescriptors.get(name), f, []);
522+
}
523+
case ECall(e,params):
524+
var args = new Array();
525+
for (p in params)
526+
args.push(expr(p));
527+
528+
switch(Tools.expr(e)) {
529+
case EField(e,f):
530+
var name = getIdent(e);
531+
name = getClassDecl().imports.get(name)?.fullPath ?? name;
532+
if (name != null && _scriptEnumDescriptors.exists(name))
533+
{
534+
return new PolymodEnum(_scriptEnumDescriptors.get(name), f, args);
535+
}
536+
default:
537+
}
538+
case ESwitch(e, cases, def):
539+
var val:Dynamic = expr(e);
540+
541+
if (Std.isOfType(val, PolymodEnum))
542+
{
543+
var old:Int = declared.length;
544+
var match = false;
545+
for(c in cases)
546+
{
547+
for(v in c.values)
548+
{
549+
switch (Tools.expr(v))
550+
{
551+
case ECall(e, params):
552+
switch (Tools.expr(e))
553+
{
554+
case EField(_, f):
555+
if (val._value == f)
556+
{
557+
for (i => p in params)
558+
{
559+
switch (Tools.expr(p))
560+
{
561+
case EIdent(n):
562+
declared.push({
563+
n: n,
564+
old: {r: locals.get(n)}
565+
});
566+
locals.set(n, {r: val._args[i]});
567+
default:
568+
}
569+
}
570+
match = true;
571+
break;
572+
}
573+
default:
574+
}
575+
case EField(_, f):
576+
if (val._value == f)
577+
{
578+
match = true;
579+
break;
580+
}
581+
default:
582+
}
583+
}
584+
if(match)
585+
{
586+
val = expr(c.expr);
587+
break;
588+
}
589+
}
590+
if (!match)
591+
{
592+
val = def == null ? null : expr(def);
593+
}
594+
restore(old);
595+
return val;
596+
}
466597
default:
467598
// Do nothing.
468599
}
@@ -601,6 +732,21 @@ class PolymodInterpEx extends Interp
601732
return a;
602733
}
603734

735+
function getIdent(e:Expr):Null<String> {
736+
#if hscriptPos
737+
switch (e.e)
738+
{
739+
#else
740+
switch (e)
741+
{
742+
#end
743+
case EIdent(v):
744+
return v;
745+
default:
746+
return null;
747+
}
748+
}
749+
604750
override function makeIterator(v:Dynamic):Iterator<Dynamic>
605751
{
606752
if (v.iterator != null)
@@ -1255,6 +1401,7 @@ class PolymodInterpEx extends Interp
12551401
{
12561402
var pkg:Array<String> = null;
12571403
var imports:Map<String, PolymodClassImport> = [];
1404+
var importsToValidate:Map<String, PolymodClassImport> = [];
12581405

12591406
for (importPath in PolymodScriptClass.defaultImports.keys())
12601407
{
@@ -1306,6 +1453,8 @@ class PolymodInterpEx extends Interp
13061453
importedClass.cls = PolymodScriptClass.abstractClassImpls.get(importedClass.fullPath);
13071454
trace('RESOLVED ABSTRACT CLASS ${importedClass.fullPath} -> ${Type.getClassName(importedClass.cls)}');
13081455
trace(Type.getClassFields(importedClass.cls));
1456+
} else if (_scriptEnumDescriptors.exists(importedClass.fullPath)) {
1457+
// do nothing
13091458
} else {
13101459
var resultCls:Class<Dynamic> = Type.resolveClass(importedClass.fullPath);
13111460

@@ -1316,7 +1465,9 @@ class PolymodInterpEx extends Interp
13161465

13171466
// If the class is still not found, skip this import entirely.
13181467
if (resultCls == null && resultEnm == null) {
1319-
Polymod.error(SCRIPT_CLASS_MODULE_NOT_FOUND, 'Could not import class ${importedClass.fullPath}', origin);
1468+
//Polymod.error(SCRIPT_CLASS_MODULE_NOT_FOUND, 'Could not import class ${importedClass.fullPath}', origin);
1469+
// this could be a scripted class or enum that hasn't been registered yet
1470+
importsToValidate.set(importedClass.name, importedClass);
13201471
continue;
13211472
} else if (resultCls != null) {
13221473
importedClass.cls = resultCls;
@@ -1372,6 +1523,7 @@ class PolymodInterpEx extends Interp
13721523

13731524
var classDecl:PolymodClassDeclEx = {
13741525
imports: imports,
1526+
importsToValidate: importsToValidate,
13751527
pkg: pkg,
13761528
name: c.name,
13771529
params: c.params,
@@ -1384,6 +1536,25 @@ class PolymodInterpEx extends Interp
13841536
staticFields: staticFields,
13851537
};
13861538
registerScriptClass(classDecl);
1539+
case DEnum(e):
1540+
if (pkg != null)
1541+
{
1542+
imports.set(e.name, {
1543+
name: e.name,
1544+
pkg: pkg,
1545+
fullPath: pkg.join(".") + "." + e.name,
1546+
cls: null,
1547+
enm: null,
1548+
});
1549+
}
1550+
1551+
var enumDecl:PolymodEnumDeclEx = {
1552+
pkg: pkg,
1553+
name: e.name,
1554+
fields: e.fields,
1555+
};
1556+
1557+
registerScriptEnum(enumDecl);
13871558
case DTypedef(_):
13881559
}
13891560
}

0 commit comments

Comments
 (0)