From bdc8c36ca0ab72302de7a8277e4bade0e00d8772 Mon Sep 17 00:00:00 2001 From: "mstarzinger@chromium.org" Date: Tue, 15 Oct 2013 08:32:58 +0000 Subject: [PATCH] Unify several checking methods between parser and pre-parser. R=ulan@chromium.org Review URL: https://codereview.chromium.org/27206002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17207 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/parser.cc | 33 +++----- src/parser.h | 25 ++---- src/preparser.cc | 82 +++++++++++-------- src/preparser.h | 209 ++++++++++++++++++++--------------------------- 4 files changed, 157 insertions(+), 192 deletions(-) diff --git a/src/parser.cc b/src/parser.cc index 1f60163c0d..a17883fd45 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -3025,7 +3025,7 @@ Expression* Parser::ParseConditionalExpression(bool accept_IN, bool* ok) { } -static int Precedence(Token::Value tok, bool accept_IN) { +int ParserBase::Precedence(Token::Value tok, bool accept_IN) { if (tok == Token::IN && !accept_IN) return 0; // 0 precedence will terminate binary expression parsing @@ -3845,11 +3845,6 @@ void Parser::BuildObjectLiteralConstantProperties( } -// Force instantiation of template instances class. -template void ObjectLiteralChecker::CheckProperty( - Token::Value property, PropertyKind type, bool* ok); - - Expression* Parser::ParseObjectLiteral(bool* ok) { // ObjectLiteral :: // '{' ( @@ -3863,8 +3858,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { int number_of_boilerplate_properties = 0; bool has_function = false; - ObjectLiteralChecker checker(this, &scanner_, - top_scope_->language_mode()); + ObjectLiteralChecker checker(this, top_scope_->language_mode()); Expect(Token::LBRACE, CHECK_OK); @@ -4618,9 +4612,9 @@ bool ParserBase::peek_any_identifier() { } -bool Parser::CheckContextualKeyword(Vector keyword) { +bool ParserBase::CheckContextualKeyword(Vector keyword) { if (peek() == Token::IDENTIFIER && - scanner().is_next_contextual_keyword(keyword)) { + scanner()->is_next_contextual_keyword(keyword)) { Consume(Token::IDENTIFIER); return true; } @@ -4645,12 +4639,12 @@ void ParserBase::ExpectSemicolon(bool* ok) { } -void Parser::ExpectContextualKeyword(Vector keyword, bool* ok) { +void ParserBase::ExpectContextualKeyword(Vector keyword, bool* ok) { Expect(Token::IDENTIFIER, ok); if (!*ok) return; - if (!scanner().is_literal_contextual_keyword(keyword)) { + if (!scanner()->is_literal_contextual_keyword(keyword)) { + ReportUnexpectedToken(scanner()->current_token()); *ok = false; - ReportUnexpectedToken(scanner().current_token()); } } @@ -4745,14 +4739,11 @@ void Parser::CheckStrictModeLValue(Expression* expression, // Checks whether an octal literal was last seen between beg_pos and end_pos. // If so, reports an error. Only called for strict mode. -void Parser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) { - Scanner::Location octal = scanner().octal_position(); - if (octal.IsValid() && - beg_pos <= octal.beg_pos && - octal.end_pos <= end_pos) { - ReportMessageAt(octal, "strict_octal_literal", - Vector::empty()); - scanner().clear_octal_position(); +void ParserBase::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) { + Scanner::Location octal = scanner()->octal_position(); + if (octal.IsValid() && beg_pos <= octal.beg_pos && octal.end_pos <= end_pos) { + ReportMessageAt(octal, "strict_octal_literal"); + scanner()->clear_octal_position(); *ok = false; } } diff --git a/src/parser.h b/src/parser.h index 6c65ec3d82..79ce68b615 100644 --- a/src/parser.h +++ b/src/parser.h @@ -439,13 +439,6 @@ class Parser : public ParserBase { static bool Parse(CompilationInfo* info) { return Parser(info).Parse(); } bool Parse(); - void ReportMessageAt(Scanner::Location loc, - const char* message, - Vector args = Vector::empty()); - void ReportMessageAt(Scanner::Location loc, - const char* message, - Vector > args); - private: static const int kMaxNumFunctionLocals = 131071; // 2^17-1 @@ -562,6 +555,15 @@ class Parser : public ParserBase { void ReportInvalidPreparseData(Handle name, bool* ok); void ReportMessage(const char* message, Vector args); void ReportMessage(const char* message, Vector > args); + void ReportMessageAt(Scanner::Location location, const char* type) { + ReportMessageAt(location, type, Vector::empty()); + } + void ReportMessageAt(Scanner::Location loc, + const char* message, + Vector args); + void ReportMessageAt(Scanner::Location loc, + const char* message, + Vector > args); void set_pre_parse_data(ScriptDataImpl *data) { pre_parse_data_ = data; @@ -570,8 +572,6 @@ class Parser : public ParserBase { bool inside_with() const { return top_scope_->inside_with(); } Scanner& scanner() { return scanner_; } - int position() { return scanner_.location().beg_pos; } - int peek_position() { return scanner_.peek_location().beg_pos; } Mode mode() const { return mode_; } ScriptDataImpl* pre_parse_data() const { return pre_parse_data_; } bool is_extended_mode() { @@ -694,9 +694,6 @@ class Parser : public ParserBase { bool CheckInOrOf(bool accept_OF, ForEachStatement::VisitMode* visit_mode); - bool CheckContextualKeyword(Vector keyword); - void ExpectContextualKeyword(Vector keyword, bool* ok); - Handle LiteralString(PretenureFlag tenured) { if (scanner().is_literal_ascii()) { return isolate_->factory()->NewStringFromAscii( @@ -741,9 +738,6 @@ class Parser : public ParserBase { const char* error, bool* ok); - // Strict mode octal literal validation. - void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok); - // For harmony block scoping mode: Check if the scope has conflicting var/let // declarations from different scopes. It covers for example // @@ -826,7 +820,6 @@ class Parser : public ParserBase { CompilationInfo* info_; friend class BlockState; friend class FunctionState; - friend class ObjectLiteralChecker; }; diff --git a/src/preparser.cc b/src/preparser.cc index 2d670ac623..f9c13860ed 100644 --- a/src/preparser.cc +++ b/src/preparser.cc @@ -65,7 +65,7 @@ PreParser::PreParseResult PreParser::PreParseLazyFunction( function_scope.set_is_generator(is_generator); ASSERT_EQ(i::Token::LBRACE, scanner()->current_token()); bool ok = true; - int start_position = scanner()->peek_location().beg_pos; + int start_position = peek_position(); ParseLazyFunctionLiteralBody(&ok); if (stack_overflow()) return kPreParseStackOverflow; if (!ok) { @@ -129,18 +129,6 @@ void PreParser::ReportUnexpectedToken(i::Token::Value token) { } -// Checks whether octal literal last seen is between beg_pos and end_pos. -// If so, reports an error. -void PreParser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) { - i::Scanner::Location octal = scanner()->octal_position(); - if (beg_pos <= octal.beg_pos && octal.end_pos <= end_pos) { - ReportMessageAt(octal, "strict_octal_literal", NULL); - scanner()->clear_octal_position(); - *ok = false; - } -} - - #define CHECK_OK ok); \ if (!*ok) return kUnknownSourceElements; \ ((void)0 @@ -659,10 +647,9 @@ PreParser::Statement PreParser::ParseWhileStatement(bool* ok) { bool PreParser::CheckInOrOf(bool accept_OF) { - if (peek() == i::Token::IN || - (allow_for_of() && accept_OF && peek() == i::Token::IDENTIFIER && - scanner()->is_next_contextual_keyword(v8::internal::CStrVector("of")))) { - Next(); + if (Check(Token::IN) || + (allow_for_of() && accept_OF && + CheckContextualKeyword(CStrVector("of")))) { return true; } return false; @@ -901,14 +888,6 @@ PreParser::Expression PreParser::ParseConditionalExpression(bool accept_IN, } -int PreParser::Precedence(i::Token::Value tok, bool accept_IN) { - if (tok == i::Token::IN && !accept_IN) - return 0; // 0 precedence will terminate binary expression parsing - - return i::Token::Precedence(tok); -} - - // Precedence >= 4 PreParser::Expression PreParser::ParseBinaryExpression(int prec, bool accept_IN, @@ -1238,7 +1217,7 @@ PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) { // | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral) // )*[','] '}' - i::ObjectLiteralChecker checker(this, scanner(), language_mode()); + ObjectLiteralChecker checker(this, language_mode()); Expect(i::Token::LBRACE, CHECK_OK); while (peek() != i::Token::RBRACE) { @@ -1265,8 +1244,7 @@ PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) { if (!is_keyword) { LogSymbol(); } - i::PropertyKind type = is_getter ? i::kGetterProperty - : i::kSetterProperty; + PropertyKind type = is_getter ? kGetterProperty : kSetterProperty; checker.CheckProperty(name, type, CHECK_OK); ParseFunctionLiteral(false, CHECK_OK); if (peek() != i::Token::RBRACE) { @@ -1274,22 +1252,22 @@ PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) { } continue; // restart the while } - checker.CheckProperty(next, i::kValueProperty, CHECK_OK); + checker.CheckProperty(next, kValueProperty, CHECK_OK); break; } case i::Token::STRING: Consume(next); - checker.CheckProperty(next, i::kValueProperty, CHECK_OK); + checker.CheckProperty(next, kValueProperty, CHECK_OK); GetStringSymbol(); break; case i::Token::NUMBER: Consume(next); - checker.CheckProperty(next, i::kValueProperty, CHECK_OK); + checker.CheckProperty(next, kValueProperty, CHECK_OK); break; default: if (i::Token::IsKeyword(next)) { Consume(next); - checker.CheckProperty(next, i::kValueProperty, CHECK_OK); + checker.CheckProperty(next, kValueProperty, CHECK_OK); } else { // Unexpected token. *ok = false; @@ -1368,7 +1346,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral(bool is_generator, // FormalParameterList :: // '(' (Identifier)*[','] ')' Expect(i::Token::LPAREN, CHECK_OK); - int start_position = scanner()->location().beg_pos; + int start_position = position(); bool done = (peek() == i::Token::RPAREN); i::DuplicateFinder duplicate_finder(scanner()->unicode_cache()); while (!done) { @@ -1428,7 +1406,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral(bool is_generator, void PreParser::ParseLazyFunctionLiteralBody(bool* ok) { - int body_start = scanner()->location().beg_pos; + int body_start = position(); log_->PauseRecording(); ParseSourceElements(i::Token::RBRACE, ok); log_->ResumeRecording(); @@ -1462,7 +1440,7 @@ PreParser::Expression PreParser::ParseV8Intrinsic(bool* ok) { void PreParser::LogSymbol() { - int identifier_pos = scanner()->location().beg_pos; + int identifier_pos = position(); if (scanner()->is_literal_ascii()) { log_->LogAsciiSymbol(identifier_pos, scanner()->literal_ascii_string()); } else { @@ -1602,7 +1580,7 @@ void PreParser::StrictModeIdentifierViolation(i::Scanner::Location location, PreParser::Identifier PreParser::ParseIdentifierName(bool* ok) { i::Token::Value next = Next(); if (i::Token::IsKeyword(next)) { - int pos = scanner()->location().beg_pos; + int pos = position(); const char* keyword = i::Token::String(next); log_->LogAsciiSymbol(pos, i::Vector(keyword, i::StrLength(keyword))); @@ -1637,4 +1615,36 @@ PreParser::Identifier PreParser::ParseIdentifierNameOrGetOrSet(bool* is_get, } +void PreParser::ObjectLiteralChecker::CheckProperty(Token::Value property, + PropertyKind type, + 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); + } else { + old = finder_.AddUtf16Symbol(scanner()->literal_utf16_string(), type); + } + PropertyKind old_type = static_cast(old); + if (HasConflict(old_type, type)) { + if (IsDataDataConflict(old_type, type)) { + // Both are data properties. + if (language_mode_ == CLASSIC_MODE) return; + parser()->ReportMessageAt(scanner()->location(), + "strict_duplicate_property"); + } else if (IsDataAccessorConflict(old_type, type)) { + // Both a data and an accessor property with the same name. + parser()->ReportMessageAt(scanner()->location(), + "accessor_data_property"); + } else { + ASSERT(IsAccessorAccessorConflict(old_type, type)); + // Both accessors of the same type. + parser()->ReportMessageAt(scanner()->location(), + "accessor_get_set"); + } + *ok = false; + } +} + } } // v8::internal diff --git a/src/preparser.h b/src/preparser.h index 74cffa29b2..5cb453527e 100644 --- a/src/preparser.h +++ b/src/preparser.h @@ -35,96 +35,6 @@ namespace v8 { namespace internal { -// Used to detect duplicates in object literals. Each of the values -// kGetterProperty, kSetterProperty and kValueProperty represents -// a type of object literal property. When parsing a property, its -// type value is stored in the DuplicateFinder for the property name. -// Values are chosen so that having intersection bits means the there is -// an incompatibility. -// I.e., you can add a getter to a property that already has a setter, since -// kGetterProperty and kSetterProperty doesn't intersect, but not if it -// already has a getter or a value. Adding the getter to an existing -// setter will store the value (kGetterProperty | kSetterProperty), which -// is incompatible with adding any further properties. -enum PropertyKind { - kNone = 0, - // Bit patterns representing different object literal property types. - kGetterProperty = 1, - kSetterProperty = 2, - kValueProperty = 7, - // Helper constants. - kValueFlag = 4 -}; - - -// Validation per 11.1.5 Object Initialiser -template -class ObjectLiteralChecker { - public: - ObjectLiteralChecker(P* parser, Scanner* scanner, LanguageMode mode) - : parser_(parser), - scanner_(scanner), - finder_(scanner->unicode_cache()), - language_mode_(mode) { } - - void CheckProperty(Token::Value property, PropertyKind type, bool* ok); - - private: - // Checks the type of conflict based on values coming from PropertyType. - bool HasConflict(PropertyKind type1, PropertyKind type2) { - return (type1 & type2) != 0; - } - bool IsDataDataConflict(PropertyKind type1, PropertyKind type2) { - return ((type1 & type2) & kValueFlag) != 0; - } - bool IsDataAccessorConflict(PropertyKind type1, PropertyKind type2) { - return ((type1 ^ type2) & kValueFlag) != 0; - } - bool IsAccessorAccessorConflict(PropertyKind type1, PropertyKind type2) { - return ((type1 | type2) & kValueFlag) == 0; - } - - P* parser_; - Scanner* scanner_; - DuplicateFinder finder_; - LanguageMode language_mode_; -}; - - -template -void ObjectLiteralChecker

