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 {
// 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")
......
......@@ -173,10 +173,12 @@ void FunctionLiteral::InitializeSharedInfo(
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) {
......@@ -189,11 +191,13 @@ ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone,
}
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;
}
......@@ -1090,6 +1094,7 @@ DONT_OPTIMIZE_NODE(ModuleUrl)
DONT_OPTIMIZE_NODE(ModuleStatement)
DONT_OPTIMIZE_NODE(WithStatement)
DONT_OPTIMIZE_NODE(DebuggerStatement)
DONT_OPTIMIZE_NODE(ClassLiteral)
DONT_OPTIMIZE_NODE(NativeFunctionLiteral)
DONT_OPTIMIZE_NODE(SuperReference)
......
......@@ -40,12 +40,12 @@ namespace internal {
// 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) \
......@@ -73,28 +73,29 @@ namespace internal {
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) \
......@@ -1459,7 +1460,7 @@ class ObjectLiteralProperty FINAL : public ZoneObject {
};
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_; }
......@@ -1478,7 +1479,8 @@ class ObjectLiteralProperty FINAL : public ZoneObject {
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:
......@@ -1486,6 +1488,7 @@ class ObjectLiteralProperty FINAL : public ZoneObject {
Expression* value_;
Kind kind_;
bool emit_store_;
bool is_static_;
Handle<Map> receiver_type_;
};
......@@ -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 {
public:
DECLARE_NODE_TYPE(NativeFunctionLiteral)
......@@ -3300,16 +3337,17 @@ class AstNodeFactory FINAL BASE_EMBEDDED {
}
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.
}
......@@ -3465,6 +3503,17 @@ class AstNodeFactory FINAL BASE_EMBEDDED {
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) {
......
......@@ -812,6 +812,12 @@ void AstGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
}
void AstGraphBuilder::VisitClassLiteral(ClassLiteral* expr) {
// TODO(arv): Implement.
UNREACHABLE();
}
void AstGraphBuilder::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
UNREACHABLE();
}
......
......@@ -175,6 +175,8 @@ DEFINE_IMPLICATION(harmony, harmony_arrow_functions)
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)
......
......@@ -33,18 +33,22 @@ void BreakableStatementChecker::VisitVariableDeclaration(
VariableDeclaration* decl) {
}
void BreakableStatementChecker::VisitFunctionDeclaration(
FunctionDeclaration* decl) {
}
void BreakableStatementChecker::VisitModuleDeclaration(
ModuleDeclaration* decl) {
}
void BreakableStatementChecker::VisitImportDeclaration(
ImportDeclaration* decl) {
}
void BreakableStatementChecker::VisitExportDeclaration(
ExportDeclaration* decl) {
}
......@@ -178,6 +182,13 @@ void BreakableStatementChecker::VisitFunctionLiteral(FunctionLiteral* expr) {
}
void BreakableStatementChecker::VisitClassLiteral(ClassLiteral* expr) {
if (expr->extends() != NULL) {
Visit(expr->extends());
}
}
void BreakableStatementChecker::VisitNativeFunctionLiteral(
NativeFunctionLiteral* 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(
NativeFunctionLiteral* expr) {
Comment cmnt(masm_, "[ NativeFunctionLiteral");
......
......@@ -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(
NativeFunctionLiteral* expr) {
DCHECK(!HasStackOverflow());
......
......@@ -8,6 +8,7 @@ var kMessages = {
// 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
......@@ -139,6 +140,7 @@ var kMessages = {
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)"],
......
......@@ -1016,6 +1016,7 @@ template <class C> inline bool Is(Object* obj);
"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") \
......
......@@ -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) {
DCHECK(expression != NULL);
Property* property = expression->AsProperty();
......@@ -1136,6 +1146,8 @@ Statement* Parser::ParseModuleElement(ZoneList<const AstRawString*>* labels,
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:
......@@ -1475,6 +1487,10 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
result = ParseFunctionDeclaration(&names, CHECK_OK);
break;
case Token::CLASS:
result = ParseClassDeclaration(&names, CHECK_OK);
break;
case Token::VAR:
case Token::LET:
case Token::CONST:
......@@ -1537,10 +1553,13 @@ Statement* Parser::ParseBlockElement(ZoneList<const AstRawString*>* labels,
// 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:
......@@ -1652,6 +1671,9 @@ Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels,
return ParseFunctionDeclaration(NULL, ok);
}
case Token::CLASS:
return ParseClassDeclaration(NULL, ok);
case Token::DEBUGGER:
return ParseDebuggerStatement(ok);
......@@ -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) {
if (allow_harmony_scoping() && strict_mode() == STRICT) {
return ParseScopedBlock(labels, ok);
......
......@@ -363,6 +363,7 @@ class ParserTraits {
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;
......@@ -401,6 +402,10 @@ class ParserTraits {
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();
......@@ -518,6 +523,8 @@ class ParserTraits {
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() {
......@@ -705,6 +712,8 @@ class Parser : public ParserBase<ParserTraits> {
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,
......
......@@ -78,6 +78,12 @@ PreParserIdentifier PreParserTraits::GetSymbol(Scanner* scanner) {
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();
}
......@@ -178,6 +184,8 @@ PreParser::Statement PreParser::ParseSourceElement(bool* ok) {
switch (peek()) {
case Token::FUNCTION:
return ParseFunctionDeclaration(ok);
case Token::CLASS:
return ParseClassDeclaration(ok);
case Token::CONST:
return ParseVariableStatement(kSourceElement, ok);
case Token::LET:
......@@ -305,6 +313,9 @@ PreParser::Statement PreParser::ParseStatement(bool* ok) {
}
}
case Token::CLASS:
return ParseClassDeclaration(CHECK_OK);
case Token::DEBUGGER:
return ParseDebuggerStatement(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) {
// Block ::
// '{' Statement* '}'
......
......@@ -46,6 +46,7 @@ namespace internal {
// typedef Identifier;
// typedef Expression;
// typedef FunctionLiteral;
// typedef ClassLiteral;
// typedef ObjectLiteralProperty;
// typedef Literal;
// typedef ExpressionList;
......@@ -63,6 +64,7 @@ class ParserBase : public Traits {
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;
......@@ -480,10 +482,12 @@ class ParserBase : public Traits {
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);
......@@ -498,6 +502,10 @@ class ParserBase : public Traits {
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,
......@@ -612,10 +620,20 @@ class PreParserIdentifier {
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;
......@@ -638,7 +656,9 @@ class PreParserIdentifier {
kLetIdentifier,
kYieldIdentifier,
kEvalIdentifier,
kArgumentsIdentifier
kArgumentsIdentifier,
kPrototypeIdentifier,
kConstructorIdentifier
};
explicit PreParserIdentifier(Type type) : type_(type) {}
Type type_;
......@@ -927,6 +947,7 @@ class PreParserScope {
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.
......@@ -971,11 +992,12 @@ class PreParserFactory {
}
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,
......@@ -985,7 +1007,7 @@ class PreParserFactory {
int pos) {
return PreParserExpression::Default();
}
PreParserExpression NewVariableProxy(void* generator_variable) {
PreParserExpression NewVariableProxy(void* variable) {
return PreParserExpression::Default();
}
PreParserExpression NewProperty(PreParserExpression obj,
......@@ -1061,6 +1083,14 @@ class PreParserFactory {
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.
......@@ -1099,6 +1129,7 @@ class PreParserTraits {
typedef PreParserExpression Expression;
typedef PreParserExpression YieldExpression;
typedef PreParserExpression FunctionLiteral;
typedef PreParserExpression ClassLiteral;
typedef PreParserExpression ObjectLiteralProperty;
typedef PreParserExpression Literal;
typedef PreParserExpressionList ExpressionList;
......@@ -1125,6 +1156,14 @@ class PreParserTraits {
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();
......@@ -1245,6 +1284,12 @@ class PreParserTraits {
static PreParserExpression EmptyObjectLiteralProperty() {
return PreParserExpression::Default();
}
static PreParserExpression EmptyFunctionLiteral() {
return PreParserExpression::Default();
}
static PreParserExpression EmptyClassLiteral() {
return PreParserExpression::Default();
}
static PreParserExpressionList NullExpressionList() {
return PreParserExpressionList();
}
......@@ -1435,6 +1480,7 @@ class PreParser : public ParserBase<PreParserTraits> {
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);
......@@ -1708,6 +1754,7 @@ ParserBase<Traits>::ParsePrimaryExpression(bool* ok) {
// ArrayLiteral
// ObjectLiteral
// RegExpLiteral
// ClassLiteral
// '(' Expression ')'
int pos = peek_position();
......@@ -1778,6 +1825,23 @@ ParserBase<Traits>::ParsePrimaryExpression(bool* ok) {
}
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);
......@@ -1848,7 +1912,7 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral(
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:
......@@ -1857,27 +1921,35 @@ typename ParserBase<Traits>::IdentifierT ParserBase<Traits>::ParsePropertyName(
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));
......@@ -1887,6 +1959,13 @@ typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase<
} 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(
......@@ -1896,25 +1975,43 @@ typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase<
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);
......@@ -1927,7 +2024,7 @@ typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase<
? factory()->NewNumberLiteral(index, 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(
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
......@@ -2400,7 +2499,7 @@ template <class Traits>
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
......@@ -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>
typename ParserBase<Traits>::ExpressionT
ParserBase<Traits>::CheckAndRewriteReferenceExpression(
......
......@@ -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) {
Print("(");
PrintLiteral(node->name(), false);
......@@ -323,16 +338,22 @@ void PrettyPrinter::VisitObjectLiteral(ObjectLiteral* node) {
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++) {
......@@ -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) {
IndentedScope indent(this, "NATIVE FUNC LITERAL");
PrintLiteralIndented("NAME", node->name(), false);
......
......@@ -52,6 +52,7 @@ class PrettyPrinter: public AstVisitor {
void PrintDeclarations(ZoneList<Declaration*>* declarations);
void PrintFunctionLiteral(FunctionLiteral* function);
void PrintCaseClause(CaseClause* clause);
void PrintObjectLiteralProperty(ObjectLiteralProperty* property);
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
};
......
......@@ -902,70 +902,73 @@ uc32 Scanner::ScanIdentifierUnicodeEscape() {
// ----------------------------------------------------------------------------
// 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)
......
......@@ -653,7 +653,7 @@ class Scanner {
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_;
};
......
......@@ -148,10 +148,13 @@ namespace internal {
/* 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) \
\
......
......@@ -352,6 +352,9 @@ void AstTyper::VisitFunctionLiteral(FunctionLiteral* expr) {
}
void AstTyper::VisitClassLiteral(ClassLiteral* expr) {}
void AstTyper::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
}
......
......@@ -1448,9 +1448,15 @@ TEST(ParserSync) {
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) {
......@@ -1525,10 +1531,14 @@ void RunParserSyncTest(const char* context_data[][2],
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) {
......@@ -3537,3 +3547,405 @@ TEST(MethodDefinitionDuplicateProperty) {
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));
}
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