Skip to content

Instantly share code, notes, and snippets.

@nadako
Last active February 19, 2019 02:07
Show Gist options
  • Save nadako/2ad4246f257e627a5833 to your computer and use it in GitHub Desktop.
Save nadako/2ad4246f257e627a5833 to your computer and use it in GitHub Desktop.
Tuple builder using new Rest feature of @:genericBuild
class Main {
static function main() {
var a = getValue();
}
static function getValue():Tuple<Bool,Int> {
return new Tuple(true, 10);
}
}
@:genericBuild(TupleMacro.build())
class Tuple<Rest> {}
import haxe.macro.Context;
import haxe.macro.Expr;
import haxe.macro.Type;
using haxe.macro.Tools;
class TupleMacro {
static var arityMap = new Map<Int,Bool>();
static function build():ComplexType {
return switch (Context.getLocalType()) {
case TInst(_.get() => {name: "Tuple"}, types):
if (types.length == 0) {
var args = Context.getConstructorArguments();
if (args != null)
types = [for (arg in args) Context.typeof(arg)];
}
if (types.length < 2)
Context.fatalError("Tuple must have at least 2 elements", Context.currentPos());
buildTuple(types);
default:
throw false;
}
}
static function buildTuple(types:Array<Type>):ComplexType {
var arity = types.length;
var name = 'Tuple$arity';
var isTargetCS = Context.defined("cs");
if (!arityMap.exists(arity)) {
var pos = Context.currentPos();
var fields:Array<Field> = [];
var constructorArgs:Array<FunctionArg> = [];
var constructorExprs:Array<Expr> = [];
var typeParams:Array<TypeParamDecl> = [];
for (i in 0...arity) {
var fieldName = 'v$i';
var typeName = 'T$i';
var ct = TPath({pack: [], name: typeName});
typeParams.push({name: typeName});
constructorArgs.push({name: fieldName, type: ct});
constructorExprs.push(macro this.$fieldName = $i{fieldName});
var meta:Metadata = [];
if (isTargetCS)
meta.push({name: ":readOnly", pos: pos});
fields.push({
pos: pos,
name: fieldName,
access: [APublic],
kind: FProp("default", "null", ct),
meta: meta,
});
}
fields.push({
pos: pos,
name: "new",
access: [APublic, AInline],
kind: FFun({
args: constructorArgs,
ret: macro : Void,
expr: macro $b{constructorExprs}
})
});
var meta:Metadata = [];
if (isTargetCS) {
meta.push({name: ":nativeGen", pos: pos});
meta.push({name: ":struct", pos: pos});
}
Context.defineType({
pos: pos,
pack: [],
name: name,
params: typeParams,
meta: meta,
kind: TDClass(),
fields: fields
});
arityMap[arity] = true;
}
return TPath({pack: [], name: name, params: [for (t in types) TPType(t.toComplexType())]});
}
}
@cambiata
Copy link

cambiata commented May 27, 2017

Great example! Thanx!

One thing has to be changed for it to work:
Context.getConstructorArguments() is renamed to Context.getCallArguments().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment