| Index: src/preparser.h
|
| diff --git a/src/preparser.h b/src/preparser.h
|
| index c7ac7ff81aed0e5885e4fcf8d030e34c61ea61b0..d1426e54fe7b7fc3b405ce4367deb342dc6cd9b4 100644
|
| --- a/src/preparser.h
|
| +++ b/src/preparser.h
|
| @@ -28,6 +28,7 @@
|
| #ifndef V8_PREPARSER_H
|
| #define V8_PREPARSER_H
|
|
|
| +#include "func-name-inferrer.h"
|
| #include "hashmap.h"
|
| #include "scopes.h"
|
| #include "token.h"
|
| @@ -50,6 +51,7 @@ class ParserBase : public Traits {
|
| scope_(NULL),
|
| function_state_(NULL),
|
| extension_(extension),
|
| + fni_(NULL),
|
| scanner_(scanner),
|
| stack_limit_(stack_limit),
|
| stack_overflow_(false),
|
| @@ -330,8 +332,8 @@ class ParserBase : public Traits {
|
| typename Traits::Type::Identifier ParseIdentifierName(bool* ok);
|
| // Parses an identifier and determines whether or not it is 'get' or 'set'.
|
| typename Traits::Type::Identifier ParseIdentifierNameOrGetOrSet(bool* is_get,
|
| - bool* is_set,
|
| - bool* ok);
|
| + bool* is_set,
|
| + bool* ok);
|
|
|
| typename Traits::Type::Expression ParseRegExpLiteral(bool seen_equal,
|
| bool* ok);
|
| @@ -339,6 +341,7 @@ class ParserBase : public Traits {
|
| typename Traits::Type::Expression ParsePrimaryExpression(bool* ok);
|
| typename Traits::Type::Expression ParseExpression(bool accept_IN, bool* ok);
|
| typename Traits::Type::Expression ParseArrayLiteral(bool* ok);
|
| + typename Traits::Type::Expression ParseObjectLiteral(bool* ok);
|
|
|
| // Used to detect duplicates in object literals. Each of the values
|
| // kGetterProperty, kSetterProperty and kValueProperty represents
|
| @@ -403,6 +406,7 @@ class ParserBase : public Traits {
|
| typename Traits::Type::Scope* scope_; // Scope stack.
|
| FunctionState* function_state_; // Function state stack.
|
| v8::Extension* extension_;
|
| + FuncNameInferrer* fni_;
|
|
|
| private:
|
| Scanner* scanner_;
|
| @@ -606,6 +610,35 @@ class PreParserFactory {
|
| int pos) {
|
| return PreParserExpression::Default();
|
| }
|
| +
|
| + PreParserExpression NewObjectLiteralProperty(bool is_getter,
|
| + PreParserExpression value,
|
| + int pos) {
|
| + return PreParserExpression::Default();
|
| + }
|
| +
|
| + PreParserExpression NewObjectLiteralProperty(PreParserExpression key,
|
| + PreParserExpression value) {
|
| + return PreParserExpression::Default();
|
| + }
|
| +
|
| + PreParserExpression NewObjectLiteral(PreParserExpressionList properties,
|
| + int literal_index,
|
| + int boilerplate_properties,
|
| + bool has_function,
|
| + int pos) {
|
| + return PreParserExpression::Default();
|
| + }
|
| +
|
| + PreParserExpression NewLiteral(PreParserIdentifier identifier,
|
| + int pos) {
|
| + return PreParserExpression::Default();
|
| + }
|
| +
|
| + PreParserExpression NewNumberLiteral(double number,
|
| + int pos) {
|
| + return PreParserExpression::Default();
|
| + }
|
| };
|
|
|
|
|
| @@ -627,7 +660,11 @@ class PreParserTraits {
|
| // Return types for traversing functions.
|
| typedef PreParserIdentifier Identifier;
|
| typedef PreParserExpression Expression;
|
| + typedef PreParserExpression FunctionLiteral;
|
| + typedef PreParserExpression ObjectLiteralProperty;
|
| + typedef PreParserExpression Literal;
|
| typedef PreParserExpressionList ExpressionList;
|
| + typedef PreParserExpressionList PropertyList;
|
| };
|
|
|
| explicit PreParserTraits(PreParser* pre_parser) : pre_parser_(pre_parser) {}
|
| @@ -644,6 +681,23 @@ class PreParserTraits {
|
| return identifier.IsEvalOrArguments();
|
| }
|
|
|
| + static bool IsBoilerplateProperty(PreParserExpression property) {
|
| + // PreParser doesn't count boilerplate properties.
|
| + return false;
|
| + }
|
| +
|
| + static bool IsArrayIndex(PreParserIdentifier string, uint32_t* index) {
|
| + return false;
|
| + }
|
| +
|
| + static void PushLiteralName(FuncNameInferrer* fni, PreParserIdentifier id) {
|
| + // PreParser should not use FuncNameInferrer.
|
| + ASSERT(false);
|
| + }
|
| +
|
| + static void CheckFunctionLiteralInsideTopLevelObjectLiteral(
|
| + PreParserScope* scope, PreParserExpression value, bool* has_function) {}
|
| +
|
| // Reporting errors.
|
| void ReportMessageAt(Scanner::Location location,
|
| const char* message,
|
| @@ -663,6 +717,9 @@ class PreParserTraits {
|
| static PreParserExpression EmptyExpression() {
|
| return PreParserExpression::Default();
|
| }
|
| + static PreParserExpression EmptyLiteral() {
|
| + return PreParserExpression::Default();
|
| + }
|
|
|
| // Odd-ball literal creators.
|
| static PreParserExpression GetLiteralTheHole(int position,
|
| @@ -702,10 +759,21 @@ class PreParserTraits {
|
| return PreParserExpressionList();
|
| }
|
|
|
| + static PreParserExpressionList NewPropertyList(int size, void* zone) {
|
| + return PreParserExpressionList();
|
| + }
|
| +
|
| // Temporary glue; these functions will move to ParserBase.
|
| PreParserExpression ParseAssignmentExpression(bool accept_IN, bool* ok);
|
| - PreParserExpression ParseObjectLiteral(bool* ok);
|
| PreParserExpression ParseV8Intrinsic(bool* ok);
|
| + PreParserExpression ParseFunctionLiteral(
|
| + PreParserIdentifier name,
|
| + Scanner::Location function_name_location,
|
| + bool name_is_strict_reserved,
|
| + bool is_generator,
|
| + int function_token_position,
|
| + FunctionLiteral::FunctionType type,
|
| + bool* ok);
|
|
|
| private:
|
| PreParser* pre_parser_;
|
| @@ -1230,6 +1298,166 @@ typename Traits::Type::Expression ParserBase<Traits>::ParseArrayLiteral(
|
| return factory()->NewArrayLiteral(values, literal_index, pos);
|
| }
|
|
|
| +
|
| +template <class Traits>
|
| +typename Traits::Type::Expression ParserBase<Traits>::ParseObjectLiteral(
|
| + bool* ok) {
|
| + // ObjectLiteral ::
|
| + // '{' ((
|
| + // ((IdentifierName | String | Number) ':' AssignmentExpression) |
|
| + // (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral)
|
| + // ) ',')* '}'
|
| + // (Except that trailing comma is not required and not allowed.)
|
| +
|
| + int pos = peek_position();
|
| + typename Traits::Type::PropertyList properties =
|
| + this->NewPropertyList(4, zone_);
|
| + int number_of_boilerplate_properties = 0;
|
| + bool has_function = false;
|
| +
|
| + ObjectLiteralChecker checker(this, strict_mode());
|
| +
|
| + Expect(Token::LBRACE, CHECK_OK);
|
| +
|
| + while (peek() != Token::RBRACE) {
|
| + if (fni_ != NULL) fni_->Enter();
|
| +
|
| + typename Traits::Type::Literal key = this->EmptyLiteral();
|
| + Token::Value next = peek();
|
| + int next_pos = peek_position();
|
| +
|
| + switch (next) {
|
| + case Token::FUTURE_RESERVED_WORD:
|
| + case Token::FUTURE_STRICT_RESERVED_WORD:
|
| + case Token::IDENTIFIER: {
|
| + bool is_getter = false;
|
| + bool is_setter = false;
|
| + typename Traits::Type::Identifier id =
|
| + ParseIdentifierNameOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
|
| + if (fni_ != NULL) this->PushLiteralName(fni_, id);
|
| +
|
| + if ((is_getter || is_setter) && peek() != Token::COLON) {
|
| + // Special handling of getter and setter syntax:
|
| + // { ... , get foo() { ... }, ... , set foo(v) { ... v ... } , ... }
|
| + // We have already read the "get" or "set" keyword.
|
| + Token::Value next = Next();
|
| + if (next != i::Token::IDENTIFIER &&
|
| + next != i::Token::FUTURE_RESERVED_WORD &&
|
| + next != i::Token::FUTURE_STRICT_RESERVED_WORD &&
|
| + next != i::Token::NUMBER &&
|
| + next != i::Token::STRING &&
|
| + !Token::IsKeyword(next)) {
|
| + ReportUnexpectedToken(next);
|
| + *ok = false;
|
| + return this->EmptyLiteral();
|
| + }
|
| + // Validate the property.
|
| + PropertyKind type = is_getter ? kGetterProperty : kSetterProperty;
|
| + checker.CheckProperty(next, type, CHECK_OK);
|
| + typename Traits::Type::Identifier name = this->GetSymbol(scanner_);
|
| + typename Traits::Type::FunctionLiteral value =
|
| + this->ParseFunctionLiteral(
|
| + name, scanner()->location(),
|
| + false, // reserved words are allowed here
|
| + false, // not a generator
|
| + RelocInfo::kNoPosition, FunctionLiteral::ANONYMOUS_EXPRESSION,
|
| + CHECK_OK);
|
| + // Allow any number of parameters for compatibilty with JSC.
|
| + // Specification only allows zero parameters for get and one for set.
|
| + typename Traits::Type::ObjectLiteralProperty property =
|
| + factory()->NewObjectLiteralProperty(is_getter, value, next_pos);
|
| + if (this->IsBoilerplateProperty(property)) {
|
| + number_of_boilerplate_properties++;
|
| + }
|
| + properties->Add(property, zone());
|
| + if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK);
|
| +
|
| + if (fni_ != NULL) {
|
| + fni_->Infer();
|
| + fni_->Leave();
|
| + }
|
| + continue; // restart the while
|
| + }
|
| + // Failed to parse as get/set property, so it's just a normal property
|
| + // (which might be called "get" or "set" or something else).
|
| + key = factory()->NewLiteral(id, next_pos);
|
| + break;
|
| + }
|
| + case Token::STRING: {
|
| + Consume(Token::STRING);
|
| + typename Traits::Type::Identifier string = this->GetSymbol(scanner_);
|
| + if (fni_ != NULL) this->PushLiteralName(fni_, string);
|
| + uint32_t index;
|
| + if (this->IsArrayIndex(string, &index)) {
|
| + key = factory()->NewNumberLiteral(index, next_pos);
|
| + break;
|
| + }
|
| + key = factory()->NewLiteral(string, next_pos);
|
| + break;
|
| + }
|
| + case Token::NUMBER: {
|
| + Consume(Token::NUMBER);
|
| + key = this->ExpressionFromLiteral(Token::NUMBER, next_pos, scanner_,
|
| + factory());
|
| + break;
|
| + }
|
| + default:
|
| + if (Token::IsKeyword(next)) {
|
| + Consume(next);
|
| + typename Traits::Type::Identifier string = this->GetSymbol(scanner_);
|
| + key = factory()->NewLiteral(string, next_pos);
|
| + } else {
|
| + Token::Value next = Next();
|
| + ReportUnexpectedToken(next);
|
| + *ok = false;
|
| + return this->EmptyLiteral();
|
| + }
|
| + }
|
| +
|
| + // Validate the property
|
| + checker.CheckProperty(next, kValueProperty, CHECK_OK);
|
| +
|
| + Expect(Token::COLON, CHECK_OK);
|
| + typename Traits::Type::Expression value =
|
| + this->ParseAssignmentExpression(true, CHECK_OK);
|
| +
|
| + typename Traits::Type::ObjectLiteralProperty property =
|
| + factory()->NewObjectLiteralProperty(key, value);
|
| +
|
| + // Mark top-level object literals that contain function literals and
|
| + // pretenure the literal so it can be added as a constant function
|
| + // property. (Parser only.)
|
| + this->CheckFunctionLiteralInsideTopLevelObjectLiteral(scope_, value,
|
| + &has_function);
|
| +
|
| + // Count CONSTANT or COMPUTED properties to maintain the enumeration order.
|
| + if (this->IsBoilerplateProperty(property)) {
|
| + number_of_boilerplate_properties++;
|
| + }
|
| + properties->Add(property, zone());
|
| +
|
| + // TODO(1240767): Consider allowing trailing comma.
|
| + if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK);
|
| +
|
| + if (fni_ != NULL) {
|
| + fni_->Infer();
|
| + fni_->Leave();
|
| + }
|
| + }
|
| + Expect(Token::RBRACE, CHECK_OK);
|
| +
|
| + // Computation of literal_index must happen before pre parse bailout.
|
| + int literal_index = function_state_->NextMaterializedLiteralIndex();
|
| +
|
| + return factory()->NewObjectLiteral(properties,
|
| + literal_index,
|
| + number_of_boilerplate_properties,
|
| + has_function,
|
| + pos);
|
| +}
|
| +
|
| +
|
| +
|
| #undef CHECK_OK
|
|
|
|
|
|
|