Index: src/preparser.h |
diff --git a/src/preparser.h b/src/preparser.h |
index b24c0728477a9a9bff8cabfb7c0d6a2d1188605d..0147caf5d134e312bc5fd49754d7c57c8d19f866 100644 |
--- a/src/preparser.h |
+++ b/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( |