summaryrefslogtreecommitdiff
path: root/node_modules/@babel/plugin-transform-block-scoping/lib/loop.js
diff options
context:
space:
mode:
authorlittleblack111 <littleblack11111@gmail.com>2023-10-14 15:31:11 +0800
committerlittleblack111 <littleblack11111@gmail.com>2023-10-14 15:31:11 +0800
commitaa773172311dcada759dfbaac485f4bc6e00bc21 (patch)
treeca6d9a5eff3ab8f689f9acb4f0df791d9486813d /node_modules/@babel/plugin-transform-block-scoping/lib/loop.js
parentc5a5384e846f242e901e859fe600d695d8990a9a (diff)
added babel
Diffstat (limited to 'node_modules/@babel/plugin-transform-block-scoping/lib/loop.js')
-rw-r--r--node_modules/@babel/plugin-transform-block-scoping/lib/loop.js294
1 files changed, 294 insertions, 0 deletions
diff --git a/node_modules/@babel/plugin-transform-block-scoping/lib/loop.js b/node_modules/@babel/plugin-transform-block-scoping/lib/loop.js
new file mode 100644
index 00000000..0c0a17f8
--- /dev/null
+++ b/node_modules/@babel/plugin-transform-block-scoping/lib/loop.js
@@ -0,0 +1,294 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.getLoopBodyBindings = getLoopBodyBindings;
+exports.getUsageInBody = getUsageInBody;
+exports.isVarInLoopHead = isVarInLoopHead;
+exports.wrapLoopBody = wrapLoopBody;
+var _core = require("@babel/core");
+const collectLoopBodyBindingsVisitor = {
+ "Expression|Declaration|Loop"(path) {
+ path.skip();
+ },
+ Scope(path, state) {
+ if (path.isFunctionParent()) path.skip();
+ const {
+ bindings
+ } = path.scope;
+ for (const name of Object.keys(bindings)) {
+ const binding = bindings[name];
+ if (binding.kind === "let" || binding.kind === "const" || binding.kind === "hoisted") {
+ state.blockScoped.push(binding);
+ }
+ }
+ }
+};
+function getLoopBodyBindings(loopPath) {
+ const state = {
+ blockScoped: []
+ };
+ loopPath.traverse(collectLoopBodyBindingsVisitor, state);
+ return state.blockScoped;
+}
+function getUsageInBody(binding, loopPath) {
+ const seen = new WeakSet();
+ let capturedInClosure = false;
+ const constantViolations = filterMap(binding.constantViolations, path => {
+ const {
+ inBody,
+ inClosure
+ } = relativeLoopLocation(path, loopPath);
+ if (!inBody) return null;
+ capturedInClosure || (capturedInClosure = inClosure);
+ const id = path.isUpdateExpression() ? path.get("argument") : path.isAssignmentExpression() ? path.get("left") : null;
+ if (id) seen.add(id.node);
+ return id;
+ });
+ const references = filterMap(binding.referencePaths, path => {
+ if (seen.has(path.node)) return null;
+ const {
+ inBody,
+ inClosure
+ } = relativeLoopLocation(path, loopPath);
+ if (!inBody) return null;
+ capturedInClosure || (capturedInClosure = inClosure);
+ return path;
+ });
+ return {
+ capturedInClosure,
+ hasConstantViolations: constantViolations.length > 0,
+ usages: references.concat(constantViolations)
+ };
+}
+function relativeLoopLocation(path, loopPath) {
+ const bodyPath = loopPath.get("body");
+ let inClosure = false;
+ for (let currPath = path; currPath; currPath = currPath.parentPath) {
+ if (currPath.isFunction() || currPath.isClass() || currPath.isMethod()) {
+ inClosure = true;
+ }
+ if (currPath === bodyPath) {
+ return {
+ inBody: true,
+ inClosure
+ };
+ } else if (currPath === loopPath) {
+ return {
+ inBody: false,
+ inClosure
+ };
+ }
+ }
+ throw new Error("Internal Babel error: path is not in loop. Please report this as a bug.");
+}
+const collectCompletionsAndVarsVisitor = {
+ Function(path) {
+ path.skip();
+ },
+ LabeledStatement: {
+ enter({
+ node
+ }, state) {
+ state.labelsStack.push(node.label.name);
+ },
+ exit({
+ node
+ }, state) {
+ const popped = state.labelsStack.pop();
+ if (popped !== node.label.name) {
+ throw new Error("Assertion failure. Please report this bug to Babel.");
+ }
+ }
+ },
+ Loop: {
+ enter(_, state) {
+ state.labellessContinueTargets++;
+ state.labellessBreakTargets++;
+ },
+ exit(_, state) {
+ state.labellessContinueTargets--;
+ state.labellessBreakTargets--;
+ }
+ },
+ SwitchStatement: {
+ enter(_, state) {
+ state.labellessBreakTargets++;
+ },
+ exit(_, state) {
+ state.labellessBreakTargets--;
+ }
+ },
+ "BreakStatement|ContinueStatement"(path, state) {
+ const {
+ label
+ } = path.node;
+ if (label) {
+ if (state.labelsStack.includes(label.name)) return;
+ } else if (path.isBreakStatement() ? state.labellessBreakTargets > 0 : state.labellessContinueTargets > 0) {
+ return;
+ }
+ state.breaksContinues.push(path);
+ },
+ ReturnStatement(path, state) {
+ state.returns.push(path);
+ },
+ VariableDeclaration(path, state) {
+ if (path.parent === state.loopNode && isVarInLoopHead(path)) return;
+ if (path.node.kind === "var") state.vars.push(path);
+ }
+};
+function wrapLoopBody(loopPath, captured, updatedBindingsUsages) {
+ const loopNode = loopPath.node;
+ const state = {
+ breaksContinues: [],
+ returns: [],
+ labelsStack: [],
+ labellessBreakTargets: 0,
+ labellessContinueTargets: 0,
+ vars: [],
+ loopNode
+ };
+ loopPath.traverse(collectCompletionsAndVarsVisitor, state);
+ const callArgs = [];
+ const closureParams = [];
+ const updater = [];
+ for (const [name, updatedUsage] of updatedBindingsUsages) {
+ callArgs.push(_core.types.identifier(name));
+ const innerName = loopPath.scope.generateUid(name);
+ closureParams.push(_core.types.identifier(innerName));
+ updater.push(_core.types.assignmentExpression("=", _core.types.identifier(name), _core.types.identifier(innerName)));
+ for (const path of updatedUsage) path.replaceWith(_core.types.identifier(innerName));
+ }
+ for (const name of captured) {
+ if (updatedBindingsUsages.has(name)) continue;
+ callArgs.push(_core.types.identifier(name));
+ closureParams.push(_core.types.identifier(name));
+ }
+ const id = loopPath.scope.generateUid("loop");
+ const fn = _core.types.functionExpression(null, closureParams, _core.types.toBlock(loopNode.body));
+ let call = _core.types.callExpression(_core.types.identifier(id), callArgs);
+ const fnParent = loopPath.findParent(p => p.isFunction());
+ if (fnParent) {
+ const {
+ async,
+ generator
+ } = fnParent.node;
+ fn.async = async;
+ fn.generator = generator;
+ if (generator) call = _core.types.yieldExpression(call, true);else if (async) call = _core.types.awaitExpression(call);
+ }
+ const updaterNode = updater.length > 0 ? _core.types.expressionStatement(_core.types.sequenceExpression(updater)) : null;
+ if (updaterNode) fn.body.body.push(updaterNode);
+ const [varPath] = loopPath.insertBefore(_core.types.variableDeclaration("var", [_core.types.variableDeclarator(_core.types.identifier(id), fn)]));
+ const bodyStmts = [];
+ const varNames = [];
+ for (const varPath of state.vars) {
+ const assign = [];
+ for (const decl of varPath.node.declarations) {
+ varNames.push(...Object.keys(_core.types.getBindingIdentifiers(decl.id)));
+ if (decl.init) {
+ assign.push(_core.types.assignmentExpression("=", decl.id, decl.init));
+ }
+ }
+ if (assign.length > 0) {
+ let replacement = assign.length === 1 ? assign[0] : _core.types.sequenceExpression(assign);
+ if (!_core.types.isForStatement(varPath.parent, {
+ init: varPath.node
+ }) && !_core.types.isForXStatement(varPath.parent, {
+ left: varPath.node
+ })) {
+ replacement = _core.types.expressionStatement(replacement);
+ }
+ varPath.replaceWith(replacement);
+ } else {
+ varPath.remove();
+ }
+ }
+ if (varNames.length) {
+ varPath.pushContainer("declarations", varNames.map(name => _core.types.variableDeclarator(_core.types.identifier(name))));
+ }
+ const labelNum = state.breaksContinues.length;
+ const returnNum = state.returns.length;
+ if (labelNum + returnNum === 0) {
+ bodyStmts.push(_core.types.expressionStatement(call));
+ } else if (labelNum === 1 && returnNum === 0) {
+ for (const path of state.breaksContinues) {
+ const {
+ node
+ } = path;
+ const {
+ type,
+ label
+ } = node;
+ let name = type === "BreakStatement" ? "break" : "continue";
+ if (label) name += " " + label.name;
+ path.replaceWith(_core.types.addComment(_core.types.returnStatement(_core.types.numericLiteral(1)), "trailing", " " + name, true));
+ if (updaterNode) path.insertBefore(_core.types.cloneNode(updaterNode));
+ bodyStmts.push(_core.template.statement.ast`
+ if (${call}) ${node}
+ `);
+ }
+ } else {
+ const completionId = loopPath.scope.generateUid("ret");
+ if (varPath.isVariableDeclaration()) {
+ varPath.pushContainer("declarations", [_core.types.variableDeclarator(_core.types.identifier(completionId))]);
+ bodyStmts.push(_core.types.expressionStatement(_core.types.assignmentExpression("=", _core.types.identifier(completionId), call)));
+ } else {
+ bodyStmts.push(_core.types.variableDeclaration("var", [_core.types.variableDeclarator(_core.types.identifier(completionId), call)]));
+ }
+ const injected = [];
+ for (const path of state.breaksContinues) {
+ const {
+ node
+ } = path;
+ const {
+ type,
+ label
+ } = node;
+ let name = type === "BreakStatement" ? "break" : "continue";
+ if (label) name += " " + label.name;
+ let i = injected.indexOf(name);
+ const hasInjected = i !== -1;
+ if (!hasInjected) {
+ injected.push(name);
+ i = injected.length - 1;
+ }
+ path.replaceWith(_core.types.addComment(_core.types.returnStatement(_core.types.numericLiteral(i)), "trailing", " " + name, true));
+ if (updaterNode) path.insertBefore(_core.types.cloneNode(updaterNode));
+ if (hasInjected) continue;
+ bodyStmts.push(_core.template.statement.ast`
+ if (${_core.types.identifier(completionId)} === ${_core.types.numericLiteral(i)}) ${node}
+ `);
+ }
+ if (returnNum) {
+ for (const path of state.returns) {
+ const arg = path.node.argument || path.scope.buildUndefinedNode();
+ path.replaceWith(_core.template.statement.ast`
+ return { v: ${arg} };
+ `);
+ }
+ bodyStmts.push(_core.template.statement.ast`
+ if (${_core.types.identifier(completionId)}) return ${_core.types.identifier(completionId)}.v;
+ `);
+ }
+ }
+ loopNode.body = _core.types.blockStatement(bodyStmts);
+ return varPath;
+}
+function isVarInLoopHead(path) {
+ if (_core.types.isForStatement(path.parent)) return path.key === "init";
+ if (_core.types.isForXStatement(path.parent)) return path.key === "left";
+ return false;
+}
+function filterMap(list, fn) {
+ const result = [];
+ for (const item of list) {
+ const mapped = fn(item);
+ if (mapped) result.push(mapped);
+ }
+ return result;
+}
+
+//# sourceMappingURL=loop.js.map