Skip to content

Instantly share code, notes, and snippets.

@nadako
Last active June 21, 2016 21:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nadako/561112bfdd7f5714e88412852aab70a2 to your computer and use it in GitHub Desktop.
Save nadako/561112bfdd7f5714e88412852aab70a2 to your computer and use it in GitHub Desktop.
// register a build-macro that will be called
// for building fields for subclasses of this class
@:autoBuild(ComponentMacro.build())
class Component {
// this function will be overriden in subclasses
public function registerCallbacks(updates:Array<Void->Void>) {}
}
import haxe.macro.Context;
import haxe.macro.Expr;
class ComponentMacro {
// this is a build macro function that returns an array
// of fields for the class being built
static function build():Array<Field> {
// get all the fields that are already there (e.g. defined by syntax in the source file)
var fields = Context.getBuildFields();
// this is an array of expressions for the registerCallbacks function body
var registerExprs = new Array<Expr>();
// iterate over defined fields to find the update function
for (field in fields) {
// this is an update function if it contains metadata named "update"
var isUpdateFunction = Lambda.exists(field.meta, function(m) return m.name == "update");
// if it is - generate an expression that adds this method to the updates array
// and push this expression to the array of register function expressions
if (isUpdateFunction) {
var fieldName = field.name;
registerExprs.push(macro updates.push(this.$fieldName));
}
}
// if we did found a function to register, add override of the registerCallbacks method
// to this class' fields
if (registerExprs.length > 0) {
fields.push({
pos: Context.currentPos(), // whatever current position is, we don't really care
name: "registerCallbacks", // the function we're overriding is named like this,
access: [APublic, AOverride], // access specifiers: public override
kind: FFun({ // this is a function (not var or property)
args: [
{
name: "updates", // the function has one argument "updates"
type: macro : Array<Void->Void> // typed as Array<Void->Void>, just like in superclass
}
],
ret: null, // we don't care about return type (it will be inferred as Void anyway)
expr: macro $b{registerExprs} // the function body is a block of expressions we collected in registerExprs
})
});
}
// finally return the fields of our subclass
return fields;
}
}
class MyComponent extends Component {
public function new() {}
@update
function myCoolUpdate() {
trace("hello");
}
}
class Main {
static function main() {
var updates = [];
var myComp = new MyComponent();
myComp.registerCallbacks(updates);
for (update in updates)
update();
}
}
// Generated by Haxe 3.3.0
(function () { "use strict";
function $extend(from, fields) {
function Inherit() {} Inherit.prototype = from; var proto = new Inherit();
for (var name in fields) proto[name] = fields[name];
if( fields.toString !== Object.prototype.toString ) proto.toString = fields.toString;
return proto;
}
var Component = function() { };
Component.prototype = {
registerCallbacks: function(updates) {
}
};
var MyComponent = function() {
};
MyComponent.__super__ = Component;
MyComponent.prototype = $extend(Component.prototype,{
myCoolUpdate: function() {
console.log("hello");
}
,registerCallbacks: function(updates) {
updates.push($bind(this,this.myCoolUpdate));
}
});
var Main = function() { };
Main.main = function() {
var updates = [];
new MyComponent().registerCallbacks(updates);
var _g = 0;
while(_g < updates.length) {
var update = updates[_g];
++_g;
update();
}
};
var $_, $fid = 0;
function $bind(o,m) { if( m == null ) return null; if( m.__id__ == null ) m.__id__ = $fid++; var f; if( o.hx__closures__ == null ) o.hx__closures__ = {}; else f = o.hx__closures__[m.__id__]; if( f == null ) { f = function(){ return f.method.apply(f.scope, arguments); }; f.scope = o; f.method = m; o.hx__closures__[m.__id__] = f; } return f; }
MyComponent.__meta__ = { fields : { myCoolUpdate : { update : null}}};
Main.main();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment