| Index: src/preparser.h
|
| diff --git a/src/preparser.h b/src/preparser.h
|
| index 15887bae08234a65b024940f0942750840630075..451809068582fe88a5bc8fe01893f0df4dd15bfb 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,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;
|
| @@ -642,7 +660,9 @@ class PreParserIdentifier {
|
| kLetIdentifier,
|
| kYieldIdentifier,
|
| kEvalIdentifier,
|
| - kArgumentsIdentifier
|
| + kArgumentsIdentifier,
|
| + kPrototypeIdentifier,
|
| + kConstructorIdentifier
|
| };
|
| explicit PreParserIdentifier(Type type) : type_(type) {}
|
| Type type_;
|
| @@ -931,6 +951,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.
|
| @@ -975,11 +996,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,
|
| @@ -989,7 +1011,7 @@ class PreParserFactory {
|
| int pos) {
|
| return PreParserExpression::Default();
|
| }
|
| - PreParserExpression NewVariableProxy(void* generator_variable) {
|
| + PreParserExpression NewVariableProxy(void* variable) {
|
| return PreParserExpression::Default();
|
| }
|
| PreParserExpression NewProperty(PreParserExpression obj,
|
| @@ -1065,6 +1087,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.
|
| @@ -1103,6 +1133,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 +1160,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 +1288,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();
|
| }
|
| @@ -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,7 +1916,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:
|
| @@ -1861,27 +1925,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));
|
| @@ -1891,6 +1963,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 +1979,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);
|
| @@ -1931,7 +2028,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);
|
| }
|
|
|
|
|
| @@ -1954,8 +2051,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
|
| @@ -2404,7 +2503,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 +2706,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(
|
|
|