jass 0.9.1 → 0.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/jass.rb +5 -0
  4. data/lib/jass/compiler.rb +5 -0
  5. data/lib/jass/plugin.rb +2 -1
  6. data/lib/jass/version.rb +1 -1
  7. data/vendor/node_modules/@types/estree/index.d.ts +4 -2
  8. data/vendor/node_modules/@types/estree/package.json +2 -2
  9. data/vendor/node_modules/acorn/bin/_acorn.js +12 -12
  10. data/vendor/node_modules/acorn/bin/run_test262.js +2 -3
  11. data/vendor/node_modules/acorn/bin/test262.whitelist +0 -5
  12. data/vendor/node_modules/acorn/dist/acorn.es.js +76 -68
  13. data/vendor/node_modules/acorn/dist/acorn.js +76 -68
  14. data/vendor/node_modules/acorn/dist/acorn_loose.es.js +42 -30
  15. data/vendor/node_modules/acorn/dist/acorn_loose.js +42 -30
  16. data/vendor/node_modules/acorn/dist/walk.es.js +47 -43
  17. data/vendor/node_modules/acorn/dist/walk.js +47 -43
  18. data/vendor/node_modules/acorn/package.json +9 -5
  19. data/vendor/node_modules/chalk/index.js.flow +93 -0
  20. data/vendor/node_modules/chalk/package.json +8 -3
  21. data/vendor/node_modules/color-convert/conversions.js +36 -29
  22. data/vendor/node_modules/color-convert/package.json +4 -4
  23. data/vendor/node_modules/estree-walker/index.d.ts +17 -0
  24. data/vendor/node_modules/estree-walker/package.json +2 -1
  25. data/vendor/node_modules/fill-range/index.js +2 -2
  26. data/vendor/node_modules/fill-range/package.json +24 -7
  27. data/vendor/node_modules/is-reference/node_modules/@types/estree/index.d.ts +546 -0
  28. data/vendor/node_modules/is-reference/node_modules/@types/estree/package.json +22 -0
  29. data/vendor/node_modules/math-random/browser.js +17 -0
  30. data/vendor/node_modules/math-random/node.js +13 -0
  31. data/vendor/node_modules/math-random/package.json +31 -0
  32. data/vendor/node_modules/math-random/test.js +26 -0
  33. data/vendor/node_modules/nodent-compiler/compiler.js +115 -11
  34. data/vendor/node_modules/nodent-compiler/{lib/output.js → output.js} +0 -0
  35. data/vendor/node_modules/nodent-compiler/package.json +8 -4
  36. data/vendor/node_modules/{nodent-compiler/lib → nodent-transform}/arboriculture.js +1340 -1107
  37. data/vendor/node_modules/nodent-transform/package.json +19 -0
  38. data/vendor/node_modules/path-parse/package.json +1 -1
  39. data/vendor/node_modules/pretty-ms/index.js +2 -1
  40. data/vendor/node_modules/pretty-ms/package.json +2 -3
  41. data/vendor/node_modules/randomatic/index.js +12 -2
  42. data/vendor/node_modules/randomatic/node_modules/is-number/index.js +6 -7
  43. data/vendor/node_modules/randomatic/node_modules/is-number/package.json +9 -16
  44. data/vendor/node_modules/randomatic/node_modules/kind-of/index.js +112 -102
  45. data/vendor/node_modules/randomatic/node_modules/kind-of/package.json +18 -20
  46. data/vendor/node_modules/randomatic/package.json +15 -13
  47. data/vendor/node_modules/repeat-element/index.js +1 -1
  48. data/vendor/node_modules/repeat-element/package.json +27 -22
  49. data/vendor/node_modules/resolve/lib/async.js +20 -17
  50. data/vendor/node_modules/resolve/lib/core.js +2 -2
  51. data/vendor/node_modules/resolve/lib/core.json +4 -1
  52. data/vendor/node_modules/resolve/lib/sync.js +52 -13
  53. data/vendor/node_modules/resolve/package.json +3 -3
  54. data/vendor/node_modules/rollup-plugin-commonjs/dist/rollup-plugin-commonjs.cjs.js +50 -12
  55. data/vendor/node_modules/rollup-plugin-commonjs/dist/rollup-plugin-commonjs.es.js +50 -12
  56. data/vendor/node_modules/rollup-plugin-commonjs/package.json +2 -2
  57. data/vendor/node_modules/rollup-plugin-commonjs/src/index.js +49 -11
  58. data/vendor/node_modules/rollup-plugin-commonjs/src/transform.js +1 -1
  59. data/vendor/node_modules/rollup-plugin-node-resolve/dist/rollup-plugin-node-resolve.cjs.js +82 -85
  60. data/vendor/node_modules/rollup-plugin-node-resolve/dist/rollup-plugin-node-resolve.es.js +82 -85
  61. data/vendor/node_modules/rollup-plugin-node-resolve/package.json +1 -1
  62. data/vendor/node_modules/rollup-plugin-node-resolve/src/index.js +81 -84
  63. data/vendor/node_modules/rollup-pluginutils/dist/pluginutils.cjs.js +81 -2
  64. data/vendor/node_modules/rollup-pluginutils/dist/pluginutils.es.js +81 -3
  65. data/vendor/node_modules/rollup-pluginutils/package.json +12 -6
  66. data/vendor/node_modules/rollup-pluginutils/src/attachScopes.js +10 -2
  67. data/vendor/node_modules/rollup-pluginutils/src/dataToEsm.js +69 -0
  68. data/vendor/node_modules/rollup-pluginutils/src/index.js +1 -0
  69. data/vendor/node_modules/supports-color/index.js +1 -5
  70. data/vendor/node_modules/supports-color/package.json +51 -51
  71. data/vendor/yarn.lock +65 -70
  72. metadata +16 -21
  73. data/vendor/node_modules/irregular-plurals/irregular-plurals.json +0 -146
  74. data/vendor/node_modules/irregular-plurals/package.json +0 -39
  75. data/vendor/node_modules/nodent-compiler/lib/parser.js +0 -291
  76. data/vendor/node_modules/path-parse/index.min.js +0 -1
  77. data/vendor/node_modules/path-parse/test.min.js +0 -1
  78. data/vendor/node_modules/plur/index.js +0 -20
  79. data/vendor/node_modules/plur/package.json +0 -42
  80. data/vendor/node_modules/randomatic/node_modules/is-number/node_modules/kind-of/index.js +0 -116
  81. data/vendor/node_modules/randomatic/node_modules/is-number/node_modules/kind-of/package.json +0 -90
  82. data/vendor/node_modules/rollup-pluginutils/dist/pluginutils.es6.js +0 -217
  83. data/vendor/node_modules/rollup-pluginutils/node_modules/estree-walker/dist/estree-walker.es.js +0 -55
  84. data/vendor/node_modules/rollup-pluginutils/node_modules/estree-walker/dist/estree-walker.es6.js +0 -59
  85. data/vendor/node_modules/rollup-pluginutils/node_modules/estree-walker/dist/estree-walker.umd.js +0 -65
  86. data/vendor/node_modules/rollup-pluginutils/node_modules/estree-walker/package.json +0 -33
  87. 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,13 @@
1
+ var crypto = require('crypto')
2
+ var max = Math.pow(2, 32)
3
+
4
+ module.exports = random
5
+ module.exports.cryptographic = true
6
+
7
+ function random () {
8
+ var buf = crypto
9
+ .randomBytes(4)
10
+ .toString('hex')
11
+
12
+ return parseInt(buf, 16) / max
13
+ }
@@ -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
- var parser = require('./lib/parser') ;
2
- var treeSurgeon = require('./lib/arboriculture') ;
3
- var outputCode = require('./lib/output') ;
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
- buffer = new Buffer(str.toString(), 'binary');
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.asynchronize(pr,null,opts,this.log || noLogger) ;
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 = parser.parse(r.origCode, opts && opts.parser) ;
177
+ r.ast = acornParse(r.origCode, opts && opts.parser) ;
104
178
  if (opts.babelTree) {
105
- parser.treeWalker(r.ast,function(node,descend,path){
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
- initOpts.log("Warning: nodent.Promise is deprecated. Use nodent.Thenable instead");
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
 
@@ -1,15 +1,19 @@
1
1
  {
2
2
  "name": "nodent-compiler",
3
- "version": "3.1.7",
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/basic.js # Please install 'nodent' and test the compiler fully from there."
7
+ "test": "node tests tests/semantics/*"
8
8
  },
9
9
  "dependencies": {
10
10
  "acorn": ">=2.5.2",
11
- "acorn-es7-plugin": ">=1.1.6",
12
- "source-map": "^0.5.6"
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 = { start:true, end: true, loc: true, range: true } ;
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) return ;
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
- getScope: function(){ 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},
50
- isScope: function(){ 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')},
51
- isFunction: function(){ 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'},
52
- isClass: function(){ return this.node.type === 'ClassDeclaration' || this.node.type === 'ClassExpression'},
53
- isBlockStatement: function(){ return this.node.type==='ClassBody' || this.node.type === 'Program' || this.node.type === 'BlockStatement' ? this.node.body : this.node.type === 'SwitchCase' ? this.node.consequent : false},
54
- isExpressionStatement: function(){ return this.node.type === 'ExpressionStatement'},
55
- isLiteral: function(){ 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'},
56
- isDirective: function(){ return this.node.type === 'ExpressionStatement' && (this.node.expression.type === 'StringLiteral' || this.node.expression.type === 'Literal' && typeof this.node.expression.value === 'string')},
57
- isUnaryExpression: function(){ return this.node.type === 'UnaryExpression'},
58
- isAwait: function(){ return this.node.type === 'AwaitExpression' && !this.node.$hidden},
59
- isAsync: function(){ return this.node.async },
60
- isStatement: function(){ return this.node.type.match(/[a-zA-Z]+Declaration/) !== null || this.node.type.match(/[a-zA-Z]+Statement/) !== null},
61
- isExpression: function(){ return this.node.type.match(/[a-zA-Z]+Expression/) !== null},
62
- isLoop: function(){ return this.node.type === 'ForStatement' || this.node.type === 'WhileStatement' || this.node.type === 'DoWhileStatement'}, // Other loops?
63
- isJump: function(){ return this.node.type === 'ReturnStatement' || this.node.type === 'ThrowStatement' || this.node.type === 'BreakStatement' || this.node.type === 'ContinueStatement'},
64
- isES6: function(){
65
- switch (this.node.type) {
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
- return true ;
85
-
106
+ return true;
86
107
  case 'VariableDeclaration':
87
- return this.node.kind && this.node.kind !== 'var' ;
88
-
108
+ return this.node.kind && this.node.kind === 'let';
89
109
  case 'FunctionDeclaration':
90
110
  case 'FunctionExpression':
91
- return !!this.node.generator;
111
+ return !(!this.node.generator);
92
112
  }
93
- }
113
+ }
94
114
  };
95
-
96
- var NodeExaminer = {} ;
97
- Object.keys(examinations).forEach(function(k){
98
- Object.defineProperty(NodeExaminer,k,{
99
- get:examinations[k]
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, __sourceMapping, opts, logger) {
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
- genIdent[k.slice(1)] = ident(opts[k]);
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 = parser.part("try {$:0} catch($2) {return $1($2)}",[cloneNode(left.body),arg,ident('$boundEx')]).body ;
259
- } else if (opts.es6target && !left.id && left.type.indexOf("Function")===0) {
260
- left.type = 'ArrowFunctionExpression' ;
261
- return left ;
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
- return parser.part("$0.bind(this)",[left]).expr;
290
+ if (containsThis(left))
291
+ return parsePart("$0.bind(this)", [left]).expr;
292
+ return left;
268
293
  }
269
-
270
- var params = [{ "type": "ThisExpression" }] ;
271
- if (arg) {
272
- return parser.part("$0.$1(this,$2)",[left,genIdent.asyncbind,arg]).expr;
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 parser.part("var $0 = $1",[ident(name),bindAsync({
279
- "type": "FunctionExpression",
280
- "id": null,
281
- "generator": false,
282
- "expression": false,
283
- "params": argnames || [],
284
- "body": Array.isArray(body)?{type:'BlockStatement',body:body}:body
285
- }, binding)]).body[0] ;
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 = parser.part("var $0 = arguments",[genIdent.arguments]).body[0] ;
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
- parser.treeWalker(ast, function (node, descend, path) {
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
- path[0].parent.shorthand = false ;
331
- path[0].parent.key = ident('arguments') ;
332
- ast.$usesArguments = true ;
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
- node.name = opts.$arguments;
338
- ast.$usesArguments = true ;
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
- descend();
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,(useLazyLoops?Nothing:mapLoops),mapIfStmt,mapSwitch,mapBlock]);
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
- id: name?typeof name==="string"?ident(name):name:undefined,
459
- params: [],
460
- body: {
461
- type: 'BlockStatement',
462
- body: cloneNode(body)
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 = parser.part("$0.call($1)",[name,[{"type": "ThisExpression"}].concat(args || [])]).expr ;
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
- function returnThisCall(name,args) {
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 parser.treeWalker(n, function (node, descend, path) {
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
- node.type = 'ReturnStatement';
585
- node.$mapped = true;
586
- node.argument = {
587
- type: 'CallExpression',
588
- callee: getExit(path, [opts]).$error,
589
- arguments: [node.argument]
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
- tryNesting++;
595
- descend(node);
596
- tryNesting--;
597
- return;
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
- parser.treeWalker(ast, function (node, descend, path) {
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(parser.part("if ($0) return $1 ; return $2",[node.test,node.consequent,node.alternate]).body);
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
- parser.treeWalker(ast, function (node, descend, path) {
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 idx++ ;
685
- } else idx++ ;
724
+ block.body.push(ctn);
725
+ idx++;
726
+ } else
727
+ idx++;
728
+ } else
729
+ idx++;
686
730
  }
687
- } else idx++ ;
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
- parser.treeWalker(ast, function (node, descend, path) {
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
- path[0].parent[path[0].field] = {
790
- type:'BlockStatement',
791
- body:[node]
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 = !!containsAwait(node);
797
- node.$finallyExit = node.finalizer && inAsync(path) && !!contains(node.finalizer.body,isExitStatement) ;
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; i<body.length; i++) {
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; i<path.length; i++)
857
- if (examine(path[i].self).isFunction)
858
- return path[i].self.async || path[i].self.$wasAsync ;
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 = parser.part("return $0()",
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
- var chainFinalize = parser.part(
907
- "(function ($value) { "+
908
- " $:body; "+
909
- " return $exit && ($exit.call(this, $value)); "+
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
- afterDirectives(ref.parent[ref.field],[finalizer]);
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
- function closedWalk(ast,state) {
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
- parser.treeWalker(ast, function (node, descend, path) {
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: (opts.promises || opts.generators)?{
1118
+ callee: opts.promises || opts.generators ? {
1079
1119
  type: 'MemberExpression',
1080
- object: ident('Promise'),
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 = parser.part("var $0,$1 = [];for ($0 in $2) $1.push($0)",[idx,inArray,node.right]).body ;
1119
- var loop = parser.part("for ($0; $1.length;){ $2 = $1.shift(); $:3 ; }",[
1120
- node.left,
1121
- inArray,
1122
- node.left.type === 'VariableDeclaration' ? node.left.declarations[0].id : node.left,
1123
- node.body]).body[0] ;
1124
- loop.$label = label ;
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 = parser.part("[$0[Symbol.iterator]()]",[node.right]).expr;
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
- index = node.left.declarations[0].id ;
1149
- var decls = getDeclNames(node.left.declarations[0].id) ;
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 = parser.part("!($0[1] = $0[0].next()).done && (($1 = $0[1].value) || true)",[iterator,index]).expr ;
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
- transformForIn(node, path) ;
1229
+ transformForIn(node, path);
1190
1230
  } else if (node.type === 'ForOfStatement' && containsAwait(node)) {
1191
- iterizeForOf(node, path);
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 ('$label' in p.self && p.self.type==='ForStatement' && p.self.$mapped) ;
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 (n.type==='AwaitExpression' && !n.$hidden)
1202
- || (inAsyncLoop && (n.type==='BreakStatement'|| n.type==='ContinueStatement') && n.label)
1203
- };
1204
-
1205
- if (!node.$mapped && examine(node).isLoop && contains(node,mappableLoop)) {
1206
- path[0].self.$mapped = true ;
1207
- var p ;
1208
- var mapped = [] ;
1209
- var init = node.init;
1210
- var test = node.test || literal(true);
1211
- var step = node.update;
1212
- var body = node.body;
1213
-
1214
- if (step) {
1215
- step = {
1216
- type:'ExpressionStatement',
1217
- expression: step
1218
- } ;
1219
- }
1220
-
1221
- if (init) {
1222
- if (!examine(init).isStatement) {
1223
- init = {
1224
- type: 'ExpressionStatement',
1225
- expression: init
1226
- };
1227
- }
1228
- mapped.push(init) ;
1229
- }
1230
-
1231
- var ref, label ;
1232
- if (node.$label) {
1233
- label = node.$label.name ;
1234
- ref = path[1] ;
1235
- } else {
1236
- label = generatedSymbol++ ;
1237
- ref = path[0] ;
1238
- }
1239
-
1240
- label = opts.generatedSymbolPrefix + "Loop_" + label;
1241
- var idTrampoline = ident(label + "_trampoline") ;
1242
- var idIter = ident(label) ;
1243
- var idStep = step ? ident(label + "_step") : idIter ;
1244
- var idContinuation = ident(label + "_exit") ;
1245
- var idBounce = ident("q") ;
1246
- var idCatchParam = ident("$exception") ;
1247
- var continuation, deferredCode ;
1248
-
1249
- if ('index' in ref) {
1250
- var idx = ref.index;
1251
- deferredCode = ref.parent[ref.field].splice(idx + 1, ref.parent[ref.field].length - (idx + 1));
1252
- } else {
1253
- deferredCode = [] ;
1254
- }
1255
-
1256
- continuation = makeContinuation(idContinuation, deferredCode) ;
1257
- var returnIter = {
1258
- "type": "ReturnStatement",
1259
- "argument": idIter
1260
- } ;
1261
-
1262
- var returnStep = {
1263
- "type": "ReturnStatement",
1264
- "argument": idStep
1265
- } ;
1266
-
1267
- var returnBreak = {
1268
- type: 'ReturnStatement',
1269
- argument: {
1270
- "type": "ArrayExpression",
1271
- "elements":[literal(1)]
1272
- }
1273
- };
1274
-
1275
- parser.treeWalker(body, function mapExits(n, descend, subpath) {
1276
- if (examine(n).isFunction || examine(n).isLoop) {
1277
- return true;
1278
- } else if (n.type === 'BreakStatement' || n.type === 'ContinueStatement') {
1279
- if (n.label) {
1280
- var labelStack = subpath.filter(function(p){
1281
- return '$label' in p.self
1282
- }).map(function(p,idx){
1283
- return p.self.$label && p.self.$label.name
1284
- }) ;
1285
-
1286
- // Work out how many loops to exit by examining subpath.
1287
- var loops = [] ;
1288
- for (var l=0; l<labelStack.length; l++) {
1289
- if (labelStack[l] === n.label.name) {
1290
- if (n.type === 'BreakStatement')
1291
- loops.push(literal(1)) ;
1292
- subpath[0].replace({
1293
- type: 'ReturnStatement',
1294
- argument: {
1295
- "type": "ArrayExpression",
1296
- "elements":loops.reverse()
1297
- }
1298
- }) ;
1299
- break ;
1300
- }
1301
- loops.push(literal(0)) ;
1302
- }
1303
- } else {
1304
- if (n.type === 'BreakStatement')
1305
- subpath[0].replace(returnBreak) ;
1306
- else // continue;
1307
- subpath[0].replace(returnStep) ;
1308
- }
1309
- } else {
1310
- descend();
1311
- }
1312
- },path) ;
1313
-
1314
- if (body.type === 'BlockStatement')
1315
- body = body.body.slice(0) ;
1316
- else
1317
- body = [body] ;
1318
-
1319
- if (node.type==='DoWhileStatement') {
1320
- body = body.concat({
1321
- "type": "IfStatement",
1322
- "test": {
1323
- type:'UnaryExpression',
1324
- argument:test,
1325
- prefix:true,
1326
- operator:'!'
1327
- },
1328
- "consequent": returnBreak,
1329
- alternate:returnStep
1330
- }) ;
1331
- } else {
1332
- body = [{
1333
- "type": "IfStatement",
1334
- "test": test,
1335
- "consequent": {
1336
- "type": "BlockStatement",
1337
- "body": body.concat(returnStep)
1338
- },
1339
- alternate:returnBreak
1340
- }] ;
1341
- }
1342
-
1343
- if (opts.noRuntime) {
1344
- mapped.push({
1345
- "type": "VariableDeclaration",
1346
- "declarations": [{
1347
- "type": "VariableDeclarator",
1348
- "id": idTrampoline
1349
- }],
1350
- "kind": "var"
1351
- }) ;
1352
- }
1353
- var invokeIterate ;
1354
- var exit = getExit(path, [opts]).$error ;
1355
- if (opts.noRuntime) {
1356
- invokeIterate = parser.part(
1357
- opts.es6target?
1358
- "($idTrampoline = ((q) => { "+
1359
- " $$setMapped: while (q) { "+
1360
- " if (q.then) "+
1361
- (depth===1?
1362
- " return void q.then($idTrampoline, $exit); ":
1363
- " return q.then($idTrampoline, $exit); ")+
1364
- " try { "+
1365
- " if (q.pop) "+
1366
- " if (q.length) "+
1367
- " return q.pop() ? $idContinuation.call(this) : q; "+
1368
- " else "+
1369
- " q = $idStep; "+
1370
- " else "+
1371
- " q = q.call(this) "+
1372
- " } catch (_exception) { "+
1373
- " return $exit(_exception); "+
1374
- " } "+
1375
- " } "+
1376
- "}))($idIter)":
1377
- "($idTrampoline = (function (q) { "+
1378
- " $$setMapped: while (q) { "+
1379
- " if (q.then) "+
1380
- (depth===1?
1381
- " return void q.then($idTrampoline, $exit); ":
1382
- " return q.then($idTrampoline, $exit); ")+
1383
- " try { "+
1384
- " if (q.pop) "+
1385
- " if (q.length) "+
1386
- " return q.pop() ? $idContinuation.call(this) : q; "+
1387
- " else "+
1388
- " q = $idStep; "+
1389
- " else "+
1390
- " q = q.call(this) "+
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
- setMapped:function(n){ n.$mapped = true ; return n },
1398
- idTrampoline:idTrampoline,
1399
- exit:exit,
1400
- idIter:idIter,
1401
- idContinuation:idContinuation,
1402
- idStep:idStep
1403
- }).expr ;
1404
- } else {
1405
- invokeIterate = parser.part("(Function.$0.trampoline(this,$1,$2,$3,$5)($4))",[
1406
- genIdent.asyncbind,
1407
- idContinuation,idStep,exit,
1408
- idIter,
1409
- literal(depth===1)
1410
- ]).expr;
1411
- }
1412
-
1413
- mapped.push({type:'ReturnStatement',argument:invokeIterate}) ;
1414
- mapped.push({
1415
- $label:node.$label,
1416
- "type": "FunctionDeclaration",
1417
- "id": idIter,
1418
- "params": [],
1419
- "body": {
1420
- "type": "BlockStatement",
1421
- "body": body
1422
- }
1423
- }) ;
1424
-
1425
- if (step) {
1426
- mapped.push({
1427
- "type": "FunctionDeclaration",
1428
- id: idStep,
1429
- "params": [],
1430
- "body": {
1431
- "type": "BlockStatement",
1432
- "body": [ step,returnIter ]
1433
- }
1434
- }) ;
1435
- }
1436
-
1437
- if (init && init.type==='VariableDeclaration' && (init.kind==='let' || init.kind==='const')) {
1438
- if (init.kind==='const')
1439
- init.kind = 'let' ;
1440
-
1441
- path[0].replace([{
1442
- type:'BlockStatement',
1443
- body:mapped.map(down)
1444
- },down(continuation)]) ;
1445
- } else {
1446
- mapped.push(continuation) ;
1447
- path[0].replace(mapped.map(down)) ;
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
- parser.treeWalker(ast, function (node, descend, path) {
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 + (label));
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
- parser.treeWalker(body[i], mapExits);
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
- if (init && init.type==='VariableDeclaration' && (init.kind==='let' || init.kind==='const')) {
1588
- if (init.kind==='const')
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
- return contains(fn.body,function(node){
1620
- return ((node.type === 'Identifier' && (node.name === opts.$return || node.name === opts.$error))
1621
- || (isExitStatement(node) && examine(node).isAsync)) ;
1622
- },function(node){
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 parser.treeWalker(ast, function (node, descend, path) {
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
- type: 'FunctionExpression',
1650
- params: [genIdent.return,genIdent.error],
1651
- body: asyncDefineMethod(mapReturns(transform.body, path)),
1652
- $wasAsync: true
1653
- }, opts),(opts.promises || opts.generators || opts.engine) ? null : literal(opts.lazyThenables?0:true) ) ;
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: ident('Promise'),
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
- parser.treeWalker(ast, function (node, descend, path) {
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
- && examine(member).isAsync && path[0].parent.kind === 'get') {
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 = [{self:fnBody}].concat(path) ;
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: ident('Promise'),
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 parser.treeWalker(ast, function (node, descend, path) {
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 parser.part("{ return (function*($return,$error){ $:body }).$asyncspawn(Promise,this) }",{
1791
- 'return':genIdent.return,
1792
- error:genIdent.error,
1793
- asyncspawn:genIdent.asyncspawn,
1794
- body: mapAsyncReturns(body).concat(deferExit ? [{
1795
- type: 'ReturnStatement',
1796
- argument: genIdent.return
1797
- }] : [])
1798
- }).body[0] ;
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
- parser.treeWalker(ast, function (node, descend, path) {
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
- parser.treeWalker(ast, function (node, descend, path) {
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
- && examine(member).isAsync && path[0].parent.kind === 'get') {
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
- parser.treeWalker(ast, function (node, descend, path) {
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 || examine(node).isScope) {
1937
- return;
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){ return v[0].parent.type !== 'ExportNamedDeclaration'}) ;
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
- else {
1979
- var repl = (values.length > 1)?{type:'SequenceExpression',expressions:values} : values[0] ;
1980
- if (ref.parent.type.slice(0,3)!=='For')
1981
- repl = {type:'ExpressionStatement',expression:repl} ;
1982
- ref.replace(repl);
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 { decls: varDecls, duplicates: duplicates } ;
2045
+ return {
2046
+ decls: varDecls,
2047
+ duplicates: duplicates
2048
+ };
2009
2049
  }
2010
-
2050
+
2011
2051
  function getDeclNames(id) {
2012
- if (!id) return [] ;
2052
+ if (!id)
2053
+ return [];
2013
2054
  if (Array.isArray(id)) {
2014
- return id.reduce(function(z,j){ return z.concat(getDeclNames(j.id))},[]) ;
2055
+ return id.reduce(function (z, j) {
2056
+ return z.concat(getDeclNames(j.id));
2057
+ }, []);
2015
2058
  }
2016
2059
  switch (id.type) {
2017
- case 'Identifier':
2018
- return [id.name] ;
2019
- case 'AssignmentPattern':
2020
- return getDeclNames(id.left);
2021
- case 'ArrayPattern':
2022
- return id.elements.reduce(function(z,e){ return z.concat(getDeclNames(e)) },[]) ;
2023
- case 'ObjectPattern':
2024
- return id.properties.reduce(function(z,e){ return z.concat(getDeclNames(e)) },[]) ;
2025
- case 'ObjectProperty':
2026
- case 'Property':
2027
- return getDeclNames(id.value) ;
2028
- case 'RestElement':
2029
- case 'RestProperty':
2030
- return getDeclNames(id.argument) ;
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
- function fail(node){
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
- case 'Identifier':
2045
- // Find the declaration of any names on the left
2046
- if (names[target.name] === 'const') fail(target) ;
2047
- break ;
2048
- case 'ArrayPattern':
2049
- target.elements.forEach(function(e){
2050
- if (names[e.name] === 'const') fail(e) ;
2051
- }) ;
2052
- break ;
2053
- case 'ObjectPattern':
2054
- target.properties.forEach(function(p){
2055
- if (names[p.key.name] === 'const') fail(p) ;
2056
- }) ;
2057
- break ;
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
- parser.treeWalker(ast, function (node, descend, path) {
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; i<body[h].declarations.length; i++) {
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
- if (node.type === 'AssignmentExpression')
2079
- checkAssignable(node.left) ;
2080
- else if (node.type === 'UpdateExpression')
2081
- checkAssignable(node.argument) ;
2082
- if (body)
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
- var sequences = {
2090
- TemplateLiteral:function(x) { return x.expressions },
2091
- NewExpression:function(x) { return x.arguments },
2092
- CallExpression:function(x) { return x.arguments },
2093
- SequenceExpression:function(x) { return x.expressions },
2094
- ArrayExpression:function(x) { return x.elements },
2095
- ObjectExpression:function(oe){ return oe.properties.map(function(p){ return p.value })}
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
- function containsAssign(ast){
2101
- return contains(ast, function(n){
2102
- return n.type==='AssignmentExpression'
2103
- });
2160
+ function containsAssign(ast) {
2161
+ return contains(ast, function (n) {
2162
+ return n.type === 'AssignmentExpression';
2163
+ });
2104
2164
  }
2105
-
2106
- parser.treeWalker(ast, function (node, descend, path) {
2107
- var i ;
2108
- descend() ;
2109
- // Ensure assigments are evaluated before any await expressions, eg:
2110
- // f(a=1, b = await a) --> a=1; f(a,b=await a)
2111
-
2112
- function moveAssignments(dest){
2113
- if (assignments.length) {
2114
- dest.argument = {
2115
- type:'SequenceExpression',
2116
- expressions:assignments.map(function(a){
2117
- var b = cloneNode(a)
2118
- coerce(a,a.left);
2119
- return b ;
2120
- }).concat(dest.argument)
2121
- } ;
2122
- assignments = [] ;
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' && n.id) {
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
- var inStrictBody = false ;
2193
- parser.treeWalker(ast, function (node, descend, path) {
2194
- var prevScope = inStrictBody ;
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
- var isScope = !path[0].parent || examine(path[0].parent).isScope ;
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
- consts.forEach(function(d){
2231
- d[0].self.declarations.forEach(function(e){
2232
- getDeclNames(e.id).forEach(function(n){
2233
- if (names[n] || duplicates[n]) {
2234
- delete names[n] ;
2235
- duplicates[n] = e ;
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; depth<d.length; depth++)
2246
- if (examine(d[depth].parent).isBlockStatement)
2247
- break ;
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){ return name in duplicates }) ;
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
- d[0].self.kind = 'var' ;
2282
- decls = ids.filter(function(name){ return name in names }) ;
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
- ref.remove() ;
2344
+ ref.remove();
2292
2345
  }
2293
- }) ;
2294
- vars = scopedNodes(node, isFreeVariable(['var']),false);
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) { return examine(n).isDirective },true);
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
- vars = vars?extractVars(vars,'var'):{duplicates:{},decls:[]} ;
2304
- lets = lets?extractVars(lets,'let'):{duplicates:{},decls:[]} ;
2305
-
2306
- Object.keys(vars.duplicates).forEach(function(id){
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
- // Labeled blocks need to be treated as loops that exit on the first iteration if they contain awaits and labelled breaks
2346
- if (node.type==='LabeledStatement' && node.body.type==='BlockStatement' && containsAwait(node.body) && contains(node.body,function(m){
2347
- return m.type === 'BreakStatement' && m.label
2348
- })) {
2349
- node.body.body.push({ type: 'BreakStatement' }) ;
2350
- node.body = {
2351
- type: 'DoWhileStatement',
2352
- test: literal(0),
2353
- body: node.body
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; n<path.length;n++)
2365
- if (path[n].self.type==='ForOfStatement' || path[n].self.type==='ForInStatement' || examine(path[n].self).isLoop)
2366
- depth += 1 ;
2367
- else if (examine(path[n].self).isFunction)
2368
- break ;
2369
-
2370
- node.$depth = depth ;
2371
- if (path[0].parent.type==='LabeledStatement') {
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
- return (examine(n).isFunction && contains(n,function(n){
2391
- return n.type==='Super'
2392
- }) && contains(n,function(n){
2393
- return n.async && (n.type==='ReturnStatement' || n.type==='ThrowStatement') ;
2394
- }))
2395
- },true))) {
2396
- parser.treeWalker(method.body, function (node, descend, path) {
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 = parser.part("this.$super($field).call(this,$args)",{
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 = parser.part("this.$super($field)",{
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 parser.treeWalker(ast, function (node, descend, path) {
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 = parser.part("(function($field) { return super[$field] })",{ field:ident("$field") }).expr ;
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
- parser.treeWalker(ast, function (node, descend, path) {
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
- parser.treeWalker(ast, function (node, descend, path) {
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
- var nodes ;
2490
- if (node.type === 'Program')
2491
- nodes = node.body ;
2492
- else if (examine(node).isFunction)
2493
- nodes = node.body.body ;
2494
- else return false ;
2495
-
2496
- if (nodes) for (var i=0; i<nodes.length; i++)
2497
- if (examine(nodes[i]).isDirective && nodes[i].expression.value.match(/^\s*use\s+strict\s*$/))
2498
- return true ;
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
- parser.treeWalker(ast, function (node, descend, path) {
2574
+ treeWalk(ast, function (node, descend, path) {
2518
2575
  descend();
2519
- if (node.type==='ArrowFunctionExpression'
2520
- && node.body.type === 'BlockStatement'
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
- parser.treeWalker(ast, function (node, descend, path) {
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
- parser.treeWalker(ast, function (node, descend, path) {
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]; // Multiple ref
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
- parser.treeWalker(ast, function (node, descend, path) {
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
- parser.treeWalker(ast, function (node, descend, path) {
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
- parser.treeWalker(ast, function (node, descend, path) {
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 functionScope = node.type === 'Program' ? node : node.body ;
2618
- var functions = scopedNodes(functionScope,function(n,path){
2619
- if (n.type==='FunctionDeclaration') {
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
- parser.treeWalker(ast,function(node,descend,path){
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
- // Remove all the 'hiiden' node info generated during transformation
2668
- parser.treeWalker(ast,function(node,descend,path){
2669
- descend() ;
2670
- Object.keys(node).filter(function(k){ return k[0]==='$'}).forEach(function(k){
2671
- delete node[k] ;
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
- module.exports = {
2679
- printNode:printNode,
2680
- babelLiteralNode: babelLiteralNode,
2681
- asynchronize: function (pr, __sourceMapping, opts, logger) {
2682
- try {
2683
- return asynchronize(pr, __sourceMapping, opts, logger);
2684
- } catch (ex) {
2685
- if (ex instanceof SyntaxError) {
2686
- var l = pr.origCode.substr(ex.pos - ex.loc.column);
2687
- l = l.split("\n")[0];
2688
- ex.message += " (nodent)\n" + l + "\n" + l.replace(/[\S ]/g, "-").substring(0, ex.loc.column) + "^";
2689
- ex.stack = "";
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
- throw ex;
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
  };