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";
|
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 = {
|
export var metadata = {
|
||||||
group: "builtin-trailing"
|
group: "builtin-trailing"
|
||||||
};
|
};
|
||||||
|
|
||||||
export function Program(node, parent, scope) {
|
function remap(path, key, create) {
|
||||||
aliasFunction(function () {
|
// ensure that we're shadowed
|
||||||
return node.body;
|
if (!path.inShadow()) return;
|
||||||
}, this, scope);
|
|
||||||
|
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) {
|
export function ThisExpression() {
|
||||||
aliasFunction(function () {
|
return remap(this, "this", () => t.thisExpression());
|
||||||
t.ensureBlock(node);
|
|
||||||
return node.body.body;
|
|
||||||
}, this, scope);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
export function ThisExpression() {
|
||||||
if (!this.findParent(function (node) {
|
if (!this.findParent((node) => !node.shadow && THIS_BREAK_KEYS.indexOf(node.type) >= 0)) {
|
||||||
return !node.shadow && THIS_BREAK_KEYS.indexOf(node.type) >= 0;
|
|
||||||
})) {
|
|
||||||
return t.identifier("undefined");
|
return t.identifier("undefined");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -125,6 +125,25 @@ export default class TraversalPath {
|
|||||||
return false;
|
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.
|
* Check whether this node was a part of the original AST.
|
||||||
*/
|
*/
|
||||||
@ -148,7 +167,7 @@ export default class TraversalPath {
|
|||||||
findParent(callback) {
|
findParent(callback) {
|
||||||
var path = this;
|
var path = this;
|
||||||
while (path) {
|
while (path) {
|
||||||
if (callback(path.node)) return path.node;
|
if (callback(path.node, path)) return path;
|
||||||
path = path.parentPath;
|
path = path.parentPath;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user