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
This commit is contained in:
parent
7062b8fb49
commit
7efd2eb144
@ -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")
|
||||
|
||||
|
||||
|
11
src/ast.cc
11
src/ast.cc
@ -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)
|
||||
|
||||
|
119
src/ast.h
119
src/ast.h
@ -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* '}'
|
||||
|
210
src/preparser.h
210
src/preparser.h
@ -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();
|
||||
};
|
||||
|
131
src/scanner.cc
131
src/scanner.cc
@ -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));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user