// For generating string constants.
-#define STRING_CONSTANTS(F) \
- F(anonymous_function, "(anonymous function)") \
- F(arguments, "arguments") \
- F(done, "done") \
- F(dot, ".") \
- F(dot_for, ".for") \
- F(dot_generator, ".generator") \
- F(dot_generator_object, ".generator_object") \
- F(dot_iterator, ".iterator") \
- F(dot_module, ".module") \
- F(dot_result, ".result") \
- F(empty, "") \
- F(eval, "eval") \
+#define STRING_CONSTANTS(F) \
+ F(anonymous_function, "(anonymous function)") \
+ F(arguments, "arguments") \
+ F(constructor, "constructor") \
+ F(done, "done") \
+ F(dot, ".") \
+ F(dot_for, ".for") \
+ F(dot_generator, ".generator") \
+ F(dot_generator_object, ".generator_object") \
+ F(dot_iterator, ".iterator") \
+ F(dot_module, ".module") \
+ F(dot_result, ".result") \
+ F(empty, "") \
+ F(eval, "eval") \
F(initialize_const_global, "initializeConstGlobal") \
- F(initialize_var_global, "initializeVarGlobal") \
- F(make_reference_error, "MakeReferenceError") \
- F(make_syntax_error, "MakeSyntaxError") \
- F(make_type_error, "MakeTypeError") \
- F(module, "module") \
- F(native, "native") \
- F(next, "next") \
- F(proto, "__proto__") \
- F(prototype, "prototype") \
- F(this, "this") \
- F(use_asm, "use asm") \
- F(use_strict, "use strict") \
+ F(initialize_var_global, "initializeVarGlobal") \
+ F(make_reference_error, "MakeReferenceError") \
+ F(make_syntax_error, "MakeSyntaxError") \
+ F(make_type_error, "MakeTypeError") \
+ F(module, "module") \
+ F(native, "native") \
+ F(next, "next") \
+ F(proto, "__proto__") \
+ F(prototype, "prototype") \
+ F(this, "this") \
+ F(use_asm, "use asm") \
+ F(use_strict, "use strict") \
F(value, "value")
ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone,
AstValueFactory* ast_value_factory,
- Literal* key, Expression* value) {
+ Literal* key, Expression* value,
+ bool is_static) {
emit_store_ = true;
key_ = key;
value_ = value;
+ is_static_ = is_static;
if (key->raw_value()->EqualsString(ast_value_factory->proto_string())) {
kind_ = PROTOTYPE;
} else if (value_->AsMaterializedLiteral() != NULL) {
}
-ObjectLiteralProperty::ObjectLiteralProperty(
- Zone* zone, bool is_getter, FunctionLiteral* value) {
+ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone, bool is_getter,
+ FunctionLiteral* value,
+ bool is_static) {
emit_store_ = true;
value_ = value;
kind_ = is_getter ? GETTER : SETTER;
+ is_static_ = is_static;
}
DONT_OPTIMIZE_NODE(ModuleStatement)
DONT_OPTIMIZE_NODE(WithStatement)
DONT_OPTIMIZE_NODE(DebuggerStatement)
+DONT_OPTIMIZE_NODE(ClassLiteral)
DONT_OPTIMIZE_NODE(NativeFunctionLiteral)
DONT_OPTIMIZE_NODE(SuperReference)
// Nodes of the abstract syntax tree. Only concrete classes are
// enumerated here.
-#define DECLARATION_NODE_LIST(V) \
- V(VariableDeclaration) \
- V(FunctionDeclaration) \
- V(ModuleDeclaration) \
- V(ImportDeclaration) \
- V(ExportDeclaration) \
+#define DECLARATION_NODE_LIST(V) \
+ V(VariableDeclaration) \
+ V(FunctionDeclaration) \
+ V(ModuleDeclaration) \
+ V(ImportDeclaration) \
+ V(ExportDeclaration)
#define MODULE_NODE_LIST(V) \
V(ModuleLiteral) \
V(TryFinallyStatement) \
V(DebuggerStatement)
-#define EXPRESSION_NODE_LIST(V) \
- V(FunctionLiteral) \
- V(NativeFunctionLiteral) \
- V(Conditional) \
- V(VariableProxy) \
- V(Literal) \
- V(RegExpLiteral) \
- V(ObjectLiteral) \
- V(ArrayLiteral) \
- V(Assignment) \
- V(Yield) \
- V(Throw) \
- V(Property) \
- V(Call) \
- V(CallNew) \
- V(CallRuntime) \
- V(UnaryOperation) \
- V(CountOperation) \
- V(BinaryOperation) \
- V(CompareOperation) \
- V(ThisFunction) \
- V(SuperReference) \
+#define EXPRESSION_NODE_LIST(V) \
+ V(FunctionLiteral) \
+ V(ClassLiteral) \
+ V(NativeFunctionLiteral) \
+ V(Conditional) \
+ V(VariableProxy) \
+ V(Literal) \
+ V(RegExpLiteral) \
+ V(ObjectLiteral) \
+ V(ArrayLiteral) \
+ V(Assignment) \
+ V(Yield) \
+ V(Throw) \
+ V(Property) \
+ V(Call) \
+ V(CallNew) \
+ V(CallRuntime) \
+ V(UnaryOperation) \
+ V(CountOperation) \
+ V(BinaryOperation) \
+ V(CompareOperation) \
+ V(ThisFunction) \
+ V(SuperReference) \
V(CaseClause)
#define AST_NODE_LIST(V) \
};
ObjectLiteralProperty(Zone* zone, AstValueFactory* ast_value_factory,
- Literal* key, Expression* value);
+ Literal* key, Expression* value, bool is_static);
Literal* key() { return key_; }
Expression* value() { return value_; }
protected:
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; }
private:
Expression* value_;
Kind kind_;
bool emit_store_;
+ bool is_static_;
Handle<Map> receiver_type_;
};
};
+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 {
public:
DECLARE_NODE_TYPE(NativeFunctionLiteral)
}
ObjectLiteral::Property* NewObjectLiteralProperty(Literal* key,
- Expression* value) {
- return new (zone_)
- ObjectLiteral::Property(zone_, ast_value_factory_, key, value);
+ Expression* value,
+ bool is_static) {
+ return new (zone_) ObjectLiteral::Property(zone_, ast_value_factory_, key,
+ value, is_static);
}
ObjectLiteral::Property* NewObjectLiteralProperty(bool is_getter,
FunctionLiteral* value,
- int pos) {
+ int pos, bool is_static) {
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));
return prop; // Not an AST node, will not be visited.
}
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,
v8::Extension* extension,
int pos) {
}
+void AstGraphBuilder::VisitClassLiteral(ClassLiteral* expr) {
+ // TODO(arv): Implement.
+ UNREACHABLE();
+}
+
+
void AstGraphBuilder::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
UNREACHABLE();
}
DEFINE_IMPLICATION(harmony, harmony_classes)
DEFINE_IMPLICATION(harmony, harmony_object_literals)
DEFINE_IMPLICATION(harmony_modules, harmony_scoping)
+DEFINE_IMPLICATION(harmony_classes, harmony_scoping)
+DEFINE_IMPLICATION(harmony_classes, harmony_object_literals)
DEFINE_IMPLICATION(harmony, es_staging)
VariableDeclaration* decl) {
}
+
void BreakableStatementChecker::VisitFunctionDeclaration(
FunctionDeclaration* decl) {
}
+
void BreakableStatementChecker::VisitModuleDeclaration(
ModuleDeclaration* decl) {
}
+
void BreakableStatementChecker::VisitImportDeclaration(
ImportDeclaration* decl) {
}
+
void BreakableStatementChecker::VisitExportDeclaration(
ExportDeclaration* decl) {
}
}
+void BreakableStatementChecker::VisitClassLiteral(ClassLiteral* expr) {
+ if (expr->extends() != NULL) {
+ Visit(expr->extends());
+ }
+}
+
+
void BreakableStatementChecker::VisitNativeFunctionLiteral(
NativeFunctionLiteral* 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(
NativeFunctionLiteral* expr) {
Comment cmnt(masm_, "[ NativeFunctionLiteral");
}
+void HOptimizedGraphBuilder::VisitClassLiteral(ClassLiteral* lit) {
+ DCHECK(!HasStackOverflow());
+ DCHECK(current_block() != NULL);
+ DCHECK(current_block()->HasPredecessor());
+ return Bailout(kClassLiteral);
+}
+
+
void HOptimizedGraphBuilder::VisitNativeFunctionLiteral(
NativeFunctionLiteral* expr) {
DCHECK(!HasStackOverflow());
// Error
cyclic_proto: ["Cyclic __proto__ value"],
code_gen_from_strings: ["%0"],
+ constructor_special_method: ["Class constructor may not be an accessor"],
generator_running: ["Generator is already running"],
generator_finished: ["Generator has already finished"],
// TypeError
array_indexof_not_defined: ["Array.getIndexOf: Argument undefined"],
object_not_extensible: ["Can't add property ", "%0", ", object is not extensible"],
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_eval_arguments: ["Unexpected eval or arguments in strict mode"],
too_many_arguments: ["Too many arguments in function call (only 65535 allowed)"],
"Call to a JavaScript runtime function") \
V(kCannotTranslatePositionInChangedArea, \
"Cannot translate position in changed area") \
+ V(kClassLiteral, "Class literal") \
V(kCodeGenerationFailed, "Code generation failed") \
V(kCodeObjectNotProperlyPatched, "Code object not properly patched") \
V(kCompoundAssignmentToLookupSlot, "Compound assignment to lookup slot") \
}
+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) {
DCHECK(expression != NULL);
Property* property = expression->AsProperty();
switch (peek()) {
case Token::FUNCTION:
return ParseFunctionDeclaration(NULL, ok);
+ case Token::CLASS:
+ return ParseClassDeclaration(NULL, ok);
case Token::IMPORT:
return ParseImportDeclaration(ok);
case Token::EXPORT:
result = ParseFunctionDeclaration(&names, CHECK_OK);
break;
+ case Token::CLASS:
+ result = ParseClassDeclaration(&names, CHECK_OK);
+ break;
+
case Token::VAR:
case Token::LET:
case Token::CONST:
// LetDeclaration
// ConstDeclaration
// GeneratorDeclaration
+ // ClassDeclaration
switch (peek()) {
case Token::FUNCTION:
return ParseFunctionDeclaration(NULL, ok);
+ case Token::CLASS:
+ return ParseClassDeclaration(NULL, ok);
case Token::CONST:
return ParseVariableStatement(kModuleElement, NULL, ok);
case Token::LET:
return ParseFunctionDeclaration(NULL, ok);
}
+ case Token::CLASS:
+ return ParseClassDeclaration(NULL, ok);
+
case Token::DEBUGGER:
return ParseDebuggerStatement(ok);
}
+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) {
if (allow_harmony_scoping() && strict_mode() == STRICT) {
return ParseScopedBlock(labels, ok);
typedef v8::internal::Expression* Expression;
typedef Yield* YieldExpression;
typedef v8::internal::FunctionLiteral* FunctionLiteral;
+ typedef v8::internal::ClassLiteral* ClassLiteral;
typedef v8::internal::Literal* Literal;
typedef ObjectLiteral::Property* ObjectLiteralProperty;
typedef ZoneList<v8::internal::Expression*>* ExpressionList;
static bool IsIdentifier(Expression* expression);
+ bool IsPrototype(const AstRawString* identifier) const;
+
+ bool IsConstructor(const AstRawString* identifier) const;
+
static const AstRawString* AsIdentifier(Expression* expression) {
DCHECK(IsIdentifier(expression));
return expression->AsVariableProxy()->raw_name();
return NULL;
}
static ObjectLiteralProperty* EmptyObjectLiteralProperty() { return NULL; }
+ static FunctionLiteral* EmptyFunctionLiteral() { return NULL; }
+ static ClassLiteral* EmptyClassLiteral() { return NULL; }
// Used in error return values.
static ZoneList<Expression*>* NullExpressionList() {
Statement* ParseStatement(ZoneList<const AstRawString*>* labels, bool* ok);
Statement* ParseFunctionDeclaration(ZoneList<const AstRawString*>* names,
bool* ok);
+ Statement* ParseClassDeclaration(ZoneList<const AstRawString*>* names,
+ bool* ok);
Statement* ParseNativeDeclaration(bool* ok);
Block* ParseBlock(ZoneList<const AstRawString*>* labels, bool* ok);
Block* ParseVariableStatement(VariableDeclarationContext var_context,
if (scanner->UnescapedLiteralMatches("arguments", 9)) {
return PreParserIdentifier::Arguments();
}
+ if (scanner->UnescapedLiteralMatches("prototype", 9)) {
+ return PreParserIdentifier::Prototype();
+ }
+ if (scanner->UnescapedLiteralMatches("constructor", 11)) {
+ return PreParserIdentifier::Constructor();
+ }
return PreParserIdentifier::Default();
}
switch (peek()) {
case Token::FUNCTION:
return ParseFunctionDeclaration(ok);
+ case Token::CLASS:
+ return ParseClassDeclaration(ok);
case Token::CONST:
return ParseVariableStatement(kSourceElement, ok);
case Token::LET:
}
}
+ case Token::CLASS:
+ return ParseClassDeclaration(CHECK_OK);
+
case Token::DEBUGGER:
return ParseDebuggerStatement(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) {
// Block ::
// '{' Statement* '}'
// typedef Identifier;
// typedef Expression;
// typedef FunctionLiteral;
+// typedef ClassLiteral;
// typedef ObjectLiteralProperty;
// typedef Literal;
// typedef ExpressionList;
typedef typename Traits::Type::Expression ExpressionT;
typedef typename Traits::Type::Identifier IdentifierT;
typedef typename Traits::Type::FunctionLiteral FunctionLiteralT;
+ typedef typename Traits::Type::ClassLiteral ClassLiteralT;
typedef typename Traits::Type::Literal LiteralT;
typedef typename Traits::Type::ObjectLiteralProperty ObjectLiteralPropertyT;
ExpressionT ParsePrimaryExpression(bool* ok);
ExpressionT ParseExpression(bool accept_IN, bool* ok);
ExpressionT ParseArrayLiteral(bool* ok);
+ IdentifierT ParsePropertyName(bool* is_get, bool* is_set, bool* is_static,
+ bool* ok);
ExpressionT ParseObjectLiteral(bool* ok);
ObjectLiteralPropertyT ParsePropertyDefinition(ObjectLiteralChecker* checker,
+ bool in_class, bool is_static,
bool* ok);
- IdentifierT ParsePropertyName(bool* is_getter, bool* is_setter, bool* ok);
typename Traits::Type::ExpressionList ParseArguments(bool* ok);
ExpressionT ParseAssignmentExpression(bool accept_IN, bool* ok);
ExpressionT ParseYieldExpression(bool* ok);
bool* ok);
ExpressionT ParseArrowFunctionLiteral(int start_pos, ExpressionT params_ast,
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
// left-hand side of assignments). Although ruled out by ECMA as early errors,
static PreParserIdentifier Yield() {
return PreParserIdentifier(kYieldIdentifier);
}
+ static PreParserIdentifier Prototype() {
+ return PreParserIdentifier(kPrototypeIdentifier);
+ }
+ static PreParserIdentifier Constructor() {
+ return PreParserIdentifier(kConstructorIdentifier);
+ }
bool IsEval() const { return type_ == kEvalIdentifier; }
bool IsArguments() const { return type_ == kArgumentsIdentifier; }
- bool IsEvalOrArguments() const { return type_ >= kEvalIdentifier; }
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 IsFutureStrictReserved() const {
return type_ == kFutureStrictReservedIdentifier;
kLetIdentifier,
kYieldIdentifier,
kEvalIdentifier,
- kArgumentsIdentifier
+ kArgumentsIdentifier,
+ kPrototypeIdentifier,
+ kConstructorIdentifier
};
explicit PreParserIdentifier(Type type) : type_(type) {}
Type type_;
ScopeType type() { return scope_type_; }
StrictMode strict_mode() const { return 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,
// things cannot get lazier than that.
}
PreParserExpression NewObjectLiteralProperty(bool is_getter,
PreParserExpression value,
- int pos) {
+ int pos, bool is_static) {
return PreParserExpression::Default();
}
PreParserExpression NewObjectLiteralProperty(PreParserExpression key,
- PreParserExpression value) {
+ PreParserExpression value,
+ bool is_static) {
return PreParserExpression::Default();
}
PreParserExpression NewObjectLiteral(PreParserExpressionList properties,
int pos) {
return PreParserExpression::Default();
}
- PreParserExpression NewVariableProxy(void* generator_variable) {
+ PreParserExpression NewVariableProxy(void* variable) {
return PreParserExpression::Default();
}
PreParserExpression NewProperty(PreParserExpression obj,
int position) {
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
// dummy method right in this class.
typedef PreParserExpression Expression;
typedef PreParserExpression YieldExpression;
typedef PreParserExpression FunctionLiteral;
+ typedef PreParserExpression ClassLiteral;
typedef PreParserExpression ObjectLiteralProperty;
typedef PreParserExpression Literal;
typedef PreParserExpressionList ExpressionList;
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".
static bool IsThisProperty(PreParserExpression expression) {
return expression.IsThisProperty();
static PreParserExpression EmptyObjectLiteralProperty() {
return PreParserExpression::Default();
}
+ static PreParserExpression EmptyFunctionLiteral() {
+ return PreParserExpression::Default();
+ }
+ static PreParserExpression EmptyClassLiteral() {
+ return PreParserExpression::Default();
+ }
static PreParserExpressionList NullExpressionList() {
return PreParserExpressionList();
}
SourceElements ParseSourceElements(int end_token, bool* ok);
Statement ParseStatement(bool* ok);
Statement ParseFunctionDeclaration(bool* ok);
+ Statement ParseClassDeclaration(bool* ok);
Statement ParseBlock(bool* ok);
Statement ParseVariableStatement(VariableDeclarationContext var_context,
bool* ok);
// ArrayLiteral
// ObjectLiteral
// RegExpLiteral
+ // ClassLiteral
// '(' Expression ')'
int pos = peek_position();
}
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:
if (allow_natives_syntax() || extension_ != NULL) {
result = this->ParseV8Intrinsic(CHECK_OK);
template <class Traits>
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();
switch (next) {
case Token::STRING:
case Token::NUMBER:
Consume(Token::NUMBER);
return this->GetNumberAsSymbol(scanner_);
+ case Token::STATIC:
+ *is_static = true;
+ // Fall through.
default:
- return ParseIdentifierNameOrGetOrSet(is_getter, is_setter,
- CHECK_OK_CUSTOM(EmptyIdentifier));
+ return ParseIdentifierNameOrGetOrSet(is_get, is_set, ok);
}
+ UNREACHABLE();
+ return this->EmptyIdentifier();
}
template <class Traits>
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.
ExpressionT value = this->EmptyExpression();
- bool is_getter = false;
- bool is_setter = false;
+ bool is_get = false;
+ bool is_set = false;
+ bool name_is_static = false;
Token::Value name_token = peek();
int next_pos = peek_position();
- IdentifierT name = ParsePropertyName(
- &is_getter, &is_setter, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+ IdentifierT name =
+ ParsePropertyName(&is_get, &is_set, &name_is_static,
+ CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+
if (fni_ != NULL) this->PushLiteralName(fni_, name);
- if (peek() == Token::COLON) {
+ if (!in_class && peek() == Token::COLON) {
// PropertyDefinition : PropertyName ':' AssignmentExpression
checker->CheckProperty(name_token, kValueProperty,
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
} else if (allow_harmony_object_literals_ && peek() == Token::LPAREN) {
// Concise Method
+
+ if (is_static && this->IsPrototype(name)) {
+ ReportMessageAt(scanner()->location(), "static_prototype");
+ *ok = false;
+ return this->EmptyObjectLiteralProperty();
+ }
+
checker->CheckProperty(name_token, kValueProperty,
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
value = this->ParseFunctionLiteral(
FunctionLiteral::ANONYMOUS_EXPRESSION, FunctionLiteral::NORMAL_ARITY,
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
bool dont_care = false;
name_token = peek();
- name = ParsePropertyName(&dont_care, &dont_care,
+ name = ParsePropertyName(&dont_care, &dont_care, &dont_care,
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+
// 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,
- is_getter ? kGetterProperty : kSetterProperty,
+ is_get ? kGetterProperty : kSetterProperty,
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
+
typename Traits::Type::FunctionLiteral value = this->ParseFunctionLiteral(
name, scanner()->location(),
false, // reserved words are allowed here
FunctionKind::kNormalFunction, RelocInfo::kNoPosition,
FunctionLiteral::ANONYMOUS_EXPRESSION,
- is_getter ? FunctionLiteral::GETTER_ARITY
- : FunctionLiteral::SETTER_ARITY,
+ is_get ? FunctionLiteral::GETTER_ARITY : FunctionLiteral::SETTER_ARITY,
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
- return factory()->NewObjectLiteralProperty(is_getter, value, next_pos);
+ return factory()->NewObjectLiteralProperty(is_get, value, next_pos,
+ is_static);
} else {
Token::Value next = Next();
ReportUnexpectedToken(next);
? factory()->NewNumberLiteral(index, next_pos)
: factory()->NewStringLiteral(name, next_pos);
- return factory()->NewObjectLiteralProperty(key, value);
+ return factory()->NewObjectLiteralProperty(key, value, is_static);
}
while (peek() != Token::RBRACE) {
if (fni_ != NULL) fni_->Enter();
+ const bool in_class = false;
+ const bool is_static = false;
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
// pretenure the literal so it can be added as a constant function
typename ParserBase<Traits>::ExpressionT
ParserBase<Traits>::ParseMemberExpression(bool* ok) {
// MemberExpression ::
- // (PrimaryExpression | FunctionLiteral)
+ // (PrimaryExpression | FunctionLiteral | ClassLiteral)
// ('[' Expression ']' | '.' Identifier | Arguments)*
// The '[' Expression ']' and '.' Identifier parts are parsed by
}
+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>
typename ParserBase<Traits>::ExpressionT
ParserBase<Traits>::CheckAndRewriteReferenceExpression(
}
+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) {
Print("(");
PrintLiteral(node->name(), false);
Print("{ ");
for (int i = 0; i < node->properties()->length(); i++) {
if (i != 0) Print(",");
- ObjectLiteral::Property* property = node->properties()->at(i);
- Print(" ");
- Visit(property->key());
- Print(": ");
- Visit(property->value());
+ PrintObjectLiteralProperty(node->properties()->at(i));
}
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) {
Print("[ ");
for (int i = 0; i < node->values()->length(); i++) {
}
+void AstPrinter::VisitClassLiteral(ClassLiteral* node) {
+ IndentedScope indent(this, "CLASS LITERAL");
+ PrintLiteralIndented("NAME", node->name(), false);
+}
+
+
void AstPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) {
IndentedScope indent(this, "NATIVE FUNC LITERAL");
PrintLiteralIndented("NAME", node->name(), false);
void PrintDeclarations(ZoneList<Declaration*>* declarations);
void PrintFunctionLiteral(FunctionLiteral* function);
void PrintCaseClause(CaseClause* clause);
+ void PrintObjectLiteralProperty(ObjectLiteralProperty* property);
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
};
// ----------------------------------------------------------------------------
// Keyword Matcher
-#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \
- KEYWORD_GROUP('b') \
- KEYWORD("break", Token::BREAK) \
- KEYWORD_GROUP('c') \
- KEYWORD("case", Token::CASE) \
- KEYWORD("catch", Token::CATCH) \
- KEYWORD("class", Token::FUTURE_RESERVED_WORD) \
- KEYWORD("const", Token::CONST) \
- KEYWORD("continue", Token::CONTINUE) \
- KEYWORD_GROUP('d') \
- KEYWORD("debugger", Token::DEBUGGER) \
- KEYWORD("default", Token::DEFAULT) \
- KEYWORD("delete", Token::DELETE) \
- KEYWORD("do", Token::DO) \
- KEYWORD_GROUP('e') \
- KEYWORD("else", Token::ELSE) \
- KEYWORD("enum", Token::FUTURE_RESERVED_WORD) \
- KEYWORD("export", \
- harmony_modules ? Token::EXPORT : Token::FUTURE_RESERVED_WORD) \
- KEYWORD("extends", Token::FUTURE_RESERVED_WORD) \
- KEYWORD_GROUP('f') \
- KEYWORD("false", Token::FALSE_LITERAL) \
- KEYWORD("finally", Token::FINALLY) \
- KEYWORD("for", Token::FOR) \
- KEYWORD("function", Token::FUNCTION) \
- KEYWORD_GROUP('i') \
- KEYWORD("if", Token::IF) \
- KEYWORD("implements", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD("import", \
- harmony_modules ? Token::IMPORT : Token::FUTURE_RESERVED_WORD) \
- KEYWORD("in", Token::IN) \
- KEYWORD("instanceof", Token::INSTANCEOF) \
- KEYWORD("interface", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD_GROUP('l') \
- KEYWORD("let", \
- harmony_scoping ? Token::LET : Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD_GROUP('n') \
- KEYWORD("new", Token::NEW) \
- KEYWORD("null", Token::NULL_LITERAL) \
- KEYWORD_GROUP('p') \
- KEYWORD("package", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD("private", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD("protected", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD("public", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD_GROUP('r') \
- KEYWORD("return", Token::RETURN) \
- KEYWORD_GROUP('s') \
- KEYWORD("static", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD("super", \
- harmony_classes ? Token::SUPER : Token::FUTURE_RESERVED_WORD) \
- KEYWORD("switch", Token::SWITCH) \
- KEYWORD_GROUP('t') \
- KEYWORD("this", Token::THIS) \
- KEYWORD("throw", Token::THROW) \
- KEYWORD("true", Token::TRUE_LITERAL) \
- KEYWORD("try", Token::TRY) \
- KEYWORD("typeof", Token::TYPEOF) \
- KEYWORD_GROUP('v') \
- KEYWORD("var", Token::VAR) \
- KEYWORD("void", Token::VOID) \
- KEYWORD_GROUP('w') \
- KEYWORD("while", Token::WHILE) \
- KEYWORD("with", Token::WITH) \
- KEYWORD_GROUP('y') \
+#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \
+ KEYWORD_GROUP('b') \
+ KEYWORD("break", Token::BREAK) \
+ KEYWORD_GROUP('c') \
+ KEYWORD("case", Token::CASE) \
+ KEYWORD("catch", Token::CATCH) \
+ KEYWORD("class", \
+ harmony_classes ? Token::CLASS : Token::FUTURE_RESERVED_WORD) \
+ KEYWORD("const", Token::CONST) \
+ KEYWORD("continue", Token::CONTINUE) \
+ KEYWORD_GROUP('d') \
+ KEYWORD("debugger", Token::DEBUGGER) \
+ KEYWORD("default", Token::DEFAULT) \
+ KEYWORD("delete", Token::DELETE) \
+ KEYWORD("do", Token::DO) \
+ KEYWORD_GROUP('e') \
+ KEYWORD("else", Token::ELSE) \
+ KEYWORD("enum", Token::FUTURE_RESERVED_WORD) \
+ KEYWORD("export", \
+ harmony_modules ? Token::EXPORT : Token::FUTURE_RESERVED_WORD) \
+ KEYWORD("extends", \
+ harmony_classes ? Token::EXTENDS : Token::FUTURE_RESERVED_WORD) \
+ KEYWORD_GROUP('f') \
+ KEYWORD("false", Token::FALSE_LITERAL) \
+ KEYWORD("finally", Token::FINALLY) \
+ KEYWORD("for", Token::FOR) \
+ KEYWORD("function", Token::FUNCTION) \
+ KEYWORD_GROUP('i') \
+ KEYWORD("if", Token::IF) \
+ KEYWORD("implements", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("import", \
+ harmony_modules ? Token::IMPORT : Token::FUTURE_RESERVED_WORD) \
+ KEYWORD("in", Token::IN) \
+ KEYWORD("instanceof", Token::INSTANCEOF) \
+ KEYWORD("interface", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD_GROUP('l') \
+ KEYWORD("let", \
+ harmony_scoping ? Token::LET : Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD_GROUP('n') \
+ KEYWORD("new", Token::NEW) \
+ KEYWORD("null", Token::NULL_LITERAL) \
+ KEYWORD_GROUP('p') \
+ KEYWORD("package", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("private", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("protected", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("public", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD_GROUP('r') \
+ KEYWORD("return", Token::RETURN) \
+ KEYWORD_GROUP('s') \
+ KEYWORD("static", harmony_classes ? Token::STATIC \
+ : Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("super", \
+ harmony_classes ? Token::SUPER : Token::FUTURE_RESERVED_WORD) \
+ KEYWORD("switch", Token::SWITCH) \
+ KEYWORD_GROUP('t') \
+ KEYWORD("this", Token::THIS) \
+ KEYWORD("throw", Token::THROW) \
+ KEYWORD("true", Token::TRUE_LITERAL) \
+ KEYWORD("try", Token::TRY) \
+ KEYWORD("typeof", Token::TYPEOF) \
+ KEYWORD_GROUP('v') \
+ KEYWORD("var", Token::VAR) \
+ KEYWORD("void", Token::VOID) \
+ KEYWORD_GROUP('w') \
+ KEYWORD("while", Token::WHILE) \
+ KEYWORD("with", Token::WITH) \
+ KEYWORD_GROUP('y') \
KEYWORD("yield", Token::YIELD)
bool harmony_modules_;
// Whether we scan 0o777 and 0b111 as numbers.
bool harmony_numeric_literals_;
- // Whether we scan 'super' as keyword.
+ // Whether we scan 'class', 'extends', 'static' and 'super' as keywords.
bool harmony_classes_;
};
/* Future reserved words (ECMA-262, section 7.6.1.2). */ \
T(FUTURE_RESERVED_WORD, NULL, 0) \
T(FUTURE_STRICT_RESERVED_WORD, NULL, 0) \
+ K(CLASS, "class", 0) \
K(CONST, "const", 0) \
K(EXPORT, "export", 0) \
+ K(EXTENDS, "extends", 0) \
K(IMPORT, "import", 0) \
K(LET, "let", 0) \
+ K(STATIC, "static", 0) \
K(YIELD, "yield", 0) \
K(SUPER, "super", 0) \
\
}
+void AstTyper::VisitClassLiteral(ClassLiteral* expr) {}
+
+
void AstTyper::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
}
i::GetCurrentStackPosition() - 128 * 1024);
static const ParserFlag flags1[] = {
- kAllowLazy, kAllowHarmonyScoping,
- kAllowModules, kAllowArrowFunctions,
- kAllowHarmonyNumericLiterals, kAllowHarmonyObjectLiterals};
+ kAllowArrowFunctions,
+ kAllowClasses,
+ kAllowHarmonyNumericLiterals,
+ kAllowHarmonyObjectLiterals,
+ kAllowHarmonyScoping,
+ kAllowLazy,
+ kAllowModules,
+ };
+
for (int i = 0; context_data[i][0] != NULL; ++i) {
for (int j = 0; statement_data[j] != NULL; ++j) {
for (int k = 0; termination_data[k] != NULL; ++k) {
i::GetCurrentStackPosition() - 128 * 1024);
static const ParserFlag default_flags[] = {
- kAllowArrowFunctions, kAllowClasses,
- kAllowHarmonyNumericLiterals, kAllowHarmonyObjectLiterals,
- kAllowHarmonyScoping, kAllowLazy,
- kAllowModules, kAllowNativesSyntax,
+ kAllowArrowFunctions,
+ kAllowClasses,
+ kAllowHarmonyNumericLiterals,
+ kAllowHarmonyObjectLiterals,
+ kAllowHarmonyScoping,
+ kAllowLazy,
+ kAllowModules,
+ kAllowNativesSyntax,
};
ParserFlag* generated_flags = NULL;
if (flags == NULL) {
RunParserSyncTest(context_data, params_data, kError, NULL, 0,
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));
+}