jass 0.9.1 → 0.9.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/jass.rb +5 -0
- data/lib/jass/compiler.rb +5 -0
- data/lib/jass/plugin.rb +2 -1
- data/lib/jass/version.rb +1 -1
- data/vendor/node_modules/@types/estree/index.d.ts +4 -2
- data/vendor/node_modules/@types/estree/package.json +2 -2
- data/vendor/node_modules/acorn/bin/_acorn.js +12 -12
- data/vendor/node_modules/acorn/bin/run_test262.js +2 -3
- data/vendor/node_modules/acorn/bin/test262.whitelist +0 -5
- data/vendor/node_modules/acorn/dist/acorn.es.js +76 -68
- data/vendor/node_modules/acorn/dist/acorn.js +76 -68
- data/vendor/node_modules/acorn/dist/acorn_loose.es.js +42 -30
- data/vendor/node_modules/acorn/dist/acorn_loose.js +42 -30
- data/vendor/node_modules/acorn/dist/walk.es.js +47 -43
- data/vendor/node_modules/acorn/dist/walk.js +47 -43
- data/vendor/node_modules/acorn/package.json +9 -5
- data/vendor/node_modules/chalk/index.js.flow +93 -0
- data/vendor/node_modules/chalk/package.json +8 -3
- data/vendor/node_modules/color-convert/conversions.js +36 -29
- data/vendor/node_modules/color-convert/package.json +4 -4
- data/vendor/node_modules/estree-walker/index.d.ts +17 -0
- data/vendor/node_modules/estree-walker/package.json +2 -1
- data/vendor/node_modules/fill-range/index.js +2 -2
- data/vendor/node_modules/fill-range/package.json +24 -7
- data/vendor/node_modules/is-reference/node_modules/@types/estree/index.d.ts +546 -0
- data/vendor/node_modules/is-reference/node_modules/@types/estree/package.json +22 -0
- data/vendor/node_modules/math-random/browser.js +17 -0
- data/vendor/node_modules/math-random/node.js +13 -0
- data/vendor/node_modules/math-random/package.json +31 -0
- data/vendor/node_modules/math-random/test.js +26 -0
- data/vendor/node_modules/nodent-compiler/compiler.js +115 -11
- data/vendor/node_modules/nodent-compiler/{lib/output.js → output.js} +0 -0
- data/vendor/node_modules/nodent-compiler/package.json +8 -4
- data/vendor/node_modules/{nodent-compiler/lib → nodent-transform}/arboriculture.js +1340 -1107
- data/vendor/node_modules/nodent-transform/package.json +19 -0
- data/vendor/node_modules/path-parse/package.json +1 -1
- data/vendor/node_modules/pretty-ms/index.js +2 -1
- data/vendor/node_modules/pretty-ms/package.json +2 -3
- data/vendor/node_modules/randomatic/index.js +12 -2
- data/vendor/node_modules/randomatic/node_modules/is-number/index.js +6 -7
- data/vendor/node_modules/randomatic/node_modules/is-number/package.json +9 -16
- data/vendor/node_modules/randomatic/node_modules/kind-of/index.js +112 -102
- data/vendor/node_modules/randomatic/node_modules/kind-of/package.json +18 -20
- data/vendor/node_modules/randomatic/package.json +15 -13
- data/vendor/node_modules/repeat-element/index.js +1 -1
- data/vendor/node_modules/repeat-element/package.json +27 -22
- data/vendor/node_modules/resolve/lib/async.js +20 -17
- data/vendor/node_modules/resolve/lib/core.js +2 -2
- data/vendor/node_modules/resolve/lib/core.json +4 -1
- data/vendor/node_modules/resolve/lib/sync.js +52 -13
- data/vendor/node_modules/resolve/package.json +3 -3
- data/vendor/node_modules/rollup-plugin-commonjs/dist/rollup-plugin-commonjs.cjs.js +50 -12
- data/vendor/node_modules/rollup-plugin-commonjs/dist/rollup-plugin-commonjs.es.js +50 -12
- data/vendor/node_modules/rollup-plugin-commonjs/package.json +2 -2
- data/vendor/node_modules/rollup-plugin-commonjs/src/index.js +49 -11
- data/vendor/node_modules/rollup-plugin-commonjs/src/transform.js +1 -1
- data/vendor/node_modules/rollup-plugin-node-resolve/dist/rollup-plugin-node-resolve.cjs.js +82 -85
- data/vendor/node_modules/rollup-plugin-node-resolve/dist/rollup-plugin-node-resolve.es.js +82 -85
- data/vendor/node_modules/rollup-plugin-node-resolve/package.json +1 -1
- data/vendor/node_modules/rollup-plugin-node-resolve/src/index.js +81 -84
- data/vendor/node_modules/rollup-pluginutils/dist/pluginutils.cjs.js +81 -2
- data/vendor/node_modules/rollup-pluginutils/dist/pluginutils.es.js +81 -3
- data/vendor/node_modules/rollup-pluginutils/package.json +12 -6
- data/vendor/node_modules/rollup-pluginutils/src/attachScopes.js +10 -2
- data/vendor/node_modules/rollup-pluginutils/src/dataToEsm.js +69 -0
- data/vendor/node_modules/rollup-pluginutils/src/index.js +1 -0
- data/vendor/node_modules/supports-color/index.js +1 -5
- data/vendor/node_modules/supports-color/package.json +51 -51
- data/vendor/yarn.lock +65 -70
- metadata +16 -21
- data/vendor/node_modules/irregular-plurals/irregular-plurals.json +0 -146
- data/vendor/node_modules/irregular-plurals/package.json +0 -39
- data/vendor/node_modules/nodent-compiler/lib/parser.js +0 -291
- data/vendor/node_modules/path-parse/index.min.js +0 -1
- data/vendor/node_modules/path-parse/test.min.js +0 -1
- data/vendor/node_modules/plur/index.js +0 -20
- data/vendor/node_modules/plur/package.json +0 -42
- data/vendor/node_modules/randomatic/node_modules/is-number/node_modules/kind-of/index.js +0 -116
- data/vendor/node_modules/randomatic/node_modules/is-number/node_modules/kind-of/package.json +0 -90
- data/vendor/node_modules/rollup-pluginutils/dist/pluginutils.es6.js +0 -217
- data/vendor/node_modules/rollup-pluginutils/node_modules/estree-walker/dist/estree-walker.es.js +0 -55
- data/vendor/node_modules/rollup-pluginutils/node_modules/estree-walker/dist/estree-walker.es6.js +0 -59
- data/vendor/node_modules/rollup-pluginutils/node_modules/estree-walker/dist/estree-walker.umd.js +0 -65
- data/vendor/node_modules/rollup-pluginutils/node_modules/estree-walker/package.json +0 -33
- data/vendor/node_modules/rollup-pluginutils/node_modules/estree-walker/src/estree-walker.js +0 -49
@@ -0,0 +1,22 @@
|
|
1
|
+
{
|
2
|
+
"name": "@types/estree",
|
3
|
+
"version": "0.0.38",
|
4
|
+
"description": "TypeScript definitions for ESTree AST specification",
|
5
|
+
"license": "MIT",
|
6
|
+
"contributors": [
|
7
|
+
{
|
8
|
+
"name": "RReverser",
|
9
|
+
"url": "https://github.com/RReverser",
|
10
|
+
"githubUsername": "RReverser"
|
11
|
+
}
|
12
|
+
],
|
13
|
+
"main": "",
|
14
|
+
"repository": {
|
15
|
+
"type": "git",
|
16
|
+
"url": "https://www.github.com/DefinitelyTyped/DefinitelyTyped.git"
|
17
|
+
},
|
18
|
+
"scripts": {},
|
19
|
+
"dependencies": {},
|
20
|
+
"typesPublisherContentHash": "19879f4eaa24d649d1de20d95bf747d91637d037470d47442d96dad57ec9a424",
|
21
|
+
"typeScriptVersion": "2.0"
|
22
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module.exports = (function (global) {
|
2
|
+
var uint32 = 'Uint32Array' in global
|
3
|
+
var crypto = global.crypto || global.msCrypto
|
4
|
+
var rando = crypto && typeof crypto.getRandomValues === 'function'
|
5
|
+
var good = uint32 && crypto && rando
|
6
|
+
if (!good) return Math.random
|
7
|
+
|
8
|
+
var arr = new Uint32Array(1)
|
9
|
+
var max = Math.pow(2, 32)
|
10
|
+
function random () {
|
11
|
+
crypto.getRandomValues(arr)
|
12
|
+
return arr[0] / max
|
13
|
+
}
|
14
|
+
|
15
|
+
random.cryptographic = true
|
16
|
+
return random
|
17
|
+
})(typeof self !== 'undefined' ? self : window)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
{
|
2
|
+
"name": "math-random",
|
3
|
+
"version": "1.0.1",
|
4
|
+
"description": "a drop-in replacement for Math.random that uses cryptographically secure random number generation, where available",
|
5
|
+
"main": "node.js",
|
6
|
+
"browser": "browser.js",
|
7
|
+
"scripts": {
|
8
|
+
"test": "tape test.js"
|
9
|
+
},
|
10
|
+
"devDependencies": {
|
11
|
+
"array-unique": "~0.2.1",
|
12
|
+
"tape": "~4.2.2"
|
13
|
+
},
|
14
|
+
"testling": {
|
15
|
+
"files": "test.js"
|
16
|
+
},
|
17
|
+
"repository": {
|
18
|
+
"type": "git",
|
19
|
+
"url": "git@github.com:michaelrhodes/math-random"
|
20
|
+
},
|
21
|
+
"keywords": [
|
22
|
+
"Math.random",
|
23
|
+
"crypto.getRandomValues"
|
24
|
+
],
|
25
|
+
"author": "Michael Rhodes",
|
26
|
+
"license": "MIT",
|
27
|
+
"bugs": {
|
28
|
+
"url": "https://github.com/michaelrhodes/math-random/issues"
|
29
|
+
},
|
30
|
+
"homepage": "https://github.com/michaelrhodes/math-random"
|
31
|
+
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
var test = require('tape')
|
2
|
+
var unique = require('array-unique')
|
3
|
+
var random = require('./')
|
4
|
+
|
5
|
+
test('it works', function (assert) {
|
6
|
+
var number, l = 1000, cache = []
|
7
|
+
|
8
|
+
for (var i = 0; i < l; i++) {
|
9
|
+
number = random()
|
10
|
+
if (number <= 0) {
|
11
|
+
assert.fail('a random number was less than or equal to zero')
|
12
|
+
assert.end()
|
13
|
+
return
|
14
|
+
}
|
15
|
+
if (number >= 1) {
|
16
|
+
assert.fail('a random number was greater than or equal to one')
|
17
|
+
assert.end()
|
18
|
+
return
|
19
|
+
}
|
20
|
+
cache.push(number)
|
21
|
+
}
|
22
|
+
|
23
|
+
assert.pass('all ' + l + ' random numbers were greater than zero and less than one')
|
24
|
+
assert.equal(cache.length, unique(cache).length, 'all ' + l + ' random numbers were unique')
|
25
|
+
assert.end()
|
26
|
+
})
|
@@ -1,6 +1,72 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
var
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
var acorn = require("acorn");
|
4
|
+
var treeSurgeon = require('nodent-transform') ;
|
5
|
+
var outputCode = require('./output') ;
|
6
|
+
|
7
|
+
var alreadyInstalledPlugin = false ;
|
8
|
+
|
9
|
+
function acornParse(code,config) {
|
10
|
+
var comments = [] ;
|
11
|
+
var options = {
|
12
|
+
ecmaVersion:9,
|
13
|
+
allowHashBang:true,
|
14
|
+
allowReturnOutsideFunction:true,
|
15
|
+
allowImportExportEverywhere:true,
|
16
|
+
locations:true,
|
17
|
+
onComment:comments
|
18
|
+
} ;
|
19
|
+
|
20
|
+
if (config)
|
21
|
+
for (var k in config)
|
22
|
+
if (k !== 'noNodentExtensions' && k != 'onParserInstallation')
|
23
|
+
options[k] = config[k] ;
|
24
|
+
|
25
|
+
if (!(config && config.noNodentExtensions) || parseInt(acorn.version) < 4) {
|
26
|
+
if (!alreadyInstalledPlugin) {
|
27
|
+
if (parseInt(acorn.version) < 4)
|
28
|
+
console.warn("Nodent: Warning - noNodentExtensions option requires acorn >=v4.x. Extensions installed.") ;
|
29
|
+
require('acorn-es7-plugin')(acorn) ;
|
30
|
+
if (config && config.onParserInstallation) config.onParserInstallation(acorn) ;
|
31
|
+
alreadyInstalledPlugin = true ;
|
32
|
+
}
|
33
|
+
options.plugins = options.plugins || {} ;
|
34
|
+
options.plugins.asyncawait = {asyncExits:true, awaitAnywhere:true} ;
|
35
|
+
}
|
36
|
+
|
37
|
+
var ast = acorn.parse(code,options) ;
|
38
|
+
|
39
|
+
// attach comments to the most tightly containing node
|
40
|
+
treeSurgeon.treeWalker(ast,function(node,descend,path){
|
41
|
+
descend() ;
|
42
|
+
while (comments.length && node.loc &&
|
43
|
+
(node.loc.start.line >= comments[0].loc.start.line && node.loc.end.line>=comments[0].loc.end.line)) {
|
44
|
+
node.$comments = node.$comments||[] ;
|
45
|
+
node.$comments.push(comments.shift()) ;
|
46
|
+
}
|
47
|
+
}) ;
|
48
|
+
return ast ;
|
49
|
+
}
|
50
|
+
|
51
|
+
function parse(code) {
|
52
|
+
return acornParse(code, {
|
53
|
+
noNodentExtensions:true, // The partial parser only ever parses vanilla JS
|
54
|
+
locations:false,
|
55
|
+
ranges:false,
|
56
|
+
onComment:null
|
57
|
+
}) ;
|
58
|
+
}
|
59
|
+
|
60
|
+
function printNode(n) {
|
61
|
+
if (!n) return '' ;
|
62
|
+
if (Array.isArray(n))
|
63
|
+
return n.map(printNode).join("|\n");
|
64
|
+
try {
|
65
|
+
return outputCode(n) ; //+"\t//@"+Object.keys(n).filter(function(k){ return k[0]==='$'}).map(function(k){ return k+":"+n[k] });
|
66
|
+
} catch (ex) {
|
67
|
+
return ex.message + ": " + (n && n.type);
|
68
|
+
}
|
69
|
+
} ;
|
4
70
|
|
5
71
|
/* Utils */
|
6
72
|
function copyObj(a){
|
@@ -18,7 +84,11 @@ function btoa(str) {
|
|
18
84
|
if (str instanceof Buffer) {
|
19
85
|
buffer = str;
|
20
86
|
} else {
|
21
|
-
|
87
|
+
if (Buffer.from) {
|
88
|
+
buffer = Buffer.from(str.toString(), 'binary');
|
89
|
+
} else {
|
90
|
+
buffer = new Buffer(str.toString(), 'binary');
|
91
|
+
}
|
22
92
|
}
|
23
93
|
|
24
94
|
return buffer.toString('base64');
|
@@ -40,7 +110,11 @@ function compile(code,origFilename,__sourceMapping,opts) {
|
|
40
110
|
}
|
41
111
|
|
42
112
|
var pr = this.parse(code,origFilename,null,opts);
|
43
|
-
this.
|
113
|
+
this.transform(pr,opts,{
|
114
|
+
parse: parse, // Parse a JS fragment into an AST
|
115
|
+
printNode: printNode, // Print a node as JS source
|
116
|
+
logger:this.logger || noLogger // Log a warning
|
117
|
+
}) ;
|
44
118
|
this.prettyPrint(pr,opts) ;
|
45
119
|
return pr ;
|
46
120
|
}
|
@@ -100,9 +174,9 @@ function parseCode(code,origFilename,__sourceMapping,opts) {
|
|
100
174
|
|
101
175
|
var r = { origCode:code.toString(), filename:origFilename } ;
|
102
176
|
try {
|
103
|
-
r.ast =
|
177
|
+
r.ast = acornParse(r.origCode, opts && opts.parser) ;
|
104
178
|
if (opts.babelTree) {
|
105
|
-
|
179
|
+
treeSurgeon.treeWalker(r.ast,function(node,descend,path){
|
106
180
|
if (node.type==='Literal')
|
107
181
|
path[0].replace(treeSurgeon.babelLiteralNode(node.value)) ;
|
108
182
|
else if (node.type==='Property') {
|
@@ -135,14 +209,43 @@ NodentCompiler.prototype.isThenable = function(x) { return x && x instanceof Obj
|
|
135
209
|
NodentCompiler.prototype.compile = compile ;
|
136
210
|
// Exported ; but not to be used lightly!
|
137
211
|
NodentCompiler.prototype.parse = parseCode ;
|
138
|
-
NodentCompiler.prototype.asynchronize = treeSurgeon.asynchronize ;
|
139
|
-
NodentCompiler.prototype.printNode = treeSurgeon.printNode ;
|
140
212
|
NodentCompiler.prototype.prettyPrint = prettyPrint ;
|
141
213
|
NodentCompiler.prototype.getDefaultCompileOptions = undefined ;
|
214
|
+
NodentCompiler.prototype.transform = treeSurgeon.transform ;
|
215
|
+
// asynchronize and printNode were previuosly defined in arboriculture, but they are
|
216
|
+
// are now (>3.2.0) pulled up into compiler so arboriculture.transform can be called from other
|
217
|
+
// hosts such as babel 7
|
218
|
+
NodentCompiler.prototype.asynchronize = function asynchronize(pr, __sourceMapping, opts, logger) {
|
219
|
+
try {
|
220
|
+
var tree = treeSurgeon.transform(pr, opts, {
|
221
|
+
parse: parse, // Parse a JS fragment into an AST
|
222
|
+
printNode: printNode, // Print a node as JS source
|
223
|
+
logger:logger // Log a warning
|
224
|
+
}) ;
|
225
|
+
if (opts.babelTree) {
|
226
|
+
tree.ast = treeSurgeon.treeWalker(tree.ast, function(node,descend,path){
|
227
|
+
if (node.type === 'Literal')
|
228
|
+
path[0].replace(treeSurgeon.babelLiteralNode(node.value)) ;
|
229
|
+
else
|
230
|
+
descend() ;
|
231
|
+
}) ;
|
232
|
+
}
|
233
|
+
return tree ;
|
234
|
+
} catch (ex) {
|
235
|
+
if (ex instanceof SyntaxError) {
|
236
|
+
var l = pr.origCode.substr(ex.pos - ex.loc.column);
|
237
|
+
l = l.split("\n")[0];
|
238
|
+
ex.message += " (nodent)\n" + l + "\n" + l.replace(/[\S ]/g, "-").substring(0, ex.loc.column) + "^";
|
239
|
+
ex.stack = "";
|
240
|
+
}
|
241
|
+
throw ex;
|
242
|
+
}
|
243
|
+
} ;
|
244
|
+
NodentCompiler.prototype.printNode = printNode ;
|
142
245
|
|
143
246
|
Object.defineProperty(NodentCompiler.prototype,"Promise",{
|
144
247
|
get:function (){
|
145
|
-
|
248
|
+
console.warn("Warning: nodent.Promise is deprecated. Use nodent.Thenable instead");
|
146
249
|
return Thenable;
|
147
250
|
},
|
148
251
|
enumerable:false,
|
@@ -159,12 +262,13 @@ NodentCompiler.initialCodeGenOpts = {
|
|
159
262
|
sourcemap:true,
|
160
263
|
engine:false,
|
161
264
|
parser:{sourceType:'script'},
|
265
|
+
generatedSymbolPrefix:"$",
|
162
266
|
$return:"$return",
|
163
267
|
$error:"$error",
|
164
268
|
$arguments:"$args",
|
269
|
+
$Promise:"Promise",
|
165
270
|
$asyncspawn:"$asyncspawn",
|
166
271
|
$asyncbind:"$asyncbind",
|
167
|
-
generatedSymbolPrefix:"$",
|
168
272
|
$makeThenable:'$makeThenable'
|
169
273
|
};
|
170
274
|
|
File without changes
|
@@ -1,15 +1,19 @@
|
|
1
1
|
{
|
2
2
|
"name": "nodent-compiler",
|
3
|
-
"version": "3.
|
3
|
+
"version": "3.2.9",
|
4
4
|
"description": "NoDent - Asynchronous Javascript language extensions",
|
5
5
|
"main": "compiler.js",
|
6
6
|
"scripts": {
|
7
|
-
"test": "node tests/
|
7
|
+
"test": "node tests tests/semantics/*"
|
8
8
|
},
|
9
9
|
"dependencies": {
|
10
10
|
"acorn": ">=2.5.2",
|
11
|
-
"acorn-es7-plugin": "
|
12
|
-
"
|
11
|
+
"acorn-es7-plugin": "^1.1.7",
|
12
|
+
"nodent-transform": "^3.2.9",
|
13
|
+
"source-map": "^0.5.7"
|
14
|
+
},
|
15
|
+
"devDependencies": {
|
16
|
+
"nodent-runtime": "^3.2.1"
|
13
17
|
},
|
14
18
|
"repository": {
|
15
19
|
"type": "git",
|
@@ -1,22 +1,8 @@
|
|
1
1
|
'use strict';
|
2
|
-
|
3
2
|
/* We manipulate (abstract syntax) trees */
|
4
|
-
var parser = require('./parser');
|
5
|
-
var outputCode = require('./output');
|
6
3
|
/** Helpers **/
|
7
|
-
/*global.printNode = */function printNode(n) {
|
8
|
-
if (!n) return '' ;
|
9
|
-
if (Array.isArray(n))
|
10
|
-
return n.map(printNode).join("|\n");
|
11
|
-
try {
|
12
|
-
return outputCode(n) ; //+"\t//@"+Object.keys(n).filter(function(k){ return k[0]==='$'}).map(function(k){ return k+":"+n[k] });
|
13
|
-
} catch (ex) {
|
14
|
-
return ex.message + ": " + (n && n.type);
|
15
|
-
}
|
16
|
-
}
|
17
|
-
|
18
4
|
function cloneNode(n) {
|
19
|
-
if (Array.isArray(n))
|
5
|
+
if (Array.isArray(n))
|
20
6
|
return n.map(function (n) {
|
21
7
|
return cloneNode(n);
|
22
8
|
});
|
@@ -29,40 +15,76 @@ function cloneNode(n) {
|
|
29
15
|
|
30
16
|
/* Bit of a hack: without having to search for references to this
|
31
17
|
* node, force it to be some replacement node */
|
32
|
-
var locationInfo = {
|
18
|
+
var locationInfo = {
|
19
|
+
start: true,
|
20
|
+
end: true,
|
21
|
+
loc: true,
|
22
|
+
range: true
|
23
|
+
};
|
33
24
|
function coerce(node, replace) {
|
34
|
-
if (node===replace)
|
25
|
+
if (node === replace)
|
26
|
+
return;
|
35
27
|
node.__proto__ = Object.getPrototypeOf(replace);
|
36
28
|
Object.keys(node).forEach(function (k) {
|
37
|
-
if (!(k in locationInfo))
|
29
|
+
if (!(k in locationInfo))
|
38
30
|
delete node[k];
|
39
31
|
});
|
40
32
|
Object.keys(replace).forEach(function (k) {
|
41
|
-
if (!(k in node))
|
33
|
+
if (!(k in node))
|
42
34
|
node[k] = replace[k];
|
43
35
|
});
|
44
36
|
}
|
45
37
|
|
46
|
-
function Nothing(){}
|
38
|
+
function Nothing() {}
|
47
39
|
|
48
40
|
var examinations = {
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
41
|
+
getScope: function () {
|
42
|
+
return this.node.type === 'FunctionDeclaration' || this.node.type === 'FunctionExpression' || this.node.type === 'Function' || this.node.type === 'ObjectMethod' || this.node.type === 'ClassMethod' || this.node.type === 'ArrowFunctionExpression' && this.node.body.type === 'BlockStatement' ? this.node.body.body : this.node.type === 'Program' ? this.node.body : null;
|
43
|
+
},
|
44
|
+
isScope: function () {
|
45
|
+
return this.node.type === 'FunctionDeclaration' || this.node.type === 'FunctionExpression' || this.node.type === 'Function' || this.node.type === 'Program' || this.node.type === 'ObjectMethod' || this.node.type === 'ClassMethod' || this.node.type === 'ArrowFunctionExpression' && this.node.body.type === 'BlockStatement';
|
46
|
+
},
|
47
|
+
isFunction: function () {
|
48
|
+
return this.node.type === 'FunctionDeclaration' || this.node.type === 'FunctionExpression' || this.node.type === 'Function' || this.node.type === 'ObjectMethod' || this.node.type === 'ClassMethod' || this.node.type === 'ArrowFunctionExpression';
|
49
|
+
},
|
50
|
+
isClass: function () {
|
51
|
+
return this.node.type === 'ClassDeclaration' || this.node.type === 'ClassExpression';
|
52
|
+
},
|
53
|
+
isBlockStatement: function () {
|
54
|
+
return this.node.type === 'ClassBody' || this.node.type === 'Program' || this.node.type === 'BlockStatement' ? this.node.body : this.node.type === 'SwitchCase' ? this.node.consequent : false;
|
55
|
+
},
|
56
|
+
isExpressionStatement: function () {
|
57
|
+
return this.node.type === 'ExpressionStatement';
|
58
|
+
},
|
59
|
+
isLiteral: function () {
|
60
|
+
return this.node.type === 'Literal' || this.node.type === 'BooleanLiteral' || this.node.type === 'RegExpLiteral' || this.node.type === 'NumericLiteral' || this.node.type === 'StringLiteral' || this.node.type === 'NullLiteral';
|
61
|
+
},
|
62
|
+
isDirective: function () {
|
63
|
+
return this.node.type === 'ExpressionStatement' && (this.node.expression.type === 'StringLiteral' || this.node.expression.type === 'Literal' && typeof this.node.expression.value === 'string');
|
64
|
+
},
|
65
|
+
isUnaryExpression: function () {
|
66
|
+
return this.node.type === 'UnaryExpression';
|
67
|
+
},
|
68
|
+
isAwait: function () {
|
69
|
+
return this.node.type === 'AwaitExpression' && !this.node.$hidden;
|
70
|
+
},
|
71
|
+
isAsync: function () {
|
72
|
+
return this.node.async;
|
73
|
+
},
|
74
|
+
isStatement: function () {
|
75
|
+
return this.node.type.match(/[a-zA-Z]+Declaration/) !== null || this.node.type.match(/[a-zA-Z]+Statement/) !== null;
|
76
|
+
},
|
77
|
+
isExpression: function () {
|
78
|
+
return this.node.type.match(/[a-zA-Z]+Expression/) !== null;
|
79
|
+
},
|
80
|
+
isLoop: function () { // Other loops?
|
81
|
+
return this.node.type === 'ForStatement' || this.node.type === 'WhileStatement' || this.node.type === 'DoWhileStatement';
|
82
|
+
},
|
83
|
+
isJump: function () {
|
84
|
+
return this.node.type === 'ReturnStatement' || this.node.type === 'ThrowStatement' || this.node.type === 'BreakStatement' || this.node.type === 'ContinueStatement';
|
85
|
+
},
|
86
|
+
isES6: function () {
|
87
|
+
switch (this.node.type) {
|
66
88
|
case 'ExportNamedDeclaration':
|
67
89
|
case 'ExportSpecifier':
|
68
90
|
case 'ExportDefaultDeclaration':
|
@@ -81,111 +103,36 @@ var examinations = {
|
|
81
103
|
case 'TemplateLiteral':
|
82
104
|
case 'ClassDeclaration':
|
83
105
|
case 'ClassExpression':
|
84
|
-
|
85
|
-
|
106
|
+
return true;
|
86
107
|
case 'VariableDeclaration':
|
87
|
-
|
88
|
-
|
108
|
+
return this.node.kind && this.node.kind === 'let';
|
89
109
|
case 'FunctionDeclaration':
|
90
110
|
case 'FunctionExpression':
|
91
|
-
|
111
|
+
return !(!this.node.generator);
|
92
112
|
}
|
93
|
-
|
113
|
+
}
|
94
114
|
};
|
95
|
-
|
96
|
-
|
97
|
-
Object.
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
}) ;
|
102
|
-
|
115
|
+
var NodeExaminer = {};
|
116
|
+
Object.keys(examinations).forEach(function (k) {
|
117
|
+
Object.defineProperty(NodeExaminer, k, {
|
118
|
+
get: examinations[k]
|
119
|
+
});
|
120
|
+
});
|
103
121
|
function examine(node) {
|
104
|
-
if (!node)
|
122
|
+
if (!node)
|
105
123
|
return {};
|
106
|
-
NodeExaminer.node = node
|
107
|
-
return NodeExaminer
|
108
|
-
}
|
109
|
-
|
110
|
-
/*
|
111
|
-
* descendOn = true Enter scopes within scopes
|
112
|
-
* descendOn = false/undefined/null Do not enter scopes within scopes
|
113
|
-
* descendOn = function Descend when function(node) is true
|
114
|
-
*/
|
115
|
-
function contains(ast, fn, descendOn) {
|
116
|
-
if (!ast)
|
117
|
-
return null;
|
118
|
-
if (fn && typeof fn === 'object') {
|
119
|
-
var keys = Object.keys(fn);
|
120
|
-
return contains(ast, function (node) {
|
121
|
-
return keys.every(function (k) {
|
122
|
-
return node[k] == fn[k];
|
123
|
-
});
|
124
|
-
});
|
125
|
-
}
|
126
|
-
var n, found = {};
|
127
|
-
if (Array.isArray(ast)) {
|
128
|
-
for (var i = 0;i < ast.length; i++)
|
129
|
-
if (n = contains(ast[i], fn))
|
130
|
-
return n;
|
131
|
-
return null;
|
132
|
-
}
|
133
|
-
|
134
|
-
var subScopes = descendOn ;
|
135
|
-
if (typeof descendOn !== "function") {
|
136
|
-
if (descendOn) {
|
137
|
-
subScopes = function(n) { return true } ;
|
138
|
-
} else {
|
139
|
-
subScopes = function(n) { return !examine(n).isScope } ;
|
140
|
-
}
|
141
|
-
}
|
142
|
-
|
143
|
-
try {
|
144
|
-
parser.treeWalker(ast, function (node, descend, path) {
|
145
|
-
if (fn(node)) {
|
146
|
-
found.path = path;
|
147
|
-
throw found;
|
148
|
-
}
|
149
|
-
if (node === ast || subScopes(node))
|
150
|
-
descend();
|
151
|
-
});
|
152
|
-
} catch (ex) {
|
153
|
-
if (ex === found)
|
154
|
-
return found.path;
|
155
|
-
throw ex;
|
156
|
-
}
|
157
|
-
return null;
|
158
|
-
}
|
159
|
-
|
160
|
-
function containsAwait(ast) {
|
161
|
-
return contains(ast, function(n){
|
162
|
-
return n.type==='AwaitExpression' && !n.$hidden
|
163
|
-
});
|
164
|
-
}
|
165
|
-
|
166
|
-
function containsAwaitInBlock(ast) {
|
167
|
-
return contains(ast, function(n){
|
168
|
-
return n.type==='AwaitExpression' && !n.$hidden
|
169
|
-
}, function (n) {
|
170
|
-
var x = examine(n) ;
|
171
|
-
return !x.isBlockStatement && !x.isScope
|
172
|
-
});
|
173
|
-
}
|
174
|
-
|
175
|
-
function containsThis(ast) {
|
176
|
-
return contains(ast, {
|
177
|
-
type: 'ThisExpression'
|
178
|
-
});
|
124
|
+
NodeExaminer.node = node;
|
125
|
+
return NodeExaminer;
|
179
126
|
}
|
180
127
|
|
181
128
|
function babelLiteralNode(value) {
|
182
|
-
if (value === null)
|
129
|
+
if (value === null)
|
183
130
|
return {
|
184
131
|
type: 'NullLiteral',
|
185
132
|
value: null,
|
186
133
|
raw: 'null'
|
187
134
|
};
|
188
|
-
if (value === true || value === false)
|
135
|
+
if (value === true || value === false)
|
189
136
|
return {
|
190
137
|
type: 'BooleanLiteral',
|
191
138
|
value: value,
|
@@ -202,7 +149,7 @@ function babelLiteralNode(value) {
|
|
202
149
|
flags: parts[2]
|
203
150
|
};
|
204
151
|
}
|
205
|
-
if (typeof value === 'number')
|
152
|
+
if (typeof value === 'number')
|
206
153
|
return {
|
207
154
|
type: 'NumericLiteral',
|
208
155
|
value: value,
|
@@ -216,6 +163,8 @@ function babelLiteralNode(value) {
|
|
216
163
|
}
|
217
164
|
|
218
165
|
function ident(name, loc) {
|
166
|
+
if (!name)
|
167
|
+
throw new Error("Illegal Identifier name") ;
|
219
168
|
return {
|
220
169
|
type: 'Identifier',
|
221
170
|
name: name,
|
@@ -225,70 +174,166 @@ function ident(name, loc) {
|
|
225
174
|
|
226
175
|
function idents(s) {
|
227
176
|
var r = {};
|
228
|
-
for (var k in s)
|
177
|
+
for (var k in s)
|
229
178
|
r[k] = typeof s[k] === "string" ? ident(s[k]) : s[k];
|
230
179
|
return r;
|
231
180
|
}
|
232
181
|
|
233
|
-
function asynchronize(pr,
|
182
|
+
function asynchronize(pr, opts, logger, parsePart, printNode) {
|
234
183
|
var continuations = {};
|
235
184
|
var generatedSymbol = 1;
|
236
185
|
var genIdent = {};
|
186
|
+
|
237
187
|
Object.keys(opts).filter(function (k) {
|
238
188
|
return k[0] === '$';
|
239
189
|
}).forEach(function (k) {
|
240
|
-
|
190
|
+
if (opts[k])
|
191
|
+
genIdent[k.slice(1)] = ident(opts[k]);
|
241
192
|
});
|
242
|
-
|
193
|
+
/*
|
194
|
+
* descendOn = true Enter scopes within scopes
|
195
|
+
* descendOn = false/undefined/null Do not enter scopes within scopes
|
196
|
+
* descendOn = function Descend when function(node) is true
|
197
|
+
*/
|
198
|
+
function contains(ast, fn, descendOn) {
|
199
|
+
if (!ast)
|
200
|
+
return null;
|
201
|
+
if (fn && typeof fn === 'object') {
|
202
|
+
var keys = Object.keys(fn);
|
203
|
+
return contains(ast, function (node) {
|
204
|
+
return keys.every(function (k) {
|
205
|
+
return node[k] == fn[k];
|
206
|
+
});
|
207
|
+
});
|
208
|
+
}
|
209
|
+
var n, found = {};
|
210
|
+
if (Array.isArray(ast)) {
|
211
|
+
for (var i = 0;i < ast.length; i++)
|
212
|
+
if (n = contains(ast[i], fn))
|
213
|
+
return n;
|
214
|
+
return null;
|
215
|
+
}
|
216
|
+
var subScopes = descendOn;
|
217
|
+
if (typeof descendOn !== "function") {
|
218
|
+
if (descendOn) {
|
219
|
+
subScopes = function (n) {
|
220
|
+
return true;
|
221
|
+
};
|
222
|
+
} else {
|
223
|
+
subScopes = function (n) {
|
224
|
+
return !examine(n).isScope;
|
225
|
+
};
|
226
|
+
}
|
227
|
+
}
|
228
|
+
try {
|
229
|
+
treeWalk(ast, function (node, descend, path) {
|
230
|
+
if (fn(node)) {
|
231
|
+
found.path = path;
|
232
|
+
throw found;
|
233
|
+
}
|
234
|
+
if (node === ast || subScopes(node))
|
235
|
+
descend();
|
236
|
+
});
|
237
|
+
} catch (ex) {
|
238
|
+
if (ex === found)
|
239
|
+
return found.path;
|
240
|
+
throw ex;
|
241
|
+
}
|
242
|
+
return null;
|
243
|
+
}
|
244
|
+
|
245
|
+
function containsAwait(ast) {
|
246
|
+
return contains(ast, function (n) {
|
247
|
+
return n.type === 'AwaitExpression' && !n.$hidden;
|
248
|
+
});
|
249
|
+
}
|
250
|
+
|
251
|
+
function containsAwaitInBlock(ast) {
|
252
|
+
return contains(ast, function (n) {
|
253
|
+
return n.type === 'AwaitExpression' && !n.$hidden;
|
254
|
+
}, function (n) {
|
255
|
+
var x = examine(n);
|
256
|
+
return !x.isBlockStatement && !x.isScope;
|
257
|
+
});
|
258
|
+
}
|
259
|
+
|
260
|
+
function containsThis(ast) {
|
261
|
+
return contains(ast, {
|
262
|
+
type: 'ThisExpression'
|
263
|
+
});
|
264
|
+
}
|
265
|
+
|
243
266
|
/* Generate a prototypical call of the form:
|
244
267
|
* (left).$asyncbind(this,...args)
|
245
268
|
*/
|
246
|
-
function bindAsync(left,arg) {
|
247
|
-
if (opts.es6target && !left.id && !arg && left.type.indexOf("Function")===0) {
|
248
|
-
left.type = 'ArrowFunctionExpression'
|
249
|
-
return left
|
269
|
+
function bindAsync(left, arg) {
|
270
|
+
if (opts.es6target && !left.id && !arg && left.type.indexOf("Function") === 0) {
|
271
|
+
left.type = 'ArrowFunctionExpression';
|
272
|
+
return left;
|
250
273
|
}
|
251
|
-
|
252
274
|
if (opts.noRuntime) {
|
253
275
|
if (arg) {
|
254
276
|
if (examine(arg).isLiteral) {
|
255
|
-
throw new Error("Nodent: 'noRuntime' option only compatible with -promise and -engine modes")
|
277
|
+
throw new Error("Nodent: 'noRuntime' option only compatible with -promise and -engine modes");
|
256
278
|
}
|
257
279
|
// Add a global synchronous exception handler to (left)
|
258
|
-
left.body.body =
|
259
|
-
|
260
|
-
|
261
|
-
|
280
|
+
left.body.body = parsePart("try {$:0} catch($2) {return $1($2)}", [cloneNode(left.body),
|
281
|
+
arg,ident('$boundEx')]).body;
|
282
|
+
} else if (opts.es6target && !left.id && left.type.indexOf("Function") === 0) {
|
283
|
+
left.type = 'ArrowFunctionExpression';
|
284
|
+
return left;
|
262
285
|
}
|
263
286
|
if (opts.es6target && !left.id) {
|
264
|
-
left.type = 'ArrowFunctionExpression'
|
287
|
+
left.type = 'ArrowFunctionExpression';
|
265
288
|
return left;
|
266
289
|
}
|
267
|
-
|
290
|
+
if (containsThis(left))
|
291
|
+
return parsePart("$0.bind(this)", [left]).expr;
|
292
|
+
return left;
|
268
293
|
}
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
294
|
+
var subst = {
|
295
|
+
runtime: genIdent.runtime,
|
296
|
+
asyncbind: genIdent.asyncbind,
|
297
|
+
fn: left,
|
298
|
+
arg: arg
|
299
|
+
};
|
300
|
+
if (opts.$runtime) {
|
301
|
+
if (arg) {
|
302
|
+
return parsePart("$runtime.$asyncbind.call($fn,this,$arg)", subst).expr;
|
303
|
+
} else {
|
304
|
+
if (opts.lazyThenables || containsThis(left))
|
305
|
+
return parsePart("$runtime.$asyncbind.call($fn,this)", subst).expr;
|
306
|
+
return left;
|
307
|
+
}
|
308
|
+
} else {
|
309
|
+
if (arg) {
|
310
|
+
return parsePart("$fn.$asyncbind(this,$arg)", subst).expr;
|
311
|
+
} else {
|
312
|
+
if (opts.lazyThenables || containsThis(left))
|
313
|
+
return parsePart("$fn.$asyncbind(this)", subst).expr;
|
314
|
+
return left;
|
315
|
+
}
|
273
316
|
}
|
274
|
-
return parser.part("$0.$1(this)",[left,genIdent.asyncbind]).expr;
|
275
317
|
}
|
276
|
-
|
318
|
+
|
277
319
|
function makeBoundFn(name, body, argnames, binding) {
|
278
|
-
return
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
320
|
+
return parsePart("var $0 = $1", [ident(name),bindAsync({
|
321
|
+
"type": "FunctionExpression",
|
322
|
+
"id": null,
|
323
|
+
"generator": false,
|
324
|
+
"expression": false,
|
325
|
+
"params": argnames || [],
|
326
|
+
"body": Array.isArray(body) ? {
|
327
|
+
type: 'BlockStatement',
|
328
|
+
body: body
|
329
|
+
} : body
|
330
|
+
}, binding)]).body[0];
|
286
331
|
}
|
287
|
-
|
332
|
+
|
288
333
|
function where(node) {
|
289
334
|
return pr.filename + (node && node.loc && node.loc.start ? "(" + node.loc.start.line + ":" + node.loc.start.column + ")\t" : "\t");
|
290
335
|
}
|
291
|
-
|
336
|
+
|
292
337
|
function literal(value) {
|
293
338
|
if (opts.babelTree) {
|
294
339
|
return babelLiteralNode(value);
|
@@ -300,10 +345,10 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
300
345
|
};
|
301
346
|
}
|
302
347
|
}
|
303
|
-
|
348
|
+
|
304
349
|
function getMemberFunction(node) {
|
305
|
-
if (!node)
|
306
|
-
return null
|
350
|
+
if (!node)
|
351
|
+
return null;
|
307
352
|
if (opts.babelTree && (node.type === 'ClassMethod' || node.type === 'ObjectMethod')) {
|
308
353
|
return node;
|
309
354
|
} else if ((!opts.babelTree && node.type === 'MethodDefinition' || node.type === 'Property' && (node.method || node.kind == 'get' || node.kind == 'set')) && examine(node.value).isFunction) {
|
@@ -311,50 +356,47 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
311
356
|
}
|
312
357
|
return null;
|
313
358
|
}
|
314
|
-
|
315
|
-
var assign$Args =
|
316
|
-
|
359
|
+
|
360
|
+
var assign$Args = parsePart("var $0 = arguments", [genIdent.arguments]).body[0];
|
317
361
|
/* Replace 'arguments' identifiers in a function. Return true if a
|
318
362
|
* replacement has been made and so the symbol opts.$arguments needs
|
319
363
|
* initializing.
|
320
364
|
*/
|
321
|
-
function replaceArguments(ast,nested) {
|
322
|
-
if (!examine(ast).isFunction)
|
323
|
-
throw new Error("Can only replace 'arguments' in functions")
|
324
|
-
|
365
|
+
function replaceArguments(ast, nested) {
|
366
|
+
if (!examine(ast).isFunction)
|
367
|
+
throw new Error("Can only replace 'arguments' in functions");
|
325
368
|
if (!('$usesArguments' in ast)) {
|
326
|
-
|
369
|
+
treeWalk(ast, function (node, descend, path) {
|
327
370
|
if (node.type === 'Identifier' && node.name === 'arguments') {
|
328
371
|
// Fix up shorthand properties
|
329
372
|
if (path[0].parent.shorthand) {
|
330
|
-
|
331
|
-
|
332
|
-
|
373
|
+
path[0].parent.shorthand = false;
|
374
|
+
path[0].parent.key = ident('arguments');
|
375
|
+
ast.$usesArguments = true;
|
333
376
|
}
|
334
|
-
|
335
377
|
// Replace identifiers that are not keys
|
336
|
-
if (path[0].field !== 'key') {
|
337
|
-
|
338
|
-
|
378
|
+
if (path[0].field !== 'key' && path[0].field !== 'property') {
|
379
|
+
node.name = opts.$arguments;
|
380
|
+
ast.$usesArguments = true;
|
339
381
|
}
|
340
382
|
} else if (node === ast || !examine(node).isFunction) {
|
341
|
-
|
342
|
-
} else if (node.type==='ArrowFunctionExpression') {
|
343
|
-
replaceArguments(node)
|
344
|
-
ast.$usesArguments = ast.$usesArguments || node.$usesArguments
|
383
|
+
descend();
|
384
|
+
} else if (node.type === 'ArrowFunctionExpression') {
|
385
|
+
replaceArguments(node);
|
386
|
+
ast.$usesArguments = ast.$usesArguments || node.$usesArguments;
|
345
387
|
}
|
346
388
|
});
|
347
|
-
ast.$usesArguments = ast.$usesArguments || false
|
389
|
+
ast.$usesArguments = ast.$usesArguments || false;
|
348
390
|
}
|
349
391
|
return ast.$usesArguments && ast.type !== 'ArrowFunctionExpression';
|
350
392
|
}
|
351
|
-
|
393
|
+
|
352
394
|
function generateSymbol(node) {
|
353
|
-
if (typeof node != 'string')
|
354
|
-
node = node.type.replace(/Statement|Expression/g,"");
|
395
|
+
if (typeof node != 'string')
|
396
|
+
node = node.type.replace(/Statement|Expression/g, "");
|
355
397
|
return opts.generatedSymbolPrefix + node + "_" + generatedSymbol++;
|
356
398
|
}
|
357
|
-
|
399
|
+
|
358
400
|
function setExit(n, sym) {
|
359
401
|
if (n) {
|
360
402
|
n.$exit = idents({
|
@@ -364,7 +406,7 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
364
406
|
}
|
365
407
|
return n;
|
366
408
|
}
|
367
|
-
|
409
|
+
|
368
410
|
function getExitNode(path) {
|
369
411
|
for (var n = 0;n < path.length; n++) {
|
370
412
|
if (path[n].self.$exit) {
|
@@ -376,19 +418,24 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
376
418
|
}
|
377
419
|
return null;
|
378
420
|
}
|
379
|
-
|
421
|
+
|
380
422
|
function getExit(path, parents) {
|
381
423
|
var n = getExitNode(path);
|
382
|
-
if (n)
|
424
|
+
if (n)
|
383
425
|
return n.$exit;
|
384
426
|
if (parents) {
|
385
|
-
for (var i = 0;i < parents.length; i++)
|
386
|
-
if (parents[i])
|
427
|
+
for (var i = 0;i < parents.length; i++)
|
428
|
+
if (parents[i])
|
387
429
|
return idents(parents[i]);
|
388
430
|
}
|
389
431
|
return null;
|
390
432
|
}
|
391
433
|
|
434
|
+
|
435
|
+
var looksLikeES6 = opts.es6target || pr.ast.type === 'Program' && pr.ast.sourceType === 'module' || contains(pr.ast, function (n) {
|
436
|
+
return examine(n).isES6;
|
437
|
+
}, true);
|
438
|
+
|
392
439
|
// actually do the transforms
|
393
440
|
if (opts.engine) {
|
394
441
|
// Only Transform extensions:
|
@@ -398,33 +445,25 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
398
445
|
// - get async id(){} / async get id(){}
|
399
446
|
// - super references (in case they are used by async exits - in general they aren't)
|
400
447
|
// Everything else is passed through unmolested to be run by a JS engine such as V8 v5.4
|
401
|
-
pr.ast = fixSuperReferences(pr.ast,true);
|
448
|
+
pr.ast = fixSuperReferences(pr.ast, true);
|
402
449
|
pr.ast = asyncSpawn(pr.ast, opts.engine);
|
403
450
|
pr.ast = exposeCompilerOpts(pr.ast);
|
404
|
-
cleanCode(pr.ast)
|
451
|
+
cleanCode(pr.ast);
|
405
452
|
} else if (opts.generators) {
|
406
453
|
// Transform to generators
|
407
454
|
pr.ast = fixSuperReferences(pr.ast);
|
408
455
|
pr.ast = asyncSpawn(pr.ast);
|
409
456
|
pr.ast = exposeCompilerOpts(pr.ast);
|
410
|
-
cleanCode(pr.ast)
|
457
|
+
cleanCode(pr.ast);
|
411
458
|
} else {
|
412
459
|
// Transform to callbacks, optionally with Promises
|
413
460
|
pr.ast = fixSuperReferences(pr.ast);
|
414
461
|
asyncTransforms(pr.ast);
|
415
462
|
}
|
416
|
-
if (opts.babelTree) {
|
417
|
-
parser.treeWalker(pr.ast, function (node, descend, path) {
|
418
|
-
descend();
|
419
|
-
if (node.type === 'Literal') {
|
420
|
-
coerce(node, literal(node.value));
|
421
|
-
}
|
422
|
-
});
|
423
|
-
}
|
424
463
|
return pr;
|
425
|
-
|
464
|
+
|
426
465
|
function asyncTransforms(ast, awaitFlag) {
|
427
|
-
var useLazyLoops = !(opts.promises || opts.generators || opts.engine) && opts.lazyThenables
|
466
|
+
var useLazyLoops = !(opts.promises || opts.generators || opts.engine) && opts.lazyThenables;
|
428
467
|
// Because we create functions (and scopes), we need all declarations before use
|
429
468
|
blockifyArrows(ast);
|
430
469
|
hoistDeclarations(ast);
|
@@ -436,31 +475,32 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
436
475
|
// Loops are asynchronized in an odd way - the loop is turned into a function that is
|
437
476
|
// invoked through tail recursion OR callback. They are like the inner functions of
|
438
477
|
// async functions to allow for completion and throwing
|
439
|
-
(useLazyLoops?asyncLoops_1:Nothing)(ast);
|
478
|
+
(useLazyLoops ? asyncLoops_1 : Nothing)(ast);
|
440
479
|
// Handle the various JS control flow keywords by splitting into continuations that could
|
441
480
|
// be invoked asynchronously
|
442
481
|
mapLogicalOp(ast);
|
443
482
|
mapCondOp(ast);
|
444
|
-
walkDown(ast, [mapTryCatch,
|
483
|
+
walkDown(ast, [mapTryCatch,useLazyLoops ? Nothing : mapLoops,mapIfStmt,mapSwitch,
|
484
|
+
mapBlock]);
|
445
485
|
// Map awaits by creating continuations and passing them into the async resolver
|
446
486
|
asyncAwait(ast, awaitFlag);
|
447
487
|
exposeCompilerOpts(ast);
|
448
488
|
// Remove guff generated by transpiling
|
449
489
|
cleanCode(ast);
|
450
490
|
}
|
451
|
-
|
491
|
+
|
452
492
|
/* Create a 'continuation' - a block of statements that have been hoisted
|
453
493
|
* into a named function so they can be invoked conditionally or asynchronously */
|
454
494
|
function makeContinuation(name, body) {
|
455
495
|
var ctn = {
|
456
496
|
$continuation: true,
|
457
|
-
type: name?'FunctionDeclaration':'FunctionExpression',
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
497
|
+
type: name ? 'FunctionDeclaration' : 'FunctionExpression',
|
498
|
+
id: name ? typeof name === "string" ? ident(name) : name : undefined,
|
499
|
+
params: [],
|
500
|
+
body: {
|
501
|
+
type: 'BlockStatement',
|
502
|
+
body: cloneNode(body)
|
503
|
+
}
|
464
504
|
};
|
465
505
|
if (name) {
|
466
506
|
continuations[name] = {
|
@@ -469,7 +509,7 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
469
509
|
}
|
470
510
|
return ctn;
|
471
511
|
}
|
472
|
-
|
512
|
+
|
473
513
|
/* Generate an expression AST the immediate invokes the specified async function, e.g.
|
474
514
|
* (await ((async function(){ ...body... })()))
|
475
515
|
*/
|
@@ -487,9 +527,9 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
487
527
|
"body": body
|
488
528
|
}
|
489
529
|
}).body.body[0].argument
|
490
|
-
}
|
530
|
+
};
|
491
531
|
}
|
492
|
-
|
532
|
+
|
493
533
|
/* Used to invoke a 'continuation' - a function that represents
|
494
534
|
* a block of statements lifted out so they can be labelled (as
|
495
535
|
* a function definition) to be invoked via multiple execution
|
@@ -497,20 +537,23 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
497
537
|
* in the original scope of the statements, the continuation function
|
498
538
|
* must also have the correct 'this'.*/
|
499
539
|
function thisCall(name, args) {
|
500
|
-
if (typeof name === 'string')
|
540
|
+
if (typeof name === 'string')
|
501
541
|
name = ident(name);
|
502
|
-
var n =
|
542
|
+
var n = parsePart("$0.call($1)", [name,[{
|
543
|
+
"type": "ThisExpression"
|
544
|
+
}].concat(args || [])]).expr;
|
503
545
|
name.$thisCall = n;
|
504
546
|
n.$thisCallName = name.name;
|
505
547
|
return n;
|
506
548
|
}
|
507
|
-
|
549
|
+
|
550
|
+
function returnThisCall(name, args) {
|
508
551
|
return {
|
509
|
-
type:'ReturnStatement',
|
510
|
-
argument: thisCall(name,args)
|
511
|
-
}
|
552
|
+
type: 'ReturnStatement',
|
553
|
+
argument: thisCall(name, args)
|
554
|
+
};
|
512
555
|
}
|
513
|
-
|
556
|
+
|
514
557
|
function deferredFinally(node, expr) {
|
515
558
|
return {
|
516
559
|
"type": "CallExpression",
|
@@ -518,7 +561,7 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
518
561
|
"arguments": expr ? [expr] : []
|
519
562
|
};
|
520
563
|
}
|
521
|
-
|
564
|
+
|
522
565
|
/**
|
523
566
|
* returnMapper is an Uglify2 transformer that is used to change statements such as:
|
524
567
|
* return some-expression ;
|
@@ -536,8 +579,8 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
536
579
|
});
|
537
580
|
}
|
538
581
|
var lambdaNesting = 0;
|
539
|
-
var tryNesting = 0
|
540
|
-
return
|
582
|
+
var tryNesting = 0;
|
583
|
+
return treeWalk(n, function (node, descend, path) {
|
541
584
|
if (node.type === 'ReturnStatement' && !node.$mapped) {
|
542
585
|
if (lambdaNesting > 0) {
|
543
586
|
if (!examine(node).isAsync) {
|
@@ -571,7 +614,7 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
571
614
|
}
|
572
615
|
return;
|
573
616
|
} else if (node.type === 'ThrowStatement') {
|
574
|
-
var isAsync = examine(node).isAsync
|
617
|
+
var isAsync = examine(node).isAsync;
|
575
618
|
if (lambdaNesting > 0) {
|
576
619
|
if (!isAsync) {
|
577
620
|
return descend(node);
|
@@ -579,22 +622,22 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
579
622
|
delete node.async;
|
580
623
|
}
|
581
624
|
if (!isAsync && tryNesting) {
|
582
|
-
descend()
|
625
|
+
descend();
|
583
626
|
} else {
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
627
|
+
node.type = 'ReturnStatement';
|
628
|
+
node.$mapped = true;
|
629
|
+
node.argument = {
|
630
|
+
type: 'CallExpression',
|
631
|
+
callee: getExit(path, [opts]).$error,
|
632
|
+
arguments: [node.argument]
|
633
|
+
};
|
591
634
|
}
|
592
635
|
return;
|
593
636
|
} else if (node.type === 'TryStatement') {
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
637
|
+
tryNesting++;
|
638
|
+
descend(node);
|
639
|
+
tryNesting--;
|
640
|
+
return;
|
598
641
|
} else if (examine(node).isFunction) {
|
599
642
|
lambdaNesting++;
|
600
643
|
descend(node);
|
@@ -606,7 +649,7 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
606
649
|
}
|
607
650
|
}, path);
|
608
651
|
}
|
609
|
-
|
652
|
+
|
610
653
|
/*
|
611
654
|
To implement conditional execution, a?b:c is mapped to
|
612
655
|
|
@@ -615,21 +658,22 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
615
658
|
Note that 'await (async function(){})()' can be optimized to a Thenable since no args are passed
|
616
659
|
*/
|
617
660
|
function mapCondOp(ast, state) {
|
618
|
-
if (Array.isArray(ast))
|
661
|
+
if (Array.isArray(ast))
|
619
662
|
return ast.map(function (n) {
|
620
663
|
return mapCondOp(n, state);
|
621
664
|
});
|
622
|
-
|
665
|
+
treeWalk(ast, function (node, descend, path) {
|
623
666
|
descend();
|
624
667
|
if (node.type === 'ConditionalExpression' && (containsAwait(node.alternate) || containsAwait(node.consequent))) {
|
625
668
|
var z = ident(generateSymbol("condOp"));
|
626
|
-
var xform = internalIIAFE(
|
669
|
+
var xform = internalIIAFE(parsePart("if ($0) return $1 ; return $2", [node.test,
|
670
|
+
node.consequent,node.alternate]).body);
|
627
671
|
coerce(node, xform);
|
628
672
|
}
|
629
673
|
}, state);
|
630
674
|
return ast;
|
631
675
|
}
|
632
|
-
|
676
|
+
|
633
677
|
/*
|
634
678
|
To implement conditional execution, logical operators with an awaited RHS are mapped thus:
|
635
679
|
|
@@ -639,56 +683,57 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
639
683
|
Note that 'await (async function(){})()' can be optimized to a Thenable since no args are passed
|
640
684
|
*/
|
641
685
|
function mapLogicalOp(ast, state) {
|
642
|
-
if (Array.isArray(ast))
|
686
|
+
if (Array.isArray(ast))
|
643
687
|
return ast.map(function (n) {
|
644
688
|
return mapLogicalOp(n, state);
|
645
689
|
});
|
646
|
-
|
690
|
+
treeWalk(ast, function (node, descend, path) {
|
647
691
|
descend();
|
648
692
|
if (node.type === 'LogicalExpression' && containsAwait(node.right)) {
|
649
693
|
var codeFrag;
|
650
694
|
var z = ident(generateSymbol("logical" + (node.operator === '&&' ? "And" : "Or")));
|
651
|
-
|
652
695
|
if (node.operator === '||') {
|
653
|
-
codeFrag = "var $0; if (!($0 = $1)) {$0 = $2} return $0"
|
696
|
+
codeFrag = "var $0; if (!($0 = $1)) {$0 = $2} return $0";
|
654
697
|
} else if (node.operator === '&&') {
|
655
|
-
codeFrag = "var $0; if ($0 = $1) {$0 = $2} return $0"
|
656
|
-
} else
|
657
|
-
throw new Error(where(node) + "Illegal logical operator: "+node.operator);
|
658
|
-
|
659
|
-
coerce(node, internalIIAFE(parser.part(codeFrag,[z,node.left, node.right]).body));
|
698
|
+
codeFrag = "var $0; if ($0 = $1) {$0 = $2} return $0";
|
699
|
+
} else
|
700
|
+
throw new Error(where(node) + "Illegal logical operator: " + node.operator);
|
701
|
+
coerce(node, internalIIAFE(parsePart(codeFrag, [z,node.left,node.right]).body));
|
660
702
|
}
|
661
703
|
}, state);
|
662
704
|
return ast;
|
663
705
|
}
|
664
|
-
|
706
|
+
|
665
707
|
function mapBlock(block, path, down) {
|
666
708
|
if (block.type !== "SwitchCase" && examine(block).isBlockStatement) {
|
667
|
-
var idx = 0
|
709
|
+
var idx = 0;
|
668
710
|
while (idx < block.body.length) {
|
669
|
-
var node = block.body[idx]
|
711
|
+
var node = block.body[idx];
|
670
712
|
if (node.type !== "SwitchCase" && examine(node).isBlockStatement) {
|
671
|
-
var blockScoped = containsBlockScopedDeclarations(node.body)
|
713
|
+
var blockScoped = containsBlockScopedDeclarations(node.body);
|
672
714
|
if (!blockScoped) {
|
673
|
-
block.body.splice.apply(block.body,[idx,1].concat(node.body));
|
715
|
+
block.body.splice.apply(block.body, [idx,1].concat(node.body));
|
674
716
|
} else {
|
675
717
|
if (containsAwaitInBlock(node)) {
|
676
718
|
var symName = generateSymbol(node);
|
677
719
|
var deferredCode = block.body.splice(idx + 1, block.body.length - (idx + 1));
|
678
720
|
if (deferredCode.length) {
|
679
721
|
var ctn = makeContinuation(symName, deferredCode);
|
680
|
-
delete continuations[symName]
|
722
|
+
delete continuations[symName];
|
681
723
|
node.body.push(returnThisCall(symName));
|
682
|
-
block.body.push(ctn)
|
683
|
-
idx
|
684
|
-
} else
|
685
|
-
|
724
|
+
block.body.push(ctn);
|
725
|
+
idx++;
|
726
|
+
} else
|
727
|
+
idx++;
|
728
|
+
} else
|
729
|
+
idx++;
|
686
730
|
}
|
687
|
-
} else
|
731
|
+
} else
|
732
|
+
idx++;
|
688
733
|
}
|
689
734
|
}
|
690
735
|
}
|
691
|
-
|
736
|
+
|
692
737
|
/*
|
693
738
|
* Translate:
|
694
739
|
if (x) { y; } more... ;
|
@@ -714,12 +759,12 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
714
759
|
var call = returnThisCall(symName);
|
715
760
|
synthBlock.body.push(down(makeContinuation(symName, deferredCode)));
|
716
761
|
[ifStmt.consequent,ifStmt.alternate].forEach(function (cond) {
|
717
|
-
if (!cond)
|
762
|
+
if (!cond)
|
718
763
|
return;
|
719
764
|
var blockEnd;
|
720
|
-
if (!examine(cond).isBlockStatement)
|
765
|
+
if (!examine(cond).isBlockStatement)
|
721
766
|
blockEnd = cond;
|
722
|
-
else
|
767
|
+
else
|
723
768
|
blockEnd = cond.body[cond.body.length - 1];
|
724
769
|
if (!(blockEnd && blockEnd.type === 'ReturnStatement')) {
|
725
770
|
if (!(cond.type === 'BlockStatement')) {
|
@@ -735,7 +780,7 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
735
780
|
});
|
736
781
|
// If both blocks are transformed, the trailing call to $post_if()
|
737
782
|
// can be omitted as it'll be unreachable via a synchronous path
|
738
|
-
if (!(ifStmt.consequent && ifStmt.alternate && ifStmt.consequent.$deferred && ifStmt.alternate.$deferred))
|
783
|
+
if (!(ifStmt.consequent && ifStmt.alternate && ifStmt.consequent.$deferred && ifStmt.alternate.$deferred))
|
739
784
|
synthBlock.body.push(cloneNode(call));
|
740
785
|
}
|
741
786
|
} else {
|
@@ -743,7 +788,7 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
743
788
|
}
|
744
789
|
}
|
745
790
|
}
|
746
|
-
|
791
|
+
|
747
792
|
function mapSwitch(switchStmt, path, down) {
|
748
793
|
if (!switchStmt.$switched && switchStmt.type === 'SwitchStatement' && containsAwait(switchStmt.cases)) {
|
749
794
|
switchStmt.$switched = true;
|
@@ -751,7 +796,7 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
751
796
|
if ('index' in ref) {
|
752
797
|
var j = ref.index + 1;
|
753
798
|
deferredCode = ref.parent[ref.field].splice(j, ref.parent[ref.field].length - j);
|
754
|
-
if (deferredCode.length && deferredCode[deferredCode.length - 1].type === 'BreakStatement')
|
799
|
+
if (deferredCode.length && deferredCode[deferredCode.length - 1].type === 'BreakStatement')
|
755
800
|
ref.parent[ref.field].push(deferredCode.pop());
|
756
801
|
symName = generateSymbol(switchStmt);
|
757
802
|
deferred = returnThisCall(symName);
|
@@ -766,7 +811,7 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
766
811
|
if (containsAwait(caseStmt.consequent)) {
|
767
812
|
var end = caseStmt.consequent[caseStmt.consequent.length - 1];
|
768
813
|
if (end.type === 'BreakStatement') {
|
769
|
-
caseStmt.consequent[caseStmt.consequent.length - 1] = cloneNode(deferred)
|
814
|
+
caseStmt.consequent[caseStmt.consequent.length - 1] = cloneNode(deferred);
|
770
815
|
} else if (end.type === 'ReturnStatement' || end.type === 'ThrowStatement') {} else {
|
771
816
|
// Do nothing - block ends in return or throw
|
772
817
|
logger(where(caseStmt) + "switch-case fall-through not supported - added break. See https://github.com/MatAtBread/nodent#differences-from-the-es7-specification");
|
@@ -777,27 +822,27 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
777
822
|
return true;
|
778
823
|
}
|
779
824
|
}
|
780
|
-
|
825
|
+
|
781
826
|
function isExitStatement(n) {
|
782
|
-
return n.type==='ReturnStatement' || n.type==='ThrowStatement'
|
827
|
+
return n.type === 'ReturnStatement' || n.type === 'ThrowStatement';
|
783
828
|
}
|
829
|
+
|
784
830
|
/* Give unique names to TryCatch blocks */
|
785
|
-
function labelTryCatch(ast,engineMode) {
|
786
|
-
|
831
|
+
function labelTryCatch(ast, engineMode) {
|
832
|
+
treeWalk(ast, function (node, descend, path) {
|
787
833
|
if (node.type === 'TryStatement' && !node.$seh) {
|
788
834
|
if (!examine(path[0].parent).isBlockStatement) {
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
835
|
+
path[0].parent[path[0].field] = {
|
836
|
+
type: 'BlockStatement',
|
837
|
+
body: [node]
|
838
|
+
};
|
793
839
|
}
|
794
840
|
// Every try-catch needs a name, so asyncDefine/asyncAwait knows who's handling errors
|
795
841
|
node.$seh = generateSymbol("Try") + "_";
|
796
|
-
node.$containedAwait =
|
797
|
-
node.$finallyExit = node.finalizer && inAsync(path) &&
|
798
|
-
|
842
|
+
node.$containedAwait = !(!containsAwait(node));
|
843
|
+
node.$finallyExit = node.finalizer && inAsync(path) && !(!contains(node.finalizer.body, isExitStatement));
|
799
844
|
if (node.$containedAwait || node.$finallyExit) {
|
800
|
-
node.$needsMapping = engineMode? !node.$finallyExit : true
|
845
|
+
node.$needsMapping = engineMode ? !node.$finallyExit : true;
|
801
846
|
var parent = getExit(path, [opts]);
|
802
847
|
if (node.finalizer && !node.handler) {
|
803
848
|
// We have a finally, but no 'catch'. Create the default catch clause 'catch(_ex) { throw _ex }'
|
@@ -841,24 +886,24 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
841
886
|
});
|
842
887
|
return ast;
|
843
888
|
}
|
844
|
-
|
845
|
-
function afterDirectives(body,nodes) {
|
846
|
-
for (var i=0;
|
847
|
-
if (examine(body[i]).isDirective)
|
848
|
-
continue
|
849
|
-
body.splice.apply(body,[i,0].concat(nodes))
|
850
|
-
return
|
889
|
+
|
890
|
+
function afterDirectives(body, nodes) {
|
891
|
+
for (var i = 0;i < body.length; i++) {
|
892
|
+
if (examine(body[i]).isDirective)
|
893
|
+
continue;
|
894
|
+
body.splice.apply(body, [i,0].concat(nodes));
|
895
|
+
return;
|
851
896
|
}
|
852
|
-
body.splice.apply(body,[body.length,0].concat(nodes))
|
897
|
+
body.splice.apply(body, [body.length,0].concat(nodes));
|
853
898
|
}
|
854
|
-
|
899
|
+
|
855
900
|
function inAsync(path) {
|
856
|
-
for (var i=0;
|
857
|
-
if (examine(path[i].self).isFunction)
|
858
|
-
|
859
|
-
return false
|
901
|
+
for (var i = 0;i < path.length; i++)
|
902
|
+
if (examine(path[i].self).isFunction)
|
903
|
+
return path[i].self.async || path[i].self.$wasAsync;
|
904
|
+
return false;
|
860
905
|
}
|
861
|
-
|
906
|
+
|
862
907
|
function mapTryCatch(node, path, down) {
|
863
908
|
if (node.$needsMapping) {
|
864
909
|
var continuation, ctnName, catchBody;
|
@@ -867,11 +912,10 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
867
912
|
var i = ref.index + 1;
|
868
913
|
var afterTry = ref.parent[ref.field].splice(i, ref.parent[ref.field].length - i);
|
869
914
|
if (afterTry.length) {
|
870
|
-
ctnName = node.$seh + "Post";
|
871
|
-
var afterContinuation = down(makeBoundFn(ctnName, afterTry, [], getExit(path, [opts]).$error));
|
872
|
-
ref.parent[ref.field].splice(ref.index,0,afterContinuation);
|
873
|
-
continuation =
|
874
|
-
[node.finalizer ? deferredFinally(node, ident(ctnName)) : ident(ctnName)]).body[0] ;
|
915
|
+
ctnName = ident(node.$seh + "Post") ;
|
916
|
+
var afterContinuation = down(makeBoundFn(ctnName.name, afterTry, [], getExit(path, [opts]).$error));
|
917
|
+
ref.parent[ref.field].splice(ref.index, 0, afterContinuation);
|
918
|
+
continuation = parsePart("return $0()", [node.finalizer ? deferredFinally(node, ctnName) : ctnName]).body[0];
|
875
919
|
} else if (node.finalizer) {
|
876
920
|
continuation = returnThisCall(deferredFinally(node));
|
877
921
|
}
|
@@ -887,28 +931,27 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
887
931
|
if (node.handler) {
|
888
932
|
var symCatch = ident(node.$seh + "Catch");
|
889
933
|
catchBody = cloneNode(node.handler.body);
|
934
|
+
down(catchBody);
|
890
935
|
var catcher = makeBoundFn(symCatch.name, catchBody, [cloneNode(node.handler.param)], node.finalizer ? deferredFinally(node, binding.$error) : binding.$error);
|
891
936
|
node.handler.body.body = [{
|
892
937
|
type: 'CallExpression',
|
893
938
|
callee: symCatch,
|
894
939
|
arguments: [cloneNode(node.handler.param)]
|
895
940
|
}];
|
896
|
-
ref.parent[ref.field].splice(ref.index,0,catcher)
|
941
|
+
ref.parent[ref.field].splice(ref.index, 0, catcher);
|
897
942
|
}
|
898
943
|
if (node.finalizer) {
|
899
|
-
down(node.finalizer)
|
944
|
+
down(node.finalizer);
|
900
945
|
var finalParams = {
|
901
|
-
exit:ident(node.$seh + "Exit"),
|
902
|
-
value:ident(node.$seh + "Value"),
|
903
|
-
body:cloneNode(node.finalizer.body)
|
904
|
-
}
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
" })",finalParams).expr ;
|
911
|
-
|
946
|
+
exit: ident(node.$seh + "Exit"),
|
947
|
+
value: ident(node.$seh + "Value"),
|
948
|
+
body: cloneNode(node.finalizer.body)
|
949
|
+
};
|
950
|
+
var chainFinalize = parsePart(
|
951
|
+
"(function ($value) { " +
|
952
|
+
" $:body; " +
|
953
|
+
" return $exit && ($exit.call(this, $value)); " +
|
954
|
+
"})", finalParams).expr;
|
912
955
|
var finalizer = {
|
913
956
|
type: 'VariableDeclaration',
|
914
957
|
kind: 'var',
|
@@ -916,41 +959,38 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
916
959
|
type: "VariableDeclarator",
|
917
960
|
id: ident(node.$seh + "Finally"),
|
918
961
|
init: bindAsync({
|
919
|
-
type:'FunctionExpression',
|
920
|
-
params:[finalParams.exit],
|
921
|
-
id:null,
|
922
|
-
body:{
|
923
|
-
type:'BlockStatement',
|
924
|
-
body:[{
|
962
|
+
type: 'FunctionExpression',
|
963
|
+
params: [finalParams.exit],
|
964
|
+
id: null,
|
965
|
+
body: {
|
966
|
+
type: 'BlockStatement',
|
967
|
+
body: [{
|
925
968
|
type: 'ReturnStatement',
|
926
|
-
argument: bindAsync(chainFinalize,binding.$error)
|
969
|
+
argument: bindAsync(chainFinalize, binding.$error)
|
927
970
|
}]
|
928
971
|
}
|
929
972
|
})
|
930
973
|
}]
|
931
|
-
}
|
932
|
-
|
933
|
-
|
934
|
-
var callFinally = parser.part("return $0()",
|
935
|
-
[node.finalizer ? deferredFinally(node, ident(ctnName)) : ident(ctnName)]).body[0] ;
|
974
|
+
};
|
975
|
+
afterDirectives(ref.parent[ref.field], [finalizer]);
|
976
|
+
var callFinally = cloneNode(continuation) ;//parsePart("return $0()", [node.finalizer ? deferredFinally(node, ctnName) : ctnName]).body[0];
|
936
977
|
catchBody.body[catchBody.length - 1] = callFinally;
|
937
978
|
node.block.body[node.block.body.length - 1] = callFinally;
|
938
979
|
delete node.finalizer;
|
939
980
|
}
|
940
981
|
}
|
941
982
|
}
|
942
|
-
|
983
|
+
|
943
984
|
function walkDown(ast, mappers, state) {
|
944
985
|
var walked = [];
|
945
|
-
|
946
|
-
|
947
|
-
return parser.treeWalker(ast, function (node, descend, path) {
|
986
|
+
function closedWalk(ast, state) {
|
987
|
+
return treeWalk(ast, function (node, descend, path) {
|
948
988
|
function walkDownSubtree(node) {
|
949
989
|
return closedWalk(node, path);
|
950
990
|
}
|
951
|
-
|
991
|
+
|
952
992
|
if (walked.indexOf(node) < 0) {
|
953
|
-
walked.push(node)
|
993
|
+
walked.push(node);
|
954
994
|
mappers.forEach(function (m) {
|
955
995
|
m(node, path, walkDownSubtree);
|
956
996
|
});
|
@@ -959,20 +999,20 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
959
999
|
return;
|
960
1000
|
}, state);
|
961
1001
|
}
|
962
|
-
|
963
|
-
closedWalk(ast,state)
|
964
|
-
return ast
|
1002
|
+
|
1003
|
+
closedWalk(ast, state);
|
1004
|
+
return ast;
|
965
1005
|
}
|
966
|
-
|
1006
|
+
|
967
1007
|
function asyncAwait(ast, inAsync, parentCatcher) {
|
968
|
-
|
1008
|
+
treeWalk(ast, function (node, descend, path) {
|
969
1009
|
if (node.type == 'IfStatement') {
|
970
|
-
if (node.consequent.type != 'BlockStatement' && containsAwait(node.consequent))
|
1010
|
+
if (node.consequent.type != 'BlockStatement' && containsAwait(node.consequent))
|
971
1011
|
node.consequent = {
|
972
1012
|
type: 'BlockStatement',
|
973
1013
|
body: [node.consequent]
|
974
1014
|
};
|
975
|
-
if (node.alternate && node.alternate.type != 'BlockStatement' && containsAwait(node.alternate))
|
1015
|
+
if (node.alternate && node.alternate.type != 'BlockStatement' && containsAwait(node.alternate))
|
976
1016
|
node.alternate = {
|
977
1017
|
type: 'BlockStatement',
|
978
1018
|
body: [node.alternate]
|
@@ -989,9 +1029,9 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
989
1029
|
});
|
990
1030
|
if (!inAsync || inAsync === "warn") {
|
991
1031
|
var errMsg = where(node) + "'await' used inside non-async function. ";
|
992
|
-
if (opts.promises)
|
1032
|
+
if (opts.promises)
|
993
1033
|
errMsg += "'return' value Promise runtime-specific";
|
994
|
-
else
|
1034
|
+
else
|
995
1035
|
errMsg += "'return' value from await is synchronous";
|
996
1036
|
logger(errMsg + ". See https://github.com/MatAtBread/nodent#differences-from-the-es7-specification");
|
997
1037
|
}
|
@@ -1013,7 +1053,7 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1013
1053
|
break;
|
1014
1054
|
}
|
1015
1055
|
}
|
1016
|
-
if (!stmt)
|
1056
|
+
if (!stmt)
|
1017
1057
|
throw new Error(where(node) + "Illegal await not contained in a statement");
|
1018
1058
|
var containingExits = getExit(path, [parentCatcher,opts]);
|
1019
1059
|
var i = stmt.index;
|
@@ -1036,7 +1076,7 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1036
1076
|
}, inAsync, containingExits)
|
1037
1077
|
};
|
1038
1078
|
} else {
|
1039
|
-
if (callBack.length)
|
1079
|
+
if (callBack.length)
|
1040
1080
|
callback = {
|
1041
1081
|
type: 'FunctionExpression',
|
1042
1082
|
params: [cloneNode(result)],
|
@@ -1059,7 +1099,7 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1059
1099
|
// Wrap the callback statement(s) in a Block and transform them
|
1060
1100
|
if (!returner) {
|
1061
1101
|
if (callback) {
|
1062
|
-
returner = bindAsync(callback,containingExits.$error)
|
1102
|
+
returner = bindAsync(callback, containingExits.$error);
|
1063
1103
|
} else {
|
1064
1104
|
returner = {
|
1065
1105
|
type: 'FunctionExpression',
|
@@ -1075,11 +1115,11 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1075
1115
|
expr = {
|
1076
1116
|
type: 'CallExpression',
|
1077
1117
|
arguments: [expr],
|
1078
|
-
callee:
|
1118
|
+
callee: opts.promises || opts.generators ? {
|
1079
1119
|
type: 'MemberExpression',
|
1080
|
-
object:
|
1120
|
+
object: genIdent.Promise,
|
1081
1121
|
property: ident('resolve')
|
1082
|
-
}:{
|
1122
|
+
} : {
|
1083
1123
|
// ES7 makeThenable
|
1084
1124
|
type: 'MemberExpression',
|
1085
1125
|
object: ident('Object'),
|
@@ -1107,30 +1147,28 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1107
1147
|
});
|
1108
1148
|
return ast;
|
1109
1149
|
}
|
1110
|
-
|
1150
|
+
|
1111
1151
|
// Transform a for..in into it's iterative equivalent
|
1112
1152
|
function transformForIn(node, path) {
|
1113
|
-
var label = node.$label
|
1114
|
-
delete node.$label
|
1115
|
-
|
1116
|
-
var idx = ident(generateSymbol("idx"))
|
1153
|
+
var label = node.$label;
|
1154
|
+
delete node.$label;
|
1155
|
+
var idx = ident(generateSymbol("idx"));
|
1117
1156
|
var inArray = ident(generateSymbol("in"));
|
1118
|
-
var declVars =
|
1119
|
-
|
1120
|
-
|
1121
|
-
inArray,
|
1122
|
-
node.
|
1123
|
-
|
1124
|
-
|
1125
|
-
for (var b=0; b<path.length; b++) {
|
1157
|
+
var declVars = parsePart("var $0,$1 = [];for ($0 in $2) $1.push($0)", [idx,
|
1158
|
+
inArray,node.right]).body;
|
1159
|
+
var loop = parsePart("for ($0; $1.length;){ $2 = $1.shift(); $:3 ; }", [node.left,
|
1160
|
+
inArray,node.left.type === 'VariableDeclaration' ? node.left.declarations[0].id : node.left,
|
1161
|
+
node.body]).body[0];
|
1162
|
+
loop.$label = label;
|
1163
|
+
for (var b = 0;b < path.length; b++) {
|
1126
1164
|
if (examine(path[b].parent).isBlockStatement) {
|
1127
|
-
path[b].parent[path[b].field].splice(path[b].index,0,declVars[0],declVars[1])
|
1128
|
-
break
|
1165
|
+
path[b].parent[path[b].field].splice(path[b].index, 0, declVars[0], declVars[1]);
|
1166
|
+
break;
|
1129
1167
|
}
|
1130
1168
|
}
|
1131
|
-
coerce(node,loop)
|
1169
|
+
coerce(node, loop);
|
1132
1170
|
}
|
1133
|
-
|
1171
|
+
|
1134
1172
|
// Transform a for..of into it's iterative equivalent
|
1135
1173
|
function iterizeForOf(node, path) {
|
1136
1174
|
if (node.body.type !== 'BlockStatement') {
|
@@ -1139,22 +1177,23 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1139
1177
|
body: [node.body]
|
1140
1178
|
};
|
1141
1179
|
}
|
1142
|
-
var index, iterator, initIterator =
|
1143
|
-
|
1180
|
+
var index, iterator, initIterator = parsePart("[$0[Symbol.iterator]()]", [node.right]).expr;
|
1144
1181
|
if (node.left.type === 'VariableDeclaration') {
|
1145
|
-
if (node.left.kind==='const')
|
1146
|
-
node.left.kind = 'let'
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
1182
|
+
if (node.left.kind === 'const')
|
1183
|
+
node.left.kind = 'let';
|
1184
|
+
if (node.left.kind === 'let') {
|
1185
|
+
node.update = literal(null) ;
|
1186
|
+
node.update.$EmptyExpression = true ;
|
1187
|
+
}
|
1188
|
+
index = node.left.declarations[0].id;
|
1189
|
+
var decls = getDeclNames(node.left.declarations[0].id);
|
1150
1190
|
iterator = ident(generateSymbol("iterator_" + decls.join('_')));
|
1151
|
-
|
1152
|
-
node.left.declarations = decls.map(function(name){
|
1191
|
+
node.left.declarations = decls.map(function (name) {
|
1153
1192
|
return {
|
1154
1193
|
type: "VariableDeclarator",
|
1155
1194
|
id: ident(name)
|
1156
|
-
}
|
1157
|
-
})
|
1195
|
+
};
|
1196
|
+
});
|
1158
1197
|
node.left.declarations.push({
|
1159
1198
|
type: "VariableDeclarator",
|
1160
1199
|
id: iterator,
|
@@ -1176,282 +1215,276 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1176
1215
|
node.init = declaration;
|
1177
1216
|
}
|
1178
1217
|
node.type = 'ForStatement';
|
1179
|
-
node.test =
|
1218
|
+
node.test = parsePart("!($0[1] = $0[0].next()).done && (($1 = $0[1].value) || true)", [iterator,
|
1219
|
+
index]).expr;
|
1180
1220
|
delete node.left;
|
1181
1221
|
delete node.right;
|
1182
1222
|
}
|
1183
|
-
|
1223
|
+
|
1184
1224
|
/* Map loops */
|
1185
1225
|
/* As of v3.0.0 loops are asynchronized via a trampoline to prevent stack overflow in big loops with no actionable awaits. */
|
1186
1226
|
function mapLoops(node, path, down) {
|
1187
|
-
var depth = node.$depth
|
1227
|
+
var depth = node.$depth;
|
1188
1228
|
if (node.type === 'ForInStatement' && containsAwait(node)) {
|
1189
|
-
|
1229
|
+
transformForIn(node, path);
|
1190
1230
|
} else if (node.type === 'ForOfStatement' && containsAwait(node)) {
|
1191
|
-
|
1231
|
+
iterizeForOf(node, path);
|
1192
1232
|
}
|
1193
|
-
|
1194
1233
|
// Are we inside a loop that has already been asynchronized and is labelled?
|
1195
|
-
var inAsyncLoop = path.some(function(p){
|
1196
|
-
return
|
1197
|
-
})
|
1198
|
-
|
1234
|
+
var inAsyncLoop = path.some(function (p) {
|
1235
|
+
return '$label' in p.self && p.self.type === 'ForStatement' && p.self.$mapped;
|
1236
|
+
});
|
1199
1237
|
// Check if the loop contains an await, or a labelled exit if we're inside an async loop
|
1200
|
-
function mappableLoop(n){
|
1201
|
-
return
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
1219
|
-
|
1220
|
-
|
1221
|
-
|
1222
|
-
if (
|
1223
|
-
|
1224
|
-
|
1225
|
-
|
1226
|
-
|
1227
|
-
|
1228
|
-
|
1229
|
-
|
1230
|
-
|
1231
|
-
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1241
|
-
|
1242
|
-
|
1243
|
-
|
1244
|
-
|
1245
|
-
|
1246
|
-
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1250
|
-
|
1251
|
-
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1257
|
-
|
1258
|
-
|
1259
|
-
"
|
1260
|
-
|
1261
|
-
|
1262
|
-
|
1263
|
-
|
1264
|
-
|
1265
|
-
|
1266
|
-
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1270
|
-
|
1271
|
-
|
1272
|
-
|
1273
|
-
|
1274
|
-
|
1275
|
-
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1279
|
-
|
1280
|
-
|
1281
|
-
|
1282
|
-
|
1283
|
-
|
1284
|
-
|
1285
|
-
|
1286
|
-
|
1287
|
-
|
1288
|
-
|
1289
|
-
|
1290
|
-
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1294
|
-
|
1295
|
-
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1302
|
-
|
1303
|
-
|
1304
|
-
|
1305
|
-
|
1306
|
-
|
1307
|
-
|
1308
|
-
|
1309
|
-
|
1310
|
-
|
1311
|
-
|
1312
|
-
|
1313
|
-
|
1314
|
-
|
1315
|
-
|
1316
|
-
|
1317
|
-
|
1318
|
-
|
1319
|
-
|
1320
|
-
|
1321
|
-
|
1322
|
-
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1326
|
-
|
1327
|
-
|
1328
|
-
|
1329
|
-
|
1330
|
-
}
|
1331
|
-
|
1332
|
-
|
1333
|
-
|
1334
|
-
|
1335
|
-
|
1336
|
-
|
1337
|
-
|
1338
|
-
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
1342
|
-
|
1343
|
-
|
1344
|
-
|
1345
|
-
|
1346
|
-
|
1347
|
-
|
1348
|
-
|
1349
|
-
|
1350
|
-
|
1351
|
-
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1360
|
-
|
1361
|
-
|
1362
|
-
|
1363
|
-
|
1364
|
-
|
1365
|
-
|
1366
|
-
|
1367
|
-
|
1368
|
-
|
1369
|
-
|
1370
|
-
|
1371
|
-
|
1372
|
-
|
1373
|
-
|
1374
|
-
|
1375
|
-
|
1376
|
-
|
1377
|
-
|
1378
|
-
|
1379
|
-
|
1380
|
-
|
1381
|
-
|
1382
|
-
|
1383
|
-
|
1384
|
-
|
1385
|
-
|
1386
|
-
|
1387
|
-
|
1388
|
-
|
1389
|
-
|
1390
|
-
|
1391
|
-
" } catch (_exception) { "+
|
1392
|
-
" return $exit(_exception); "+
|
1393
|
-
" } "+
|
1394
|
-
" } "+
|
1395
|
-
"}).bind(this))($idIter)",
|
1238
|
+
function mappableLoop(n) {
|
1239
|
+
return n.type === 'AwaitExpression' && !n.$hidden || inAsyncLoop && (n.type === 'BreakStatement' || n.type === 'ContinueStatement') && n.label;
|
1240
|
+
}
|
1241
|
+
|
1242
|
+
if (!node.$mapped && examine(node).isLoop && contains(node, mappableLoop)) {
|
1243
|
+
path[0].self.$mapped = true;
|
1244
|
+
var p;
|
1245
|
+
var mapped = [];
|
1246
|
+
var init = node.init;
|
1247
|
+
var test = node.test || literal(true);
|
1248
|
+
var step = node.update;
|
1249
|
+
var body = node.body;
|
1250
|
+
var localised = init && init.type === 'VariableDeclaration' && (init.kind === 'let' || init.kind === 'const');
|
1251
|
+
if (localised) {
|
1252
|
+
init.kind = 'let';
|
1253
|
+
}
|
1254
|
+
if (step) {
|
1255
|
+
step = {
|
1256
|
+
type: 'ExpressionStatement',
|
1257
|
+
expression: step
|
1258
|
+
};
|
1259
|
+
}
|
1260
|
+
if (init) {
|
1261
|
+
if (!examine(init).isStatement) {
|
1262
|
+
init = {
|
1263
|
+
type: 'ExpressionStatement',
|
1264
|
+
expression: init
|
1265
|
+
};
|
1266
|
+
}
|
1267
|
+
if (!localised)
|
1268
|
+
mapped.push(init);
|
1269
|
+
}
|
1270
|
+
var ref, label;
|
1271
|
+
if (node.$label) {
|
1272
|
+
label = node.$label.name;
|
1273
|
+
ref = path[1];
|
1274
|
+
} else {
|
1275
|
+
label = generatedSymbol++;
|
1276
|
+
ref = path[0];
|
1277
|
+
}
|
1278
|
+
label = opts.generatedSymbolPrefix + "Loop_" + label;
|
1279
|
+
var idLocal = localised ? ident(label + "_local"):null ;
|
1280
|
+
var idTrampoline = ident(label + "_trampoline");
|
1281
|
+
var idIter = ident(label);
|
1282
|
+
var idStep = step ? ident(label + "_step") : idIter;
|
1283
|
+
var idContinuation = ident(label + "_exit");
|
1284
|
+
var idBounce = ident("q");
|
1285
|
+
var idCatchParam = ident("$exception");
|
1286
|
+
var continuation, deferredCode;
|
1287
|
+
if ('index' in ref) {
|
1288
|
+
var idx = ref.index;
|
1289
|
+
deferredCode = ref.parent[ref.field].splice(idx + 1, ref.parent[ref.field].length - (idx + 1));
|
1290
|
+
} else {
|
1291
|
+
deferredCode = [];
|
1292
|
+
}
|
1293
|
+
continuation = makeContinuation(idContinuation, deferredCode);
|
1294
|
+
var initIter = localised ? parsePart("$0.bind(this,$1)", [idIter,init ? init.declarations.map(function (d) {
|
1295
|
+
return d && d.init ? d.init : ident("undefined");
|
1296
|
+
}) : []]).expr : idIter;
|
1297
|
+
var returnStep = parsePart("return $0", [idStep]).body[0];
|
1298
|
+
var returnBreak = {
|
1299
|
+
type: 'ReturnStatement',
|
1300
|
+
argument: {
|
1301
|
+
"type": "ArrayExpression",
|
1302
|
+
"elements": [literal(1)]
|
1303
|
+
}
|
1304
|
+
};
|
1305
|
+
treeWalk(body, function mapExits(n, descend, subpath) {
|
1306
|
+
if (examine(n).isFunction || examine(n).isLoop) {
|
1307
|
+
return true;
|
1308
|
+
} else if (n.type === 'BreakStatement' || n.type === 'ContinueStatement') {
|
1309
|
+
if (n.label) {
|
1310
|
+
var labelStack = subpath.filter(function (p) {
|
1311
|
+
return '$label' in p.self;
|
1312
|
+
}).map(function (p, idx) {
|
1313
|
+
return p.self.$label && p.self.$label.name;
|
1314
|
+
});
|
1315
|
+
// Work out how many loops to exit by examining subpath.
|
1316
|
+
var loops = [];
|
1317
|
+
for (var l = 0;l < labelStack.length; l++) {
|
1318
|
+
if (labelStack[l] === n.label.name) {
|
1319
|
+
if (n.type === 'BreakStatement')
|
1320
|
+
loops.push(literal(1));
|
1321
|
+
subpath[0].replace({
|
1322
|
+
type: 'ReturnStatement',
|
1323
|
+
argument: {
|
1324
|
+
"type": "ArrayExpression",
|
1325
|
+
"elements": loops.reverse()
|
1326
|
+
}
|
1327
|
+
});
|
1328
|
+
break;
|
1329
|
+
}
|
1330
|
+
loops.push(literal(0));
|
1331
|
+
}
|
1332
|
+
} else {
|
1333
|
+
if (n.type === 'BreakStatement')
|
1334
|
+
subpath[0].replace(returnBreak);
|
1335
|
+
else
|
1336
|
+
subpath[0].replace(returnStep); // continue;
|
1337
|
+
}
|
1338
|
+
} else {
|
1339
|
+
descend();
|
1340
|
+
}
|
1341
|
+
}, path);
|
1342
|
+
if (body.type === 'BlockStatement')
|
1343
|
+
body = body.body.slice(0);
|
1344
|
+
else
|
1345
|
+
body = [body];
|
1346
|
+
if (node.type === 'DoWhileStatement') {
|
1347
|
+
body = body.concat({
|
1348
|
+
"type": "IfStatement",
|
1349
|
+
"test": {
|
1350
|
+
type: 'UnaryExpression',
|
1351
|
+
argument: test,
|
1352
|
+
prefix: true,
|
1353
|
+
operator: '!'
|
1354
|
+
},
|
1355
|
+
"consequent": returnBreak,
|
1356
|
+
alternate: returnStep
|
1357
|
+
});
|
1358
|
+
} else {
|
1359
|
+
body = [{
|
1360
|
+
"type": "IfStatement",
|
1361
|
+
"test": test,
|
1362
|
+
"consequent": {
|
1363
|
+
"type": "BlockStatement",
|
1364
|
+
"body": body.concat(returnStep)
|
1365
|
+
},
|
1366
|
+
alternate: returnBreak
|
1367
|
+
}];
|
1368
|
+
}
|
1369
|
+
var decls = [];
|
1370
|
+
if (opts.noRuntime)
|
1371
|
+
decls.push({
|
1372
|
+
"type": "VariableDeclarator",
|
1373
|
+
"id": idTrampoline
|
1374
|
+
});
|
1375
|
+
if (step && localised)
|
1376
|
+
decls.push({
|
1377
|
+
"type": "VariableDeclarator",
|
1378
|
+
"id": idLocal
|
1379
|
+
});
|
1380
|
+
if (decls.length)
|
1381
|
+
mapped.push({
|
1382
|
+
"type": "VariableDeclaration",
|
1383
|
+
"declarations": decls,
|
1384
|
+
"kind": "var"
|
1385
|
+
});
|
1386
|
+
var invokeIterate;
|
1387
|
+
var exit = getExit(path, [opts]).$error;
|
1388
|
+
if (opts.noRuntime) {
|
1389
|
+
invokeIterate = parsePart(
|
1390
|
+
opts.es6target?
|
1391
|
+
"($idTrampoline = ((q) => { "+
|
1392
|
+
" $$setMapped: while (q) { "+
|
1393
|
+
" if (q.then) "+
|
1394
|
+
(depth===1?
|
1395
|
+
" return void q.then($idTrampoline, $exit); ":
|
1396
|
+
" return q.then($idTrampoline, $exit); ")+
|
1397
|
+
" try { "+
|
1398
|
+
" if (q.pop) "+
|
1399
|
+
" if (q.length) "+
|
1400
|
+
" return q.pop() ? $idContinuation.call(this) : q; "+
|
1401
|
+
" else "+
|
1402
|
+
" q = $idStep; "+
|
1403
|
+
" else "+
|
1404
|
+
" q = q.call(this) "+
|
1405
|
+
" } catch (_exception) { "+
|
1406
|
+
" return $exit(_exception); "+
|
1407
|
+
" } "+
|
1408
|
+
" } "+
|
1409
|
+
"}))($idIter)":
|
1410
|
+
"($idTrampoline = (function (q) { "+
|
1411
|
+
" $$setMapped: while (q) { "+
|
1412
|
+
" if (q.then) "+
|
1413
|
+
(depth===1?
|
1414
|
+
" return void q.then($idTrampoline, $exit); ":
|
1415
|
+
" return q.then($idTrampoline, $exit); ")+
|
1416
|
+
" try { "+
|
1417
|
+
" if (q.pop) "+
|
1418
|
+
" if (q.length) "+
|
1419
|
+
" return q.pop() ? $idContinuation.call(this) : q; "+
|
1420
|
+
" else "+
|
1421
|
+
" q = $idStep; "+
|
1422
|
+
" else "+
|
1423
|
+
" q = q.call(this) "+
|
1424
|
+
" } catch (_exception) { "+
|
1425
|
+
" return $exit(_exception); "+
|
1426
|
+
" } "+
|
1427
|
+
" } "+
|
1428
|
+
"}).bind(this))($idIter)",
|
1396
1429
|
{
|
1397
|
-
|
1398
|
-
|
1399
|
-
|
1400
|
-
|
1401
|
-
|
1402
|
-
|
1403
|
-
|
1404
|
-
|
1405
|
-
|
1406
|
-
|
1407
|
-
|
1408
|
-
|
1409
|
-
|
1410
|
-
|
1411
|
-
|
1412
|
-
|
1413
|
-
|
1414
|
-
|
1415
|
-
|
1416
|
-
|
1417
|
-
|
1418
|
-
|
1419
|
-
|
1420
|
-
|
1421
|
-
|
1422
|
-
|
1423
|
-
|
1424
|
-
|
1425
|
-
|
1426
|
-
|
1427
|
-
|
1428
|
-
|
1429
|
-
|
1430
|
-
|
1431
|
-
|
1432
|
-
|
1433
|
-
|
1434
|
-
|
1435
|
-
|
1436
|
-
|
1437
|
-
|
1438
|
-
|
1439
|
-
|
1440
|
-
|
1441
|
-
|
1442
|
-
|
1443
|
-
|
1444
|
-
|
1445
|
-
|
1446
|
-
|
1447
|
-
|
1448
|
-
|
1430
|
+
setMapped: function (n) {
|
1431
|
+
n.$mapped = true;
|
1432
|
+
return n;
|
1433
|
+
},
|
1434
|
+
idTrampoline: idTrampoline,
|
1435
|
+
exit: exit,
|
1436
|
+
idIter: initIter,
|
1437
|
+
idContinuation: idContinuation,
|
1438
|
+
idStep: idStep
|
1439
|
+
}).expr;
|
1440
|
+
} else {
|
1441
|
+
invokeIterate = parsePart("($0.$1.trampoline(this,$2,$3,$4,$6)($5))", [opts.$runtime ? genIdent.runtime : ident('Function'),
|
1442
|
+
genIdent.asyncbind,idContinuation,idStep,
|
1443
|
+
exit,initIter,literal(depth === 1)]).expr;
|
1444
|
+
}
|
1445
|
+
var iterDecls = init && init.declarations ? init.declarations.map(function (d) {
|
1446
|
+
return d.id;
|
1447
|
+
}) : [];
|
1448
|
+
if (step) {
|
1449
|
+
var stepArgs = {
|
1450
|
+
idIter: idIter,
|
1451
|
+
idStep: idStep,
|
1452
|
+
step: step,
|
1453
|
+
idLocal: idLocal,
|
1454
|
+
decId: iterDecls
|
1455
|
+
};
|
1456
|
+
if (localised) {
|
1457
|
+
stepArgs.iterDecls = iterDecls;
|
1458
|
+
mapped.push(parsePart(step.expression.$EmptyExpression ?
|
1459
|
+
(opts.es6target ? "function $idStep(){ return $idIter.bind(this,...$idLocal()) }" : "function $idStep(){ var [$decId] = $idLocal(); return $idIter.bind(this,$decId) }") :
|
1460
|
+
"function $idStep(){ var [$decId] = $idLocal(); $:step; return $idIter.bind(this,$decId) }", stepArgs).body[0]);
|
1461
|
+
body.unshift(parsePart("$idLocal = function(){ return [$decId] }", stepArgs).body[0]);
|
1462
|
+
} else {
|
1463
|
+
mapped.push(parsePart(step.expression.$EmptyExpression ? "function $idStep(){ return $idIter }" : "function $idStep(){ $:step; return $idIter }", stepArgs).body[0]);
|
1464
|
+
}
|
1465
|
+
}
|
1466
|
+
mapped.push({
|
1467
|
+
$label: node.$label,
|
1468
|
+
"type": "FunctionDeclaration",
|
1469
|
+
"id": idIter,
|
1470
|
+
"params": localised ? iterDecls : [],
|
1471
|
+
"body": {
|
1472
|
+
"type": "BlockStatement",
|
1473
|
+
"body": body
|
1474
|
+
}
|
1475
|
+
});
|
1476
|
+
mapped.push({
|
1477
|
+
type: 'ReturnStatement',
|
1478
|
+
argument: invokeIterate
|
1479
|
+
});
|
1480
|
+
mapped.push(continuation);
|
1481
|
+
path[0].replace(mapped.map(down));
|
1449
1482
|
}
|
1450
1483
|
}
|
1451
|
-
|
1484
|
+
|
1452
1485
|
/* Previous, recursive implementation for backwards compatibility */
|
1453
|
-
function asyncLoops_1(ast,state) {
|
1454
|
-
|
1486
|
+
function asyncLoops_1(ast, state) {
|
1487
|
+
treeWalk(ast, function (node, descend, path) {
|
1455
1488
|
function mapContinue(label) {
|
1456
1489
|
return {
|
1457
1490
|
type: 'ReturnStatement',
|
@@ -1462,7 +1495,9 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1462
1495
|
argument: thisCall(label || symContinue)
|
1463
1496
|
}
|
1464
1497
|
};
|
1465
|
-
}
|
1498
|
+
}
|
1499
|
+
|
1500
|
+
;
|
1466
1501
|
function mapExits(n, descend) {
|
1467
1502
|
if (n.type === 'BreakStatement') {
|
1468
1503
|
coerce(n, cloneNode(mapBreak(n.label && opts.generatedSymbolPrefix + "Loop_" + n.label.name + "_exit")));
|
@@ -1473,9 +1508,9 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1473
1508
|
}
|
1474
1509
|
descend();
|
1475
1510
|
}
|
1476
|
-
|
1511
|
+
|
1477
1512
|
if (node.type === 'ForInStatement' && containsAwait(node)) {
|
1478
|
-
transformForIn(node, path)
|
1513
|
+
transformForIn(node, path);
|
1479
1514
|
} else if (node.type === 'ForOfStatement' && containsAwait(node)) {
|
1480
1515
|
iterizeForOf(node, path);
|
1481
1516
|
}
|
@@ -1486,7 +1521,7 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1486
1521
|
var condition = node.test || literal(true);
|
1487
1522
|
var step = node.update;
|
1488
1523
|
var body = node.body;
|
1489
|
-
var loopUsesThis = containsThis(body)
|
1524
|
+
var loopUsesThis = containsThis(body);
|
1490
1525
|
if (init) {
|
1491
1526
|
if (!examine(init).isStatement) {
|
1492
1527
|
init = {
|
@@ -1498,13 +1533,13 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1498
1533
|
step = step && {
|
1499
1534
|
type: 'ExpressionStatement',
|
1500
1535
|
expression: step
|
1501
|
-
}
|
1536
|
+
};
|
1502
1537
|
body = examine(body).isBlockStatement ? cloneNode(body).body : [cloneNode(body)];
|
1503
|
-
var label = node.$label && node.$label.name
|
1538
|
+
var label = node.$label && node.$label.name;
|
1504
1539
|
label = "Loop_" + (label || generatedSymbol++);
|
1505
1540
|
var symExit = opts.generatedSymbolPrefix + (label + "_exit");
|
1506
1541
|
var symContinue = opts.generatedSymbolPrefix + (label + "_next");
|
1507
|
-
var loop = ident(opts.generatedSymbolPrefix +
|
1542
|
+
var loop = ident(opts.generatedSymbolPrefix + label);
|
1508
1543
|
// How to exit the loop
|
1509
1544
|
var mapBreak = function (label) {
|
1510
1545
|
return {
|
@@ -1521,20 +1556,19 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1521
1556
|
}
|
1522
1557
|
};
|
1523
1558
|
};
|
1524
|
-
|
1525
1559
|
// How to continue the loop
|
1526
1560
|
var defContinue = makeContinuation(symContinue, [{
|
1527
1561
|
type: 'ReturnStatement',
|
1528
1562
|
argument: {
|
1529
1563
|
type: 'CallExpression',
|
1530
|
-
callee: loopUsesThis? bindAsync(loop):loop,
|
1564
|
+
callee: loopUsesThis ? bindAsync(loop) : loop,
|
1531
1565
|
arguments: [ident(symExit),genIdent.error]
|
1532
1566
|
}
|
1533
1567
|
}]);
|
1534
|
-
if (step)
|
1568
|
+
if (step)
|
1535
1569
|
defContinue.body.body.unshift(step);
|
1536
1570
|
for (var i = 0;i < body.length; i++) {
|
1537
|
-
|
1571
|
+
treeWalk(body[i], mapExits);
|
1538
1572
|
}
|
1539
1573
|
body.push(cloneNode(mapContinue()));
|
1540
1574
|
var subCall = {
|
@@ -1583,17 +1617,15 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1583
1617
|
argument: bindAsync(subCall, literal(0))
|
1584
1618
|
}
|
1585
1619
|
};
|
1586
|
-
|
1587
|
-
|
1588
|
-
|
1589
|
-
init.kind = 'let' ;
|
1620
|
+
if (init && init.type === 'VariableDeclaration' && (init.kind === 'let' || init.kind === 'const')) {
|
1621
|
+
if (init.kind === 'const')
|
1622
|
+
init.kind = 'let';
|
1590
1623
|
replace = {
|
1591
|
-
type:'BlockStatement',
|
1592
|
-
body:[cloneNode(init),replace]
|
1624
|
+
type: 'BlockStatement',
|
1625
|
+
body: [cloneNode(init),replace]
|
1593
1626
|
};
|
1594
|
-
init = null
|
1627
|
+
init = null;
|
1595
1628
|
}
|
1596
|
-
|
1597
1629
|
for (p = 0; p < path.length; p++) {
|
1598
1630
|
var ref = path[p];
|
1599
1631
|
if ('index' in ref) {
|
@@ -1607,29 +1639,27 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1607
1639
|
}
|
1608
1640
|
}
|
1609
1641
|
return true;
|
1610
|
-
},state);
|
1642
|
+
}, state);
|
1611
1643
|
return ast;
|
1612
1644
|
}
|
1613
|
-
|
1645
|
+
|
1614
1646
|
function containsAsyncExit(fn) {
|
1615
1647
|
if (!examine(fn).isFunction) {
|
1616
|
-
throw new Error("Cannot examine non-Function node types for async exits")
|
1648
|
+
throw new Error("Cannot examine non-Function node types for async exits");
|
1617
1649
|
}
|
1618
|
-
|
1619
|
-
|
1620
|
-
|
1621
|
-
|
1622
|
-
}
|
1623
|
-
return !(examine(node).isFunction && (node.$wasAsync || examine(node).isAsync)) ;
|
1624
|
-
}) ;
|
1650
|
+
return contains(fn.body, function (node) {
|
1651
|
+
return node.type === 'Identifier' && (node.name === opts.$return || node.name === opts.$error) || isExitStatement(node) && examine(node).isAsync;
|
1652
|
+
}, function (node) {
|
1653
|
+
return !(examine(node).isFunction && (node.$wasAsync || examine(node).isAsync));
|
1654
|
+
});
|
1625
1655
|
}
|
1626
|
-
|
1656
|
+
|
1627
1657
|
// TODO: Hoist directives (as in asyncDefine)
|
1628
1658
|
function asyncDefineMethod(ast) {
|
1629
|
-
return
|
1659
|
+
return treeWalk(ast, function (node, descend, path) {
|
1630
1660
|
var transform = getMemberFunction(node);
|
1631
1661
|
descend();
|
1632
|
-
if (!transform || !examine(transform).isAsync)
|
1662
|
+
if (!transform || !examine(transform).isAsync)
|
1633
1663
|
return;
|
1634
1664
|
if (node.kind == 'set') {
|
1635
1665
|
var ex = new SyntaxError(where(transform) + "method 'async set' cannot be invoked", pr.filename, node.start);
|
@@ -1637,7 +1667,6 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1637
1667
|
ex.loc = node.loc.start;
|
1638
1668
|
throw ex;
|
1639
1669
|
}
|
1640
|
-
|
1641
1670
|
transform.async = false;
|
1642
1671
|
var usesArgs = replaceArguments(transform);
|
1643
1672
|
if (!containsAsyncExit(transform) && (transform.body.body.length === 0 || transform.body.body[transform.body.body.length - 1].type !== 'ReturnStatement')) {
|
@@ -1646,12 +1675,11 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1646
1675
|
});
|
1647
1676
|
}
|
1648
1677
|
var funcback = bindAsync(setExit({
|
1649
|
-
|
1650
|
-
|
1651
|
-
|
1652
|
-
|
1653
|
-
|
1654
|
-
|
1678
|
+
type: 'FunctionExpression',
|
1679
|
+
params: [genIdent.return,genIdent.error],
|
1680
|
+
body: asyncDefineMethod(mapReturns(transform.body, path)),
|
1681
|
+
$wasAsync: true
|
1682
|
+
}, opts), opts.promises || opts.generators || opts.engine ? null : literal(opts.lazyThenables ? 0 : true));
|
1655
1683
|
if (opts.promises) {
|
1656
1684
|
transform.body = {
|
1657
1685
|
type: 'BlockStatement',
|
@@ -1659,7 +1687,7 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1659
1687
|
type: 'ReturnStatement',
|
1660
1688
|
argument: {
|
1661
1689
|
type: 'NewExpression',
|
1662
|
-
callee:
|
1690
|
+
callee: genIdent.Promise,
|
1663
1691
|
arguments: [funcback]
|
1664
1692
|
}
|
1665
1693
|
}]
|
@@ -1674,30 +1702,29 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1674
1702
|
};
|
1675
1703
|
}
|
1676
1704
|
if (usesArgs) {
|
1677
|
-
afterDirectives(transform.body.body,[assign$Args]);
|
1705
|
+
afterDirectives(transform.body.body, [assign$Args]);
|
1678
1706
|
}
|
1679
1707
|
});
|
1680
1708
|
}
|
1681
|
-
|
1709
|
+
|
1682
1710
|
function asyncDefine(ast) {
|
1683
|
-
|
1711
|
+
treeWalk(ast, function (node, descend, path) {
|
1684
1712
|
descend();
|
1685
1713
|
if (examine(node).isAsync && examine(node).isFunction) {
|
1686
|
-
var member
|
1687
|
-
if ((member = getMemberFunction(path[0].parent))
|
1688
|
-
|
1689
|
-
warnAsyncGetter(path[0].parent.key) ;
|
1714
|
+
var member;
|
1715
|
+
if ((member = getMemberFunction(path[0].parent)) && examine(member).isAsync && path[0].parent.kind === 'get') {
|
1716
|
+
warnAsyncGetter(path[0].parent.key);
|
1690
1717
|
}
|
1691
1718
|
delete node.async;
|
1692
|
-
|
1693
1719
|
var usesArgs = replaceArguments(node);
|
1694
1720
|
var fnBody = setExit({
|
1695
1721
|
type: 'FunctionExpression',
|
1696
1722
|
params: [genIdent.return,genIdent.error],
|
1697
1723
|
$wasAsync: true
|
1698
|
-
}, opts)
|
1699
|
-
var thisPath = [{
|
1700
|
-
|
1724
|
+
}, opts);
|
1725
|
+
var thisPath = [{
|
1726
|
+
self: fnBody
|
1727
|
+
}].concat(path);
|
1701
1728
|
if (examine(node.body).isBlockStatement) {
|
1702
1729
|
if (!containsAsyncExit(node) && (node.body.body.length === 0 || node.body.body[node.body.body.length - 1].type !== 'ReturnStatement')) {
|
1703
1730
|
node.body.body.push({
|
@@ -1720,13 +1747,11 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1720
1747
|
};
|
1721
1748
|
node.expression = false;
|
1722
1749
|
}
|
1723
|
-
|
1724
|
-
fnBody = bindAsync(fnBody,(opts.promises || opts.generators || opts.engine) ? null : literal(opts.lazyThenables?0:true)) ;
|
1725
|
-
|
1750
|
+
fnBody = bindAsync(fnBody, opts.promises || opts.generators || opts.engine ? null : literal(opts.lazyThenables ? 0 : true));
|
1726
1751
|
if (opts.promises) {
|
1727
1752
|
fnBody = {
|
1728
1753
|
type: 'NewExpression',
|
1729
|
-
callee:
|
1754
|
+
callee: genIdent.Promise,
|
1730
1755
|
arguments: [fnBody]
|
1731
1756
|
};
|
1732
1757
|
}
|
@@ -1738,20 +1763,22 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1738
1763
|
argument: fnBody
|
1739
1764
|
}]
|
1740
1765
|
};
|
1741
|
-
if (usesArgs)
|
1742
|
-
afterDirectives(fnBody.body,[assign$Args]);
|
1766
|
+
if (usesArgs)
|
1767
|
+
afterDirectives(fnBody.body, [assign$Args]);
|
1743
1768
|
node.body = fnBody;
|
1744
1769
|
return;
|
1745
1770
|
}
|
1746
1771
|
});
|
1747
1772
|
return ast;
|
1748
1773
|
}
|
1749
|
-
|
1774
|
+
|
1750
1775
|
/*
|
1751
1776
|
* Rewrite
|
1752
1777
|
async function <name>?<argumentlist><body>
|
1753
1778
|
to
|
1754
|
-
function <name>?<argumentlist>{ return function*() {<body>}.$asyncspawn(); }
|
1779
|
+
function <name>?<argumentlist>{ return function*() {<body>}.$asyncspawn(Promise,this); }
|
1780
|
+
or if the $runtime is set:
|
1781
|
+
$runtime.$asyncspawn.call(function <name>?<argumentlist>{ return function*() {<body>},Promise,this); }
|
1755
1782
|
*/
|
1756
1783
|
// Like mapReturns, but ONLY for return/throw async
|
1757
1784
|
function mapAsyncReturns(ast) {
|
@@ -1759,7 +1786,7 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1759
1786
|
return ast.map(mapAsyncReturns);
|
1760
1787
|
}
|
1761
1788
|
var lambdaNesting = 0;
|
1762
|
-
return
|
1789
|
+
return treeWalk(ast, function (node, descend, path) {
|
1763
1790
|
if ((node.type === 'ThrowStatement' || node.type === 'ReturnStatement') && !node.$mapped) {
|
1764
1791
|
if (lambdaNesting > 0) {
|
1765
1792
|
if (examine(node).isAsync) {
|
@@ -1782,33 +1809,35 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1782
1809
|
descend(node);
|
1783
1810
|
});
|
1784
1811
|
}
|
1785
|
-
|
1812
|
+
|
1786
1813
|
function spawnBody(body, deferExit) {
|
1787
|
-
if (opts.noRuntime)
|
1788
|
-
throw new Error("Nodent: 'noRuntime' option only compatible with -promise and -engine modes")
|
1789
|
-
|
1790
|
-
return
|
1791
|
-
'return':genIdent.return,
|
1792
|
-
error:genIdent.error,
|
1793
|
-
asyncspawn:genIdent.asyncspawn,
|
1794
|
-
|
1795
|
-
|
1796
|
-
|
1797
|
-
|
1798
|
-
|
1814
|
+
if (opts.noRuntime)
|
1815
|
+
throw new Error("Nodent: 'noRuntime' option only compatible with -promise and -engine modes");
|
1816
|
+
var template = !opts.$runtime ? "{ return (function*($return,$error){ $:body }).$asyncspawn($promise,this) }" : "{ return $runtime.$asyncspawn.call(function*($return,$error){ $:body },$promise,this) }";
|
1817
|
+
return parsePart(template, {
|
1818
|
+
'return': genIdent.return,
|
1819
|
+
error: genIdent.error,
|
1820
|
+
asyncspawn: genIdent.asyncspawn,
|
1821
|
+
runtime: genIdent.runtime,
|
1822
|
+
promise: genIdent.Promise,
|
1823
|
+
body: mapAsyncReturns(body).concat(deferExit ? [{
|
1824
|
+
type: 'ReturnStatement',
|
1825
|
+
argument: genIdent.return
|
1826
|
+
}] : [])
|
1827
|
+
}).body[0];
|
1799
1828
|
}
|
1800
|
-
|
1829
|
+
|
1801
1830
|
function warnAsyncGetter(id) {
|
1802
1831
|
if (!id.$asyncgetwarninig) {
|
1803
1832
|
id.$asyncgetwarninig = true;
|
1804
|
-
logger(where(id) + "'async get "+printNode(id)+"(){...}' is non-standard. See https://github.com/MatAtBread/nodent#differences-from-the-es7-specification");
|
1833
|
+
logger(where(id) + "'async get " + printNode(id) + "(){...}' is non-standard. See https://github.com/MatAtBread/nodent#differences-from-the-es7-specification");
|
1805
1834
|
}
|
1806
1835
|
}
|
1807
|
-
|
1808
|
-
function asyncSpawn(ast,engine) {
|
1809
|
-
function mapAwaits(ast,hide) {
|
1810
|
-
|
1811
|
-
if (node !== ast && examine(node).isFunction)
|
1836
|
+
|
1837
|
+
function asyncSpawn(ast, engine) {
|
1838
|
+
function mapAwaits(ast, hide) {
|
1839
|
+
treeWalk(ast, function (node, descend, path) {
|
1840
|
+
if (node !== ast && examine(node).isFunction)
|
1812
1841
|
return;
|
1813
1842
|
if (examine(node).isAwait) {
|
1814
1843
|
if (hide) {
|
@@ -1820,18 +1849,18 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1820
1849
|
node.type = 'YieldExpression';
|
1821
1850
|
descend();
|
1822
1851
|
}
|
1823
|
-
} else
|
1852
|
+
} else
|
1824
1853
|
descend();
|
1825
1854
|
});
|
1826
1855
|
}
|
1827
|
-
|
1856
|
+
|
1828
1857
|
function promiseTransform(ast) {
|
1829
1858
|
var promises = opts.promises;
|
1830
1859
|
opts.promises = true;
|
1831
1860
|
asyncTransforms(ast, true);
|
1832
1861
|
opts.promises = promises;
|
1833
1862
|
}
|
1834
|
-
|
1863
|
+
|
1835
1864
|
function expandArrows(fn) {
|
1836
1865
|
if (fn.body.type !== 'BlockStatement') {
|
1837
1866
|
fn.body = {
|
@@ -1844,25 +1873,24 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1844
1873
|
}
|
1845
1874
|
return fn;
|
1846
1875
|
}
|
1847
|
-
|
1876
|
+
|
1848
1877
|
function warnAsyncExit(exit, fn) {
|
1849
1878
|
if (!fn.$asyncexitwarninig) {
|
1850
1879
|
fn.$asyncexitwarninig = true;
|
1851
1880
|
logger(where(exit) + "'async " + ({
|
1852
1881
|
ReturnStatement: 'return',
|
1853
1882
|
ThrowStatement: 'throw'
|
1854
|
-
})[exit.type] + "' not possible in "+(engine?'engine':'generator')+" mode. Using Promises for function at " + where(fn));
|
1883
|
+
})[exit.type] + "' not possible in " + (engine ? 'engine' : 'generator') + " mode. Using Promises for function at " + where(fn));
|
1855
1884
|
}
|
1856
1885
|
}
|
1857
|
-
|
1858
|
-
|
1886
|
+
|
1887
|
+
treeWalk(ast, function (node, descend, path) {
|
1859
1888
|
descend();
|
1860
1889
|
var fn, exit, usesArgs;
|
1861
1890
|
if (examine(node).isAsync && examine(node).isFunction) {
|
1862
|
-
var member
|
1863
|
-
if ((member = getMemberFunction(path[0].parent))
|
1864
|
-
|
1865
|
-
warnAsyncGetter(path[0].parent.key) ;
|
1891
|
+
var member;
|
1892
|
+
if ((member = getMemberFunction(path[0].parent)) && examine(member).isAsync && path[0].parent.kind === 'get') {
|
1893
|
+
warnAsyncGetter(path[0].parent.key);
|
1866
1894
|
}
|
1867
1895
|
if (exit = containsAsyncExit(node)) {
|
1868
1896
|
// Do the Promise transform
|
@@ -1872,40 +1900,39 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1872
1900
|
fn = node;
|
1873
1901
|
delete fn.async;
|
1874
1902
|
usesArgs = replaceArguments(fn);
|
1875
|
-
mapAwaits(fn,false);
|
1903
|
+
mapAwaits(fn, false);
|
1876
1904
|
fn = expandArrows(fn);
|
1877
1905
|
fn.body = spawnBody(fn.body.body, exit);
|
1878
|
-
if (usesArgs)
|
1879
|
-
afterDirectives(fn.body.body,[assign$Args]);
|
1906
|
+
if (usesArgs)
|
1907
|
+
afterDirectives(fn.body.body, [assign$Args]);
|
1880
1908
|
if (fn.id && path[0].parent.type === 'ExpressionStatement') {
|
1881
1909
|
fn.type = 'FunctionDeclaration';
|
1882
1910
|
path[1].replace(fn);
|
1883
1911
|
} else {
|
1884
1912
|
path[0].replace(fn);
|
1885
1913
|
}
|
1886
|
-
} else if (path[0].parent.kind !== 'get')
|
1887
|
-
mapAwaits(node,true)
|
1914
|
+
} else if (path[0].parent.kind !== 'get')
|
1915
|
+
mapAwaits(node, true);
|
1888
1916
|
} else if ((fn = getMemberFunction(node)) && examine(fn).isAsync) {
|
1889
1917
|
if (exit = containsAsyncExit(fn)) {
|
1890
1918
|
// Do the Promise transform
|
1891
1919
|
warnAsyncExit(exit, fn);
|
1892
1920
|
promiseTransform(node);
|
1893
|
-
} else if (!engine || node.kind==='get') {
|
1921
|
+
} else if (!engine || node.kind === 'get') {
|
1894
1922
|
if (engine) {
|
1895
|
-
promiseTransform(node)
|
1923
|
+
promiseTransform(node);
|
1896
1924
|
} else {
|
1897
1925
|
node.async = false;
|
1898
1926
|
usesArgs = replaceArguments(fn);
|
1899
|
-
mapAwaits(fn,false);
|
1927
|
+
mapAwaits(fn, false);
|
1900
1928
|
coerce(fn, expandArrows(fn));
|
1901
1929
|
fn.body = spawnBody(fn.body.body, exit);
|
1902
1930
|
}
|
1903
|
-
if (usesArgs)
|
1904
|
-
afterDirectives(fn.body.body,[assign$Args]);
|
1931
|
+
if (usesArgs)
|
1932
|
+
afterDirectives(fn.body.body, [assign$Args]);
|
1905
1933
|
}
|
1906
1934
|
}
|
1907
1935
|
});
|
1908
|
-
|
1909
1936
|
// Map (and warn) about any out-of-scope awaits that are being
|
1910
1937
|
// mapped using Promises.
|
1911
1938
|
var st = cloneNode(opts);
|
@@ -1913,7 +1940,7 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1913
1940
|
opts.generators = false;
|
1914
1941
|
blockifyArrows(ast);
|
1915
1942
|
hoistDeclarations(ast);
|
1916
|
-
labelTryCatch(ast,st.engine);
|
1943
|
+
labelTryCatch(ast, st.engine);
|
1917
1944
|
mapLogicalOp(ast);
|
1918
1945
|
mapCondOp(ast);
|
1919
1946
|
walkDown(ast, [mapTryCatch,mapLoops,mapIfStmt,mapSwitch,mapBlock]);
|
@@ -1922,47 +1949,52 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1922
1949
|
opts.generators = st.generators;
|
1923
1950
|
return ast;
|
1924
1951
|
}
|
1925
|
-
|
1952
|
+
|
1926
1953
|
/* Find all nodes within this scope matching the specified function */
|
1927
1954
|
function scopedNodes(ast, matching, flat) {
|
1955
|
+
if (!flat) flat = ['isScope','isLoop'] ;
|
1928
1956
|
var matches = [];
|
1929
|
-
|
1930
|
-
if (node === ast)
|
1957
|
+
treeWalk(ast, function (node, descend, path) {
|
1958
|
+
if (node === ast)
|
1931
1959
|
return descend();
|
1932
1960
|
if (matching(node, path)) {
|
1933
1961
|
matches.push([].concat(path));
|
1934
1962
|
return;
|
1935
1963
|
}
|
1936
|
-
if (flat
|
1937
|
-
|
1938
|
-
|
1964
|
+
if (flat === true) return ;
|
1965
|
+
var x = examine(node) ;
|
1966
|
+
for (var i=0; i<flat.length; i++)
|
1967
|
+
if (x[flat[i]])
|
1968
|
+
return ;
|
1939
1969
|
descend();
|
1940
1970
|
});
|
1941
1971
|
return matches;
|
1942
1972
|
}
|
1943
|
-
|
1944
|
-
function extractVars(vars,kind) {
|
1973
|
+
|
1974
|
+
function extractVars(vars, kind) {
|
1945
1975
|
var varDecls = [];
|
1946
|
-
var duplicates = {}
|
1947
|
-
vars = vars.filter(function(v){
|
1976
|
+
var duplicates = {};
|
1977
|
+
vars = vars.filter(function (v) {
|
1978
|
+
return v[0].parent.type !== 'ExportNamedDeclaration';
|
1979
|
+
});
|
1948
1980
|
if (vars.length) {
|
1949
1981
|
var definitions = {};
|
1950
1982
|
vars.forEach(function (path) {
|
1951
1983
|
function addName(name) {
|
1952
1984
|
if (name in definitions) {
|
1953
|
-
duplicates[name] = self.declarations[i]
|
1985
|
+
duplicates[name] = self.declarations[i];
|
1954
1986
|
} else {
|
1955
|
-
definitions[name] = self.declarations[i]
|
1987
|
+
definitions[name] = self.declarations[i];
|
1956
1988
|
}
|
1957
1989
|
}
|
1958
|
-
|
1990
|
+
|
1959
1991
|
var ref = path[0];
|
1960
1992
|
var self = ref.self;
|
1961
|
-
var kind = self.kind
|
1993
|
+
var kind = self.kind;
|
1962
1994
|
var values = [];
|
1963
1995
|
for (var i = 0;i < self.declarations.length; i++) {
|
1964
|
-
var decl = self.declarations[i]
|
1965
|
-
getDeclNames(decl.id).forEach(addName)
|
1996
|
+
var decl = self.declarations[i];
|
1997
|
+
getDeclNames(decl.id).forEach(addName);
|
1966
1998
|
if (decl.init) {
|
1967
1999
|
var value = {
|
1968
2000
|
type: 'AssignmentExpression',
|
@@ -1973,17 +2005,22 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
1973
2005
|
values.push(value);
|
1974
2006
|
}
|
1975
2007
|
}
|
1976
|
-
if (values.length == 0)
|
2008
|
+
if (values.length == 0)
|
1977
2009
|
ref.remove();
|
1978
|
-
|
1979
|
-
|
1980
|
-
|
1981
|
-
|
1982
|
-
|
2010
|
+
else {
|
2011
|
+
var repl = values.length > 1 ? {
|
2012
|
+
type: 'SequenceExpression',
|
2013
|
+
expressions: values
|
2014
|
+
} : values[0];
|
2015
|
+
if (ref.parent.type.slice(0, 3) !== 'For')
|
2016
|
+
repl = {
|
2017
|
+
type: 'ExpressionStatement',
|
2018
|
+
expression: repl
|
2019
|
+
};
|
2020
|
+
ref.replace(repl);
|
1983
2021
|
}
|
1984
2022
|
});
|
1985
|
-
|
1986
|
-
var defs = Object.keys(definitions) ;
|
2023
|
+
var defs = Object.keys(definitions);
|
1987
2024
|
if (defs.length) {
|
1988
2025
|
defs = defs.map(function (name) {
|
1989
2026
|
return {
|
@@ -2005,200 +2042,215 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
2005
2042
|
}
|
2006
2043
|
}
|
2007
2044
|
}
|
2008
|
-
return {
|
2045
|
+
return {
|
2046
|
+
decls: varDecls,
|
2047
|
+
duplicates: duplicates
|
2048
|
+
};
|
2009
2049
|
}
|
2010
|
-
|
2050
|
+
|
2011
2051
|
function getDeclNames(id) {
|
2012
|
-
if (!id)
|
2052
|
+
if (!id)
|
2053
|
+
return [];
|
2013
2054
|
if (Array.isArray(id)) {
|
2014
|
-
return id.reduce(function(z,
|
2055
|
+
return id.reduce(function (z, j) {
|
2056
|
+
return z.concat(getDeclNames(j.id));
|
2057
|
+
}, []);
|
2015
2058
|
}
|
2016
2059
|
switch (id.type) {
|
2017
|
-
|
2018
|
-
|
2019
|
-
|
2020
|
-
|
2021
|
-
|
2022
|
-
|
2023
|
-
|
2024
|
-
|
2025
|
-
|
2026
|
-
|
2027
|
-
|
2028
|
-
|
2029
|
-
|
2030
|
-
|
2060
|
+
case 'Identifier':
|
2061
|
+
return [id.name];
|
2062
|
+
case 'AssignmentPattern':
|
2063
|
+
return getDeclNames(id.left);
|
2064
|
+
case 'ArrayPattern':
|
2065
|
+
return id.elements.reduce(function (z, e) {
|
2066
|
+
return z.concat(getDeclNames(e));
|
2067
|
+
}, []);
|
2068
|
+
case 'ObjectPattern':
|
2069
|
+
return id.properties.reduce(function (z, e) {
|
2070
|
+
return z.concat(getDeclNames(e));
|
2071
|
+
}, []);
|
2072
|
+
case 'ObjectProperty':
|
2073
|
+
case 'Property':
|
2074
|
+
return getDeclNames(id.value);
|
2075
|
+
case 'RestElement':
|
2076
|
+
case 'RestProperty':
|
2077
|
+
return getDeclNames(id.argument);
|
2031
2078
|
}
|
2032
2079
|
}
|
2033
|
-
|
2080
|
+
|
2034
2081
|
function checkConstsNotAssigned(ast) {
|
2035
2082
|
/* Ensure no consts are on the LHS of an AssignmentExpression */
|
2036
|
-
var names = {}
|
2037
|
-
|
2038
|
-
|
2039
|
-
logger(where(node) + "Possible assignment to 'const " + printNode(node)+"'");
|
2083
|
+
var names = {};
|
2084
|
+
function fail(node) {
|
2085
|
+
logger(where(node) + "Possible assignment to 'const " + printNode(node) + "'");
|
2040
2086
|
}
|
2041
|
-
|
2087
|
+
|
2042
2088
|
function checkAssignable(target) {
|
2043
2089
|
switch (target.type) {
|
2044
|
-
|
2045
|
-
|
2046
|
-
|
2047
|
-
|
2048
|
-
|
2049
|
-
|
2050
|
-
|
2051
|
-
|
2052
|
-
|
2053
|
-
|
2054
|
-
|
2055
|
-
|
2056
|
-
|
2057
|
-
|
2090
|
+
case 'Identifier':
|
2091
|
+
// Find the declaration of any names on the left
|
2092
|
+
if (names[target.name] === 'const')
|
2093
|
+
fail(target);
|
2094
|
+
break;
|
2095
|
+
case 'ArrayPattern':
|
2096
|
+
target.elements.forEach(function (e) {
|
2097
|
+
if (names[e.name] === 'const')
|
2098
|
+
fail(e);
|
2099
|
+
});
|
2100
|
+
break;
|
2101
|
+
case 'ObjectPattern':
|
2102
|
+
target.properties.forEach(function (p) {
|
2103
|
+
if (names[p.key.name] === 'const')
|
2104
|
+
fail(p);
|
2105
|
+
});
|
2106
|
+
break;
|
2058
2107
|
}
|
2059
2108
|
}
|
2060
|
-
|
2061
|
-
|
2062
|
-
var body = examine(node).isBlockStatement
|
2109
|
+
|
2110
|
+
treeWalk(ast, function (node, descend, path) {
|
2111
|
+
var body = examine(node).isBlockStatement;
|
2063
2112
|
if (body) {
|
2064
|
-
names = Object.create(names)
|
2065
|
-
|
2066
|
-
for (var h=0; h<body.length; h++) {
|
2113
|
+
names = Object.create(names);
|
2114
|
+
for (var h = 0;h < body.length; h++) {
|
2067
2115
|
if (body[h].type === 'VariableDeclaration') {
|
2068
|
-
for (var i=0;
|
2069
|
-
getDeclNames(body[h].declarations[i].id).forEach(function(name){
|
2070
|
-
names[name] = body[h].kind
|
2071
|
-
})
|
2116
|
+
for (var i = 0;i < body[h].declarations.length; i++) {
|
2117
|
+
getDeclNames(body[h].declarations[i].id).forEach(function (name) {
|
2118
|
+
names[name] = body[h].kind;
|
2119
|
+
});
|
2072
2120
|
}
|
2073
2121
|
}
|
2074
2122
|
}
|
2075
2123
|
}
|
2076
|
-
descend()
|
2077
|
-
|
2078
|
-
|
2079
|
-
|
2080
|
-
|
2081
|
-
|
2082
|
-
|
2083
|
-
names = Object.getPrototypeOf(names) ;
|
2124
|
+
descend();
|
2125
|
+
if (node.type === 'AssignmentExpression')
|
2126
|
+
checkAssignable(node.left);
|
2127
|
+
else if (node.type === 'UpdateExpression')
|
2128
|
+
checkAssignable(node.argument);
|
2129
|
+
if (body)
|
2130
|
+
names = Object.getPrototypeOf(names);
|
2084
2131
|
});
|
2085
2132
|
}
|
2086
|
-
|
2133
|
+
|
2087
2134
|
/* Move directives, vars and named functions to the top of their scope iff. the scope contains an 'await' */
|
2088
2135
|
function hoistDeclarations(ast) {
|
2089
|
-
|
2090
|
-
|
2091
|
-
|
2092
|
-
|
2093
|
-
|
2094
|
-
|
2095
|
-
|
2096
|
-
|
2136
|
+
var sequences = {
|
2137
|
+
TemplateLiteral: function (x) {
|
2138
|
+
return x.expressions;
|
2139
|
+
},
|
2140
|
+
NewExpression: function (x) {
|
2141
|
+
return x.arguments;
|
2142
|
+
},
|
2143
|
+
CallExpression: function (x) {
|
2144
|
+
return x.arguments;
|
2145
|
+
},
|
2146
|
+
SequenceExpression: function (x) {
|
2147
|
+
return x.expressions;
|
2148
|
+
},
|
2149
|
+
ArrayExpression: function (x) {
|
2150
|
+
return x.elements;
|
2151
|
+
},
|
2152
|
+
ObjectExpression: function (oe) {
|
2153
|
+
return oe.properties.map(function (p) {
|
2154
|
+
return p.value;
|
2155
|
+
});
|
2156
|
+
}
|
2157
|
+
};
|
2097
2158
|
/* Identify SequenceExpressions, Parameter lists and VariableDeclarators that contain assigments and split them up
|
2098
2159
|
to ensure the correct evaluation order */
|
2099
|
-
|
2100
|
-
|
2101
|
-
|
2102
|
-
|
2103
|
-
});
|
2160
|
+
function containsAssign(ast) {
|
2161
|
+
return contains(ast, function (n) {
|
2162
|
+
return n.type === 'AssignmentExpression';
|
2163
|
+
});
|
2104
2164
|
}
|
2105
|
-
|
2106
|
-
|
2107
|
-
|
2108
|
-
|
2109
|
-
|
2110
|
-
|
2111
|
-
|
2112
|
-
|
2113
|
-
|
2114
|
-
|
2115
|
-
|
2116
|
-
|
2117
|
-
|
2118
|
-
|
2119
|
-
|
2120
|
-
|
2121
|
-
|
2122
|
-
|
2123
|
-
}
|
2124
|
-
}
|
2125
|
-
|
2126
|
-
|
2127
|
-
if (node.type in sequences && !node.$hoisted) {
|
2128
|
-
var expr = sequences[node.type](node) ;
|
2129
|
-
var assignments = [] ;
|
2130
|
-
var path ;
|
2131
|
-
for (i=0; i<expr.length;i++) {
|
2132
|
-
if (examine(expr[i]).isScope)
|
2133
|
-
continue ;
|
2134
|
-
|
2135
|
-
if (path = containsAwait(expr[i]))
|
2136
|
-
moveAssignments(path[0].self) ;
|
2137
|
-
|
2138
|
-
if (!containsAwait(expr.slice(i+1)))
|
2139
|
-
break ;
|
2140
|
-
|
2141
|
-
if (path = containsAssign(expr[i]))
|
2142
|
-
assignments.push(path[0].self) ;
|
2143
|
-
}
|
2144
|
-
} else if (node.type === 'VariableDeclaration') {
|
2145
|
-
// If any of the VariableDeclarators contain an initial value and are followed by a VariableDeclarator
|
2146
|
-
// containing an await, split them up into multiple statements
|
2147
|
-
for (i=node.declarations.length-1; i>0; i--) {
|
2148
|
-
if (node.declarations[i] && node.declarations[i].init && containsAwait(node.declarations[i].init)) {
|
2149
|
-
var insert = {
|
2150
|
-
type:'VariableDeclaration',
|
2151
|
-
kind: node.kind,
|
2152
|
-
declarations: node.declarations.splice(i)
|
2153
|
-
} ;
|
2154
|
-
var ref = path[0] ;
|
2155
|
-
if ('index' in ref) {
|
2156
|
-
ref.parent[ref.field].splice(ref.index+1,0,insert) ;
|
2157
|
-
} else throw new Error("VariableDeclaration not in a block") ;
|
2158
|
-
}
|
2165
|
+
|
2166
|
+
treeWalk(ast, function (node, descend, path) {
|
2167
|
+
var i;
|
2168
|
+
descend();
|
2169
|
+
// Ensure assigments are evaluated before any await expressions, eg:
|
2170
|
+
// f(a=1, b = await a) --> a=1; f(a,b=await a)
|
2171
|
+
function moveAssignments(dest) {
|
2172
|
+
if (assignments.length) {
|
2173
|
+
dest.argument = {
|
2174
|
+
type: 'SequenceExpression',
|
2175
|
+
expressions: assignments.map(function (a) {
|
2176
|
+
var b = cloneNode(a);
|
2177
|
+
coerce(a, a.left);
|
2178
|
+
return b;
|
2179
|
+
}).concat(dest.argument)
|
2180
|
+
};
|
2181
|
+
assignments = [];
|
2182
|
+
}
|
2159
2183
|
}
|
2160
|
-
|
2161
|
-
|
2162
|
-
|
2184
|
+
|
2185
|
+
if (node.type in sequences && !node.$hoisted) {
|
2186
|
+
var expr = sequences[node.type](node);
|
2187
|
+
var assignments = [];
|
2188
|
+
var path;
|
2189
|
+
for (i = 0; i < expr.length; i++) {
|
2190
|
+
if (examine(expr[i]).isScope)
|
2191
|
+
continue;
|
2192
|
+
if (path = containsAwait(expr[i]))
|
2193
|
+
moveAssignments(path[0].self);
|
2194
|
+
if (!containsAwait(expr.slice(i + 1)))
|
2195
|
+
break;
|
2196
|
+
if (path = containsAssign(expr[i]))
|
2197
|
+
assignments.push(path[0].self);
|
2198
|
+
}
|
2199
|
+
} else if (node.type === 'VariableDeclaration') {
|
2200
|
+
// If any of the VariableDeclarators contain an initial value and are followed by a VariableDeclarator
|
2201
|
+
// containing an await, split them up into multiple statements
|
2202
|
+
for (i = node.declarations.length - 1; i > 0; i--) {
|
2203
|
+
if (node.declarations[i] && node.declarations[i].init && containsAwait(node.declarations[i].init)) {
|
2204
|
+
var insert = {
|
2205
|
+
type: 'VariableDeclaration',
|
2206
|
+
kind: node.kind,
|
2207
|
+
declarations: node.declarations.splice(i)
|
2208
|
+
};
|
2209
|
+
var ref = path[0];
|
2210
|
+
if ('index' in ref) {
|
2211
|
+
ref.parent[ref.field].splice(ref.index + 1, 0, insert);
|
2212
|
+
} else
|
2213
|
+
throw new Error("VariableDeclaration not in a block");
|
2214
|
+
}
|
2215
|
+
}
|
2216
|
+
}
|
2217
|
+
});
|
2163
2218
|
/* Hoist declarations */
|
2164
2219
|
function isFreeVariable(kinds) {
|
2165
|
-
return function(n, path) {
|
2166
|
-
if (n.type === 'VariableDeclaration' && (n.kind = n.kind || 'var') && kinds.indexOf(n.kind)>=0) {
|
2167
|
-
var p = path[0]
|
2220
|
+
return function (n, path) {
|
2221
|
+
if (n.type === 'VariableDeclaration' && (n.kind = n.kind || 'var') && kinds.indexOf(n.kind) >= 0) {
|
2222
|
+
var p = path[0];
|
2168
2223
|
// Don't hoist the LHS of for (var/let/const _ of/in ... ; ;){}
|
2169
|
-
if (p.field == "left" && (p.parent.type === 'ForInStatement' || p.parent.type === 'ForOfStatement'))
|
2224
|
+
if (p.field == "left" && (p.parent.type === 'ForInStatement' || p.parent.type === 'ForOfStatement'))
|
2170
2225
|
return false;
|
2171
|
-
|
2172
2226
|
// Don't hoist the LHS of for (let/const _ = ... ; ;){}
|
2173
|
-
if (p.field == "init" && p.parent.type === 'ForStatement' && (n.kind==="const" || n.kind==="let"))
|
2227
|
+
if (p.field == "init" && p.parent.type === 'ForStatement' && (n.kind === "const" || n.kind === "let"))
|
2174
2228
|
return false;
|
2175
|
-
|
2176
2229
|
return true;
|
2177
2230
|
}
|
2178
|
-
}
|
2231
|
+
};
|
2179
2232
|
}
|
2180
|
-
|
2233
|
+
|
2181
2234
|
function isHoistableFunction(n, path) {
|
2182
2235
|
// YES: We're a named function, but not a continuation
|
2183
|
-
if (n.type==='FunctionDeclaration'
|
2236
|
+
if (n.type === 'FunctionDeclaration' && n.id) {
|
2184
2237
|
return examine(n).isAsync || !n.$continuation;
|
2185
2238
|
}
|
2186
2239
|
// No, we're not a hoistable function
|
2187
2240
|
return false;
|
2188
2241
|
}
|
2189
|
-
|
2190
|
-
checkConstsNotAssigned(ast)
|
2191
|
-
|
2192
|
-
|
2193
|
-
|
2194
|
-
|
2195
|
-
inStrictBody = inStrictBody || isStrict(node) ;
|
2196
|
-
|
2242
|
+
|
2243
|
+
checkConstsNotAssigned(ast);
|
2244
|
+
var inStrictBody = false;
|
2245
|
+
treeWalk(ast, function (node, descend, path) {
|
2246
|
+
var prevScope = inStrictBody;
|
2247
|
+
inStrictBody = inStrictBody || isStrict(node);
|
2197
2248
|
if (examine(node).isBlockStatement) {
|
2198
2249
|
if (containsAwait(node)) {
|
2199
2250
|
// For this scope/block, find all the hoistable functions, vars and directives
|
2200
|
-
|
2201
|
-
|
2251
|
+
var isVarScope = !path[0].parent || examine(path[0].parent).isScope ;
|
2252
|
+
var isLoopScope = path[0].parent && examine(path[0].parent).isLoop ;
|
2253
|
+
var isScope = isVarScope || isLoopScope ;
|
2202
2254
|
/* 'const' is highly problematic. In early version of Chrome (Node 0.10, 4.x, 5.x) non-standard behaviour:
|
2203
2255
|
*
|
2204
2256
|
* Node scope multiple-decls
|
@@ -2217,36 +2269,34 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
2217
2269
|
* - const's with a single declaration in the current scope (NOT block) should be hoisted to function level, and defined as 'var'
|
2218
2270
|
* - const's with duplicate declarations in the current scope (NOT block) should be hoisted to block level, and defined as 'let'
|
2219
2271
|
*/
|
2220
|
-
|
2221
|
-
var directives, consts, vars, lets, functions ;
|
2272
|
+
var directives, consts, vars, lets, functions;
|
2222
2273
|
if (isScope) {
|
2223
|
-
consts = scopedNodes(node, isFreeVariable(['const']),false);
|
2224
|
-
var names = {}, duplicates = {}
|
2225
|
-
|
2274
|
+
consts = scopedNodes(node, isFreeVariable(['const']), false);
|
2275
|
+
var names = {}, duplicates = {};
|
2226
2276
|
// Work out which const identifiers are duplicates
|
2227
2277
|
// Ones that are only declared once can simply be treated as vars, whereas
|
2228
2278
|
// identifiers that are declared multiple times have block-scope and are
|
2229
|
-
// only valid in node 6 or in strict mode on node 4/5
|
2230
|
-
|
2231
|
-
|
2232
|
-
|
2233
|
-
|
2234
|
-
|
2235
|
-
|
2279
|
+
// only valid in node 6 or in strict mode on node 4/5.
|
2280
|
+
// In strict mode or ES6-a-like targets always assume the correct ES6 semantics (block scope)
|
2281
|
+
consts.forEach(function (d) {
|
2282
|
+
d[0].self.declarations.forEach(function (e) {
|
2283
|
+
getDeclNames(e.id).forEach(function (n) {
|
2284
|
+
if (inStrictBody || looksLikeES6 || names[n] || duplicates[n]) {
|
2285
|
+
looksLikeES6 = true ;
|
2286
|
+
delete names[n];
|
2287
|
+
duplicates[n] = e;
|
2236
2288
|
} else {
|
2237
|
-
names[n] = e
|
2289
|
+
names[n] = e;
|
2238
2290
|
}
|
2239
|
-
})
|
2240
|
-
})
|
2241
|
-
})
|
2242
|
-
|
2291
|
+
});
|
2292
|
+
});
|
2293
|
+
});
|
2243
2294
|
// Change all the declarations into assignments, since consts are always initialized
|
2244
|
-
consts.forEach(function(d){
|
2245
|
-
for (var depth=0;
|
2246
|
-
if (examine(d[depth].parent).isBlockStatement)
|
2247
|
-
|
2248
|
-
|
2249
|
-
var ref = d[depth] ;
|
2295
|
+
consts.forEach(function (d) {
|
2296
|
+
for (var depth = 0;depth < d.length; depth++)
|
2297
|
+
if (examine(d[depth].parent).isBlockStatement)
|
2298
|
+
break;
|
2299
|
+
var ref = d[depth];
|
2250
2300
|
ref.append({
|
2251
2301
|
type: 'ExpressionStatement',
|
2252
2302
|
expression: {
|
@@ -2258,58 +2308,66 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
2258
2308
|
left: d.id,
|
2259
2309
|
right: d.init
|
2260
2310
|
};
|
2261
|
-
d.init = null
|
2262
|
-
return a
|
2311
|
+
d.init = null;
|
2312
|
+
return a;
|
2263
2313
|
})
|
2264
2314
|
}
|
2265
2315
|
});
|
2266
|
-
var ids = getDeclNames(d[0].self.declarations)
|
2267
|
-
var decls = ids.filter(function(name){
|
2316
|
+
var ids = getDeclNames(d[0].self.declarations);
|
2317
|
+
var decls = ids.filter(function (name) {
|
2318
|
+
return name in duplicates;
|
2319
|
+
});
|
2268
2320
|
if (decls.length) {
|
2269
2321
|
d[0].append({
|
2270
|
-
type:'VariableDeclaration',
|
2271
|
-
kind:'let',
|
2272
|
-
declarations: decls.map(function(name){
|
2322
|
+
type: 'VariableDeclaration',
|
2323
|
+
kind: 'let',
|
2324
|
+
declarations: decls.map(function (name) {
|
2273
2325
|
return {
|
2274
|
-
type:'VariableDeclarator',
|
2275
|
-
id:ident(name)
|
2276
|
-
}
|
2326
|
+
type: 'VariableDeclarator',
|
2327
|
+
id: ident(name)
|
2328
|
+
};
|
2277
2329
|
})
|
2278
|
-
})
|
2330
|
+
});
|
2279
2331
|
}
|
2280
|
-
|
2281
|
-
|
2282
|
-
|
2332
|
+
d[0].self.kind = 'var';
|
2333
|
+
decls = ids.filter(function (name) {
|
2334
|
+
return name in names;
|
2335
|
+
});
|
2283
2336
|
if (decls.length) {
|
2284
|
-
d[0].self.declarations = decls.map(function(name){
|
2337
|
+
d[0].self.declarations = decls.map(function (name) {
|
2285
2338
|
return {
|
2286
|
-
type:'VariableDeclarator',
|
2287
|
-
id:ident(name)
|
2288
|
-
}
|
2339
|
+
type: 'VariableDeclarator',
|
2340
|
+
id: ident(name)
|
2341
|
+
};
|
2289
2342
|
});
|
2290
2343
|
} else {
|
2291
|
-
|
2344
|
+
ref.remove();
|
2292
2345
|
}
|
2293
|
-
})
|
2294
|
-
vars = scopedNodes(node, isFreeVariable(['var']),
|
2295
|
-
lets = []
|
2346
|
+
});
|
2347
|
+
if (isVarScope && !isLoopScope) vars = scopedNodes(node, isFreeVariable(['var']), ['isScope']);
|
2348
|
+
lets = [];
|
2296
2349
|
} else {
|
2297
|
-
lets = scopedNodes(node, isFreeVariable(['const']),true);
|
2350
|
+
lets = scopedNodes(node, isFreeVariable(['const']), true);
|
2298
2351
|
}
|
2299
|
-
lets = lets.concat(scopedNodes(node, isFreeVariable(['let']),true));
|
2300
|
-
directives = scopedNodes(node, function (n) {
|
2352
|
+
lets = lets.concat(scopedNodes(node, isFreeVariable(['let']), true));
|
2353
|
+
directives = scopedNodes(node, function (n) {
|
2354
|
+
return examine(n).isDirective;
|
2355
|
+
}, true);
|
2301
2356
|
functions = scopedNodes(node, isHoistableFunction, inStrictBody);
|
2302
|
-
|
2303
|
-
|
2304
|
-
|
2305
|
-
|
2306
|
-
|
2357
|
+
vars = vars ? extractVars(vars, 'var') : {
|
2358
|
+
duplicates: {},
|
2359
|
+
decls: []
|
2360
|
+
};
|
2361
|
+
lets = lets ? extractVars(lets, 'let') : {
|
2362
|
+
duplicates: {},
|
2363
|
+
decls: []
|
2364
|
+
};
|
2365
|
+
Object.keys(vars.duplicates).forEach(function (id) {
|
2307
2366
|
logger(where(vars.duplicates[id]) + "Duplicate declaration '" + printNode(vars.duplicates[id]) + "'");
|
2308
|
-
})
|
2309
|
-
Object.keys(lets.duplicates).forEach(function(id){
|
2367
|
+
});
|
2368
|
+
Object.keys(lets.duplicates).forEach(function (id) {
|
2310
2369
|
logger(where(lets.duplicates[id]) + "Duplicate declaration '" + printNode(lets.duplicates[id]) + "'");
|
2311
|
-
})
|
2312
|
-
|
2370
|
+
});
|
2313
2371
|
functions = functions.map(function (path) {
|
2314
2372
|
var ref = path[0], symName;
|
2315
2373
|
// What is the name of this function (could be async, so check the expression if necessary),
|
@@ -2330,7 +2388,6 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
2330
2388
|
var movedFn = ref.self.type === 'FunctionDeclaration' ? ref.remove() : ref.replace(ident(symName));
|
2331
2389
|
return movedFn;
|
2332
2390
|
});
|
2333
|
-
|
2334
2391
|
directives = directives.map(function (path) {
|
2335
2392
|
var ref = path[0];
|
2336
2393
|
return ref.remove();
|
@@ -2339,61 +2396,61 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
2339
2396
|
node.body = directives.concat(vars.decls).concat(lets.decls).concat(functions).concat(node.body);
|
2340
2397
|
}
|
2341
2398
|
}
|
2342
|
-
inStrictBody = prevScope
|
2399
|
+
inStrictBody = prevScope;
|
2343
2400
|
}
|
2344
|
-
|
2345
|
-
|
2346
|
-
|
2347
|
-
|
2348
|
-
|
2349
|
-
|
2350
|
-
|
2351
|
-
|
2352
|
-
|
2353
|
-
|
2354
|
-
|
2401
|
+
// Labeled breaks need to be treated as loops that always exit early, if they contain awaits
|
2402
|
+
if (node.type === 'LabeledStatement' && node.body.type === 'BlockStatement' && containsAwait(node.body)) {
|
2403
|
+
if (contains(node.body, function (m) {
|
2404
|
+
return m.type === 'BreakStatement' && m.label && m.label.name == node.label.name;
|
2405
|
+
})) {
|
2406
|
+
node.body.body.push({
|
2407
|
+
type: 'BreakStatement'
|
2408
|
+
});
|
2409
|
+
node.body = {
|
2410
|
+
type: 'DoWhileStatement',
|
2411
|
+
test: literal(0),
|
2412
|
+
body: node.body
|
2413
|
+
};
|
2414
|
+
}
|
2355
2415
|
}
|
2356
|
-
|
2357
2416
|
descend();
|
2358
|
-
|
2359
2417
|
// It makes life easier if labeled loops have the label to hand, so we simply reference them here with a hidden $label
|
2360
2418
|
// and keep a record of how nested the for loop is (since it's transformed top to bottom and counting during
|
2361
2419
|
// transformation is therefore not possible
|
2362
|
-
if (node.type==='ForOfStatement' || node.type==='ForInStatement' || examine(node).isLoop) {
|
2363
|
-
var depth = 0
|
2364
|
-
for (var n=0;
|
2365
|
-
if (path[n].self.type==='ForOfStatement' || path[n].self.type==='ForInStatement' || examine(path[n].self).isLoop)
|
2366
|
-
|
2367
|
-
|
2368
|
-
|
2369
|
-
|
2370
|
-
|
2371
|
-
|
2372
|
-
node.$label = path[0].parent.label ;
|
2420
|
+
if (node.type === 'ForOfStatement' || node.type === 'ForInStatement' || examine(node).isLoop) {
|
2421
|
+
var depth = 0;
|
2422
|
+
for (var n = 0;n < path.length; n++)
|
2423
|
+
if (path[n].self.type === 'ForOfStatement' || path[n].self.type === 'ForInStatement' || examine(path[n].self).isLoop)
|
2424
|
+
depth += 1;
|
2425
|
+
else if (examine(path[n].self).isFunction)
|
2426
|
+
break;
|
2427
|
+
node.$depth = depth;
|
2428
|
+
if (path[0].parent.type === 'LabeledStatement') {
|
2429
|
+
node.$label = path[0].parent.label;
|
2373
2430
|
} else {
|
2374
|
-
node.$label = null
|
2431
|
+
node.$label = null;
|
2375
2432
|
}
|
2376
2433
|
}
|
2377
2434
|
return true;
|
2378
2435
|
});
|
2379
2436
|
return ast;
|
2380
2437
|
}
|
2381
|
-
|
2438
|
+
|
2382
2439
|
function mapSupers(classNode, engine) {
|
2383
2440
|
function superID() {
|
2384
2441
|
return classNode.$superID = classNode.$superID || ident("$super$" + generatedSymbol++);
|
2385
2442
|
}
|
2386
|
-
|
2443
|
+
|
2387
2444
|
return function (method) {
|
2388
2445
|
method = getMemberFunction(method);
|
2389
|
-
if (method && examine(method).isAsync && (!engine || method.kind === 'get' || contains(method,function(n){
|
2390
|
-
|
2391
|
-
|
2392
|
-
|
2393
|
-
|
2394
|
-
|
2395
|
-
},true))) {
|
2396
|
-
|
2446
|
+
if (method && examine(method).isAsync && (!engine || method.kind === 'get' || contains(method, function (n) {
|
2447
|
+
return examine(n).isFunction && contains(n, function (n) {
|
2448
|
+
return n.type === 'Super';
|
2449
|
+
}) && contains(n, function (n) {
|
2450
|
+
return n.async && (n.type === 'ReturnStatement' || n.type === 'ThrowStatement');
|
2451
|
+
});
|
2452
|
+
}, true))) {
|
2453
|
+
treeWalk(method.body, function (node, descend, path) {
|
2397
2454
|
var r;
|
2398
2455
|
if (!examine(node).isClass) {
|
2399
2456
|
descend();
|
@@ -2401,18 +2458,18 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
2401
2458
|
if (path[0].parent.type === 'MemberExpression') {
|
2402
2459
|
if (path[1].parent.type === 'CallExpression' && path[1].field === 'callee') {
|
2403
2460
|
// super[m](...) maps to: this.$superid(m).call(this,...)
|
2404
|
-
r =
|
2405
|
-
'super':superID(),
|
2406
|
-
field:path[0].parent.computed ? path[0].parent.property:literal(path[0].parent.property.name),
|
2407
|
-
args:path[1].parent.arguments
|
2408
|
-
}).expr
|
2461
|
+
r = parsePart("this.$super($field).call(this,$args)", {
|
2462
|
+
'super': superID(),
|
2463
|
+
field: path[0].parent.computed ? path[0].parent.property : literal(path[0].parent.property.name),
|
2464
|
+
args: path[1].parent.arguments
|
2465
|
+
}).expr;
|
2409
2466
|
path[2].replace(r);
|
2410
2467
|
} else {
|
2411
2468
|
// super[f], maps to: this.$superid(f)
|
2412
|
-
r =
|
2413
|
-
'super':superID(),
|
2414
|
-
field:path[0].parent.computed ?path[0].parent.property : literal(path[0].parent.property.name)
|
2415
|
-
}).expr
|
2469
|
+
r = parsePart("this.$super($field)", {
|
2470
|
+
'super': superID(),
|
2471
|
+
field: path[0].parent.computed ? path[0].parent.property : literal(path[0].parent.property.name)
|
2472
|
+
}).expr;
|
2416
2473
|
path[1].replace(r);
|
2417
2474
|
}
|
2418
2475
|
} else {
|
@@ -2424,14 +2481,16 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
2424
2481
|
}
|
2425
2482
|
};
|
2426
2483
|
}
|
2427
|
-
|
2428
|
-
function fixSuperReferences(ast,engine) {
|
2429
|
-
return
|
2484
|
+
|
2485
|
+
function fixSuperReferences(ast, engine) {
|
2486
|
+
return treeWalk(ast, function (node, descend, path) {
|
2430
2487
|
descend();
|
2431
2488
|
if (node.type === 'ClassDeclaration' || node.type === 'ClassExpression') {
|
2432
|
-
node.body.body.forEach(mapSupers(node,engine));
|
2489
|
+
node.body.body.forEach(mapSupers(node, engine));
|
2433
2490
|
if (node.$superID) {
|
2434
|
-
var method =
|
2491
|
+
var method = parsePart("(function($field) { return super[$field] })", {
|
2492
|
+
field: ident("$field")
|
2493
|
+
}).expr;
|
2435
2494
|
if (opts.babelTree) {
|
2436
2495
|
method.type = 'ClassMethod';
|
2437
2496
|
method.key = node.$superID;
|
@@ -2449,11 +2508,11 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
2449
2508
|
}
|
2450
2509
|
});
|
2451
2510
|
}
|
2452
|
-
|
2511
|
+
|
2453
2512
|
function blockifyArrows(ast) {
|
2454
|
-
|
2513
|
+
treeWalk(ast, function (node, descend, path) {
|
2455
2514
|
var awaiting = containsAwait(node);
|
2456
|
-
if (awaiting)
|
2515
|
+
if (awaiting) {
|
2457
2516
|
if (node.type === 'ArrowFunctionExpression' && node.body.type !== 'BlockStatement') {
|
2458
2517
|
node.body = {
|
2459
2518
|
type: "BlockStatement",
|
@@ -2469,10 +2528,10 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
2469
2528
|
});
|
2470
2529
|
return ast;
|
2471
2530
|
}
|
2472
|
-
|
2531
|
+
|
2473
2532
|
function exposeCompilerOpts(ast) {
|
2474
2533
|
// Expose compiler
|
2475
|
-
|
2534
|
+
treeWalk(ast, function (node, descend, path) {
|
2476
2535
|
descend();
|
2477
2536
|
if (node.type === 'Identifier' && node.name === '__nodent') {
|
2478
2537
|
coerce(node, literal(opts));
|
@@ -2480,47 +2539,42 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
2480
2539
|
});
|
2481
2540
|
return ast;
|
2482
2541
|
}
|
2483
|
-
|
2542
|
+
|
2484
2543
|
/* Called with a Program or FunctionDeclaration.body */
|
2485
2544
|
function isStrict(node) {
|
2486
|
-
if (node.type === 'Program' && node.sourceType === 'module')
|
2487
|
-
return true
|
2488
|
-
|
2489
|
-
|
2490
|
-
|
2491
|
-
|
2492
|
-
|
2493
|
-
|
2494
|
-
|
2495
|
-
|
2496
|
-
|
2497
|
-
if (examine(nodes[i]).isDirective && nodes[i].expression.value.match(/^\s*use\s+strict\s*$/))
|
2498
|
-
|
2499
|
-
return false
|
2545
|
+
if (node.type === 'Program' && node.sourceType === 'module')
|
2546
|
+
return true;
|
2547
|
+
var nodes;
|
2548
|
+
if (node.type === 'Program')
|
2549
|
+
nodes = node.body;
|
2550
|
+
else if (examine(node).isFunction)
|
2551
|
+
nodes = node.body.body;
|
2552
|
+
else
|
2553
|
+
return false;
|
2554
|
+
if (nodes)
|
2555
|
+
for (var i = 0;i < nodes.length; i++)
|
2556
|
+
if (examine(nodes[i]).isDirective && nodes[i].expression.value.match(/^\s*use\s+strict\s*$/))
|
2557
|
+
return true;
|
2558
|
+
return false;
|
2500
2559
|
}
|
2501
|
-
|
2560
|
+
|
2502
2561
|
function containsBlockScopedDeclarations(nodes) {
|
2503
2562
|
for (var i = 0;i < nodes.length; i++) {
|
2504
2563
|
var node = nodes[i];
|
2505
|
-
if (node.type === 'ClassDeclaration' ||
|
2506
|
-
(node.type === 'VariableDeclaration' && (node.kind === 'let' || node.kind === 'const')) ||
|
2507
|
-
(node.type === 'FunctionDeclaration' && node.id && node.id.name && !node.$continuation)) {
|
2564
|
+
if (node.type === 'ClassDeclaration' || node.type === 'VariableDeclaration' && (node.kind === 'let' || node.kind === 'const') || node.type === 'FunctionDeclaration' && node.id && node.id.name && !node.$continuation) {
|
2508
2565
|
return true;
|
2509
2566
|
}
|
2510
2567
|
}
|
2511
2568
|
return false;
|
2512
2569
|
}
|
2513
|
-
|
2570
|
+
|
2514
2571
|
/* Remove un-necessary nested blocks and crunch down empty function implementations */
|
2515
2572
|
function cleanCode(ast) {
|
2516
2573
|
// Coalese BlockStatements
|
2517
|
-
|
2574
|
+
treeWalk(ast, function (node, descend, path) {
|
2518
2575
|
descend();
|
2519
|
-
if (node.type==='ArrowFunctionExpression'
|
2520
|
-
|
2521
|
-
&& node.body.body.length===1
|
2522
|
-
&& node.body.body[0].type==='ReturnStatement') {
|
2523
|
-
node.body = node.body.body[0].argument
|
2576
|
+
if (node.type === 'ArrowFunctionExpression' && node.body.type === 'BlockStatement' && node.body.body.length === 1 && node.body.body[0].type === 'ReturnStatement') {
|
2577
|
+
node.body = node.body.body[0].argument;
|
2524
2578
|
} else {
|
2525
2579
|
var block, child;
|
2526
2580
|
// If this node is a block with vanilla BlockStatements (no controlling entity), merge them
|
@@ -2529,7 +2583,7 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
2529
2583
|
// For ES6, this needs more care, as blocks containing 'let/const/class' have a scope of their own
|
2530
2584
|
for (var i = 0;i < block.length; i++) {
|
2531
2585
|
if ((child = examine(block[i]).isBlockStatement) && !containsBlockScopedDeclarations(child)) {
|
2532
|
-
if (!containsBlockScopedDeclarations(block[i]))
|
2586
|
+
if (!containsBlockScopedDeclarations(block[i]))
|
2533
2587
|
[].splice.apply(block, [i,1].concat(child));
|
2534
2588
|
}
|
2535
2589
|
}
|
@@ -2537,7 +2591,7 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
2537
2591
|
}
|
2538
2592
|
});
|
2539
2593
|
// Truncate BlockStatements with a Jump (break;continue;return;throw) inside
|
2540
|
-
|
2594
|
+
treeWalk(ast, function (node, descend, path) {
|
2541
2595
|
descend();
|
2542
2596
|
if (examine(node).isJump) {
|
2543
2597
|
var ref = path[0];
|
@@ -2546,9 +2600,9 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
2546
2600
|
var ctn = ref.parent[ref.field];
|
2547
2601
|
while (i < ctn.length) {
|
2548
2602
|
// Remove any statements EXCEPT for function/var definitions
|
2549
|
-
if (ctn[i].type === 'VariableDeclaration' || examine(ctn[i]).isFunction && ctn[i].id)
|
2603
|
+
if (ctn[i].type === 'VariableDeclaration' || examine(ctn[i]).isFunction && ctn[i].id)
|
2550
2604
|
i += 1;
|
2551
|
-
else
|
2605
|
+
else
|
2552
2606
|
ctn.splice(i, 1);
|
2553
2607
|
}
|
2554
2608
|
}
|
@@ -2556,11 +2610,11 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
2556
2610
|
});
|
2557
2611
|
/* Inline continuations that are only referenced once */
|
2558
2612
|
// Find any continuations that have a single reference
|
2559
|
-
|
2613
|
+
treeWalk(ast, function (node, descend, path) {
|
2560
2614
|
descend();
|
2561
2615
|
if (node.$thisCall && continuations[node.name]) {
|
2562
2616
|
if (continuations[node.name].ref) {
|
2563
|
-
delete continuations[node.name]; //
|
2617
|
+
delete continuations[node.name]; // Multiple ref
|
2564
2618
|
} else {
|
2565
2619
|
continuations[node.name].ref = node.$thisCall;
|
2566
2620
|
}
|
@@ -2571,14 +2625,14 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
2571
2625
|
});
|
2572
2626
|
if (calls.length) {
|
2573
2627
|
// Replace all the calls to the continuation with the body from the continuation followed by 'return;'
|
2574
|
-
|
2628
|
+
treeWalk(ast, function (node, descend, path) {
|
2575
2629
|
descend();
|
2576
2630
|
if (calls.indexOf(node) >= 0) {
|
2577
2631
|
if (path[1].self.type === 'ReturnStatement') {
|
2578
2632
|
var sym = node.$thisCallName;
|
2579
2633
|
var repl = cloneNode(continuations[sym].def.body.body);
|
2580
2634
|
continuations[sym].$inlined = true;
|
2581
|
-
if (!examine(path[1].self).isJump)
|
2635
|
+
if (!examine(path[1].self).isJump)
|
2582
2636
|
repl.push({
|
2583
2637
|
type: 'ReturnStatement'
|
2584
2638
|
});
|
@@ -2590,55 +2644,47 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
2590
2644
|
return continuations[c].$inlined && continuations[c].def;
|
2591
2645
|
});
|
2592
2646
|
// Remove all the (now inline) declarations of the continuations
|
2593
|
-
|
2647
|
+
treeWalk(ast, function (node, descend, path) {
|
2594
2648
|
descend();
|
2595
2649
|
if (defs.indexOf(node) >= 0) {
|
2596
2650
|
path[0].remove();
|
2597
2651
|
}
|
2598
2652
|
});
|
2599
2653
|
}
|
2600
|
-
|
2601
2654
|
// Hoist generated FunctionDeclarations within ES5 Strict functions (actually put them at the
|
2602
2655
|
// end of the scope-block, don't hoist them, it's just an expensive operation)
|
2603
|
-
var looksLikeES6 = (ast.type==='Program' && ast.sourceType==='module') || contains(ast,function(n){
|
2604
|
-
return examine(n).isES6 ;
|
2605
|
-
},true) ;
|
2606
|
-
|
2607
2656
|
if (!looksLikeES6) {
|
2608
|
-
var useStrict = isStrict(ast)
|
2609
|
-
(function(ast){
|
2610
|
-
|
2611
|
-
if (node.type==='Program' || node.type==='FunctionDeclaration' || node.type==='FunctionExpression') {
|
2612
|
-
var wasStrict = useStrict
|
2613
|
-
useStrict = useStrict || isStrict(node)
|
2657
|
+
var useStrict = isStrict(ast);
|
2658
|
+
(function (ast) {
|
2659
|
+
treeWalk(ast, function (node, descend, path) {
|
2660
|
+
if (node.type === 'Program' || node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression') {
|
2661
|
+
var wasStrict = useStrict;
|
2662
|
+
useStrict = useStrict || isStrict(node);
|
2614
2663
|
if (useStrict) {
|
2615
2664
|
descend();
|
2616
|
-
|
2617
|
-
var
|
2618
|
-
|
2619
|
-
|
2620
|
-
return path[0].parent !== functionScope ;
|
2665
|
+
var functionScope = node.type === 'Program' ? node : node.body;
|
2666
|
+
var functions = scopedNodes(functionScope, function (n, path) {
|
2667
|
+
if (n.type === 'FunctionDeclaration') {
|
2668
|
+
return path[0].parent !== functionScope;
|
2621
2669
|
}
|
2622
|
-
})
|
2623
|
-
|
2670
|
+
},['isScope']);
|
2624
2671
|
functions = functions.map(function (path) {
|
2625
|
-
return path[0].remove()
|
2672
|
+
return path[0].remove();
|
2626
2673
|
});
|
2627
|
-
[].push.apply(functionScope.body,functions)
|
2674
|
+
[].push.apply(functionScope.body, functions);
|
2628
2675
|
} else {
|
2629
2676
|
descend();
|
2630
2677
|
}
|
2631
|
-
useStrict = wasStrict
|
2678
|
+
useStrict = wasStrict;
|
2632
2679
|
} else {
|
2633
2680
|
descend();
|
2634
2681
|
}
|
2635
|
-
})
|
2682
|
+
});
|
2636
2683
|
})(ast);
|
2637
2684
|
}
|
2638
|
-
|
2639
2685
|
/*
|
2640
2686
|
function replaceSymbols(ast,from,to) {
|
2641
|
-
|
2687
|
+
treeWalk(ast,function(node,descend,path){
|
2642
2688
|
descend() ;
|
2643
2689
|
if (node.type=='Identifier' && node.name==from) {
|
2644
2690
|
node.name = to ;
|
@@ -2663,32 +2709,219 @@ function asynchronize(pr, __sourceMapping, opts, logger) {
|
|
2663
2709
|
// these can be simplified to:
|
2664
2710
|
// $return
|
2665
2711
|
*/
|
2666
|
-
|
2667
|
-
|
2668
|
-
|
2669
|
-
|
2670
|
-
|
2671
|
-
|
2672
|
-
|
2673
|
-
|
2712
|
+
// Remove all the 'hidden' node info generated during transformation
|
2713
|
+
treeWalk(ast, function (node, descend, path) {
|
2714
|
+
descend();
|
2715
|
+
Object.keys(node).filter(function (k) {
|
2716
|
+
return k[0] === '$';
|
2717
|
+
}).forEach(function (k) {
|
2718
|
+
delete node[k];
|
2719
|
+
});
|
2720
|
+
});
|
2674
2721
|
return ast;
|
2675
2722
|
}
|
2723
|
+
|
2676
2724
|
}
|
2677
2725
|
|
2678
|
-
|
2679
|
-
|
2680
|
-
|
2681
|
-
|
2682
|
-
|
2683
|
-
|
2684
|
-
|
2685
|
-
|
2686
|
-
|
2687
|
-
|
2688
|
-
|
2689
|
-
|
2726
|
+
/* AST helpers: treeWalk */
|
2727
|
+
function loc(old, repl) {
|
2728
|
+
['start','end','loc','range'].forEach(function (k) {
|
2729
|
+
if (k in old && !(k in repl))
|
2730
|
+
repl[k] = old[k];
|
2731
|
+
});
|
2732
|
+
}
|
2733
|
+
|
2734
|
+
var referencePrototypes = {
|
2735
|
+
replace: function (newNode) {
|
2736
|
+
if (Array.isArray(newNode) && newNode.length === 1)
|
2737
|
+
newNode = newNode[0];
|
2738
|
+
if ('index' in this) {
|
2739
|
+
loc(this.parent[this.field][this.index], newNode);
|
2740
|
+
if (Array.isArray(newNode)) {
|
2741
|
+
[].splice.apply(this.parent[this.field], [this.index,1].concat(newNode));
|
2742
|
+
} else {
|
2743
|
+
this.parent[this.field][this.index] = newNode;
|
2690
2744
|
}
|
2691
|
-
|
2745
|
+
} else {
|
2746
|
+
loc(this.parent[this.field], newNode);
|
2747
|
+
if (Array.isArray(newNode)) {
|
2748
|
+
this.parent[this.field] = {
|
2749
|
+
type: 'BlockStatement',
|
2750
|
+
body: newNode
|
2751
|
+
};
|
2752
|
+
} else {
|
2753
|
+
this.parent[this.field] = newNode;
|
2754
|
+
}
|
2755
|
+
}
|
2756
|
+
return this.self;
|
2757
|
+
},
|
2758
|
+
append: function (newNode) {
|
2759
|
+
if (Array.isArray(newNode) && newNode.length === 1)
|
2760
|
+
newNode = newNode[0];
|
2761
|
+
if ('index' in this) {
|
2762
|
+
if (Array.isArray(newNode)) {
|
2763
|
+
[].splice.apply(this.parent[this.field], [this.index + 1,0].concat(newNode));
|
2764
|
+
} else {
|
2765
|
+
this.parent[this.field].splice(this.index + 1, 0, newNode);
|
2766
|
+
}
|
2767
|
+
} else {
|
2768
|
+
throw new Error("Cannot append Element node to non-array");
|
2692
2769
|
}
|
2770
|
+
return this.self;
|
2771
|
+
},
|
2772
|
+
index: function () {
|
2773
|
+
return this.parent[this.field].indexOf(this.self);
|
2774
|
+
},
|
2775
|
+
removeElement: function () {
|
2776
|
+
return this.parent[this.field].splice(this.index, 1)[0];
|
2777
|
+
},
|
2778
|
+
removeNode: function () {
|
2779
|
+
var r = this.parent[this.field];
|
2780
|
+
delete this.parent[this.field];
|
2781
|
+
return r;
|
2782
|
+
}
|
2783
|
+
};
|
2784
|
+
var notNodeKeys = {
|
2785
|
+
start: true,
|
2786
|
+
end: true,
|
2787
|
+
loc: true,
|
2788
|
+
range: true,
|
2789
|
+
type: true
|
2790
|
+
};
|
2791
|
+
function forEachNodeKey(n, down) {
|
2792
|
+
if (n && n.type) {
|
2793
|
+
var keys = Object.keys(n).filter(function (k) {
|
2794
|
+
return k[0] != '$' && k[0] != '_' && !(k in notNodeKeys) && typeof n[k] === 'object' && n[k] && (typeof n[k].type === 'string' || Array.isArray(n[k]));
|
2795
|
+
});
|
2796
|
+
keys.forEach(function (member) {
|
2797
|
+
if (Array.isArray(n[member])) {
|
2798
|
+
n[member].forEach(function (node, index) {
|
2799
|
+
down(node, member, index);
|
2800
|
+
});
|
2801
|
+
} else
|
2802
|
+
down(n[member], member, null);
|
2803
|
+
});
|
2804
|
+
}
|
2805
|
+
}
|
2806
|
+
|
2807
|
+
function treeWalk(n, walker, state) {
|
2808
|
+
if (!state) {
|
2809
|
+
state = [{
|
2810
|
+
self: n
|
2811
|
+
}];
|
2812
|
+
state.replace = function (pos, newNode) {
|
2813
|
+
state[pos].replace(newNode);
|
2814
|
+
};
|
2815
|
+
}
|
2816
|
+
function descend() {
|
2817
|
+
forEachNodeKey(n, function down(sub, key, index) {
|
2818
|
+
if (!sub)
|
2819
|
+
return;
|
2820
|
+
var ref = {
|
2821
|
+
replace: referencePrototypes.replace,
|
2822
|
+
append: referencePrototypes.append,
|
2823
|
+
self: sub,
|
2824
|
+
parent: n,
|
2825
|
+
field: key
|
2826
|
+
};
|
2827
|
+
if (index !== null) {
|
2828
|
+
ref.index = true;
|
2829
|
+
Object.defineProperties(ref, {
|
2830
|
+
index: {
|
2831
|
+
enumerable: true,
|
2832
|
+
get: referencePrototypes.index
|
2833
|
+
}
|
2834
|
+
});
|
2835
|
+
ref.remove = referencePrototypes.removeElement;
|
2836
|
+
} else {
|
2837
|
+
ref.remove = referencePrototypes.removeNode;
|
2838
|
+
}
|
2839
|
+
state.unshift(ref);
|
2840
|
+
treeWalk(ref.self, walker, state);
|
2841
|
+
state.shift();
|
2842
|
+
});
|
2843
|
+
}
|
2844
|
+
|
2845
|
+
;
|
2846
|
+
walker(n, descend, state);
|
2847
|
+
return n;
|
2848
|
+
}
|
2849
|
+
|
2850
|
+
/* AST helpers: partialParser */
|
2851
|
+
function partialParser(parse) {
|
2852
|
+
var parseCache = {};
|
2853
|
+
return function partialParse(code, args) {
|
2854
|
+
if (!parseCache[code]) {
|
2855
|
+
parseCache[code] = parse(code);
|
2856
|
+
}
|
2857
|
+
var result = substitute(parseCache[code]);
|
2858
|
+
return {
|
2859
|
+
body: result.body,
|
2860
|
+
expr: result.body[0].type === 'ExpressionStatement' ? result.body[0].expression : null
|
2861
|
+
};
|
2862
|
+
/* parse and substitute:
|
2863
|
+
*
|
2864
|
+
* $1 Substitute the specified expression. If $1 occupies a slot which is an array of expressions (e.g arguments, params)
|
2865
|
+
* and the passed argument is an array, subtitute the whole set
|
2866
|
+
* {$:1} Substitute a single statement
|
2867
|
+
*
|
2868
|
+
*/
|
2869
|
+
function substitute(src, dest) {
|
2870
|
+
if (Array.isArray(dest) && !Array.isArray(src))
|
2871
|
+
throw new Error("Can't substitute an array for a node");
|
2872
|
+
dest = dest || {};
|
2873
|
+
Object.keys(src).forEach(function (k) {
|
2874
|
+
if (!(src[k] instanceof Object))
|
2875
|
+
return dest[k] = src[k];
|
2876
|
+
function moreNodes(v) {
|
2877
|
+
if (typeof v === "function")
|
2878
|
+
v = v();
|
2879
|
+
dest = dest.concat(v);
|
2880
|
+
return dest;
|
2881
|
+
}
|
2882
|
+
|
2883
|
+
function copyNode(v) {
|
2884
|
+
if (typeof v === "function")
|
2885
|
+
v = v();
|
2886
|
+
dest[k] = v;
|
2887
|
+
return dest;
|
2888
|
+
}
|
2889
|
+
|
2890
|
+
// The src is an array, so create/grow the destination
|
2891
|
+
// It could an an array of expressions $1,$2,$3 or statements $:1;$:2;$:3;
|
2892
|
+
if (Array.isArray(src[k]))
|
2893
|
+
return dest[k] = substitute(src[k], []);
|
2894
|
+
var p;
|
2895
|
+
if (Array.isArray(dest))
|
2896
|
+
p = moreNodes;
|
2897
|
+
else
|
2898
|
+
p = copyNode;
|
2899
|
+
// Substitute a single identifier $.. with an expression (TODO: test provided arg is an expression node)
|
2900
|
+
if (src[k].type === 'Identifier' && src[k].name[0] === '$')
|
2901
|
+
return p(args[src[k].name.slice(1)]);
|
2902
|
+
// Substitute a single labeled statement $:.. with a statement (TODO: test provided arg is a statement node)
|
2903
|
+
if (src[k].type === 'LabeledStatement' && src[k].label.name === '$') {
|
2904
|
+
var spec = src[k].body.expression;
|
2905
|
+
return p(args[spec.name || spec.value]);
|
2906
|
+
}
|
2907
|
+
// Magic label to call a function to modify a statement node $$method: <statement>
|
2908
|
+
// The newNode = args.method(oldNode)
|
2909
|
+
if (src[k].type === 'LabeledStatement' && src[k].label.name.slice(0, 2) === '$$') {
|
2910
|
+
return p(args[src[k].label.name.slice(2)](substitute(src[k]).body));
|
2911
|
+
}
|
2912
|
+
return p(substitute(src[k]));
|
2913
|
+
});
|
2914
|
+
return dest;
|
2915
|
+
}
|
2916
|
+
};
|
2917
|
+
}
|
2918
|
+
|
2919
|
+
module.exports = {
|
2920
|
+
treeWalker: treeWalk,
|
2921
|
+
partialParser: partialParser,
|
2922
|
+
babelLiteralNode: babelLiteralNode,
|
2923
|
+
transform: function (pr, opts, helpers) {
|
2924
|
+
/* DEBUG USE ONLY: global.printNode = helpers.printNode ;*/
|
2925
|
+
return asynchronize(pr, opts, helpers.logger || function(){}, partialParser(helpers.parse), helpers.printNode);
|
2693
2926
|
}
|
2694
2927
|
};
|