Compare commits
1 Commits
kiss-worka
...
genes-issu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a77aedb458 |
95
.github/workflows/ci.yml
vendored
95
.github/workflows/ci.yml
vendored
@@ -1,95 +0,0 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
haxe-version:
|
||||
- stable
|
||||
- nightly
|
||||
target:
|
||||
- node
|
||||
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Get yarn cache directory path
|
||||
id: yarn-cache-dir-path
|
||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||
|
||||
- name: Cache Yarn
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-
|
||||
|
||||
- name: Cache Haxe
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/haxe
|
||||
key: haxe
|
||||
|
||||
- name: Install Lix
|
||||
uses: lix-pm/setup-lix@master
|
||||
|
||||
- name: Install Haxe
|
||||
run: lix install haxe ${{ matrix.haxe-version }}
|
||||
|
||||
- name: Install Haxe Libraries
|
||||
run: lix download
|
||||
|
||||
- name: Run Test
|
||||
run: lix run travix ${{ matrix.target }}
|
||||
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
needs: test
|
||||
if: startsWith(github.ref, 'refs/tags/') # consider using the "release" event. see: https://docs.github.com/en/actions/reference/events-that-trigger-workflows#release
|
||||
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Get yarn cache directory path
|
||||
id: yarn-cache-dir-path
|
||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||
|
||||
- name: Cache Yarn
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-
|
||||
|
||||
- name: Cache Haxe
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/haxe
|
||||
key: haxe
|
||||
|
||||
- name: Install Lix
|
||||
uses: lix-pm/setup-lix@master
|
||||
|
||||
- name: Install Haxe
|
||||
run: lix install haxe stable
|
||||
|
||||
- name: Install Haxe Libraries
|
||||
run: lix download
|
||||
|
||||
- name: Release to Haxelib
|
||||
run: lix run travix release
|
||||
env:
|
||||
HAXELIB_AUTH: ${{ secrets.HAXELIB_AUTH }}
|
||||
|
||||
2
.haxerc
2
.haxerc
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"version": "4.2.1",
|
||||
"version": "e552bdc",
|
||||
"resolveLibs": "scoped"
|
||||
}
|
||||
@@ -22,7 +22,7 @@ install:
|
||||
- lix download
|
||||
|
||||
script:
|
||||
- lix run travix node
|
||||
- lix run travix node -lib hx3compat
|
||||
|
||||
jobs:
|
||||
include:
|
||||
17
.vscode/tasks.json
vendored
17
.vscode/tasks.json
vendored
@@ -1,19 +1,6 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"version": "0.1.0",
|
||||
"command": "haxelib",
|
||||
"args": ["run", "travix", "node"],
|
||||
"problemMatcher": "$haxe",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "haxelib",
|
||||
"command": "haxelib",
|
||||
"args": [
|
||||
"run",
|
||||
"travix",
|
||||
"node"
|
||||
],
|
||||
"problemMatcher": "$haxe",
|
||||
"group": "build"
|
||||
}
|
||||
]
|
||||
"problemMatcher": "$haxe"
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
# Tinkerbell Macro Library
|
||||
|
||||
[](https://github.com/haxetink/tink_macro/actions)
|
||||
[](https://gitter.im/haxetink/public)
|
||||
[](https://discord.com/channels/162395145352904705/579634919576436736)
|
||||
|
||||
[](https://travis-ci.org/haxetink/tink_macro)
|
||||
[](https://gitter.im/haxetink/public)
|
||||
|
||||
Explained in current marketing speak, `tink_macro` is *the* macro toolkit ;)
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# @install: lix --silent download "haxelib:/hx3compat#1.0.3" into hx3compat/1.0.3/haxelib
|
||||
-cp ${HAXE_LIBCACHE}/hx3compat/1.0.3/haxelib/std
|
||||
-D hx3compat=1.0.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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# @install: lix --silent download "haxelib:/hxnodejs#12.0.0" into hxnodejs/12.0.0/haxelib
|
||||
-cp ${HAXE_LIBCACHE}/hxnodejs/12.0.0/haxelib/src
|
||||
-D hxnodejs=12.0.0
|
||||
# @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')
|
||||
# should behave like other target defines and not be defined in macro context
|
||||
--macro define('nodejs')
|
||||
--macro _hxnodejs.VersionWarning.include()
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# @install: lix --silent download "gh://github.com/haxetink/tink_chunk#f095072a029f1f50ce5f2cc0a690c3e834298d96" into tink_chunk/0.3.1/github/f095072a029f1f50ce5f2cc0a690c3e834298d96
|
||||
-cp ${HAXE_LIBCACHE}/tink_chunk/0.3.1/github/f095072a029f1f50ce5f2cc0a690c3e834298d96/src
|
||||
-D tink_chunk=0.3.1
|
||||
@@ -1,8 +1,8 @@
|
||||
# @install: lix --silent download "gh://github.com/haxetink/tink_cli#1278ad2a34fd5e2403e414aefe09bb938d0c8825" into tink_cli/0.5.1/github/1278ad2a34fd5e2403e414aefe09bb938d0c8825
|
||||
-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_macro
|
||||
-lib tink_stringly
|
||||
-cp ${HAXE_LIBCACHE}/tink_cli/0.5.1/github/1278ad2a34fd5e2403e414aefe09bb938d0c8825/src
|
||||
-D tink_cli=0.5.1
|
||||
-lib tink_macro
|
||||
-cp ${HAXE_LIBCACHE}/tink_cli/0.3.1/haxelib/src
|
||||
# Make sure docs are generated
|
||||
-D use-rtti-doc
|
||||
@@ -1,3 +1,3 @@
|
||||
# @install: lix --silent download "haxelib:/tink_core#2.1.0" into tink_core/2.1.0/haxelib
|
||||
-cp ${HAXE_LIBCACHE}/tink_core/2.1.0/haxelib/src
|
||||
-D tink_core=2.1.0
|
||||
-D tink_core=1.24.0
|
||||
# @install: lix --silent download "haxelib:/tink_core#1.24.0" into tink_core/1.24.0/haxelib
|
||||
-cp ${HAXE_LIBCACHE}/tink_core/1.24.0/haxelib/src
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# @install: lix --silent download "gh://github.com/haxetink/tink_io#e4a92421865adfd7037474937cffacaa1abd4338" into tink_io/0.8.0/github/e4a92421865adfd7037474937cffacaa1abd4338
|
||||
-lib tink_chunk
|
||||
-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
|
||||
-cp ${HAXE_LIBCACHE}/tink_io/0.8.0/github/e4a92421865adfd7037474937cffacaa1abd4338/src
|
||||
-D tink_io=0.8.0
|
||||
-lib tink_core
|
||||
-cp ${HAXE_LIBCACHE}/tink_io/0.5.0/haxelib/src
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
# @install: lix --silent download "gh://github.com/haxetink/tink_streams#aa006c354e742164c4f7bc8ec4532bc9154fb0d0" into tink_streams/0.3.3/github/aa006c354e742164c4f7bc8ec4532bc9154fb0d0
|
||||
-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.3.3/github/aa006c354e742164c4f7bc8ec4532bc9154fb0d0/src
|
||||
-D tink_streams=0.3.3
|
||||
# temp for development, delete this file when pure branch merged
|
||||
-D pure
|
||||
-cp ${HAXE_LIBCACHE}/tink_streams/0.2.1/haxelib/src
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# @install: lix --silent download "gh://github.com/back2dos/travix#354c2b2a82cc3b03e2f87cc1b6f0ddc0a6a5c133" into travix/0.15.0/github/354c2b2a82cc3b03e2f87cc1b6f0ddc0a6a5c133
|
||||
# @post-install: cd ${HAXE_LIBCACHE}/travix/0.15.0/github/354c2b2a82cc3b03e2f87cc1b6f0ddc0a6a5c133 && haxe -cp src --run travix.PostDownload
|
||||
# @run: haxelib run-dir travix ${HAXE_LIBCACHE}/travix/0.15.0/github/354c2b2a82cc3b03e2f87cc1b6f0ddc0a6a5c133
|
||||
-D travix=0.12.2
|
||||
# @install: lix --silent download "gh://github.com/back2dos/travix#7da3bf96717b52bf3c7e5d2273bf927a8cd7aeb5" into travix/0.12.2/github/7da3bf96717b52bf3c7e5d2273bf927a8cd7aeb5
|
||||
# @post-install: cd ${HAXE_LIBCACHE}/travix/0.12.2/github/7da3bf96717b52bf3c7e5d2273bf927a8cd7aeb5 && haxe -cp src --run travix.PostDownload
|
||||
# @run: haxelib run-dir travix ${HAXE_LIBCACHE}/travix/0.12.2/github/7da3bf96717b52bf3c7e5d2273bf927a8cd7aeb5
|
||||
-lib tink_cli
|
||||
-cp ${HAXE_LIBCACHE}/travix/0.15.0/github/354c2b2a82cc3b03e2f87cc1b6f0ddc0a6a5c133/src
|
||||
-D travix=0.15.0
|
||||
--macro travix.Macro.setup()
|
||||
-cp ${HAXE_LIBCACHE}/travix/0.12.2/github/7da3bf96717b52bf3c7e5d2273bf927a8cd7aeb5/src
|
||||
|
||||
24
haxelib.json
24
haxelib.json
@@ -1,20 +1,20 @@
|
||||
{
|
||||
"name": "tink_macro",
|
||||
"description": "The macro toolkit ;)",
|
||||
"classPath": "src",
|
||||
"dependencies": {
|
||||
"tink_core": ""
|
||||
},
|
||||
"url": "https://github.com/haxetink/tink_macro",
|
||||
"contributors": [
|
||||
"back2dos"
|
||||
],
|
||||
"version": "1.0.3",
|
||||
"releasenote": "Make Member::hasMeta null safe.",
|
||||
"license": "MIT",
|
||||
"tags": [
|
||||
"tink",
|
||||
"macro",
|
||||
"utility"
|
||||
],
|
||||
"license": "MIT"
|
||||
"classPath": "src",
|
||||
"description": "The macro toolkit ;)",
|
||||
"contributors": [
|
||||
"back2dos"
|
||||
],
|
||||
"releasenote": "Compat with haxe 4 rc4 onward.",
|
||||
"version": "0.18.0",
|
||||
"url": "http://haxetink.org/tink_macro",
|
||||
"dependencies": {
|
||||
"tink_core": ""
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,6 @@ using StringTools;
|
||||
|
||||
typedef Positions = tink.macro.Positions;
|
||||
typedef ExprTools = haxe.macro.ExprTools;
|
||||
typedef TypedExprTools = haxe.macro.TypedExprTools;
|
||||
typedef TypedExprs = tink.macro.TypedExprs;
|
||||
typedef Exprs = tink.macro.Exprs;
|
||||
typedef Functions = tink.macro.Functions;
|
||||
typedef Metadatas = tink.macro.Metadatas;
|
||||
@@ -33,12 +31,6 @@ class MacroApi {
|
||||
|
||||
static var MAIN_CANDIDATES = ['-main', '-x', '--run'];
|
||||
static public function getMainClass():Option<String> {
|
||||
#if (haxe_ver >= 4.3)
|
||||
return switch haxe.macro.Compiler.getConfiguration().mainClass {
|
||||
case null: None;
|
||||
case p: Some(p.pack.concat([p.name]).join('.'));
|
||||
}
|
||||
#else
|
||||
var args = Sys.args();
|
||||
|
||||
for (c in MAIN_CANDIDATES)
|
||||
@@ -48,7 +40,6 @@ class MacroApi {
|
||||
}
|
||||
|
||||
return None;
|
||||
#end
|
||||
}
|
||||
|
||||
@:persistent static var idCounter = 0;
|
||||
@@ -61,16 +52,9 @@ class MacroApi {
|
||||
|
||||
static public var completionPoint(default, null):Option<{
|
||||
var file(default, never):String;
|
||||
var content(default, never):Null<String>;
|
||||
var pos(default, never):Int;
|
||||
}>;
|
||||
|
||||
static public function getBuildFields():Option<Array<haxe.macro.Expr.Field>>
|
||||
return switch completionPoint {
|
||||
case Some(v) if (v.content != null && (v.content.charAt(v.pos - 1) == '@' || (v.content.charAt(v.pos - 1) == ':' && v.content.charAt(v.pos - 2) == '@'))): None;
|
||||
default: Some(haxe.macro.Context.getBuildFields());
|
||||
}
|
||||
|
||||
static public var args(default, null):Iterable<String>;
|
||||
static var initialized = initArgs();
|
||||
|
||||
@@ -87,15 +71,12 @@ class MacroApi {
|
||||
params:{
|
||||
file:String,
|
||||
offset:Int,
|
||||
contents:String,
|
||||
}
|
||||
} = haxe.Json.parse(arg);
|
||||
|
||||
switch payload {
|
||||
case { jsonrpc: '2.0', method: 'display/completion' }:
|
||||
Some({
|
||||
file: payload.params.file,
|
||||
content: payload.params.contents,
|
||||
pos: payload.params.offset,
|
||||
});
|
||||
default: None;
|
||||
|
||||
@@ -44,7 +44,6 @@ package tink.macro;
|
||||
else
|
||||
Context.currentPos().error('unknown id ' + id);
|
||||
}
|
||||
static public var lastEvaled(default, null):Dynamic;
|
||||
#else
|
||||
@:noUsing static public function makeOuter<A>(a:A):Bouncer
|
||||
return null;
|
||||
@@ -56,11 +55,6 @@ package tink.macro;
|
||||
default: ethis.reject();
|
||||
}
|
||||
|
||||
@:noUsing static public macro function eval(f:Void->Dynamic) {
|
||||
lastEvaled = f();
|
||||
return macro null;
|
||||
}
|
||||
|
||||
@:noUsing macro static public function catchBounce(id:Int)
|
||||
return doBounce(id);
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ class BuildCache {
|
||||
|
||||
@:persistent static var cache = new Map();
|
||||
|
||||
static public function getType3(name, ?types, ?pos:Position, build:BuildContext3->TypeDefinition, ?normalizer:Type->Type) {
|
||||
static public function getType3(name, ?types, ?pos:Position, build:BuildContext3->TypeDefinition) {
|
||||
if (types == null)
|
||||
switch Context.getLocalType() {
|
||||
case TInst(_.toString() == name => true, [t1, t2, t3]):
|
||||
@@ -55,10 +55,10 @@ class BuildCache {
|
||||
pos: ctx.pos,
|
||||
name: ctx.name,
|
||||
usings: ctx.usings
|
||||
}), normalizer);
|
||||
}));
|
||||
}
|
||||
|
||||
static public function getTypeN(name, ?types, ?pos:Position, build:BuildContextN->TypeDefinition, ?normalizer:Type->Type) {
|
||||
static public function getTypeN(name, ?types, ?pos:Position, build:BuildContextN->TypeDefinition) {
|
||||
|
||||
if (pos == null)
|
||||
pos = Context.currentPos();
|
||||
@@ -86,10 +86,10 @@ class BuildCache {
|
||||
pos: ctx.pos,
|
||||
name: ctx.name,
|
||||
usings: ctx.usings
|
||||
}), normalizer);
|
||||
}));
|
||||
}
|
||||
|
||||
static public function getType2(name, ?types, ?pos:Position, build:BuildContext2->TypeDefinition, ?normalizer:Type->Type) {
|
||||
static public function getType2(name, ?types, ?pos:Position, build:BuildContext2->TypeDefinition) {
|
||||
if (types == null)
|
||||
switch Context.getLocalType() {
|
||||
case TInst(_.toString() == name => true, [t1, t2]):
|
||||
@@ -107,7 +107,7 @@ class BuildCache {
|
||||
pos: ctx.pos,
|
||||
name: ctx.name,
|
||||
usings: ctx.usings
|
||||
}), normalizer);
|
||||
}));
|
||||
}
|
||||
|
||||
static public function getParams(name:String, ?pos:Position)
|
||||
@@ -130,14 +130,14 @@ class BuildCache {
|
||||
default: pos.makeFailure('too many parameters');
|
||||
});
|
||||
|
||||
static public function getType(name, ?type, ?pos:Position, build:BuildContext->TypeDefinition, ?normalizer:Type->Type) {
|
||||
static public function getType(name, ?type, ?pos:Position, build:BuildContext->TypeDefinition) {
|
||||
|
||||
if (type == null)
|
||||
type = getParam(name, pos).sure();
|
||||
|
||||
var forName =
|
||||
switch cache[name] {
|
||||
case null: cache[name] = new Group(name, normalizer);
|
||||
case null: cache[name] = new Group(name);
|
||||
case v: v;
|
||||
}
|
||||
|
||||
@@ -155,11 +155,10 @@ private class Group {
|
||||
|
||||
var name:String;
|
||||
var counter = 0;
|
||||
var entries:TypeMap<Entry>;
|
||||
var entries = new TypeMap<Entry>();
|
||||
|
||||
public function new(name, ?normalizer) {
|
||||
public function new(name) {
|
||||
this.name = name;
|
||||
this.entries = new TypeMap(normalizer);
|
||||
}
|
||||
|
||||
public function get(type:Type, pos:Position, build:BuildContext->TypeDefinition):Type {
|
||||
|
||||
@@ -23,10 +23,7 @@ class ClassBuilder {
|
||||
target = Context.getLocalClass().get();
|
||||
|
||||
if (fields == null)
|
||||
fields = switch MacroApi.getBuildFields() {
|
||||
case None: target.pos.error('Impossible to get builds fields now. Possible cause: https://github.com/HaxeFoundation/haxe/issues/9853');
|
||||
case Some(v): v;
|
||||
}
|
||||
fields = Context.getBuildFields();
|
||||
|
||||
this.initializeFrom = fields;
|
||||
this.target = target;
|
||||
@@ -195,14 +192,10 @@ class ClassBuilder {
|
||||
return m;
|
||||
}
|
||||
|
||||
static public function run(plugins:Array<ClassBuilder->Void>, ?verbose)
|
||||
return switch MacroApi.getBuildFields() {
|
||||
case None: null;
|
||||
case Some(fields):
|
||||
var builder = new ClassBuilder(fields);
|
||||
static public function run(plugins:Array<ClassBuilder->Void>, ?verbose) {
|
||||
var builder = new ClassBuilder();
|
||||
for (p in plugins)
|
||||
p(builder);
|
||||
return builder.export(verbose);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ class Constructor {
|
||||
var afterArgs:Array<FunctionArg>;
|
||||
var pos:Position;
|
||||
var onGenerateHooks:Array<Function->Void>;
|
||||
var superCall:Expr;
|
||||
var superCall:Array<Expr>;
|
||||
var owner:ClassBuilder;
|
||||
var meta:Metadata;
|
||||
public var isPublic:Null<Bool>;
|
||||
@@ -57,12 +57,17 @@ class Constructor {
|
||||
default: oldStatements = [f.expr];
|
||||
}
|
||||
}
|
||||
superCall =
|
||||
if (oldStatements.length == 0) [].toBlock();
|
||||
else switch oldStatements[0] {
|
||||
case macro super($a{_}): oldStatements.shift();
|
||||
default: [].toBlock();
|
||||
|
||||
for (i in 0...oldStatements.length)
|
||||
switch oldStatements[i] {
|
||||
case macro super($a{_}):
|
||||
superCall = oldStatements.splice(0, i + 1);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
if (superCall == null)
|
||||
superCall = [];
|
||||
}
|
||||
|
||||
public function getArgList():Array<FunctionArg>
|
||||
@@ -95,33 +100,10 @@ class Constructor {
|
||||
case Value(e): e;
|
||||
}
|
||||
|
||||
var member = owner.memberByName(name).sure(),
|
||||
initStatement = macro @:pos(pos) this.$name = $e;
|
||||
var tmp = MacroApi.tempName();
|
||||
var member = owner.memberByName(name).sure();
|
||||
|
||||
var bypass = switch options.bypass {
|
||||
case null:
|
||||
switch member.kind {
|
||||
case FProp(_, 'default' | 'null', _):
|
||||
false;
|
||||
#if haxe4
|
||||
case FProp('default', 'never', _):
|
||||
member.isFinal = true;
|
||||
false;
|
||||
case FProp(_, 'set', _):
|
||||
member.addMeta(':isVar');
|
||||
initStatement = macro @:pos(pos) @:bypassAccessor this.$name = $e;
|
||||
false;
|
||||
#end
|
||||
case FProp(_):
|
||||
true;
|
||||
case FFun(_):
|
||||
pos.error('cannot rebind function');
|
||||
default: false;
|
||||
}
|
||||
case v: v;
|
||||
}
|
||||
|
||||
if (bypass && member.kind.match(FProp(_, 'never' | 'set', _, _))) {
|
||||
if (options.bypass && member.kind.match(FProp(_, 'never' | 'set', _, _))) {
|
||||
|
||||
member.addMeta(':isVar');
|
||||
|
||||
@@ -153,14 +135,8 @@ class Constructor {
|
||||
macro @:pos(pos) this.$name = $e;
|
||||
case FVar(AccNo | AccNormal, AccNever):
|
||||
setDirectly(Context.typeExpr(macro @:pos(pos) this.$name));
|
||||
#if haxe4
|
||||
case FVar(AccCall, _):
|
||||
var target = Context.storeTypedExpr(Context.typeExpr(macro @:pos(pos) @:bypassAccessor this.$name));
|
||||
macro @:pos(pos) $target = $e;
|
||||
#else
|
||||
case FVar(AccCall, AccNever):
|
||||
setDirectly(fields['get_$name'].expr());
|
||||
#end
|
||||
case FVar(_, AccCall):
|
||||
setDirectly(fields['set_$name'].expr());
|
||||
default:
|
||||
@@ -170,17 +146,14 @@ class Constructor {
|
||||
}).bounce(), options.prepend);
|
||||
}
|
||||
else
|
||||
addStatement(
|
||||
initStatement,
|
||||
options.prepend
|
||||
);
|
||||
addStatement(macro @:pos(pos) this.$name = $e, options.prepend);
|
||||
}
|
||||
public inline function publish()
|
||||
if (isPublic == null)
|
||||
isPublic = true;
|
||||
|
||||
function toBlock()
|
||||
return [superCall]
|
||||
return superCall
|
||||
.concat(nuStatements)
|
||||
.concat(oldStatements)
|
||||
.toBlock(pos);
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package tink.macro;
|
||||
|
||||
import Type in Inspect;
|
||||
|
||||
import haxe.macro.Context;
|
||||
import haxe.macro.Expr;
|
||||
import haxe.macro.Type;
|
||||
import haxe.PosInfos;
|
||||
import haxe.macro.Printer;
|
||||
import haxe.DynamicAccess as Dict;
|
||||
|
||||
using Lambda;
|
||||
using StringTools;
|
||||
@@ -19,7 +20,6 @@ typedef VarDecl = { name : String, type : ComplexType, expr : Null<Expr> };
|
||||
typedef ParamSubst = {
|
||||
var exists(default, null):String->Bool;
|
||||
var get(default, null):String->ComplexType;
|
||||
function iterator():Iterator<ComplexType>;
|
||||
}
|
||||
|
||||
private class Heureka { public function new() {} }
|
||||
@@ -48,26 +48,20 @@ class Exprs {
|
||||
static public inline function as(e:Expr, c:ComplexType)
|
||||
return ECheckType(e, c).at(e.pos);
|
||||
|
||||
static public function eval(e:Expr):Dynamic {
|
||||
Context.typeof(macro tink.macro.Bouncer.eval(function () return $e));
|
||||
return Bouncer.lastEvaled;
|
||||
}
|
||||
|
||||
static public function finalize(e:Expr, ?nuPos:Position, ?rules:Dict<String>, ?skipFields = false, ?callPos:PosInfos) {
|
||||
static public function finalize(e:Expr, ?nuPos:Position, ?rules:Dynamic<String>, ?skipFields = false, ?callPos:PosInfos) {
|
||||
if (nuPos == null)
|
||||
nuPos = Context.currentPos();
|
||||
if (rules == null)
|
||||
rules = { };
|
||||
|
||||
function replace(s:String):String
|
||||
return switch rules[s] {
|
||||
case null:
|
||||
if (s.startsWith('tmp')) {
|
||||
rules[s] = MacroApi.tempName(s.substr(3));
|
||||
function replace(s:String)
|
||||
return {
|
||||
if (Reflect.hasField(rules, s))
|
||||
Reflect.field(rules, s)
|
||||
else if (s.startsWith('tmp')) {
|
||||
Reflect.setField(rules, s, MacroApi.tempName(s.substr(3)));
|
||||
replace(s);
|
||||
}
|
||||
else s;
|
||||
case v: v;
|
||||
}
|
||||
|
||||
return e.transform(function (e:Expr) {
|
||||
@@ -116,15 +110,16 @@ class Exprs {
|
||||
static public function getPrivate(e:Expr, field:String, ?pos:Position)
|
||||
return macro @:pos(pos.sanitize()) @:privateAccess $e.$field;
|
||||
|
||||
static public function substitute(source:Expr, vars:Dict<Expr>, ?pos)
|
||||
static public function substitute(source:Expr, vars:Dynamic<Expr>, ?pos)
|
||||
return
|
||||
transform(source, function (e:Expr) {
|
||||
return switch e {
|
||||
case macro $i{name}:
|
||||
switch vars[name] {
|
||||
case null: e;
|
||||
case v: v;
|
||||
}
|
||||
return
|
||||
switch (e.getIdent()) {
|
||||
case Success(name):
|
||||
if (Reflect.hasField(vars, name))
|
||||
Reflect.field(vars, name);
|
||||
else
|
||||
e;
|
||||
default: e;
|
||||
}
|
||||
}, pos);
|
||||
@@ -136,68 +131,44 @@ class Exprs {
|
||||
default: e;
|
||||
}
|
||||
|
||||
static public function substParams(source:Expr, subst:ParamSubst, ?pos:Position):Expr {
|
||||
if (!subst.iterator().hasNext())
|
||||
return source;
|
||||
|
||||
function replace(ct:ComplexType)
|
||||
return switch ct {
|
||||
case TPath({ pack: [], name: name }) if (subst.exists(name)):
|
||||
subst.get(name);
|
||||
default: ct;
|
||||
static public function substParams(source:Expr, subst:ParamSubst, ?pos):Expr
|
||||
return crawl(
|
||||
source,
|
||||
function (e)
|
||||
return switch e.expr {
|
||||
case ENew({ pack: [], name: name }, args) if (subst.exists(name)):
|
||||
switch subst.get(name) {
|
||||
case TPath(p):
|
||||
ENew(p, args).at(e.pos);
|
||||
default: e;//TODO: report an error?
|
||||
}
|
||||
|
||||
return source
|
||||
.transform(
|
||||
function (e) return switch e {
|
||||
case macro $i{name} if (subst.exists(name)):
|
||||
case EConst(CIdent(name)) if (subst.exists(name)):
|
||||
switch subst.get(name) {
|
||||
case TPath({ pack: pack, name: name }):
|
||||
pack.concat([name]).drill(e.pos);
|
||||
default: e;//TODO: report an error?
|
||||
}
|
||||
default: e;
|
||||
})
|
||||
.mapTypes(replace);
|
||||
},
|
||||
function (c:ComplexType)
|
||||
return
|
||||
switch (c) {
|
||||
case TPath({ pack: [], name: name }) if (subst.exists(name)):
|
||||
subst.get(name);
|
||||
default: c;
|
||||
}
|
||||
, pos);
|
||||
|
||||
static public function mapTypes(e:Expr, transformer:ComplexType->ComplexType, ?pos:Position) {
|
||||
return e.transform(
|
||||
function (e) return switch e {
|
||||
case { expr: ENew(p, args) }:
|
||||
switch TPath(p).map(transformer) {
|
||||
case TPath(nu):
|
||||
ENew(nu, args).at(e.pos);
|
||||
case v:
|
||||
pos.error(v.toString() + ' cannot be instantiated in ${e.pos}');
|
||||
}
|
||||
case macro cast($v, $ct):
|
||||
ct = ct.map(transformer);
|
||||
(macro @:pos(e.pos) cast($v, $ct));
|
||||
case { expr: ECheckType(v, ct) }: // cannot use reification, because that's `EParentheses(ECheckType)` and macros can (and apparently do) generate a non-wrapped one
|
||||
ECheckType(v, ct.map(transformer)).at(e.pos);
|
||||
case { expr: EVars(vars) }:
|
||||
EVars([for (v in vars) {
|
||||
name: v.name,
|
||||
type: v.type.map(transformer),
|
||||
expr: v.expr,
|
||||
}]).at(e.pos);
|
||||
case { expr: EFunction(kind, f) }:
|
||||
EFunction(kind, Functions.mapSignature(f, transformer)).at(e.pos);
|
||||
default: e;
|
||||
}
|
||||
);
|
||||
}
|
||||
static public function transform(source:Expr, transformer:Expr->Expr, ?pos):Expr
|
||||
return crawl(source, transformer, function (t) return t, pos);
|
||||
|
||||
static public function transform(source:Expr, transformer:Expr->Expr, ?pos):Expr {
|
||||
function apply(e:Expr)
|
||||
return switch e {
|
||||
case null | { expr: null }: e;
|
||||
default: transformer(haxe.macro.ExprTools.map(e, apply));
|
||||
}
|
||||
|
||||
return apply(source);
|
||||
}
|
||||
static function crawlArray(a:Array<Dynamic>, transformer:Expr->Expr, retyper:ComplexType-> ComplexType, pos:Position):Array<Dynamic>
|
||||
return
|
||||
if (a == null) a;
|
||||
else
|
||||
[for (v in a)
|
||||
crawl(v, transformer, retyper, pos)
|
||||
];
|
||||
|
||||
static public function getIterType(target:Expr)
|
||||
return
|
||||
@@ -230,11 +201,10 @@ class Exprs {
|
||||
,ETernary(econd, eif, eelse):
|
||||
EIf(econd, rec(eif), rec(eelse)).at(e.pos);
|
||||
case ESwitch(e, cases, edef):
|
||||
ESwitch(e, [for (c in cases) {
|
||||
expr: rec(c.expr),
|
||||
guard: c.guard,
|
||||
values: c.values,
|
||||
}], rec(edef)).at(e.pos);
|
||||
cases = Reflect.copy(cases);//not exactly pretty, but does the job
|
||||
for (c in cases)
|
||||
c.expr = rec(c.expr);
|
||||
ESwitch(e, cases, rec(edef)).at(e.pos);
|
||||
case EFor(it, expr) if (loops):
|
||||
EFor(it, rec(expr)).at(e.pos);
|
||||
case EWhile(cond, body, normal) if (loops):
|
||||
@@ -249,12 +219,36 @@ class Exprs {
|
||||
}
|
||||
}
|
||||
|
||||
static function crawl(target:Dynamic, transformer:Expr->Expr, retyper:ComplexType->ComplexType, pos:Position):Dynamic
|
||||
return
|
||||
if (Std.is(target, Array))
|
||||
crawlArray(target, transformer, retyper, pos);
|
||||
else
|
||||
switch (Inspect.typeof(target)) {
|
||||
case TNull, TInt, TFloat, TBool, TFunction, TUnknown, TClass(_): target;
|
||||
case TEnum(e):
|
||||
var ret:Dynamic = Inspect.createEnumIndex(e, Inspect.enumIndex(target), crawlArray(Inspect.enumParameters(target), transformer, retyper, pos));
|
||||
if (Inspect.getEnum(ret) == ComplexType)
|
||||
retyper(ret);
|
||||
else
|
||||
ret;
|
||||
case TObject:
|
||||
var ret:Dynamic = { };
|
||||
for (field in Reflect.fields(target))
|
||||
Reflect.setField(ret, field, crawl(Reflect.field(target, field), transformer, retyper, pos));
|
||||
if (Std.is(ret.expr, ExprDef)) {
|
||||
ret = transformer(ret);
|
||||
if (pos != null) ret.pos = pos;
|
||||
}
|
||||
ret;
|
||||
}
|
||||
|
||||
static public inline function iterate(target:Expr, body:Expr, ?loopVar:String = 'i', ?pos:Position)
|
||||
return macro @:pos(pos.sanitize()) for ($i{loopVar} in $target) $body;
|
||||
|
||||
static public function toFields(object:Dict<Expr>, ?pos:Position)
|
||||
return EObjectDecl([for (field in object.keys())
|
||||
{ field:field, expr: object[field] }
|
||||
static public function toFields(object:Dynamic<Expr>, ?pos:Position)
|
||||
return EObjectDecl([for (field in Reflect.fields(object))
|
||||
{ field:field, expr: untyped Reflect.field(object, field) }
|
||||
]).at(pos);
|
||||
|
||||
static public inline function log(e:Expr, ?pos:PosInfos):Expr {
|
||||
@@ -266,7 +260,7 @@ class Exprs {
|
||||
return e.pos.error(reason);
|
||||
|
||||
static public inline function toString(e:Expr):String
|
||||
return new tink.macro.Printer().printExpr(e);
|
||||
return new haxe.macro.Printer().printExpr(e);
|
||||
|
||||
static public inline function at(e:ExprDef, ?pos:Position)
|
||||
return {
|
||||
|
||||
@@ -33,22 +33,6 @@ class Functions {
|
||||
expr: if (makeReturn) EReturn(e).at(e.pos) else e
|
||||
}
|
||||
}
|
||||
|
||||
static public function mapSignature(f:Function, transform):Function
|
||||
return {
|
||||
ret: Types.map(f.ret, transform),
|
||||
args: [for (a in f.args) {
|
||||
name: a.name,
|
||||
value: a.value,
|
||||
type: Types.map(a.type, transform),
|
||||
#if haxe4
|
||||
meta: a.meta,
|
||||
#end
|
||||
}],
|
||||
expr: f.expr,
|
||||
params: Types.mapTypeParamDecls(f.params, transform),
|
||||
}
|
||||
|
||||
static public function getArgIdents(f:Function):Array<Expr> {
|
||||
var ret = [];
|
||||
for (arg in f.args)
|
||||
|
||||
@@ -99,15 +99,6 @@ abstract Member(Field) from Field to Field {
|
||||
if (this.meta == null) [];
|
||||
else [for (tag in this.meta) if (tag.name == name) tag];
|
||||
|
||||
public function hasMeta(name)
|
||||
return switch this.meta {
|
||||
case null | []: false;
|
||||
case meta:
|
||||
for (m in meta)
|
||||
if (m.name == name) return true;
|
||||
false;
|
||||
}
|
||||
|
||||
public inline function asField():Field return this;
|
||||
public function publish()
|
||||
if (this.access == null) this.access = [APublic];
|
||||
|
||||
@@ -1,568 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)2005-2019 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package tink.macro;
|
||||
|
||||
import haxe.macro.Expr;
|
||||
|
||||
using Lambda;
|
||||
using StringTools;
|
||||
|
||||
/**
|
||||
This class provides some utility methods to convert elements from the
|
||||
macro context to a human-readable String representation.
|
||||
*/
|
||||
class Printer {
|
||||
var tabs:String;
|
||||
var tabString:String;
|
||||
|
||||
public function new(?tabString = "\t") {
|
||||
tabs = "";
|
||||
this.tabString = tabString;
|
||||
}
|
||||
|
||||
public function printUnop(op:Unop)
|
||||
return switch (op) {
|
||||
case OpIncrement: "++";
|
||||
case OpDecrement: "--";
|
||||
case OpNot: "!";
|
||||
case OpNeg: "-";
|
||||
case OpNegBits: "~";
|
||||
case OpSpread: "...";
|
||||
}
|
||||
|
||||
public function printBinop(op:Binop)
|
||||
return switch (op) {
|
||||
case OpAdd: "+";
|
||||
case OpMult: "*";
|
||||
case OpDiv: "/";
|
||||
case OpSub: "-";
|
||||
case OpAssign: "=";
|
||||
case OpEq: "==";
|
||||
case OpNotEq: "!=";
|
||||
case OpGt: ">";
|
||||
case OpGte: ">=";
|
||||
case OpLt: "<";
|
||||
case OpLte: "<=";
|
||||
case OpAnd: "&";
|
||||
case OpOr: "|";
|
||||
case OpXor: "^";
|
||||
case OpBoolAnd: "&&";
|
||||
case OpBoolOr: "||";
|
||||
case OpShl: "<<";
|
||||
case OpShr: ">>";
|
||||
case OpUShr: ">>>";
|
||||
case OpMod: "%";
|
||||
case OpInterval: "...";
|
||||
case OpArrow: "=>";
|
||||
case OpIn: "in";
|
||||
case OpNullCoal: "??";
|
||||
case OpAssignOp(op):
|
||||
printBinop(op) + "=";
|
||||
}
|
||||
|
||||
function escapeString(s:String, delim:String) {
|
||||
return delim
|
||||
+ s.replace('\\', '\\\\')
|
||||
.replace("\n", "\\n")
|
||||
.replace("\t", "\\t")
|
||||
.replace("\r", "\\r")
|
||||
.replace("'", "\\'")
|
||||
.replace('"', "\\\"") #if sys .replace("\x00", "\\x00") #end + delim;
|
||||
}
|
||||
|
||||
public function printFormatString(s:String) {
|
||||
return escapeString(s, "'");
|
||||
}
|
||||
|
||||
public function printString(s:String) {
|
||||
return escapeString(s, '"');
|
||||
}
|
||||
|
||||
public function printConstant(c:Constant)
|
||||
return switch (c) {
|
||||
case CString(s, SingleQuotes): printFormatString(s);
|
||||
case CString(s, _): printString(s);
|
||||
case CIdent(s), CInt(s, null), CFloat(s, null):
|
||||
s;
|
||||
case CInt(s, suffix), CFloat(s, suffix):
|
||||
s + suffix;
|
||||
case CRegexp(s, opt): '~/$s/$opt';
|
||||
}
|
||||
|
||||
public function printTypeParam(param:TypeParam)
|
||||
return switch (param) {
|
||||
case TPType(ct): printComplexType(ct);
|
||||
case TPExpr(e): printExpr(e);
|
||||
}
|
||||
|
||||
public function printTypePath(tp:TypePath)
|
||||
return (tp.pack.length > 0 ? tp.pack.join(".") + "." : "")
|
||||
+ tp.name
|
||||
+ (tp.sub != null ? '.${tp.sub}' : "")
|
||||
+ (tp.params == null ? "" : tp.params.length > 0 ? "<" + tp.params.map(printTypeParam).join(", ") + ">" : "");
|
||||
|
||||
// TODO: check if this can cause loops
|
||||
public function printComplexType(ct:ComplexType)
|
||||
return switch (ct) {
|
||||
case TPath(tp): printTypePath(tp);
|
||||
case TFunction(args, ret):
|
||||
var wrapArgumentsInParentheses = switch args {
|
||||
// type `:(a:X) -> Y` has args as [TParent(TNamed(...))], i.e `a:X` gets wrapped in `TParent()`. We don't add parentheses to avoid printing `:((a:X)) -> Y`
|
||||
case [TParent(t)]: false;
|
||||
// this case catches a single argument that's a type-path, so that `X -> Y` prints `X -> Y` not `(X) -> Y`
|
||||
case [TPath(_) | TOptional(TPath(_))]: false;
|
||||
default: true;
|
||||
}
|
||||
var argStr = args.map(printComplexType).join(", ");
|
||||
(wrapArgumentsInParentheses ? '($argStr)' : argStr) + " -> " + (switch ret {
|
||||
// wrap return type in parentheses if it's also a function
|
||||
case TFunction(_): '(${printComplexType(ret)})';
|
||||
default: (printComplexType(ret): String);
|
||||
});
|
||||
case TAnonymous(fields): "{ " + [for (f in fields) printField(f) + "; "].join("") + "}";
|
||||
case TParent(ct): "(" + printComplexType(ct) + ")";
|
||||
case TOptional(ct): "?" + printComplexType(ct);
|
||||
case TNamed(n, ct): n + ":" + printComplexType(ct);
|
||||
case TExtend(tpl, fields):
|
||||
var types = [for (t in tpl) "> " + printTypePath(t) + ", "].join("");
|
||||
var fields = [for (f in fields) printField(f) + "; "].join("");
|
||||
'{${types}${fields}}';
|
||||
case TIntersection(tl): tl.map(printComplexType).join(" & ");
|
||||
}
|
||||
|
||||
public function printMetadata(meta:MetadataEntry)
|
||||
return '@${meta.name}' + ((meta.params != null && meta.params.length > 0) ? '(${printExprs(meta.params, ", ")})' : "");
|
||||
|
||||
public function printAccess(access:Access)
|
||||
return switch (access) {
|
||||
case AStatic: "static";
|
||||
case APublic: "public";
|
||||
case APrivate: "private";
|
||||
case AOverride: "override";
|
||||
case AInline: "inline";
|
||||
case ADynamic: "dynamic";
|
||||
case AMacro: "macro";
|
||||
case AFinal: "final";
|
||||
case AExtern: "extern";
|
||||
case AAbstract: "abstract";
|
||||
case AOverload: "overload";
|
||||
}
|
||||
|
||||
public function printField(field:Field) {
|
||||
inline function orderAccess(access: Array<Access>) {
|
||||
// final should always be printed last
|
||||
// (does not modify input array)
|
||||
return access.has(AFinal) ? access.filter(a -> !a.match(AFinal)).concat([AFinal]) : access;
|
||||
}
|
||||
return (field.doc != null
|
||||
&& field.doc != "" ? "/**\n"
|
||||
+ tabs
|
||||
+ tabString
|
||||
+ StringTools.replace(field.doc, "\n", "\n" + tabs + tabString)
|
||||
+ "\n"
|
||||
+ tabs
|
||||
+ "**/\n"
|
||||
+ tabs : "")
|
||||
+ (field.meta != null && field.meta.length > 0 ? field.meta.map(printMetadata).join('\n$tabs') + '\n$tabs' : "")
|
||||
+ (field.access != null && field.access.length > 0 ? orderAccess(field.access).map(printAccess).join(" ") + " " : "")
|
||||
+ switch (field.kind) {
|
||||
case FVar(t, eo): ((field.access != null && field.access.has(AFinal)) ? '' : 'var ') + '${field.name}' + opt(t, printComplexType, " : ") + opt(eo, printExpr, " = ");
|
||||
case FProp(get, set, t, eo): 'var ${field.name}($get, $set)' + opt(t, printComplexType, " : ") + opt(eo, printExpr, " = ");
|
||||
case FFun(func): 'function ${field.name}' + printFunction(func);
|
||||
}
|
||||
}
|
||||
|
||||
public function printTypeParamDecl(tpd:TypeParamDecl)
|
||||
return (tpd.meta != null && tpd.meta.length > 0 ? tpd.meta.map(printMetadata).join(" ") + " " : "")
|
||||
+ tpd.name
|
||||
+ (tpd.params != null && tpd.params.length > 0 ? "<" + tpd.params.map(printTypeParamDecl).join(", ") + ">" : "")
|
||||
+ (tpd.constraints != null && tpd.constraints.length > 0 ? ":(" + tpd.constraints.map(printComplexType).join(", ") + ")" : "")
|
||||
+ (tpd.defaultType != null ? "=" + printComplexType(tpd.defaultType) : "");
|
||||
|
||||
public function printFunctionArg(arg:FunctionArg)
|
||||
return (arg.opt ? "?" : "") + arg.name + opt(arg.type, printComplexType, ":") + opt(arg.value, printExpr, " = ");
|
||||
|
||||
public function printFunction(func:Function, ?kind:FunctionKind) {
|
||||
var skipParentheses = switch func.args {
|
||||
case [{ type:null }]: kind == FArrow;
|
||||
case _: false;
|
||||
}
|
||||
return (func.params == null ? "" : func.params.length > 0 ? "<" + func.params.map(printTypeParamDecl).join(", ") + ">" : "")
|
||||
+ (skipParentheses ? "" : "(")
|
||||
+ func.args.map(printFunctionArg).join(", ")
|
||||
+ (skipParentheses ? "" : ")")
|
||||
+ (kind == FArrow ? " ->" : "")
|
||||
+ opt(func.ret, printComplexType, ":")
|
||||
+ opt(func.expr, printExpr, " ");
|
||||
}
|
||||
|
||||
public function printVar(v:Var) {
|
||||
var s = v.name + opt(v.type, printComplexType, ":") + opt(v.expr, printExpr, " = ");
|
||||
return switch v.meta {
|
||||
case null|[]: s;
|
||||
case meta: meta.map(printMetadata).join(" ") + " " + s;
|
||||
}
|
||||
}
|
||||
|
||||
public function printObjectFieldKey(of:ObjectField) {
|
||||
return switch (of.quotes) {
|
||||
case null | Unquoted: of.field;
|
||||
case Quoted: '"${of.field}"'; // TODO: Have to escape that?
|
||||
}
|
||||
}
|
||||
|
||||
public function printObjectField(of:ObjectField) {
|
||||
return '${printObjectFieldKey(of)} : ${printExpr(of.expr)}';
|
||||
}
|
||||
|
||||
public function printExpr(e:Expr)
|
||||
return e == null ? "#NULL" : switch (e.expr) {
|
||||
case EConst(c): printConstant(c);
|
||||
case EArray(e1, e2): '${printExpr(e1)}[${printExpr(e2)}]';
|
||||
case EBinop(op, e1, e2): '${printExpr(e1)} ${printBinop(op)} ${printExpr(e2)}';
|
||||
case EField(e1, n, kind): kind == Safe ? '${printExpr(e1)}?.$n' : '${printExpr(e1)}.$n';
|
||||
case EParenthesis(e1): '(${printExpr(e1)})';
|
||||
case EObjectDecl(fl):
|
||||
"{ " + fl.map(function(fld) return printObjectField(fld)).join(", ") + " }";
|
||||
case EArrayDecl(el): '[${printExprs(el, ", ")}]';
|
||||
case ECall(e1, el): '${printExpr(e1)}(${printExprs(el, ", ")})';
|
||||
case ENew(tp, el): 'new ${printTypePath(tp)}(${printExprs(el, ", ")})';
|
||||
case EUnop(op, true, e1): printExpr(e1) + printUnop(op);
|
||||
case EUnop(op, false, e1): printUnop(op) + printExpr(e1);
|
||||
case EFunction(FNamed(no,inlined), func): (inlined ? 'inline ' : '') + 'function $no' + printFunction(func);
|
||||
case EFunction(kind, func): (kind != FArrow ? "function" : "") + printFunction(func, kind);
|
||||
case EVars([]): "var ";
|
||||
case EVars([v]): ((v.isStatic) ? "static " : "") + ((v.isFinal) ? "final " : "var ") + printVar(v);
|
||||
case EVars(vl): [for (v in vl) printExpr({expr: EVars([v]), pos: e.pos})].join("; ");
|
||||
case EBlock([]): '{ }';
|
||||
case EBlock(el):
|
||||
var old = tabs;
|
||||
tabs += tabString;
|
||||
var s = '{\n$tabs' + printExprs(el, ';\n$tabs');
|
||||
tabs = old;
|
||||
s + ';\n$tabs}';
|
||||
case EFor(e1, e2): 'for (${printExpr(e1)}) ${printExpr(e2)}';
|
||||
case EIf(econd, eif, null): 'if (${printExpr(econd)}) ${printExpr(eif)}';
|
||||
case EIf(econd, eif, eelse): 'if (${printExpr(econd)}) ${printExpr(eif)} else ${printExpr(eelse)}';
|
||||
case EWhile(econd, e1, true): 'while (${printExpr(econd)}) ${printExpr(e1)}';
|
||||
case EWhile(econd, e1, false): 'do ${printExpr(e1)} while (${printExpr(econd)})';
|
||||
case ESwitch(e1, cl, edef):
|
||||
var old = tabs;
|
||||
tabs += tabString;
|
||||
var s = 'switch ${printExpr(e1)} {\n$tabs'
|
||||
+ cl.map(function(c) return 'case ${printExprs(c.values, ", ")}' + (c.guard != null ? ' if (${printExpr(c.guard)}):' : ":")
|
||||
+ (c.expr != null ? (opt(c.expr, printExpr)) + ";" : ""))
|
||||
.join('\n$tabs');
|
||||
if (edef != null)
|
||||
s += '\n${tabs}default:' + (edef.expr == null ? "" : printExpr(edef) + ";");
|
||||
tabs = old;
|
||||
s + '\n$tabs}';
|
||||
case ETry(e1, cl):
|
||||
'try ${printExpr(e1)}' + cl.map(function(c) return ' catch(${c.name}${c.type == null ? '' : (':' + printComplexType(c.type))}) ${printExpr(c.expr)}').join("");
|
||||
case EReturn(eo): "return" + opt(eo, printExpr, " ");
|
||||
case EBreak: "break";
|
||||
case EContinue: "continue";
|
||||
case EUntyped(e1): "untyped " + printExpr(e1);
|
||||
case EThrow(e1): "throw " + printExpr(e1);
|
||||
case ECast(e1, cto) if (cto != null): 'cast(${printExpr(e1)}, ${printComplexType(cto)})';
|
||||
case ECast(e1, _): "cast " + printExpr(e1);
|
||||
case EIs(e1, ct): '${printExpr(e1)} is ${printComplexType(ct)}';
|
||||
case EDisplay(e1, _): '#DISPLAY(${printExpr(e1)})';
|
||||
case ETernary(econd, eif, eelse): '${printExpr(econd)} ? ${printExpr(eif)} : ${printExpr(eelse)}';
|
||||
case ECheckType(e1, ct): '(${printExpr(e1)} : ${printComplexType(ct)})';
|
||||
case EMeta({ name:":implicitReturn" }, { expr:EReturn(e1) }): printExpr(e1);
|
||||
case EMeta(meta, e1): printMetadata(meta) + " " + printExpr(e1);
|
||||
}
|
||||
|
||||
public function printExprs(el:Array<Expr>, sep:String) {
|
||||
return el.map(printExpr).join(sep);
|
||||
}
|
||||
|
||||
function printExtension(tpl:Array<TypePath>, fields:Array<Field>) {
|
||||
return '{\n$tabs>'
|
||||
+ tpl.map(printTypePath).join(',\n$tabs>')
|
||||
+ ","
|
||||
+ (fields.length > 0 ? ('\n$tabs' + fields.map(printField).join(';\n$tabs') + ";\n}") : ("\n}"));
|
||||
}
|
||||
|
||||
function printStructure(fields:Array<Field>) {
|
||||
return fields.length == 0 ? "{ }" : '{\n$tabs' + fields.map(printField).join(';\n$tabs') + ";\n}";
|
||||
}
|
||||
|
||||
public function printTypeDefinition(t:TypeDefinition, printPackage = true):String {
|
||||
var old = tabs;
|
||||
tabs = tabString;
|
||||
|
||||
var str = t == null ? "#NULL" : (printPackage && t.pack.length > 0 && t.pack[0] != "" ? "package " + t.pack.join(".") + ";\n" : "")
|
||||
+ (t.doc != null && t.doc != "" ? "/**\n" + tabString + StringTools.replace(t.doc, "\n", "\n" + tabString) + "\n**/\n" : "")
|
||||
+ (t.meta != null && t.meta.length > 0 ? t.meta.map(printMetadata).join(" ") + " " : "")
|
||||
+ (t.isExtern ? "extern " : "")
|
||||
+ switch (t.kind) {
|
||||
case TDEnum:
|
||||
"enum "
|
||||
+ t.name
|
||||
+ ((t.params != null && t.params.length > 0) ? "<" + t.params.map(printTypeParamDecl).join(", ") + ">" : "")
|
||||
+ " {\n"
|
||||
+ [
|
||||
for (field in t.fields)
|
||||
tabs
|
||||
+ (field.doc != null
|
||||
&& field.doc != "" ? "/**\n"
|
||||
+ tabs
|
||||
+ tabString
|
||||
+ StringTools.replace(field.doc, "\n", "\n" + tabs + tabString)
|
||||
+ "\n"
|
||||
+ tabs
|
||||
+ "**/\n"
|
||||
+ tabs : "")
|
||||
+ (field.meta != null && field.meta.length > 0 ? field.meta.map(printMetadata).join(" ") + " " : "")
|
||||
+ (switch (field.kind) {
|
||||
case FVar(t, _): field.name + opt(t, printComplexType, ":");
|
||||
case FProp(_, _, _, _): throw "FProp is invalid for TDEnum.";
|
||||
case FFun(func): field.name + printFunction(func);
|
||||
})
|
||||
+ ";"].join("\n")
|
||||
+ "\n}";
|
||||
case TDStructure:
|
||||
"typedef "
|
||||
+ t.name
|
||||
+ ((t.params != null && t.params.length > 0) ? "<" + t.params.map(printTypeParamDecl).join(", ") + ">" : "")
|
||||
+ " = {\n"
|
||||
+ [
|
||||
for (f in t.fields) {
|
||||
tabs + printField(f) + ";";
|
||||
}
|
||||
].join("\n")
|
||||
+ "\n}";
|
||||
case TDClass(superClass, interfaces, isInterface, isFinal, isAbstract):
|
||||
(isFinal ? "final " : "")
|
||||
+ (isAbstract ? "abstract " : "")
|
||||
+ (isInterface ? "interface " : "class ")
|
||||
+ t.name
|
||||
+ (t.params != null && t.params.length > 0 ? "<" + t.params.map(printTypeParamDecl).join(", ") + ">" : "")
|
||||
+ (superClass != null ? " extends " + printTypePath(superClass) : "")
|
||||
+ (interfaces != null ? (isInterface ? [for (tp in interfaces) " extends " + printTypePath(tp)] : [
|
||||
for (tp in interfaces)
|
||||
" implements " + printTypePath(tp)
|
||||
]).join("") : "")
|
||||
+ " {\n"
|
||||
+ [
|
||||
for (f in t.fields) {
|
||||
tabs + printFieldWithDelimiter(f);
|
||||
}
|
||||
].join("\n")
|
||||
+ "\n}";
|
||||
case TDAlias(ct):
|
||||
"typedef "
|
||||
+ t.name
|
||||
+ ((t.params != null && t.params.length > 0) ? "<" + t.params.map(printTypeParamDecl).join(", ") + ">" : "")
|
||||
+ " = "
|
||||
+ (switch (ct) {
|
||||
case TExtend(tpl, fields): printExtension(tpl, fields);
|
||||
case TAnonymous(fields): printStructure(fields);
|
||||
case _: printComplexType(ct);
|
||||
})
|
||||
+ ";";
|
||||
case TDAbstract(tthis, from, to):
|
||||
"abstract "
|
||||
+ t.name
|
||||
+ ((t.params != null && t.params.length > 0) ? "<" + t.params.map(printTypeParamDecl).join(", ") + ">" : "")
|
||||
+ (tthis == null ? "" : "(" + printComplexType(tthis) + ")")
|
||||
+ (from == null ? "" : [for (f in from) " from " + printComplexType(f)].join(""))
|
||||
+ (to == null ? "" : [for (t in to) " to " + printComplexType(t)].join(""))
|
||||
+ " {\n"
|
||||
+ [
|
||||
for (f in t.fields) {
|
||||
tabs + printFieldWithDelimiter(f);
|
||||
}
|
||||
].join("\n")
|
||||
+ "\n}";
|
||||
case TDField(kind, access):
|
||||
tabs = old;
|
||||
(access != null && access.length > 0 ? access.map(printAccess).join(" ") + " " : "")
|
||||
+ switch (kind) {
|
||||
case FVar(type, eo): ((access != null && access.has(AFinal)) ? '' : 'var ') + '${t.name}' + opt(type, printComplexType, " : ") + opt(eo, printExpr, " = ") + ";";
|
||||
case FProp(get, set, type, eo): 'var ${t.name}($get, $set)' + opt(type, printComplexType, " : ") + opt(eo, printExpr, " = ") + ";";
|
||||
case FFun(func): 'function ${t.name}' + printFunction(func) + switch func.expr { case {expr: EBlock(_)}: ""; case _: ";"; };
|
||||
}
|
||||
} tabs = old;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
function printFieldWithDelimiter(f:Field):String {
|
||||
return printField(f) + switch (f.kind) {
|
||||
case FVar(_, _), FProp(_, _, _, _): ";";
|
||||
case FFun({expr: null}): ";";
|
||||
case FFun({expr: {expr: EBlock(_)}}): "";
|
||||
case FFun(_): ";";
|
||||
case _: "";
|
||||
};
|
||||
}
|
||||
|
||||
function opt<T>(v:T, f:T->String, prefix = "")
|
||||
return v == null ? "" : (prefix + f(v));
|
||||
|
||||
public function printExprWithPositions(e:Expr) {
|
||||
var buffer = new StringBuf();
|
||||
function format4(i:Int) {
|
||||
return StringTools.lpad(Std.string(i), " ", 4);
|
||||
}
|
||||
function loop(tabs:String, e:Expr) {
|
||||
function add(s:String, ?p = null) {
|
||||
if (p == null) {
|
||||
p = e.pos;
|
||||
}
|
||||
var p = #if macro haxe.macro.Context.getPosInfos(p) #else e.pos #end;
|
||||
buffer.add('${format4(p.min)}-${format4(p.max)} $tabs$s\n');
|
||||
}
|
||||
function loopI(e:Expr)
|
||||
loop(tabs + tabString, e);
|
||||
switch (e.expr) {
|
||||
case EConst(c):
|
||||
add(printConstant(c));
|
||||
case EArray(e1, e2):
|
||||
add("EArray");
|
||||
loopI(e1);
|
||||
loopI(e2);
|
||||
case EBinop(op, e1, e2):
|
||||
add("EBinop " + printBinop(op));
|
||||
loopI(e1);
|
||||
loopI(e2);
|
||||
case EField(e, field):
|
||||
add("EField " + field);
|
||||
loopI(e);
|
||||
case EParenthesis(e):
|
||||
add("EParenthesis");
|
||||
loopI(e);
|
||||
case EObjectDecl(fields):
|
||||
add("EObjectDecl");
|
||||
for (field in fields) {
|
||||
add(field.field); // TODO: we don't have the field pos?
|
||||
loopI(field.expr);
|
||||
}
|
||||
case EArrayDecl(values):
|
||||
add("EArrayDecl");
|
||||
values.iter(loopI);
|
||||
case ECall(e, params):
|
||||
add("ECall");
|
||||
loopI(e);
|
||||
params.iter(loopI);
|
||||
case ENew(tp, params):
|
||||
add("ENew " + printTypePath(tp));
|
||||
params.iter(loopI);
|
||||
case EUnop(op, postFix, e):
|
||||
add("EUnop " + printUnop(op));
|
||||
loopI(e);
|
||||
case EVars(vars):
|
||||
add("EVars");
|
||||
for (v in vars) {
|
||||
if (v.expr != null) {
|
||||
add(v.name);
|
||||
loopI(v.expr);
|
||||
}
|
||||
}
|
||||
case EFunction(_, f):
|
||||
add("EFunction");
|
||||
if (f.expr != null) {
|
||||
loopI(f.expr);
|
||||
}
|
||||
case EBlock(exprs):
|
||||
add("EBlock");
|
||||
exprs.iter(loopI);
|
||||
case EFor(it, expr):
|
||||
add("EFor");
|
||||
loopI(it);
|
||||
loopI(expr);
|
||||
case EIf(econd, eif, eelse):
|
||||
add("EIf");
|
||||
loopI(econd);
|
||||
loopI(eif);
|
||||
if (eelse != null) {
|
||||
loopI(eelse);
|
||||
}
|
||||
case EWhile(econd, e, normalWhile):
|
||||
add("EWhile");
|
||||
loopI(econd);
|
||||
loopI(e);
|
||||
case ESwitch(e, cases, edef):
|
||||
add("ESwitch");
|
||||
loopI(e);
|
||||
for (c in cases) {
|
||||
for (pat in c.values) {
|
||||
loop(tabs + tabString + tabString, pat);
|
||||
}
|
||||
if (c.expr != null) {
|
||||
loop(tabs + tabString + tabString + tabString, c.expr);
|
||||
}
|
||||
}
|
||||
if (edef != null) {
|
||||
loop(tabs + tabString + tabString + tabString, edef);
|
||||
}
|
||||
case ETry(e, catches):
|
||||
add("ETry");
|
||||
loopI(e);
|
||||
for (c in catches) {
|
||||
loop(tabs + tabString + tabString, c.expr);
|
||||
}
|
||||
case EReturn(e):
|
||||
add("EReturn");
|
||||
if (e != null) {
|
||||
loopI(e);
|
||||
}
|
||||
case EBreak:
|
||||
add("EBreak");
|
||||
case EContinue:
|
||||
add("EContinue");
|
||||
case EUntyped(e):
|
||||
add("EUntyped");
|
||||
loopI(e);
|
||||
case EThrow(e):
|
||||
add("EThrow");
|
||||
loopI(e);
|
||||
case ECast(e, t):
|
||||
add("ECast");
|
||||
loopI(e);
|
||||
case EIs(e, t):
|
||||
add("EIs");
|
||||
loopI(e);
|
||||
case EDisplay(e, displayKind):
|
||||
add("EDisplay");
|
||||
loopI(e);
|
||||
case ETernary(econd, eif, eelse):
|
||||
add("ETernary");
|
||||
loopI(econd);
|
||||
loopI(eif);
|
||||
loopI(eelse);
|
||||
case ECheckType(e, t):
|
||||
add("ECheckType");
|
||||
loopI(e);
|
||||
case EMeta(s, e):
|
||||
add("EMeta " + printMetadata(s));
|
||||
loopI(e);
|
||||
}
|
||||
}
|
||||
loop("", e);
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,6 @@ package tink.macro;
|
||||
|
||||
import haxe.macro.Expr;
|
||||
import haxe.macro.Type;
|
||||
using haxe.macro.Tools;
|
||||
using tink.MacroApi;
|
||||
|
||||
class Sisyphus {
|
||||
|
||||
@@ -63,7 +61,8 @@ class Sisyphus {
|
||||
}
|
||||
}
|
||||
|
||||
static public 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) {
|
||||
@@ -96,12 +95,8 @@ class Sisyphus {
|
||||
TPath(toTypePath(baseType, params));
|
||||
case TFun(args, ret):
|
||||
TFunction(
|
||||
[for (a in args) {
|
||||
var t = #if haxe4 TNamed(a.name, #else ( #end toComplexType(a.t));
|
||||
if (a.opt) TOptional(t) else t;
|
||||
}],
|
||||
toComplexType(ret)
|
||||
);
|
||||
[ for (a in args) a.opt ? nullable(toComplexType(a.t)) : toComplexType(a.t) ],
|
||||
toComplexType(ret));
|
||||
case TAnonymous(_.get() => { fields: fields }):
|
||||
TAnonymous([ for (cf in fields) toField(cf) ]);
|
||||
case TDynamic(t):
|
||||
@@ -137,89 +132,4 @@ class Sisyphus {
|
||||
}],
|
||||
}
|
||||
}
|
||||
|
||||
static function exactBase<T:BaseType>(r:Ref<T>, params:Array<Type>) {
|
||||
var t = r.get();
|
||||
var isMain = !t.isPrivate && switch t.pack {
|
||||
case []: t.module == t.name || t.module == 'StdTypes';
|
||||
default: StringTools.endsWith(t.module, '.${t.name}');
|
||||
}
|
||||
|
||||
return (
|
||||
if (isMain) t.pack.concat([t.name]).join('.')
|
||||
else t.module + '.' + t.name
|
||||
) + switch params {
|
||||
case []: '';
|
||||
case params:
|
||||
'<${params.map(toExactString).join(', ')}>';
|
||||
}
|
||||
}
|
||||
|
||||
static inline function isFinal(c:ClassField)
|
||||
return #if haxe4 c.isFinal #else false #end;
|
||||
|
||||
static function exactAnonField(c:ClassField) {
|
||||
var kw =
|
||||
switch c.kind {
|
||||
case FMethod(_): 'function';
|
||||
case FVar(_):
|
||||
if (isFinal(c)) 'final' else 'var';
|
||||
}
|
||||
|
||||
return [for (m in c.meta.get()) m.toString() + ' '].join('') + '$kw ${c.name}' + (switch c.kind {
|
||||
case FVar(read, write):
|
||||
(
|
||||
if (isFinal(c) || (read == AccNormal && write == AccNormal)) ''
|
||||
else '(${read.accessToName()}, ${read.accessToName(false)})'
|
||||
) + ':' + c.type.toExactString();
|
||||
case FMethod(_):
|
||||
switch haxe.macro.Context.follow(c.type) {
|
||||
case TFun(arg, ret): exactSig(arg, ret, ':');
|
||||
default: throw 'assert';
|
||||
}
|
||||
}) + ';';
|
||||
}
|
||||
|
||||
static function exactSig(args:Array<{name:String, opt:Bool, t:Type}>, ret:Type, sep:String)
|
||||
return '(${[for (a in args) (if (a.opt) '?' else '') + a.name + ':' + toExactString(a.t)].join(', ')})$sep${toExactString(ret)}';
|
||||
|
||||
static public function toExactString(t:Type)
|
||||
return switch t {
|
||||
case TMono(t): t.toString();
|
||||
case TEnum(r, params): exactBase(r, params);
|
||||
case TInst(r, params): exactBase(r, params);
|
||||
case TType(r, params): exactBase(r, params);
|
||||
case TAbstract(r, params): exactBase(r, params);
|
||||
case TFun(args, ret): exactSig(args, ret, '->');
|
||||
case TAnonymous(a): '{ ${[for (f in a.get().fields) exactAnonField(f)].join(' ')} }';
|
||||
case TDynamic(null): 'Dynamic';
|
||||
case TDynamic(t): 'Dynamic<${toExactString(t)}>';
|
||||
case TLazy(f): toExactString(f());
|
||||
}
|
||||
|
||||
static function eager(t:Type)
|
||||
return switch t {
|
||||
case TLazy(f): eager(f());
|
||||
default: t;
|
||||
}
|
||||
|
||||
static public function compare(t1:Type, t2:Type, ?follow:Bool = true) {
|
||||
if (follow) {
|
||||
t1 = t1.reduce();
|
||||
t2 = t2.reduce();
|
||||
}
|
||||
else {
|
||||
t1 = eager(t1);
|
||||
t2 = eager(t2);
|
||||
}
|
||||
|
||||
return switch t1.getIndex() - t2.getIndex() {
|
||||
case 0:
|
||||
switch Reflect.compare(t1.toString(), t2.toString()) {
|
||||
case 0: Reflect.compare(t1.toExactString(), t2.toExactString());
|
||||
case v: v;
|
||||
}
|
||||
case v: v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,33 +8,14 @@ import haxe.macro.Type;
|
||||
using tink.MacroApi;
|
||||
|
||||
class TypeMap<V> extends BalancedTree<Type, V> implements IMap<Type, V> {
|
||||
var normalize:Type->Type;
|
||||
var follow:Bool;
|
||||
|
||||
public function new(?normalize:Type->Type) {
|
||||
this.normalize = switch normalize {
|
||||
case null: function (t) return t.reduce();
|
||||
case fn: fn;
|
||||
}
|
||||
public function new(?noFollow:Bool) {
|
||||
this.follow = noFollow != true;
|
||||
super();
|
||||
}
|
||||
|
||||
override function compare(k1:Type, k2:Type):Int
|
||||
return normalize(k1).compare(normalize(k2), false);
|
||||
|
||||
static public function noFollow(t:Type)
|
||||
return t;
|
||||
|
||||
static public function keepNull(t:Type):Type
|
||||
return switch t {
|
||||
case TAbstract(_.get() => { name: 'Null', pack: [] }, [t])
|
||||
#if !haxe4 | TType(_.get() => { name: 'Null', pack: []}, [t]) #end
|
||||
:
|
||||
var ct = keepNull(t).toComplex({ direct: true });
|
||||
(macro : Null<$ct>).toType().sure();
|
||||
|
||||
case TLazy(f): keepNull(f());
|
||||
case TType(_, _): keepNull(Context.follow(t, true));
|
||||
default: t;
|
||||
}
|
||||
return k1.compare(k2, follow);
|
||||
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package tink.macro;
|
||||
|
||||
import haxe.macro.Context;
|
||||
import haxe.macro.Type;
|
||||
import haxe.ds.Option;
|
||||
using haxe.macro.Tools;
|
||||
|
||||
class TypedExprs {
|
||||
|
||||
static public function extractAll<T>(t:TypedExpr, f:TypedExpr->Option<T>):Array<T> {
|
||||
var out = [];
|
||||
function rec(t:TypedExpr)
|
||||
if (t != null) {
|
||||
switch f(t) {
|
||||
case Some(v): out.push(v);
|
||||
default:
|
||||
}
|
||||
t.iter(rec);
|
||||
}
|
||||
rec(t);
|
||||
return out;
|
||||
}
|
||||
|
||||
static public function extract<T>(t:TypedExpr, f:TypedExpr->Option<T>):Option<T> {
|
||||
try extractAll(t, function (t) {
|
||||
var ret = f(t);
|
||||
if (ret != None)
|
||||
throw ret;
|
||||
return ret;
|
||||
})
|
||||
catch (e:Option<Dynamic>) return cast e;
|
||||
return None;
|
||||
}
|
||||
|
||||
static public function eval(t:TypedExpr)
|
||||
return Exprs.eval(Context.storeTypedExpr(t));
|
||||
|
||||
static public function isThis(t:TypedExpr):Bool
|
||||
return switch t {
|
||||
case null: false;
|
||||
case { expr: TConst(TThis) | TLocal({ name: '`this' })}: true;
|
||||
default: false;
|
||||
}
|
||||
|
||||
static public inline function hasThis(t)
|
||||
return contains(t, isThis);
|
||||
|
||||
static public function findAll(t:TypedExpr, f:TypedExpr->Bool):Array<TypedExpr>
|
||||
return extractAll(t, collect(f));
|
||||
|
||||
static public function find(t:TypedExpr, f:TypedExpr->Bool):Option<TypedExpr>
|
||||
return extract(t, collect(f));
|
||||
|
||||
static public function contains(t:TypedExpr, f:TypedExpr->Bool):Bool
|
||||
return find(t, f) != None;
|
||||
|
||||
static inline function collect(f)
|
||||
return function (t) return if (f(t)) Some(t) else None;
|
||||
}
|
||||
@@ -10,8 +10,6 @@ using haxe.macro.Tools;
|
||||
using tink.MacroApi;
|
||||
using tink.CoreApi;
|
||||
|
||||
import haxe.macro.Type.Ref;
|
||||
|
||||
class Types {
|
||||
|
||||
static public function definedType(typeName:String)
|
||||
@@ -41,10 +39,9 @@ class Types {
|
||||
static public function accessToName(v:VarAccess, ?read = true)
|
||||
return
|
||||
switch (v) {
|
||||
case AccNormal: 'default';
|
||||
case AccInline: if (read) 'default' else 'never';
|
||||
case AccNormal, AccInline: 'default';
|
||||
case AccNo: 'null';
|
||||
case AccNever #if haxe4 | AccCtor #end: 'never';
|
||||
case AccNever: 'never';
|
||||
case AccCall: if (read) 'get' else 'set';
|
||||
default:
|
||||
throw 'not implemented';
|
||||
@@ -73,79 +70,6 @@ class Types {
|
||||
getDeclaredFields(t.superClass.t.get(), out, marker);
|
||||
}
|
||||
|
||||
static public function mapTypeParams(a:Array<TypeParam>, f)
|
||||
return
|
||||
if (a == null) null;
|
||||
else [for (p in a) switch p {
|
||||
case TPType(t): TPType(t.map(f));
|
||||
default: p;
|
||||
}];
|
||||
|
||||
static public function mapTypeParamDecls(a:Array<TypeParamDecl>, f:ComplexType->ComplexType):Array<TypeParamDecl>
|
||||
return
|
||||
if (a == null) null;
|
||||
else [for (p in a) {
|
||||
name: p.name,
|
||||
meta: p.meta,
|
||||
params: mapTypeParamDecls(p.params, f),
|
||||
constraints: switch p.constraints {
|
||||
case null: null;
|
||||
case a: [for (t in a) map(t, f)];
|
||||
}
|
||||
}];
|
||||
|
||||
static public function mapTypePath(p:TypePath, transform):TypePath
|
||||
return {
|
||||
name: p.name,
|
||||
pack: p.pack,
|
||||
sub: p.sub,
|
||||
params: mapTypeParams(p.params, transform),
|
||||
}
|
||||
|
||||
static public function map(ct:ComplexType, transform:ComplexType->ComplexType) {
|
||||
if (ct == null)
|
||||
return null;
|
||||
inline function rec(ct)
|
||||
return map(transform(ct), transform);
|
||||
|
||||
function mapFields(fields:Array<Field>):Array<Field>
|
||||
return [for (f in fields) {
|
||||
name: f.name,
|
||||
pos: f.pos,
|
||||
kind: switch f.kind {
|
||||
case FVar(t, e): FVar(rec(t), e);
|
||||
case FProp(get, set, t, e): FProp(get, set, rec(t), e);
|
||||
case FFun(f): FFun(Functions.mapSignature(f, transform));
|
||||
},
|
||||
access: f.access,
|
||||
meta: switch f.meta {
|
||||
case null: null;
|
||||
case a: [for (m in a) {
|
||||
name: m.name,
|
||||
pos: m.pos,
|
||||
params: [for (e in m.params) e.mapTypes(transform)],
|
||||
}];
|
||||
},
|
||||
doc: f.doc,
|
||||
}];
|
||||
return transform(switch ct {
|
||||
case TParent(t): TParent(rec(t));
|
||||
#if haxe4
|
||||
case TNamed(n, t): TNamed(n, rec(t));
|
||||
case TIntersection(tl): TIntersection([for (t in tl) rec(t)]);
|
||||
#end
|
||||
case TOptional(t): TOptional(rec(t));
|
||||
case TAnonymous(fields):
|
||||
TAnonymous(mapFields(fields));
|
||||
case TPath(p):
|
||||
TPath(mapTypePath(p, transform));
|
||||
case TExtend(paths, fields):
|
||||
TExtend([for (p in paths) mapTypePath(p, transform)], mapFields(fields));
|
||||
case TFunction(args, ret):
|
||||
TFunction([for (a in args) rec(a)], rec(ret));
|
||||
});
|
||||
}
|
||||
|
||||
static var fieldsCache = new Map();
|
||||
static public function getFields(t:Type, ?substituteParams = true)
|
||||
return
|
||||
@@ -160,31 +84,12 @@ class Types {
|
||||
}
|
||||
var ret = fieldsCache.get(id);
|
||||
if (substituteParams && ret.isSuccess()) {
|
||||
ret = Success([
|
||||
for (field in ret.sure()) ({
|
||||
name: field.name,
|
||||
type: haxe.macro.TypeTools.applyTypeParameters(field.type, c.params, params),
|
||||
pos: field.pos,
|
||||
meta: field.meta,
|
||||
doc: field.doc,
|
||||
expr: function () return field.expr(),
|
||||
isPublic: field.isPublic,
|
||||
params: field.params,
|
||||
kind: field.kind,
|
||||
overloads: field.overloads,
|
||||
#if haxe4
|
||||
isExtern: field.isExtern,
|
||||
isFinal: field.isFinal,
|
||||
#if (haxe >= version("4.2.0-rc.1"))
|
||||
isAbstract: field.isAbstract,
|
||||
#end
|
||||
#end
|
||||
}:ClassField)
|
||||
]);
|
||||
var fields = Reflect.copy(ret.sure());
|
||||
|
||||
for (field in fields)
|
||||
field.type = haxe.macro.TypeTools.applyTypeParameters(field.type, c.params, params);
|
||||
}
|
||||
#if !haxe4
|
||||
fieldsCache.remove(id);//TODO: find a proper solution to avoid stale cache
|
||||
#end
|
||||
ret;
|
||||
case TAnonymous(anon): Success(anon.get().fields);
|
||||
default: Context.currentPos().makeFailure('type $t has no fields');
|
||||
@@ -211,22 +116,7 @@ class Types {
|
||||
default: Failure('type "$t" has no position');
|
||||
}
|
||||
|
||||
static public function deduceCommonType(types:Array<Type>):Outcome<Type, Error> {
|
||||
var exprs = types.map(function(t) {
|
||||
var ct = t.toComplex();
|
||||
return macro (cast null:$ct);
|
||||
});
|
||||
|
||||
return switch (macro $a{exprs}).typeof() {
|
||||
case Success(TInst(_, [v])): Success(v);
|
||||
case Success(_): throw 'unreachable';
|
||||
case Failure(e): Failure(new Error('Unable to deduce common type among $types'));
|
||||
}
|
||||
}
|
||||
|
||||
/// like haxe.macro.TypeTools.toString, but not lossy
|
||||
static public function toExactString(t:Type)
|
||||
return Sisyphus.toExactString(t);
|
||||
|
||||
static public function toString(t:ComplexType)
|
||||
return new Printer().printComplexType(t);
|
||||
@@ -279,7 +169,8 @@ class Types {
|
||||
return if (once) t else reduce(t, false);
|
||||
return switch type {
|
||||
case TAbstract(_.get() => { name: 'Null', pack: [] }, [t]): rec(t);
|
||||
case TLazy(_) | TType(_): rec(Context.follow(type, once));
|
||||
case TLazy(f): rec(f());
|
||||
case TType(_, _): rec(Context.follow(type, once));
|
||||
default: type;
|
||||
}
|
||||
}
|
||||
@@ -314,9 +205,6 @@ class Types {
|
||||
|
||||
if (types.length == 1) return Success(types[1]);
|
||||
|
||||
#if haxe4
|
||||
return Success(TIntersection(types));
|
||||
#end
|
||||
var paths = [],
|
||||
fields = [];
|
||||
|
||||
@@ -358,8 +246,18 @@ class Types {
|
||||
throw 'assert';
|
||||
}
|
||||
|
||||
static public function compare(t1:Type, t2:Type, ?follow:Bool = true)
|
||||
return Sisyphus.compare(t1, t2, follow);
|
||||
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?: .*\)$/;
|
||||
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
-cp tests
|
||||
-lib hx3compat
|
||||
-main Run
|
||||
@@ -29,8 +29,6 @@ abstract PhysicalType<T>(Either<Class<T>, Enum<T>>) {
|
||||
}
|
||||
//TODO: this helper should go somewhere
|
||||
class Base extends TestCase {
|
||||
function stringCompare<A>(v1:A, v2:A, ?pos)
|
||||
assertEquals(Std.string(v1), Std.string(v2), pos);
|
||||
|
||||
function fail(msg:String, ?c : PosInfos) {
|
||||
currentTest.done = true;
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
class Dummy {
|
||||
public function new() {}
|
||||
static public var p(default, never) = new Private();
|
||||
}
|
||||
|
||||
private class Private {
|
||||
public function new() {}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import haxe.macro.Context.typeof;
|
||||
using tink.MacroApi;
|
||||
|
||||
class ExactStrings extends Base {
|
||||
function test() {
|
||||
function expect(s:String, e, ?pos)
|
||||
assertEquals(s, typeof(e).toExactString(), pos);
|
||||
|
||||
expect('Dummy', macro new Dummy());
|
||||
expect('nested.Dummy', macro new nested.Dummy());
|
||||
expect('Dummy.Private', macro Dummy.p);
|
||||
expect('nested.Dummy.Private', macro nested.Dummy.p);
|
||||
expect('{ @foo var x:Int; }', macro (null:{@foo var x:Int;}));
|
||||
expect('{ @foo @bar var x:Int; }', macro (null:{@foo @bar var x:Int;}));
|
||||
expect('{ @bar @foo var x:Int; }', macro (null:{@bar @foo var x:Int;}));// not 100% sure this is always the best choice, but let's roll with it
|
||||
expect('{ @bar var x:Int; }', macro (null:{@bar var x:Int;}));
|
||||
expect('{ var x:Int; var y:Int; }', macro (null:{x:Int,y:Int}));
|
||||
expect('{ var x:Int; var y:Int; }', macro (null:{y:Int,x:Int}));
|
||||
expect('{ function foo(x:Int, ?y:Int):Void; }', macro (null:{ function foo(x:Int, ?y:Int):Void; }));
|
||||
}
|
||||
}
|
||||
@@ -16,15 +16,6 @@ class Exprs extends Base {
|
||||
assertTrue(id.length <= 3);
|
||||
}
|
||||
}
|
||||
|
||||
function testEval() {
|
||||
var expr = macro (untyped {foo:[{bar:234},'bar']});
|
||||
var str = Std.string(untyped {foo:[{bar:234},'bar']});
|
||||
assertEquals(Std.string(expr.eval()), Std.string(untyped {foo:[{bar:234},'bar']}));
|
||||
|
||||
// This doesn't work in Haxe 4.3, which is correct, because typeExpr types an expression into target context, rather than macro context
|
||||
// assertEquals(Std.string(Context.typeExpr(expr).eval()), Std.string(untyped {foo:[{bar:234},'bar']}));
|
||||
}
|
||||
function testGet() {
|
||||
assertEquals('foo', (macro foo).getIdent().sure());
|
||||
assertEquals('foo', (macro "foo").getString().sure());
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
typedef MyString = String;
|
||||
@@ -6,6 +6,8 @@ import haxe.macro.Expr;
|
||||
using tink.MacroApi;
|
||||
|
||||
class Positions extends Base {
|
||||
function stringCompare<A>(v1:A, v2:A)
|
||||
assertEquals(Std.string(v1), Std.string(v2));
|
||||
|
||||
function testSanitize() {
|
||||
var p:Position = null;
|
||||
@@ -17,6 +19,6 @@ class Positions extends Base {
|
||||
function testBlank() {
|
||||
var p:Position = null;
|
||||
var t = p.makeBlankType();
|
||||
stringCompare('TMono(<mono>)', cast t.toType().sure().reduce());
|
||||
stringCompare('TMono(<mono>)', cast t.toType().sure());
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,6 @@
|
||||
package ;
|
||||
|
||||
import haxe.unit.*;
|
||||
#if macro
|
||||
using haxe.macro.Tools;
|
||||
#end
|
||||
|
||||
class Run {
|
||||
#if !macro
|
||||
@@ -17,13 +14,11 @@ class Run {
|
||||
new TypeMapTest(),
|
||||
new Functions(),
|
||||
new Misc(),
|
||||
new ExactStrings(),
|
||||
];
|
||||
#end
|
||||
macro static function test() {
|
||||
var runner = new TestRunner();
|
||||
tink.macro.ClassBuilder;
|
||||
tink.macro.BuildCache;
|
||||
for (c in cases)
|
||||
runner.add(c);
|
||||
runner.run();
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
package;
|
||||
|
||||
import haxe.unit.TestCase;
|
||||
import haxe.macro.Expr;
|
||||
|
||||
using tink.MacroApi;
|
||||
import tink.macro.TypeMap;
|
||||
using haxe.macro.Context;
|
||||
|
||||
class TypeMapTest extends TestCase {
|
||||
|
||||
function testMap() {
|
||||
var t = new TypeMap();
|
||||
var t1 = (macro [{ foo: [{ bar: '5' }]}]).typeof().sure();
|
||||
var t2 = (macro [{ foo: [{ bar: 5 }]}]).typeof().sure();
|
||||
var t3 = (macro [{ foo: [{ bar: 5 }]}]).typeof().sure();
|
||||
var t4 = (macro [{ foo: [({ bar: 5 }:{ @foo var bar:Int; })]}]).typeof().sure();
|
||||
var t1 = (macro [{ foo: [{ bar: '5' }]}]).typeof();
|
||||
var t2 = (macro [{ foo: [{ bar: 5 }]}]).typeof();
|
||||
|
||||
t.set(t1, 0);
|
||||
assertEquals(Lambda.count(t), 1);
|
||||
@@ -21,10 +19,7 @@ class TypeMapTest extends TestCase {
|
||||
t.set(t1, 2);
|
||||
assertEquals(Lambda.count(t), 2);
|
||||
t.set(t2, 3);
|
||||
t.set(t3, 3);
|
||||
assertEquals(Lambda.count(t), 2);
|
||||
t.set(t4, 4);
|
||||
assertEquals(Lambda.count(t), 3);
|
||||
|
||||
assertEquals(t.get(t1), 2);
|
||||
assertEquals(t.get(t2), 3);
|
||||
@@ -32,22 +27,4 @@ class TypeMapTest extends TestCase {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
function testNormalization() {
|
||||
for (settings in [
|
||||
{ count: 4, map: new TypeMap(TypeMap.noFollow)},
|
||||
{ count: 2, map: new TypeMap(TypeMap.keepNull)},
|
||||
{ count: 1, map: new TypeMap()},
|
||||
]) {
|
||||
|
||||
function set(ct:ComplexType)
|
||||
settings.map.set(ct.toType().sure(), ct);
|
||||
|
||||
set(macro : String);
|
||||
set(macro : MyString);
|
||||
set(macro : Null<String>);
|
||||
set(macro : Null<MyString>);
|
||||
|
||||
assertEquals(settings.count, Lambda.count(settings.map));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ class Types extends Base {
|
||||
assertFalse(o.isSuccess());
|
||||
|
||||
function testIs() {
|
||||
|
||||
assertSuccess(resolve('Int').isSubTypeOf(resolve('Float')));
|
||||
assertFailure(resolve('Float').isSubTypeOf(resolve('Int')));
|
||||
}
|
||||
@@ -64,20 +65,5 @@ class Types extends Base {
|
||||
assertEquals('String', Context.getType('String').toComplex().toString());
|
||||
assertEquals('tink.CoreApi.Noise', Context.getType('tink.CoreApi.Noise').toComplex().toString());
|
||||
}
|
||||
|
||||
function testDeduceCommonType() {
|
||||
function ct2t(ct:ComplexType) return ct.toType().sure();
|
||||
assertEquals('StdTypes.Float', tink.macro.Types.deduceCommonType([(macro:Float), (macro:Int)].map(ct2t)).sure().toComplex().toString());
|
||||
assertEquals('Types.CommonI1', tink.macro.Types.deduceCommonType([(macro:Types.CommonA), (macro:Types.CommonB), (macro:Types.CommonC)].map(ct2t)).sure().toComplex().toString());
|
||||
assertEquals('Types.CommonI2', tink.macro.Types.deduceCommonType([(macro:Types.CommonB), (macro:Types.CommonC)].map(ct2t)).sure().toComplex().toString());
|
||||
// assertEquals('Types.CommonI3', tink.macro.Types.deduceCommonType([(macro:Types.CommonC)].map(ct2t)).sure().toComplex().toString());
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
interface CommonI1 {}
|
||||
interface CommonI2 {}
|
||||
interface CommonI3 {}
|
||||
class CommonA implements CommonI1 {}
|
||||
class CommonB implements CommonI2 implements CommonI1 {}
|
||||
class CommonC implements CommonI3 implements CommonI2 implements CommonI1 {}
|
||||
@@ -1,10 +0,0 @@
|
||||
package nested;
|
||||
|
||||
class Dummy {
|
||||
public function new() {}
|
||||
static public var p(default, never) = new Private();
|
||||
}
|
||||
|
||||
private class Private {
|
||||
public function new() {}
|
||||
}
|
||||
Reference in New Issue
Block a user