Skip to content

Instantly share code, notes, and snippets.

@haxiomic
Last active July 7, 2017 07:57
Show Gist options
  • Save haxiomic/1e6e0cffc1a27f4f09d8 to your computer and use it in GitHub Desktop.
Save haxiomic/1e6e0cffc1a27f4f09d8 to your computer and use it in GitHub Desktop.
import haxe.macro.Context;
import haxe.macro.Expr;
import haxe.macro.ExprTools;
class ClassBuild{
//the entire contents of a class is contained in the class's fields
//a class-building-macro's job is to return an array of fields
static function saveClass():Array<Field>{
//we want to keep the currently defined fields intact, so first we get them from the context
var fields = Context.getBuildFields();
//the plan is to add a new field (which will be a function) named getSavedData
//we want to set the contents of that function to return an object containing all our @:save fields
//first we find the @:save fields and collect them in an array
var saveFieldNames = new Array<String>();
//iterate fields, look at field metas and find ones named :save
for(field in fields){
var metas = field.meta;//an array of meta objects (checkout std/haxe/macro/Expr to see the typedefs)
for(meta in metas){
switch meta.name {
case ':save':
//(we can also access any params here with meta.params)
//ok, we now know this field has @:save meta, lets store its name in an array
saveFieldNames.push(field.name);
}
}
}
//now we want to do is to add a new field that looks like this
/*
public function getSavedData(){
return {
$fieldName1: $fieldName1,
$fieldName2: $fieldName2,
...
}
}
*/
//it's possible to compose the whole field manually using the typedefs in Expr.hx, but it's much easier to use the 'macro' keyword
//this takes expressions and turns them into Expr types for you
//the macro keyword pretty powerful but sometimes we do need to do things manually:
//the following creates an expression for an object like: {a: a, b: b}
var objExpr:Expr = {
expr: EObjectDecl([
for(name in saveFieldNames){
field: name,
expr: macro $i{name} //for more info on $i{...} see http://haxe.org/manual/macro-reification-expression.html
}
]),
pos: Context.currentPos()
}
//lets test to see if the expression looks right
//trace(ExprTools.toString(objExpr));
//we can't do 'macro public function getSavedData(){...}' because it's not supported
//what we can do however is use it to create a class expression and then just take the fields from that
//just like string interpolation, we can use the object expression we created above
//see http://haxe.org/manual/macro-reification-class.html
var classObject = macro class SomeName{
public function getSavedData(){
return ${objExpr};
}
};
//now we append the fields in our 'classObject' to the fields of the class we're building
fields = fields.concat(classObject.fields);
//job done
return fields;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment