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
19 changes: 12 additions & 7 deletions polymod/hscript/_internal/PolymodInterpEx.hx
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ class PolymodInterpEx extends Interp
continue;
}

Polymod.error(SCRIPT_CLASS_MODULE_NOT_FOUND, 'Could not import ${imp.fullPath}', clsPath);
Polymod.error(SCRIPT_CLASS_MODULE_NOT_FOUND, 'Could not import ${imp.fullPath}. Check to ensure the module exists and is spelled correctly.', clsPath);
}

// Check if the scripted classes extend the right type.
Expand All @@ -338,15 +338,15 @@ class PolymodInterpEx extends Interp
case CTPath(path, params):
if (params != null && params.length > 0)
{
Polymod.error(SCRIPT_CLASS_MODULE_NOT_FOUND, 'Could not extend ${superClassPath}, do not include type parameters in super class name', clsPath);
Polymod.error(SCRIPT_CLASS_MODULE_NOT_FOUND, 'Could not extend ${superClassPath}, do not include type parameters in super class name.', clsPath);
}

default:
// Other error handling?
}

// Default
Polymod.error(SCRIPT_CLASS_MODULE_NOT_FOUND, 'Could not extend ${superClassPath}, is the type imported?', clsPath);
Polymod.error(SCRIPT_CLASS_MODULE_NOT_FOUND, 'Could not extend ${superClassPath}. Make sure the type to extend has been imported.', clsPath);
}
else
{
Expand Down Expand Up @@ -1852,8 +1852,15 @@ class PolymodInterpEx extends Interp
} else if (PolymodScriptClass.abstractClassImpls.exists(importedClass.fullPath)) {
// We used a macro to map each abstract to its implementation.
importedClass.cls = PolymodScriptClass.abstractClassImpls.get(importedClass.fullPath);
trace('RESOLVED ABSTRACT CLASS ${importedClass.fullPath} -> ${Type.getClassName(importedClass.cls)}');
trace(Type.getClassFields(importedClass.cls));

if (importedClass.cls == null) {
trace('UNRESOLVED ABSTRACT CLASS ${importedClass.fullPath}');
Polymod.warning(SCRIPT_CLASS_MODULE_NOT_FOUND, 'Abstract type ${importedClass.fullPath} could not be resolved. Try using the underlying type instead.', origin);
} else {
trace('RESOLVED ABSTRACT CLASS ${importedClass.fullPath} -> ${Type.getClassName(importedClass.cls)}');
trace(Type.getClassFields(importedClass.cls));
}

} else if (_scriptEnumDescriptors.exists(importedClass.fullPath)) {
// do nothing
} else {
Expand All @@ -1866,7 +1873,6 @@ class PolymodInterpEx extends Interp

// If the class is still not found, skip this import entirely.
if (resultCls == null && resultEnm == null) {
//Polymod.error(SCRIPT_CLASS_MODULE_NOT_FOUND, 'Could not import class ${importedClass.fullPath}', origin);
// this could be a scripted class or enum that hasn't been registered yet
importsToValidate.set(importedClass.name, importedClass);
continue;
Expand Down Expand Up @@ -1917,7 +1923,6 @@ class PolymodInterpEx extends Interp

// If the class is still not found, skip this import entirely.
if (resultCls == null) {
//Polymod.error(SCRIPT_CLASS_MODULE_NOT_FOUND, 'Could not import class ${importedClass.fullPath}', origin);
// this could be a scripted class that hasn't been registered yet
importsToValidate.set(importedClass.name, importedClass);
continue;
Expand Down
140 changes: 76 additions & 64 deletions polymod/hscript/_internal/PolymodScriptClassMacro.hx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ using StringTools;
class PolymodScriptClassMacro {
/**
* Returns a `Map<String, Class<Dynamic>>` which maps superclass paths to scripted classes.
* So `class ScriptedStage extends Stage implements HScriptable` will be `"Stage" -> ScriptedStage`
* So `class ScriptedStage extends Stage implements HScriptable` will be `"Stage" -> ScriptedStage`
*/
public static macro function listHScriptedClasses():ExprOf<Map<String, Class<Dynamic>>> {
if (!onGenerateCallbackRegistered)
Expand Down Expand Up @@ -62,22 +62,22 @@ class PolymodScriptClassMacro {
static var onAfterTypingCallbackRegistered:Bool = false;

static function onGenerate(allTypes:Array<haxe.macro.Type>) {
// Reset these, since onGenerate persists across multiple builds.
// Reset these, since onGenerate persists across multiple builds.
var hscriptedClassType:ClassType = MacroUtil.getClassType('polymod.hscript.HScriptedClass');

var hscriptedClassEntries:Array<Expr> = [];
var hscriptedClassEntries:Array<Expr> = [];
var abstractImplEntries:Array<Expr> = [];
var abstractStaticEntries:Array<Expr> = [];

for (type in allTypes) {
switch (type) {
// Class instances
case TInst(t, _params):
var classType:ClassType = t.get();
var classType:ClassType = t.get();
var classPath:String = '${classType.pack.concat([classType.name]).join(".")}';

if (classType.isInterface) {
// Ignore interfaces.
if (classType.isInterface) {
// Ignore interfaces.
} else if (MacroUtil.implementsInterface(classType, hscriptedClassType)) {
// Context.info('${classPath} implements HScriptedClass? YEAH', Context.currentPos());
// TODO: Do we need to parameterize?
Expand All @@ -95,54 +95,54 @@ class PolymodScriptClassMacro {
} else { }
case TAbstract(t, _params):
var abstractPath:String = t.toString();
if (abstractPath == 'flixel.util.FlxColor') {
var abstractType = t.get();
var abstractImpl = abstractType.impl.get();
var abstractImplPath = abstractType.impl.toString();
// Context.info('${abstractImplPath} implements FlxColor', Context.currentPos());
var abstractType = t.get();
var abstractImpl = abstractType.impl?.get();
var abstractImplPath:String = abstractType.impl?.toString() ?? '';

var entryData = [
macro $v{abstractPath},
macro $v{abstractImplPath}
];
if (abstractImpl == null) {
// If the abstract doesn't have an implementation, it's usually an extern or something, so we always want to ignore it.
continue;
}

abstractImplEntries.push(macro $a{entryData});
var entryData = [
macro $v{abstractPath},
macro $v{abstractImplPath}
];

for (field in abstractImpl.statics.get()) {
switch (field.type) {
case TAbstract(_, _):
//
case TType(_, _):
//
default:
continue;
}

var key:String = '${abstractImplPath}.${field.name}';
abstractImplEntries.push(macro $a{entryData});

if (!staticFieldToClass.exists(key)) {
for (field in abstractImpl.statics.get()) {
switch (field.type) {
case TAbstract(_, _):
//
case TType(_, _):
//
default:
continue;
}

var staticEntryData = [
macro $v{key},
macro $v{staticFieldToClass[key]},
];
}

var key:String = '${abstractImplPath}.${field.name}';

abstractStaticEntries.push(macro $a{staticEntryData});
if (!staticFieldToClass.exists(key)) {
continue;
}

// Try to apply RTTI?
abstractType.meta.add(':rtti', [], Context.currentPos());
abstractImpl.meta.add(':rtti', [], Context.currentPos());
var staticEntryData = [
macro $v{key},
macro $v{staticFieldToClass[key]},
];

abstractStaticEntries.push(macro $a{staticEntryData});
}
default:
continue;
continue;
}
}

var polymodScriptClassClassType:ClassType = MacroUtil.getClassType('polymod.hscript._internal.PolymodScriptClassMacro');
polymodScriptClassClassType.meta.remove('hscriptedClasses');
Context.info('PolymodScriptClassMacro: Registering ${hscriptedClassEntries.length} HScriptedClasses, ${abstractImplEntries.length} abstract impls, ${abstractStaticEntries.length} abstract statics', Context.currentPos());

var polymodScriptClassClassType:ClassType = MacroUtil.getClassType('polymod.hscript._internal.PolymodScriptClassMacro');
polymodScriptClassClassType.meta.remove('hscriptedClasses');
polymodScriptClassClassType.meta.add('hscriptedClasses', hscriptedClassEntries, Context.currentPos());
polymodScriptClassClassType.meta.remove('abstractImpls');
polymodScriptClassClassType.meta.add('abstractImpls', abstractImplEntries, Context.currentPos());
Expand All @@ -161,11 +161,15 @@ class PolymodScriptClassMacro {
var abstractPath = a.toString();
var abstractType = a.get();

if (abstractPath != 'flixel.util.FlxColor') {
// If the abstract is private, the implementation won't be accessible.
var abstractIsPrivate = abstractType.isPrivate;
if (abstractIsPrivate) {
continue;
}

if (abstractType.impl == null) {

// Check if, for other reasons, the implementation is missing.
var abstractHasNoImpl = abstractType.impl == null;
if (abstractHasNoImpl) {
continue;
}

Expand All @@ -175,8 +179,6 @@ class PolymodScriptClassMacro {
for (field in abstractImplType.statics.get()) {
switch (field.kind) {
case FVar(read, write):
trace(field.name, read, write);

var canGet:Bool = read == AccInline || read == AccNormal;
if (read == AccCall) {
var getter:Null<ClassField> = null;
Expand All @@ -187,15 +189,15 @@ class PolymodScriptClassMacro {
}

if (getter == null) {
throw 'This should not happen';
throw 'Getter is null?';
}

switch (getter.type) {
case TFun(args, _):
if (args.length != 0)
continue;
default:
throw 'This should not happen';
throw 'Getter has an unknown type?';
}

canGet = true;
Expand All @@ -211,15 +213,15 @@ class PolymodScriptClassMacro {
}

if (setter == null) {
throw 'This should not happen';
throw 'Setter is null?';
}

switch (setter.type) {
case TFun(args, _):
if (args.length != 1)
continue;
default:
throw 'This should not happen';
throw 'Setter has an unknown type?';
}

canSet = true;
Expand All @@ -235,9 +237,20 @@ class PolymodScriptClassMacro {
pos: Context.currentPos(),
name: fieldName,
access: [Access.APublic, Access.AStatic],
kind: FProp(canGet ? 'get' : 'never', canSet ? 'set' : 'never', Context.toComplexType(field.type), null)
kind: FProp(canGet ? 'get' : 'never', canSet ? 'set' : 'never', (macro: Dynamic), null)
});

var fieldExpr:Expr = null;
try {
// when this fails, this should mean that we are dealing with an enum abstract
// so we need to handle it differently
var fullPath:String = '${abstractType.module}.${abstractType.name}';
Context.getType(fullPath);
fieldExpr = Context.parse('${fullPath}.${field.name}', Context.currentPos());
} catch (_) {
fieldExpr = Context.getTypedExpr(field.expr());
}

if (canGet) {
fields.push({
pos: Context.currentPos(),
Expand All @@ -248,7 +261,7 @@ class PolymodScriptClassMacro {
ret: null,
expr: macro {
@:privateAccess
return ${Context.parse(abstractPath + '.' + field.name, Context.currentPos())};
return ${fieldExpr};
}
})
});
Expand All @@ -264,7 +277,7 @@ class PolymodScriptClassMacro {
ret: null,
expr: macro {
@:privateAccess
return ${Context.parse(abstractPath + '.' + field.name, Context.currentPos())} = value;
return ${fieldExpr} = value;
}
})
});
Expand Down Expand Up @@ -299,25 +312,25 @@ class PolymodScriptClassMacro {
public static function fetchHScriptedClasses():Map<String, Class<Dynamic>> {
var metaData = Meta.getType(PolymodScriptClassMacro);

// trace('Got metaData: ' + metaData);
// trace('Got metaData: ' + metaData);

if (metaData.hscriptedClasses != null) {
trace('Got hscriptedClasses: ' + metaData.hscriptedClasses);
trace('Got hscriptedClasses: ' + metaData.hscriptedClasses);

var result:Map<String, Class<Dynamic>> = [];

// Each element is formatted as `[superClassPath, classPath]`.

for (element in metaData.hscriptedClasses) {
if (element.length != 2) {
throw 'Malformed element in hscriptedClasses: ' + element;
}
if (element.length != 2) {
throw 'Malformed element in hscriptedClasses: ' + element;
}

var superClassPath:String = element[0];
var classPath:String = element[1];
var superClassPath:String = element[0];
var classPath:String = element[1];
var classType:Class<Dynamic> = cast Type.resolveClass(classPath);
result.set(superClassPath, classType);
}
result.set(superClassPath, classType);
}

return result;
} else {
Expand All @@ -340,7 +353,6 @@ class PolymodScriptClassMacro {

var abstractPath:String = element[0];
var abstractImplPath:String = element[1];
// var abstractType:Class<Dynamic> = cast Type.resolveClass(abstractPath);
#if js
trace('Resolving using JS method');
var abstractImplType:Class<Dynamic> = resolveClass(abstractPath);
Expand All @@ -353,7 +365,7 @@ class PolymodScriptClassMacro {
var abstractImplType:Class<Dynamic> = cast Type.resolveClass(abstractImplPath);

if (abstractImplType == null) {
throw 'Could not resolve ' + abstractImplPath;
// trace('POLYMOD ABSTRACTS: Could not resolve $abstractImplPath');
}
#end

Expand Down