зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1048384 - Getter/setter syntax should work with computed property names. r=jorendorff
This commit is contained in:
Родитель
eb93e16fa1
Коммит
0f8ce911a5
|
@ -7086,6 +7086,22 @@ DoubleToAtom(ExclusiveContext *cx, double value)
|
||||||
return ToAtom<CanGC>(cx, HandleValue::fromMarkedLocation(&tmp));
|
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>
|
template <typename ParseHandler>
|
||||||
typename ParseHandler::Node
|
typename ParseHandler::Node
|
||||||
Parser<ParseHandler>::objectLiteral()
|
Parser<ParseHandler>::objectLiteral()
|
||||||
|
@ -7121,16 +7137,9 @@ Parser<ParseHandler>::objectLiteral()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_LB: {
|
case TOK_LB: {
|
||||||
// Computed property name.
|
propname = computedPropertyName(literal);
|
||||||
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);
|
|
||||||
if (!propname)
|
if (!propname)
|
||||||
return null();
|
return null();
|
||||||
handler.setListFlag(literal, PNX_NONCONST);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7186,6 +7195,10 @@ Parser<ParseHandler>::objectLiteral()
|
||||||
propname = newNumber(tokenStream.currentToken());
|
propname = newNumber(tokenStream.currentToken());
|
||||||
if (!propname)
|
if (!propname)
|
||||||
return null();
|
return null();
|
||||||
|
} else if (tt == TOK_LB) {
|
||||||
|
propname = computedPropertyName(literal);
|
||||||
|
if (!propname)
|
||||||
|
return null();
|
||||||
} else {
|
} else {
|
||||||
// Not an accessor property after all.
|
// Not an accessor property after all.
|
||||||
tokenStream.ungetToken();
|
tokenStream.ungetToken();
|
||||||
|
|
|
@ -624,6 +624,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
|
||||||
Node pushLetScope(Handle<StaticBlockObject*> blockObj, StmtInfoPC *stmt);
|
Node pushLetScope(Handle<StaticBlockObject*> blockObj, StmtInfoPC *stmt);
|
||||||
bool noteNameUse(HandlePropertyName name, Node pn);
|
bool noteNameUse(HandlePropertyName name, Node pn);
|
||||||
Node objectLiteral();
|
Node objectLiteral();
|
||||||
|
Node computedPropertyName(Node literal);
|
||||||
Node arrayInitializer();
|
Node arrayInitializer();
|
||||||
Node newRegExp();
|
Node newRegExp();
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ assertEq(a.foo1, 1);
|
||||||
assertEq(a.foo2, 2);
|
assertEq(a.foo2, 2);
|
||||||
assertEq(a.foo3, 3);
|
assertEq(a.foo3, 3);
|
||||||
|
|
||||||
|
var expr = "abc";
|
||||||
syntaxError("({[");
|
syntaxError("({[");
|
||||||
syntaxError("({[expr");
|
syntaxError("({[expr");
|
||||||
syntaxError("({[expr]");
|
syntaxError("({[expr]");
|
||||||
|
@ -174,8 +175,69 @@ assertEq(next.done, true);
|
||||||
assertEq(next.value.hello, 2);
|
assertEq(next.value.hello, 2);
|
||||||
assertEq(next.value.world, 3);
|
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");
|
reportCompare(0, 0, "ok");
|
||||||
|
|
|
@ -402,6 +402,13 @@ var node = Reflect.parse("a = {[field1]: 5}");
|
||||||
Pattern({ body: [ { expression: { right: { properties: [ {key: { loc:
|
Pattern({ body: [ { expression: { right: { properties: [ {key: { loc:
|
||||||
{ start: { line: 1, column: 5 }, end: { line: 1, column: 13 }}}}]}}}]}).match(node);
|
{ 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
|
// statements
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче