diff options
Diffstat (limited to 'node_modules/@babel/plugin-transform-parameters/lib/rest.js')
| -rw-r--r-- | node_modules/@babel/plugin-transform-parameters/lib/rest.js | 284 |
1 files changed, 284 insertions, 0 deletions
diff --git a/node_modules/@babel/plugin-transform-parameters/lib/rest.js b/node_modules/@babel/plugin-transform-parameters/lib/rest.js new file mode 100644 index 00000000..2ae054b1 --- /dev/null +++ b/node_modules/@babel/plugin-transform-parameters/lib/rest.js @@ -0,0 +1,284 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = convertFunctionRest; +var _core = require("@babel/core"); +var _shadowUtils = require("./shadow-utils.js"); +const buildRest = _core.template.statement(` + for (var LEN = ARGUMENTS.length, + ARRAY = new Array(ARRAY_LEN), + KEY = START; + KEY < LEN; + KEY++) { + ARRAY[ARRAY_KEY] = ARGUMENTS[KEY]; + } +`); +const restIndex = _core.template.expression(` + (INDEX < OFFSET || ARGUMENTS.length <= INDEX) ? undefined : ARGUMENTS[INDEX] +`); +const restIndexImpure = _core.template.expression(` + REF = INDEX, (REF < OFFSET || ARGUMENTS.length <= REF) ? undefined : ARGUMENTS[REF] +`); +const restLength = _core.template.expression(` + ARGUMENTS.length <= OFFSET ? 0 : ARGUMENTS.length - OFFSET +`); +function referencesRest(path, state) { + if (path.node.name === state.name) { + return path.scope.bindingIdentifierEquals(state.name, state.outerBinding); + } + return false; +} +const memberExpressionOptimisationVisitor = { + Scope(path, state) { + if (!path.scope.bindingIdentifierEquals(state.name, state.outerBinding)) { + path.skip(); + } + }, + Flow(path) { + if (path.isTypeCastExpression()) return; + path.skip(); + }, + Function(path, state) { + const oldNoOptimise = state.noOptimise; + state.noOptimise = true; + path.traverse(memberExpressionOptimisationVisitor, state); + state.noOptimise = oldNoOptimise; + path.skip(); + }, + ReferencedIdentifier(path, state) { + const { + node + } = path; + if (node.name === "arguments") { + state.deopted = true; + } + if (!referencesRest(path, state)) return; + if (state.noOptimise) { + state.deopted = true; + } else { + const { + parentPath + } = path; + if (parentPath.listKey === "params" && parentPath.key < state.offset) { + return; + } + if (parentPath.isMemberExpression({ + object: node + })) { + const grandparentPath = parentPath.parentPath; + const argsOptEligible = !state.deopted && !(grandparentPath.isAssignmentExpression() && parentPath.node === grandparentPath.node.left || grandparentPath.isLVal() || grandparentPath.isForXStatement() || grandparentPath.isUpdateExpression() || grandparentPath.isUnaryExpression({ + operator: "delete" + }) || (grandparentPath.isCallExpression() || grandparentPath.isNewExpression()) && parentPath.node === grandparentPath.node.callee); + if (argsOptEligible) { + if (parentPath.node.computed) { + if (parentPath.get("property").isBaseType("number")) { + state.candidates.push({ + cause: "indexGetter", + path + }); + return; + } + } else if (parentPath.node.property.name === "length") { + state.candidates.push({ + cause: "lengthGetter", + path + }); + return; + } + } + } + if (state.offset === 0 && parentPath.isSpreadElement()) { + const call = parentPath.parentPath; + if (call.isCallExpression() && call.node.arguments.length === 1) { + state.candidates.push({ + cause: "argSpread", + path + }); + return; + } + } + state.references.push(path); + } + }, + BindingIdentifier(path, state) { + if (referencesRest(path, state)) { + state.deopted = true; + } + } +}; +function getParamsCount(node) { + let count = node.params.length; + if (count > 0 && _core.types.isIdentifier(node.params[0], { + name: "this" + })) { + count -= 1; + } + return count; +} +function hasRest(node) { + const length = node.params.length; + return length > 0 && _core.types.isRestElement(node.params[length - 1]); +} +function optimiseIndexGetter(path, argsId, offset) { + const offsetLiteral = _core.types.numericLiteral(offset); + let index; + const parent = path.parent; + if (_core.types.isNumericLiteral(parent.property)) { + index = _core.types.numericLiteral(parent.property.value + offset); + } else if (offset === 0) { + index = parent.property; + } else { + index = _core.types.binaryExpression("+", parent.property, _core.types.cloneNode(offsetLiteral)); + } + const { + scope, + parentPath + } = path; + if (!scope.isPure(index)) { + const temp = scope.generateUidIdentifierBasedOnNode(index); + scope.push({ + id: temp, + kind: "var" + }); + parentPath.replaceWith(restIndexImpure({ + ARGUMENTS: argsId, + OFFSET: offsetLiteral, + INDEX: index, + REF: _core.types.cloneNode(temp) + })); + } else { + parentPath.replaceWith(restIndex({ + ARGUMENTS: argsId, + OFFSET: offsetLiteral, + INDEX: index + })); + const replacedParentPath = parentPath; + const offsetTestPath = replacedParentPath.get("test"); + const valRes = offsetTestPath.get("left").evaluate(); + if (valRes.confident) { + if (valRes.value === true) { + replacedParentPath.replaceWith(scope.buildUndefinedNode()); + } else { + offsetTestPath.replaceWith(offsetTestPath.get("right")); + } + } + } +} +function optimiseLengthGetter(path, argsId, offset) { + if (offset) { + path.parentPath.replaceWith(restLength({ + ARGUMENTS: argsId, + OFFSET: _core.types.numericLiteral(offset) + })); + } else { + path.replaceWith(argsId); + } +} +function convertFunctionRest(path) { + const { + node, + scope + } = path; + if (!hasRest(node)) return false; + const restPath = path.get(`params.${node.params.length - 1}.argument`); + if (!restPath.isIdentifier()) { + const shadowedParams = new Set(); + (0, _shadowUtils.collectShadowedParamsNames)(restPath, path.scope, shadowedParams); + let needsIIFE = shadowedParams.size > 0; + if (!needsIIFE) { + const state = { + needsOuterBinding: false, + scope + }; + restPath.traverse(_shadowUtils.iifeVisitor, state); + needsIIFE = state.needsOuterBinding; + } + if (needsIIFE) { + path.ensureBlock(); + path.set("body", _core.types.blockStatement([(0, _shadowUtils.buildScopeIIFE)(shadowedParams, path.node.body)])); + } + } + let rest = restPath.node; + node.params.pop(); + if (_core.types.isPattern(rest)) { + const pattern = rest; + rest = scope.generateUidIdentifier("ref"); + const declar = _core.types.variableDeclaration("let", [_core.types.variableDeclarator(pattern, rest)]); + path.ensureBlock(); + node.body.body.unshift(declar); + } else if (rest.name === "arguments") { + scope.rename(rest.name); + } + const argsId = _core.types.identifier("arguments"); + const paramsCount = getParamsCount(node); + const state = { + references: [], + offset: paramsCount, + argumentsNode: argsId, + outerBinding: scope.getBindingIdentifier(rest.name), + candidates: [], + name: rest.name, + deopted: false + }; + path.traverse(memberExpressionOptimisationVisitor, state); + if (!state.deopted && !state.references.length) { + for (const { + path, + cause + } of state.candidates) { + const clonedArgsId = _core.types.cloneNode(argsId); + switch (cause) { + case "indexGetter": + optimiseIndexGetter(path, clonedArgsId, state.offset); + break; + case "lengthGetter": + optimiseLengthGetter(path, clonedArgsId, state.offset); + break; + default: + path.replaceWith(clonedArgsId); + } + } + return true; + } + state.references.push(...state.candidates.map(({ + path + }) => path)); + const start = _core.types.numericLiteral(paramsCount); + const key = scope.generateUidIdentifier("key"); + const len = scope.generateUidIdentifier("len"); + let arrKey, arrLen; + if (paramsCount) { + arrKey = _core.types.binaryExpression("-", _core.types.cloneNode(key), _core.types.cloneNode(start)); + arrLen = _core.types.conditionalExpression(_core.types.binaryExpression(">", _core.types.cloneNode(len), _core.types.cloneNode(start)), _core.types.binaryExpression("-", _core.types.cloneNode(len), _core.types.cloneNode(start)), _core.types.numericLiteral(0)); + } else { + arrKey = _core.types.identifier(key.name); + arrLen = _core.types.identifier(len.name); + } + const loop = buildRest({ + ARGUMENTS: argsId, + ARRAY_KEY: arrKey, + ARRAY_LEN: arrLen, + START: start, + ARRAY: rest, + KEY: key, + LEN: len + }); + if (state.deopted) { + node.body.body.unshift(loop); + } else { + let target = path.getEarliestCommonAncestorFrom(state.references).getStatementParent(); + target.findParent(path => { + if (path.isLoop()) { + target = path; + } else { + return path.isFunction(); + } + }); + target.insertBefore(loop); + } + return true; +} + +//# sourceMappingURL=rest.js.map |
