source: imaps-frontend/node_modules/@babel/plugin-transform-block-scoping/lib/loop.js

main
Last change on this file was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 4 days ago

F4 Finalna Verzija

  • Property mode set to 100644
File size: 9.6 KB
Line 
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.getLoopBodyBindings = getLoopBodyBindings;
7exports.getUsageInBody = getUsageInBody;
8exports.isVarInLoopHead = isVarInLoopHead;
9exports.wrapLoopBody = wrapLoopBody;
10var _core = require("@babel/core");
11const collectLoopBodyBindingsVisitor = {
12 "Expression|Declaration|Loop"(path) {
13 path.skip();
14 },
15 Scope(path, state) {
16 if (path.isFunctionParent()) path.skip();
17 const {
18 bindings
19 } = path.scope;
20 for (const name of Object.keys(bindings)) {
21 const binding = bindings[name];
22 if (binding.kind === "let" || binding.kind === "const" || binding.kind === "hoisted") {
23 state.blockScoped.push(binding);
24 }
25 }
26 }
27};
28function getLoopBodyBindings(loopPath) {
29 const state = {
30 blockScoped: []
31 };
32 loopPath.traverse(collectLoopBodyBindingsVisitor, state);
33 return state.blockScoped;
34}
35function getUsageInBody(binding, loopPath) {
36 const seen = new WeakSet();
37 let capturedInClosure = false;
38 const constantViolations = filterMap(binding.constantViolations, path => {
39 const {
40 inBody,
41 inClosure
42 } = relativeLoopLocation(path, loopPath);
43 if (!inBody) return null;
44 capturedInClosure || (capturedInClosure = inClosure);
45 const id = path.isUpdateExpression() ? path.get("argument") : path.isAssignmentExpression() ? path.get("left") : null;
46 if (id) seen.add(id.node);
47 return id;
48 });
49 const references = filterMap(binding.referencePaths, path => {
50 if (seen.has(path.node)) return null;
51 const {
52 inBody,
53 inClosure
54 } = relativeLoopLocation(path, loopPath);
55 if (!inBody) return null;
56 capturedInClosure || (capturedInClosure = inClosure);
57 return path;
58 });
59 return {
60 capturedInClosure,
61 hasConstantViolations: constantViolations.length > 0,
62 usages: references.concat(constantViolations)
63 };
64}
65function relativeLoopLocation(path, loopPath) {
66 const bodyPath = loopPath.get("body");
67 let inClosure = false;
68 for (let currPath = path; currPath; currPath = currPath.parentPath) {
69 if (currPath.isFunction() || currPath.isClass() || currPath.isMethod()) {
70 inClosure = true;
71 }
72 if (currPath === bodyPath) {
73 return {
74 inBody: true,
75 inClosure
76 };
77 } else if (currPath === loopPath) {
78 return {
79 inBody: false,
80 inClosure
81 };
82 }
83 }
84 throw new Error("Internal Babel error: path is not in loop. Please report this as a bug.");
85}
86const collectCompletionsAndVarsVisitor = {
87 Function(path) {
88 path.skip();
89 },
90 LabeledStatement: {
91 enter({
92 node
93 }, state) {
94 state.labelsStack.push(node.label.name);
95 },
96 exit({
97 node
98 }, state) {
99 const popped = state.labelsStack.pop();
100 if (popped !== node.label.name) {
101 throw new Error("Assertion failure. Please report this bug to Babel.");
102 }
103 }
104 },
105 Loop: {
106 enter(_, state) {
107 state.labellessContinueTargets++;
108 state.labellessBreakTargets++;
109 },
110 exit(_, state) {
111 state.labellessContinueTargets--;
112 state.labellessBreakTargets--;
113 }
114 },
115 SwitchStatement: {
116 enter(_, state) {
117 state.labellessBreakTargets++;
118 },
119 exit(_, state) {
120 state.labellessBreakTargets--;
121 }
122 },
123 "BreakStatement|ContinueStatement"(path, state) {
124 const {
125 label
126 } = path.node;
127 if (label) {
128 if (state.labelsStack.includes(label.name)) return;
129 } else if (path.isBreakStatement() ? state.labellessBreakTargets > 0 : state.labellessContinueTargets > 0) {
130 return;
131 }
132 state.breaksContinues.push(path);
133 },
134 ReturnStatement(path, state) {
135 state.returns.push(path);
136 },
137 VariableDeclaration(path, state) {
138 if (path.parent === state.loopNode && isVarInLoopHead(path)) return;
139 if (path.node.kind === "var") state.vars.push(path);
140 }
141};
142function wrapLoopBody(loopPath, captured, updatedBindingsUsages) {
143 const loopNode = loopPath.node;
144 const state = {
145 breaksContinues: [],
146 returns: [],
147 labelsStack: [],
148 labellessBreakTargets: 0,
149 labellessContinueTargets: 0,
150 vars: [],
151 loopNode
152 };
153 loopPath.traverse(collectCompletionsAndVarsVisitor, state);
154 const callArgs = [];
155 const closureParams = [];
156 const updater = [];
157 for (const [name, updatedUsage] of updatedBindingsUsages) {
158 callArgs.push(_core.types.identifier(name));
159 const innerName = loopPath.scope.generateUid(name);
160 closureParams.push(_core.types.identifier(innerName));
161 updater.push(_core.types.assignmentExpression("=", _core.types.identifier(name), _core.types.identifier(innerName)));
162 for (const path of updatedUsage) path.replaceWith(_core.types.identifier(innerName));
163 }
164 for (const name of captured) {
165 if (updatedBindingsUsages.has(name)) continue;
166 callArgs.push(_core.types.identifier(name));
167 closureParams.push(_core.types.identifier(name));
168 }
169 const id = loopPath.scope.generateUid("loop");
170 const fn = _core.types.functionExpression(null, closureParams, _core.types.toBlock(loopNode.body));
171 let call = _core.types.callExpression(_core.types.identifier(id), callArgs);
172 const fnParent = loopPath.findParent(p => p.isFunction());
173 if (fnParent) {
174 const {
175 async,
176 generator
177 } = fnParent.node;
178 fn.async = async;
179 fn.generator = generator;
180 if (generator) call = _core.types.yieldExpression(call, true);else if (async) call = _core.types.awaitExpression(call);
181 }
182 const updaterNode = updater.length > 0 ? _core.types.expressionStatement(_core.types.sequenceExpression(updater)) : null;
183 if (updaterNode) fn.body.body.push(updaterNode);
184 const [varPath] = loopPath.insertBefore(_core.types.variableDeclaration("var", [_core.types.variableDeclarator(_core.types.identifier(id), fn)]));
185 const bodyStmts = [];
186 const varNames = [];
187 for (const varPath of state.vars) {
188 const assign = [];
189 for (const decl of varPath.node.declarations) {
190 varNames.push(...Object.keys(_core.types.getBindingIdentifiers(decl.id)));
191 if (decl.init) {
192 assign.push(_core.types.assignmentExpression("=", decl.id, decl.init));
193 } else if (_core.types.isForXStatement(varPath.parent, {
194 left: varPath.node
195 })) {
196 assign.push(decl.id);
197 }
198 }
199 if (assign.length > 0) {
200 const replacement = assign.length === 1 ? assign[0] : _core.types.sequenceExpression(assign);
201 varPath.replaceWith(replacement);
202 } else {
203 varPath.remove();
204 }
205 }
206 if (varNames.length) {
207 varPath.pushContainer("declarations", varNames.map(name => _core.types.variableDeclarator(_core.types.identifier(name))));
208 }
209 const labelNum = state.breaksContinues.length;
210 const returnNum = state.returns.length;
211 if (labelNum + returnNum === 0) {
212 bodyStmts.push(_core.types.expressionStatement(call));
213 } else if (labelNum === 1 && returnNum === 0) {
214 for (const path of state.breaksContinues) {
215 const {
216 node
217 } = path;
218 const {
219 type,
220 label
221 } = node;
222 let name = type === "BreakStatement" ? "break" : "continue";
223 if (label) name += " " + label.name;
224 path.replaceWith(_core.types.addComment(_core.types.returnStatement(_core.types.numericLiteral(1)), "trailing", " " + name, true));
225 if (updaterNode) path.insertBefore(_core.types.cloneNode(updaterNode));
226 bodyStmts.push(_core.template.statement.ast`
227 if (${call}) ${node}
228 `);
229 }
230 } else {
231 const completionId = loopPath.scope.generateUid("ret");
232 if (varPath.isVariableDeclaration()) {
233 varPath.pushContainer("declarations", [_core.types.variableDeclarator(_core.types.identifier(completionId))]);
234 bodyStmts.push(_core.types.expressionStatement(_core.types.assignmentExpression("=", _core.types.identifier(completionId), call)));
235 } else {
236 bodyStmts.push(_core.types.variableDeclaration("var", [_core.types.variableDeclarator(_core.types.identifier(completionId), call)]));
237 }
238 const injected = [];
239 for (const path of state.breaksContinues) {
240 const {
241 node
242 } = path;
243 const {
244 type,
245 label
246 } = node;
247 let name = type === "BreakStatement" ? "break" : "continue";
248 if (label) name += " " + label.name;
249 let i = injected.indexOf(name);
250 const hasInjected = i !== -1;
251 if (!hasInjected) {
252 injected.push(name);
253 i = injected.length - 1;
254 }
255 path.replaceWith(_core.types.addComment(_core.types.returnStatement(_core.types.numericLiteral(i)), "trailing", " " + name, true));
256 if (updaterNode) path.insertBefore(_core.types.cloneNode(updaterNode));
257 if (hasInjected) continue;
258 bodyStmts.push(_core.template.statement.ast`
259 if (${_core.types.identifier(completionId)} === ${_core.types.numericLiteral(i)}) ${node}
260 `);
261 }
262 if (returnNum) {
263 for (const path of state.returns) {
264 const arg = path.node.argument || path.scope.buildUndefinedNode();
265 path.replaceWith(_core.template.statement.ast`
266 return { v: ${arg} };
267 `);
268 }
269 bodyStmts.push(_core.template.statement.ast`
270 if (${_core.types.identifier(completionId)}) return ${_core.types.identifier(completionId)}.v;
271 `);
272 }
273 }
274 loopNode.body = _core.types.blockStatement(bodyStmts);
275 return varPath;
276}
277function isVarInLoopHead(path) {
278 if (_core.types.isForStatement(path.parent)) return path.key === "init";
279 if (_core.types.isForXStatement(path.parent)) return path.key === "left";
280 return false;
281}
282function filterMap(list, fn) {
283 const result = [];
284 for (const item of list) {
285 const mapped = fn(item);
286 if (mapped) result.push(mapped);
287 }
288 return result;
289}
290
291//# sourceMappingURL=loop.js.map
Note: See TracBrowser for help on using the repository browser.