consolidate the concept of "virtual types"
This commit is contained in:
parent
6a4e93bf0f
commit
0112c63779
@ -17,7 +17,7 @@ export default function (exports, opts) {
|
||||
};
|
||||
|
||||
exports.JSXIdentifier = function (node, parent) {
|
||||
if (node.name === "this" && t.isReferenced(node, parent)) {
|
||||
if (node.name === "this" && this.isReferenced()) {
|
||||
return t.thisExpression();
|
||||
} else if (esutils.keyword.isIdentifierNameES6(node.name)) {
|
||||
node.type = "Identifier";
|
||||
|
||||
@ -19,7 +19,7 @@ var awaitVisitor = {
|
||||
var referenceVisitor = {
|
||||
enter(node, parent, scope, state) {
|
||||
var name = state.id.name;
|
||||
if (t.isReferencedIdentifier(node, parent, { name: name }) && scope.bindingIdentifierEquals(name, state.id)) {
|
||||
if (this.isReferencedIdentifier({ name: name }) && scope.bindingIdentifierEquals(name, state.id)) {
|
||||
return state.ref = state.ref || scope.generateUidIdentifier(name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import callDelegate from "../../helpers/call-delegate";
|
||||
import * as util from "../../../util";
|
||||
import traverse from "../../../traversal";
|
||||
import * as t from "../../../types";
|
||||
|
||||
export function shouldVisit(node) {
|
||||
@ -13,16 +14,15 @@ var hasDefaults = function (node) {
|
||||
return false;
|
||||
};
|
||||
|
||||
var iifeVisitor = {
|
||||
enter(node, parent, scope, state) {
|
||||
if (!this.isReferencedIdentifier()) return;
|
||||
var iifeVisitor = traverse.explode({
|
||||
ReferencedIdentifier(node, parent, scope, state) {
|
||||
if (!state.scope.hasOwnBinding(node.name)) return;
|
||||
if (state.scope.bindingIdentifierEquals(node.name, node)) return;
|
||||
|
||||
state.iife = true;
|
||||
this.stop();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
exports.Function = function (node, parent, scope, file) {
|
||||
if (!hasDefaults(node)) return;
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import traverse from "../../../traversal";
|
||||
import * as t from "../../../types";
|
||||
|
||||
var visitor = {
|
||||
enter(node, parent, scope, state) {
|
||||
if (!this.isReferencedIdentifier()) return;
|
||||
var visitor = traverse.explode({
|
||||
ReferencedIdentifier(node, parent, scope, state) {
|
||||
if (t.isFor(parent) && parent.left === node) return;
|
||||
|
||||
var declared = state.letRefs[node.name];
|
||||
@ -25,7 +25,7 @@ var visitor = {
|
||||
return t.logicalExpression("&&", assert, node);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
export var metadata = {
|
||||
optional: true
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import reduceRight from "lodash/collection/reduceRight";
|
||||
import * as messages from "../../../messages";
|
||||
import flatten from "lodash/array/flatten";
|
||||
import traverse from "../../../traversal";
|
||||
import * as util from "../../../util";
|
||||
import map from "lodash/collection/map";
|
||||
import * as t from "../../../types";
|
||||
@ -16,54 +17,61 @@ function returnBlock(expr) {
|
||||
}
|
||||
|
||||
// looks for and replaces tail recursion calls
|
||||
var firstPass = {
|
||||
var firstPass = traverse.explode({
|
||||
enter(node, parent, scope, state) {
|
||||
if (this.isReturnStatement()) {
|
||||
this.skip();
|
||||
return state.subTransform(node.argument);
|
||||
} else if (t.isTryStatement(parent)) {
|
||||
if (t.isTryStatement(parent)) {
|
||||
if (node === parent.block) {
|
||||
this.skip();
|
||||
} else if (parent.finalizer && node !== parent.finalizer) {
|
||||
this.skip();
|
||||
}
|
||||
} else if (this.isFunction()) {
|
||||
this.skip();
|
||||
} else if (this.isVariableDeclaration()) {
|
||||
this.skip();
|
||||
state.vars.push(node);
|
||||
}
|
||||
},
|
||||
|
||||
ReturnStatement(node, parent, scope, state) {
|
||||
this.skip();
|
||||
return state.subTransform(node.argument);
|
||||
},
|
||||
|
||||
Function(node, parent, scope, state) {
|
||||
this.skip();
|
||||
},
|
||||
|
||||
VariableDeclaration(node, parent, scope, state) {
|
||||
this.skip();
|
||||
state.vars.push(node);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// hoists up function declarations, replaces `this` and `arguments` and marks
|
||||
// them as needed
|
||||
var secondPass = {
|
||||
enter(node, parent, scope, state) {
|
||||
if (this.isThisExpression()) {
|
||||
state.needsThis = true;
|
||||
return state.getThisId();
|
||||
} else if (this.isReferencedIdentifier({ name: "arguments" })) {
|
||||
state.needsArguments = true;
|
||||
return state.getArgumentsId();
|
||||
} else if (this.isFunction()) {
|
||||
this.skip();
|
||||
if (this.isFunctionDeclaration()) {
|
||||
node = t.variableDeclaration("var", [
|
||||
t.variableDeclarator(node.id, t.toExpression(node))
|
||||
]);
|
||||
node._blockHoist = 2;
|
||||
return node;
|
||||
}
|
||||
var secondPass = traverse.explode({
|
||||
ThisExpression(node, parent, scope, state) {
|
||||
state.needsThis = true;
|
||||
return state.getThisId();
|
||||
},
|
||||
|
||||
ReferencedIdentifier(node, parent, scope, state) {
|
||||
if (node.name !== "arguments") return;
|
||||
state.needsArguments = true;
|
||||
return state.getArgumentsId();
|
||||
},
|
||||
|
||||
Function(node, parent, scope, state) {
|
||||
this.skip();
|
||||
if (this.isFunctionDeclaration()) {
|
||||
node = t.variableDeclaration("var", [
|
||||
t.variableDeclarator(node.id, t.toExpression(node))
|
||||
]);
|
||||
node._blockHoist = 2;
|
||||
return node;
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// optimizes recursion by removing `this` and `arguments` if they aren't used
|
||||
var thirdPass = {
|
||||
enter(node, parent, scope, state) {
|
||||
if (!this.isExpressionStatement()) return;
|
||||
|
||||
var thirdPass = traverse.explode({
|
||||
ExpressionStatement(node, parent, scope, state) {
|
||||
var expr = node.expression;
|
||||
if (!t.isAssignmentExpression(expr)) return;
|
||||
|
||||
@ -75,7 +83,7 @@ var thirdPass = {
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
class TailCallTransformer {
|
||||
constructor(path, scope, file) {
|
||||
|
||||
@ -15,7 +15,7 @@ export default class Binding {
|
||||
* Description
|
||||
*/
|
||||
|
||||
setTypeAnnotation() {
|
||||
setTypeAnnotation() {
|
||||
var typeInfo = this.path.getTypeAnnotation();
|
||||
this.typeAnnotationInferred = typeInfo.inferred;
|
||||
this.typeAnnotation = typeInfo.annotation;
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
import PathHoister from "./hoister";
|
||||
import * as virtualTypes from "./virtual-types";
|
||||
import isBoolean from "lodash/lang/isBoolean";
|
||||
import isNumber from "lodash/lang/isNumber";
|
||||
import isRegExp from "lodash/lang/isRegExp";
|
||||
import isString from "lodash/lang/isString";
|
||||
import codeFrame from "../../helpers/code-frame";
|
||||
import parse from "../../helpers/parse";
|
||||
import { explode } from "../visitors";
|
||||
import traverse from "../index";
|
||||
import includes from "lodash/collection/includes";
|
||||
import assign from "lodash/object/assign";
|
||||
@ -12,33 +14,33 @@ import extend from "lodash/object/extend";
|
||||
import Scope from "../scope";
|
||||
import * as t from "../../types";
|
||||
|
||||
var hoistVariablesVisitor = {
|
||||
enter(node, parent, scope) {
|
||||
if (this.isFunction()) {
|
||||
return this.skip();
|
||||
}
|
||||
var hoistVariablesVisitor = explode({
|
||||
Function() {
|
||||
this.skip();
|
||||
},
|
||||
|
||||
VariableDeclaration(node, parent, scope) {
|
||||
if (node.kind !== "var") return;
|
||||
|
||||
if (this.isVariableDeclaration() && node.kind === "var") {
|
||||
var bindings = this.getBindingIdentifiers();
|
||||
for (var key in bindings) {
|
||||
scope.push({ id: bindings[key] });
|
||||
}
|
||||
|
||||
var exprs = [];
|
||||
|
||||
for (var i = 0; i < node.declarations.length; i++) {
|
||||
var declar = node.declarations[i];
|
||||
if (declar.init) {
|
||||
exprs.push(t.expressionStatement(
|
||||
t.assignmentExpression("=", declar.id, declar.init)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return exprs;
|
||||
for (var key in bindings) {
|
||||
scope.push({ id: bindings[key] });
|
||||
}
|
||||
|
||||
var exprs = [];
|
||||
|
||||
for (var i = 0; i < node.declarations.length; i++) {
|
||||
var declar = node.declarations[i];
|
||||
if (declar.init) {
|
||||
exprs.push(t.expressionStatement(
|
||||
t.assignmentExpression("=", declar.id, declar.init)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return exprs;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
export default class TraversalPath {
|
||||
constructor(parent, container) {
|
||||
@ -938,46 +940,6 @@ export default class TraversalPath {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
isScope(): boolean {
|
||||
return t.isScope(this.node, this.parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
isReferencedIdentifier(opts): boolean {
|
||||
return t.isReferencedIdentifier(this.node, this.parent, opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
isReferenced(): boolean {
|
||||
return t.isReferenced(this.node, this.parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
isBlockScoped(): boolean {
|
||||
return t.isBlockScoped(this.node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
isVar(): boolean {
|
||||
return t.isVar(this.node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
@ -1096,8 +1058,15 @@ export default class TraversalPath {
|
||||
assign(TraversalPath.prototype, require("./evaluation"));
|
||||
assign(TraversalPath.prototype, require("./conversion"));
|
||||
|
||||
for (var i = 0; i < t.TYPES.length; i++) {
|
||||
let type = t.TYPES[i];
|
||||
for (let type in virtualTypes) {
|
||||
if (type[0] === "_") continue;
|
||||
|
||||
TraversalPath.prototype[`is${type}`] = function (opts) {
|
||||
return virtualTypes[type].checkPath(this, opts);
|
||||
};
|
||||
}
|
||||
|
||||
for (let type of (t.TYPES: Array)) {
|
||||
let typeKey = `is${type}`;
|
||||
TraversalPath.prototype[typeKey] = function (opts) {
|
||||
return t[typeKey](this.node, opts);
|
||||
|
||||
34
src/babel/traversal/path/virtual-types.js
Normal file
34
src/babel/traversal/path/virtual-types.js
Normal file
@ -0,0 +1,34 @@
|
||||
import * as t from "../../types";
|
||||
|
||||
export var ReferencedIdentifier = {
|
||||
type: "Identifier",
|
||||
checkPath(path, opts) {
|
||||
return t.isReferencedIdentifier(path.node, path.parent, opts);
|
||||
}
|
||||
};
|
||||
|
||||
export var Scope = {
|
||||
type: "Scopable",
|
||||
checkPath(path) {
|
||||
return t.isScope(path.node, path.parent);
|
||||
}
|
||||
};
|
||||
|
||||
export var Referenced = {
|
||||
checkPath(path) {
|
||||
return t.isReferenced(path.node, path.parent);
|
||||
}
|
||||
};
|
||||
|
||||
export var BlockScoped = {
|
||||
checkPath(path) {
|
||||
return t.isBlockScoped(path.node);
|
||||
}
|
||||
};
|
||||
|
||||
export var Var = {
|
||||
type: "VariableDeclaration",
|
||||
checkPath(path) {
|
||||
return t.isVar(path.node);
|
||||
}
|
||||
};
|
||||
@ -65,33 +65,34 @@ var programReferenceVisitor = explode({
|
||||
}
|
||||
});
|
||||
|
||||
var blockVariableVisitor = {
|
||||
var blockVariableVisitor = explode({
|
||||
Scope() {
|
||||
this.skip();
|
||||
},
|
||||
|
||||
enter(node, parent, scope, state) {
|
||||
if (this.isFunctionDeclaration() || this.isBlockScoped()) {
|
||||
state.registerDeclaration(this);
|
||||
}
|
||||
if (this.isScope()) {
|
||||
this.skip();
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
var renameVisitor = explode({
|
||||
Identifier(node, parent, scope, state) {
|
||||
if (this.isReferenced() && node.name === state.oldName) {
|
||||
if (this.parentPath.isProperty() && this.key === "key" && parent.shorthand) {
|
||||
var value = t.identifier(state.newName);;
|
||||
ReferencedIdentifier(node, parent, scope, state) {
|
||||
if (node.name !== state.oldName) return;
|
||||
|
||||
if (parent.value === state.binding) {
|
||||
state.info.identifier = state.binding = value;
|
||||
}
|
||||
if (this.parentPath.isProperty() && this.key === "key" && parent.shorthand) {
|
||||
var value = t.identifier(state.newName);;
|
||||
|
||||
parent.shorthand = false;
|
||||
parent.value = value;
|
||||
parent.key = t.identifier(state.oldName);
|
||||
} else {
|
||||
node.name = state.newName;
|
||||
if (parent.value === state.binding) {
|
||||
state.info.identifier = state.binding = value;
|
||||
}
|
||||
|
||||
parent.shorthand = false;
|
||||
parent.value = value;
|
||||
parent.key = t.identifier(state.oldName);
|
||||
} else {
|
||||
node.name = state.newName;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@ -1,20 +1,56 @@
|
||||
import * as typeWrappers from "./wrappers";
|
||||
import * as messages from "../../messages";
|
||||
import * as t from "../../types";
|
||||
import * as virtualTypes from "./path/virtual-types";
|
||||
import * as messages from "../messages";
|
||||
import * as t from "../types";
|
||||
|
||||
export function explode(visitor, mergeConflicts) {
|
||||
// make sure there's no __esModule type since this is because we're using loose mode
|
||||
// and it sets __esModule to be enumerable on all modules :(
|
||||
delete visitor.__esModule;
|
||||
|
||||
// ensure visitors are objects
|
||||
for (let nodeType in visitor) {
|
||||
if (shouldIgnoreKey(nodeType)) continue;
|
||||
|
||||
var fns = visitor[nodeType];
|
||||
|
||||
if (typeof fns === "function") {
|
||||
visitor[nodeType] = fns = { enter: fns };
|
||||
visitor[nodeType] = { enter: fns };
|
||||
}
|
||||
}
|
||||
|
||||
// add type wrappers
|
||||
for (let nodeType in visitor) {
|
||||
if (shouldIgnoreKey(nodeType)) continue;
|
||||
|
||||
var wrapper = virtualTypes[nodeType];
|
||||
if (!wrapper) continue;
|
||||
|
||||
// wrap all the functions
|
||||
var fns = visitor[nodeType];
|
||||
for (var type in fns) {
|
||||
fns[type] = wrapCheck(wrapper, fns[type]);
|
||||
}
|
||||
|
||||
// clear it from the visitor
|
||||
delete visitor[nodeType];
|
||||
|
||||
if (wrapper.type) {
|
||||
// merge the visitor if necessary or just put it back in
|
||||
if (visitor[wrapper.type]) {
|
||||
merge(visitor[wrapper.type], fns);
|
||||
} else {
|
||||
visitor[wrapper.type] = fns;
|
||||
}
|
||||
} else {
|
||||
merge(visitor, fns);
|
||||
}
|
||||
}
|
||||
|
||||
// add aliases
|
||||
for (let nodeType in visitor) {
|
||||
if (shouldIgnoreKey(nodeType)) continue;
|
||||
|
||||
var fns = visitor[nodeType];
|
||||
|
||||
var aliases = t.FLIPPED_ALIAS_KEYS[nodeType];
|
||||
if (!aliases) continue;
|
||||
@ -34,30 +70,6 @@ export function explode(visitor, mergeConflicts) {
|
||||
}
|
||||
}
|
||||
|
||||
// handle type wrappers
|
||||
for (let nodeType in visitor) {
|
||||
if (shouldIgnoreKey(nodeType)) continue;
|
||||
|
||||
var wrapper = typeWrappers[nodeType];
|
||||
if (!wrapper) continue;
|
||||
|
||||
// wrap all the functions
|
||||
var fns = visitor[nodeType];
|
||||
for (var type in fns) {
|
||||
fns[type] = wrapper.wrap(fns[type]);
|
||||
}
|
||||
|
||||
// clear it from the visitor
|
||||
delete visitor[nodeType];
|
||||
|
||||
// merge the visitor if necessary or just put it back in
|
||||
if (visitor[wrapper.type]) {
|
||||
merge(visitor[wrapper.type], fns);
|
||||
} else {
|
||||
visitor[wrapper.type] = fns;
|
||||
}
|
||||
}
|
||||
|
||||
return visitor;
|
||||
}
|
||||
|
||||
@ -75,7 +87,7 @@ export function verify(visitor) {
|
||||
for (var nodeType in visitor) {
|
||||
if (shouldIgnoreKey(nodeType)) continue;
|
||||
|
||||
if (!t.VISITOR_KEYS[nodeType]) {
|
||||
if (t.TYPES.indexOf(nodeType) < 0) {
|
||||
throw new Error(messages.get("traverseVerifyNodeType", nodeType));
|
||||
}
|
||||
|
||||
@ -94,6 +106,14 @@ export function verify(visitor) {
|
||||
visitor._verified = true;
|
||||
}
|
||||
|
||||
function wrapCheck(wrapper, fn) {
|
||||
return function () {
|
||||
if (wrapper.checkPath(this)) {
|
||||
return fn.apply(this, arguments);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function shouldIgnoreKey(key) {
|
||||
// internal/hidden key
|
||||
if (key[0] === "_") return true;
|
||||
@ -1,10 +0,0 @@
|
||||
export var ReferencedIdentifier = {
|
||||
type: "Identifier",
|
||||
wrap(fn) {
|
||||
return function () {
|
||||
if (this.isReferencedIdentifier()) {
|
||||
return fn.apply(this, arguments);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user