Compare commits

..

57 Commits

Author SHA1 Message Date
Juraj Kirchheim
0be2090232 Release 0.16.0 2018-01-16 17:14:42 +01:00
Juraj Kirchheim
0dc774db21 Add support for scoping. 2017-12-24 12:23:10 +01:00
Juraj Kirchheim
a7c22bf5af Return bulk added members from ClassBuilder. 2017-12-18 14:26:25 +01:00
Juraj Kirchheim
a164b335ed Improve Type to ComplexType conversion for type parameters. 2017-12-18 11:28:23 +01:00
Juraj Kirchheim
d02306eebd Add class reification shorthand to ClassBuilder. 2017-12-18 11:27:59 +01:00
Juraj Kirchheim
ff9ef59445 Expose more logic from BuildCache. 2017-12-18 11:27:32 +01:00
Juraj Kirchheim
bfc5c2b88f Factor out build cache's param retrieval into separate function. 2017-12-15 12:27:01 +01:00
Juraj Kirchheim
57042819b1 Release 0.15.4 2017-12-08 10:41:26 +01:00
Juraj Kirchheim
82d15d9ffc Report invalid type in getFields. 2017-12-08 10:40:24 +01:00
Juraj Kirchheim
0d9fff7e01 Reverse order in setter bypass to make type inference suffer less. 2017-12-06 17:13:01 +01:00
Juraj Kirchheim
45d5f3e0ea Release 0.15.3 2017-12-01 16:32:19 +01:00
Juraj Kirchheim
800891bee2 Fixes #21. 2017-12-01 16:31:22 +01:00
Juraj Kirchheim
0802bf7f79 Minor tweak. 2017-12-01 16:30:42 +01:00
Juraj Kirchheim
42897c7cd5 Merge branch 'master' of https://github.com/haxetink/tink_macro 2017-11-30 13:05:06 +01:00
Juraj Kirchheim
0e902745b1 Release 0.15.2 2017-11-30 13:04:39 +01:00
Juraj Kirchheim
3dec4fa404 Improve position reporting. 2017-11-30 13:04:07 +01:00
Juraj Kirchheim
c0ec918f52 Merge pull request #20 from markknol/patch-1
Update README.md
2017-11-30 11:52:41 +01:00
Mark Knol
4eb9729f0e Update README.md
Fix links in index
2017-11-30 10:56:14 +01:00
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
back2dos
65d341f1e1 "push and read travis log" is the best kind of debugging ... 2017-03-20 11:50:32 +01:00
back2dos
68fa50c7c3 Let's see if we can fix that. 2017-03-20 11:32:50 +01:00
back2dos
32aa2d6570 Bump version. 2017-03-20 11:20:59 +01:00
back2dos
d81642e733 Use travix release. 2017-03-20 11:19:49 +01:00
Juraj Kirchheim
d5f4987ddb Release 0.13.1 2017-03-16 16:31:14 +01:00
Juraj Kirchheim
671f1bc995 Merge pull request #11 from haxetink/kevinresol-patch-1
Add TypeMap alias
2017-03-16 16:02:34 +01:00
back2dos
b1012937fc Release 0.13.0 2017-03-06 17:58:24 +01:00
back2dos
bd4b8c436f Build cache works better with compiler server. 2017-03-06 17:58:07 +01:00
back2dos
dbebd0d70d Allow querying whether a type exists. 2017-03-06 17:57:30 +01:00
Juraj Kirchheim
4c523e02a5 Release 0.12.3 2017-03-06 14:31:20 +01:00
Juraj Kirchheim
f39fc3b296 Try to save TMono. 2017-03-06 09:16:31 +01:00
14 changed files with 229 additions and 116 deletions

1
.gitignore vendored Normal file
View File

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

View File

