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 |