I’ve just got into using macros to try to get this one weird bit of functionality working, and I think I’ve almost gotten what I want. What I’m trying to do is build a class at compile time that combines a set of input classes, so for example, these two classes:
class TestClass
{
public var floatField:Float;
public var intField:Int;
}
class TestClass2
{
public var floatField:Float;
// this would compile to an error as the types don't match
// public var intField:String;
public var stringField:String;
}
would become:
class CombinedClass
{
public var floatField:Float;
public var intField:Int;
public var stringField:String;
}
What I want to use this for looks like this:
var combinedObj:CombinedClass;
var testObj:TestClass = cast combinedObj;
testObj.intField = 4; //type safe!
trace(combinedObj.intField); //4
I currently have this implemented using an autoBuild macro that adds all of the class fields to a static list, and then at some point generateClass is called that puts it all together and defines the type. I’ve put the macro source here.
However, the execution order of the macros is obviously really important, and I’ve found that I can guarantee the macro order like this:
TestClass2;
TestClass;
TestMacro.generateClass();
But that’s not so ideal. Having to state the classes used in a specific place undermines the benefits of having this API. Reading this, it states quite ambiguously that the order of build macros specifically is undefined, and that multi-pass macros should happen in the macro source. This left me under the impression that expression macros would be delayed until after the build macros are all run, but in testing I’ve found that this isn’t true.
My question is, essentially, how do I get the right behavior? If I could call macro.context.defineType multiple times and overwrite the class in each call to the build macro, that would do it. If I could delay a macro execution until after all of the build macros, that would also do it. If I could access the list of class fields at runtime, I could build anonymous structures instead, and that would work in the same way. The reason I feel like this should be possible is that the API will not be exposing the combined class to the user, so any solution that doesn’t require the user to jump through hoops would be enough.
Thanks in advance!