Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(50)

Unified Diff: src/preparser.h

Issue 196133017: Experimental parser: merge r19949 (Closed) Base URL: https://v8.googlecode.com/svn/branches/experimental/parser
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/preparse-data.cc ('k') | src/preparser.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/preparser.h
diff --git a/src/preparser.h b/src/preparser.h
index b1d90bb0b26f6bf1cf0f9a46e9d06ce199ade2c5..8eac919f0f13ef6f44dc8a64b602e921438100e8 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"
@@ -38,7 +39,46 @@
namespace v8 {
namespace internal {
-// Common base class shared between parser and pre-parser.
+// Common base class shared between parser and pre-parser. Traits encapsulate
+// the differences between Parser and PreParser:
+
+// - Return types: For example, Parser functions return Expression* and
+// PreParser functions return PreParserExpression.
+
+// - Creating parse tree nodes: Parser generates an AST during the recursive
+// descent. PreParser doesn't create a tree. Instead, it passes around minimal
+// data objects (PreParserExpression, PreParserIdentifier etc.) which contain
+// just enough data for the upper layer functions. PreParserFactory is
+// responsible for creating these dummy objects. It provides a similar kind of
+// interface as AstNodeFactory, so ParserBase doesn't need to care which one is
+// used.
+
+// - Miscellanous other tasks interleaved with the recursive descent. For
+// example, Parser keeps track of which function literals should be marked as
+// pretenured, and PreParser doesn't care.
+
+// The traits are expected to contain the following typedefs:
+// struct Traits {
+// // In particular...
+// struct Type {
+// // Used by FunctionState and BlockState.
+// typedef Scope;
+// typedef GeneratorVariable;
+// typedef Zone;
+// // Return types for traversing functions.
+// typedef Identifier;
+// typedef Expression;
+// typedef FunctionLiteral;
+// typedef ObjectLiteralProperty;
+// typedef Literal;
+// typedef ExpressionList;
+// typedef PropertyList;
+// // For constructing objects returned by the traversing functions.
+// typedef Factory;
+// };
+// // ...
+// };
+
template <typename Traits>
class ParserBase : public Traits {
public:
@@ -51,6 +91,7 @@ class ParserBase : public Traits {
scope_(NULL),
function_state_(NULL),
extension_(extension),
+ fni_(NULL),
scanner_(scanner),
stack_limit_(stack_limit),
stack_overflow_(false),
@@ -298,8 +339,7 @@ class ParserBase : public Traits {
return function_state_->factory();
}
- bool is_classic_mode() const { return scope_->is_classic_mode(); }
-
+ StrictMode strict_mode() { return scope_->strict_mode(); }
bool is_generator() const { return function_state_->is_generator(); }
// Report syntax errors.
@@ -332,8 +372,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);
@@ -341,6 +381,11 @@ 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);
+ typename Traits::Type::ExpressionList ParseArguments(bool* ok);
+ typename Traits::Type::Expression ParseAssignmentExpression(bool accept_IN,
+ bool* ok);
+ typename Traits::Type::Expression ParseYieldExpression(bool* ok);
// Used to detect duplicates in object literals. Each of the values
// kGetterProperty, kSetterProperty and kValueProperty represents
@@ -366,10 +411,10 @@ class ParserBase : public Traits {
// Validation per ECMA 262 - 11.1.5 "Object Initialiser".
class ObjectLiteralChecker {
public:
- ObjectLiteralChecker(ParserBase* parser, LanguageMode mode)
+ ObjectLiteralChecker(ParserBase* parser, StrictMode strict_mode)
: parser_(parser),
finder_(scanner()->unicode_cache()),
- language_mode_(mode) { }
+ strict_mode_(strict_mode) { }
void CheckProperty(Token::Value property, PropertyKind type, bool* ok);
@@ -393,7 +438,7 @@ class ParserBase : public Traits {
ParserBase* parser_;
DuplicateFinder finder_;
- LanguageMode language_mode_;
+ StrictMode strict_mode_;
};
// If true, the next (and immediately following) function literal is
@@ -405,6 +450,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_;
@@ -522,6 +568,17 @@ class PreParserExpression {
bool IsStrictFunction() { return code_ == kStrictFunctionExpression; }
+ // Dummy implementation for making expression->AsCall() work (see below).
+ PreParserExpression* operator->() { return this; }
+
+ // These are only used when doing function name inferring, and PreParser
+ // doesn't do function name inferring.
+ void* AsCall() const { return NULL; }
+ void* AsCallNew() const { return NULL; }
+
+ // More dummy implementations of things PreParser doesn't need to track:
+ void set_index(int index) {} // For YieldExpressions
+
private:
// First two/three bits are used as flags.
// Bit 0 and 1 represent identifiers or strings literals, and are
@@ -554,8 +611,12 @@ class PreParserExpression {
class PreParserExpressionList {
public:
// These functions make list->Add(some_expression) work (and do nothing).
+ PreParserExpressionList() : length_(0) {}
PreParserExpressionList* operator->() { return this; }
- void Add(PreParserExpression, void*) { }
+ void Add(PreParserExpression, void*) { ++length_; }
+ int length() const { return length_; }
+ private:
+ int length_;
};
@@ -564,36 +625,27 @@ class PreParserScope {
explicit PreParserScope(PreParserScope* outer_scope, ScopeType scope_type)
: scope_type_(scope_type) {
if (outer_scope) {
- scope_inside_with_ =
- outer_scope->scope_inside_with_ || is_with_scope();
- language_mode_ = outer_scope->language_mode();
+ scope_inside_with_ = outer_scope->scope_inside_with_ || is_with_scope();
+ strict_mode_ = outer_scope->strict_mode();
} else {
scope_inside_with_ = is_with_scope();
- language_mode_ = CLASSIC_MODE;
+ strict_mode_ = SLOPPY;
}
}
bool is_with_scope() const { return scope_type_ == WITH_SCOPE; }
- bool is_classic_mode() const {
- return language_mode() == CLASSIC_MODE;
- }
- bool is_extended_mode() {
- return language_mode() == EXTENDED_MODE;
- }
bool inside_with() const {
return scope_inside_with_;
}
ScopeType type() { return scope_type_; }
- LanguageMode language_mode() const { return language_mode_; }
- void SetLanguageMode(LanguageMode language_mode) {
- language_mode_ = language_mode;
- }
+ StrictMode strict_mode() const { return strict_mode_; }
+ void SetStrictMode(StrictMode strict_mode) { strict_mode_ = strict_mode; }
private:
ScopeType scope_type_;
bool scope_inside_with_;
- LanguageMode language_mode_;
+ StrictMode strict_mode_;
};
@@ -617,6 +669,53 @@ 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();
+ }
+
+ PreParserExpression NewAssignment(Token::Value op,
+ PreParserExpression left,
+ PreParserExpression right,
+ int pos) {
+ return PreParserExpression::Default();
+ }
+
+ PreParserExpression NewVariableProxy(void* generator_variable) {
+ return PreParserExpression::Default();
+ }
+
+ PreParserExpression NewYield(PreParserExpression generator_object,
+ PreParserExpression expression,
+ Yield::Kind yield_kind,
+ int pos) {
+ return PreParserExpression::Default();
+ }
};
@@ -625,11 +724,12 @@ class PreParser;
class PreParserTraits {
public:
struct Type {
+ // TODO(marja): To be removed. The Traits object should contain all the data
+ // it needs.
typedef PreParser* Parser;
- // Types used by FunctionState and BlockState.
+ // Used by FunctionState and BlockState.
typedef PreParserScope Scope;
- typedef PreParserFactory Factory;
// PreParser doesn't need to store generator variables.
typedef void GeneratorVariable;
// No interaction with Zones.
@@ -638,7 +738,15 @@ class PreParserTraits {
// Return types for traversing functions.
typedef PreParserIdentifier Identifier;
typedef PreParserExpression Expression;
+ typedef PreParserExpression YieldExpression;
+ typedef PreParserExpression FunctionLiteral;
+ typedef PreParserExpression ObjectLiteralProperty;
+ typedef PreParserExpression Literal;
typedef PreParserExpressionList ExpressionList;
+ typedef PreParserExpressionList PropertyList;
+
+ // For constructing objects returned by the traversing functions.
+ typedef PreParserFactory Factory;
};
explicit PreParserTraits(PreParser* pre_parser) : pre_parser_(pre_parser) {}
@@ -655,6 +763,53 @@ class PreParserTraits {
return identifier.IsEvalOrArguments();
}
+ // Returns true if the expression is of type "this.foo".
+ static bool IsThisProperty(PreParserExpression expression) {
+ return expression.IsThisProperty();
+ }
+
+ static bool IsBoilerplateProperty(PreParserExpression property) {
+ // PreParser doesn't count boilerplate properties.
+ return false;
+ }
+
+ static bool IsArrayIndex(PreParserIdentifier string, uint32_t* index) {
+ return false;
+ }
+
+ // Functions for encapsulating the differences between parsing and preparsing;
+ // operations interleaved with the recursive descent.
+ static void PushLiteralName(FuncNameInferrer* fni, PreParserIdentifier id) {
+ // PreParser should not use FuncNameInferrer.
+ ASSERT(false);
+ }
+
+ static void CheckFunctionLiteralInsideTopLevelObjectLiteral(
+ PreParserScope* scope, PreParserExpression value, bool* has_function) {}
+
+ static void CheckAssigningFunctionLiteralToProperty(
+ PreParserExpression left, PreParserExpression right) {}
+
+
+ static PreParserExpression ValidateAssignmentLeftHandSide(
+ PreParserExpression expression) {
+ // Parser generates a runtime error here if the left hand side is not valid.
+ // PreParser doesn't have to.
+ return expression;
+ }
+
+ static PreParserExpression MarkExpressionAsLValue(
+ PreParserExpression expression) {
+ // TODO(marja): To be able to produce the same errors, the preparser needs
+ // to start tracking which expressions are variables and which are lvalues.
+ return expression;
+ }
+
+ // Checks LHS expression for assignment and prefix/postfix increment/decrement
+ // in strict mode.
+ void CheckStrictModeLValue(PreParserExpression expression, bool* ok);
+
+
// Reporting errors.
void ReportMessageAt(Scanner::Location location,
const char* message,
@@ -674,6 +829,12 @@ class PreParserTraits {
static PreParserExpression EmptyExpression() {
return PreParserExpression::Default();
}
+ static PreParserExpression EmptyLiteral() {
+ return PreParserExpression::Default();
+ }
+ static PreParserExpressionList NullExpressionList() {
+ return PreParserExpressionList();
+ }
// Odd-ball literal creators.
static PreParserExpression GetLiteralTheHole(int position,
@@ -713,10 +874,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);
+ PreParserExpression ParseConditionalExpression(bool accept_IN, bool* ok);
private:
PreParser* pre_parser_;
@@ -764,7 +936,7 @@ class PreParser : public ParserBase<PreParserTraits> {
if (stack_overflow()) return kPreParseStackOverflow;
if (!ok) {
ReportUnexpectedToken(scanner()->current_token());
- } else if (!scope_->is_classic_mode()) {
+ } else if (scope_->strict_mode() == STRICT) {
CheckOctalLiteral(start_position, scanner()->location().end_pos, &ok);
}
return kPreParseSuccess;
@@ -778,7 +950,7 @@ class PreParser : public ParserBase<PreParserTraits> {
// keyword and parameters, and have consumed the initial '{'.
// At return, unless an error occurred, the scanner is positioned before the
// the final '}'.
- PreParseResult PreParseLazyFunction(LanguageMode mode,
+ PreParseResult PreParseLazyFunction(StrictMode strict_mode,
bool is_generator,
ParserRecorder* log);
@@ -853,8 +1025,6 @@ class PreParser : public ParserBase<PreParserTraits> {
kUnknownSourceElements
};
- typedef int Arguments;
-
// All ParseXXX functions take as the last argument an *ok parameter
// which is set to false if parsing failed; it is unchanged otherwise.
// By making the 'exception handling' explicit, we are forced to check
@@ -883,9 +1053,6 @@ class PreParser : public ParserBase<PreParserTraits> {
Statement ParseThrowStatement(bool* ok);
Statement ParseTryStatement(bool* ok);
Statement ParseDebuggerStatement(bool* ok);
-
- Expression ParseAssignmentExpression(bool accept_IN, bool* ok);
- Expression ParseYieldExpression(bool* ok);
Expression ParseConditionalExpression(bool accept_IN, bool* ok);
Expression ParseBinaryExpression(int prec, bool accept_IN, bool* ok);
Expression ParseUnaryExpression(bool* ok);
@@ -898,12 +1065,13 @@ class PreParser : public ParserBase<PreParserTraits> {
Expression ParseObjectLiteral(bool* ok);
Expression ParseV8Intrinsic(bool* ok);
- Arguments ParseArguments(bool* ok);
Expression ParseFunctionLiteral(
Identifier name,
Scanner::Location function_name_location,
bool name_is_strict_reserved,
bool is_generator,
+ int function_token_pos,
+ FunctionLiteral::FunctionType function_type,
bool* ok);
void ParseLazyFunctionLiteralBody(bool* ok);
@@ -952,12 +1120,6 @@ ParserBase<Traits>::FunctionState::~FunctionState() {
template<class Traits>
void ParserBase<Traits>::ReportUnexpectedToken(Token::Value token) {
- // We don't report stack overflows here, to avoid increasing the
- // stack depth even further. Instead we report it after parsing is
- // over, in ParseProgram.
- if (token == Token::ILLEGAL && stack_overflow()) {
- return;
- }
Scanner::Location source_location = scanner()->location();
// Four of the tokens are treated specially
@@ -974,9 +1136,8 @@ void ParserBase<Traits>::ReportUnexpectedToken(Token::Value token) {
return ReportMessageAt(source_location, "unexpected_reserved");
case Token::YIELD:
case Token::FUTURE_STRICT_RESERVED_WORD:
- return ReportMessageAt(source_location,
- is_classic_mode() ? "unexpected_token_identifier"
- : "unexpected_strict_reserved");
+ return ReportMessageAt(source_location, strict_mode() == SLOPPY
+ ? "unexpected_token_identifier" : "unexpected_strict_reserved");
default:
const char* name = Token::String(token);
ASSERT(name != NULL);
@@ -994,13 +1155,14 @@ typename Traits::Type::Identifier ParserBase<Traits>::ParseIdentifier(
if (next == Token::IDENTIFIER) {
typename Traits::Type::Identifier name = this->GetSymbol(scanner());
if (allow_eval_or_arguments == kDontAllowEvalOrArguments &&
- !is_classic_mode() && this->IsEvalOrArguments(name)) {
+ strict_mode() == STRICT && this->IsEvalOrArguments(name)) {
ReportMessageAt(scanner()->location(), "strict_eval_arguments");
*ok = false;
}
return name;
- } else if (is_classic_mode() && (next == Token::FUTURE_STRICT_RESERVED_WORD ||
- (next == Token::YIELD && !is_generator()))) {
+ } else if (strict_mode() == SLOPPY &&
+ (next == Token::FUTURE_STRICT_RESERVED_WORD ||
+ (next == Token::YIELD && !is_generator()))) {
return this->GetSymbol(scanner());
} else {
this->ReportUnexpectedToken(next);
@@ -1050,12 +1212,7 @@ ParserBase<Traits>::ParseIdentifierNameOrGetOrSet(bool* is_get,
bool* ok) {
typename Traits::Type::Identifier result = ParseIdentifierName(ok);
if (!*ok) return Traits::EmptyIdentifier();
- if (scanner()->is_literal_ascii() &&
- scanner()->literal_length() == 3) {
- const char* token = scanner()->literal_ascii_string().start();
- *is_get = strncmp(token, "get", 3) == 0;
- *is_set = !*is_get && strncmp(token, "set", 3) == 0;
- }
+ scanner()->IsGetOrSet(is_get, is_set);
return result;
}
@@ -1094,6 +1251,13 @@ ParserBase<Traits>::ParseRegExpLiteral(bool seen_equal, bool* ok) {
#define DUMMY ) // to make indentation work
#undef DUMMY
+// Used in functions where the return type is not Traits::Type::Expression.
+#define CHECK_OK_CUSTOM(x) ok); \
+ if (!*ok) return this->x(); \
+ ((void)0
+#define DUMMY ) // to make indentation work
+#undef DUMMY
+
template <class Traits>
typename Traits::Type::Expression ParserBase<Traits>::ParsePrimaryExpression(
bool* ok) {
@@ -1239,7 +1403,295 @@ 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) {
+ // Need {} because of the CHECK_OK macro.
+ 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) {
+ // Need {} because of the CHECK_OK macro.
+ 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);
+}
+
+
+template <class Traits>
+typename Traits::Type::ExpressionList ParserBase<Traits>::ParseArguments(
+ bool* ok) {
+ // Arguments ::
+ // '(' (AssignmentExpression)*[','] ')'
+
+ typename Traits::Type::ExpressionList result =
+ this->NewExpressionList(4, zone_);
+ Expect(Token::LPAREN, CHECK_OK_CUSTOM(NullExpressionList));
+ bool done = (peek() == Token::RPAREN);
+ while (!done) {
+ typename Traits::Type::Expression argument =
+ this->ParseAssignmentExpression(true,
+ CHECK_OK_CUSTOM(NullExpressionList));
+ result->Add(argument, zone_);
+ if (result->length() > Code::kMaxArguments) {
+ ReportMessageAt(scanner()->location(), "too_many_arguments");
+ *ok = false;
+ return this->NullExpressionList();
+ }
+ done = (peek() == Token::RPAREN);
+ if (!done) {
+ // Need {} because of the CHECK_OK_CUSTOM macro.
+ Expect(Token::COMMA, CHECK_OK_CUSTOM(NullExpressionList));
+ }
+ }
+ Expect(Token::RPAREN, CHECK_OK_CUSTOM(NullExpressionList));
+ return result;
+}
+
+// Precedence = 2
+template <class Traits>
+typename Traits::Type::Expression ParserBase<Traits>::ParseAssignmentExpression(
+ bool accept_IN, bool* ok) {
+ // AssignmentExpression ::
+ // ConditionalExpression
+ // YieldExpression
+ // LeftHandSideExpression AssignmentOperator AssignmentExpression
+
+ if (peek() == Token::YIELD && is_generator()) {
+ return this->ParseYieldExpression(ok);
+ }
+
+ if (fni_ != NULL) fni_->Enter();
+ typename Traits::Type::Expression expression =
+ this->ParseConditionalExpression(accept_IN, CHECK_OK);
+
+ if (!Token::IsAssignmentOp(peek())) {
+ if (fni_ != NULL) fni_->Leave();
+ // Parsed conditional expression only (no assignment).
+ return expression;
+ }
+
+ // Signal a reference error if the expression is an invalid left-hand
+ // side expression. We could report this as a syntax error here but
+ // for compatibility with JSC we choose to report the error at
+ // runtime.
+ // TODO(ES5): Should change parsing for spec conformance.
+ expression = this->ValidateAssignmentLeftHandSide(expression);
+
+ if (strict_mode() == STRICT) {
+ // Assignment to eval or arguments is disallowed in strict mode.
+ this->CheckStrictModeLValue(expression, CHECK_OK);
+ }
+ expression = this->MarkExpressionAsLValue(expression);
+
+ Token::Value op = Next(); // Get assignment operator.
+ int pos = position();
+ typename Traits::Type::Expression right =
+ this->ParseAssignmentExpression(accept_IN, CHECK_OK);
+
+ // TODO(1231235): We try to estimate the set of properties set by
+ // constructors. We define a new property whenever there is an
+ // assignment to a property of 'this'. We should probably only add
+ // properties if we haven't seen them before. Otherwise we'll
+ // probably overestimate the number of properties.
+ if (op == Token::ASSIGN && this->IsThisProperty(expression)) {
+ function_state_->AddProperty();
+ }
+
+ this->CheckAssigningFunctionLiteralToProperty(expression, right);
+
+ if (fni_ != NULL) {
+ // Check if the right hand side is a call to avoid inferring a
+ // name if we're dealing with "a = function(){...}();"-like
+ // expression.
+ if ((op == Token::INIT_VAR
+ || op == Token::INIT_CONST_LEGACY
+ || op == Token::ASSIGN)
+ && (right->AsCall() == NULL && right->AsCallNew() == NULL)) {
+ fni_->Infer();
+ } else {
+ fni_->RemoveLastFunction();
+ }
+ fni_->Leave();
+ }
+
+ return factory()->NewAssignment(op, expression, right, pos);
+}
+
+template <class Traits>
+typename Traits::Type::Expression ParserBase<Traits>::ParseYieldExpression(
+ bool* ok) {
+ // YieldExpression ::
+ // 'yield' '*'? AssignmentExpression
+ int pos = peek_position();
+ Expect(Token::YIELD, CHECK_OK);
+ Yield::Kind kind =
+ Check(Token::MUL) ? Yield::DELEGATING : Yield::SUSPEND;
+ typename Traits::Type::Expression generator_object =
+ factory()->NewVariableProxy(function_state_->generator_object_variable());
+ typename Traits::Type::Expression expression =
+ ParseAssignmentExpression(false, CHECK_OK);
+ typename Traits::Type::YieldExpression yield =
+ factory()->NewYield(generator_object, expression, kind, pos);
+ if (kind == Yield::DELEGATING) {
+ yield->set_index(function_state_->NextHandlerIndex());
+ }
+ return yield;
+}
+
+
#undef CHECK_OK
+#undef CHECK_OK_CUSTOM
template <typename Traits>
@@ -1249,17 +1701,15 @@ void ParserBase<Traits>::ObjectLiteralChecker::CheckProperty(
bool* ok) {
int old;
if (property == Token::NUMBER) {
- old = finder_.AddNumber(scanner()->literal_ascii_string(), type);
- } else if (scanner()->is_literal_ascii()) {
- old = finder_.AddAsciiSymbol(scanner()->literal_ascii_string(), type);
+ old = scanner()->FindNumber(&finder_, type);
} else {
- old = finder_.AddUtf16Symbol(scanner()->literal_utf16_string(), type);
+ old = scanner()->FindSymbol(&finder_, type);
}
PropertyKind old_type = static_cast<PropertyKind>(old);
if (HasConflict(old_type, type)) {
if (IsDataDataConflict(old_type, type)) {
// Both are data properties.
- if (language_mode_ == CLASSIC_MODE) return;
+ if (strict_mode_ == SLOPPY) return;
parser()->ReportMessageAt(scanner()->location(),
"strict_duplicate_property");
} else if (IsDataAccessorConflict(old_type, type)) {
« no previous file with comments | « src/preparse-data.cc ('k') | src/preparser.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698