Commit 714f5f40 authored by arv@chromium.org's avatar arv@chromium.org

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
parent a479b2cb
...@@ -761,17 +761,17 @@ enum FunctionKind { ...@@ -761,17 +761,17 @@ enum FunctionKind {
kNormalFunction = 0, kNormalFunction = 0,
kArrowFunction = 1, kArrowFunction = 1,
kGeneratorFunction = 2, kGeneratorFunction = 2,
kConciseMethod = 4 kConciseMethod = 4,
kConciseGeneratorMethod = kGeneratorFunction | kConciseMethod
}; };
inline bool IsValidFunctionKind(FunctionKind kind) { 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 || return kind == FunctionKind::kNormalFunction ||
kind == FunctionKind::kArrowFunction || kind == FunctionKind::kArrowFunction ||
kind == FunctionKind::kGeneratorFunction || kind == FunctionKind::kGeneratorFunction ||
kind == FunctionKind::kConciseMethod; kind == FunctionKind::kConciseMethod ||
kind == FunctionKind::kConciseGeneratorMethod;
} }
......
...@@ -1936,11 +1936,12 @@ template <class Traits> ...@@ -1936,11 +1936,12 @@ template <class Traits>
typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase< typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase<
Traits>::ParsePropertyDefinition(ObjectLiteralChecker* checker, Traits>::ParsePropertyDefinition(ObjectLiteralChecker* checker,
bool in_class, bool is_static, bool* ok) { bool in_class, bool is_static, bool* ok) {
// TODO(arv): Add support for concise generator methods.
ExpressionT value = this->EmptyExpression(); ExpressionT value = this->EmptyExpression();
bool is_get = false; bool is_get = false;
bool is_set = false; bool is_set = false;
bool name_is_static = false; bool name_is_static = false;
bool is_generator = allow_harmony_object_literals_ && Check(Token::MUL);
Token::Value name_token = peek(); Token::Value name_token = peek();
int next_pos = peek_position(); int next_pos = peek_position();
IdentifierT name = IdentifierT name =
...@@ -1949,7 +1950,7 @@ typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase< ...@@ -1949,7 +1950,7 @@ typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase<
if (fni_ != NULL) this->PushLiteralName(fni_, name); if (fni_ != NULL) this->PushLiteralName(fni_, name);
if (!in_class && peek() == Token::COLON) { if (!in_class && !is_generator && peek() == Token::COLON) {
// PropertyDefinition : PropertyName ':' AssignmentExpression // PropertyDefinition : PropertyName ':' AssignmentExpression
checker->CheckProperty(name_token, kValueProperty, checker->CheckProperty(name_token, kValueProperty,
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
...@@ -1957,7 +1958,8 @@ typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase< ...@@ -1957,7 +1958,8 @@ typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase<
value = this->ParseAssignmentExpression( value = this->ParseAssignmentExpression(
true, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); 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 // Concise Method
if (is_static && this->IsPrototype(name)) { if (is_static && this->IsPrototype(name)) {
...@@ -1965,14 +1967,22 @@ typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase< ...@@ -1965,14 +1967,22 @@ typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase<
*ok = false; *ok = false;
return this->EmptyObjectLiteralProperty(); 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, checker->CheckProperty(name_token, kValueProperty,
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
FunctionKind kind = is_generator ? FunctionKind::kConciseGeneratorMethod
: FunctionKind::kConciseMethod;
value = this->ParseFunctionLiteral( value = this->ParseFunctionLiteral(
name, scanner()->location(), name, scanner()->location(),
false, // reserved words are allowed here false, // reserved words are allowed here
FunctionKind::kConciseMethod, RelocInfo::kNoPosition, kind, RelocInfo::kNoPosition, FunctionLiteral::ANONYMOUS_EXPRESSION,
FunctionLiteral::ANONYMOUS_EXPRESSION, FunctionLiteral::NORMAL_ARITY, FunctionLiteral::NORMAL_ARITY,
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
} else if (in_class && name_is_static && !is_static) { } else if (in_class && name_is_static && !is_static) {
......
...@@ -1758,11 +1758,10 @@ function FunctionSourceString(func) { ...@@ -1758,11 +1758,10 @@ function FunctionSourceString(func) {
? 'anonymous' ? 'anonymous'
: %FunctionGetName(func); : %FunctionGetName(func);
// TODO(arv): Handle concise generator methods. var isGenerator = %FunctionIsGenerator(func);
var head = %FunctionIsConciseMethod(func) var head = %FunctionIsConciseMethod(func)
? '' ? (isGenerator ? '*' : '')
: %FunctionIsGenerator(func) ? 'function* ' : 'function '; : (isGenerator ? 'function* ' : 'function ');
return head + name + source; return head + name + source;
} }
......
...@@ -3411,6 +3411,8 @@ TEST(ErrorsSuper) { ...@@ -3411,6 +3411,8 @@ TEST(ErrorsSuper) {
TEST(NoErrorsMethodDefinition) { TEST(NoErrorsMethodDefinition) {
const char* context_data[][2] = {{"({", "});"}, const char* context_data[][2] = {{"({", "});"},
{"'use strict'; ({", "});"}, {"'use strict'; ({", "});"},
{"({*", "});"},
{"'use strict'; ({*", "});"},
{NULL, NULL}}; {NULL, NULL}};
const char* object_literal_body_data[] = { const char* object_literal_body_data[] = {
...@@ -3431,6 +3433,8 @@ TEST(NoErrorsMethodDefinition) { ...@@ -3431,6 +3433,8 @@ TEST(NoErrorsMethodDefinition) {
TEST(MethodDefinitionNames) { TEST(MethodDefinitionNames) {
const char* context_data[][2] = {{"({", "(x, y) {}});"}, const char* context_data[][2] = {{"({", "(x, y) {}});"},
{"'use strict'; ({", "(x, y) {}});"}, {"'use strict'; ({", "(x, y) {}});"},
{"({*", "(x, y) {}});"},
{"'use strict'; ({*", "(x, y) {}});"},
{NULL, NULL}}; {NULL, NULL}};
const char* name_data[] = { const char* name_data[] = {
...@@ -3505,6 +3509,8 @@ TEST(MethodDefinitionNames) { ...@@ -3505,6 +3509,8 @@ TEST(MethodDefinitionNames) {
TEST(MethodDefinitionStrictFormalParamereters) { TEST(MethodDefinitionStrictFormalParamereters) {
const char* context_data[][2] = {{"({method(", "){}});"}, const char* context_data[][2] = {{"({method(", "){}});"},
{"'use strict'; ({method(", "){}});"}, {"'use strict'; ({method(", "){}});"},
{"({*method(", "){}});"},
{"'use strict'; ({*method(", "){}});"},
{NULL, NULL}}; {NULL, NULL}};
const char* params_data[] = { const char* params_data[] = {
...@@ -3540,6 +3546,18 @@ TEST(MethodDefinitionDuplicateProperty) { ...@@ -3540,6 +3546,18 @@ TEST(MethodDefinitionDuplicateProperty) {
"x() {}, 'x'() {}", "x() {}, 'x'() {}",
"0() {}, '0'() {}", "0() {}, '0'() {}",
"1.0() {}, 1: 1", "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 NULL
}; };
...@@ -3549,7 +3567,7 @@ TEST(MethodDefinitionDuplicateProperty) { ...@@ -3549,7 +3567,7 @@ TEST(MethodDefinitionDuplicateProperty) {
} }
TEST(NoErrorsClassExpression) { TEST(ClassExpressionNoErrors) {
const char* context_data[][2] = {{"(", ");"}, const char* context_data[][2] = {{"(", ");"},
{"var C = ", ";"}, {"var C = ", ";"},
{"bar, ", ";"}, {"bar, ", ";"},
...@@ -3573,7 +3591,7 @@ TEST(NoErrorsClassExpression) { ...@@ -3573,7 +3591,7 @@ TEST(NoErrorsClassExpression) {
} }
TEST(NoErrorsClassDeclaration) { TEST(ClassDeclarationNoErrors) {
const char* context_data[][2] = {{"", ""}, const char* context_data[][2] = {{"", ""},
{"{", "}"}, {"{", "}"},
{"if (true) {", "}"}, {"if (true) {", "}"},
...@@ -3592,7 +3610,7 @@ TEST(NoErrorsClassDeclaration) { ...@@ -3592,7 +3610,7 @@ TEST(NoErrorsClassDeclaration) {
} }
TEST(NoErrorsClassBody) { TEST(ClassBodyNoErrors) {
// Tests that parser and preparser accept valid class syntax. // Tests that parser and preparser accept valid class syntax.
const char* context_data[][2] = {{"(class {", "});"}, const char* context_data[][2] = {{"(class {", "});"},
{"(class extends Base {", "});"}, {"(class extends Base {", "});"},
...@@ -3604,12 +3622,16 @@ TEST(NoErrorsClassBody) { ...@@ -3604,12 +3622,16 @@ TEST(NoErrorsClassBody) {
";;", ";;",
"m() {}", "m() {}",
"m() {};", "m() {};",
";m() {}", "; m() {}",
"m() {}; n(x) {}", "m() {}; n(x) {}",
"get x() {}", "get x() {}",
"set x(v) {}", "set x(v) {}",
"get() {}", "get() {}",
"set() {}", "set() {}",
"*g() {}",
"*g() {};",
"; *g() {}",
"*g() {}; *h(x) {}",
"static() {}", "static() {}",
"static m() {}", "static m() {}",
"static get x() {}", "static get x() {}",
...@@ -3619,6 +3641,10 @@ TEST(NoErrorsClassBody) { ...@@ -3619,6 +3641,10 @@ TEST(NoErrorsClassBody) {
"static static() {}", "static static() {}",
"static get static() {}", "static get static() {}",
"static set static(v) {}", "static set static(v) {}",
"*static() {}",
"*get() {}",
"*set() {}",
"static *g() {}",
NULL}; NULL};
static const ParserFlag always_flags[] = { static const ParserFlag always_flags[] = {
...@@ -3630,39 +3656,23 @@ TEST(NoErrorsClassBody) { ...@@ -3630,39 +3656,23 @@ TEST(NoErrorsClassBody) {
} }
TEST(MethodDefinitionstrictFormalParamereters) { TEST(ClassPropertyNameNoErrors) {
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) {
const char* context_data[][2] = {{"(class {", "() {}});"}, const char* context_data[][2] = {{"(class {", "() {}});"},
{"(class { get ", "() {}});"}, {"(class { get ", "() {}});"},
{"(class { set ", "(v) {}});"}, {"(class { set ", "(v) {}});"},
{"(class { static ", "() {}});"}, {"(class { static ", "() {}});"},
{"(class { static get ", "() {}});"}, {"(class { static get ", "() {}});"},
{"(class { static set ", "(v) {}});"}, {"(class { static set ", "(v) {}});"},
{"(class { *", "() {}});"},
{"(class { static *", "() {}});"},
{"class C {", "() {}}"}, {"class C {", "() {}}"},
{"class C { get ", "() {}}"}, {"class C { get ", "() {}}"},
{"class C { set ", "(v) {}}"}, {"class C { set ", "(v) {}}"},
{"class C { static ", "() {}}"}, {"class C { static ", "() {}}"},
{"class C { static get ", "() {}}"}, {"class C { static get ", "() {}}"},
{"class C { static set ", "(v) {}}"}, {"class C { static set ", "(v) {}}"},
{"class C { *", "() {}}"},
{"class C { static *", "() {}}"},
{NULL, NULL}}; {NULL, NULL}};
const char* name_data[] = { const char* name_data[] = {
"42", "42",
...@@ -3704,7 +3714,7 @@ TEST(NoErrorsClassPropertyName) { ...@@ -3704,7 +3714,7 @@ TEST(NoErrorsClassPropertyName) {
} }
TEST(ErrorsClassExpression) { TEST(ClassExpressionErrors) {
const char* context_data[][2] = {{"(", ");"}, const char* context_data[][2] = {{"(", ");"},
{"var C = ", ";"}, {"var C = ", ";"},
{"bar, ", ";"}, {"bar, ", ";"},
...@@ -3735,7 +3745,7 @@ TEST(ErrorsClassExpression) { ...@@ -3735,7 +3745,7 @@ TEST(ErrorsClassExpression) {
} }
TEST(ErrorsClassDeclaration) { TEST(ClassDeclarationErrors) {
const char* context_data[][2] = {{"", ""}, const char* context_data[][2] = {{"", ""},
{"{", "}"}, {"{", "}"},
{"if (true) {", "}"}, {"if (true) {", "}"},
...@@ -3750,11 +3760,17 @@ TEST(ErrorsClassDeclaration) { ...@@ -3750,11 +3760,17 @@ TEST(ErrorsClassDeclaration) {
"class name { m; n }", "class name { m; n }",
"class name { m: 1 }", "class name { m: 1 }",
"class name { m(); n() }", "class name { m(); n() }",
"class name { get m }", "class name { get x }",
"class name { get m() }", "class name { get x() }",
"class name { set m() {) }", // missing required param "class name { set x() {) }", // missing required param
"class {}", // Name is required for declaration "class {}", // Name is required for declaration
"class extends base {}", "class extends base {}",
"class name { *",
"class name { * }",
"class name { *; }",
"class name { *get x() {} }",
"class name { *set x(_) {} }",
"class name { *static m() {} }",
NULL}; NULL};
static const ParserFlag always_flags[] = { static const ParserFlag always_flags[] = {
...@@ -3766,7 +3782,7 @@ TEST(ErrorsClassDeclaration) { ...@@ -3766,7 +3782,7 @@ TEST(ErrorsClassDeclaration) {
} }
TEST(ErrorsClassName) { TEST(ClassNameErrors) {
const char* context_data[][2] = {{"class ", "{}"}, const char* context_data[][2] = {{"class ", "{}"},
{"(class ", "{});"}, {"(class ", "{});"},
{"'use strict'; class ", "{}"}, {"'use strict'; class ", "{}"},
...@@ -3796,7 +3812,7 @@ TEST(ErrorsClassName) { ...@@ -3796,7 +3812,7 @@ TEST(ErrorsClassName) {
} }
TEST(ErrorsClassGetterParamName) { TEST(ClassGetterParamNameErrors) {
const char* context_data[][2] = { const char* context_data[][2] = {
{"class C { get name(", ") {} }"}, {"class C { get name(", ") {} }"},
{"(class { get name(", ") {} });"}, {"(class { get name(", ") {} });"},
...@@ -3829,7 +3845,7 @@ TEST(ErrorsClassGetterParamName) { ...@@ -3829,7 +3845,7 @@ TEST(ErrorsClassGetterParamName) {
} }
TEST(ErrorsClassStaticPrototype) { TEST(ClassStaticPrototypeErrors) {
const char* context_data[][2] = {{"class C {", "}"}, const char* context_data[][2] = {{"class C {", "}"},
{"(class {", "});"}, {"(class {", "});"},
{NULL, NULL}}; {NULL, NULL}};
...@@ -3838,6 +3854,7 @@ TEST(ErrorsClassStaticPrototype) { ...@@ -3838,6 +3854,7 @@ TEST(ErrorsClassStaticPrototype) {
"static prototype() {}", "static prototype() {}",
"static get prototype() {}", "static get prototype() {}",
"static set prototype(_) {}", "static set prototype(_) {}",
"static *prototype() {}",
NULL}; NULL};
static const ParserFlag always_flags[] = { static const ParserFlag always_flags[] = {
...@@ -3849,7 +3866,7 @@ TEST(ErrorsClassStaticPrototype) { ...@@ -3849,7 +3866,7 @@ TEST(ErrorsClassStaticPrototype) {
} }
TEST(ErrorsClassSpecialConstructor) { TEST(ClassSpecialConstructorErrors) {
const char* context_data[][2] = {{"class C {", "}"}, const char* context_data[][2] = {{"class C {", "}"},
{"(class {", "});"}, {"(class {", "});"},
{NULL, NULL}}; {NULL, NULL}};
...@@ -3857,6 +3874,7 @@ TEST(ErrorsClassSpecialConstructor) { ...@@ -3857,6 +3874,7 @@ TEST(ErrorsClassSpecialConstructor) {
const char* class_body_data[] = { const char* class_body_data[] = {
"get constructor() {}", "get constructor() {}",
"get constructor(_) {}", "get constructor(_) {}",
"*constructor() {}",
NULL}; NULL};
static const ParserFlag always_flags[] = { static const ParserFlag always_flags[] = {
...@@ -3868,7 +3886,7 @@ TEST(ErrorsClassSpecialConstructor) { ...@@ -3868,7 +3886,7 @@ TEST(ErrorsClassSpecialConstructor) {
} }
TEST(NoErrorsClassConstructor) { TEST(ClassConstructorNoErrors) {
const char* context_data[][2] = {{"class C {", "}"}, const char* context_data[][2] = {{"class C {", "}"},
{"(class {", "});"}, {"(class {", "});"},
{NULL, NULL}}; {NULL, NULL}};
...@@ -3878,6 +3896,7 @@ TEST(NoErrorsClassConstructor) { ...@@ -3878,6 +3896,7 @@ TEST(NoErrorsClassConstructor) {
"static constructor() {}", "static constructor() {}",
"static get constructor() {}", "static get constructor() {}",
"static set constructor(_) {}", "static set constructor(_) {}",
"static *constructor() {}",
NULL}; NULL};
static const ParserFlag always_flags[] = { static const ParserFlag always_flags[] = {
...@@ -3889,7 +3908,7 @@ TEST(NoErrorsClassConstructor) { ...@@ -3889,7 +3908,7 @@ TEST(NoErrorsClassConstructor) {
} }
TEST(ErrorsClassMultipleConstructor) { TEST(ClassMultipleConstructorErrors) {
// We currently do not allow any duplicate properties in class bodies. This // We currently do not allow any duplicate properties in class bodies. This
// test ensures that when we change that we still throw on duplicate // test ensures that when we change that we still throw on duplicate
// constructors. // constructors.
...@@ -3912,7 +3931,7 @@ TEST(ErrorsClassMultipleConstructor) { ...@@ -3912,7 +3931,7 @@ TEST(ErrorsClassMultipleConstructor) {
// TODO(arv): We should allow duplicate property names. // TODO(arv): We should allow duplicate property names.
// https://code.google.com/p/v8/issues/detail?id=3570 // https://code.google.com/p/v8/issues/detail?id=3570
DISABLED_TEST(NoErrorsClassMultiplePropertyNames) { DISABLED_TEST(ClassMultiplePropertyNamesNoErrors) {
const char* context_data[][2] = {{"class C {", "}"}, const char* context_data[][2] = {{"class C {", "}"},
{"(class {", "});"}, {"(class {", "});"},
{NULL, NULL}}; {NULL, NULL}};
...@@ -3932,7 +3951,7 @@ DISABLED_TEST(NoErrorsClassMultiplePropertyNames) { ...@@ -3932,7 +3951,7 @@ DISABLED_TEST(NoErrorsClassMultiplePropertyNames) {
} }
TEST(ErrorsClassesAreStrict) { TEST(ClassesAreStrictErrors) {
const char* context_data[][2] = {{"", ""}, const char* context_data[][2] = {{"", ""},
{"(", ");"}, {"(", ");"},
{NULL, NULL}}; {NULL, NULL}};
...@@ -3940,6 +3959,7 @@ TEST(ErrorsClassesAreStrict) { ...@@ -3940,6 +3959,7 @@ TEST(ErrorsClassesAreStrict) {
const char* class_body_data[] = { const char* class_body_data[] = {
"class C { method() { with ({}) {} } }", "class C { method() { with ({}) {} } }",
"class C extends function() { with ({}) {} } {}", "class C extends function() { with ({}) {} } {}",
"class C { *method() { with ({}) {} } }",
NULL}; NULL};
static const ParserFlag always_flags[] = { static const ParserFlag always_flags[] = {
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
// Flags: --harmony-object-literals --allow-natives-syntax // Flags: --harmony-object-literals --allow-natives-syntax
(function TestDescriptor() { (function TestBasics() {
var object = { var object = {
method() { method() {
return 42; return 42;
...@@ -15,6 +15,16 @@ ...@@ -15,6 +15,16 @@
})(); })();
(function TestThis() {
var object = {
method() {
assertEquals(object, this);
}
};
object.method();
})();
(function TestDescriptor() { (function TestDescriptor() {
var object = { var object = {
method() { method() {
...@@ -34,9 +44,7 @@ ...@@ -34,9 +44,7 @@
(function TestProto() { (function TestProto() {
var object = { var object = {
method() { method() {}
return 42;
}
}; };
assertEquals(Function.prototype, Object.getPrototypeOf(object.method)); assertEquals(Function.prototype, Object.getPrototypeOf(object.method));
...@@ -45,9 +53,7 @@ ...@@ -45,9 +53,7 @@
(function TestNotConstructable() { (function TestNotConstructable() {
var object = { var object = {
method() { method() {}
return 42;
}
}; };
assertThrows(function() { assertThrows(function() {
...@@ -58,9 +64,7 @@ ...@@ -58,9 +64,7 @@
(function TestFunctionName() { (function TestFunctionName() {
var object = { var object = {
method() { method() {},
return 42;
},
1() {}, 1() {},
2.0() {} 2.0() {}
}; };
...@@ -68,7 +72,6 @@ ...@@ -68,7 +72,6 @@
assertEquals('method', f.name); assertEquals('method', f.name);
var g = object[1]; var g = object[1];
assertEquals('1', g.name); assertEquals('1', g.name);
var h = object[2]; var h = object[2];
assertEquals('2', h.name); assertEquals('2', h.name);
})(); })();
...@@ -90,9 +93,7 @@ ...@@ -90,9 +93,7 @@
(function TestNoPrototype() { (function TestNoPrototype() {
var object = { var object = {
method() { method() {}
return 42;
}
}; };
var f = object.method; var f = object.method;
assertFalse(f.hasOwnProperty('prototype')); assertFalse(f.hasOwnProperty('prototype'));
...@@ -121,3 +122,127 @@ ...@@ -121,3 +122,127 @@
assertEquals(42, object.method()); assertEquals(42, object.method());
assertFalse(object.method.hasOwnProperty('prototype')); 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());
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment