more generator spring cleaning

This commit is contained in:
Sebastian McKenzie 2014-11-17 17:30:41 +11:00
parent 8e115ef3ed
commit 7b74c1c8ec
6 changed files with 124 additions and 117 deletions

View File

@ -15,10 +15,10 @@ var assert = require("assert");
var types = require("ast-types");
var leap = require("./leap");
var meta = require("./meta");
var t = require("../../../types");
var _ = require("lodash");
var runtimeKeysMethod = runtimeProperty("keys");
var b = types.builders;
var n = types.namedTypes;
function Emitter(contextId) {
@ -58,7 +58,7 @@ function Emitter(contextId) {
// location to be determined at any time, even after generating code that
// refers to the location.
function loc() {
return b.literal(-1);
return t.literal(-1);
}
// Sets the exact value of the given location to the offset of the next
@ -78,7 +78,7 @@ Emitter.prototype.mark = function(loc) {
};
Emitter.prototype.emit = function(node) {
if (n.Expression.check(node)) node = b.expressionStatement(node);
if (t.isExpression(node)) node = t.expressionStatement(node);
n.Statement.assert(node);
this.listing.push(node);
};
@ -92,16 +92,16 @@ Emitter.prototype.emitAssign = function(lhs, rhs) {
// Shorthand for an assignment statement.
Emitter.prototype.assign = function(lhs, rhs) {
return b.expressionStatement(
b.assignmentExpression("=", lhs, rhs));
return t.expressionStatement(
t.assignmentExpression("=", lhs, rhs));
};
// Convenience function for generating expressions like context.next,
// context.sent, and context.rval.
Emitter.prototype.contextProperty = function(name, computed) {
return b.memberExpression(
return t.memberExpression(
this.contextId,
computed ? b.literal(name) : b.identifier(name),
computed ? t.literal(name) : t.identifier(name),
!!computed
);
};
@ -117,15 +117,15 @@ var volatileContextPropertyNames = {
// that should probably be stored in a temporary variable when there's a
// possibility the property will get overwritten.
Emitter.prototype.isVolatileContextProperty = function(expr) {
if (n.MemberExpression.check(expr)) {
if (t.isMemberExpression(expr)) {
if (expr.computed) {
// If it's a computed property such as context[couldBeAnything],
// assume the worst in terms of volatility.
return true;
}
if (n.Identifier.check(expr.object) &&
n.Identifier.check(expr.property) &&
if (t.isIdentifier(expr.object) &&
t.isIdentifier(expr.property) &&
expr.object.name === this.contextId.name &&
_.has(volatileContextPropertyNames, expr.property.name)) {
return true;
@ -156,7 +156,7 @@ Emitter.prototype.setReturnValue = function(valuePath) {
Emitter.prototype.clearPendingException = function(tryLoc, assignee) {
n.Literal.assert(tryLoc);
var catchCall = b.callExpression(
var catchCall = t.callExpression(
this.contextProperty("catch", true),
[tryLoc]
);
@ -172,7 +172,7 @@ Emitter.prototype.clearPendingException = function(tryLoc, assignee) {
// exact value of the location is not yet known.
Emitter.prototype.jump = function(toLoc) {
this.emitAssign(this.contextProperty("next"), toLoc);
this.emit(b.breakStatement());
this.emit(t.breakStatement());
};
// Conditional jump.
@ -180,11 +180,11 @@ Emitter.prototype.jumpIf = function(test, toLoc) {
n.Expression.assert(test);
n.Literal.assert(toLoc);
this.emit(b.ifStatement(
this.emit(t.ifStatement(
test,
b.blockStatement([
t.blockStatement([
this.assign(this.contextProperty("next"), toLoc),
b.breakStatement()
t.breakStatement()
])
));
};
@ -195,18 +195,18 @@ Emitter.prototype.jumpIfNot = function(test, toLoc) {
n.Literal.assert(toLoc);
var negatedTest;
if (n.UnaryExpression.check(test) && test.operator === "!") {
if (t.isUnaryExpression(test) && test.operator === "!") {
// Avoid double negation.
negatedTest = test.argument;
} else {
negatedTest = b.unaryExpression("!", test);
negatedTest = t.unaryExpression("!", test);
}
this.emit(b.ifStatement(
this.emit(t.ifStatement(
negatedTest,
b.blockStatement([
t.blockStatement([
this.assign(this.contextProperty("next"), toLoc),
b.breakStatement()
t.breakStatement()
])
));
};
@ -222,10 +222,10 @@ Emitter.prototype.makeTempVar = function() {
};
Emitter.prototype.getContextFunction = function(id) {
var node = b.functionExpression(
var node = t.functionExpression(
id || null,
[this.contextId],
b.blockStatement([this.getDispatchLoop()]),
t.blockStatement([this.getDispatchLoop()]),
false, // Not a generator anymore!
false // Nor an expression.
);
@ -255,7 +255,7 @@ Emitter.prototype.getDispatchLoop = function() {
self.listing.forEach(function(stmt, i) {
if (self.marked.hasOwnProperty(i)) {
cases.push(b.switchCase(b.literal(i), current = []));
cases.push(t.switchCase(t.literal(i), current = []));
alreadyEnded = false;
}
@ -271,24 +271,24 @@ Emitter.prototype.getDispatchLoop = function() {
this.finalLoc.value = this.listing.length;
cases.push(
b.switchCase(this.finalLoc, [
t.switchCase(this.finalLoc, [
// Intentionally fall through to the "end" case...
]),
// So that the runtime can jump to the final location without having
// to know its offset, we provide the "end" case as a synonym.
b.switchCase(b.literal("end"), [
t.switchCase(t.literal("end"), [
// This will check/clear both context.thrown and context.rval.
b.returnStatement(
b.callExpression(this.contextProperty("stop"), [])
t.returnStatement(
t.callExpression(this.contextProperty("stop"), [])
)
])
);
return b.whileStatement(
b.literal(true),
b.switchStatement(
b.assignmentExpression(
return t.whileStatement(
t.literal(true),
t.switchStatement(
t.assignmentExpression(
"=",
this.contextProperty("prev"),
this.contextProperty("next")
@ -300,10 +300,10 @@ Emitter.prototype.getDispatchLoop = function() {
// See comment above re: alreadyEnded.
function isSwitchCaseEnder(stmt) {
return n.BreakStatement.check(stmt) ||
n.ContinueStatement.check(stmt) ||
n.ReturnStatement.check(stmt) ||
n.ThrowStatement.check(stmt);
return t.isBreakStatement(stmt) ||
t.isContinueStatement(stmt) ||
t.isReturnStatement(stmt) ||
t.isThrowStatement(stmt);
}
Emitter.prototype.getTryEntryList = function() {
@ -315,7 +315,7 @@ Emitter.prototype.getTryEntryList = function() {
var lastLocValue = 0;
return b.arrayExpression(
return t.arrayExpression(
this.tryEntries.map(function(tryEntry) {
var thisLocValue = tryEntry.firstLoc.value;
assert.ok(thisLocValue >= lastLocValue, "try entries out of order");
@ -334,7 +334,7 @@ Emitter.prototype.getTryEntryList = function() {
triple[2] = fe.firstLoc;
}
return b.arrayExpression(triple);
return t.arrayExpression(triple);
})
);
};
@ -354,13 +354,13 @@ Emitter.prototype.explode = function(path, ignoreResult) {
n.Node.assert(node);
if (n.Statement.check(node))
if (t.isStatement(node))
return self.explodeStatement(path);
if (n.Expression.check(node))
if (t.isExpression(node))
return self.explodeExpression(path, ignoreResult);
if (n.Declaration.check(node))
if (t.isDeclaration(node))
throw getDeclError(node);
switch (node.type) {
@ -406,7 +406,7 @@ Emitter.prototype.explodeStatement = function(path, labelId) {
// Explode BlockStatement nodes even if they do not contain a yield,
// because we don't want or need the curly braces.
if (n.BlockStatement.check(stmt)) {
if (t.isBlockStatement(stmt)) {
return path.get("body").each(
self.explodeStatement,
self
@ -510,7 +510,7 @@ Emitter.prototype.explodeStatement = function(path, labelId) {
var keyIterNextFn = self.makeTempVar();
self.emitAssign(
keyIterNextFn,
b.callExpression(
t.callExpression(
runtimeKeysMethod,
[self.explodeExpression(path.get("right"))]
)
@ -520,13 +520,13 @@ Emitter.prototype.explodeStatement = function(path, labelId) {
var keyInfoTmpVar = self.makeTempVar();
self.jumpIf(
b.memberExpression(
b.assignmentExpression(
t.memberExpression(
t.assignmentExpression(
"=",
keyInfoTmpVar,
b.callExpression(keyIterNextFn, [])
t.callExpression(keyIterNextFn, [])
),
b.identifier("done"),
t.identifier("done"),
false
),
after
@ -534,9 +534,9 @@ Emitter.prototype.explodeStatement = function(path, labelId) {
self.emitAssign(
stmt.left,
b.memberExpression(
t.memberExpression(
keyInfoTmpVar,
b.identifier("value"),
t.identifier("value"),
false
)
);
@ -589,8 +589,8 @@ Emitter.prototype.explodeStatement = function(path, labelId) {
n.SwitchCase.assert(c);
if (c.test) {
condition = b.conditionalExpression(
b.binaryExpression("===", disc, c.test),
condition = t.conditionalExpression(
t.binaryExpression("===", disc, c.test),
caseLocs[i] = loc(),
condition
);
@ -731,7 +731,7 @@ Emitter.prototype.explodeStatement = function(path, labelId) {
self.explodeStatement(path.get("finalizer"));
});
self.emit(b.callExpression(
self.emit(t.callExpression(
self.contextProperty("finish"),
[finallyEntry.firstLoc]
));
@ -743,7 +743,7 @@ Emitter.prototype.explodeStatement = function(path, labelId) {
break;
case "ThrowStatement":
self.emit(b.throwStatement(
self.emit(t.throwStatement(
self.explodeExpression(path.get("argument"))
));
@ -767,7 +767,7 @@ Emitter.prototype.emitAbruptCompletion = function(record) {
"normal completions are not abrupt"
);
var abruptArgs = [b.literal(record.type)];
var abruptArgs = [t.literal(record.type)];
if (record.type === "break" || record.type === "continue") {
n.Literal.assert(record.target);
@ -780,8 +780,8 @@ Emitter.prototype.emitAbruptCompletion = function(record) {
}
this.emit(
b.returnStatement(
b.callExpression(
t.returnStatement(
t.callExpression(
this.contextProperty("abrupt"),
abruptArgs
)
@ -797,7 +797,7 @@ function isValidCompletion(record) {
}
if (type === "break" || type === "continue") {
return !_.has(record, "value") && n.Literal.check(record.target);
return !_.has(record, "value") && t.isLiteral(record.target);;
}
if (type === "return" || type === "throw") {
@ -818,7 +818,7 @@ function isValidCompletion(record) {
// targets, but minimizing the number of switch cases keeps the generated
// code shorter.
Emitter.prototype.getUnmarkedCurrentLoc = function() {
return b.literal(this.listing.length);
return t.literal(this.listing.length);
};
// The context.prev property takes the value of context.next whenever we
@ -940,7 +940,7 @@ Emitter.prototype.explodeExpression = function(path, ignoreResult) {
return finish(self.explodeExpression(path.get("expression")));
case "MemberExpression":
return finish(b.memberExpression(
return finish(t.memberExpression(
self.explodeExpression(path.get("object")),
expr.computed ? explodeViaTempVar(null, path.get("property")) : expr.property,
expr.computed
@ -956,15 +956,14 @@ Emitter.prototype.explodeExpression = function(path, ignoreResult) {
// MemberExpression, then we need to force it to be unqualified by
// using the (0, object.property)(...) trick; otherwise, it will
// receive the object of the MemberExpression as its `this` object.
if (!n.MemberExpression.check(oldCalleePath.node) &&
n.MemberExpression.check(newCallee)) {
newCallee = b.sequenceExpression([
b.literal(0),
if (!t.isMemberExpression(oldCalleePath.node) && t.isMemberExpression(newCallee)) {
newCallee = t.sequenceExpression([
t.literal(0),
newCallee
]);
}
return finish(b.callExpression(
return finish(t.callExpression(
newCallee,
path.get("arguments").map(function(argPath) {
return explodeViaTempVar(null, argPath);
@ -972,7 +971,7 @@ Emitter.prototype.explodeExpression = function(path, ignoreResult) {
));
case "NewExpression":
return finish(b.newExpression(
return finish(t.newExpression(
explodeViaTempVar(null, path.get("callee")),
path.get("arguments").map(function(argPath) {
return explodeViaTempVar(null, argPath);
@ -980,9 +979,9 @@ Emitter.prototype.explodeExpression = function(path, ignoreResult) {
));
case "ObjectExpression":
return finish(b.objectExpression(
return finish(t.objectExpression(
path.get("properties").map(function(propPath) {
return b.property(
return t.property(
propPath.value.kind,
propPath.value.key,
explodeViaTempVar(null, propPath.get("value"))
@ -991,7 +990,7 @@ Emitter.prototype.explodeExpression = function(path, ignoreResult) {
));
case "ArrayExpression":
return finish(b.arrayExpression(
return finish(t.arrayExpression(
path.get("elements").map(function(elemPath) {
return explodeViaTempVar(null, elemPath);
})
@ -1054,7 +1053,7 @@ Emitter.prototype.explodeExpression = function(path, ignoreResult) {
return result;
case "UnaryExpression":
return finish(b.unaryExpression(
return finish(t.unaryExpression(
expr.operator,
// Can't (and don't need to) break up the syntax of the argument.
// Think about delete a[b].
@ -1063,21 +1062,21 @@ Emitter.prototype.explodeExpression = function(path, ignoreResult) {
));
case "BinaryExpression":
return finish(b.binaryExpression(
return finish(t.binaryExpression(
expr.operator,
explodeViaTempVar(null, path.get("left")),
explodeViaTempVar(null, path.get("right"))
));
case "AssignmentExpression":
return finish(b.assignmentExpression(
return finish(t.assignmentExpression(
expr.operator,
self.explodeExpression(path.get("left")),
self.explodeExpression(path.get("right"))
));
case "UpdateExpression":
return finish(b.updateExpression(
return finish(t.updateExpression(
expr.operator,
self.explodeExpression(path.get("argument")),
expr.prefix
@ -1090,10 +1089,10 @@ Emitter.prototype.explodeExpression = function(path, ignoreResult) {
if (arg && expr.delegate) {
result = self.makeTempVar();
self.emit(b.returnStatement(b.callExpression(
self.emit(t.returnStatement(t.callExpression(
self.contextProperty("delegateYield"), [
arg,
b.literal(result.property.name),
t.literal(result.property.name),
after
]
)));
@ -1104,7 +1103,7 @@ Emitter.prototype.explodeExpression = function(path, ignoreResult) {
}
self.emitAssign(self.contextProperty("next"), after);
self.emit(b.returnStatement(arg || null));
self.emit(t.returnStatement(arg || null));
self.mark(after);
return self.contextProperty("sent");

View File

@ -3,17 +3,17 @@
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* https://raw.github.com/facebook/regenerator/master/LICENSE file. An
* https://raw.githut.com/facebook/regenerator/master/LICENSE file. An
* additional grant of patent rights can be found in the PATENTS file in
* the same directory.
*/
var assert = require("assert");
var types = require("ast-types");
var t = require("../../../types");
var _ = require("lodash");
var n = types.namedTypes;
var b = types.builders;
// The hoist function takes a FunctionExpression or FunctionDeclaration
// and replaces any Declaration nodes in its body with assignments, then
@ -33,7 +33,7 @@ exports.hoist = function(funPath) {
vars[dec.id.name] = dec.id;
if (dec.init) {
exprs.push(b.assignmentExpression(
exprs.push(t.assignmentExpression(
"=", dec.id, dec.init
));
} else if (includeIdentifiers) {
@ -47,7 +47,7 @@ exports.hoist = function(funPath) {
if (exprs.length === 1)
return exprs[0];
return b.sequenceExpression(exprs);
return t.sequenceExpression(exprs);
}
types.visit(funPath.get("body"), {
@ -58,7 +58,7 @@ exports.hoist = function(funPath) {
} else {
// We don't need to traverse this expression any further because
// there can't be any new declarations inside an expression.
return b.expressionStatement(expr);
return t.expressionStatement(expr);
}
// Since the original node has been either removed or replaced,
@ -68,7 +68,7 @@ exports.hoist = function(funPath) {
visitForStatement: function(path) {
var init = path.value.init;
if (n.VariableDeclaration.check(init)) {
if (t.isVariableDeclaration(init)) {
path.get("init").replace(varDeclToExpr(init, false));
}
this.traverse(path);
@ -76,7 +76,7 @@ exports.hoist = function(funPath) {
visitForInStatement: function(path) {
var left = path.value.left;
if (n.VariableDeclaration.check(left)) {
if (t.isVariableDeclaration(left)) {
path.get("left").replace(varDeclToExpr(left, true));
}
this.traverse(path);
@ -86,11 +86,11 @@ exports.hoist = function(funPath) {
var node = path.value;
vars[node.id.name] = node.id;
var assignment = b.expressionStatement(
b.assignmentExpression(
var assignment = t.expressionStatement(
t.assignmentExpression(
"=",
node.id,
b.functionExpression(
t.functionExpression(
node.id,
node.params,
node.body,
@ -100,7 +100,7 @@ exports.hoist = function(funPath) {
)
);
if (n.BlockStatement.check(path.parent.node)) {
if (t.isBlockStatement(path.parent.node)) {
// Insert the assignment form before the first statement in the
// enclosing block.
path.parent.get("body").unshift(assignment);
@ -129,7 +129,7 @@ exports.hoist = function(funPath) {
var paramNames = {};
funPath.get("params").each(function(paramPath) {
var param = paramPath.value;
if (n.Identifier.check(param)) {
if (t.isIdentifier(param)) {
paramNames[param.name] = param;
} else {
// Variables declared by destructuring parameter patterns will be
@ -141,7 +141,7 @@ exports.hoist = function(funPath) {
Object.keys(vars).forEach(function(name) {
if (!_.has(paramNames, name)) {
declarations.push(b.variableDeclarator(vars[name], null));
declarations.push(t.variableDeclarator(vars[name], null));
}
});
@ -149,5 +149,5 @@ exports.hoist = function(funPath) {
return null; // Be sure to handle this case!
}
return b.variableDeclaration("var", declarations);
return t.variableDeclaration("var", declarations);
};

View File

@ -11,6 +11,7 @@
var assert = require("assert");
var types = require("ast-types");
var m = require("private").makeAccessor();
var t = require("../../../types");
var _ = require("lodash");
var isArray = types.builtInTypes.array;

View File

@ -3,20 +3,22 @@
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* https://raw.github.com/facebook/regenerator/master/LICENSE file. An
* https://raw.githut.com/facebook/regenerator/master/LICENSE file. An
* additional grant of patent rights can be found in the PATENTS file in
* the same directory.
*/
var types = require("ast-types");
var n = types.namedTypes;
var b = types.builders;
var hoist = require("./hoist").hoist;
var Emitter = require("./emit").Emitter;
var runtimeProperty = require("./util").runtimeProperty;
var runtimeWrapMethod = runtimeProperty("wrap");
var runtimeMarkMethod = runtimeProperty("mark");
var Emitter = require("./emit").Emitter;
var hoist = require("./hoist").hoist;
var types = require("ast-types");
var t = require("../../../types");
var n = types.namedTypes;
var runtimeAsyncMethod = runtimeProperty("async");
var runtimeWrapMethod = runtimeProperty("wrap");
var runtimeMarkMethod = runtimeProperty("mark");
exports.transform = function transform(node) {
return types.visit(node, visitor);
@ -38,8 +40,8 @@ var visitor = types.PathVisitor.fromMethodsObject({
if (node.expression) {
// Transform expression lambdas into normal functions.
node.expression = false;
node.body = b.blockStatement([
b.returnStatement(node.body)
node.body = t.blockStatement([
t.returnStatement(node.body)
]);
}
@ -51,7 +53,7 @@ var visitor = types.PathVisitor.fromMethodsObject({
node.id = path.scope.parent.declareTemporary("callee$")
);
var innerFnId = b.identifier(node.id.name + "$");
var innerFnId = t.identifier(node.id.name + "$");
var contextId = path.scope.declareTemporary("context$");
var vars = hoist(path);
@ -68,8 +70,8 @@ var visitor = types.PathVisitor.fromMethodsObject({
emitter.getContextFunction(innerFnId),
// Async functions don't care about the outer function because they
// don't need it to be marked and don't inherit from its .prototype.
node.async ? b.literal(null) : outerFnId,
b.thisExpression()
node.async ? t.literal(null) : outerFnId,
t.thisExpression()
];
var tryEntryList = emitter.getTryEntryList();
@ -77,24 +79,23 @@ var visitor = types.PathVisitor.fromMethodsObject({
wrapArgs.push(tryEntryList);
}
var wrapCall = b.callExpression(
var wrapCall = t.callExpression(
node.async ? runtimeAsyncMethod : runtimeWrapMethod,
wrapArgs
);
outerBody.push(b.returnStatement(wrapCall));
node.body = b.blockStatement(outerBody);
outerBody.push(t.returnStatement(wrapCall));
node.body = t.blockStatement(outerBody);
if (node.async) {
node.async = false;
return;
}
if (n.FunctionDeclaration.check(node)) {
if (t.isFunctionDeclaration(node)) {
var pp = path.parent;
while (pp && !(n.BlockStatement.check(pp.value) ||
n.Program.check(pp.value))) {
while (pp && !(t.isBlockStatement(pp.value) || t.isProgram(pp.value))) {
pp = pp.parent;
}
@ -150,10 +151,10 @@ var visitor = types.PathVisitor.fromMethodsObject({
// declaration. Note that all the other fields are the same.
node.type = "FunctionExpression";
var varDecl = b.variableDeclaration("var", [
b.variableDeclarator(
var varDecl = t.variableDeclaration("var", [
t.variableDeclarator(
node.id,
b.callExpression(runtimeMarkMethod, [node])
t.callExpression(runtimeMarkMethod, [node])
)
]);
@ -179,7 +180,7 @@ var visitor = types.PathVisitor.fromMethodsObject({
} else {
n.FunctionExpression.assert(node);
return b.callExpression(runtimeMarkMethod, [node]);
return t.callExpression(runtimeMarkMethod, [node]);
}
}
});
@ -190,17 +191,16 @@ function shouldNotHoistAbove(stmtPath) {
// If the first statement is a "use strict" declaration, make sure to
// insert hoisted declarations afterwards.
if (n.ExpressionStatement.check(value) &&
n.Literal.check(value.expression) &&
if (t.isExpressionStatement(value) &&
t.isLiteral(value.expression) &&
value.expression.value === "use strict") {
return true;
}
if (n.VariableDeclaration.check(value)) {
if (t.isVariableDeclaration(value)) {
for (var i = 0; i < value.declarations.length; ++i) {
var decl = value.declarations[i];
if (n.CallExpression.check(decl.init) &&
types.astNodesAreEquivalent(decl.init.callee, runtimeMarkMethod)) {
if (t.isCallExpression(decl.init) && types.astNodesAreEquivalent(decl.init.callee, runtimeMarkMethod)) {
return true;
}
}
@ -216,6 +216,6 @@ var awaitVisitor = types.PathVisitor.fromMethodsObject({
visitAwaitExpression: function(path) {
// Convert await expressions to yield expressions.
return b.yieldExpression(path.value.argument, false);
return t.yieldExpression(path.value.argument, false);
}
});

View File

@ -19,6 +19,7 @@
"Property": ["kind", "key", "value", "computed"],
"ReturnStatement": ["argument"],
"SequenceExpression": ["expressions"],
"ThrowExpression": ["argument"],
"UnaryExpression": ["operator", "argument", "prefix"],
"VariableDeclaration": ["kind", "declarations"],
"VariableDeclarator": ["id", "init"],

View File

@ -50,6 +50,12 @@ _.each(_aliases, function (types, type) {
//
t.isExpression = function (node) {
return !t.isDeclaration(node);
};
//
t.shallowEqual = function (actual, expected) {
var same = true;