Index: src/preparser.h |
diff --git a/src/preparser.h b/src/preparser.h |
index 15887bae08234a65b024940f0942750840630075..c1355ab984a7709797675ba73f6dbefb4b1872fc 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; |
@@ -483,10 +485,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); |
@@ -501,6 +505,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, |
@@ -616,10 +624,18 @@ 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; } |
marja
2014/09/11 09:40:58
This looks incorrect now, because you're adding mo
arv (Not doing code reviews)
2014/09/11 18:24:42
Oops.
|
bool IsYield() const { return type_ == kYieldIdentifier; } |
+ bool IsPrototype() const { return type_ >= kPrototypeIdentifier; } |
marja
2014/09/11 09:40:58
Why >= ? And in case somebody adds new enum values
arv (Not doing code reviews)
2014/09/11 18:24:42
Ooops here too.
|
+ bool IsConstructor() const { return type_ >= kConstructorIdentifier; } |
bool IsFutureReserved() const { return type_ == kFutureReservedIdentifier; } |
bool IsFutureStrictReserved() const { |
return type_ == kFutureStrictReservedIdentifier; |
@@ -642,7 +658,9 @@ class PreParserIdentifier { |
kLetIdentifier, |
kYieldIdentifier, |
kEvalIdentifier, |
- kArgumentsIdentifier |
+ kArgumentsIdentifier, |
+ kPrototypeIdentifier, |
+ kConstructorIdentifier |
}; |
explicit PreParserIdentifier(Type type) : type_(type) {} |
Type type_; |
@@ -869,6 +887,10 @@ class PreParserStatement { |
return PreParserStatement(kFunctionDeclaration); |
} |
+ static PreParserStatement ClassDeclaration() { |
+ return PreParserStatement(kClassDeclaration); |
+ } |
+ |
// Creates expression statement from expression. |
// Preserves being an unparenthesized string literal, possibly |
// "use strict". |
@@ -895,12 +917,15 @@ class PreParserStatement { |
return code_ == kFunctionDeclaration; |
} |
+ bool IsClassDeclaration() { return code_ == kClassDeclaration; } |
+ |
private: |
enum Type { |
kUnknownStatement, |
kStringLiteralExpressionStatement, |
kUseStrictExpressionStatement, |
- kFunctionDeclaration |
+ kFunctionDeclaration, |
+ kClassDeclaration |
}; |
explicit PreParserStatement(Type code) : code_(code) {} |
@@ -975,11 +1000,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, |
@@ -1065,6 +1091,13 @@ class PreParserFactory { |
int position) { |
return PreParserExpression::Default(); |
} |
+ PreParserExpression NewClassLiteral(PreParserIdentifier name, |
+ PreParserExpression extends, |
+ 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. |
@@ -1103,6 +1136,7 @@ class PreParserTraits { |
typedef PreParserExpression Expression; |
typedef PreParserExpression YieldExpression; |
typedef PreParserExpression FunctionLiteral; |
+ typedef PreParserExpression ClassLiteral; |
typedef PreParserExpression ObjectLiteralProperty; |
typedef PreParserExpression Literal; |
typedef PreParserExpressionList ExpressionList; |
@@ -1129,6 +1163,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(); |
@@ -1249,6 +1291,9 @@ class PreParserTraits { |
static PreParserExpression EmptyObjectLiteralProperty() { |
return PreParserExpression::Default(); |
} |
+ static PreParserExpression EmptyClassLiteral() { |
+ return PreParserExpression::Default(); |
+ } |
static PreParserExpressionList NullExpressionList() { |
return PreParserExpressionList(); |
} |
@@ -1439,6 +1484,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); |
@@ -1712,6 +1758,7 @@ ParserBase<Traits>::ParsePrimaryExpression(bool* ok) { |
// ArrayLiteral |
// ObjectLiteral |
// RegExpLiteral |
+ // ClassLiteral |
// '(' Expression ')' |
int pos = peek_position(); |
@@ -1782,6 +1829,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); |
@@ -1852,36 +1916,48 @@ 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: |
Consume(Token::STRING); |
return this->GetSymbol(scanner_); |
+ |
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)); |
@@ -1891,6 +1967,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( |
@@ -1900,25 +1983,40 @@ 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 (this->IsConstructor(name)) { |
+ 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); |
@@ -1931,7 +2029,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); |
} |
@@ -1951,11 +2049,13 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral( |
Expect(Token::LBRACE, CHECK_OK); |
+ const bool in_class = false; |
+ const bool is_static = false; |
while (peek() != Token::RBRACE) { |
if (fni_ != NULL) fni_->Enter(); |
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 |
@@ -2404,7 +2504,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 |
@@ -2607,6 +2707,57 @@ 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) { |
+ // Classes are always strict. |
+ 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(); |
+ } |
+ |
+ ExpressionT extends = this->EmptyExpression(); |
+ if (Check(Token::EXTENDS)) { |
+ extends = |
+ this->ParseLeftHandSideExpression(CHECK_OK_CUSTOM(EmptyClassLiteral)); |
+ } |
+ |
+ ObjectLiteralChecker checker(this, strict_mode()); |
+ const bool in_class = true; |
+ const bool is_static = false; |
+ typename Traits::Type::PropertyList properties = |
+ this->NewPropertyList(4, zone_); |
+ |
+ Expect(Token::LBRACE, CHECK_OK_CUSTOM(EmptyClassLiteral)); |
+ while (peek() != Token::RBRACE) { |
+ if (Check(Token::SEMICOLON)) continue; |
+ if (fni_ != NULL) fni_->Enter(); |
+ |
+ 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, properties, |
+ this->ast_value_factory(), pos); |
+} |
+ |
+ |
template <typename Traits> |
typename ParserBase<Traits>::ExpressionT |
ParserBase<Traits>::CheckAndRewriteReferenceExpression( |