1 | "use strict";
|
2 |
|
3 | var _assert = require("assert");
|
4 |
|
5 |
|
6 | var _assert2 = _interopRequireDefault(_assert);
|
7 |
|
8 | var _babelTypes = require("babel-types");
|
9 |
|
10 |
|
11 | var t = _interopRequireWildcard(_babelTypes);
|
12 |
|
13 | var _hoist = require("./hoist");
|
14 |
|
15 | var _emit = require("./emit");
|
16 |
|
17 | var _util = require("./util");
|
18 |
|
19 |
|
20 | var util = _interopRequireWildcard(_util);
|
21 |
|
22 |
|
23 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
|
24 |
|
25 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
26 |
|
27 | var getMarkInfo = require("private").makeAccessor(); |
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 | exports.visitor = {
|
38 | Function: {
|
39 | exit: function /*istanbul ignore next*/exit(path, state) {
|
40 | var node = path.node;
|
41 |
|
42 | if (node.generator) {
|
43 | if (node.async) {
|
44 |
|
45 | if (state.opts.asyncGenerators === false) return;
|
46 | } else {
|
47 |
|
48 | if (state.opts.generators === false) return;
|
49 | }
|
50 | } else if (node.async) {
|
51 |
|
52 | if (state.opts.async === false) return;
|
53 | } else {
|
54 |
|
55 | return;
|
56 | }
|
57 |
|
58 | var contextId = path.scope.generateUidIdentifier("context");
|
59 | var argsId = path.scope.generateUidIdentifier("args");
|
60 |
|
61 | path.ensureBlock();
|
62 | var bodyBlockPath = path.get("body");
|
63 |
|
64 | if (node.async) {
|
65 | bodyBlockPath.traverse(awaitVisitor);
|
66 | }
|
67 |
|
68 | bodyBlockPath.traverse(functionSentVisitor, {
|
69 | context: contextId
|
70 | });
|
71 |
|
72 | var outerBody = [];
|
73 | var innerBody = [];
|
74 |
|
75 | bodyBlockPath.get("body").forEach(function (childPath) {
|
76 | var node = childPath.node;
|
77 | if (node && node._blockHoist != null) {
|
78 | outerBody.push(node);
|
79 | } else {
|
80 | innerBody.push(node);
|
81 | }
|
82 | });
|
83 |
|
84 | if (outerBody.length > 0) {
|
85 |
|
86 |
|
87 | bodyBlockPath.node.body = innerBody;
|
88 | }
|
89 |
|
90 | var outerFnExpr = getOuterFnExpr(path);
|
91 |
|
92 |
|
93 |
|
94 | t.assertIdentifier(node.id);
|
95 | var innerFnId = t.identifier(node.id.name + "$");
|
96 |
|
97 |
|
98 |
|
99 | var vars = (0, _hoist.hoist)(path);
|
100 |
|
101 | var didRenameArguments = renameArguments(path, argsId);
|
102 | if (didRenameArguments) {
|
103 | vars = vars || t.variableDeclaration("var", []);
|
104 | vars.declarations.push(t.variableDeclarator(argsId, t.identifier("arguments")));
|
105 | }
|
106 |
|
107 | var emitter = new _emit.Emitter(contextId);
|
108 | emitter.explode(path.get("body"));
|
109 |
|
110 | if (vars && vars.declarations.length > 0) {
|
111 | outerBody.push(vars);
|
112 | }
|
113 |
|
114 | var wrapArgs = [emitter.getContextFunction(innerFnId),
|
115 |
|
116 |
|
117 |
|
118 | node.generator ? outerFnExpr : t.nullLiteral(), t.thisExpression()];
|
119 |
|
120 | var tryLocsList = emitter.getTryLocsList();
|
121 | if (tryLocsList) {
|
122 | wrapArgs.push(tryLocsList);
|
123 | }
|
124 |
|
125 | var wrapCall = t.callExpression(util.runtimeProperty(node.async ? "async" : "wrap"), wrapArgs);
|
126 |
|
127 | outerBody.push(t.returnStatement(wrapCall));
|
128 | node.body = t.blockStatement(outerBody);
|
129 |
|
130 | var wasGeneratorFunction = node.generator;
|
131 | if (wasGeneratorFunction) {
|
132 | node.generator = false;
|
133 | }
|
134 |
|
135 | if (node.async) {
|
136 | node.async = false;
|
137 | }
|
138 |
|
139 | if (wasGeneratorFunction && t.isExpression(node)) {
|
140 | path.replaceWith(t.callExpression(util.runtimeProperty("mark"), [node]));
|
141 | }
|
142 |
|
143 |
|
144 |
|
145 |
|
146 | path.requeue();
|
147 | }
|
148 | }
|
149 | };
|
150 |
|
151 |
|
152 |
|
153 |
|
154 |
|
155 | function getOuterFnExpr(funPath) {
|
156 | var node = funPath.node;
|
157 | t.assertFunction(node);
|
158 |
|
159 | if (!node.id) {
|
160 |
|
161 |
|
162 | node.id = funPath.scope.parent.generateUidIdentifier("callee");
|
163 | }
|
164 |
|
165 | if (node.generator &&
|
166 | t.isFunctionDeclaration(node)) {
|
167 | var pp = funPath.findParent(function (path) {
|
168 | return path.isProgram() || path.isBlockStatement();
|
169 | });
|
170 |
|
171 | if (!pp) {
|
172 | return node.id;
|
173 | }
|
174 |
|
175 | var markDecl = getRuntimeMarkDecl(pp);
|
176 | var markedArray = markDecl.declarations[0].id;
|
177 | var funDeclIdArray = markDecl.declarations[0].init.callee.object;
|
178 | t.assertArrayExpression(funDeclIdArray);
|
179 |
|
180 | var index = funDeclIdArray.elements.length;
|
181 | funDeclIdArray.elements.push(node.id);
|
182 |
|
183 | return t.memberExpression(markedArray, t.numericLiteral(index), true);
|
184 | }
|
185 |
|
186 | return node.id;
|
187 | }
|
188 |
|
189 | function getRuntimeMarkDecl(blockPath) {
|
190 | var block = blockPath.node;
|
191 | _assert2.default.ok(Array.isArray(block.body));
|
192 |
|
193 | var info = getMarkInfo(block);
|
194 | if (info.decl) {
|
195 | return info.decl;
|
196 | }
|
197 |
|
198 | info.decl = t.variableDeclaration("var", [t.variableDeclarator(blockPath.scope.generateUidIdentifier("marked"), t.callExpression(t.memberExpression(t.arrayExpression([]), t.identifier("map"), false), [util.runtimeProperty("mark")]))]);
|
199 |
|
200 | blockPath.unshiftContainer("body", info.decl);
|
201 |
|
202 | return info.decl;
|
203 | }
|
204 |
|
205 | function renameArguments(funcPath, argsId) {
|
206 | var state = {
|
207 | didRenameArguments: false,
|
208 | argsId: argsId
|
209 | };
|
210 |
|
211 | funcPath.traverse(argumentsVisitor, state);
|
212 |
|
213 |
|
214 |
|
215 |
|
216 |
|
217 | return state.didRenameArguments;
|
218 | }
|
219 |
|
220 | var argumentsVisitor = {
|
221 | "FunctionExpression|FunctionDeclaration": function /*istanbul ignore next*/FunctionExpressionFunctionDeclaration(path) {
|
222 | path.skip();
|
223 | },
|
224 |
|
225 | Identifier: function /*istanbul ignore next*/Identifier(path, state) {
|
226 | if (path.node.name === "arguments" && util.isReference(path)) {
|
227 | path.replaceWith(state.argsId);
|
228 | state.didRenameArguments = true;
|
229 | }
|
230 | }
|
231 | };
|
232 |
|
233 | var functionSentVisitor = {
|
234 | MetaProperty: function MetaProperty(path) {
|
235 | var node = path.node;
|
236 |
|
237 |
|
238 | if (node.meta.name === "function" && node.property.name === "sent") {
|
239 | path.replaceWith(t.memberExpression(this.context, t.identifier("_sent")));
|
240 | }
|
241 | }
|
242 | };
|
243 |
|
244 | var awaitVisitor = {
|
245 | Function: function /*istanbul ignore next*/Function(path) {
|
246 | path.skip();
|
247 | },
|
248 |
|
249 | AwaitExpression: function /*istanbul ignore next*/AwaitExpression(path) {
|
250 |
|
251 | var argument = path.node.argument;
|
252 |
|
253 |
|
254 |
|
255 |
|
256 | path.replaceWith(t.yieldExpression(t.callExpression(util.runtimeProperty("awrap"), [argument]), false));
|
257 | }
|
258 | }; |
\ | No newline at end of file |