Bug 1220702 - Part 3: Distinguish ES6 generators from legacy generators in Reflect.parse() output. r=Waldo.

--HG--
extra : commitid : EjbmKoUzVHY
extra : rebase_source : c9a5d21662ebe9b22a6ea4f6b74de30d5a7979a4
This commit is contained in:
Jason Orendorff 2015-11-03 14:53:44 -06:00
parent ee1aaa35e1
commit 63c05bf58b
7 changed files with 62 additions and 22 deletions

View File

@ -222,6 +222,13 @@ GetPropertyDefault(JSContext* cx, HandleObject obj, HandleId id, HandleValue def
return GetProperty(cx, obj, obj, id, result);
}
enum class GeneratorStyle
{
None,
Legacy,
ES6
};
/*
* Builder class that constructs JavaScript AST node objects. See:
*
@ -458,8 +465,8 @@ class NodeBuilder
bool function(ASTType type, TokenPos* pos,
HandleValue id, NodeVector& args, NodeVector& defaults,
HandleValue body, HandleValue rest, bool isGenerator, bool isExpression,
MutableHandleValue dst);
HandleValue body, HandleValue rest, GeneratorStyle generatorStyle,
bool isExpression, MutableHandleValue dst);
bool variableDeclarator(HandleValue id, HandleValue init, TokenPos* pos,
MutableHandleValue dst);
@ -1595,7 +1602,7 @@ bool
NodeBuilder::function(ASTType type, TokenPos* pos,
HandleValue id, NodeVector& args, NodeVector& defaults,
HandleValue body, HandleValue rest,
bool isGenerator, bool isExpression,
GeneratorStyle generatorStyle, bool isExpression,
MutableHandleValue dst)
{
RootedValue array(cx), defarray(cx);
@ -1604,6 +1611,7 @@ NodeBuilder::function(ASTType type, TokenPos* pos,
if (!newArray(defaults, &defarray))
return false;
bool isGenerator = generatorStyle != GeneratorStyle::None;
RootedValue isGeneratorVal(cx, BooleanValue(isGenerator));
RootedValue isExpressionVal(cx, BooleanValue(isExpression));
@ -1612,6 +1620,27 @@ NodeBuilder::function(ASTType type, TokenPos* pos,
return callback(cb, opt(id), array, body, isGeneratorVal, isExpressionVal, pos, dst);
}
if (isGenerator) {
// Distinguish ES6 generators from legacy generators.
RootedValue styleVal(cx);
JSAtom* styleStr = generatorStyle == GeneratorStyle::ES6
? Atomize(cx, "es6", 3)
: Atomize(cx, "legacy", 6);
if (!styleStr)
return false;
styleVal.setString(styleStr);
return newNode(type, pos,
"id", id,
"params", array,
"defaults", defarray,
"body", body,
"rest", rest,
"generator", isGeneratorVal,
"style", styleVal,
"expression", isExpressionVal,
dst);
}
return newNode(type, pos,
"id", id,
"params", array,
@ -3407,8 +3436,12 @@ ASTSerializer::function(ParseNode* pn, ASTType type, MutableHandleValue dst)
{
RootedFunction func(cx, pn->pn_funbox->function());
// FIXME: Provide more information (legacy generator vs star generator).
bool isGenerator = pn->pn_funbox->isGenerator();
GeneratorStyle generatorStyle =
pn->pn_funbox->isGenerator()
? (pn->pn_funbox->isLegacyGenerator()
? GeneratorStyle::Legacy
: GeneratorStyle::ES6)
: GeneratorStyle::None;
bool isExpression =
#if JS_HAS_EXPR_CLOSURES
@ -3432,7 +3465,7 @@ ASTSerializer::function(ParseNode* pn, ASTType type, MutableHandleValue dst)
rest.setNull();
return functionArgsAndBody(pn->pn_body, args, defaults, &body, &rest) &&
builder.function(type, &pn->pn_pos, id, args, defaults, body,
rest, isGenerator, isExpression, dst);
rest, generatorStyle, isExpression, dst);
}
bool

View File

@ -38,13 +38,14 @@ function funDecl(id, params, body, defaults=[], rest=null) {
rest: rest,
generator: false });
}
function genFunDecl(id, params, body) {
function genFunDecl(style, id, params, body) {
return Pattern({ type: "FunctionDeclaration",
id: id,
params: params,
defaults: [],
body: body,
generator: true });
generator: true,
style: style });
}
function varDecl(decls) {
return Pattern({ type: "VariableDeclaration", declarations: decls, kind: "var" });
@ -157,12 +158,13 @@ function funExpr(id, args, body, gen) {
body: body,
generator: false });
}
function genFunExpr(id, args, body) {
function genFunExpr(style, id, args, body) {
return Pattern({ type: "FunctionExpression",
id: id,
params: args,
body: body,
generator: true });
generator: true,
style: style });
}
function arrowExpr(args, body) {
return Pattern({ type: "ArrowFunctionExpression",

View File

@ -41,7 +41,7 @@ assertGlobalExpr("({ x: y })", 13, { objectExpression: () => 13 });
assertGlobalExpr("this", 14, { thisExpression: () => 14 });
assertGlobalExpr("[x for (x in y)]", 17, { comprehensionExpression: () => 17 });
assertGlobalExpr("(x for (x in y))", 18, { generatorExpression: () => 18 });
assertGlobalExpr("(function() { yield 42 })", genFunExpr(null, [], blockStmt([exprStmt(19)])), { yieldExpression: () => 19 });
assertGlobalExpr("(function() { yield 42 })", genFunExpr("legacy", null, [], blockStmt([exprStmt(19)])), { yieldExpression: () => 19 });
assertGlobalStmt("switch (x) { case y: }", switchStmt(ident("x"), [1]), { switchCase: () => 1 });
assertGlobalStmt("try { } catch (e) { }", 2, { tryStatement: (b, g, u, f) => u, catchClause: () => 2 });

View File

@ -14,10 +14,11 @@ function testClasses() {
function methodFun(id, kind, generator, args, body = []) {
assertEq(generator && kind === "method", generator);
assertEq(typeof id === 'string' || id === null, true);
let idN = typeof id === 'string' ? ident(id): null;
let methodMaker = generator ? genFunExpr : funExpr;
let idN = typeof id === 'string' ? ident(id) : null;
let methodName = kind !== "method" ? null : idN;
return methodMaker(methodName, args.map(ident), blockStmt(body));
return generator
? genFunExpr("es6", methodName, args.map(ident), blockStmt(body))
: funExpr(methodName, args.map(ident), blockStmt(body));
}
function simpleMethod(id, kind, generator, args=[], isStatic=false) {

View File

@ -3,10 +3,14 @@ function test() {
// generators
assertDecl("function gen(x) { yield }", genFunDecl(ident("gen"), [ident("x")], blockStmt([exprStmt(yieldExpr(null))])));
assertExpr("(function(x) { yield })", genFunExpr(null, [ident("x")], blockStmt([exprStmt(yieldExpr(null))])));
assertDecl("function gen(x) { yield 42 }", genFunDecl(ident("gen"), [ident("x")], blockStmt([exprStmt(yieldExpr(lit(42)))])));
assertExpr("(function(x) { yield 42 })", genFunExpr(null, [ident("x")], blockStmt([exprStmt(yieldExpr(lit(42)))])));
assertDecl("function gen(x) { yield }", genFunDecl("legacy", ident("gen"), [ident("x")], blockStmt([exprStmt(yieldExpr(null))])));
assertExpr("(function(x) { yield })", genFunExpr("legacy", null, [ident("x")], blockStmt([exprStmt(yieldExpr(null))])));
assertDecl("function gen(x) { yield 42 }", genFunDecl("legacy", ident("gen"), [ident("x")], blockStmt([exprStmt(yieldExpr(lit(42)))])));
assertExpr("(function(x) { yield 42 })", genFunExpr("legacy", null, [ident("x")], blockStmt([exprStmt(yieldExpr(lit(42)))])));
assertDecl("function* gen() {}", genFunDecl("es6", ident("gen"), [], blockStmt([])));
assertExpr("(function*() {})", genFunExpr("es6", null, [], blockStmt([])));
assertExpr("(function* gen() {})", genFunExpr("es6", ident("gen"), [], blockStmt([])));
}

View File

@ -7,7 +7,7 @@ assertExpr("b = { a() { } }", aExpr("=", ident("b"),
true}])));
assertExpr("b = { *a() { } }", aExpr("=", ident("b"),
objExpr([{ key: ident("a"), value: genFunExpr(ident("a"), [], blockStmt([])), method:
objExpr([{ key: ident("a"), value: genFunExpr("es6", ident("a"), [], blockStmt([])), method:
true}])));
// Method definitions without braces
@ -28,9 +28,9 @@ assertExpr("({ set x(v) { return 42 } })",
// Bug 1073809 - Getter/setter syntax with generators
assertExpr("({*get() { }})", objExpr([{ type: "Property", key: ident("get"), method: true,
value: genFunExpr(ident("get"), [], blockStmt([]))}]));
value: genFunExpr("es6", ident("get"), [], blockStmt([]))}]));
assertExpr("({*set() { }})", objExpr([{ type: "Property", key: ident("set"), method: true,
value: genFunExpr(ident("set"), [], blockStmt([]))}]));
value: genFunExpr("es6", ident("set"), [], blockStmt([]))}]));
assertError("({*get foo() { }})", SyntaxError);
assertError("({*set foo() { }})", SyntaxError);

View File

@ -16,7 +16,7 @@ function testNewTarget() {
assertError("(() => new.target))", SyntaxError);
// valid in generators, too!
assertStmt("function *foo() { new.target; }", genFunDecl(ident("foo"), [],
assertStmt("function *foo() { new.target; }", genFunDecl("es6", ident("foo"), [],
blockStmt([exprStmt(newTarget())])));
// new.target is a member expression. You should be able to call, invoke, or