@@ -2,18 +2,26 @@ sudo: required
dist: trusty
language: haxe
haxe:
- "3.2.1"
- development
- 3.2.1
- development
matrix:
allow_failures:
- haxe: development
- haxe: development
install:
- haxelib install travix
- haxelib run travix install
- haxelib install travix
- haxelib run travix install
script:
- haxelib run travix node
- haxelib run travix node
env:
secure: T4SCtY5qmEsK1ARWPevJmqLm23tv4CobLrbPOQV3FsoQno7FCP1S/+9GmuoJKzeTjWMzdTeDsp8TVwZ6AyGjvhl2nZNjhU+QTsir4tfbYYRyvsz/QK6pveFbPQVv7OsnnaB4wbZtqGZ8mzFeQf7Ol4tsNe7iUFJb/iVc+4/lUxo=
deploy:
provider: script
script: haxe && haxelib run travix release
on:
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
[![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 ;)
@@ -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`.
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.
@@ -389,7 +391,7 @@ The `init` method is the swiss army knife of initializing fields. The `options.p
#### 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.

1
bin/.gitignore vendored
View File

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

View File

@@ -11,8 +11,8 @@
"contributors": [
"back2dos"
],
"releasenote": "Fix issue with .toComplex()",
"version": "0.12.2",
"releasenote": "Support artificial scopes when typing. Expose more BuildCache logic. Further improve Type -> ComplexType transformation.",
"version": "0.16.0",
"url": "http://haxetink.org/tink_macro",
"dependencies": {
"tink_core": ""

View File

@@ -5,6 +5,7 @@ import haxe.macro.Expr;
import haxe.macro.Type;
import tink.macro.TypeMap;
using tink.MacroApi;
using haxe.macro.Tools;
typedef BuildContextN = {
@@ -105,22 +106,30 @@ class BuildCache {
}));
}
static public function getParams(name:String, ?pos:Position)
return
switch Context.getLocalType() {
case TInst(_.toString() == name => true, v):
Success(v);
case TInst(_.get() => { pos: pos }, _):
pos.makeFailure('Expected $name');
case v:
pos.makeFailure('$v should be a class');
}
static public function getParam(name:String, ?pos:Position)
return
getParams(name, pos)
.flatMap(function (args:Array<Type>) return switch args {
case [v]: Success(v);
case []: pos.makeFailure('type parameter expected');
default: pos.makeFailure('too many parameters');
});
static public function getType(name, ?type, ?pos:Position, build:BuildContext->TypeDefinition) {
if (pos == null)
pos = Context.currentPos();
if (type == null)
switch Context.getLocalType() {
case TInst(_.toString() == name => true, [v]):
type = v;
case TInst(_.toString() == name => true, _):
Context.fatalError('type parameter expected', pos);
case TInst(_.get() => { pos: pos }, _):
Context.fatalError('Expected $name', pos);
default:
throw 'assert';
}
type = getParam(name, pos).sure();
var forName =
switch cache[name] {
@@ -128,7 +137,7 @@ class BuildCache {
case v: v;
}
return forName.get(type, pos, build);
return forName.get(type, pos.sanitize(), build);
}
}
@@ -157,17 +166,28 @@ private class Group {
name: path.split('.').pop()
});
Context.defineModule(path, [def], usings);
entries.set(type, { name: path } );
Context.defineModule(path, [def], usings);
return Context.getType(path);
}
function doMake()
while (true)
switch '$name${counter++}' {
case _.definedType() => Some(_):
case v:
return make(v);
}
return
switch entries.get(type) {
case null:
make('$name${counter++}');
doMake();
case v:
Context.getType(v.name);
switch v.name.definedType() {
case Some(v): v;
default: doMake();
}
}
}
}

View File

@@ -75,7 +75,7 @@ class ClassBuilder {
}
catch (e:Dynamic) {//fails for unknown reason
if (e == 'assert')
neko.Lib.rethrow(e);
tink.core.Error.rethrow(e);
constructor = new Constructor(this, null);
}
break;
@@ -175,6 +175,12 @@ class ClassBuilder {
return m;
}
public function addMembers(td:TypeDefinition):Array<Member> {
for (f in td.fields)
addMember(f);
return td.fields;
}
public function addMember(m:Member, ?front:Bool = false):Member {
doAddMember(m, front);

View File

@@ -62,6 +62,10 @@ class Constructor {
default: [].toBlock();
}
}
public function getArgList():Array<FunctionArg>
return beforeArgs.concat(args).concat(afterArgs);
public function addStatement(e:Expr, ?prepend)
if (prepend)
this.nuStatements.unshift(e)
@@ -96,7 +100,7 @@ class Constructor {
case Success(member): member.addMeta(':isVar');
default:
}
addStatement(macro @:pos(pos) (cast this).$name = if (true) $e else this.$name, options.prepend);//TODO: this seems to report type errors here rather than at the declaration position
addStatement(macro @:pos(pos) (cast this).$name = if (false) this.$name else $e, options.prepend);//TODO: this seems to report type errors here rather than at the declaration position
}
else
addStatement(macro @:pos(pos) this.$name = $e, options.prepend);

View File

