ES6: Implement generator method shorthand
https://people.mozilla.org/~jorendorff/es6-draft.html#sec-method-definitions BUG=v8:3516 LOG=Y R=dslomov@chromium.org Review URL: https://codereview.chromium.org/577973002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24048 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
a479b2cb03
commit
714f5f401c
@ -761,17 +761,17 @@ enum FunctionKind {
|
||||
kNormalFunction = 0,
|
||||
kArrowFunction = 1,
|
||||
kGeneratorFunction = 2,
|
||||
kConciseMethod = 4
|
||||
kConciseMethod = 4,
|
||||
kConciseGeneratorMethod = kGeneratorFunction | kConciseMethod
|
||||
};
|
||||
|
||||
|
||||
inline bool IsValidFunctionKind(FunctionKind kind) {
|
||||
// At the moment these are mutually exclusive but in the future that wont be
|
||||
// the case since ES6 allows concise generator methods.
|
||||
return kind == FunctionKind::kNormalFunction ||
|
||||
kind == FunctionKind::kArrowFunction ||
|
||||
kind == FunctionKind::kGeneratorFunction ||
|
||||
kind == FunctionKind::kConciseMethod;
|
||||
kind == FunctionKind::kConciseMethod ||
|
||||
kind == FunctionKind::kConciseGeneratorMethod;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1936,11 +1936,12 @@ template <class Traits>
|
||||
typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase<
|
||||
Traits>::ParsePropertyDefinition(ObjectLiteralChecker* checker,
|
||||
bool in_class, bool is_static, bool* ok) {
|
||||
// TODO(arv): Add support for concise generator methods.
|
||||
ExpressionT value = this->EmptyExpression();
|
||||
bool is_get = false;
|
||||
bool is_set = false;
|
||||
bool name_is_static = false;
|
||||
bool is_generator = allow_harmony_object_literals_ && Check(Token::MUL);
|
||||
|
||||
Token::Value name_token = peek();
|
||||
int next_pos = peek_position();
|
||||
IdentifierT name =
|
||||
@ -1949,7 +1950,7 @@ typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase<
|
||||
|
||||
if (fni_ != NULL) this->PushLiteralName(fni_, name);
|
||||
|
||||
if (!in_class && peek() == Token::COLON) {
|
||||
if (!in_class && !is_generator && peek() == Token::COLON) {
|
||||
// PropertyDefinition : PropertyName ':' AssignmentExpression
|
||||
checker->CheckProperty(name_token, kValueProperty,
|
||||
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
||||
@ -1957,7 +1958,8 @@ typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase<
|
||||
value = this->ParseAssignmentExpression(
|
||||
true, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
||||
|
||||
} else if (allow_harmony_object_literals_ && peek() == Token::LPAREN) {
|
||||
} else if (is_generator ||
|
||||
(allow_harmony_object_literals_ && peek() == Token::LPAREN)) {
|
||||
// Concise Method
|
||||
|
||||
if (is_static && this->IsPrototype(name)) {
|
||||
@ -1965,14 +1967,22 @@ typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase<
|
||||
*ok = false;
|
||||
return this->EmptyObjectLiteralProperty();
|
||||
}
|
||||
if (is_generator && in_class && !is_static && this->IsConstructor(name)) {
|
||||
ReportMessageAt(scanner()->location(), "constructor_special_method");
|
||||
*ok = false;
|
||||
return this->EmptyObjectLiteralProperty();
|
||||
}
|
||||
|
||||
checker->CheckProperty(name_token, kValueProperty,
|
||||
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
||||
FunctionKind kind = is_generator ? FunctionKind::kConciseGeneratorMethod
|
||||
: FunctionKind::kConciseMethod;
|
||||
|
||||
value = this->ParseFunctionLiteral(
|
||||
name, scanner()->location(),
|
||||
false, // reserved words are allowed here
|
||||
FunctionKind::kConciseMethod, RelocInfo::kNoPosition,
|
||||
FunctionLiteral::ANONYMOUS_EXPRESSION, FunctionLiteral::NORMAL_ARITY,
|
||||
kind, RelocInfo::kNoPosition, FunctionLiteral::ANONYMOUS_EXPRESSION,
|
||||
FunctionLiteral::NORMAL_ARITY,
|
||||
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
||||
|
||||
} else if (in_class && name_is_static && !is_static) {
|
||||
|
@ -1758,11 +1758,10 @@ function FunctionSourceString(func) {
|
||||
? 'anonymous'
|
||||
: %FunctionGetName(func);
|
||||
|
||||
// TODO(arv): Handle concise generator methods.
|
||||
|
||||
var isGenerator = %FunctionIsGenerator(func);
|
||||
var head = %FunctionIsConciseMethod(func)
|
||||
? ''
|
||||
: %FunctionIsGenerator(func) ? 'function* ' : 'function ';
|
||||
? (isGenerator ? '*' : '')
|
||||
: (isGenerator ? 'function* ' : 'function ');
|
||||
return head + name + source;
|
||||
}
|
||||
|
||||
|
@ -3411,6 +3411,8 @@ TEST(ErrorsSuper) {
|
||||
TEST(NoErrorsMethodDefinition) {
|
||||
const char* context_data[][2] = {{"({", "});"},
|
||||
{"'use strict'; ({", "});"},
|
||||
{"({*", "});"},
|
||||
{"'use strict'; ({*", "});"},
|
||||
{NULL, NULL}};
|
||||
|
||||
const char* object_literal_body_data[] = {
|
||||
@ -3431,6 +3433,8 @@ TEST(NoErrorsMethodDefinition) {
|
||||
TEST(MethodDefinitionNames) {
|
||||
const char* context_data[][2] = {{"({", "(x, y) {}});"},
|
||||
{"'use strict'; ({", "(x, y) {}});"},
|
||||
{"({*", "(x, y) {}});"},
|
||||
{"'use strict'; ({*", "(x, y) {}});"},
|
||||
{NULL, NULL}};
|
||||
|
||||
const char* name_data[] = {
|
||||
@ -3505,6 +3509,8 @@ TEST(MethodDefinitionNames) {
|
||||
TEST(MethodDefinitionStrictFormalParamereters) {
|
||||
const char* context_data[][2] = {{"({method(", "){}});"},
|
||||
{"'use strict'; ({method(", "){}});"},
|
||||
{"({*method(", "){}});"},
|
||||
{"'use strict'; ({*method(", "){}});"},
|
||||
{NULL, NULL}};
|
||||
|
||||
const char* params_data[] = {
|
||||
@ -3540,6 +3546,18 @@ TEST(MethodDefinitionDuplicateProperty) {
|
||||
"x() {}, 'x'() {}",
|
||||
"0() {}, '0'() {}",
|
||||
"1.0() {}, 1: 1",
|
||||
|
||||
"x: 1, *x() {}",
|
||||
"*x() {}, x: 1",
|
||||
"*x() {}, get x() {}",
|
||||
"*x() {}, set x(_) {}",
|
||||
"*x() {}, *x() {}",
|
||||
"*x() {}, y() {}, *x() {}",
|
||||
"*x() {}, *\"x\"() {}",
|
||||
"*x() {}, *'x'() {}",
|
||||
"*0() {}, *'0'() {}",
|
||||
"*1.0() {}, 1: 1",
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -3549,7 +3567,7 @@ TEST(MethodDefinitionDuplicateProperty) {
|
||||
}
|
||||
|
||||
|
||||
TEST(NoErrorsClassExpression) {
|
||||
TEST(ClassExpressionNoErrors) {
|
||||
const char* context_data[][2] = {{"(", ");"},
|
||||
{"var C = ", ";"},
|
||||
{"bar, ", ";"},
|
||||
@ -3573,7 +3591,7 @@ TEST(NoErrorsClassExpression) {
|
||||
}
|
||||
|
||||
|
||||
TEST(NoErrorsClassDeclaration) {
|
||||
TEST(ClassDeclarationNoErrors) {
|
||||
const char* context_data[][2] = {{"", ""},
|
||||
{"{", "}"},
|
||||
{"if (true) {", "}"},
|
||||
@ -3592,7 +3610,7 @@ TEST(NoErrorsClassDeclaration) {
|
||||
}
|
||||
|
||||
|
||||
TEST(NoErrorsClassBody) {
|
||||
TEST(ClassBodyNoErrors) {
|
||||
// Tests that parser and preparser accept valid class syntax.
|
||||
const char* context_data[][2] = {{"(class {", "});"},
|
||||
{"(class extends Base {", "});"},
|
||||
@ -3610,6 +3628,10 @@ TEST(NoErrorsClassBody) {
|
||||
"set x(v) {}",
|
||||
"get() {}",
|
||||
"set() {}",
|
||||
"*g() {}",
|
||||
"*g() {};",
|
||||
"; *g() {}",
|
||||
"*g() {}; *h(x) {}",
|
||||
"static() {}",
|
||||
"static m() {}",
|
||||
"static get x() {}",
|
||||
@ -3619,6 +3641,10 @@ TEST(NoErrorsClassBody) {
|
||||
"static static() {}",
|
||||
"static get static() {}",
|
||||
"static set static(v) {}",
|
||||
"*static() {}",
|
||||
"*get() {}",
|
||||
"*set() {}",
|
||||
"static *g() {}",
|
||||
NULL};
|
||||
|
||||
static const ParserFlag always_flags[] = {
|
||||
@ -3630,39 +3656,23 @@ TEST(NoErrorsClassBody) {
|
||||
}
|
||||
|
||||
|
||||
TEST(MethodDefinitionstrictFormalParamereters) {
|
||||
const char* context_data[][2] = {{"({method(", "){}});"},
|
||||
{NULL, NULL}};
|
||||
|
||||
const char* params_data[] = {
|
||||
"x, x",
|
||||
"x, y, x",
|
||||
"eval",
|
||||
"arguments",
|
||||
"var",
|
||||
"const",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
|
||||
RunParserSyncTest(context_data, params_data, kError, NULL, 0,
|
||||
always_flags, arraysize(always_flags));
|
||||
}
|
||||
|
||||
|
||||
TEST(NoErrorsClassPropertyName) {
|
||||
TEST(ClassPropertyNameNoErrors) {
|
||||
const char* context_data[][2] = {{"(class {", "() {}});"},
|
||||
{"(class { get ", "() {}});"},
|
||||
{"(class { set ", "(v) {}});"},
|
||||
{"(class { static ", "() {}});"},
|
||||
{"(class { static get ", "() {}});"},
|
||||
{"(class { static set ", "(v) {}});"},
|
||||
{"(class { *", "() {}});"},
|
||||
{"(class { static *", "() {}});"},
|
||||
{"class C {", "() {}}"},
|
||||
{"class C { get ", "() {}}"},
|
||||
{"class C { set ", "(v) {}}"},
|
||||
{"class C { static ", "() {}}"},
|
||||
{"class C { static get ", "() {}}"},
|
||||
{"class C { static set ", "(v) {}}"},
|
||||
{"class C { *", "() {}}"},
|
||||
{"class C { static *", "() {}}"},
|
||||
{NULL, NULL}};
|
||||
const char* name_data[] = {
|
||||
"42",
|
||||
@ -3704,7 +3714,7 @@ TEST(NoErrorsClassPropertyName) {
|
||||
}
|
||||
|
||||
|
||||
TEST(ErrorsClassExpression) {
|
||||
TEST(ClassExpressionErrors) {
|
||||
const char* context_data[][2] = {{"(", ");"},
|
||||
{"var C = ", ";"},
|
||||
{"bar, ", ";"},
|
||||
@ -3735,7 +3745,7 @@ TEST(ErrorsClassExpression) {
|
||||
}
|
||||
|
||||
|
||||
TEST(ErrorsClassDeclaration) {
|
||||
TEST(ClassDeclarationErrors) {
|
||||
const char* context_data[][2] = {{"", ""},
|
||||
{"{", "}"},
|
||||
{"if (true) {", "}"},
|
||||
@ -3750,11 +3760,17 @@ TEST(ErrorsClassDeclaration) {
|
||||
"class name { m; n }",
|
||||
"class name { m: 1 }",
|
||||
"class name { m(); n() }",
|
||||
"class name { get m }",
|
||||
"class name { get m() }",
|
||||
"class name { set m() {) }", // missing required param
|
||||
"class name { get x }",
|
||||
"class name { get x() }",
|
||||
"class name { set x() {) }", // missing required param
|
||||
"class {}", // Name is required for declaration
|
||||
"class extends base {}",
|
||||
"class name { *",
|
||||
"class name { * }",
|
||||
"class name { *; }",
|
||||
"class name { *get x() {} }",
|
||||
"class name { *set x(_) {} }",
|
||||
"class name { *static m() {} }",
|
||||
NULL};
|
||||
|
||||
static const ParserFlag always_flags[] = {
|
||||
@ -3766,7 +3782,7 @@ TEST(ErrorsClassDeclaration) {
|
||||
}
|
||||
|
||||
|
||||
TEST(ErrorsClassName) {
|
||||
TEST(ClassNameErrors) {
|
||||
const char* context_data[][2] = {{"class ", "{}"},
|
||||
{"(class ", "{});"},
|
||||
{"'use strict'; class ", "{}"},
|
||||
@ -3796,7 +3812,7 @@ TEST(ErrorsClassName) {
|
||||
}
|
||||
|
||||
|
||||
TEST(ErrorsClassGetterParamName) {
|
||||
TEST(ClassGetterParamNameErrors) {
|
||||
const char* context_data[][2] = {
|
||||
{"class C { get name(", ") {} }"},
|
||||
{"(class { get name(", ") {} });"},
|
||||
@ -3829,7 +3845,7 @@ TEST(ErrorsClassGetterParamName) {
|
||||
}
|
||||
|
||||
|
||||
TEST(ErrorsClassStaticPrototype) {
|
||||
TEST(ClassStaticPrototypeErrors) {
|
||||
const char* context_data[][2] = {{"class C {", "}"},
|
||||
{"(class {", "});"},
|
||||
{NULL, NULL}};
|
||||
@ -3838,6 +3854,7 @@ TEST(ErrorsClassStaticPrototype) {
|
||||
"static prototype() {}",
|
||||
"static get prototype() {}",
|
||||
"static set prototype(_) {}",
|
||||
"static *prototype() {}",
|
||||
NULL};
|
||||
|
||||
static const ParserFlag always_flags[] = {
|
||||
@ -3849,7 +3866,7 @@ TEST(ErrorsClassStaticPrototype) {
|
||||
}
|
||||
|
||||
|
||||
TEST(ErrorsClassSpecialConstructor) {
|
||||
TEST(ClassSpecialConstructorErrors) {
|
||||
const char* context_data[][2] = {{"class C {", "}"},
|
||||
{"(class {", "});"},
|
||||
{NULL, NULL}};
|
||||
@ -3857,6 +3874,7 @@ TEST(ErrorsClassSpecialConstructor) {
|
||||
const char* class_body_data[] = {
|
||||
"get constructor() {}",
|
||||
"get constructor(_) {}",
|
||||
"*constructor() {}",
|
||||
NULL};
|
||||
|
||||
static const ParserFlag always_flags[] = {
|
||||
@ -3868,7 +3886,7 @@ TEST(ErrorsClassSpecialConstructor) {
|
||||
}
|
||||
|
||||
|
||||
TEST(NoErrorsClassConstructor) {
|
||||
TEST(ClassConstructorNoErrors) {
|
||||
const char* context_data[][2] = {{"class C {", "}"},
|
||||
{"(class {", "});"},
|
||||
{NULL, NULL}};
|
||||
@ -3878,6 +3896,7 @@ TEST(NoErrorsClassConstructor) {
|
||||
"static constructor() {}",
|
||||
"static get constructor() {}",
|
||||
"static set constructor(_) {}",
|
||||
"static *constructor() {}",
|
||||
NULL};
|
||||
|
||||
static const ParserFlag always_flags[] = {
|
||||
@ -3889,7 +3908,7 @@ TEST(NoErrorsClassConstructor) {
|
||||
}
|
||||
|
||||
|
||||
TEST(ErrorsClassMultipleConstructor) {
|
||||
TEST(ClassMultipleConstructorErrors) {
|
||||
// We currently do not allow any duplicate properties in class bodies. This
|
||||
// test ensures that when we change that we still throw on duplicate
|
||||
// constructors.
|
||||
@ -3912,7 +3931,7 @@ TEST(ErrorsClassMultipleConstructor) {
|
||||
|
||||
// TODO(arv): We should allow duplicate property names.
|
||||
// https://code.google.com/p/v8/issues/detail?id=3570
|
||||
DISABLED_TEST(NoErrorsClassMultiplePropertyNames) {
|
||||
DISABLED_TEST(ClassMultiplePropertyNamesNoErrors) {
|
||||
const char* context_data[][2] = {{"class C {", "}"},
|
||||
{"(class {", "});"},
|
||||
{NULL, NULL}};
|
||||
@ -3932,7 +3951,7 @@ DISABLED_TEST(NoErrorsClassMultiplePropertyNames) {
|
||||
}
|
||||
|
||||
|
||||
TEST(ErrorsClassesAreStrict) {
|
||||
TEST(ClassesAreStrictErrors) {
|
||||
const char* context_data[][2] = {{"", ""},
|
||||
{"(", ");"},
|
||||
{NULL, NULL}};
|
||||
@ -3940,6 +3959,7 @@ TEST(ErrorsClassesAreStrict) {
|
||||
const char* class_body_data[] = {
|
||||
"class C { method() { with ({}) {} } }",
|
||||
"class C extends function() { with ({}) {} } {}",
|
||||
"class C { *method() { with ({}) {} } }",
|
||||
NULL};
|
||||
|
||||
static const ParserFlag always_flags[] = {
|
||||
|
@ -5,7 +5,7 @@
|
||||
// Flags: --harmony-object-literals --allow-natives-syntax
|
||||
|
||||
|
||||
(function TestDescriptor() {
|
||||
(function TestBasics() {
|
||||
var object = {
|
||||
method() {
|
||||
return 42;
|
||||
@ -15,6 +15,16 @@
|
||||
})();
|
||||
|
||||
|
||||
(function TestThis() {
|
||||
var object = {
|
||||
method() {
|
||||
assertEquals(object, this);
|
||||
}
|
||||
};
|
||||
object.method();
|
||||
})();
|
||||
|
||||
|
||||
(function TestDescriptor() {
|
||||
var object = {
|
||||
method() {
|
||||
@ -34,9 +44,7 @@
|
||||
|
||||
(function TestProto() {
|
||||
var object = {
|
||||
method() {
|
||||
return 42;
|
||||
}
|
||||
method() {}
|
||||
};
|
||||
|
||||
assertEquals(Function.prototype, Object.getPrototypeOf(object.method));
|
||||
@ -45,9 +53,7 @@
|
||||
|
||||
(function TestNotConstructable() {
|
||||
var object = {
|
||||
method() {
|
||||
return 42;
|
||||
}
|
||||
method() {}
|
||||
};
|
||||
|
||||
assertThrows(function() {
|
||||
@ -58,9 +64,7 @@
|
||||
|
||||
(function TestFunctionName() {
|
||||
var object = {
|
||||
method() {
|
||||
return 42;
|
||||
},
|
||||
method() {},
|
||||
1() {},
|
||||
2.0() {}
|
||||
};
|
||||
@ -68,7 +72,6 @@
|
||||
assertEquals('method', f.name);
|
||||
var g = object[1];
|
||||
assertEquals('1', g.name);
|
||||
|
||||
var h = object[2];
|
||||
assertEquals('2', h.name);
|
||||
})();
|
||||
@ -90,9 +93,7 @@
|
||||
|
||||
(function TestNoPrototype() {
|
||||
var object = {
|
||||
method() {
|
||||
return 42;
|
||||
}
|
||||
method() {}
|
||||
};
|
||||
var f = object.method;
|
||||
assertFalse(f.hasOwnProperty('prototype'));
|
||||
@ -121,3 +122,127 @@
|
||||
assertEquals(42, object.method());
|
||||
assertFalse(object.method.hasOwnProperty('prototype'));
|
||||
})();
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
var GeneratorFunction = function*() {}.__proto__.constructor;
|
||||
|
||||
|
||||
function assertIteratorResult(value, done, result) {
|
||||
assertEquals({value: value, done: done}, result);
|
||||
}
|
||||
|
||||
|
||||
(function TestGeneratorBasics() {
|
||||
var object = {
|
||||
*method() {
|
||||
yield 1;
|
||||
}
|
||||
};
|
||||
var g = object.method();
|
||||
assertIteratorResult(1, false, g.next());
|
||||
assertIteratorResult(undefined, true, g.next());
|
||||
})();
|
||||
|
||||
|
||||
(function TestGeneratorThis() {
|
||||
var object = {
|
||||
*method() {
|
||||
yield this;
|
||||
}
|
||||
};
|
||||
var g = object.method();
|
||||
assertIteratorResult(object, false, g.next());
|
||||
assertIteratorResult(undefined, true, g.next());
|
||||
})();
|
||||
|
||||
|
||||
(function TestGeneratorSymbolIterator() {
|
||||
var object = {
|
||||
*method() {}
|
||||
};
|
||||
var g = object.method();
|
||||
assertEquals(g, g[Symbol.iterator]());
|
||||
})();
|
||||
|
||||
|
||||
(function TestGeneratorDescriptor() {
|
||||
var object = {
|
||||
*method() {
|
||||
yield 1;
|
||||
}
|
||||
};
|
||||
|
||||
var desc = Object.getOwnPropertyDescriptor(object, 'method');
|
||||
assertTrue(desc.enumerable);
|
||||
assertTrue(desc.configurable);
|
||||
assertTrue(desc.writable);
|
||||
assertEquals('function', typeof desc.value);
|
||||
|
||||
var g = desc.value();
|
||||
assertIteratorResult(1, false, g.next());
|
||||
assertIteratorResult(undefined, true, g.next());
|
||||
})();
|
||||
|
||||
|
||||
(function TestGeneratorProto() {
|
||||
var object = {
|
||||
*method() {}
|
||||
};
|
||||
|
||||
assertEquals(GeneratorFunction.prototype,
|
||||
Object.getPrototypeOf(object.method));
|
||||
})();
|
||||
|
||||
|
||||
(function TestGeneratorConstructable() {
|
||||
var object = {
|
||||
*method() {
|
||||
yield 1;
|
||||
}
|
||||
};
|
||||
|
||||
var g = new object.method();
|
||||
assertIteratorResult(1, false, g.next());
|
||||
assertIteratorResult(undefined, true, g.next());
|
||||
})();
|
||||
|
||||
|
||||
(function TestGeneratorName() {
|
||||
var object = {
|
||||
*method() {},
|
||||
*1() {},
|
||||
*2.0() {}
|
||||
};
|
||||
var f = object.method;
|
||||
assertEquals('method', f.name);
|
||||
var g = object[1];
|
||||
assertEquals('1', g.name);
|
||||
var h = object[2];
|
||||
assertEquals('2', h.name);
|
||||
})();
|
||||
|
||||
|
||||
(function TestGeneratorNoBinding() {
|
||||
var method = 'local';
|
||||
var calls = 0;
|
||||
var object = {
|
||||
*method() {
|
||||
calls++;
|
||||
assertEquals('local', method);
|
||||
}
|
||||
};
|
||||
var g = object.method();
|
||||
assertIteratorResult(undefined, true, g.next());
|
||||
assertEquals(1, calls);
|
||||
})();
|
||||
|
||||
|
||||
(function TestGeneratorToString() {
|
||||
var object = {
|
||||
*method() { yield 1; }
|
||||
};
|
||||
assertEquals('*method() { yield 1; }', object.method.toString());
|
||||
})();
|
||||
|
Loading…
Reference in New Issue
Block a user