Skip to content

Instantly share code, notes, and snippets.

@skial
Last active August 2, 2016 11:02
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 skial/9f6b0f0a53f67d6fce4752a8010b7e2d to your computer and use it in GitHub Desktop.
Save skial/9f6b0f0a53f67d6fce4752a8010b7e2d to your computer and use it in GitHub Desktop.
Experimental code for https://groups.google.com/d/msg/haxelang/6W3gmh_DV-I/JFLiTgBXBwAJ over on the Haxe mailing list, using Haxe 3.3.0 (git build development @ f736708), but should work with Haxe 3.3.0
-cp src
-main Main
-dce full
--each
-neko bin/test.n
--next
-js bin/test.js
package ;
@:build(MyMacro.build())
class Main {
public static function main() {
MyMacro.register('c');
foo('bar');
MyMacro.register('a');
foo('baz');
trace( getCollection() );
}
public static function foo(v:String) {
// Do nothing with `v`.
MyMacro.register('foo'); // Only appears once, not for each time foo was called.
MyMacro.register('b'); // Only appears once, not for each time foo was called.
}
}
package ;
import haxe.macro.Type;
import haxe.macro.Expr;
import haxe.macro.Context;
using StringTools;
using haxe.macro.TypeTools;
using haxe.macro.ExprTools;
using haxe.macro.MacroStringTools;
using haxe.macro.ComplexTypeTools;
class MyMacro {
// Only accepts constant strings.
public static macro function register(value:String):Expr {
var type:ClassType = switch (Context.getLocalType()) {
case TInst(_.get() => c, _): c;
case _: null;
}
if (type != null) {
var storage = [];
if (type.meta.has(':storage')) {
var data = type.meta.extract(':storage')[0].params[0].toString();
storage = haxe.Unserializer.run(data.replace('"', ''));
type.meta.remove(':storage');
}
storage.push(value);
trace( 'incoming - ' + value );
trace( 'current state of storage', storage );
type.meta.add(':storage', [macro @:pos(type.pos) $v{haxe.Serializer.run(storage)}], type.pos);
}
return macro $v{value};
}
public static macro function build():Array<Field> {
var fields = Context.getBuildFields();
trace( 'running build macro' );
var type:ClassType = switch (Context.getLocalType()) {
case TInst(_.get() => c, _): c;
case _: null;
}
if (type != null) {
// Last chance to add types into current Haxe build.
Context.onAfterTyping(function(modules:Array<ModuleType>) {
for (module in modules) {
switch module {
case TClassDecl(_.get() => c) if (c.pack.toDotPath(c.name) == type.pack.toDotPath(type.name)):
var storage = [];
if (c.meta.has(':storage')) {
var data = c.meta.extract(':storage')[0].params[0].toString();
storage = haxe.Unserializer.run(data.replace('"', ''));
}
trace( 'Complete array of macro collected values', storage );
var td:TypeDefinition = macro class Collection {
public static var values:Array<String> = $v{storage};
};
// If `-dce full` is enabled.
td.meta.push({name:':keep', params:[], pos:type.pos});
Context.defineType(td);
case _:
}
}
});
fields.push( (macro class Temp {
// Not happy with `untyped`, but Collection doesnt _exist_ yet.
public static inline function getCollection():Array<String> return untyped Collection.values;
}).fields[0] );
}
return fields;
}
}
haxe build.hxml && neko bin/test.n
src/MyMacro.hx:45: running build macro
src/MyMacro.hx:33: incoming - c
src/MyMacro.hx:34: current state of storage,[c]
src/MyMacro.hx:33: incoming - foo
src/MyMacro.hx:34: current state of storage,[c,foo]
src/MyMacro.hx:33: incoming - b
src/MyMacro.hx:34: current state of storage,[c,foo,b]
src/MyMacro.hx:33: incoming - a
src/MyMacro.hx:34: current state of storage,[c,foo,b,a]
src/MyMacro.hx:67: Complete array of macro collected values,[c,foo,b,a]
Main.hx:11: [c,foo,b,a]
// Generated by Haxe 3.3.0 (git build development @ f736708)
(function () { "use strict";
var Collection = function() { };
var HxOverrides = function() { };
HxOverrides.iter = function(a) {
return { cur : 0, arr : a, hasNext : function() {
return this.cur < this.arr.length;
}, next : function() {
return this.arr[this.cur++];
}};
};
var Main = function() { };
Main.main = function() {
Main.foo("bar");
Main.foo("baz");
console.log(Collection.values.toString());
};
Main.foo = function(v) {
};
Collection.values = ["c","foo","b","a"];
Main.main();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment