Compare commits

...

28 Commits

Author SHA1 Message Date
Juraj Kirchheim
7586b54ece Release 0.15.1 2017-11-30 10:40:31 +01:00
Juraj Kirchheim
21c7d12be7 Don't drop positions when typing. 2017-11-30 10:39:57 +01:00
Juraj Kirchheim
f27d2796b1 Release 0.15.0 2017-09-25 10:52:48 +02:00
Juraj Kirchheim
417a92cabc Make it compile for Haxe 4. 2017-09-25 10:50:36 +02:00
Kevin Leung
4457ea7dee readme tweaks 2017-09-21 15:02:16 +08:00
Juraj Kirchheim
209847e5ea Release 0.14.2 2017-09-11 10:36:42 +02:00
Juraj Kirchheim
c94e4a0337 Add way to get constructor args. 2017-09-11 10:35:54 +02:00
Juraj Kirchheim
cc009b2026 Release 0.14.1 2017-08-28 15:02:56 +02:00
Juraj Kirchheim
0a36ee8e2b Merge pull request #16 from ibilon/haxe4
Support for haxe 4 EIn change to EBinop(OpIn)
2017-08-18 16:00:37 +02:00
Juraj Kirchheim
5879773566 Fix typo. 2017-08-18 15:41:31 +02:00
Juraj Kirchheim
58262a1810 Use reification to abstract over Haxe version specific differences. 2017-08-18 15:38:58 +02:00
Valentin Lemière
9ceadeb88f Support for haxe 4 EIn change to EBinop(OpIn) 2017-08-18 15:13:28 +02:00
Juraj Kirchheim
15d75965ad Release 0.14.0 2017-06-05 10:13:08 +02:00
Juraj Kirchheim
c7634e0a29 Just use Error.rethrow 2017-06-01 13:14:39 +02:00
Juraj Kirchheim
49e48bc801 Merge pull request #15 from Simn/eval
don't use neko.Lib.rethrow when not in neko
2017-06-01 13:06:27 +02:00
Simon Krajewski
c150b84f18 don't use neko.Lib.rethrow when not in neko 2017-06-01 13:01:52 +02:00
Kevin Leung
04f86ce341 official gitter badge [ci skip] 2017-05-26 07:59:52 +08:00
Kevin Leung
45380371d8 Add badge [ci skip] 2017-05-19 17:54:35 +08:00
Juraj Kirchheim
d94d946301 Update README.md 2017-05-18 13:43:49 +02:00
Juraj Kirchheim
56b7caaf01 Release 0.13.5 2017-05-06 12:42:01 +02:00
Juraj Kirchheim
73e9da8435 Fix 3.2.1. 2017-04-13 21:07:44 +02:00
Juraj Kirchheim
bf23337923 Release 0.13.4 2017-04-13 21:04:00 +02:00
Juraj Kirchheim
02bd3bf69d Add Types.getMeta. 2017-04-13 21:02:58 +02:00
Juraj Kirchheim
82a3417b97 Gitignore. 2017-04-13 20:58:16 +02:00
Juraj Kirchheim
1f986c3732 VSCode setup. 2017-04-13 20:57:29 +02:00
Kevin Leung
20e998fd12 Release 0.13.3 2017-03-20 20:01:41 +08:00
Kevin Leung
0f9c0d1e97 what the haxe? 2017-03-20 19:49:21 +08:00
Kevin Leung
2ae13d534e my turn 2017-03-20 19:41:16 +08:00
12 changed files with 105 additions and 77 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/bin

View File

@@ -22,6 +22,6 @@ env:
deploy: deploy:
provider: script provider: script
script: haxelib run travix release script: haxe && haxelib run travix release
on: on:
tags: true tags: true

5
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,5 @@
{
"haxe.displayConfigurations": [
["tests.hxml"]
]
}

6
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,6 @@
{
"version": "0.1.0",
"command": "haxelib",
"args": ["run", "travix", "node"],
"problemMatcher": "$haxe"
}

View File

