Commit 7efd2eb1 authored by arv@chromium.org's avatar arv@chromium.org

Class syntax parsing

This implements parsing for ClassExpression and ClassDeclaration.
The runtime is not yet implemented and the value is currently
hard coded to undefined.

BUG=v8:3330
LOG=Y
R=dslomov@chromium.org, marja@chromium.org, rossberg@chromium.org

Review URL: https://codereview.chromium.org/561913002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23988 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 7062b8fb
...@@ -235,32 +235,33 @@ class AstValue : public ZoneObject { ...@@ -235,32 +235,33 @@ class AstValue : public ZoneObject {
// For generating string constants. // For generating string constants.
#define STRING_CONSTANTS(F) \ #define STRING_CONSTANTS(F) \
F(anonymous_function, "(anonymous function)") \ F(anonymous_function, "(anonymous function)") \
F(arguments, "arguments") \ F(arguments, "arguments") \
F(done, "done") \ F(constructor, "constructor") \
F(dot, ".") \ F(done, "done") \
F(dot_for, ".for") \ F(dot, ".") \
F(dot_generator, ".generator") \ F(dot_for, ".for") \
F(dot_generator_object, ".generator_object") \ F(dot_generator, ".generator") \
F(dot_iterator, ".iterator") \ F(dot_generator_object, ".generator_object") \
F(dot_module, ".module") \ F(dot_iterator, ".iterator") \
F(dot_result, ".result") \ F(dot_module, ".module") \
F(empty, "") \ F(dot_result, ".result") \
F(eval, "eval") \ F(empty, "") \
F(eval, "eval") \
F(initialize_const_global, "initializeConstGlobal") \ F(initialize_const_global, "initializeConstGlobal") \
F(initialize_var_global, "initializeVarGlobal") \ F(initialize_var_global, "initializeVarGlobal") \
F(make_reference_error, "MakeReferenceError") \ F(make_reference_error, "MakeReferenceError") \
F(make_syntax_error, "MakeSyntaxError") \ F(make_syntax_error, "MakeSyntaxError") \
F(make_type_error, "MakeTypeError") \ F(make_type_error, "MakeTypeError") \
F(module, "module") \ F(module, "module") \
F(native, "native") \ F(native, "native") \
F(next, "next") \ F(next, "next") \
F(proto, "__proto__") \ F(proto, "__proto__") \
F(prototype, "prototype") \ F(prototype, "prototype") \
F(this, "this") \ F(this, "this") \
F(use_asm, "use asm") \ F(use_asm, "use asm") \
F(use_strict, "use strict") \ F(use_strict, "use strict") \
F(value, "value") F(value, "value")
......
...@@ -173,10 +173,12 @@ void FunctionLiteral::InitializeSharedInfo( ...@@ -173,10 +173,12 @@ void FunctionLiteral::InitializeSharedInfo(
ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone, ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone,
AstValueFactory* ast_value_factory, AstValueFactory* ast_value_factory,
Literal* key, Expression* value) { Literal* key, Expression* value,
bool is_static) {
emit_store_ = true; emit_store_ = true;
key_ = key; key_ = key;
value_ = value; value_ = value;
is_static_ = is_static;
if (key->raw_value()->EqualsString(ast_value_factory->proto_string())) { if (key->raw_value()->EqualsString(ast_value_factory->proto_string())) {
kind_ = PROTOTYPE; kind_ = PROTOTYPE;
} else if (value_->AsMaterializedLiteral() != NULL) { } else if (value_->AsMaterializedLiteral() != NULL) {
...@@ -189,11 +191,13 @@ ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone, ...@@ -189,11 +191,13 @@ ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone,
} }
ObjectLiteralProperty::ObjectLiteralProperty( ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone, bool is_getter,
Zone* zone, bool is_getter, FunctionLiteral* value) { FunctionLiteral* value,
bool is_static) {
emit_store_ = true; emit_store_ = true;
value_ = value; value_ = value;
kind_ = is_getter ? GETTER : SETTER; kind_ = is_getter ? GETTER : SETTER;
is_static_ = is_static;
} }
...@@ -1090,6 +1094,7 @@ DONT_OPTIMIZE_NODE(ModuleUrl) ...@@ -1090,6 +1094,7 @@ DONT_OPTIMIZE_NODE(ModuleUrl)
DONT_OPTIMIZE_NODE(ModuleStatement) DONT_OPTIMIZE_NODE(ModuleStatement)
DONT_OPTIMIZE_NODE(WithStatement) DONT_OPTIMIZE_NODE(WithStatement)
DONT_OPTIMIZE_NODE(DebuggerStatement) DONT_OPTIMIZE_NODE(DebuggerStatement)
DONT_OPTIMIZE_NODE(ClassLiteral)
DONT_OPTIMIZE_NODE(NativeFunctionLiteral) DONT_OPTIMIZE_NODE(NativeFunctionLiteral)
DONT_OPTIMIZE_NODE(SuperReference) DONT_OPTIMIZE_NODE(SuperReference)
......
...@@ -40,12 +40,12 @@ namespace internal { ...@@ -40,12 +40,12 @@ namespace internal {
// Nodes of the abstract syntax tree. Only concrete classes are // Nodes of the abstract syntax tree. Only concrete classes are
// enumerated here. // enumerated here.
#define DECLARATION_NODE_LIST(V) \ #define DECLARATION_NODE_LIST(V) \
V(VariableDeclaration) \ V(VariableDeclaration) \
V(FunctionDeclaration) \ V(FunctionDeclaration) \
V(ModuleDeclaration) \ V(ModuleDeclaration) \
V(ImportDeclaration) \ V(ImportDeclaration) \
V(ExportDeclaration) \ V(ExportDeclaration)
#define MODULE_NODE_LIST(V) \ #define MODULE_NODE_LIST(V) \
V(ModuleLiteral) \ V(ModuleLiteral) \
...@@ -73,28 +73,29 @@ namespace internal { ...@@ -73,28 +73,29 @@ namespace internal {
V(TryFinallyStatement) \ V(TryFinallyStatement) \
V(DebuggerStatement) V(DebuggerStatement)
#define EXPRESSION_NODE_LIST(V) \ #define EXPRESSION_NODE_LIST(V) \
V(FunctionLiteral) \ V(FunctionLiteral) \
V(NativeFunctionLiteral) \ V(ClassLiteral) \
V(Conditional) \ V(NativeFunctionLiteral) \
V(VariableProxy) \ V(Conditional) \
V(Literal) \ V(VariableProxy) \
V(RegExpLiteral) \ V(Literal) \
V(ObjectLiteral) \ V(RegExpLiteral) \
V(ArrayLiteral) \ V(ObjectLiteral) \
V(Assignment) \ V(ArrayLiteral) \
V(Yield) \ V(Assignment) \
V(Throw) \ V(Yield) \
V(Property) \ V(Throw) \
V(Call) \ V(Property) \
V(CallNew) \ V(Call) \
V(CallRuntime) \ V(CallNew) \
V(UnaryOperation) \ V(CallRuntime) \
V(CountOperation) \ V(UnaryOperation) \
V(BinaryOperation) \ V(CountOperation) \
V(CompareOperation) \ V(BinaryOperation) \
V(ThisFunction) \ V(CompareOperation) \
V(SuperReference) \ V(ThisFunction) \
V(SuperReference) \
V(CaseClause) V(CaseClause)
#define AST_NODE_LIST(V) \ #define AST_NODE_LIST(V) \
...@@ -1459,7 +1460,7 @@ class ObjectLiteralProperty FINAL : public ZoneObject { ...@@ -1459,7 +1460,7 @@ class ObjectLiteralProperty FINAL : public ZoneObject {
}; };
ObjectLiteralProperty(Zone* zone, AstValueFactory* ast_value_factory, ObjectLiteralProperty(Zone* zone, AstValueFactory* ast_value_factory,
Literal* key, Expression* value); Literal* key, Expression* value, bool is_static);
Literal* key() { return key_; } Literal* key() { return key_; }
Expression* value() { return value_; } Expression* value() { return value_; }
...@@ -1478,7 +1479,8 @@ class ObjectLiteralProperty FINAL : public ZoneObject { ...@@ -1478,7 +1479,8 @@ class ObjectLiteralProperty FINAL : public ZoneObject {
protected: protected:
template<class> friend class AstNodeFactory; template<class> friend class AstNodeFactory;
ObjectLiteralProperty(Zone* zone, bool is_getter, FunctionLiteral* value); ObjectLiteralProperty(Zone* zone, bool is_getter, FunctionLiteral* value,
bool is_static);
void set_key(Literal* key) { key_ = key; } void set_key(Literal* key) { key_ = key; }
private: private:
...@@ -1486,6 +1488,7 @@ class ObjectLiteralProperty FINAL : public ZoneObject { ...@@ -1486,6 +1488,7 @@ class ObjectLiteralProperty FINAL : public ZoneObject {
Expression* value_; Expression* value_;
Kind kind_; Kind kind_;
bool emit_store_; bool emit_store_;
bool is_static_;
Handle<Map> receiver_type_; Handle<Map> receiver_type_;
}; };
...@@ -2498,6 +2501,40 @@ class FunctionLiteral FINAL : public Expression { ...@@ -2498,6 +2501,40 @@ class FunctionLiteral FINAL : public Expression {
}; };
class ClassLiteral FINAL : public Expression {
public:
typedef ObjectLiteralProperty Property;
DECLARE_NODE_TYPE(ClassLiteral)
Handle<String> name() const { return raw_name_->string(); }
const AstRawString* raw_name() const { return raw_name_; }
Expression* extends() const { return extends_; }
FunctionLiteral* constructor() const { return constructor_; }
ZoneList<Property*>* properties() const { return properties_; }
protected:
ClassLiteral(Zone* zone, const AstRawString* name, Expression* extends,
FunctionLiteral* constructor, ZoneList<Property*>* properties,
AstValueFactory* ast_value_factory, int position, IdGen* id_gen)
: Expression(zone, position, id_gen),
raw_name_(name),
raw_inferred_name_(ast_value_factory->empty_string()),
extends_(extends),
constructor_(constructor),
properties_(properties) {}
private:
const AstRawString* raw_name_;
Handle<String> name_;
const AstString* raw_inferred_name_;
Handle<String> inferred_name_;
Expression* extends_;
FunctionLiteral* constructor_;
ZoneList<Property*>* properties_;
};
class NativeFunctionLiteral FINAL : public Expression { class NativeFunctionLiteral FINAL : public Expression {
public: public:
DECLARE_NODE_TYPE(NativeFunctionLiteral) DECLARE_NODE_TYPE(NativeFunctionLiteral)
...@@ -3300,16 +3337,17 @@ class AstNodeFactory FINAL BASE_EMBEDDED { ...@@ -3300,16 +3337,17 @@ class AstNodeFactory FINAL BASE_EMBEDDED {
} }
ObjectLiteral::Property* NewObjectLiteralProperty(Literal* key, ObjectLiteral::Property* NewObjectLiteralProperty(Literal* key,
Expression* value) { Expression* value,
return new (zone_) bool is_static) {
ObjectLiteral::Property(zone_, ast_value_factory_, key, value); return new (zone_) ObjectLiteral::Property(zone_, ast_value_factory_, key,
value, is_static);
} }
ObjectLiteral::Property* NewObjectLiteralProperty(bool is_getter, ObjectLiteral::Property* NewObjectLiteralProperty(bool is_getter,
FunctionLiteral* value, FunctionLiteral* value,
int pos) { int pos, bool is_static) {
ObjectLiteral::Property* prop = ObjectLiteral::Property* prop =
new(zone_) ObjectLiteral::Property(zone_, is_getter, value); new (zone_) ObjectLiteral::Property(zone_, is_getter, value, is_static);
prop->set_key(NewStringLiteral(value->raw_name(), pos)); prop->set_key(NewStringLiteral(value->raw_name(), pos));
return prop; // Not an AST node, will not be visited. return prop; // Not an AST node, will not be visited.
} }
...@@ -3465,6 +3503,17 @@ class AstNodeFactory FINAL BASE_EMBEDDED { ...@@ -3465,6 +3503,17 @@ class AstNodeFactory FINAL BASE_EMBEDDED {
return lit; return lit;
} }
ClassLiteral* NewClassLiteral(const AstRawString* name, Expression* extends,
FunctionLiteral* constructor,
ZoneList<ObjectLiteral::Property*>* properties,
AstValueFactory* ast_value_factory,
int position) {
ClassLiteral* lit =
new (zone_) ClassLiteral(zone_, name, extends, constructor, properties,
ast_value_factory, position, id_gen_);
VISIT_AND_RETURN(ClassLiteral, lit)
}
NativeFunctionLiteral* NewNativeFunctionLiteral(const AstRawString* name, NativeFunctionLiteral* NewNativeFunctionLiteral(const AstRawString* name,
v8::Extension* extension, v8::Extension* extension,
int pos) { int pos) {
......
...@@ -812,6 +812,12 @@ void AstGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { ...@@ -812,6 +812,12 @@ void AstGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
} }
void AstGraphBuilder::VisitClassLiteral(ClassLiteral* expr) {
// TODO(arv): Implement.
UNREACHABLE();
}
void AstGraphBuilder::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) { void AstGraphBuilder::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
UNREACHABLE(); UNREACHABLE();
} }
......
...@@ -175,6 +175,8 @@ DEFINE_IMPLICATION(harmony, harmony_arrow_functions) ...@@ -175,6 +175,8 @@ DEFINE_IMPLICATION(harmony, harmony_arrow_functions)
DEFINE_IMPLICATION(harmony, harmony_classes) DEFINE_IMPLICATION(harmony, harmony_classes)
DEFINE_IMPLICATION(harmony, harmony_object_literals) DEFINE_IMPLICATION(harmony, harmony_object_literals)
DEFINE_IMPLICATION(harmony_modules, harmony_scoping) DEFINE_IMPLICATION(harmony_modules, harmony_scoping)
DEFINE_IMPLICATION(harmony_classes, harmony_scoping)
DEFINE_IMPLICATION(harmony_classes, harmony_object_literals)
DEFINE_IMPLICATION(harmony, es_staging) DEFINE_IMPLICATION(harmony, es_staging)
......
...@@ -33,18 +33,22 @@ void BreakableStatementChecker::VisitVariableDeclaration( ...@@ -33,18 +33,22 @@ void BreakableStatementChecker::VisitVariableDeclaration(
VariableDeclaration* decl) { VariableDeclaration* decl) {
} }
void BreakableStatementChecker::VisitFunctionDeclaration( void BreakableStatementChecker::VisitFunctionDeclaration(
FunctionDeclaration* decl) { FunctionDeclaration* decl) {
} }
void BreakableStatementChecker::VisitModuleDeclaration( void BreakableStatementChecker::VisitModuleDeclaration(
ModuleDeclaration* decl) { ModuleDeclaration* decl) {
} }
void BreakableStatementChecker::VisitImportDeclaration( void BreakableStatementChecker::VisitImportDeclaration(
ImportDeclaration* decl) { ImportDeclaration* decl) {
} }
void BreakableStatementChecker::VisitExportDeclaration( void BreakableStatementChecker::VisitExportDeclaration(
ExportDeclaration* decl) { ExportDeclaration* decl) {
} }
...@@ -178,6 +182,13 @@ void BreakableStatementChecker::VisitFunctionLiteral(FunctionLiteral* expr) { ...@@ -178,6 +182,13 @@ void BreakableStatementChecker::VisitFunctionLiteral(FunctionLiteral* expr) {
} }
void BreakableStatementChecker::VisitClassLiteral(ClassLiteral* expr) {
if (expr->extends() != NULL) {
Visit(expr->extends());
}
}
void BreakableStatementChecker::VisitNativeFunctionLiteral( void BreakableStatementChecker::VisitNativeFunctionLiteral(
NativeFunctionLiteral* expr) { NativeFunctionLiteral* expr) {
} }
...@@ -1531,6 +1542,16 @@ void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { ...@@ -1531,6 +1542,16 @@ void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
} }
void FullCodeGenerator::VisitClassLiteral(ClassLiteral* expr) {
// TODO(arv): Implement
Comment cmnt(masm_, "[ ClassLiteral");
if (expr->extends() != NULL) {
VisitForEffect(expr->extends());
}
context()->Plug(isolate()->factory()->undefined_value());
}
void FullCodeGenerator::VisitNativeFunctionLiteral( void FullCodeGenerator::VisitNativeFunctionLiteral(
NativeFunctionLiteral* expr) { NativeFunctionLiteral* expr) {
Comment cmnt(masm_, "[ NativeFunctionLiteral"); Comment cmnt(masm_, "[ NativeFunctionLiteral");
......
...@@ -5248,6 +5248,14 @@ void HOptimizedGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { ...@@ -5248,6 +5248,14 @@ void HOptimizedGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
} }
void HOptimizedGraphBuilder::VisitClassLiteral(ClassLiteral* lit) {
DCHECK(!HasStackOverflow());
DCHECK(current_block() != NULL);
DCHECK(current_block()->HasPredecessor());
return Bailout(kClassLiteral);
}
void HOptimizedGraphBuilder::VisitNativeFunctionLiteral( void HOptimizedGraphBuilder::VisitNativeFunctionLiteral(
NativeFunctionLiteral* expr) { NativeFunctionLiteral* expr) {
DCHECK(!HasStackOverflow()); DCHECK(!HasStackOverflow());
......
...@@ -8,6 +8,7 @@ var kMessages = { ...@@ -8,6 +8,7 @@ var kMessages = {
// Error // Error
cyclic_proto: ["Cyclic __proto__ value"], cyclic_proto: ["Cyclic __proto__ value"],
code_gen_from_strings: ["%0"], code_gen_from_strings: ["%0"],
constructor_special_method: ["Class constructor may not be an accessor"],
generator_running: ["Generator is already running"], generator_running: ["Generator is already running"],
generator_finished: ["Generator has already finished"], generator_finished: ["Generator has already finished"],
// TypeError // TypeError
...@@ -139,6 +140,7 @@ var kMessages = { ...@@ -139,6 +140,7 @@ var kMessages = {
array_indexof_not_defined: ["Array.getIndexOf: Argument undefined"], array_indexof_not_defined: ["Array.getIndexOf: Argument undefined"],
object_not_extensible: ["Can't add property ", "%0", ", object is not extensible"], object_not_extensible: ["Can't add property ", "%0", ", object is not extensible"],
illegal_access: ["Illegal access"], illegal_access: ["Illegal access"],
static_prototype: ["Classes may not have static property named prototype"],
strict_mode_with: ["Strict mode code may not include a with statement"], strict_mode_with: ["Strict mode code may not include a with statement"],
strict_eval_arguments: ["Unexpected eval or arguments in strict mode"], strict_eval_arguments: ["Unexpected eval or arguments in strict mode"],
too_many_arguments: ["Too many arguments in function call (only 65535 allowed)"], too_many_arguments: ["Too many arguments in function call (only 65535 allowed)"],
......
...@@ -1016,6 +1016,7 @@ template <class C> inline bool Is(Object* obj); ...@@ -1016,6 +1016,7 @@ template <class C> inline bool Is(Object* obj);
"Call to a JavaScript runtime function") \ "Call to a JavaScript runtime function") \
V(kCannotTranslatePositionInChangedArea, \ V(kCannotTranslatePositionInChangedArea, \
"Cannot translate position in changed area") \ "Cannot translate position in changed area") \
V(kClassLiteral, "Class literal") \
V(kCodeGenerationFailed, "Code generation failed") \ V(kCodeGenerationFailed, "Code generation failed") \
V(kCodeObjectNotProperlyPatched, "Code object not properly patched") \ V(kCodeObjectNotProperlyPatched, "Code object not properly patched") \
V(kCompoundAssignmentToLookupSlot, "Compound assignment to lookup slot") \ V(kCompoundAssignmentToLookupSlot, "Compound assignment to lookup slot") \
......
...@@ -366,6 +366,16 @@ bool ParserTraits::IsEvalOrArguments(const AstRawString* identifier) const { ...@@ -366,6 +366,16 @@ bool ParserTraits::IsEvalOrArguments(const AstRawString* identifier) const {
} }
bool ParserTraits::IsPrototype(const AstRawString* identifier) const {
return identifier == parser_->ast_value_factory()->prototype_string();
}
bool ParserTraits::IsConstructor(const AstRawString* identifier) const {
return identifier == parser_->ast_value_factory()->constructor_string();
}
bool ParserTraits::IsThisProperty(Expression* expression) { bool ParserTraits::IsThisProperty(Expression* expression) {
DCHECK(expression != NULL); DCHECK(expression != NULL);
Property* property = expression->AsProperty(); Property* property = expression->AsProperty();
...@@ -1136,6 +1146,8 @@ Statement* Parser::ParseModuleElement(ZoneList<const AstRawString*>* labels, ...@@ -1136,6 +1146,8 @@ Statement* Parser::ParseModuleElement(ZoneList<const AstRawString*>* labels,
switch (peek()) { switch (peek()) {
case Token::FUNCTION: case Token::FUNCTION:
return ParseFunctionDeclaration(NULL, ok); return ParseFunctionDeclaration(NULL, ok);
case Token::CLASS:
return ParseClassDeclaration(NULL, ok);
case Token::IMPORT: case Token::IMPORT:
return ParseImportDeclaration(ok); return ParseImportDeclaration(ok);
case Token::EXPORT: case Token::EXPORT:
...@@ -1475,6 +1487,10 @@ Statement* Parser::ParseExportDeclaration(bool* ok) { ...@@ -1475,6 +1487,10 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
result = ParseFunctionDeclaration(&names, CHECK_OK); result = ParseFunctionDeclaration(&names, CHECK_OK);
break; break;
case Token::CLASS:
result = ParseClassDeclaration(&names, CHECK_OK);
break;
case Token::VAR: case Token::VAR:
case Token::LET: case Token::LET:
case Token::CONST: case Token::CONST:
...@@ -1537,10 +1553,13 @@ Statement* Parser::ParseBlockElement(ZoneList<const AstRawString*>* labels, ...@@ -1537,10 +1553,13 @@ Statement* Parser::ParseBlockElement(ZoneList<const AstRawString*>* labels,
// LetDeclaration // LetDeclaration
// ConstDeclaration // ConstDeclaration
// GeneratorDeclaration // GeneratorDeclaration
// ClassDeclaration
switch (peek()) { switch (peek()) {
case Token::FUNCTION: case Token::FUNCTION:
return ParseFunctionDeclaration(NULL, ok); return ParseFunctionDeclaration(NULL, ok);
case Token::CLASS:
return ParseClassDeclaration(NULL, ok);
case Token::CONST: case Token::CONST:
return ParseVariableStatement(kModuleElement, NULL, ok); return ParseVariableStatement(kModuleElement, NULL, ok);
case Token::LET: case Token::LET:
...@@ -1652,6 +1671,9 @@ Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels, ...@@ -1652,6 +1671,9 @@ Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels,
return ParseFunctionDeclaration(NULL, ok); return ParseFunctionDeclaration(NULL, ok);
} }
case Token::CLASS:
return ParseClassDeclaration(NULL, ok);
case Token::DEBUGGER: case Token::DEBUGGER:
return ParseDebuggerStatement(ok); return ParseDebuggerStatement(ok);
...@@ -1920,6 +1942,47 @@ Statement* Parser::ParseFunctionDeclaration( ...@@ -1920,6 +1942,47 @@ Statement* Parser::ParseFunctionDeclaration(
} }
Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names,
bool* ok) {
// ClassDeclaration ::
// 'class' Identifier ('extends' LeftHandExpression)? '{' ClassBody '}'
//
// A ClassDeclaration
//
// class C { ... }
//
// has the same semantics as:
//
// let C = class C { ... };
//
// so rewrite it as such.
Expect(Token::CLASS, CHECK_OK);
int pos = position();
bool is_strict_reserved = false;
const AstRawString* name =
ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
ClassLiteral* value = ParseClassLiteral(name, scanner()->location(),
is_strict_reserved, pos, CHECK_OK);
Block* block = factory()->NewBlock(NULL, 1, true, pos);
VariableMode mode = LET;
VariableProxy* proxy = NewUnresolved(name, mode, Interface::NewValue());
Declaration* declaration =
factory()->NewVariableDeclaration(proxy, mode, scope_, pos);
Declare(declaration, true, CHECK_OK);
Token::Value init_op = Token::INIT_LET;
Assignment* assignment = factory()->NewAssignment(init_op, proxy, value, pos);
block->AddStatement(
factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
zone());
if (names) names->Add(name, zone());
return block;
}
Block* Parser::ParseBlock(ZoneList<const AstRawString*>* labels, bool* ok) { Block* Parser::ParseBlock(ZoneList<const AstRawString*>* labels, bool* ok) {
if (allow_harmony_scoping() && strict_mode() == STRICT) { if (allow_harmony_scoping() && strict_mode() == STRICT) {
return ParseScopedBlock(labels, ok); return ParseScopedBlock(labels, ok);
......
...@@ -363,6 +363,7 @@ class ParserTraits { ...@@ -363,6 +363,7 @@ class ParserTraits {
typedef v8::internal::Expression* Expression; typedef v8::internal::Expression* Expression;
typedef Yield* YieldExpression; typedef Yield* YieldExpression;
typedef v8::internal::FunctionLiteral* FunctionLiteral; typedef v8::internal::FunctionLiteral* FunctionLiteral;
typedef v8::internal::ClassLiteral* ClassLiteral;
typedef v8::internal::Literal* Literal; typedef v8::internal::Literal* Literal;
typedef ObjectLiteral::Property* ObjectLiteralProperty; typedef ObjectLiteral::Property* ObjectLiteralProperty;
typedef ZoneList<v8::internal::Expression*>* ExpressionList; typedef ZoneList<v8::internal::Expression*>* ExpressionList;
...@@ -401,6 +402,10 @@ class ParserTraits { ...@@ -401,6 +402,10 @@ class ParserTraits {
static bool IsIdentifier(Expression* expression); static bool IsIdentifier(Expression* expression);
bool IsPrototype(const AstRawString* identifier) const;
bool IsConstructor(const AstRawString* identifier) const;
static const AstRawString* AsIdentifier(Expression* expression) { static const AstRawString* AsIdentifier(Expression* expression) {
DCHECK(IsIdentifier(expression)); DCHECK(IsIdentifier(expression));
return expression->AsVariableProxy()->raw_name(); return expression->AsVariableProxy()->raw_name();
...@@ -518,6 +523,8 @@ class ParserTraits { ...@@ -518,6 +523,8 @@ class ParserTraits {
return NULL; return NULL;
} }
static ObjectLiteralProperty* EmptyObjectLiteralProperty() { return NULL; } static ObjectLiteralProperty* EmptyObjectLiteralProperty() { return NULL; }
static FunctionLiteral* EmptyFunctionLiteral() { return NULL; }
static ClassLiteral* EmptyClassLiteral() { return NULL; }
// Used in error return values. // Used in error return values.
static ZoneList<Expression*>* NullExpressionList() { static ZoneList<Expression*>* NullExpressionList() {
...@@ -705,6 +712,8 @@ class Parser : public ParserBase<ParserTraits> { ...@@ -705,6 +712,8 @@ class Parser : public ParserBase<ParserTraits> {
Statement* ParseStatement(ZoneList<const AstRawString*>* labels, bool* ok); Statement* ParseStatement(ZoneList<const AstRawString*>* labels, bool* ok);
Statement* ParseFunctionDeclaration(ZoneList<const AstRawString*>* names, Statement* ParseFunctionDeclaration(ZoneList<const AstRawString*>* names,
bool* ok); bool* ok);
Statement* ParseClassDeclaration(ZoneList<const AstRawString*>* names,
bool* ok);
Statement* ParseNativeDeclaration(bool* ok); Statement* ParseNativeDeclaration(bool* ok);
Block* ParseBlock(ZoneList<const AstRawString*>* labels, bool* ok); Block* ParseBlock(ZoneList<const AstRawString*>* labels, bool* ok);
Block* ParseVariableStatement(VariableDeclarationContext var_context, Block* ParseVariableStatement(VariableDeclarationContext var_context,
......
...@@ -78,6 +78,12 @@ PreParserIdentifier PreParserTraits::GetSymbol(Scanner* scanner) { ...@@ -78,6 +78,12 @@ PreParserIdentifier PreParserTraits::GetSymbol(Scanner* scanner) {
if (scanner->UnescapedLiteralMatches("arguments", 9)) { if (scanner->UnescapedLiteralMatches("arguments", 9)) {
return PreParserIdentifier::Arguments(); return PreParserIdentifier::Arguments();
} }
if (scanner->UnescapedLiteralMatches("prototype", 9)) {
return PreParserIdentifier::Prototype();
}
if (scanner->UnescapedLiteralMatches("constructor", 11)) {
return PreParserIdentifier::Constructor();
}
return PreParserIdentifier::Default(); return PreParserIdentifier::Default();
} }
...@@ -178,6 +184,8 @@ PreParser::Statement PreParser::ParseSourceElement(bool* ok) { ...@@ -178,6 +184,8 @@ PreParser::Statement PreParser::ParseSourceElement(bool* ok) {
switch (peek()) { switch (peek()) {
case Token::FUNCTION: case Token::FUNCTION:
return ParseFunctionDeclaration(ok); return ParseFunctionDeclaration(ok);
case Token::CLASS:
return ParseClassDeclaration(ok);
case Token::CONST: case Token::CONST:
return ParseVariableStatement(kSourceElement, ok); return ParseVariableStatement(kSourceElement, ok);
case Token::LET: case Token::LET:
...@@ -305,6 +313,9 @@ PreParser::Statement PreParser::ParseStatement(bool* ok) { ...@@ -305,6 +313,9 @@ PreParser::Statement PreParser::ParseStatement(bool* ok) {
} }
} }
case Token::CLASS:
return ParseClassDeclaration(CHECK_OK);
case Token::DEBUGGER: case Token::DEBUGGER:
return ParseDebuggerStatement(ok); return ParseDebuggerStatement(ok);
...@@ -345,6 +356,18 @@ PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) { ...@@ -345,6 +356,18 @@ PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) {
} }
PreParser::Statement PreParser::ParseClassDeclaration(bool* ok) {
Expect(Token::CLASS, CHECK_OK);
int pos = position();
bool is_strict_reserved = false;
Identifier name =
ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
ParseClassLiteral(name, scanner()->location(), is_strict_reserved, pos,
CHECK_OK);
return Statement::Default();
}
PreParser::Statement PreParser::ParseBlock(bool* ok) { PreParser::Statement PreParser::ParseBlock(bool* ok) {
// Block :: // Block ::
// '{' Statement* '}' // '{' Statement* '}'
......
...@@ -46,6 +46,7 @@ namespace internal { ...@@ -46,6 +46,7 @@ namespace internal {
// typedef Identifier; // typedef Identifier;
// typedef Expression; // typedef Expression;
// typedef FunctionLiteral; // typedef FunctionLiteral;
// typedef ClassLiteral;
// typedef ObjectLiteralProperty; // typedef ObjectLiteralProperty;
// typedef Literal; // typedef Literal;
// typedef ExpressionList; // typedef ExpressionList;
...@@ -63,6 +64,7 @@ class ParserBase : public Traits { ...@@ -63,6 +64,7 @@ class ParserBase : public Traits {
typedef typename Traits::Type::Expression ExpressionT; typedef typename Traits::Type::Expression ExpressionT;
typedef typename Traits::Type::Identifier IdentifierT; typedef typename Traits::Type::Identifier IdentifierT;
typedef typename Traits::Type::FunctionLiteral FunctionLiteralT; typedef typename Traits::Type::FunctionLiteral FunctionLiteralT;
typedef typename Traits::Type::ClassLiteral ClassLiteralT;
typedef typename Traits::Type::Literal LiteralT; typedef typename Traits::Type::Literal LiteralT;
typedef typename Traits::Type::ObjectLiteralProperty ObjectLiteralPropertyT; typedef typename Traits::Type::ObjectLiteralProperty ObjectLiteralPropertyT;
...@@ -480,10 +482,12 @@ class ParserBase : public Traits { ...@@ -480,10 +482,12 @@ class ParserBase : public Traits {
ExpressionT ParsePrimaryExpression(bool* ok); ExpressionT ParsePrimaryExpression(bool* ok);
ExpressionT ParseExpression(bool accept_IN, bool* ok); ExpressionT ParseExpression(bool accept_IN, bool* ok);
ExpressionT ParseArrayLiteral(bool* ok); ExpressionT ParseArrayLiteral(bool* ok);
IdentifierT ParsePropertyName(bool* is_get, bool* is_set, bool* is_static,
bool* ok);
ExpressionT ParseObjectLiteral(bool* ok); ExpressionT ParseObjectLiteral(bool* ok);
ObjectLiteralPropertyT ParsePropertyDefinition(ObjectLiteralChecker* checker, ObjectLiteralPropertyT ParsePropertyDefinition(ObjectLiteralChecker* checker,
bool in_class, bool is_static,
bool* ok); bool* ok);
IdentifierT ParsePropertyName(bool* is_getter, bool* is_setter, bool* ok);
typename Traits::Type::ExpressionList ParseArguments(bool* ok); typename Traits::Type::ExpressionList ParseArguments(bool* ok);
ExpressionT ParseAssignmentExpression(bool accept_IN, bool* ok); ExpressionT ParseAssignmentExpression(bool accept_IN, bool* ok);
ExpressionT ParseYieldExpression(bool* ok); ExpressionT ParseYieldExpression(bool* ok);
...@@ -498,6 +502,10 @@ class ParserBase : public Traits { ...@@ -498,6 +502,10 @@ class ParserBase : public Traits {
bool* ok); bool* ok);
ExpressionT ParseArrowFunctionLiteral(int start_pos, ExpressionT params_ast, ExpressionT ParseArrowFunctionLiteral(int start_pos, ExpressionT params_ast,
bool* ok); bool* ok);
ClassLiteralT ParseClassLiteral(IdentifierT name,
Scanner::Location function_name_location,
bool name_is_strict_reserved, int pos,
bool* ok);
// Checks if the expression is a valid reference expression (e.g., on the // Checks if the expression is a valid reference expression (e.g., on the
// left-hand side of assignments). Although ruled out by ECMA as early errors, // left-hand side of assignments). Although ruled out by ECMA as early errors,
...@@ -612,10 +620,20 @@ class PreParserIdentifier { ...@@ -612,10 +620,20 @@ class PreParserIdentifier {
static PreParserIdentifier Yield() { static PreParserIdentifier Yield() {
return PreParserIdentifier(kYieldIdentifier); return PreParserIdentifier(kYieldIdentifier);
} }
static PreParserIdentifier Prototype() {
return PreParserIdentifier(kPrototypeIdentifier);
}
static PreParserIdentifier Constructor() {
return PreParserIdentifier(kConstructorIdentifier);
}
bool IsEval() const { return type_ == kEvalIdentifier; } bool IsEval() const { return type_ == kEvalIdentifier; }
bool IsArguments() const { return type_ == kArgumentsIdentifier; } bool IsArguments() const { return type_ == kArgumentsIdentifier; }
bool IsEvalOrArguments() const { return type_ >= kEvalIdentifier; }
bool IsYield() const { return type_ == kYieldIdentifier; } bool IsYield() const { return type_ == kYieldIdentifier; }
bool IsPrototype() const { return type_ == kPrototypeIdentifier; }
bool IsConstructor() const { return type_ == kConstructorIdentifier; }
bool IsEvalOrArguments() const {
return type_ == kEvalIdentifier || type_ == kArgumentsIdentifier;
}
bool IsFutureReserved() const { return type_ == kFutureReservedIdentifier; } bool IsFutureReserved() const { return type_ == kFutureReservedIdentifier; }
bool IsFutureStrictReserved() const { bool IsFutureStrictReserved() const {
return type_ == kFutureStrictReservedIdentifier; return type_ == kFutureStrictReservedIdentifier;
...@@ -638,7 +656,9 @@ class PreParserIdentifier { ...@@ -638,7 +656,9 @@ class PreParserIdentifier {
kLetIdentifier, kLetIdentifier,
kYieldIdentifier, kYieldIdentifier,
kEvalIdentifier, kEvalIdentifier,
kArgumentsIdentifier kArgumentsIdentifier,
kPrototypeIdentifier,
kConstructorIdentifier
}; };
explicit PreParserIdentifier(Type type) : type_(type) {} explicit PreParserIdentifier(Type type) : type_(type) {}
Type type_; Type type_;
...@@ -927,6 +947,7 @@ class PreParserScope { ...@@ -927,6 +947,7 @@ class PreParserScope {
ScopeType type() { return scope_type_; } ScopeType type() { return scope_type_; }
StrictMode strict_mode() const { return strict_mode_; } StrictMode strict_mode() const { return strict_mode_; }
void SetStrictMode(StrictMode strict_mode) { strict_mode_ = strict_mode; } void SetStrictMode(StrictMode strict_mode) { strict_mode_ = strict_mode; }
void SetScopeName(PreParserIdentifier name) {}
// When PreParser is in use, lazy compilation is already being done, // When PreParser is in use, lazy compilation is already being done,
// things cannot get lazier than that. // things cannot get lazier than that.
...@@ -971,11 +992,12 @@ class PreParserFactory { ...@@ -971,11 +992,12 @@ class PreParserFactory {
} }
PreParserExpression NewObjectLiteralProperty(bool is_getter, PreParserExpression NewObjectLiteralProperty(bool is_getter,
PreParserExpression value, PreParserExpression value,
int pos) { int pos, bool is_static) {
return PreParserExpression::Default(); return PreParserExpression::Default();
} }
PreParserExpression NewObjectLiteralProperty(PreParserExpression key, PreParserExpression NewObjectLiteralProperty(PreParserExpression key,
PreParserExpression value) { PreParserExpression value,
bool is_static) {
return PreParserExpression::Default(); return PreParserExpression::Default();
} }
PreParserExpression NewObjectLiteral(PreParserExpressionList properties, PreParserExpression NewObjectLiteral(PreParserExpressionList properties,
...@@ -985,7 +1007,7 @@ class PreParserFactory { ...@@ -985,7 +1007,7 @@ class PreParserFactory {
int pos) { int pos) {
return PreParserExpression::Default(); return PreParserExpression::Default();
} }
PreParserExpression NewVariableProxy(void* generator_variable) { PreParserExpression NewVariableProxy(void* variable) {
return PreParserExpression::Default(); return PreParserExpression::Default();
} }
PreParserExpression NewProperty(PreParserExpression obj, PreParserExpression NewProperty(PreParserExpression obj,
...@@ -1061,6 +1083,14 @@ class PreParserFactory { ...@@ -1061,6 +1083,14 @@ class PreParserFactory {
int position) { int position) {
return PreParserExpression::Default(); return PreParserExpression::Default();
} }
PreParserExpression NewClassLiteral(PreParserIdentifier name,
PreParserExpression extends,
PreParserExpression constructor,
PreParserExpressionList properties,
AstValueFactory* ast_value_factory,
int position) {
return PreParserExpression::Default();
}
// Return the object itself as AstVisitor and implement the needed // Return the object itself as AstVisitor and implement the needed
// dummy method right in this class. // dummy method right in this class.
...@@ -1099,6 +1129,7 @@ class PreParserTraits { ...@@ -1099,6 +1129,7 @@ class PreParserTraits {
typedef PreParserExpression Expression; typedef PreParserExpression Expression;
typedef PreParserExpression YieldExpression; typedef PreParserExpression YieldExpression;
typedef PreParserExpression FunctionLiteral; typedef PreParserExpression FunctionLiteral;
typedef PreParserExpression ClassLiteral;
typedef PreParserExpression ObjectLiteralProperty; typedef PreParserExpression ObjectLiteralProperty;
typedef PreParserExpression Literal; typedef PreParserExpression Literal;
typedef PreParserExpressionList ExpressionList; typedef PreParserExpressionList ExpressionList;
...@@ -1125,6 +1156,14 @@ class PreParserTraits { ...@@ -1125,6 +1156,14 @@ class PreParserTraits {
return identifier.IsEvalOrArguments(); return identifier.IsEvalOrArguments();
} }
static bool IsPrototype(PreParserIdentifier identifier) {
return identifier.IsPrototype();
}
static bool IsConstructor(PreParserIdentifier identifier) {
return identifier.IsConstructor();
}
// Returns true if the expression is of type "this.foo". // Returns true if the expression is of type "this.foo".
static bool IsThisProperty(PreParserExpression expression) { static bool IsThisProperty(PreParserExpression expression) {
return expression.IsThisProperty(); return expression.IsThisProperty();
...@@ -1245,6 +1284,12 @@ class PreParserTraits { ...@@ -1245,6 +1284,12 @@ class PreParserTraits {
static PreParserExpression EmptyObjectLiteralProperty() { static PreParserExpression EmptyObjectLiteralProperty() {
return PreParserExpression::Default(); return PreParserExpression::Default();
} }
static PreParserExpression EmptyFunctionLiteral() {
return PreParserExpression::Default();
}
static PreParserExpression EmptyClassLiteral() {
return PreParserExpression::Default();
}
static PreParserExpressionList NullExpressionList() { static PreParserExpressionList NullExpressionList() {
return PreParserExpressionList(); return PreParserExpressionList();
} }
...@@ -1435,6 +1480,7 @@ class PreParser : public ParserBase<PreParserTraits> { ...@@ -1435,6 +1480,7 @@ class PreParser : public ParserBase<PreParserTraits> {
SourceElements ParseSourceElements(int end_token, bool* ok); SourceElements ParseSourceElements(int end_token, bool* ok);
Statement ParseStatement(bool* ok); Statement ParseStatement(bool* ok);
Statement ParseFunctionDeclaration(bool* ok); Statement ParseFunctionDeclaration(bool* ok);
Statement ParseClassDeclaration(bool* ok);
Statement ParseBlock(bool* ok); Statement ParseBlock(bool* ok);
Statement ParseVariableStatement(VariableDeclarationContext var_context, Statement ParseVariableStatement(VariableDeclarationContext var_context,
bool* ok); bool* ok);
...@@ -1708,6 +1754,7 @@ ParserBase<Traits>::ParsePrimaryExpression(bool* ok) { ...@@ -1708,6 +1754,7 @@ ParserBase<Traits>::ParsePrimaryExpression(bool* ok) {
// ArrayLiteral // ArrayLiteral
// ObjectLiteral // ObjectLiteral
// RegExpLiteral // RegExpLiteral
// ClassLiteral
// '(' Expression ')' // '(' Expression ')'
int pos = peek_position(); int pos = peek_position();
...@@ -1778,6 +1825,23 @@ ParserBase<Traits>::ParsePrimaryExpression(bool* ok) { ...@@ -1778,6 +1825,23 @@ ParserBase<Traits>::ParsePrimaryExpression(bool* ok) {
} }
break; break;
case Token::CLASS: {
Consume(Token::CLASS);
int class_token_position = position();
IdentifierT name = this->EmptyIdentifier();
bool is_strict_reserved_name = false;
Scanner::Location class_name_location = Scanner::Location::invalid();
if (peek_any_identifier()) {
name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved_name,
CHECK_OK);
class_name_location = scanner()->location();
}
result = this->ParseClassLiteral(name, class_name_location,
is_strict_reserved_name,
class_token_position, CHECK_OK);
break;
}
case Token::MOD: case Token::MOD:
if (allow_natives_syntax() || extension_ != NULL) { if (allow_natives_syntax() || extension_ != NULL) {
result = this->ParseV8Intrinsic(CHECK_OK); result = this->ParseV8Intrinsic(CHECK_OK);
...@@ -1848,7 +1912,7 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral( ...@@ -1848,7 +1912,7 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral(
template <class Traits> template <class Traits>
typename ParserBase<Traits>::IdentifierT ParserBase<Traits>::ParsePropertyName( typename ParserBase<Traits>::IdentifierT ParserBase<Traits>::ParsePropertyName(
bool* is_getter, bool* is_setter, bool* ok) { bool* is_get, bool* is_set, bool* is_static, bool* ok) {
Token::Value next = peek(); Token::Value next = peek();
switch (next) { switch (next) {
case Token::STRING: case Token::STRING:
...@@ -1857,27 +1921,35 @@ typename ParserBase<Traits>::IdentifierT ParserBase<Traits>::ParsePropertyName( ...@@ -1857,27 +1921,35 @@ typename ParserBase<Traits>::IdentifierT ParserBase<Traits>::ParsePropertyName(
case Token::NUMBER: case Token::NUMBER:
Consume(Token::NUMBER); Consume(Token::NUMBER);
return this->GetNumberAsSymbol(scanner_); return this->GetNumberAsSymbol(scanner_);
case Token::STATIC:
*is_static = true;
// Fall through.
default: default:
return ParseIdentifierNameOrGetOrSet(is_getter, is_setter, return ParseIdentifierNameOrGetOrSet(is_get, is_set, ok);
CHECK_OK_CUSTOM(EmptyIdentifier));
} }
UNREACHABLE();
return this->EmptyIdentifier();
} }
template <class Traits> template <class Traits>
typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase< typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase<
Traits>::ParsePropertyDefinition(ObjectLiteralChecker* checker, bool* ok) { Traits>::ParsePropertyDefinition(ObjectLiteralChecker* checker,
bool in_class, bool is_static, bool* ok) {
// TODO(arv): Add support for concise generator methods. // TODO(arv): Add support for concise generator methods.
ExpressionT value = this->EmptyExpression(); ExpressionT value = this->EmptyExpression();
bool is_getter = false; bool is_get = false;
bool is_setter = false; bool is_set = false;
bool name_is_static = false;
Token::Value name_token = peek(); Token::Value name_token = peek();
int next_pos = peek_position(); int next_pos = peek_position();
IdentifierT name = ParsePropertyName( IdentifierT name =
&is_getter, &is_setter, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); ParsePropertyName(&is_get, &is_set, &name_is_static,
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
if (fni_ != NULL) this->PushLiteralName(fni_, name); if (fni_ != NULL) this->PushLiteralName(fni_, name);
if (peek() == Token::COLON) { if (!in_class && 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));
...@@ -1887,6 +1959,13 @@ typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase< ...@@ -1887,6 +1959,13 @@ typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase<
} else if (allow_harmony_object_literals_ && peek() == Token::LPAREN) { } else if (allow_harmony_object_literals_ && peek() == Token::LPAREN) {
// Concise Method // Concise Method
if (is_static && this->IsPrototype(name)) {
ReportMessageAt(scanner()->location(), "static_prototype");
*ok = false;
return this->EmptyObjectLiteralProperty();
}
checker->CheckProperty(name_token, kValueProperty, checker->CheckProperty(name_token, kValueProperty,
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
value = this->ParseFunctionLiteral( value = this->ParseFunctionLiteral(
...@@ -1896,25 +1975,43 @@ typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase< ...@@ -1896,25 +1975,43 @@ typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase<
FunctionLiteral::ANONYMOUS_EXPRESSION, FunctionLiteral::NORMAL_ARITY, FunctionLiteral::ANONYMOUS_EXPRESSION, FunctionLiteral::NORMAL_ARITY,
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
} else if (is_getter || is_setter) { } else if (in_class && name_is_static && !is_static) {
// static MethodDefinition
return ParsePropertyDefinition(checker, true, true, ok);
} else if (is_get || is_set) {
// Accessor // Accessor
bool dont_care = false; bool dont_care = false;
name_token = peek(); name_token = peek();
name = ParsePropertyName(&dont_care, &dont_care, name = ParsePropertyName(&dont_care, &dont_care, &dont_care,
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
// Validate the property. // Validate the property.
if (is_static && this->IsPrototype(name)) {
ReportMessageAt(scanner()->location(), "static_prototype");
*ok = false;
return this->EmptyObjectLiteralProperty();
} else if (in_class && !is_static && this->IsConstructor(name)) {
// ES6, spec draft rev 27, treats static get constructor as an error too.
// https://bugs.ecmascript.org/show_bug.cgi?id=3223
// TODO(arv): Update when bug is resolved.
ReportMessageAt(scanner()->location(), "constructor_special_method");
*ok = false;
return this->EmptyObjectLiteralProperty();
}
checker->CheckProperty(name_token, checker->CheckProperty(name_token,
is_getter ? kGetterProperty : kSetterProperty, is_get ? kGetterProperty : kSetterProperty,
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
typename Traits::Type::FunctionLiteral value = this->ParseFunctionLiteral( typename Traits::Type::FunctionLiteral value = this->ParseFunctionLiteral(
name, scanner()->location(), name, scanner()->location(),
false, // reserved words are allowed here false, // reserved words are allowed here
FunctionKind::kNormalFunction, RelocInfo::kNoPosition, FunctionKind::kNormalFunction, RelocInfo::kNoPosition,
FunctionLiteral::ANONYMOUS_EXPRESSION, FunctionLiteral::ANONYMOUS_EXPRESSION,
is_getter ? FunctionLiteral::GETTER_ARITY is_get ? FunctionLiteral::GETTER_ARITY : FunctionLiteral::SETTER_ARITY,
: FunctionLiteral::SETTER_ARITY,
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
return factory()->NewObjectLiteralProperty(is_getter, value, next_pos); return factory()->NewObjectLiteralProperty(is_get, value, next_pos,
is_static);
} else { } else {
Token::Value next = Next(); Token::Value next = Next();
ReportUnexpectedToken(next); ReportUnexpectedToken(next);
...@@ -1927,7 +2024,7 @@ typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase< ...@@ -1927,7 +2024,7 @@ typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase<
? factory()->NewNumberLiteral(index, next_pos) ? factory()->NewNumberLiteral(index, next_pos)
: factory()->NewStringLiteral(name, next_pos); : factory()->NewStringLiteral(name, next_pos);
return factory()->NewObjectLiteralProperty(key, value); return factory()->NewObjectLiteralProperty(key, value, is_static);
} }
...@@ -1950,8 +2047,10 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral( ...@@ -1950,8 +2047,10 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral(
while (peek() != Token::RBRACE) { while (peek() != Token::RBRACE) {
if (fni_ != NULL) fni_->Enter(); if (fni_ != NULL) fni_->Enter();
const bool in_class = false;
const bool is_static = false;
ObjectLiteralPropertyT property = ObjectLiteralPropertyT property =
this->ParsePropertyDefinition(&checker, CHECK_OK); this->ParsePropertyDefinition(&checker, in_class, is_static, CHECK_OK);
// Mark top-level object literals that contain function literals and // Mark top-level object literals that contain function literals and
// pretenure the literal so it can be added as a constant function // pretenure the literal so it can be added as a constant function
...@@ -2400,7 +2499,7 @@ template <class Traits> ...@@ -2400,7 +2499,7 @@ template <class Traits>
typename ParserBase<Traits>::ExpressionT typename ParserBase<Traits>::ExpressionT
ParserBase<Traits>::ParseMemberExpression(bool* ok) { ParserBase<Traits>::ParseMemberExpression(bool* ok) {
// MemberExpression :: // MemberExpression ::
// (PrimaryExpression | FunctionLiteral) // (PrimaryExpression | FunctionLiteral | ClassLiteral)
// ('[' Expression ']' | '.' Identifier | Arguments)* // ('[' Expression ']' | '.' Identifier | Arguments)*
// The '[' Expression ']' and '.' Identifier parts are parsed by // The '[' Expression ']' and '.' Identifier parts are parsed by
...@@ -2603,6 +2702,69 @@ typename ParserBase<Traits>::ExpressionT ParserBase< ...@@ -2603,6 +2702,69 @@ typename ParserBase<Traits>::ExpressionT ParserBase<
} }
template <class Traits>
typename ParserBase<Traits>::ClassLiteralT
ParserBase<Traits>::ParseClassLiteral(IdentifierT name,
Scanner::Location class_name_location,
bool name_is_strict_reserved, int pos,
bool* ok) {
// All parts of a ClassDeclaration or a ClassExpression are strict code.
if (name_is_strict_reserved) {
ReportMessageAt(class_name_location, "unexpected_strict_reserved");
*ok = false;
return this->EmptyClassLiteral();
}
if (this->IsEvalOrArguments(name)) {
ReportMessageAt(class_name_location, "strict_eval_arguments");
*ok = false;
return this->EmptyClassLiteral();
}
// TODO(arv): Implement scopes and name binding in class body only.
// TODO(arv): Maybe add CLASS_SCOPE?
typename Traits::Type::ScopePtr extends_scope =
this->NewScope(scope_, BLOCK_SCOPE);
FunctionState extends_function_state(
&function_state_, &scope_, &extends_scope, zone(),
this->ast_value_factory(), ast_node_id_gen_);
scope_->SetStrictMode(STRICT);
scope_->SetScopeName(name);
ExpressionT extends = this->EmptyExpression();
if (Check(Token::EXTENDS)) {
extends =
this->ParseLeftHandSideExpression(CHECK_OK_CUSTOM(EmptyClassLiteral));
}
ObjectLiteralChecker checker(this, STRICT);
typename Traits::Type::PropertyList properties =
this->NewPropertyList(4, zone_);
FunctionLiteralT constructor = this->EmptyFunctionLiteral();
Expect(Token::LBRACE, CHECK_OK_CUSTOM(EmptyClassLiteral));
while (peek() != Token::RBRACE) {
if (Check(Token::SEMICOLON)) continue;
if (fni_ != NULL) fni_->Enter();
const bool in_class = true;
const bool is_static = false;
ObjectLiteralPropertyT property = this->ParsePropertyDefinition(
&checker, in_class, is_static, CHECK_OK_CUSTOM(EmptyClassLiteral));
properties->Add(property, zone());
if (fni_ != NULL) {
fni_->Infer();
fni_->Leave();
}
}
Expect(Token::RBRACE, CHECK_OK_CUSTOM(EmptyClassLiteral));
return factory()->NewClassLiteral(name, extends, constructor, properties,
this->ast_value_factory(), pos);
}
template <typename Traits> template <typename Traits>
typename ParserBase<Traits>::ExpressionT typename ParserBase<Traits>::ExpressionT
ParserBase<Traits>::CheckAndRewriteReferenceExpression( ParserBase<Traits>::CheckAndRewriteReferenceExpression(
......
...@@ -289,6 +289,21 @@ void PrettyPrinter::VisitFunctionLiteral(FunctionLiteral* node) { ...@@ -289,6 +289,21 @@ void PrettyPrinter::VisitFunctionLiteral(FunctionLiteral* node) {
} }
void PrettyPrinter::VisitClassLiteral(ClassLiteral* node) {
Print("(class ");
PrintLiteral(node->name(), false);
if (node->extends()) {
Print(" extends ");
Visit(node->extends());
}
Print(" { ");
for (int i = 0; i < node->properties()->length(); i++) {
PrintObjectLiteralProperty(node->properties()->at(i));
}
Print(" })");
}
void PrettyPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) { void PrettyPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) {
Print("("); Print("(");
PrintLiteral(node->name(), false); PrintLiteral(node->name(), false);
...@@ -323,16 +338,22 @@ void PrettyPrinter::VisitObjectLiteral(ObjectLiteral* node) { ...@@ -323,16 +338,22 @@ void PrettyPrinter::VisitObjectLiteral(ObjectLiteral* node) {
Print("{ "); Print("{ ");
for (int i = 0; i < node->properties()->length(); i++) { for (int i = 0; i < node->properties()->length(); i++) {
if (i != 0) Print(","); if (i != 0) Print(",");
ObjectLiteral::Property* property = node->properties()->at(i); PrintObjectLiteralProperty(node->properties()->at(i));
Print(" ");
Visit(property->key());
Print(": ");
Visit(property->value());
} }
Print(" }"); Print(" }");
} }
void PrettyPrinter::PrintObjectLiteralProperty(
ObjectLiteralProperty* property) {
// TODO(arv): Better printing of methods etc.
Print(" ");
Visit(property->key());
Print(": ");
Visit(property->value());
}
void PrettyPrinter::VisitArrayLiteral(ArrayLiteral* node) { void PrettyPrinter::VisitArrayLiteral(ArrayLiteral* node) {
Print("[ "); Print("[ ");
for (int i = 0; i < node->values()->length(); i++) { for (int i = 0; i < node->values()->length(); i++) {
...@@ -969,6 +990,12 @@ void AstPrinter::VisitFunctionLiteral(FunctionLiteral* node) { ...@@ -969,6 +990,12 @@ void AstPrinter::VisitFunctionLiteral(FunctionLiteral* node) {
} }
void AstPrinter::VisitClassLiteral(ClassLiteral* node) {
IndentedScope indent(this, "CLASS LITERAL");
PrintLiteralIndented("NAME", node->name(), false);
}
void AstPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) { void AstPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) {
IndentedScope indent(this, "NATIVE FUNC LITERAL"); IndentedScope indent(this, "NATIVE FUNC LITERAL");
PrintLiteralIndented("NAME", node->name(), false); PrintLiteralIndented("NAME", node->name(), false);
......
...@@ -52,6 +52,7 @@ class PrettyPrinter: public AstVisitor { ...@@ -52,6 +52,7 @@ class PrettyPrinter: public AstVisitor {
void PrintDeclarations(ZoneList<Declaration*>* declarations); void PrintDeclarations(ZoneList<Declaration*>* declarations);
void PrintFunctionLiteral(FunctionLiteral* function); void PrintFunctionLiteral(FunctionLiteral* function);
void PrintCaseClause(CaseClause* clause); void PrintCaseClause(CaseClause* clause);
void PrintObjectLiteralProperty(ObjectLiteralProperty* property);
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
}; };
......
...@@ -902,70 +902,73 @@ uc32 Scanner::ScanIdentifierUnicodeEscape() { ...@@ -902,70 +902,73 @@ uc32 Scanner::ScanIdentifierUnicodeEscape() {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Keyword Matcher // Keyword Matcher
#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \ #define KEYWORDS(KEYWORD_GROUP, KEYWORD) \
KEYWORD_GROUP('b') \ KEYWORD_GROUP('b') \
KEYWORD("break", Token::BREAK) \ KEYWORD("break", Token::BREAK) \
KEYWORD_GROUP('c') \ KEYWORD_GROUP('c') \
KEYWORD("case", Token::CASE) \ KEYWORD("case", Token::CASE) \
KEYWORD("catch", Token::CATCH) \ KEYWORD("catch", Token::CATCH) \
KEYWORD("class", Token::FUTURE_RESERVED_WORD) \ KEYWORD("class", \
KEYWORD("const", Token::CONST) \ harmony_classes ? Token::CLASS : Token::FUTURE_RESERVED_WORD) \
KEYWORD("continue", Token::CONTINUE) \ KEYWORD("const", Token::CONST) \
KEYWORD_GROUP('d') \ KEYWORD("continue", Token::CONTINUE) \
KEYWORD("debugger", Token::DEBUGGER) \ KEYWORD_GROUP('d') \
KEYWORD("default", Token::DEFAULT) \ KEYWORD("debugger", Token::DEBUGGER) \
KEYWORD("delete", Token::DELETE) \ KEYWORD("default", Token::DEFAULT) \
KEYWORD("do", Token::DO) \ KEYWORD("delete", Token::DELETE) \
KEYWORD_GROUP('e') \ KEYWORD("do", Token::DO) \
KEYWORD("else", Token::ELSE) \ KEYWORD_GROUP('e') \
KEYWORD("enum", Token::FUTURE_RESERVED_WORD) \ KEYWORD("else", Token::ELSE) \
KEYWORD("export", \ KEYWORD("enum", Token::FUTURE_RESERVED_WORD) \
harmony_modules ? Token::EXPORT : Token::FUTURE_RESERVED_WORD) \ KEYWORD("export", \
KEYWORD("extends", Token::FUTURE_RESERVED_WORD) \ harmony_modules ? Token::EXPORT : Token::FUTURE_RESERVED_WORD) \
KEYWORD_GROUP('f') \ KEYWORD("extends", \
KEYWORD("false", Token::FALSE_LITERAL) \ harmony_classes ? Token::EXTENDS : Token::FUTURE_RESERVED_WORD) \
KEYWORD("finally", Token::FINALLY) \ KEYWORD_GROUP('f') \
KEYWORD("for", Token::FOR) \ KEYWORD("false", Token::FALSE_LITERAL) \
KEYWORD("function", Token::FUNCTION) \ KEYWORD("finally", Token::FINALLY) \
KEYWORD_GROUP('i') \ KEYWORD("for", Token::FOR) \
KEYWORD("if", Token::IF) \ KEYWORD("function", Token::FUNCTION) \
KEYWORD("implements", Token::FUTURE_STRICT_RESERVED_WORD) \ KEYWORD_GROUP('i') \
KEYWORD("import", \ KEYWORD("if", Token::IF) \
harmony_modules ? Token::IMPORT : Token::FUTURE_RESERVED_WORD) \ KEYWORD("implements", Token::FUTURE_STRICT_RESERVED_WORD) \
KEYWORD("in", Token::IN) \ KEYWORD("import", \
KEYWORD("instanceof", Token::INSTANCEOF) \ harmony_modules ? Token::IMPORT : Token::FUTURE_RESERVED_WORD) \
KEYWORD("interface", Token::FUTURE_STRICT_RESERVED_WORD) \ KEYWORD("in", Token::IN) \
KEYWORD_GROUP('l') \ KEYWORD("instanceof", Token::INSTANCEOF) \
KEYWORD("let", \ KEYWORD("interface", Token::FUTURE_STRICT_RESERVED_WORD) \
harmony_scoping ? Token::LET : Token::FUTURE_STRICT_RESERVED_WORD) \ KEYWORD_GROUP('l') \
KEYWORD_GROUP('n') \ KEYWORD("let", \
KEYWORD("new", Token::NEW) \ harmony_scoping ? Token::LET : Token::FUTURE_STRICT_RESERVED_WORD) \
KEYWORD("null", Token::NULL_LITERAL) \ KEYWORD_GROUP('n') \
KEYWORD_GROUP('p') \ KEYWORD("new", Token::NEW) \
KEYWORD("package", Token::FUTURE_STRICT_RESERVED_WORD) \ KEYWORD("null", Token::NULL_LITERAL) \
KEYWORD("private", Token::FUTURE_STRICT_RESERVED_WORD) \ KEYWORD_GROUP('p') \
KEYWORD("protected", Token::FUTURE_STRICT_RESERVED_WORD) \ KEYWORD("package", Token::FUTURE_STRICT_RESERVED_WORD) \
KEYWORD("public", Token::FUTURE_STRICT_RESERVED_WORD) \ KEYWORD("private", Token::FUTURE_STRICT_RESERVED_WORD) \
KEYWORD_GROUP('r') \ KEYWORD("protected", Token::FUTURE_STRICT_RESERVED_WORD) \
KEYWORD("return", Token::RETURN) \ KEYWORD("public", Token::FUTURE_STRICT_RESERVED_WORD) \
KEYWORD_GROUP('s') \ KEYWORD_GROUP('r') \
KEYWORD("static", Token::FUTURE_STRICT_RESERVED_WORD) \ KEYWORD("return", Token::RETURN) \
KEYWORD("super", \ KEYWORD_GROUP('s') \
harmony_classes ? Token::SUPER : Token::FUTURE_RESERVED_WORD) \ KEYWORD("static", harmony_classes ? Token::STATIC \
KEYWORD("switch", Token::SWITCH) \ : Token::FUTURE_STRICT_RESERVED_WORD) \
KEYWORD_GROUP('t') \ KEYWORD("super", \
KEYWORD("this", Token::THIS) \ harmony_classes ? Token::SUPER : Token::FUTURE_RESERVED_WORD) \
KEYWORD("throw", Token::THROW) \ KEYWORD("switch", Token::SWITCH) \
KEYWORD("true", Token::TRUE_LITERAL) \ KEYWORD_GROUP('t') \
KEYWORD("try", Token::TRY) \ KEYWORD("this", Token::THIS) \
KEYWORD("typeof", Token::TYPEOF) \ KEYWORD("throw", Token::THROW) \
KEYWORD_GROUP('v') \ KEYWORD("true", Token::TRUE_LITERAL) \
KEYWORD("var", Token::VAR) \ KEYWORD("try", Token::TRY) \
KEYWORD("void", Token::VOID) \ KEYWORD("typeof", Token::TYPEOF) \
KEYWORD_GROUP('w') \ KEYWORD_GROUP('v') \
KEYWORD("while", Token::WHILE) \ KEYWORD("var", Token::VAR) \
KEYWORD("with", Token::WITH) \ KEYWORD("void", Token::VOID) \
KEYWORD_GROUP('y') \ KEYWORD_GROUP('w') \
KEYWORD("while", Token::WHILE) \
KEYWORD("with", Token::WITH) \
KEYWORD_GROUP('y') \
KEYWORD("yield", Token::YIELD) KEYWORD("yield", Token::YIELD)
......
...@@ -653,7 +653,7 @@ class Scanner { ...@@ -653,7 +653,7 @@ class Scanner {
bool harmony_modules_; bool harmony_modules_;
// Whether we scan 0o777 and 0b111 as numbers. // Whether we scan 0o777 and 0b111 as numbers.
bool harmony_numeric_literals_; bool harmony_numeric_literals_;
// Whether we scan 'super' as keyword. // Whether we scan 'class', 'extends', 'static' and 'super' as keywords.
bool harmony_classes_; bool harmony_classes_;
}; };
......
...@@ -148,10 +148,13 @@ namespace internal { ...@@ -148,10 +148,13 @@ namespace internal {
/* Future reserved words (ECMA-262, section 7.6.1.2). */ \ /* Future reserved words (ECMA-262, section 7.6.1.2). */ \
T(FUTURE_RESERVED_WORD, NULL, 0) \ T(FUTURE_RESERVED_WORD, NULL, 0) \
T(FUTURE_STRICT_RESERVED_WORD, NULL, 0) \ T(FUTURE_STRICT_RESERVED_WORD, NULL, 0) \
K(CLASS, "class", 0) \
K(CONST, "const", 0) \ K(CONST, "const", 0) \
K(EXPORT, "export", 0) \ K(EXPORT, "export", 0) \
K(EXTENDS, "extends", 0) \
K(IMPORT, "import", 0) \ K(IMPORT, "import", 0) \
K(LET, "let", 0) \ K(LET, "let", 0) \
K(STATIC, "static", 0) \
K(YIELD, "yield", 0) \ K(YIELD, "yield", 0) \
K(SUPER, "super", 0) \ K(SUPER, "super", 0) \
\ \
......
...@@ -352,6 +352,9 @@ void AstTyper::VisitFunctionLiteral(FunctionLiteral* expr) { ...@@ -352,6 +352,9 @@ void AstTyper::VisitFunctionLiteral(FunctionLiteral* expr) {
} }
void AstTyper::VisitClassLiteral(ClassLiteral* expr) {}
void AstTyper::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) { void AstTyper::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
} }
......
...@@ -1448,9 +1448,15 @@ TEST(ParserSync) { ...@@ -1448,9 +1448,15 @@ TEST(ParserSync) {
i::GetCurrentStackPosition() - 128 * 1024); i::GetCurrentStackPosition() - 128 * 1024);
static const ParserFlag flags1[] = { static const ParserFlag flags1[] = {
kAllowLazy, kAllowHarmonyScoping, kAllowArrowFunctions,
kAllowModules, kAllowArrowFunctions, kAllowClasses,
kAllowHarmonyNumericLiterals, kAllowHarmonyObjectLiterals}; kAllowHarmonyNumericLiterals,
kAllowHarmonyObjectLiterals,
kAllowHarmonyScoping,
kAllowLazy,
kAllowModules,
};
for (int i = 0; context_data[i][0] != NULL; ++i) { for (int i = 0; context_data[i][0] != NULL; ++i) {
for (int j = 0; statement_data[j] != NULL; ++j) { for (int j = 0; statement_data[j] != NULL; ++j) {
for (int k = 0; termination_data[k] != NULL; ++k) { for (int k = 0; termination_data[k] != NULL; ++k) {
...@@ -1525,10 +1531,14 @@ void RunParserSyncTest(const char* context_data[][2], ...@@ -1525,10 +1531,14 @@ void RunParserSyncTest(const char* context_data[][2],
i::GetCurrentStackPosition() - 128 * 1024); i::GetCurrentStackPosition() - 128 * 1024);
static const ParserFlag default_flags[] = { static const ParserFlag default_flags[] = {
kAllowArrowFunctions, kAllowClasses, kAllowArrowFunctions,
kAllowHarmonyNumericLiterals, kAllowHarmonyObjectLiterals, kAllowClasses,
kAllowHarmonyScoping, kAllowLazy, kAllowHarmonyNumericLiterals,
kAllowModules, kAllowNativesSyntax, kAllowHarmonyObjectLiterals,
kAllowHarmonyScoping,
kAllowLazy,
kAllowModules,
kAllowNativesSyntax,
}; };
ParserFlag* generated_flags = NULL; ParserFlag* generated_flags = NULL;
if (flags == NULL) { if (flags == NULL) {
...@@ -3537,3 +3547,405 @@ TEST(MethodDefinitionDuplicateProperty) { ...@@ -3537,3 +3547,405 @@ TEST(MethodDefinitionDuplicateProperty) {
RunParserSyncTest(context_data, params_data, kError, NULL, 0, RunParserSyncTest(context_data, params_data, kError, NULL, 0,
always_flags, arraysize(always_flags)); always_flags, arraysize(always_flags));
} }
TEST(NoErrorsClassExpression) {
const char* context_data[][2] = {{"(", ");"},
{"var C = ", ";"},
{"bar, ", ";"},
{NULL, NULL}};
const char* class_data[] = {
"class {}",
"class name {}",
"class extends F {}",
"class name extends F {}",
"class extends (F, G) {}",
"class name extends (F, G) {}",
"class extends class {} {}",
"class name extends class {} {}",
"class extends class base {} {}",
"class name extends class base {} {}",
NULL};
static const ParserFlag always_flags[] = {kAllowClasses};
RunParserSyncTest(context_data, class_data, kSuccess, NULL, 0,
always_flags, arraysize(always_flags));
}
TEST(NoErrorsClassDeclaration) {
const char* context_data[][2] = {{"", ""},
{"{", "}"},
{"if (true) {", "}"},
{NULL, NULL}};
const char* statement_data[] = {
"class name {}",
"class name extends F {}",
"class name extends (F, G) {}",
"class name extends class {} {}",
"class name extends class base {} {}",
NULL};
static const ParserFlag always_flags[] = {kAllowClasses};
RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
always_flags, arraysize(always_flags));
}
TEST(NoErrorsClassBody) {
// Tests that parser and preparser accept valid class syntax.
const char* context_data[][2] = {{"(class {", "});"},
{"(class extends Base {", "});"},
{"class C {", "}"},
{"class C extends Base {", "}"},
{NULL, NULL}};
const char* class_body_data[] = {
";",
";;",
"m() {}",
"m() {};",
";m() {}",
"m() {}; n(x) {}",
"get x() {}",
"set x(v) {}",
"get() {}",
"set() {}",
"static() {}",
"static m() {}",
"static get x() {}",
"static set x(v) {}",
"static get() {}",
"static set() {}",
"static static() {}",
"static get static() {}",
"static set static(v) {}",
NULL};
static const ParserFlag always_flags[] = {
kAllowClasses,
kAllowHarmonyObjectLiterals
};
RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
always_flags, arraysize(always_flags));
}
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) {
const char* context_data[][2] = {{"(class {", "() {}});"},
{"(class { get ", "() {}});"},
{"(class { set ", "(v) {}});"},
{"(class { static ", "() {}});"},
{"(class { static get ", "() {}});"},
{"(class { static set ", "(v) {}});"},
{"class C {", "() {}}"},
{"class C { get ", "() {}}"},
{"class C { set ", "(v) {}}"},
{"class C { static ", "() {}}"},
{"class C { static get ", "() {}}"},
{"class C { static set ", "(v) {}}"},
{NULL, NULL}};
const char* name_data[] = {
"42",
"42.5",
"42e2",
"42e+2",
"42e-2",
"null",
"false",
"true",
"'str'",
"\"str\"",
"static",
"get",
"set",
"var",
"const",
"let",
"this",
"class",
"function",
"yield",
"if",
"else",
"for",
"while",
"do",
"try",
"catch",
"finally",
NULL};
static const ParserFlag always_flags[] = {
kAllowClasses,
kAllowHarmonyObjectLiterals
};
RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0,
always_flags, arraysize(always_flags));
}
TEST(ErrorsClassExpression) {
const char* context_data[][2] = {{"(", ");"},
{"var C = ", ";"},
{"bar, ", ";"},
{NULL, NULL}};
const char* class_data[] = {
"class",
"class name",
"class name extends",
"class extends",
"class {",
"class { m }",
"class { m; n }",
"class { m: 1 }",
"class { m(); n() }",
"class { get m }",
"class { get m() }",
"class { get m() { }",
"class { set m() {} }", // Missing required parameter.
"class { m() {}, n() {} }", // No commas allowed.
NULL};
static const ParserFlag always_flags[] = {
kAllowClasses,
kAllowHarmonyObjectLiterals
};
RunParserSyncTest(context_data, class_data, kError, NULL, 0,
always_flags, arraysize(always_flags));
}
TEST(ErrorsClassDeclaration) {
const char* context_data[][2] = {{"", ""},
{"{", "}"},
{"if (true) {", "}"},
{NULL, NULL}};
const char* class_data[] = {
"class",
"class name",
"class name extends",
"class extends",
"class name {",
"class name { m }",
"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 is required for declaration
"class extends base {}",
NULL};
static const ParserFlag always_flags[] = {
kAllowClasses,
kAllowHarmonyNumericLiterals
};
RunParserSyncTest(context_data, class_data, kError, NULL, 0,
always_flags, arraysize(always_flags));
}
TEST(ErrorsClassName) {
const char* context_data[][2] = {{"class ", "{}"},
{"(class ", "{});"},
{"'use strict'; class ", "{}"},
{"'use strict'; (class ", "{});"},
{NULL, NULL}};
const char* class_name[] = {
"arguments",
"eval",
"implements",
"interface",
"let",
"package",
"private",
"protected",
"public",
"static",
"var",
"yield",
NULL};
static const ParserFlag always_flags[] = {
kAllowClasses,
kAllowHarmonyObjectLiterals
};
RunParserSyncTest(context_data, class_name, kError, NULL, 0,
always_flags, arraysize(always_flags));
}
TEST(ErrorsClassGetterParamName) {
const char* context_data[][2] = {
{"class C { get name(", ") {} }"},
{"(class { get name(", ") {} });"},
{"'use strict'; class C { get name(", ") {} }"},
{"'use strict'; (class { get name(", ") {} })"},
{NULL, NULL}
};
const char* class_name[] = {
"arguments",
"eval",
"implements",
"interface",
"let",
"package",
"private",
"protected",
"public",
"static",
"var",
"yield",
NULL};
static const ParserFlag always_flags[] = {
kAllowClasses,
kAllowHarmonyObjectLiterals
};
RunParserSyncTest(context_data, class_name, kError, NULL, 0,
always_flags, arraysize(always_flags));
}
TEST(ErrorsClassStaticPrototype) {
const char* context_data[][2] = {{"class C {", "}"},
{"(class {", "});"},
{NULL, NULL}};
const char* class_body_data[] = {
"static prototype() {}",
"static get prototype() {}",
"static set prototype(_) {}",
NULL};
static const ParserFlag always_flags[] = {
kAllowClasses,
kAllowHarmonyObjectLiterals
};
RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
always_flags, arraysize(always_flags));
}
TEST(ErrorsClassSpecialConstructor) {
const char* context_data[][2] = {{"class C {", "}"},
{"(class {", "});"},
{NULL, NULL}};
const char* class_body_data[] = {
"get constructor() {}",
"get constructor(_) {}",
NULL};
static const ParserFlag always_flags[] = {
kAllowClasses,
kAllowHarmonyObjectLiterals
};
RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
always_flags, arraysize(always_flags));
}
TEST(NoErrorsClassConstructor) {
const char* context_data[][2] = {{"class C {", "}"},
{"(class {", "});"},
{NULL, NULL}};
const char* class_body_data[] = {
"constructor() {}",
"static constructor() {}",
"static get constructor() {}",
"static set constructor(_) {}",
NULL};
static const ParserFlag always_flags[] = {
kAllowClasses,
kAllowHarmonyObjectLiterals
};
RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
always_flags, arraysize(always_flags));
}
TEST(ErrorsClassMultipleConstructor) {
// 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.
const char* context_data[][2] = {{"class C {", "}"},
{"(class {", "});"},
{NULL, NULL}};
const char* class_body_data[] = {
"constructor() {}; constructor() {}",
NULL};
static const ParserFlag always_flags[] = {
kAllowClasses,
kAllowHarmonyObjectLiterals
};
RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
always_flags, arraysize(always_flags));
}
// TODO(arv): We should allow duplicate property names.
// https://code.google.com/p/v8/issues/detail?id=3570
DISABLED_TEST(NoErrorsClassMultiplePropertyNames) {
const char* context_data[][2] = {{"class C {", "}"},
{"(class {", "});"},
{NULL, NULL}};
const char* class_body_data[] = {
"constructor() {}; static constructor() {}",
"m() {}; static m() {}",
"m() {}; m() {}",
NULL};
static const ParserFlag always_flags[] = {
kAllowClasses,
kAllowHarmonyObjectLiterals
};
RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
always_flags, arraysize(always_flags));
}
TEST(ErrorsClassesAreStrict) {
const char* context_data[][2] = {{"", ""},
{"(", ");"},
{NULL, NULL}};
const char* class_body_data[] = {
"class C { method() { with ({}) {} } }",
"class C extends function() { with ({}) {} } {}",
NULL};
static const ParserFlag always_flags[] = {
kAllowClasses,
kAllowHarmonyObjectLiterals
};
RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
always_flags, arraysize(always_flags));
}
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