refactor _shadowFunctions transformer to not do an entire traverse per function
This commit is contained in:
parent
8605e835eb
commit
f373f8f003
@ -1,105 +1,33 @@
|
||||
import * as t from "../../../types";
|
||||
|
||||
var functionChildrenVisitor = {
|
||||
enter(node, parent, scope, state) {
|
||||
if (this.isClass(node)) {
|
||||
return this.skip();
|
||||
}
|
||||
|
||||
if (this.isFunction() && !node.shadow) {
|
||||
return this.skip();
|
||||
}
|
||||
|
||||
if (node._shadowedFunctionLiteral) return this.skip();
|
||||
|
||||
var getId;
|
||||
|
||||
if (this.isIdentifier() && node.name === "arguments") {
|
||||
getId = state.getArgumentsId;
|
||||
} else if (this.isThisExpression()) {
|
||||
getId = state.getThisId;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isReferenced()) return getId();
|
||||
}
|
||||
};
|
||||
|
||||
var functionVisitor = {
|
||||
enter(node, parent, scope, state) {
|
||||
if (!node.shadow) {
|
||||
if (this.isFunction()) {
|
||||
// stop traversal of this node as it'll be hit again by this transformer
|
||||
return this.skip();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// traverse all child nodes of this function and find `arguments` and `this`
|
||||
this.traverse(functionChildrenVisitor, state);
|
||||
|
||||
node.shadow = false;
|
||||
|
||||
return this.skip();
|
||||
}
|
||||
};
|
||||
|
||||
function aliasFunction(getBody, path, scope) {
|
||||
var argumentsId;
|
||||
var thisId;
|
||||
|
||||
var state = {
|
||||
getArgumentsId() {
|
||||
return argumentsId = argumentsId || scope.generateUidIdentifier("arguments");
|
||||
},
|
||||
|
||||
getThisId() {
|
||||
return thisId = thisId || scope.generateUidIdentifier("this");
|
||||
}
|
||||
};
|
||||
|
||||
// traverse the function and find all alias functions so we can alias
|
||||
// `arguments` and `this` if necessary
|
||||
path.traverse(functionVisitor, state);
|
||||
|
||||
var body;
|
||||
|
||||
var pushDeclaration = function (id, init) {
|
||||
body = body || getBody();
|
||||
body.unshift(t.variableDeclaration("var", [
|
||||
t.variableDeclarator(id, init)
|
||||
]));
|
||||
};
|
||||
|
||||
if (argumentsId) {
|
||||
pushDeclaration(argumentsId, t.identifier("arguments"));
|
||||
}
|
||||
|
||||
if (thisId) {
|
||||
pushDeclaration(thisId, t.thisExpression());
|
||||
}
|
||||
};
|
||||
|
||||
// todo: on all `this` and `arguments`, walk UP the tree instead of
|
||||
// crawling the entire function tree
|
||||
|
||||
export var metadata = {
|
||||
group: "builtin-trailing"
|
||||
};
|
||||
|
||||
export function Program(node, parent, scope) {
|
||||
aliasFunction(function () {
|
||||
return node.body;
|
||||
}, this, scope);
|
||||
function remap(path, key, create) {
|
||||
// ensure that we're shadowed
|
||||
if (!path.inShadow()) return;
|
||||
|
||||
var fnPath = path.findParent((node, path) => !node.shadow && (path.isFunction() || path.isProgram()));
|
||||
|
||||
var cached = fnPath.getData(key);
|
||||
if (cached) return cached;
|
||||
|
||||
var init = create();
|
||||
var id = path.scope.generateUidIdentifier(key);
|
||||
|
||||
fnPath.setData(key, id);
|
||||
fnPath.scope.push({ id, init });
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
export function FunctionDeclaration(node, parent, scope) {
|
||||
aliasFunction(function () {
|
||||
t.ensureBlock(node);
|
||||
return node.body.body;
|
||||
}, this, scope);
|
||||
export function ThisExpression() {
|
||||
return remap(this, "this", () => t.thisExpression());
|
||||
}
|
||||
|
||||
export { FunctionDeclaration as FunctionExpression };
|
||||
export function ReferencedIdentifier(node) {
|
||||
if (node.name === "arguments" && !node._shadowedFunctionLiteral) {
|
||||
return remap(this, "arguments", () => t.identifier("arguments"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,9 +23,7 @@ export var Program = {
|
||||
}
|
||||
|
||||
export function ThisExpression() {
|
||||
if (!this.findParent(function (node) {
|
||||
return !node.shadow && THIS_BREAK_KEYS.indexOf(node.type) >= 0;
|
||||
})) {
|
||||
if (!this.findParent((node) => !node.shadow && THIS_BREAK_KEYS.indexOf(node.type) >= 0)) {
|
||||
return t.identifier("undefined");
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,6 +125,25 @@ export default class TraversalPath {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
inShadow() {
|
||||
var path = this;
|
||||
while (path) {
|
||||
if (path.isFunction()) {
|
||||
if (path.node.shadow) {
|
||||
return path;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
path = path.parentPath;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this node was a part of the original AST.
|
||||
*/
|
||||
@ -148,7 +167,7 @@ export default class TraversalPath {
|
||||
findParent(callback) {
|
||||
var path = this;
|
||||
while (path) {
|
||||
if (callback(path.node)) return path.node;
|
||||
if (callback(path.node, path)) return path;
|
||||
path = path.parentPath;
|
||||
}
|
||||
return null;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user