139 lines
3.7 KiB
Haxe
139 lines
3.7 KiB
Haxe
package tink.macro;
|
|
|
|
import haxe.macro.Expr;
|
|
import tink.core.Pair;
|
|
using tink.MacroApi;
|
|
|
|
enum FieldInit {
|
|
Value(e:Expr);
|
|
Arg(?t:ComplexType, ?noPublish:Bool);
|
|
OptArg(?e:Expr, ?t:ComplexType, ?noPublish:Bool);
|
|
}
|
|
|
|
class Constructor {
|
|
var oldStatements:Array<Expr>;
|
|
var nuStatements:Array<Expr>;
|
|
var beforeArgs:Array<FunctionArg>;
|
|
var args:Array<FunctionArg>;
|
|
var afterArgs:Array<FunctionArg>;
|
|
var pos:Position;
|
|
var onGenerateHooks:Array<Function->Void>;
|
|
var superCall:Expr;
|
|
public var isPublic:Null<Bool>;
|
|
|
|
public function new(f:Function, ?isPublic:Null<Bool> = null, ?pos:Position, ?meta:Metadata) {
|
|
this.nuStatements = [];
|
|
this.isPublic = isPublic;
|
|
this.pos = pos.sanitize();
|
|
|
|
this.onGenerateHooks = [];
|
|
this.args = [];
|
|
this.beforeArgs = [];
|
|
this.afterArgs = [];
|
|
|
|
this.oldStatements =
|
|
if (f == null) [];
|
|
else {
|
|
for (i in 0...f.args.length) {
|
|
var a = f.args[i];
|
|
if (a.name == '_') {
|
|
afterArgs = f.args.slice(i + 1);
|
|
break;
|
|
}
|
|
beforeArgs.push(a);
|
|
}
|
|
|
|
if (f.expr == null) [];
|
|
else
|
|
switch (f.expr.expr) {
|
|
case EBlock(exprs): exprs;
|
|
default: oldStatements = [f.expr];
|
|
}
|
|
}
|
|
superCall =
|
|
if (oldStatements.length == 0) [].toBlock();
|
|
else switch oldStatements[0] {
|
|
case macro super($a{_}): oldStatements.shift();
|
|
default: [].toBlock();
|
|
}
|
|
}
|
|
public function addStatement(e:Expr, ?prepend)
|
|
if (prepend)
|
|
this.nuStatements.unshift(e)
|
|
else
|
|
this.nuStatements.push(e);
|
|
|
|
public function addArg(name:String, ?t:ComplexType, ?e:Expr, ?opt = false)
|
|
args.push( { name : name, opt : opt || e != null, type : t, value: e } );
|
|
|
|
public function init(name:String, pos:Position, with:FieldInit, ?options:{ ?prepend:Bool, ?bypass:Bool }) {
|
|
if (options == null)
|
|
options = {};
|
|
var e =
|
|
switch with {
|
|
case Arg(t, noPublish):
|
|
if (noPublish != true)
|
|
publish();
|
|
args.push( { name : name, opt : false, type : t } );
|
|
name.resolve(pos);
|
|
case OptArg(e, t, noPublish):
|
|
if (noPublish != true)
|
|
publish();
|
|
args.push( { name : name, opt : true, type : t, value: e } );
|
|
name.resolve(pos);
|
|
case Value(e): e;
|
|
}
|
|
|
|
var tmp = MacroApi.tempName();
|
|
|
|
if (options.bypass) {
|
|
if (haxe.macro.Context.defined('java')) {
|
|
addStatement(
|
|
macro @:pos(pos)
|
|
if (Math.random() < .0) {
|
|
//if this is false, then it gets thrown out before reaching the backend which will then generate invalid code
|
|
var $tmp = this.$name;
|
|
$i{tmp} = $e;
|
|
this.$name = $i{tmp};
|
|
},
|
|
true
|
|
);
|
|
addStatement(macro @:pos(pos) (cast this).$name = $e, options.prepend);
|
|
}
|
|
else {
|
|
addStatement(macro @:pos(pos) if (false) { var $tmp = this.$name; $i{tmp} = $e; }, true);
|
|
addStatement(macro @:pos(pos) (cast this).$name = $e, options.prepend);
|
|
}
|
|
}
|
|
else
|
|
addStatement(macro @:pos(pos) this.$name = $e, options.prepend);
|
|
}
|
|
public inline function publish()
|
|
if (isPublic == null)
|
|
isPublic = true;
|
|
|
|
function toBlock()
|
|
return [superCall].concat(nuStatements).concat(oldStatements).toBlock(pos);
|
|
|
|
public function onGenerate(hook)
|
|
this.onGenerateHooks.push(hook);
|
|
|
|
public function toHaxe():Field {
|
|
var f:Function = {
|
|
args: this.beforeArgs.concat(this.args).concat(this.afterArgs),
|
|
ret: 'Void'.asComplexType(),
|
|
expr: toBlock(),
|
|
params: []
|
|
};
|
|
for (hook in onGenerateHooks) hook(f);
|
|
onGenerateHooks = [];
|
|
return {
|
|
name: 'new',
|
|
doc : null,
|
|
access : isPublic ? [APublic] : [],
|
|
kind : FFun(f),
|
|
pos : pos,
|
|
meta : []
|
|
}
|
|
}
|
|
} |