::CheckProperty(Token::Value property, - PropertyKind type, - 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); - } else { - old = finder_.AddUtf16Symbol(scanner_->literal_utf16_string(), type); - } - PropertyKind old_type = static_cast(old); - if (HasConflict(old_type, type)) { - if (IsDataDataConflict(old_type, type)) { - // Both are data properties. - if (language_mode_ == CLASSIC_MODE) return; - parser_->ReportMessageAt(scanner_->location(), - "strict_duplicate_property"); - } else if (IsDataAccessorConflict(old_type, type)) { - // Both a data and an accessor property with the same name. - parser_->ReportMessageAt(scanner_->location(), - "accessor_data_property"); - } else { - ASSERT(IsAccessorAccessorConflict(old_type, type)); - // Both accessors of the same type. - parser_->ReportMessageAt(scanner_->location(), - "accessor_get_set"); - } - *ok = false; - } -} - - // Common base class shared between parser and pre-parser. class ParserBase { public: @@ -167,6 +77,8 @@ class ParserBase { protected: Scanner* scanner() const { return scanner_; } + int position() { return scanner_->location().beg_pos; } + int peek_position() { return scanner_->peek_location().beg_pos; } bool stack_overflow() const { return stack_overflow_; } void set_stack_overflow() { stack_overflow_ = true; } @@ -215,9 +127,72 @@ class ParserBase { bool peek_any_identifier(); void ExpectSemicolon(bool* ok); + bool CheckContextualKeyword(Vector keyword); + void ExpectContextualKeyword(Vector keyword, bool* ok); + + // Strict mode octal literal validation. + void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok); + + // Determine precedence of given token. + static int Precedence(Token::Value token, bool accept_IN); // Report syntax errors. virtual void ReportUnexpectedToken(Token::Value token) = 0; + virtual void ReportMessageAt(Scanner::Location loc, const char* type) = 0; + + // Used to detect duplicates in object literals. Each of the values + // kGetterProperty, kSetterProperty and kValueProperty represents + // a type of object literal property. When parsing a property, its + // type value is stored in the DuplicateFinder for the property name. + // Values are chosen so that having intersection bits means the there is + // an incompatibility. + // I.e., you can add a getter to a property that already has a setter, since + // kGetterProperty and kSetterProperty doesn't intersect, but not if it + // already has a getter or a value. Adding the getter to an existing + // setter will store the value (kGetterProperty | kSetterProperty), which + // is incompatible with adding any further properties. + enum PropertyKind { + kNone = 0, + // Bit patterns representing different object literal property types. + kGetterProperty = 1, + kSetterProperty = 2, + kValueProperty = 7, + // Helper constants. + kValueFlag = 4 + }; + + // Validation per ECMA 262 - 11.1.5 "Object Initialiser". + class ObjectLiteralChecker { + public: + ObjectLiteralChecker(ParserBase* parser, LanguageMode mode) + : parser_(parser), + finder_(scanner()->unicode_cache()), + language_mode_(mode) { } + + void CheckProperty(Token::Value property, PropertyKind type, bool* ok); + + private: + ParserBase* parser() const { return parser_; } + Scanner* scanner() const { return parser_->scanner(); } + + // Checks the type of conflict based on values coming from PropertyType. + bool HasConflict(PropertyKind type1, PropertyKind type2) { + return (type1 & type2) != 0; + } + bool IsDataDataConflict(PropertyKind type1, PropertyKind type2) { + return ((type1 & type2) & kValueFlag) != 0; + } + bool IsDataAccessorConflict(PropertyKind type1, PropertyKind type2) { + return ((type1 ^ type2) & kValueFlag) != 0; + } + bool IsAccessorAccessorConflict(PropertyKind type1, PropertyKind type2) { + return ((type1 | type2) & kValueFlag) == 0; + } + + ParserBase* parser_; + DuplicateFinder finder_; + LanguageMode language_mode_; + }; private: Scanner* scanner_; @@ -254,14 +229,13 @@ class PreParser : public ParserBase { kPreParseSuccess }; - - PreParser(i::Scanner* scanner, - i::ParserRecorder* log, + PreParser(Scanner* scanner, + ParserRecorder* log, uintptr_t stack_limit) : ParserBase(scanner, stack_limit), log_(log), scope_(NULL), - strict_mode_violation_location_(i::Scanner::Location::invalid()), + strict_mode_violation_location_(Scanner::Location::invalid()), strict_mode_violation_type_(NULL), parenthesized_function_(false) { } @@ -275,7 +249,7 @@ class PreParser : public ParserBase { Scope top_scope(&scope_, kTopLevelScope); bool ok = true; int start_position = scanner()->peek_location().beg_pos; - ParseSourceElements(i::Token::EOS, &ok); + ParseSourceElements(Token::EOS, &ok); if (stack_overflow()) return kPreParseStackOverflow; if (!ok) { ReportUnexpectedToken(scanner()->current_token()); @@ -293,9 +267,9 @@ class PreParser : public ParserBase { // keyword and parameters, and have consumed the initial '{'. // At return, unless an error occurred, the scanner is positioned before the // the final '}'. - PreParseResult PreParseLazyFunction(i::LanguageMode mode, + PreParseResult PreParseLazyFunction(LanguageMode mode, bool is_generator, - i::ParserRecorder* log); + ParserRecorder* log); private: // These types form an algebra over syntactic categories that is just @@ -556,7 +530,7 @@ class PreParser : public ParserBase { expected_properties_(0), with_nesting_count_(0), language_mode_( - (prev_ != NULL) ? prev_->language_mode() : i::CLASSIC_MODE), + (prev_ != NULL) ? prev_->language_mode() : CLASSIC_MODE), is_generator_(false) { *variable = this; } @@ -570,12 +544,12 @@ class PreParser : public ParserBase { bool is_generator() { return is_generator_; } void set_is_generator(bool is_generator) { is_generator_ = is_generator; } bool is_classic_mode() { - return language_mode_ == i::CLASSIC_MODE; + return language_mode_ == CLASSIC_MODE; } - i::LanguageMode language_mode() { + LanguageMode language_mode() { return language_mode_; } - void set_language_mode(i::LanguageMode language_mode) { + void set_language_mode(LanguageMode language_mode) { language_mode_ = language_mode; } @@ -599,15 +573,18 @@ class PreParser : public ParserBase { int materialized_literal_count_; int expected_properties_; int with_nesting_count_; - i::LanguageMode language_mode_; + LanguageMode language_mode_; bool is_generator_; }; // Report syntax error - void ReportUnexpectedToken(i::Token::Value token); - void ReportMessageAt(i::Scanner::Location location, + void ReportUnexpectedToken(Token::Value token); + void ReportMessageAt(Scanner::Location location, const char* type) { + ReportMessageAt(location, type, NULL); + } + void ReportMessageAt(Scanner::Location location, const char* type, - const char* name_opt = NULL) { + const char* name_opt) { log_->LogMessage(location.beg_pos, location.end_pos, type, name_opt); } void ReportMessageAt(int start_pos, @@ -617,8 +594,6 @@ class PreParser : public ParserBase { log_->LogMessage(start_pos, end_pos, type, name_opt); } - void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok); - // 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 @@ -682,42 +657,38 @@ class PreParser : public ParserBase { // Log the currently parsed string literal. Expression GetStringSymbol(); - void set_language_mode(i::LanguageMode language_mode) { + void set_language_mode(LanguageMode language_mode) { scope_->set_language_mode(language_mode); } bool is_classic_mode() { - return scope_->language_mode() == i::CLASSIC_MODE; + return scope_->language_mode() == CLASSIC_MODE; } bool is_extended_mode() { - return scope_->language_mode() == i::EXTENDED_MODE; + return scope_->language_mode() == EXTENDED_MODE; } - i::LanguageMode language_mode() { return scope_->language_mode(); } + LanguageMode language_mode() { return scope_->language_mode(); } bool CheckInOrOf(bool accept_OF); - static int Precedence(i::Token::Value tok, bool accept_IN); - - void SetStrictModeViolation(i::Scanner::Location, + void SetStrictModeViolation(Scanner::Location, const char* type, bool* ok); void CheckDelayedStrictModeViolation(int beg_pos, int end_pos, bool* ok); - void StrictModeIdentifierViolation(i::Scanner::Location, + void StrictModeIdentifierViolation(Scanner::Location, const char* eval_args_type, Identifier identifier, bool* ok); - i::ParserRecorder* log_; + ParserRecorder* log_; Scope* scope_; - i::Scanner::Location strict_mode_violation_location_; + Scanner::Location strict_mode_violation_location_; const char* strict_mode_violation_type_; bool parenthesized_function_; - - friend class i::ObjectLiteralChecker; }; } } // v8::internal