@@ -1,5 +1,7 @@
# Tinkerbell Macro Library # Tinkerbell Macro Library
[![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg?maxAge=2592000)](https://gitter.im/haxetink/public)
[![Build Status](https://travis-ci.org/haxetink/tink_macro.svg?branch=master)](https://travis-ci.org/haxetink/tink_macro)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/haxetink/public)
Explained in current marketing speak, `tink_macro` is *the* macro toolkit ;) Explained in current marketing speak, `tink_macro` is *the* macro toolkit ;)
@@ -301,7 +303,7 @@ abstract Member from Field to Field {
Most of the API should be self-explaining. The `isBound` property is a bad name to convey the concept that a field can be either `inline` (`true`) or `dynamic` (`false`) or neither (`null`). Equally, `isPublic` is nullable which means that normally defaults to `private`. Most of the API should be self-explaining. The `isBound` property is a bad name to convey the concept that a field can be either `inline` (`true`) or `dynamic` (`false`) or neither (`null`). Equally, `isPublic` is nullable which means that normally defaults to `private`.
The `publish` method will make a field `public` if it is not `private`. This can also be done with `if (m.isPublic == null) m.isPublic = true;` but the implementation is far more efficient - for what its worth. The `publish` method will make a field `public` if it is not explicitly marked as `private`. This can also be done with `if (m.isPublic == null) m.isPublic = true;` but the implementation is far more efficient - for what its worth.
The `extractMeta` method will "peel of" the first tag with a given `name` - if available. Note that the tag will be removed from the member. The `extractMeta` method will "peel of" the first tag with a given `name` - if available. Note that the tag will be removed from the member.
@@ -389,7 +391,7 @@ The `init` method is the swiss army knife of initializing fields. The `options.p
#### Setter Bypass #### Setter Bypass
It is important to know that when you initialize a field with `options.bypass` set to true, existing setters will by bypassed. That's particularly helpful if your setter triggers a side effect that you don't want triggered. This is achieved by generating the assignment as `(untyped this).$name = $value`. To make the code typesafe again, this is prefixed with `if (false) { var __tmp = this.$name; __tmp = $value; }`. This code is later thrown out by the compiler. Its role is to ensure type safety without interfering with the normal typing order. It is important to know that when you initialize a field with `options.bypass` set to true, existing setters will be bypassed. That's particularly helpful if your setter triggers a side effect that you don't want triggered. This is achieved by generating the assignment as `(untyped this).$name = $value`. To make the code typesafe again, this is prefixed with `if (false) { var __tmp = this.$name; __tmp = $value; }`. This code is later thrown out by the compiler. Its role is to ensure type safety without interfering with the normal typing order.
Setter bypass also causes the field to gain an `@:isVar`. And currently, with `-dce full`, additional code will be generated to avoid the field to be eliminated. Setter bypass also causes the field to gain an `@:isVar`. And currently, with `-dce full`, additional code will be generated to avoid the field to be eliminated.

1
bin/.gitignore vendored
View File

@@ -1 +0,0 @@
*.n

View File

@@ -11,8 +11,8 @@
"contributors": [ "contributors": [
"back2dos" "back2dos"
], ],
"releasenote": "Alias for TypeMap", "releasenote": "Don't drop positions when typing.",
"version": "0.13.2", "version": "0.15.1",
"url": "http://haxetink.org/tink_macro", "url": "http://haxetink.org/tink_macro",
"dependencies": { "dependencies": {
"tink_core": "" "tink_core": ""

View File

@@ -9,51 +9,51 @@ using tink.MacroApi;
using Lambda; using Lambda;
class ClassBuilder { class ClassBuilder {
var memberList:Array<Member>; var memberList:Array<Member>;
var macros:Map<String,Field>; var macros:Map<String,Field>;
var constructor:Null<Constructor>; var constructor:Null<Constructor>;
public var target(default, null):ClassType; public var target(default, null):ClassType;
var superFields:Map<String,Bool>; var superFields:Map<String,Bool>;
var initializeFrom:Array<Field>; var initializeFrom:Array<Field>;
public function new(?target, ?fields) { public function new(?target, ?fields) {
if (target == null) if (target == null)
target = Context.getLocalClass().get(); target = Context.getLocalClass().get();
if (fields == null) if (fields == null)
fields = Context.getBuildFields(); fields = Context.getBuildFields();
this.initializeFrom = fields; this.initializeFrom = fields;
this.target = target; this.target = target;
} }
function init() { function init() {
if (initializeFrom == null) return; if (initializeFrom == null) return;
var fields = initializeFrom; var fields = initializeFrom;
initializeFrom = null; initializeFrom = null;
this.memberList = []; this.memberList = [];
this.macros = new Map(); this.macros = new Map();
for (field in fields) for (field in fields)
if (field.access.has(AMacro)) if (field.access.has(AMacro))
macros.set(field.name, field) macros.set(field.name, field)
else if (field.name == 'new') { else if (field.name == 'new') {
var m:Member = field; var m:Member = field;
this.constructor = new Constructor(this, m.getFunction().sure(), m.isPublic, m.pos, field.meta); this.constructor = new Constructor(this, m.getFunction().sure(), m.isPublic, m.pos, field.meta);
} }
else else
doAddMember(field); doAddMember(field);
} }
public function getConstructor(?fallback:Function):Constructor { public function getConstructor(?fallback:Function):Constructor {
init(); init();
if (constructor == null) if (constructor == null)
if (fallback != null) if (fallback != null)
constructor = new Constructor(this, fallback); constructor = new Constructor(this, fallback);
else { else {
@@ -64,18 +64,18 @@ class ClassBuilder {
try { try {
var ctor = cl.constructor.get(); var ctor = cl.constructor.get();
var func = Context.getTypedExpr(ctor.expr()).getFunction().sure(); var func = Context.getTypedExpr(ctor.expr()).getFunction().sure();
for (arg in func.args) //this is to deal with type parameter substitutions for (arg in func.args) //this is to deal with type parameter substitutions
arg.type = null; arg.type = null;
func.expr = "super".resolve().call(func.getArgIdents()); func.expr = "super".resolve().call(func.getArgIdents());
constructor = new Constructor(this, func); constructor = new Constructor(this, func);
if (ctor.isPublic) if (ctor.isPublic)
constructor.publish(); constructor.publish();
} }
catch (e:Dynamic) {//fails for unknown reason catch (e:Dynamic) {//fails for unknown reason
if (e == 'assert') if (e == 'assert')
neko.Lib.rethrow(e); tink.core.Error.rethrow(e);
constructor = new Constructor(this, null); constructor = new Constructor(this, null);
} }
break; break;
@@ -85,15 +85,15 @@ class ClassBuilder {
if (constructor == null) if (constructor == null)
constructor = new Constructor(this, null); constructor = new Constructor(this, null);
} }
return constructor; return constructor;
} }
public function hasConstructor():Bool { public function hasConstructor():Bool {
init(); init();
return this.constructor != null; return this.constructor != null;
} }
public function export(?verbose):Array<Field> { public function export(?verbose):Array<Field> {
if (initializeFrom != null) return null; if (initializeFrom != null) return null;
var ret = (constructor == null || target.isInterface) ? [] : [constructor.toHaxe()]; var ret = (constructor == null || target.isInterface) ? [] : [constructor.toHaxe()];
@@ -108,24 +108,24 @@ class ClassBuilder {
} }
for (m in macros) for (m in macros)
ret.push(m); ret.push(m);
if (verbose) if (verbose)
for (field in ret) for (field in ret)
Context.warning(new Printer().printField(field), field.pos); Context.warning(new Printer().printField(field), field.pos);
return ret; return ret;
} }
public function iterator():Iterator<Member> { public function iterator():Iterator<Member> {
init(); init();
return this.memberList.copy().iterator(); return this.memberList.copy().iterator();
} }
public function hasOwnMember(name:String):Bool { public function hasOwnMember(name:String):Bool {
init(); init();
return return
macros.exists(name) || memberByName(name).isSuccess(); macros.exists(name) || memberByName(name).isSuccess();
} }
public function hasSuperField(name:String):Bool { public function hasSuperField(name:String):Bool {
if (superFields == null) { if (superFields == null) {
superFields = new Map(); superFields = new Map();
@@ -139,51 +139,51 @@ class ClassBuilder {
} }
return superFields.get(name); return superFields.get(name);
} }
public function memberByName(name:String, ?pos:Position) { public function memberByName(name:String, ?pos:Position) {
init(); init();
for (m in memberList) for (m in memberList)
if (m.name == name) if (m.name == name)
return Success(m); return Success(m);
return pos.makeFailure('unknown member $name'); return pos.makeFailure('unknown member $name');
} }
public function removeMember(member:Member):Bool { public function removeMember(member:Member):Bool {
init(); init();
return return
memberList.remove(member); memberList.remove(member);
} }
public function hasMember(name:String):Bool public function hasMember(name:String):Bool
return hasOwnMember(name) || hasSuperField(name); return hasOwnMember(name) || hasSuperField(name);
function doAddMember(m:Member, ?front:Bool = false):Member { function doAddMember(m:Member, ?front:Bool = false):Member {
init(); init();
if (m.name == 'new') if (m.name == 'new')
throw 'Constructor must not be registered as ordinary member'; throw 'Constructor must not be registered as ordinary member';
//if (hasOwnMember(m.name)) //if (hasOwnMember(m.name))
//m.pos.error('duplicate member declaration ' + m.name); //m.pos.error('duplicate member declaration ' + m.name);
if (front) if (front)
memberList.unshift(m); memberList.unshift(m);
else else
memberList.push(m); memberList.push(m);
return m;
}
public function addMember(m:Member, ?front:Bool = false):Member {
doAddMember(m, front);
if (!m.isStatic && hasSuperField(m.name))
m.overrides = true;
return m; return m;
} }
public function addMember(m:Member, ?front:Bool = false):Member {
doAddMember(m, front);
if (!m.isStatic && hasSuperField(m.name))
m.overrides = true;
return m;
}
static public function run(plugins:Array<ClassBuilder->Void>, ?verbose) { static public function run(plugins:Array<ClassBuilder->Void>, ?verbose) {
var builder = new ClassBuilder(); var builder = new ClassBuilder();
for (p in plugins) for (p in plugins)

View File

@@ -62,6 +62,10 @@ class Constructor {
default: [].toBlock(); default: [].toBlock();
} }
} }
public function getArgList():Array<FunctionArg>
return beforeArgs.concat(args).concat(afterArgs);
public function addStatement(e:Expr, ?prepend) public function addStatement(e:Expr, ?prepend)
if (prepend) if (prepend)
this.nuStatements.unshift(e) this.nuStatements.unshift(e)

View File

@@ -241,7 +241,7 @@ class Exprs {
} }
static public inline function iterate(target:Expr, body:Expr, ?loopVar:String = 'i', ?pos:Position) static public inline function iterate(target:Expr, body:Expr, ?loopVar:String = 'i', ?pos:Position)
return EFor(EIn(loopVar.resolve(pos), target).at(pos), body).at(pos); return macro @:pos(pos.sanitize()) for ($i{loopVar} in $target) $body;
static public function toFields(object:Dynamic<Expr>, ?pos:Position) static public function toFields(object:Dynamic<Expr>, ?pos:Position)
return EObjectDecl([for (field in Reflect.fields(object)) return EObjectDecl([for (field in Reflect.fields(object))
@@ -319,7 +319,7 @@ class Exprs {
expr = [EVars(locals).at(expr.pos), expr].toMBlock(expr.pos); expr = [EVars(locals).at(expr.pos), expr].toMBlock(expr.pos);
Success(Context.typeof(expr)); Success(Context.typeof(expr));
} }
catch (e:Error) { catch (e:haxe.macro.Error) {
var m:Dynamic = e.message; var m:Dynamic = e.message;
e.pos.makeFailure(m); e.pos.makeFailure(m);
} }

View File

@@ -17,6 +17,7 @@ class Sisyphus {
case AccCall: getOrSet; case AccCall: getOrSet;
case AccInline: "default"; case AccInline: "default";
case AccRequire(_, _): "default"; case AccRequire(_, _): "default";
default: throw "not implemented";
} }
} }
if (cf.params.length == 0) { if (cf.params.length == 0) {
@@ -102,4 +103,4 @@ class Sisyphus {
params: [ for (t in params) TPType(toComplexType(t)) ], params: [ for (t in params) TPType(toComplexType(t)) ],
} }
} }
} }

View File

@@ -19,10 +19,10 @@ class Types {
try { try {
Some(Context.getType(typeName)); Some(Context.getType(typeName));
} }
catch (e:Dynamic) catch (e:Dynamic)
if (Std.string(e) == 'Type not found \'$typeName\'') None; if (Std.string(e) == 'Type not found \'$typeName\'') None;
else neko.Lib.rethrow(e); else tink.core.Error.rethrow(e);
static var types = new Map<Int,Void->Type>(); static var types = new Map<Int,Void->Type>();
static var idCounter = 0; static var idCounter = 0;
static public function getID(t:Type, ?reduced = true) static public function getID(t:Type, ?reduced = true)
@@ -49,6 +49,16 @@ class Types {
throw 'not implemented'; throw 'not implemented';
} }
static public function getMeta(type:Type)
return switch type {
case TInst(_.get().meta => m, _): [m];
case TEnum(_.get().meta => m, _): [m];
case TAbstract(_.get().meta => m, _): [m];
case TType(_.get() => t, _): [t.meta].concat(getMeta(t.type));
case TLazy(f): getMeta(f());
default: [];
}
static function getDeclaredFields(t:ClassType, out:Array<ClassField>, marker:Map<String,Bool>) { static function getDeclaredFields(t:ClassType, out:Array<ClassField>, marker:Map<String,Bool>) {
for (field in t.fields.get()) for (field in t.fields.get())
if (!marker.exists(field.name)) { if (!marker.exists(field.name)) {
@@ -173,14 +183,14 @@ class Types {
params : [TPExpr(register(f).toExpr())], params : [TPExpr(register(f).toExpr())],
sub : null, sub : null,
}); });
static function resolveDirectType() static function resolveDirectType()
return return
switch reduce(Context.getLocalType()) { switch reduce(Context.getLocalType()) {
case TInst(_, [TInst(_.get() => { kind: KExpr(e) }, _)]): case TInst(_, [TInst(_.get() => { kind: KExpr(e) }, _)]):
types[e.getInt().sure()]();//When using compiler server, this call throws on occasion, in which case modifying this file (to update mtime and invalidate the cache) will solve the problem types[e.getInt().sure()]();//When using compiler server, this call throws on occasion, in which case modifying this file (to update mtime and invalidate the cache) will solve the problem
default: default:
throw 'assert'; throw 'assert';
} }
} }