Last active
July 7, 2017 07:57
-
-
Save haxiomic/1e6e0cffc1a27f4f09d8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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