Compare commits
36 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5f959f788e | ||
![]() |
4f84570bb7 | ||
![]() |
e398d0e694 | ||
![]() |
13d11f4f66 | ||
![]() |
d6142847eb | ||
![]() |
e6a0304016 | ||
![]() |
69368937a4 | ||
![]() |
df2389d2c8 | ||
![]() |
aad80afec2 | ||
![]() |
b68c6ac4a1 | ||
![]() |
682aeacce8 | ||
![]() |
9bcec770eb | ||
![]() |
2310b6d8e4 | ||
![]() |
7f13916154 | ||
![]() |
2b7204f8d3 | ||
![]() |
7ca0d4a650 | ||
![]() |
e38f5ae147 | ||
![]() |
4186225eb5 | ||
![]() |
f5a3d73c55 | ||
![]() |
f65df0e94b | ||
![]() |
55a4b1463f | ||
![]() |
0a6e39969b | ||
![]() |
f051345863 | ||
![]() |
74e37b4bf1 | ||
![]() |
42821979d9 | ||
![]() |
2aa0b07e9f | ||
![]() |
67e680f67f | ||
![]() |
ebade45e63 | ||
![]() |
40497bb1fc | ||
![]() |
d80b03fe9d | ||
![]() |
f269d13abf | ||
![]() |
f271cc880a | ||
![]() |
9cd59d3989 | ||
![]() |
40ee99df39 | ||
![]() |
1cb27daf46 | ||
![]() |
a9bea4287a |
52
.travis.yml
52
.travis.yml
@@ -1,27 +1,41 @@
|
||||
sudo: required
|
||||
dist: trusty
|
||||
|
||||
language: haxe
|
||||
haxe:
|
||||
- 3.2.1
|
||||
- development
|
||||
stages:
|
||||
- test
|
||||
- deploy
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- haxe: development
|
||||
language: node_js
|
||||
node_js: 8
|
||||
|
||||
install:
|
||||
- haxelib install travix
|
||||
- haxelib run travix install
|
||||
|
||||
script:
|
||||
- haxelib run travix node
|
||||
os:
|
||||
- linux
|
||||
# - osx
|
||||
|
||||
env:
|
||||
secure: T4SCtY5qmEsK1ARWPevJmqLm23tv4CobLrbPOQV3FsoQno7FCP1S/+9GmuoJKzeTjWMzdTeDsp8TVwZ6AyGjvhl2nZNjhU+QTsir4tfbYYRyvsz/QK6pveFbPQVv7OsnnaB4wbZtqGZ8mzFeQf7Ol4tsNe7iUFJb/iVc+4/lUxo=
|
||||
- HAXE_VERSION=3.4.7
|
||||
- HAXE_VERSION=latest
|
||||
|
||||
install:
|
||||
- npm i -g lix
|
||||
- lix install haxe $HAXE_VERSION
|
||||
- lix download
|
||||
|
||||
deploy:
|
||||
provider: script
|
||||
script: haxe && haxelib run travix release
|
||||
on:
|
||||
tags: true
|
||||
script:
|
||||
- lix run travix node -lib hx3compat
|
||||
|
||||
jobs:
|
||||
include:
|
||||
# - stage: test # should uncomment this when there is no matrix above (e.g. only one os, one env, etc)
|
||||
- stage: deploy
|
||||
language: haxe
|
||||
haxe: "3.4.7"
|
||||
os: linux
|
||||
install: skip
|
||||
script: skip
|
||||
env:
|
||||
secure: T4SCtY5qmEsK1ARWPevJmqLm23tv4CobLrbPOQV3FsoQno7FCP1S/+9GmuoJKzeTjWMzdTeDsp8TVwZ6AyGjvhl2nZNjhU+QTsir4tfbYYRyvsz/QK6pveFbPQVv7OsnnaB4wbZtqGZ8mzFeQf7Ol4tsNe7iUFJb/iVc+4/lUxo=
|
||||
after_success:
|
||||
- haxelib install travix
|
||||
- haxelib run travix install
|
||||
- haxelib run travix release
|
||||
|
45
README.md
45
README.md
@@ -17,18 +17,17 @@ The library is build on top of the haxe macro API and `tink_core`, having three
|
||||
|
||||
<!-- START INDEX -->
|
||||
- [Macro API](#macro-api)
|
||||
-
|
||||
- [Expression Tools](#expression-tools)
|
||||
- [Basic Helpers](#basic-helpers)
|
||||
- [Extracting Constants](#extracting-constants)
|
||||
- [Shortcuts](#shortcuts)
|
||||
- [Type Inspection](#type-inspection)
|
||||
- [Advanced Transformations](#advanced-transformations)
|
||||
- [Position Tools](#position-tools)
|
||||
- [Type Tools](#type-tools)
|
||||
- [Function Tools](#function-tools)
|
||||
- [Operation Tools](#operation-tools)
|
||||
- [Metadata Tools](#metadata-tools)
|
||||
- [Expression Tools](#expression-tools)
|
||||
- [Basic Helpers](#basic-helpers)
|
||||
- [Extracting Constants](#extracting-constants)
|
||||
- [Shortcuts](#shortcuts)
|
||||
- [Type Inspection](#type-inspection)
|
||||
- [Advanced Transformations](#advanced-transformations)
|
||||
- [Position Tools](#position-tools)
|
||||
- [Type Tools](#type-tools)
|
||||
- [Function Tools](#function-tools)
|
||||
- [Operation Tools](#operation-tools)
|
||||
- [Metadata Tools](#metadata-tools)
|
||||
- [Build Infrastructure](#build-infrastructure)
|
||||
- [Member](#member)
|
||||
- [ClassBuilder](#classbuilder)
|
||||
@@ -51,9 +50,9 @@ It is suggested to use this API by `using tink.MacroApi;`
|
||||
|
||||
Apart form `tink_macro` specific things, it will also use `haxe.macro.ExprTools` and `tink.core.Outcome`.
|
||||
|
||||
### Expression Tools
|
||||
## Expression Tools
|
||||
|
||||
#### Basic Helpers
|
||||
### Basic Helpers
|
||||
|
||||
- `at(e:ExprDef, ?pos:Position):Expr`
|
||||
A short hand for creating expression as for example `EReturn(value).at(position)`, instead of the more verbose `{ expr: EReturn(value), pos: position }`.
|
||||
@@ -69,7 +68,7 @@ Traces the string representation of an expression and returns it.
|
||||
- `concat(e1:Expr, e2:Expr):Expr`
|
||||
Concats two expressions into a block. If either sub-expression is a block itself, it gets flattened into the resulting block.
|
||||
|
||||
#### Extracting Constants
|
||||
### Extracting Constants
|
||||
|
||||
- `isWildcard(e:Expr):Bool`
|
||||
Checks whether an expression is the identifier `_`
|
||||
@@ -82,7 +81,7 @@ Attempts extracting an identifier from an expression. Note that an identifier ca
|
||||
- `getName(e:Expr):Outcome<String, tink.core.Error>`
|
||||
Attempts extracting a name, i.e. a string constant or identifier from an expression
|
||||
|
||||
#### Shortcuts
|
||||
### Shortcuts
|
||||
|
||||
Often reification is prefereable to these shortcuts - if applicable. Unlike reification, the position of these expressions will default to `Context.currentPos()` rather than the position where they were created.
|
||||
|
||||
@@ -119,7 +118,7 @@ Generates a simple if statement.
|
||||
- `iterate(target:Expr, body:Expr, ?loopVar:String = 'i', ?pos:Position):Expr`
|
||||
Will loop over `target` with a loop variable called `loopVar` using `body`-
|
||||
|
||||
#### Type Inspection
|
||||
### Type Inspection
|
||||
|
||||
- `is(e:Expr, c:ComplexType):Bool`
|
||||
Tells you whether a given expression has a given type.
|
||||
@@ -129,7 +128,7 @@ Inspects, whether an expression can be iterated over and if so returns the eleme
|
||||
- `typeof(expr:Expr, ?locals:Array<Var>):Outcome<Type, tink.core.Error>`
|
||||
Attempts to determine the type of an expression. Note that you can use `locals` to hint the compiler the type of certain identifiers. For example if you are in a build macro, and you want to get the type of a subexpression of a method body, you could "fake" the other members of the class as local variables, because in that context, the other members do not yet exists from the compiler's perspective.
|
||||
|
||||
#### Advanced Transformations
|
||||
### Advanced Transformations
|
||||
|
||||
- `has(e:Expr, condition:Expr->Bool, ?options: { ?enterFunctions: Bool })`
|
||||
This function actually does no transformation, but is very close to the rest of these functions. It allows you to check whether an expression has a sub-expression that satisfies `condition`. By default, it does not enter nested functions.
|
||||
@@ -187,7 +186,7 @@ This will traverse an expression and will apply the `yielder` to the "leafs", wh
|
||||
|
||||
If you set `options.leaveLoops` to `true`, then loops (both for and while) will be considered leafs.
|
||||
|
||||
### Position Tools
|
||||
## Position Tools
|
||||
|
||||
- `sanitize(pos:Position):Position`
|
||||
Returns the position ITself or `Context.currentPos()` if it's null.
|
||||
@@ -202,7 +201,7 @@ Creates a failed `Outcome` associated with the supplied position.
|
||||
- `getOutcome<D, F>(pos:Position, outcome:Outcome<D, F>):D`
|
||||
Attempts getting the result of the supplied outcome. If it is a failure, it will cause an error at the given position.
|
||||
|
||||
### Type Tools
|
||||
## Type Tools
|
||||
|
||||
- `getID(t:Type, ?reduced = true):Null<String>`
|
||||
Returns a String identifier for a type if available. By default, the type will be reduced prior to getting its name (typedefs are resolved etc.). With `reduced = false` you can also get the name of a typedef.
|
||||
@@ -225,7 +224,7 @@ Will tell you whether a field is a variable or not. Signature is likely to chang
|
||||
- `toComplex(type:Type, ?option:{ ?direct: Bool }):ComplexType`
|
||||
Will convert a `Type` to a `ComplexType`. Ideally this is done with `Context.toComplexType` but for monomorphs and the like, this builtin method fails and `tink_macro` uses a hack to make it work none the less. You can also use `{ direct : true }` to force this hack in case the translation fails (which can be the case with private types).
|
||||
|
||||
### Function Tools
|
||||
## Function Tools
|
||||
|
||||
- `asExpr(f:Function, ?name:String, ?pos:Position):Expr`
|
||||
Converts a function to an expression, i.e. a local function definition.
|
||||
@@ -236,7 +235,7 @@ A shorthand to create function arguments.
|
||||
- `getArgIdents(f:Function):Array<Expr>`
|
||||
Will extract the argument list of a function as an expression list of identifiers (usefull when writing call-forwarding macros or the like).
|
||||
|
||||
### Operation Tools
|
||||
## Operation Tools
|
||||
|
||||
- `get(o:Binop, e:Expr):Outcome<{ e1:Expr, e2:Expr, pos:Position }, tink.core.Error>`
|
||||
Attempts to extract a specific binary operation from an expression.
|
||||
@@ -250,7 +249,7 @@ Attempts to extract a specific unary operation from an expression.
|
||||
- `getUnop(e:Expr):Outcome<{ op:Unop, e:Expr, postFix:Bool, pos:Position }, tink.core.Error>`
|
||||
Attempts to decompose an expression into the parts of a unary operation.
|
||||
|
||||
### Metadata Tools
|
||||
## Metadata Tools
|
||||
|
||||
- `toMap(m:Metadata):Map<String, Array<Array<Expr>>`
|
||||
Will deconstruct an array of metadata tags to a `Map` mapping the tag names to an array of the argument lists of each tag with that name. So `@foo(1) @foo(2) @bar` becomes `["foo" => [[1], [2]], "bar" => [[]]]`
|
||||
|
3
haxe_libraries/hx3compat.hxml
Normal file
3
haxe_libraries/hx3compat.hxml
Normal file
@@ -0,0 +1,3 @@
|
||||
-D hx3compat=1.0.0
|
||||
# @install: lix --silent download "haxelib:/hx3compat#1.0.0" into hx3compat/1.0.0/haxelib
|
||||
-cp ${HAXE_LIBCACHE}/hx3compat/1.0.0/haxelib/std
|
6
haxe_libraries/hxnodejs.hxml
Normal file
6
haxe_libraries/hxnodejs.hxml
Normal file
@@ -0,0 +1,6 @@
|
||||
# @install: lix --silent download "haxelib:hxnodejs#4.0.9" into hxnodejs/4.0.9/haxelib
|
||||
-D hxnodejs=4.0.9
|
||||
-cp ${HAXESHIM_LIBCACHE}/hxnodejs/4.0.9/haxelib/src
|
||||
-D nodejs
|
||||
--macro allowPackage('sys')
|
||||
--macro _hxnodejs.VersionWarning.include()
|
8
haxe_libraries/tink_cli.hxml
Normal file
8
haxe_libraries/tink_cli.hxml
Normal file
@@ -0,0 +1,8 @@
|
||||
-D tink_cli=0.3.1
|
||||
# @install: lix --silent download "haxelib:/tink_cli#0.3.1" into tink_cli/0.3.1/haxelib
|
||||
-lib tink_io
|
||||
-lib tink_stringly
|
||||
-lib tink_macro
|
||||
-cp ${HAXE_LIBCACHE}/tink_cli/0.3.1/haxelib/src
|
||||
# Make sure docs are generated
|
||||
-D use-rtti-doc
|
3
haxe_libraries/tink_core.hxml
Normal file
3
haxe_libraries/tink_core.hxml
Normal file
@@ -0,0 +1,3 @@
|
||||
# @install: lix --silent download "haxelib:tink_core#1.16.1" into tink_core/1.16.1/haxelib
|
||||
-D tink_core=1.16.1
|
||||
-cp ${HAXESHIM_LIBCACHE}/tink_core/1.16.1/haxelib/src
|
5
haxe_libraries/tink_io.hxml
Normal file
5
haxe_libraries/tink_io.hxml
Normal file
@@ -0,0 +1,5 @@
|
||||
-D tink_io=0.5.0
|
||||
# @install: lix --silent download "haxelib:/tink_io#0.5.0" into tink_io/0.5.0/haxelib
|
||||
-lib tink_streams
|
||||
-lib tink_core
|
||||
-cp ${HAXE_LIBCACHE}/tink_io/0.5.0/haxelib/src
|
3
haxe_libraries/tink_macro.hxml
Normal file
3
haxe_libraries/tink_macro.hxml
Normal file
@@ -0,0 +1,3 @@
|
||||
-D tink_macro
|
||||
-cp src
|
||||
-lib tink_core
|
4
haxe_libraries/tink_streams.hxml
Normal file
4
haxe_libraries/tink_streams.hxml
Normal file
@@ -0,0 +1,4 @@
|
||||
-D tink_streams=0.2.1
|
||||
# @install: lix --silent download "haxelib:/tink_streams#0.2.1" into tink_streams/0.2.1/haxelib
|
||||
-lib tink_core
|
||||
-cp ${HAXE_LIBCACHE}/tink_streams/0.2.1/haxelib/src
|
4
haxe_libraries/tink_stringly.hxml
Normal file
4
haxe_libraries/tink_stringly.hxml
Normal file
@@ -0,0 +1,4 @@
|
||||
-D tink_stringly=0.2.0
|
||||
# @install: lix --silent download "haxelib:/tink_stringly#0.2.0" into tink_stringly/0.2.0/haxelib
|
||||
-lib tink_core
|
||||
-cp ${HAXE_LIBCACHE}/tink_stringly/0.2.0/haxelib/src
|
6
haxe_libraries/travix.hxml
Normal file
6
haxe_libraries/travix.hxml
Normal file
@@ -0,0 +1,6 @@
|
||||
-D travix=0.12.2
|
||||
# @install: lix --silent download "gh://github.com/back2dos/travix#f46e67b6330d2e85b487a9fd512b10e4e0f1058f" into travix/0.12.2/github/f46e67b6330d2e85b487a9fd512b10e4e0f1058f
|
||||
# @post-install: cd ${HAXE_LIBCACHE}/travix/0.12.2/github/f46e67b6330d2e85b487a9fd512b10e4e0f1058f && haxe -cp src --run travix.PostDownload
|
||||
# @run: haxelib run-dir travix ${HAXE_LIBCACHE}/travix/0.12.2/github/f46e67b6330d2e85b487a9fd512b10e4e0f1058f
|
||||
-lib tink_cli
|
||||
-cp ${HAXE_LIBCACHE}/travix/0.12.2/github/f46e67b6330d2e85b487a9fd512b10e4e0f1058f/src
|
24
haxelib.json
24
haxelib.json
@@ -1,20 +1,20 @@
|
||||
{
|
||||
"name": "tink_macro",
|
||||
"license": "MIT",
|
||||
"description": "The macro toolkit ;)",
|
||||
"classPath": "src",
|
||||
"dependencies": {
|
||||
"tink_core": ""
|
||||
},
|
||||
"url": "http://haxetink.org/tink_macro",
|
||||
"contributors": [
|
||||
"back2dos"
|
||||
],
|
||||
"version": "0.17.1",
|
||||
"releasenote": "Improve type parameter treatment. Add helper for getting field suggestions. Make type comparator available.",
|
||||
"tags": [
|
||||
"tink",
|
||||
"macro",
|
||||
"utility"
|
||||
],
|
||||
"classPath": "src",
|
||||
"description": "The macro toolkit ;)",
|
||||
"contributors": [
|
||||
"back2dos"
|
||||
],
|
||||
"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": ""
|
||||
}
|
||||
"license": "MIT"
|
||||
}
|
@@ -37,3 +37,50 @@ class MacroApi {
|
||||
return haxe.macro.Context.currentPos();
|
||||
|
||||
}
|
||||
|
||||
|
||||
#if (haxe_ver >= 4)
|
||||
typedef ObjectField = haxe.macro.Expr.ObjectField;
|
||||
typedef QuoteStatus = haxe.macro.Expr.QuoteStatus;
|
||||
#else
|
||||
enum QuoteStatus {
|
||||
Unquoted;
|
||||
Quoted;
|
||||
}
|
||||
private typedef F = {
|
||||
var field:String;
|
||||
var expr:haxe.macro.Expr;
|
||||
}
|
||||
|
||||
@:forward
|
||||
abstract ObjectField(F) to F {
|
||||
|
||||
static var QUOTED = "@$__hx__";
|
||||
|
||||
inline function new(o) this = o;
|
||||
|
||||
public var field(get, never):String;
|
||||
|
||||
function get_field()
|
||||
return
|
||||
if (quotes == Quoted)
|
||||
this.field.substr(QUOTED.length);
|
||||
else this.field;
|
||||
|
||||
public var quotes(get, never):QuoteStatus;
|
||||
|
||||
function get_quotes()
|
||||
return if (StringTools.startsWith(this.field, QUOTED)) Quoted else Unquoted;
|
||||
|
||||
@:from static function ofFull(o:{>F, quotes:QuoteStatus }):ObjectField
|
||||
return switch o.quotes {
|
||||
case null | Unquoted:
|
||||
new ObjectField({ field: o.field, expr: o.expr });
|
||||
default:
|
||||
new ObjectField({ field: QUOTED + o.field, expr: o.expr });
|
||||
}
|
||||
|
||||
@:from static function ofOld(o:F):ObjectField
|
||||
return new ObjectField(o);
|
||||
}
|
||||
#end
|
@@ -74,7 +74,11 @@ class BuildCache {
|
||||
var compound = ComplexType.TAnonymous([for (i in 0...types.length) {
|
||||
name: 't$i',
|
||||
pos: pos,
|
||||
kind: FVar(types[i].toComplexType()),
|
||||
kind: FVar(switch types[i] {
|
||||
case TInst(_.get().kind => KExpr(e), _):
|
||||
TPath('tink.macro.ConstParam'.asTypePath([TPExpr(e)]));
|
||||
case t: t.toComplex();
|
||||
}),
|
||||
}]).toType();
|
||||
|
||||
return getType(name, compound, pos, function (ctx) return build({
|
||||
|
@@ -63,7 +63,9 @@ class ClassBuilder {
|
||||
if (cl.constructor != null) {
|
||||
try {
|
||||
var ctor = cl.constructor.get();
|
||||
var func = Context.getTypedExpr(ctor.expr()).getFunction().sure();
|
||||
var ctorExpr = ctor.expr();
|
||||
if (ctorExpr == null) throw 'Super constructor has no expression';
|
||||
var func = Context.getTypedExpr(ctorExpr).getFunction().sure();
|
||||
|
||||
for (arg in func.args) //this is to deal with type parameter substitutions
|
||||
arg.type = null;
|
||||
@@ -196,4 +198,4 @@ class ClassBuilder {
|
||||
p(builder);
|
||||
return builder.export(verbose);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
3
src/tink/macro/ConstParam.hx
Normal file
3
src/tink/macro/ConstParam.hx
Normal file
@@ -0,0 +1,3 @@
|
||||
package tink.macro;
|
||||
|
||||
class ConstParam<Const> {}
|
@@ -1,8 +1,10 @@
|
||||
package tink.macro;
|
||||
|
||||
import haxe.macro.Type;
|
||||
import haxe.macro.Expr;
|
||||
import haxe.macro.Context;
|
||||
import tink.core.Pair;
|
||||
using haxe.macro.Tools;
|
||||
using tink.MacroApi;
|
||||
|
||||
enum FieldInit {
|
||||
@@ -100,7 +102,43 @@ class Constructor {
|
||||
case Success(member): member.addMeta(':isVar');
|
||||
default:
|
||||
}
|
||||
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
|
||||
addStatement((function () {
|
||||
var fields = [for (f in (macro this).typeof().sure().getClass().fields.get()) f.name => f];
|
||||
|
||||
function setDirectly(t:TypedExpr) {
|
||||
var direct = null;
|
||||
function seek(t:TypedExpr) {
|
||||
switch t.expr {
|
||||
case TField({ expr: TConst(TThis) }, FInstance(_, _, f)) if (f.get().name == name): direct = t;
|
||||
default: t.iter(seek);
|
||||
}
|
||||
}
|
||||
seek(t);
|
||||
if (direct == null) pos.error('nope');
|
||||
var direct = Context.storeTypedExpr(direct);
|
||||
return macro @:pos(pos) $direct = $e;
|
||||
}
|
||||
|
||||
return switch fields[name] {
|
||||
case null:
|
||||
pos.error('this direct initialization causes the compiler to do really weird things');
|
||||
case f:
|
||||
switch f.kind {
|
||||
case FVar(_, AccNormal | AccNo):
|
||||
macro @:pos(pos) this.$name = $e;
|
||||
case FVar(AccNever, AccNever):
|
||||
macro @:pos(pos) this.$name = $e;
|
||||
case FVar(AccNo | AccNormal, AccNever):
|
||||
setDirectly(Context.typeExpr(macro @:pos(pos) this.$name));
|
||||
case FVar(AccCall, AccNever):
|
||||
setDirectly(fields['get_$name'].expr());
|
||||
case FVar(_, AccCall):
|
||||
setDirectly(fields['set_$name'].expr());
|
||||
default:
|
||||
pos.error('not implemented');
|
||||
}
|
||||
}
|
||||
}).bounce(), options.prepend);
|
||||
}
|
||||
else
|
||||
addStatement(macro @:pos(pos) this.$name = $e, options.prepend);
|
||||
|
@@ -428,6 +428,22 @@ class Exprs {
|
||||
}
|
||||
}
|
||||
|
||||
static var FIRST = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
static var LATER = FIRST + '0123456789';
|
||||
|
||||
static public function shortIdent(i:Int) {
|
||||
var ret = FIRST.charAt(i % FIRST.length);
|
||||
|
||||
i = Std.int(i / FIRST.length);
|
||||
|
||||
while (i > 0) {
|
||||
ret += LATER.charAt(i % LATER.length);
|
||||
i = Std.int(i / LATER.length);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline var NOT_AN_INT = "integer constant expected";
|
||||
static inline var NOT_AN_IDENT = "identifier expected";
|
||||
static inline var NOT_A_STRING = "string constant expected";
|
||||
|
@@ -32,6 +32,7 @@ abstract Member(Field) from Field to Field {
|
||||
}
|
||||
|
||||
public var name(get, set):String;
|
||||
public var meta(get, set):Metadata;
|
||||
public var doc(get, set):Null<String>;
|
||||
public var kind(get, set):FieldType;
|
||||
public var pos(get, set):Position;
|
||||
@@ -76,6 +77,11 @@ abstract Member(Field) from Field to Field {
|
||||
}
|
||||
return pos.makeFailure('missing @$name');
|
||||
}
|
||||
|
||||
public function metaNamed(name)
|
||||
return
|
||||
if (this.meta == null) [];
|
||||
else [for (tag in this.meta) if (tag.name == name) tag];
|
||||
|
||||
public inline function asField():Field return this;
|
||||
public function publish()
|
||||
@@ -86,6 +92,12 @@ abstract Member(Field) from Field to Field {
|
||||
this.access.push(APublic);
|
||||
}
|
||||
|
||||
inline function get_meta() return switch this.meta {
|
||||
case null: this.meta = [];
|
||||
case v: v;
|
||||
}
|
||||
inline function set_meta(param) return this.meta = param;
|
||||
|
||||
inline function get_name() return this.name;
|
||||
inline function set_name(param) return this.name = param;
|
||||
|
||||
|
@@ -70,7 +70,16 @@ class Sisyphus {
|
||||
case TInst(_.get() => classType, params):
|
||||
switch (classType.kind) {
|
||||
case KTypeParameter(_):
|
||||
direct();//TODO: check if the parameter is in scope, in which case the name can simply be used
|
||||
var ct = Types.asComplexType(classType.name);
|
||||
switch Types.toType(ct) {
|
||||
case Success(TInst(_.get() => cl, _)) if (
|
||||
cl.kind.match(KTypeParameter(_))
|
||||
&& cl.module == classType.module
|
||||
&& cl.pack.join('.') == classType.pack.join('.')
|
||||
): ct;
|
||||
default:
|
||||
direct();
|
||||
}
|
||||
default:
|
||||
TPath(toTypePath(classType, params));
|
||||
}
|
||||
@@ -99,11 +108,20 @@ class Sisyphus {
|
||||
}
|
||||
static function toTypePath(baseType : BaseType, params : Array<Type>) : TypePath return {
|
||||
var module = baseType.module;
|
||||
var name = module.substring(module.lastIndexOf(".") + 1);
|
||||
var sub = switch baseType.name {
|
||||
case _ == name => true: null;
|
||||
case v: v;
|
||||
}
|
||||
|
||||
{
|
||||
pack: baseType.pack,
|
||||
name: module.substring(module.lastIndexOf(".") + 1),
|
||||
sub: baseType.name,
|
||||
params: [ for (t in params) TPType(toComplexType(t)) ],
|
||||
name: name,
|
||||
sub: sub,
|
||||
params: [for (t in params) switch t {
|
||||
case TInst(_.get().kind => KExpr(e), _): TPExpr(e);
|
||||
default: TPType(toComplexType(t));
|
||||
}],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -5,7 +5,6 @@ import haxe.ds.BalancedTree;
|
||||
import haxe.macro.Context;
|
||||
import haxe.macro.Type;
|
||||
|
||||
using haxe.macro.Tools;
|
||||
using tink.MacroApi;
|
||||
|
||||
class TypeMap<V> extends BalancedTree<Type, V> implements IMap<Type, V> {
|
||||
@@ -16,18 +15,7 @@ class TypeMap<V> extends BalancedTree<Type, V> implements IMap<Type, V> {
|
||||
super();
|
||||
}
|
||||
|
||||
override function compare(k1:Type, k2:Type):Int {
|
||||
|
||||
if (follow) {
|
||||
k1 = k1.reduce();
|
||||
k2 = k2.reduce();
|
||||
}
|
||||
|
||||
return switch k1.getIndex() - k2.getIndex() {
|
||||
case 0:
|
||||
Reflect.compare(k1.toString(), k2.toString());//much to my surprise, this actually seems to work (at least with 3.4)
|
||||
case v: v;
|
||||
}
|
||||
}
|
||||
override function compare(k1:Type, k2:Type):Int
|
||||
return k1.compare(k2, follow);
|
||||
|
||||
}
|
@@ -1,15 +1,13 @@
|
||||
package tink.macro;
|
||||
|
||||
import haxe.macro.Printer;
|
||||
import Type in Enums;
|
||||
|
||||
import haxe.macro.Context;
|
||||
import haxe.macro.Expr;
|
||||
import haxe.macro.Type;
|
||||
|
||||
using tink.macro.Exprs;
|
||||
using tink.macro.Positions;
|
||||
using tink.macro.Functions;
|
||||
using haxe.macro.Tools;
|
||||
using tink.MacroApi;
|
||||
using tink.CoreApi;
|
||||
|
||||
class Types {
|
||||
@@ -146,8 +144,16 @@ class Types {
|
||||
static public inline function asComplexType(s:String, ?params)
|
||||
return TPath(asTypePath(s, params));
|
||||
|
||||
static public inline function reduce(type:Type, ?once)
|
||||
return Context.follow(type, once);
|
||||
static public function reduce(type:Type, ?once) {
|
||||
function rec(t:Type)
|
||||
return if (once) t else reduce(t, false);
|
||||
return switch type {
|
||||
case TAbstract(_.get() => { name: 'Null', pack: [] }, [t]): rec(t);
|
||||
case TLazy(f): rec(f());
|
||||
case TType(_, _): rec(Context.follow(type, once));
|
||||
default: type;
|
||||
}
|
||||
}
|
||||
|
||||
static public function isVar(field:ClassField)
|
||||
return switch (field.kind) {
|
||||
@@ -175,6 +181,33 @@ class Types {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static public function intersect(types:Array<ComplexType>, ?pos:Position):Outcome<ComplexType, Error> {
|
||||
|
||||
if (types.length == 1) return Success(types[1]);
|
||||
|
||||
var paths = [],
|
||||
fields = [];
|
||||
|
||||
for (t in types)
|
||||
switch t {
|
||||
case TPath(p): paths.push(p);
|
||||
case TAnonymous(f):
|
||||
|
||||
for (f in f) fields.push(f);
|
||||
|
||||
case TExtend(p, f):
|
||||
|
||||
for (f in f) fields.push(f);
|
||||
for (p in p) paths.push(p);
|
||||
|
||||
default:
|
||||
|
||||
return Failure(new Error(t.toString() + ' cannot be interesected', pos));
|
||||
}
|
||||
|
||||
return Success(TExtend(paths, fields));
|
||||
}
|
||||
|
||||
static public function lazyComplex(f:Void->Type)
|
||||
return
|
||||
TPath({
|
||||
@@ -193,4 +226,25 @@ class Types {
|
||||
throw 'assert';
|
||||
}
|
||||
|
||||
static public function compare(t1:Type, t2:Type, ?follow:Bool = true) {
|
||||
if (follow) {
|
||||
t1 = t1.reduce();
|
||||
t2 = t2.reduce();
|
||||
}
|
||||
|
||||
return switch t1.getIndex() - t2.getIndex() {
|
||||
case 0:
|
||||
Reflect.compare(t1.toString(), t2.toString());//much to my surprise, this actually seems to work (at least with 3.4)
|
||||
case v: v;
|
||||
}
|
||||
}
|
||||
|
||||
static var SUGGESTIONS = ~/ \(Suggestions?: .*\)$/;
|
||||
|
||||
static public function getFieldSuggestions(type:ComplexType, name:String):String
|
||||
return switch (macro (null : $type).$name).typeof() {
|
||||
case Failure(SUGGESTIONS.match(_.message) => true): SUGGESTIONS.matched(0);
|
||||
default: '';
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package ;
|
||||
|
||||
import haxe.macro.Context;
|
||||
import haxe.macro.Expr;
|
||||
using tink.MacroApi;
|
||||
|
||||
@@ -7,6 +8,14 @@ class Exprs extends Base {
|
||||
function exprEq(e1:Expr, e2:Expr) {
|
||||
assertEquals(e1.toString(), e2.toString());
|
||||
}
|
||||
|
||||
function testShort() {
|
||||
for (i in 0...100) {
|
||||
var id = (100 * i).shortIdent();
|
||||
Context.parseInlineString(id, (macro null).pos);
|
||||
assertTrue(id.length <= 3);
|
||||
}
|
||||
}
|
||||
function testGet() {
|
||||
assertEquals('foo', (macro foo).getIdent().sure());
|
||||
assertEquals('foo', (macro "foo").getString().sure());
|
||||
|
@@ -44,4 +44,13 @@ class Types extends Base {
|
||||
|
||||
MacroApi.pos().makeBlankType().toString();
|
||||
}
|
||||
|
||||
function testExpr() {
|
||||
assertEquals('VarChar<255>', (macro : VarChar<255>).toType().sure().toComplex().toString());
|
||||
}
|
||||
|
||||
function testToComplex() {
|
||||
assertEquals('String', Context.getType('String').toComplex().toString());
|
||||
assertEquals('tink.CoreApi.Noise', Context.getType('tink.CoreApi.Noise').toComplex().toString());
|
||||
}
|
||||
}
|
1
tests/VarChar.hx
Normal file
1
tests/VarChar.hx
Normal file
@@ -0,0 +1 @@
|
||||
typedef VarChar<Const> = String;
|
Reference in New Issue
Block a user