How to build type from array using metadata?

73 views
Skip to first unread message

Dlean Jeans

unread,
May 27, 2016, 5:22:37 AM5/27/16
to Haxe
I have a game which could load some data from a json file and convert them into a type.
In this case, it converts to Upgrade type and store them in Upgrade._upgrades and they can be access from Upgrades.getUpgrade() like Upgrades.getUpgrade("health"). I wonder how to use a metadata like @:build to build the upgrades to Upgrades class and allow me to access the upgrades like Upgrades.health instead.

Munir Hussin

unread,
May 27, 2016, 11:05:04 AM5/27/16
to Haxe
If you're looking for a macro to load json files at compile time, you might want to check out the compiletime haxe lib. Or if at compile-time, you want haxe to be more syntax-tolerant and report error line numbers from the json file, then check out nadako's article on it.

If you want to roll your own, this tutorial is great to show how to write macros for code completion of any stuff (in the example, it's files from the filesystem).

Mark Knol

unread,
May 27, 2016, 3:22:21 PM5/27/16
to Haxe
And dont forget to check the macro section in the code cookbook http://code.haxe.org/ :)

Dlean Jeans

unread,
May 28, 2016, 2:11:27 AM5/28/16
to Haxe
I'm having some problems. If I add my macro, AssetPaths from HaxeFlixel will throw a error: You cannot use @:build inside a macro : make sure that your enum is not used in macro. Maybe I should contact the HaxeFlixel devs?

Here's some code:

Main.hx:
class Main extends Sprite {
public function new() {
trace(Upgrades.getUpgrade("health").getName()); // this would work
trace(Upgrades.health.getName()); // this will make AssetPaths throw the error
super();
}
}

AssetPaths.hx:
// You cannot use @:build inside a macro : make sure that your enum is not used in macro
@:build(flixel.system.FlxAssets.buildFileReferences("assets", true))
class AssetPaths {}

Upgrade.hx:
@:build(UpgradesMacro.build())
class Upgrades {
private static var _upgrades:Array<Upgrade>;
private static var _varNames:Array<String>;
public static function getUpgrade(varName:String):Upgrade {
if (_upgrades == null || _varNames == null) {
_upgrades = UpgradeJsonParser.getUpgrades();
_varNames = UpgradeJsonParser.getVarNames();
}
for (i in 0..._upgrades.length) {
var upgrade:Upgrade = _upgrades[i];
if (varName == _varNames[i])
return upgrade;
}
throw 'Upgrade $varName does not exist';
}
}

UpgradesBuilder.hx:
class UpgradesMacro {
#if macro
public macro static function build():Array<Field> {
var upgrades:Array<Upgrade> = UpgradeJsonParser.getUpgrades();
var varNames:Array<String> = UpgradeJsonParser.getVarNames();
var fields = Context.getBuildFields();
for (i in 0...upgrades.length) {
var upgrade:Upgrade = upgrades[i];
var varName:String = varNames[i];
fields.push({
name:varName,
access:[Access.APublic, Access.AStatic],
kind:FieldType.FVar(macro:Upgrade, macro $v{upgrade}),
pos:Context.currentPos(),
});
}
return fields;
}
#end
}

Dlean Jeans

unread,
May 30, 2016, 9:25:57 AM5/30/16
to Haxe
I just got macro to build some typedef successfully :D. But I don't know if I can build some fields of complex types / non-basic types. In this case, Upgrade class which is converted from a typedef.
Reply all
Reply to author
Forward
0 new messages