Bug 1048384 - Getter/setter syntax should work with computed property names. r=jorendorff

This commit is contained in:
Guptha Rajagopal 2014-08-23 13:52:00 -04:00
parent eb93e16fa1
commit 0f8ce911a5
4 changed files with 92 additions and 9 deletions

View File

@ -7086,6 +7086,22 @@ DoubleToAtom(ExclusiveContext *cx, double value)
return ToAtom<CanGC>(cx, HandleValue::fromMarkedLocation(&tmp));
}
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::computedPropertyName(Node literal)
{
uint32_t begin = pos().begin;
Node assignNode = assignExpr();
if (!assignNode)
return null();
MUST_MATCH_TOKEN(TOK_RB, JSMSG_COMP_PROP_UNTERM_EXPR);
Node propname = handler.newComputedName(assignNode, begin, pos().end);
if (!propname)
return null();
handler.setListFlag(literal, PNX_NONCONST);
return propname;
}
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::objectLiteral()
@ -7121,16 +7137,9 @@ Parser<ParseHandler>::objectLiteral()
break;
case TOK_LB: {
// Computed property name.
uint32_t begin = pos().begin;
Node assignNode = assignExpr();
if (!assignNode)
return null();
MUST_MATCH_TOKEN(TOK_RB, JSMSG_COMP_PROP_UNTERM_EXPR);
propname = handler.newComputedName(assignNode, begin, pos().end);
propname = computedPropertyName(literal);
if (!propname)
return null();
handler.setListFlag(literal, PNX_NONCONST);
break;
}
@ -7186,6 +7195,10 @@ Parser<ParseHandler>::objectLiteral()
propname = newNumber(tokenStream.currentToken());
if (!propname)
return null();
} else if (tt == TOK_LB) {
propname = computedPropertyName(literal);
if (!propname)
return null();
} else {
// Not an accessor property after all.
tokenStream.ungetToken();

View File

@ -624,6 +624,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
Node pushLetScope(Handle<StaticBlockObject*> blockObj, StmtInfoPC *stmt);
bool noteNameUse(HandlePropertyName name, Node pn);
Node objectLiteral();
Node computedPropertyName(Node literal);
Node arrayInitializer();
Node newRegExp();

View File

@ -54,6 +54,7 @@ assertEq(a.foo1, 1);
assertEq(a.foo2, 2);
assertEq(a.foo3, 3);
var expr = "abc";
syntaxError("({[");
syntaxError("({[expr");
syntaxError("({[expr]");
@ -174,8 +175,69 @@ assertEq(next.done, true);
assertEq(next.value.hello, 2);
assertEq(next.value.world, 3);
syntaxError("a = {get [expr]() { return 3; }, set[expr](v) { return 2; }}");
// get and set.
expr = "abc";
syntaxError("({get [");
syntaxError("({get [expr()");
syntaxError("({get [expr]()");
syntaxError("({get [expr]()})");
syntaxError("({get [expr] 0 ()})");
syntaxError("({get [expr], 0(})");
syntaxError("[get [expr]: 0()]");
syntaxError("({get [expr](: name: 0})");
syntaxError("({get [1, 2](): 3})");
syntaxError("({get [1;](): 1})");
syntaxError("({get [if (0) 0;](){}})");
syntaxError("({set [(a)");
syntaxError("({set [expr(a)");
syntaxError("({set [expr](a){}");
syntaxError("({set [expr]}(a)");
syntaxError("({set [expr](a), 0})");
syntaxError("[set [expr](a): 0]");
syntaxError("({set [expr](a): name: 0})");
syntaxError("({set [1, 2](a) {return 3;}})");
syntaxError("({set [1;](a) {return 1}})");
syntaxError("({set [if (0) 0;](a){}})");
syntaxError("function f() { {get [x](): 1} }");
syntaxError("function f() { get [x](): 1 }");
syntaxError("function f() { {set [x](a): 1} }");
syntaxError("function f() { set [x](a): 1 }");
f1 = "abc";
syntaxError('a = {get [f1@](){}, set [f1](a){}}'); // unexpected symbol at end of AssignmentExpression
syntaxError('a = {get@ [f1](){}, set [f1](a){}}'); // unexpected symbol after get
syntaxError('a = {get [f1](){}, set@ [f1](a){}}'); // unexpected symbol after set
expr = "hey";
a = {get [expr]() { return 3; }, set[expr](v) { throw 2; }};
assertEq(a.hey, 3);
assertThrowsValue(() => { a.hey = 5; }, 2);
// Symbols with duplicate get and set.
expr = Symbol("hey");
a = {get [expr]() { return 3; }, set[expr](v) { throw 2; },
set [expr] (w) { throw 4; }, get[expr](){return 5; }};
assertEq(a[expr], 5);
assertThrowsValue(() => { a[expr] = 7; }, 4);
// expressions with side effects are called in the right order
log = "";
obj = {
"a": log += 'a',
get [log += 'b']() {},
[log += 'c']: log += 'd',
set [log += 'e'](a) {}
};
assertEq(log, "abcde");
// assignment expressions, objects and regex in computed names
obj = {
get [a = "hey"]() { return 1; },
get [a = {b : 4}.b]() { return 2; },
set [/x/.source](a) { throw 3; }
}
assertEq(obj.hey, 1);
assertEq(obj[4], 2);
assertThrowsValue(() => { obj.x = 7; }, 3);
reportCompare(0, 0, "ok");

View File

@ -402,6 +402,13 @@ var node = Reflect.parse("a = {[field1]: 5}");
Pattern({ body: [ { expression: { right: { properties: [ {key: { loc:
{ start: { line: 1, column: 5 }, end: { line: 1, column: 13 }}}}]}}}]}).match(node);
// Bug 1048384 - Getter/setter syntax with computed names
assertExpr("b = { get [meth]() { } }", aExpr("=", ident("b"),
objExpr([{ key: computedName(ident("meth")), value: funExpr(null, [], blockStmt([])),
method: false, kind: "get"}])));
assertExpr("b = { set [meth](a) { } }", aExpr("=", ident("b"),
objExpr([{ key: computedName(ident("meth")), value: funExpr(null, [ident("a")],
blockStmt([])), method: false, kind: "set"}])));
// statements