@@ -241,7 +241,7 @@ class Exprs {
}
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)
return EObjectDecl([for (field in Reflect.fields(object))
@@ -312,16 +312,44 @@ class Exprs {
static public inline function resolve(s:String, ?pos)
return drill(s.split('.'), pos);
static var scopes = new Array<Array<Var>>();
static function inScope<T>(a:Array<Var>, f:Void->T) {
scopes.push(a);
inline function leave()
scopes.pop();
try {
var ret = f();
leave();
return ret;
}
catch (e:Dynamic) {
leave();
return Error.rethrow(e);
}
}
static public function scoped<T>(f:Void->T)
return inScope([], f);
static public function inSubScope<T>(f:Void->T, a:Array<Var>)
return inScope(switch scopes[scopes.length - 1] {
case null: a;
case v: v.concat(a);
}, f);
static public function typeof(expr:Expr, ?locals)
return
try {
if (locals == null)
locals = scopes[scopes.length - 1];
if (locals != null)
expr = [EVars(locals).at(expr.pos), expr].toMBlock(expr.pos);
Success(Context.typeof(expr));
}
catch (e:Error) {
var m:Dynamic = e.message;
e.pos.makeFailure(m);
catch (e:haxe.macro.Error) {
e.pos.makeFailure(e.message);
}
catch (e:Dynamic) {
expr.pos.makeFailure(e);

View File

@@ -12,7 +12,7 @@ class Positions {
return
switch outcome {
case Success(d): d;
case Failure(f): sanitize(pos).error(f);
case Failure(f): pos.error(f);
}
static public function makeBlankType(pos:Position):ComplexType
@@ -32,7 +32,17 @@ class Positions {
static public function error(pos:Position, error:Dynamic):Dynamic
return errorFunc(sanitize(pos), Std.string(error));
return
switch Std.instance(error, tink.core.Error) {
case null: errorFunc(sanitize(pos), Std.string(error));
case error:
errorFunc(
error.pos,
error.message +
if (pos == null) ''
else ' (referenced from ' + Std.string(pos).substr(5)
);
}
static function contextError(pos:Position, error:String):Dynamic
return Context.fatalError(error, pos);

View File

@@ -17,6 +17,7 @@ class Sisyphus {
case AccCall: getOrSet;
case AccInline: "default";
case AccRequire(_, _): "default";
default: throw "not implemented";
}
}
if (cf.params.length == 0) {
@@ -52,21 +53,24 @@ class Sisyphus {
}
}
public static function toComplexType(type : Null<Type>) : Null<ComplexType> return
public static function toComplexType(type : Null<Type>) : Null<ComplexType> return {
inline function direct()
return Types.toComplex(type, { direct: true });
switch (type) {
case null:
null;
case TMono(_.get() => t):
t == null ? null : toComplexType(t);
case TEnum(_.get().isPrivate => true, _): direct();
case TInst(_.get().isPrivate => true, _): direct();
case TType(_.get().isPrivate => true, _): direct();
case TAbstract(_.get().isPrivate => true, _): direct();
case TMono(_): direct();
case TEnum(_.get() => baseType, params):
TPath(toTypePath(baseType, params));
case TInst(_.get() => classType, params):
switch (classType.kind) {
case KTypeParameter(_):
TPath({
name: classType.name,
pack: [],
});
direct();//TODO: check if the parameter is in scope, in which case the name can simply be used
default:
TPath(toTypePath(classType, params));
}
@@ -92,7 +96,7 @@ class Sisyphus {
default:
throw "Invalid type";
}
}
static function toTypePath(baseType : BaseType, params : Array<Type>) : TypePath return {
var module = baseType.module;
{

View File

@@ -13,6 +13,16 @@ using tink.macro.Functions;
using tink.CoreApi;
class Types {
static public function definedType(typeName:String)
return
try {
Some(Context.getType(typeName));
}
catch (e:Dynamic)
if (Std.string(e) == 'Type not found \'$typeName\'') None;
else tink.core.Error.rethrow(e);
static var types = new Map<Int,Void->Type>();
static var idCounter = 0;
static public function getID(t:Type, ?reduced = true)
@@ -39,6 +49,16 @@ class Types {
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>) {
for (field in t.fields.get())
if (!marker.exists(field.name)) {
@@ -74,7 +94,7 @@ class Types {
fieldsCache.remove(id);//TODO: find a proper solution to avoid stale cache
ret;
case TAnonymous(anon): Success(anon.get().fields);
default: Context.currentPos().makeFailure('type has no fields');
default: Context.currentPos().makeFailure('type $t has no fields');
}
static public function getStatics(t:Type)