From 71a6d70d97da6dddc16e72aaed4f1c77bf59a13e Mon Sep 17 00:00:00 2001 From: "marja@chromium.org" Date: Mon, 10 Feb 2014 15:35:39 +0000 Subject: [PATCH] Traitify ParserBase and move functions there. The long-term goal is to move all recursive descent functions from Parser and PreParser into ParserBase, but first they need to be unified. Notes: - The functions moved in this CL: ParseIdentifier, ParseIdentifierName, ParseIdentifierNameOrGetOrSet, ParseIdentifierOrStrictReservedWord. - IOW, this CL removes Parser::ParseIdentifier and PreParser::ParseIdentifier and adds ParserBase::ParseIdentifier, etc. - Error reporting used to require virtual funcs; now error reporting is moved to the Traits too, and ParserBase no longer needs to be virtual. - I had to move PreParser::Identifier out of the PreParser class, because otherwise PreParserTraits cannot use it in a typedef. BUG=v8:3126 LOG=N R=mstarzinger@chromium.org Review URL: https://codereview.chromium.org/149913006 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19230 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/parser.cc | 372 +++++++-------------------- src/parser.h | 70 ++--- src/preparser.cc | 258 +++++++------------ src/preparser.h | 611 ++++++++++++++++++++++++++++++-------------- test/cctest/test-parsing.cc | 5 +- 5 files changed, 643 insertions(+), 673 deletions(-) diff --git a/src/parser.cc b/src/parser.cc index 5e7680e..f03ec02 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -533,8 +533,78 @@ Parser::FunctionState::~FunctionState() { // ---------------------------------------------------------------------------- // Implementation of Parser +bool ParserTraits::is_classic_mode() const { + return parser_->top_scope_->is_classic_mode(); +} + + +bool ParserTraits::is_generator() const { + return parser_->current_function_state_->is_generator(); +} + + +bool ParserTraits::IsEvalOrArguments(Handle identifier) const { + return identifier.is_identical_to( + parser_->isolate()->factory()->eval_string()) || + identifier.is_identical_to( + parser_->isolate()->factory()->arguments_string()); +} + + +void ParserTraits::ReportMessageAt(Scanner::Location source_location, + const char* message, + Vector args) { + MessageLocation location(parser_->script_, + source_location.beg_pos, + source_location.end_pos); + Factory* factory = parser_->isolate()->factory(); + Handle elements = factory->NewFixedArray(args.length()); + for (int i = 0; i < args.length(); i++) { + Handle arg_string = factory->NewStringFromUtf8(CStrVector(args[i])); + elements->set(i, *arg_string); + } + Handle array = factory->NewJSArrayWithElements(elements); + Handle result = factory->NewSyntaxError(message, array); + parser_->isolate()->Throw(*result, &location); +} + + +void ParserTraits::ReportMessage(const char* message, + Vector > args) { + Scanner::Location source_location = parser_->scanner().location(); + ReportMessageAt(source_location, message, args); +} + + +void ParserTraits::ReportMessageAt(Scanner::Location source_location, + const char* message, + Vector > args) { + MessageLocation location(parser_->script_, + source_location.beg_pos, + source_location.end_pos); + Factory* factory = parser_->isolate()->factory(); + Handle elements = factory->NewFixedArray(args.length()); + for (int i = 0; i < args.length(); i++) { + elements->set(i, *args[i]); + } + Handle array = factory->NewJSArrayWithElements(elements); + Handle result = factory->NewSyntaxError(message, array); + parser_->isolate()->Throw(*result, &location); +} + + +Handle ParserTraits::GetSymbol() { + int symbol_id = -1; + if (parser_->pre_parse_data() != NULL) { + symbol_id = parser_->pre_parse_data()->GetSymbolIdentifier(); + } + return parser_->LookupSymbol(symbol_id); +} + Parser::Parser(CompilationInfo* info) - : ParserBase(&scanner_, info->isolate()->stack_guard()->real_climit()), + : ParserBase(&scanner_, + info->isolate()->stack_guard()->real_climit(), + this), isolate_(info->isolate()), symbol_cache_(0, info->zone()), script_(info->script()), @@ -793,62 +863,6 @@ FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source) { } -Handle Parser::GetSymbol() { - int symbol_id = -1; - if (pre_parse_data() != NULL) { - symbol_id = pre_parse_data()->GetSymbolIdentifier(); - } - return LookupSymbol(symbol_id); -} - - -void Parser::ReportMessage(const char* message, Vector args) { - Scanner::Location source_location = scanner().location(); - ReportMessageAt(source_location, message, args); -} - - -void Parser::ReportMessage(const char* message, Vector > args) { - Scanner::Location source_location = scanner().location(); - ReportMessageAt(source_location, message, args); -} - - -void Parser::ReportMessageAt(Scanner::Location source_location, - const char* message, - Vector args) { - MessageLocation location(script_, - source_location.beg_pos, - source_location.end_pos); - Factory* factory = isolate()->factory(); - Handle elements = factory->NewFixedArray(args.length()); - for (int i = 0; i < args.length(); i++) { - Handle arg_string = factory->NewStringFromUtf8(CStrVector(args[i])); - elements->set(i, *arg_string); - } - Handle array = factory->NewJSArrayWithElements(elements); - Handle result = factory->NewSyntaxError(message, array); - isolate()->Throw(*result, &location); -} - - -void Parser::ReportMessageAt(Scanner::Location source_location, - const char* message, - Vector > args) { - MessageLocation location(script_, - source_location.beg_pos, - source_location.end_pos); - Factory* factory = isolate()->factory(); - Handle elements = factory->NewFixedArray(args.length()); - for (int i = 0; i < args.length(); i++) { - elements->set(i, *args[i]); - } - Handle array = factory->NewJSArrayWithElements(elements); - Handle result = factory->NewSyntaxError(message, array); - isolate()->Throw(*result, &location); -} - - void* Parser::ParseSourceElements(ZoneList* processor, int end_token, bool is_eval, @@ -1081,8 +1095,8 @@ Module* Parser::ParseModuleLiteral(bool* ok) { !it.done(); it.Advance()) { if (scope->LocalLookup(it.name()) == NULL) { Handle name(it.name()); - ReportMessage("module_export_undefined", - Vector >(&name, 1)); + ParserTraits::ReportMessage("module_export_undefined", + Vector >(&name, 1)); *ok = false; return NULL; } @@ -1121,7 +1135,8 @@ Module* Parser::ParseModulePath(bool* ok) { member->interface()->Print(); } #endif - ReportMessage("invalid_module_path", Vector >(&name, 1)); + ParserTraits::ReportMessage("invalid_module_path", + Vector >(&name, 1)); return NULL; } result = member; @@ -1231,7 +1246,8 @@ Block* Parser::ParseImportDeclaration(bool* ok) { module->interface()->Print(); } #endif - ReportMessage("invalid_module_path", Vector >(&name, 1)); + ParserTraits::ReportMessage("invalid_module_path", + Vector >(&name, 1)); return NULL; } VariableProxy* proxy = NewUnresolved(names[i], LET, interface); @@ -1439,8 +1455,7 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) { // Statement: // GeneratorDeclaration if (!top_scope_->is_classic_mode()) { - ReportMessageAt(scanner().peek_location(), "strict_function", - Vector::empty()); + ReportMessageAt(scanner().peek_location(), "strict_function"); *ok = false; return NULL; } @@ -1619,7 +1634,8 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) { var->interface()->Print(); } #endif - ReportMessage("module_type_error", Vector >(&name, 1)); + ParserTraits::ReportMessage("module_type_error", + Vector >(&name, 1)); } } } @@ -1777,12 +1793,6 @@ Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context, } -bool Parser::IsEvalOrArguments(Handle string) { - return string.is_identical_to(isolate()->factory()->eval_string()) || - string.is_identical_to(isolate()->factory()->arguments_string()); -} - - // If the variable declaration declares exactly one non-const // variable, then *out is set to that variable. In all other cases, // *out is untouched; in particular, it is the caller's responsibility @@ -1928,8 +1938,7 @@ Block* Parser::ParseVariableDeclarations( Declare(declaration, mode != VAR, CHECK_OK); nvars++; if (declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) { - ReportMessageAt(scanner().location(), "too_many_variables", - Vector::empty()); + ReportMessageAt(scanner().location(), "too_many_variables"); *ok = false; return NULL; } @@ -2232,7 +2241,7 @@ Statement* Parser::ParseContinueStatement(bool* ok) { message = "unknown_label"; args = Vector >(&label, 1); } - ReportMessageAt(scanner().location(), message, args); + ParserTraits::ReportMessageAt(scanner().location(), message, args); *ok = false; return NULL; } @@ -2270,7 +2279,7 @@ Statement* Parser::ParseBreakStatement(ZoneStringList* labels, bool* ok) { message = "unknown_label"; args = Vector >(&label, 1); } - ReportMessageAt(scanner().location(), message, args); + ParserTraits::ReportMessageAt(scanner().location(), message, args); *ok = false; return NULL; } @@ -3013,14 +3022,6 @@ Expression* Parser::ParseConditionalExpression(bool accept_IN, bool* ok) { } -int ParserBase::Precedence(Token::Value tok, bool accept_IN) { - if (tok == Token::IN && !accept_IN) - return 0; // 0 precedence will terminate binary expression parsing - - return Token::Precedence(tok); -} - - // Precedence >= 4 Expression* Parser::ParseBinaryExpression(int prec, bool accept_IN, bool* ok) { ASSERT(prec >= 4); @@ -3863,8 +3864,7 @@ ZoneList* Parser::ParseArguments(bool* ok) { Expression* argument = ParseAssignmentExpression(true, CHECK_OK); result->Add(argument, zone()); if (result->length() > Code::kMaxArguments) { - ReportMessageAt(scanner().location(), "too_many_arguments", - Vector::empty()); + ReportMessageAt(scanner().location(), "too_many_arguments"); *ok = false; return NULL; } @@ -4095,8 +4095,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral( top_scope_->DeclareParameter(param_name, VAR); num_parameters++; if (num_parameters > Code::kMaxArguments) { - ReportMessageAt(scanner().location(), "too_many_parameters", - Vector::empty()); + ReportMessageAt(scanner().location(), "too_many_parameters"); *ok = false; return NULL; } @@ -4187,8 +4186,10 @@ FunctionLiteral* Parser::ParseFunctionLiteral( if (arg != NULL) { args = Vector(&arg, 1); } - ReportMessageAt(Scanner::Location(logger.start(), logger.end()), - logger.message(), args); + ParserTraits::ReportMessageAt( + Scanner::Location(logger.start(), logger.end()), + logger.message(), + args); *ok = false; return NULL; } @@ -4262,33 +4263,27 @@ FunctionLiteral* Parser::ParseFunctionLiteral( // since the function can declare itself strict. if (!top_scope_->is_classic_mode()) { if (IsEvalOrArguments(function_name)) { - ReportMessageAt(function_name_location, - "strict_eval_arguments", - Vector::empty()); + ReportMessageAt(function_name_location, "strict_eval_arguments"); *ok = false; return NULL; } if (name_is_strict_reserved) { - ReportMessageAt(function_name_location, "unexpected_strict_reserved", - Vector::empty()); + ReportMessageAt(function_name_location, "unexpected_strict_reserved"); *ok = false; return NULL; } if (eval_args_error_log.IsValid()) { - ReportMessageAt(eval_args_error_log, "strict_eval_arguments", - Vector::empty()); + ReportMessageAt(eval_args_error_log, "strict_eval_arguments"); *ok = false; return NULL; } if (dupe_error_loc.IsValid()) { - ReportMessageAt(dupe_error_loc, "strict_param_dupe", - Vector::empty()); + ReportMessageAt(dupe_error_loc, "strict_param_dupe"); *ok = false; return NULL; } if (reserved_loc.IsValid()) { - ReportMessageAt(reserved_loc, "unexpected_strict_reserved", - Vector::empty()); + ReportMessageAt(reserved_loc, "unexpected_strict_reserved"); *ok = false; return NULL; } @@ -4397,7 +4392,8 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) { // Check that the function is defined if it's an inline runtime call. if (function == NULL && name->Get(0) == '_') { - ReportMessage("not_defined", Vector >(&name, 1)); + ParserTraits::ReportMessage("not_defined", + Vector >(&name, 1)); *ok = false; return NULL; } @@ -4407,88 +4403,6 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) { } -bool ParserBase::peek_any_identifier() { - Token::Value next = peek(); - return next == Token::IDENTIFIER || - next == Token::FUTURE_RESERVED_WORD || - next == Token::FUTURE_STRICT_RESERVED_WORD || - next == Token::YIELD; -} - - -bool ParserBase::CheckContextualKeyword(Vector keyword) { - if (peek() == Token::IDENTIFIER && - scanner()->is_next_contextual_keyword(keyword)) { - Consume(Token::IDENTIFIER); - return true; - } - return false; -} - - -void ParserBase::ExpectSemicolon(bool* ok) { - // Check for automatic semicolon insertion according to - // the rules given in ECMA-262, section 7.9, page 21. - Token::Value tok = peek(); - if (tok == Token::SEMICOLON) { - Next(); - return; - } - if (scanner()->HasAnyLineTerminatorBeforeNext() || - tok == Token::RBRACE || - tok == Token::EOS) { - return; - } - Expect(Token::SEMICOLON, ok); -} - - -void ParserBase::ExpectContextualKeyword(Vector keyword, bool* ok) { - Expect(Token::IDENTIFIER, ok); - if (!*ok) return; - if (!scanner()->is_literal_contextual_keyword(keyword)) { - ReportUnexpectedToken(scanner()->current_token()); - *ok = false; - } -} - - -void ParserBase::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 - switch (token) { - case Token::EOS: - return ReportMessageAt(source_location, "unexpected_eos"); - case Token::NUMBER: - return ReportMessageAt(source_location, "unexpected_token_number"); - case Token::STRING: - return ReportMessageAt(source_location, "unexpected_token_string"); - case Token::IDENTIFIER: - return ReportMessageAt(source_location, - "unexpected_token_identifier"); - case Token::FUTURE_RESERVED_WORD: - 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"); - default: - const char* name = Token::String(token); - ASSERT(name != NULL); - ReportMessageAt( - source_location, "unexpected_token", Vector(&name, 1)); - } -} - - Literal* Parser::GetLiteralUndefined(int position) { return factory()->NewLiteral( isolate()->factory()->undefined_value(), position); @@ -4501,68 +4415,6 @@ Literal* Parser::GetLiteralTheHole(int position) { } -// Parses an identifier that is valid for the current scope, in particular it -// fails on strict mode future reserved keywords in a strict scope. If -// allow_eval_or_arguments is kAllowEvalOrArguments, we allow "eval" or -// "arguments" as identifier even in strict mode (this is needed in cases like -// "var foo = eval;"). -Handle Parser::ParseIdentifier( - AllowEvalOrArgumentsAsIdentifier allow_eval_or_arguments, - bool* ok) { - Token::Value next = Next(); - if (next == Token::IDENTIFIER) { - Handle name = GetSymbol(); - if (allow_eval_or_arguments == kDontAllowEvalOrArguments && - !top_scope_->is_classic_mode() && IsEvalOrArguments(name)) { - ReportMessage("strict_eval_arguments", Vector::empty()); - *ok = false; - } - return name; - } else if (top_scope_->is_classic_mode() && - (next == Token::FUTURE_STRICT_RESERVED_WORD || - (next == Token::YIELD && !is_generator()))) { - return GetSymbol(); - } else { - ReportUnexpectedToken(next); - *ok = false; - return Handle(); - } -} - - -// Parses and identifier or a strict mode future reserved word, and indicate -// whether it is strict mode future reserved. -Handle Parser::ParseIdentifierOrStrictReservedWord( - bool* is_strict_reserved, bool* ok) { - Token::Value next = Next(); - if (next == Token::IDENTIFIER) { - *is_strict_reserved = false; - } else if (next == Token::FUTURE_STRICT_RESERVED_WORD || - (next == Token::YIELD && !is_generator())) { - *is_strict_reserved = true; - } else { - ReportUnexpectedToken(next); - *ok = false; - return Handle(); - } - return GetSymbol(); -} - - -Handle Parser::ParseIdentifierName(bool* ok) { - Token::Value next = Next(); - if (next != Token::IDENTIFIER && - next != Token::FUTURE_RESERVED_WORD && - next != Token::FUTURE_STRICT_RESERVED_WORD && - !Token::IsKeyword(next)) { - ReportUnexpectedToken(next); - *ok = false; - return Handle(); - } - return GetSymbol(); -} - - void Parser::MarkAsLValue(Expression* expression) { VariableProxy* proxy = expression != NULL ? expression->AsVariableProxy() @@ -4588,18 +4440,6 @@ 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 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; - } -} - - void Parser::CheckConflictingVarDeclarations(Scope* scope, bool* ok) { Declaration* decl = scope->CheckConflictingVarDeclarations(); if (decl != NULL) { @@ -4613,28 +4453,12 @@ void Parser::CheckConflictingVarDeclarations(Scope* scope, bool* ok) { Scanner::Location location = position == RelocInfo::kNoPosition ? Scanner::Location::invalid() : Scanner::Location(position, position + 1); - ReportMessageAt(location, "redeclaration", args); + ParserTraits::ReportMessageAt(location, "redeclaration", args); *ok = false; } } -// This function reads an identifier name and determines whether or not it -// is 'get' or 'set'. -Handle Parser::ParseIdentifierNameOrGetOrSet(bool* is_get, - bool* is_set, - bool* ok) { - Handle result = ParseIdentifierName(ok); - if (!*ok) return Handle(); - 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; - } - return result; -} - - // ---------------------------------------------------------------------------- // Parser support @@ -5683,7 +5507,7 @@ bool Parser::Parse() { Scanner::Location loc = pre_parse_data->MessageLocation(); const char* message = pre_parse_data->BuildMessage(); Vector args = pre_parse_data->BuildArgs(); - ReportMessageAt(loc, message, args); + ParserTraits::ReportMessageAt(loc, message, args); DeleteArray(message); for (int i = 0; i < args.length(); i++) { DeleteArray(args[i]); diff --git a/src/parser.h b/src/parser.h index 2b0995a..64513d3 100644 --- a/src/parser.h +++ b/src/parser.h @@ -404,10 +404,44 @@ class RegExpParser BASE_EMBEDDED { // ---------------------------------------------------------------------------- // JAVASCRIPT PARSING -// Forward declaration. +class Parser; class SingletonLogger; -class Parser : public ParserBase { +class ParserTraits { + public: + typedef Parser* ParserType; + // Return types for traversing functions. + typedef Handle IdentifierType; + + explicit ParserTraits(Parser* parser) : parser_(parser) {} + + // Helper functions for recursive descent. + bool is_classic_mode() const; + bool is_generator() const; + bool IsEvalOrArguments(Handle identifier) const; + + // Reporting errors. + void ReportMessageAt(Scanner::Location source_location, + const char* message, + Vector args); + void ReportMessage(const char* message, Vector > args); + void ReportMessageAt(Scanner::Location source_location, + const char* message, + Vector > args); + + // Identifiers: + static IdentifierType EmptyIdentifier() { + return Handle(); + } + + IdentifierType GetSymbol(); + + private: + Parser* parser_; +}; + + +class Parser : public ParserBase { public: explicit Parser(CompilationInfo* info); ~Parser() { @@ -427,6 +461,8 @@ class Parser : public ParserBase { bool Parse(); private: + friend class ParserTraits; + static const int kMaxNumFunctionLocals = 131071; // 2^17-1 enum Mode { @@ -521,10 +557,6 @@ class Parser : public ParserBase { Mode old_mode_; }; - virtual bool is_classic_mode() { - return top_scope_->is_classic_mode(); - } - // Returns NULL if parsing failed. FunctionLiteral* ParseProgram(); @@ -541,17 +573,6 @@ class Parser : public ParserBase { // Report syntax error 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; @@ -571,9 +592,6 @@ class Parser : public ParserBase { ? top_scope_ : top_scope_->DeclarationScope(); } - // Check if the given string is 'eval' or 'arguments'. - bool IsEvalOrArguments(Handle string); - // 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 @@ -660,8 +678,6 @@ class Parser : public ParserBase { // Magical syntax support. Expression* ParseV8Intrinsic(bool* ok); - bool is_generator() const { return current_function_state_->is_generator(); } - bool CheckInOrOf(bool accept_OF, ForEachStatement::VisitMode* visit_mode); Handle LiteralString(PretenureFlag tenured) { @@ -684,20 +700,10 @@ class Parser : public ParserBase { } } - Handle GetSymbol(); - // Get odd-ball literals. Literal* GetLiteralUndefined(int position); Literal* GetLiteralTheHole(int position); - Handle ParseIdentifier(AllowEvalOrArgumentsAsIdentifier, bool* ok); - Handle ParseIdentifierOrStrictReservedWord( - bool* is_strict_reserved, bool* ok); - Handle ParseIdentifierName(bool* ok); - Handle ParseIdentifierNameOrGetOrSet(bool* is_get, - bool* is_set, - bool* ok); - // Determine if the expression is a variable proxy and mark it as being used // in an assignment or with a increment/decrement operator. This is currently // used on for the statically checking assignments to harmony const bindings. diff --git a/src/preparser.cc b/src/preparser.cc index fa6f217..c01acdd 100644 --- a/src/preparser.cc +++ b/src/preparser.cc @@ -55,6 +55,68 @@ int isfinite(double value); namespace v8 { namespace internal { +bool PreParserTraits::is_classic_mode() const { + return pre_parser_->scope_->language_mode() == CLASSIC_MODE; +} + + +bool PreParserTraits::is_generator() const { + return pre_parser_->scope_->is_generator(); +} + + +void PreParserTraits::ReportMessageAt(Scanner::Location location, + const char* message, + Vector args) { + ReportMessageAt(location.beg_pos, + location.end_pos, + message, + args.length() > 0 ? args[0] : NULL); +} + + +void PreParserTraits::ReportMessageAt(Scanner::Location location, + const char* type, + const char* name_opt) { + pre_parser_->log_ + ->LogMessage(location.beg_pos, location.end_pos, type, name_opt); +} + + +void PreParserTraits::ReportMessageAt(int start_pos, + int end_pos, + const char* type, + const char* name_opt) { + pre_parser_->log_->LogMessage(start_pos, end_pos, type, name_opt); +} + + +PreParserIdentifier PreParserTraits::GetSymbol() { + Scanner* scanner = pre_parser_->scanner(); + pre_parser_->LogSymbol(); + if (scanner->current_token() == Token::FUTURE_RESERVED_WORD) { + return PreParserIdentifier::FutureReserved(); + } else if (scanner->current_token() == + Token::FUTURE_STRICT_RESERVED_WORD) { + return PreParserIdentifier::FutureStrictReserved(); + } else if (scanner->current_token() == Token::YIELD) { + return PreParserIdentifier::Yield(); + } + if (scanner->is_literal_ascii()) { + // Detect strict-mode poison words. + if (scanner->literal_length() == 4 && + !strncmp(scanner->literal_ascii_string().start(), "eval", 4)) { + return PreParserIdentifier::Eval(); + } + if (scanner->literal_length() == 9 && + !strncmp(scanner->literal_ascii_string().start(), "arguments", 9)) { + return PreParserIdentifier::Arguments(); + } + } + return PreParserIdentifier::Default(); +} + + PreParser::PreParseResult PreParser::PreParseLazyFunction( LanguageMode mode, bool is_generator, ParserRecorder* log) { log_ = log; @@ -235,8 +297,10 @@ PreParser::Statement PreParser::ParseStatement(bool* ok) { Statement statement = ParseFunctionDeclaration(CHECK_OK); Scanner::Location end_location = scanner()->location(); if (!scope_->is_classic_mode()) { - ReportMessageAt(start_location.beg_pos, end_location.end_pos, - "strict_function", NULL); + PreParserTraits::ReportMessageAt(start_location.beg_pos, + end_location.end_pos, + "strict_function", + NULL); *ok = false; return Statement::Default(); } else { @@ -352,16 +416,14 @@ PreParser::Statement PreParser::ParseVariableDeclarations( break; case STRICT_MODE: { Scanner::Location location = scanner()->peek_location(); - ReportMessageAt(location, "strict_const", NULL); + ReportMessageAt(location, "strict_const"); *ok = false; return Statement::Default(); } case EXTENDED_MODE: if (var_context != kSourceElement && var_context != kForStatement) { - Scanner::Location location = scanner()->peek_location(); - ReportMessageAt(location.beg_pos, location.end_pos, - "unprotected_const", NULL); + ReportMessageAt(scanner()->peek_location(), "unprotected_const"); *ok = false; return Statement::Default(); } @@ -376,18 +438,14 @@ PreParser::Statement PreParser::ParseVariableDeclarations( // * It is a Syntax Error if the code that matches this production is not // contained in extended code. if (!is_extended_mode()) { - Scanner::Location location = scanner()->peek_location(); - ReportMessageAt(location.beg_pos, location.end_pos, - "illegal_let", NULL); + ReportMessageAt(scanner()->peek_location(), "illegal_let"); *ok = false; return Statement::Default(); } Consume(Token::LET); if (var_context != kSourceElement && var_context != kForStatement) { - Scanner::Location location = scanner()->peek_location(); - ReportMessageAt(location.beg_pos, location.end_pos, - "unprotected_let", NULL); + ReportMessageAt(scanner()->peek_location(), "unprotected_let"); *ok = false; return Statement::Default(); } @@ -531,8 +589,7 @@ PreParser::Statement PreParser::ParseWithStatement(bool* ok) { // 'with' '(' Expression ')' Statement Expect(Token::WITH, CHECK_OK); if (!scope_->is_classic_mode()) { - Scanner::Location location = scanner()->location(); - ReportMessageAt(location, "strict_mode_with", NULL); + ReportMessageAt(scanner()->location(), "strict_mode_with"); *ok = false; return Statement::Default(); } @@ -676,8 +733,7 @@ PreParser::Statement PreParser::ParseThrowStatement(bool* ok) { Expect(Token::THROW, CHECK_OK); if (scanner()->HasAnyLineTerminatorBeforeNext()) { - Scanner::Location pos = scanner()->location(); - ReportMessageAt(pos, "newline_after_throw", NULL); + ReportMessageAt(scanner()->location(), "newline_after_throw"); *ok = false; return Statement::Default(); } @@ -705,7 +761,7 @@ PreParser::Statement PreParser::ParseTryStatement(bool* ok) { Token::Value tok = peek(); if (tok != Token::CATCH && tok != Token::FINALLY) { - ReportMessageAt(scanner()->location(), "no_catch_or_finally", NULL); + ReportMessageAt(scanner()->location(), "no_catch_or_finally"); *ok = false; return Statement::Default(); } @@ -788,8 +844,8 @@ PreParser::Expression PreParser::ParseAssignmentExpression(bool accept_IN, expression.IsIdentifier() && expression.AsIdentifier().IsEvalOrArguments()) { Scanner::Location after = scanner()->location(); - ReportMessageAt(before.beg_pos, after.end_pos, - "strict_eval_arguments", NULL); + PreParserTraits::ReportMessageAt(before.beg_pos, after.end_pos, + "strict_eval_arguments", NULL); *ok = false; return Expression::Default(); } @@ -882,8 +938,8 @@ PreParser::Expression PreParser::ParseUnaryExpression(bool* ok) { expression.IsIdentifier() && expression.AsIdentifier().IsEvalOrArguments()) { Scanner::Location after = scanner()->location(); - ReportMessageAt(before.beg_pos, after.end_pos, - "strict_eval_arguments", NULL); + PreParserTraits::ReportMessageAt(before.beg_pos, after.end_pos, + "strict_eval_arguments", NULL); *ok = false; } return Expression::Default(); @@ -905,8 +961,8 @@ PreParser::Expression PreParser::ParsePostfixExpression(bool* ok) { expression.IsIdentifier() && expression.AsIdentifier().IsEvalOrArguments()) { Scanner::Location after = scanner()->location(); - ReportMessageAt(before.beg_pos, after.end_pos, - "strict_eval_arguments", NULL); + PreParserTraits::ReportMessageAt(before.beg_pos, after.end_pos, + "strict_eval_arguments", NULL); *ok = false; return Expression::Default(); } @@ -1249,7 +1305,7 @@ PreParser::Expression PreParser::ParseRegExpLiteral(bool seen_equal, bool* ok) { if (!scanner()->ScanRegExpPattern(seen_equal)) { Next(); - ReportMessageAt(scanner()->location(), "unterminated_regexp", NULL); + ReportMessageAt(scanner()->location(), "unterminated_regexp"); *ok = false; return Expression::Default(); } @@ -1258,7 +1314,7 @@ PreParser::Expression PreParser::ParseRegExpLiteral(bool seen_equal, if (!scanner()->ScanRegExpFlags()) { Next(); - ReportMessageAt(scanner()->location(), "invalid_regexp_flags", NULL); + ReportMessageAt(scanner()->location(), "invalid_regexp_flags"); *ok = false; return Expression::Default(); } @@ -1366,31 +1422,27 @@ PreParser::Expression PreParser::ParseFunctionLiteral( // since the function can declare itself strict. if (!scope_->is_classic_mode()) { if (function_name.IsEvalOrArguments()) { - ReportMessageAt(function_name_location, "strict_eval_arguments", NULL); + ReportMessageAt(function_name_location, "strict_eval_arguments"); *ok = false; return Expression::Default(); } if (name_is_strict_reserved) { - ReportMessageAt( - function_name_location, "unexpected_strict_reserved", NULL); + ReportMessageAt(function_name_location, "unexpected_strict_reserved"); *ok = false; return Expression::Default(); } if (eval_args_error_loc.IsValid()) { - ReportMessageAt(eval_args_error_loc, "strict_eval_arguments", - Vector::empty()); + ReportMessageAt(eval_args_error_loc, "strict_eval_arguments"); *ok = false; return Expression::Default(); } if (dupe_error_loc.IsValid()) { - ReportMessageAt(dupe_error_loc, "strict_param_dupe", - Vector::empty()); + ReportMessageAt(dupe_error_loc, "strict_param_dupe"); *ok = false; return Expression::Default(); } if (reserved_error_loc.IsValid()) { - ReportMessageAt(reserved_error_loc, "unexpected_strict_reserved", - Vector::empty()); + ReportMessageAt(reserved_error_loc, "unexpected_strict_reserved"); *ok = false; return Expression::Default(); } @@ -1464,142 +1516,4 @@ PreParser::Expression PreParser::GetStringSymbol() { } -PreParser::Identifier PreParser::GetIdentifierSymbol() { - LogSymbol(); - if (scanner()->current_token() == Token::FUTURE_RESERVED_WORD) { - return Identifier::FutureReserved(); - } else if (scanner()->current_token() == - Token::FUTURE_STRICT_RESERVED_WORD) { - return Identifier::FutureStrictReserved(); - } else if (scanner()->current_token() == Token::YIELD) { - return Identifier::Yield(); - } - if (scanner()->is_literal_ascii()) { - // Detect strict-mode poison words. - if (scanner()->literal_length() == 4 && - !strncmp(scanner()->literal_ascii_string().start(), "eval", 4)) { - return Identifier::Eval(); - } - if (scanner()->literal_length() == 9 && - !strncmp(scanner()->literal_ascii_string().start(), "arguments", 9)) { - return Identifier::Arguments(); - } - } - return Identifier::Default(); -} - - -// Parses an identifier that is valid for the current scope, in particular it -// fails on strict mode future reserved keywords in a strict scope. If -// allow_eval_or_arguments is kAllowEvalOrArguments, we allow "eval" or -// "arguments" as identifier even in strict mode (this is needed in cases like -// "var foo = eval;"). -PreParser::Identifier PreParser::ParseIdentifier( - AllowEvalOrArgumentsAsIdentifier allow_eval_or_arguments, - bool* ok) { - Token::Value next = Next(); - if (next == Token::IDENTIFIER) { - PreParser::Identifier name = GetIdentifierSymbol(); - if (allow_eval_or_arguments == kDontAllowEvalOrArguments && - !scope_->is_classic_mode() && name.IsEvalOrArguments()) { - ReportMessageAt(scanner()->location(), "strict_eval_arguments", NULL); - *ok = false; - } - return name; - } else if (scope_->is_classic_mode() && - (next == Token::FUTURE_STRICT_RESERVED_WORD || - (next == Token::YIELD && !scope_->is_generator()))) { - return GetIdentifierSymbol(); - } else { - ReportUnexpectedToken(next); - *ok = false; - return Identifier::Default(); - } -} - - -// Parses and identifier or a strict mode future reserved word, and indicate -// whether it is strict mode future reserved. -PreParser::Identifier PreParser::ParseIdentifierOrStrictReservedWord( - bool* is_strict_reserved, bool* ok) { - Token::Value next = Next(); - if (next == Token::IDENTIFIER) { - *is_strict_reserved = false; - } else if (next == Token::FUTURE_STRICT_RESERVED_WORD || - (next == Token::YIELD && !scope_->is_generator())) { - *is_strict_reserved = true; - } else { - ReportUnexpectedToken(next); - *ok = false; - return Identifier::Default(); - } - return GetIdentifierSymbol(); -} - - -PreParser::Identifier PreParser::ParseIdentifierName(bool* ok) { - Token::Value next = Next(); - if (next != Token::IDENTIFIER && - next != Token::FUTURE_RESERVED_WORD && - next != Token::FUTURE_STRICT_RESERVED_WORD && - !Token::IsKeyword(next)) { - ReportUnexpectedToken(next); - *ok = false; - return Identifier::Default(); - } - return GetIdentifierSymbol(); -} - -#undef CHECK_OK - - -// This function reads an identifier and determines whether or not it -// is 'get' or 'set'. -PreParser::Identifier PreParser::ParseIdentifierNameOrGetOrSet(bool* is_get, - bool* is_set, - bool* ok) { - Identifier result = ParseIdentifierName(ok); - if (!*ok) return Identifier::Default(); - 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; - } - return result; -} - - -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 bcaab74..62ac5b8 100644 --- a/src/preparser.h +++ b/src/preparser.h @@ -36,18 +36,19 @@ namespace v8 { namespace internal { // Common base class shared between parser and pre-parser. -class ParserBase { +template +class ParserBase : public Traits { public: - ParserBase(Scanner* scanner, uintptr_t stack_limit) - : scanner_(scanner), + ParserBase(Scanner* scanner, uintptr_t stack_limit, + typename Traits::ParserType this_object) + : Traits(this_object), + scanner_(scanner), stack_limit_(stack_limit), stack_overflow_(false), allow_lazy_(false), allow_natives_syntax_(false), allow_generators_(false), allow_for_of_(false) { } - // TODO(mstarzinger): Only virtual until message reporting has been unified. - virtual ~ParserBase() { } // Getters that indicate whether certain syntactical constructs are // allowed to be parsed by this instance of the parser. @@ -87,8 +88,6 @@ class ParserBase { bool stack_overflow() const { return stack_overflow_; } void set_stack_overflow() { stack_overflow_ = true; } - virtual bool is_classic_mode() = 0; - INLINE(Token::Value peek()) { if (stack_overflow_) return Token::ILLEGAL; return scanner()->peek(); @@ -132,25 +131,99 @@ class ParserBase { } } - bool peek_any_identifier(); - void ExpectSemicolon(bool* ok); - bool CheckContextualKeyword(Vector keyword); - void ExpectContextualKeyword(Vector keyword, bool* ok); + void ExpectSemicolon(bool* ok) { + // Check for automatic semicolon insertion according to + // the rules given in ECMA-262, section 7.9, page 21. + Token::Value tok = peek(); + if (tok == Token::SEMICOLON) { + Next(); + return; + } + if (scanner()->HasAnyLineTerminatorBeforeNext() || + tok == Token::RBRACE || + tok == Token::EOS) { + return; + } + Expect(Token::SEMICOLON, ok); + } + + bool peek_any_identifier() { + Token::Value next = peek(); + return next == Token::IDENTIFIER || + next == Token::FUTURE_RESERVED_WORD || + next == Token::FUTURE_STRICT_RESERVED_WORD || + next == Token::YIELD; + } - // Strict mode octal literal validation. - void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok); + bool CheckContextualKeyword(Vector keyword) { + if (peek() == Token::IDENTIFIER && + scanner()->is_next_contextual_keyword(keyword)) { + Consume(Token::IDENTIFIER); + return true; + } + return false; + } + + void ExpectContextualKeyword(Vector keyword, bool* ok) { + Expect(Token::IDENTIFIER, ok); + if (!*ok) return; + if (!scanner()->is_literal_contextual_keyword(keyword)) { + ReportUnexpectedToken(scanner()->current_token()); + *ok = false; + } + } + + // 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 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; + } + } // Determine precedence of given token. - static int Precedence(Token::Value token, bool accept_IN); + static int Precedence(Token::Value token, bool accept_IN) { + if (token == Token::IN && !accept_IN) + return 0; // 0 precedence will terminate binary expression parsing + return Token::Precedence(token); + } // Report syntax errors. - void ReportUnexpectedToken(Token::Value token); - void ReportMessageAt(Scanner::Location location, const char* type) { - ReportMessageAt(location, type, Vector::empty()); + void ReportMessage(const char* message, Vector args) { + Scanner::Location source_location = scanner()->location(); + Traits::ReportMessageAt(source_location, message, args); } - virtual void ReportMessageAt(Scanner::Location source_location, - const char* message, - Vector args) = 0; + + void ReportMessageAt(Scanner::Location location, const char* message) { + Traits::ReportMessageAt(location, message, Vector::empty()); + } + + void ReportUnexpectedToken(Token::Value token); + + // Recursive descent functions: + + // Parses an identifier that is valid for the current scope, in particular it + // fails on strict mode future reserved keywords in a strict scope. If + // allow_eval_or_arguments is kAllowEvalOrArguments, we allow "eval" or + // "arguments" as identifier even in strict mode (this is needed in cases like + // "var foo = eval;"). + typename Traits::IdentifierType ParseIdentifier( + AllowEvalOrArgumentsAsIdentifier, + bool* ok); + // Parses an identifier or a strict mode future reserved word, and indicate + // whether it is strict mode future reserved. + typename Traits::IdentifierType ParseIdentifierOrStrictReservedWord( + bool* is_strict_reserved, + bool* ok); + typename Traits::IdentifierType ParseIdentifierName(bool* ok); + // Parses an identifier and determines whether or not it is 'get' or 'set'. + typename Traits::IdentifierType ParseIdentifierNameOrGetOrSet(bool* is_get, + bool* is_set, + bool* ok); // Used to detect duplicates in object literals. Each of the values // kGetterProperty, kSetterProperty and kValueProperty represents @@ -218,6 +291,176 @@ class ParserBase { }; +class PreParserIdentifier { + public: + static PreParserIdentifier Default() { + return PreParserIdentifier(kUnknownIdentifier); + } + static PreParserIdentifier Eval() { + return PreParserIdentifier(kEvalIdentifier); + } + static PreParserIdentifier Arguments() { + return PreParserIdentifier(kArgumentsIdentifier); + } + static PreParserIdentifier FutureReserved() { + return PreParserIdentifier(kFutureReservedIdentifier); + } + static PreParserIdentifier FutureStrictReserved() { + return PreParserIdentifier(kFutureStrictReservedIdentifier); + } + static PreParserIdentifier Yield() { + return PreParserIdentifier(kYieldIdentifier); + } + bool IsEval() { return type_ == kEvalIdentifier; } + bool IsArguments() { return type_ == kArgumentsIdentifier; } + bool IsEvalOrArguments() { return type_ >= kEvalIdentifier; } + bool IsYield() { return type_ == kYieldIdentifier; } + bool IsFutureReserved() { return type_ == kFutureReservedIdentifier; } + bool IsFutureStrictReserved() { + return type_ == kFutureStrictReservedIdentifier; + } + bool IsValidStrictVariable() { return type_ == kUnknownIdentifier; } + + private: + enum Type { + kUnknownIdentifier, + kFutureReservedIdentifier, + kFutureStrictReservedIdentifier, + kYieldIdentifier, + kEvalIdentifier, + kArgumentsIdentifier + }; + explicit PreParserIdentifier(Type type) : type_(type) {} + Type type_; + + friend class PreParserExpression; +}; + + +// Bits 0 and 1 are used to identify the type of expression: +// If bit 0 is set, it's an identifier. +// if bit 1 is set, it's a string literal. +// If neither is set, it's no particular type, and both set isn't +// use yet. +class PreParserExpression { + public: + static PreParserExpression Default() { + return PreParserExpression(kUnknownExpression); + } + + static PreParserExpression FromIdentifier(PreParserIdentifier id) { + return PreParserExpression(kIdentifierFlag | + (id.type_ << kIdentifierShift)); + } + + static PreParserExpression StringLiteral() { + return PreParserExpression(kUnknownStringLiteral); + } + + static PreParserExpression UseStrictStringLiteral() { + return PreParserExpression(kUseStrictString); + } + + static PreParserExpression This() { + return PreParserExpression(kThisExpression); + } + + static PreParserExpression ThisProperty() { + return PreParserExpression(kThisPropertyExpression); + } + + static PreParserExpression StrictFunction() { + return PreParserExpression(kStrictFunctionExpression); + } + + bool IsIdentifier() { return (code_ & kIdentifierFlag) != 0; } + + // Only works corretly if it is actually an identifier expression. + PreParserIdentifier AsIdentifier() { + return PreParserIdentifier( + static_cast(code_ >> kIdentifierShift)); + } + + bool IsStringLiteral() { return (code_ & kStringLiteralFlag) != 0; } + + bool IsUseStrictLiteral() { + return (code_ & kStringLiteralMask) == kUseStrictString; + } + + bool IsThis() { return code_ == kThisExpression; } + + bool IsThisProperty() { return code_ == kThisPropertyExpression; } + + bool IsStrictFunction() { return code_ == kStrictFunctionExpression; } + + private: + // First two/three bits are used as flags. + // Bit 0 and 1 represent identifiers or strings literals, and are + // mutually exclusive, but can both be absent. + enum { + kUnknownExpression = 0, + // Identifiers + kIdentifierFlag = 1, // Used to detect labels. + kIdentifierShift = 3, + + kStringLiteralFlag = 2, // Used to detect directive prologue. + kUnknownStringLiteral = kStringLiteralFlag, + kUseStrictString = kStringLiteralFlag | 8, + kStringLiteralMask = kUseStrictString, + + // Below here applies if neither identifier nor string literal. + kThisExpression = 4, + kThisPropertyExpression = 8, + kStrictFunctionExpression = 12 + }; + + explicit PreParserExpression(int expression_code) : code_(expression_code) {} + + int code_; +}; + +class PreParser; + + +class PreParserTraits { + public: + typedef PreParser* ParserType; + // Return types for traversing functions. + typedef PreParserIdentifier IdentifierType; + + explicit PreParserTraits(PreParser* pre_parser) : pre_parser_(pre_parser) {} + + // Helper functions for recursive descent. + bool is_classic_mode() const; + bool is_generator() const; + static bool IsEvalOrArguments(IdentifierType identifier) { + return identifier.IsEvalOrArguments(); + } + + // Reporting errors. + void ReportMessageAt(Scanner::Location location, + const char* message, + Vector args); + void ReportMessageAt(Scanner::Location location, + const char* type, + const char* name_opt); + void ReportMessageAt(int start_pos, + int end_pos, + const char* type, + const char* name_opt); + + // Identifiers: + static IdentifierType EmptyIdentifier() { + return PreParserIdentifier::Default(); + } + + IdentifierType GetSymbol(); + + private: + PreParser* pre_parser_; +}; + + // Preparsing checks a JavaScript program and emits preparse-data that helps // a later parsing to be faster. // See preparse-data-format.h for the data format. @@ -230,8 +473,11 @@ class ParserBase { // rather it is to speed up properly written and correct programs. // That means that contextual checks (like a label being declared where // it is used) are generally omitted. -class PreParser : public ParserBase { +class PreParser : public ParserBase { public: + typedef PreParserIdentifier Identifier; + typedef PreParserExpression Expression; + enum PreParseResult { kPreParseStackOverflow, kPreParseSuccess @@ -240,7 +486,7 @@ class PreParser : public ParserBase { PreParser(Scanner* scanner, ParserRecorder* log, uintptr_t stack_limit) - : ParserBase(scanner, stack_limit), + : ParserBase(scanner, stack_limit, this), log_(log), scope_(NULL), parenthesized_function_(false) { } @@ -278,6 +524,8 @@ class PreParser : public ParserBase { ParserRecorder* log); private: + friend class PreParserTraits; + // These types form an algebra over syntactic categories that is just // rich enough to let us recognize and propagate the constructs that // are either being counted in the preparser data, or is important @@ -300,142 +548,6 @@ class PreParser : public ParserBase { kHasNoInitializers }; - class Expression; - - class Identifier { - public: - static Identifier Default() { - return Identifier(kUnknownIdentifier); - } - static Identifier Eval() { - return Identifier(kEvalIdentifier); - } - static Identifier Arguments() { - return Identifier(kArgumentsIdentifier); - } - static Identifier FutureReserved() { - return Identifier(kFutureReservedIdentifier); - } - static Identifier FutureStrictReserved() { - return Identifier(kFutureStrictReservedIdentifier); - } - static Identifier Yield() { - return Identifier(kYieldIdentifier); - } - bool IsEval() { return type_ == kEvalIdentifier; } - bool IsArguments() { return type_ == kArgumentsIdentifier; } - bool IsEvalOrArguments() { return type_ >= kEvalIdentifier; } - bool IsYield() { return type_ == kYieldIdentifier; } - bool IsFutureReserved() { return type_ == kFutureReservedIdentifier; } - bool IsFutureStrictReserved() { - return type_ == kFutureStrictReservedIdentifier; - } - bool IsValidStrictVariable() { return type_ == kUnknownIdentifier; } - - private: - enum Type { - kUnknownIdentifier, - kFutureReservedIdentifier, - kFutureStrictReservedIdentifier, - kYieldIdentifier, - kEvalIdentifier, - kArgumentsIdentifier - }; - explicit Identifier(Type type) : type_(type) { } - Type type_; - - friend class Expression; - }; - - // Bits 0 and 1 are used to identify the type of expression: - // If bit 0 is set, it's an identifier. - // if bit 1 is set, it's a string literal. - // If neither is set, it's no particular type, and both set isn't - // use yet. - class Expression { - public: - static Expression Default() { - return Expression(kUnknownExpression); - } - - static Expression FromIdentifier(Identifier id) { - return Expression(kIdentifierFlag | (id.type_ << kIdentifierShift)); - } - - static Expression StringLiteral() { - return Expression(kUnknownStringLiteral); - } - - static Expression UseStrictStringLiteral() { - return Expression(kUseStrictString); - } - - static Expression This() { - return Expression(kThisExpression); - } - - static Expression ThisProperty() { - return Expression(kThisPropertyExpression); - } - - static Expression StrictFunction() { - return Expression(kStrictFunctionExpression); - } - - bool IsIdentifier() { - return (code_ & kIdentifierFlag) != 0; - } - - // Only works corretly if it is actually an identifier expression. - PreParser::Identifier AsIdentifier() { - return PreParser::Identifier( - static_cast(code_ >> kIdentifierShift)); - } - - bool IsStringLiteral() { return (code_ & kStringLiteralFlag) != 0; } - - bool IsUseStrictLiteral() { - return (code_ & kStringLiteralMask) == kUseStrictString; - } - - bool IsThis() { - return code_ == kThisExpression; - } - - bool IsThisProperty() { - return code_ == kThisPropertyExpression; - } - - bool IsStrictFunction() { - return code_ == kStrictFunctionExpression; - } - - private: - // First two/three bits are used as flags. - // Bit 0 and 1 represent identifiers or strings literals, and are - // mutually exclusive, but can both be absent. - enum { - kUnknownExpression = 0, - // Identifiers - kIdentifierFlag = 1, // Used to detect labels. - kIdentifierShift = 3, - - kStringLiteralFlag = 2, // Used to detect directive prologue. - kUnknownStringLiteral = kStringLiteralFlag, - kUseStrictString = kStringLiteralFlag | 8, - kStringLiteralMask = kUseStrictString, - - // Below here applies if neither identifier nor string literal. - kThisExpression = 4, - kThisPropertyExpression = 8, - kStrictFunctionExpression = 12 - }; - - explicit Expression(int expression_code) : code_(expression_code) { } - - int code_; - }; - class Statement { public: static Statement Default() { @@ -546,27 +658,6 @@ class PreParser : public ParserBase { bool is_generator_; }; - // Report syntax error - void ReportMessageAt(Scanner::Location location, - const char* message, - Vector args) { - ReportMessageAt(location.beg_pos, - location.end_pos, - message, - args.length() > 0 ? args[0] : NULL); - } - void ReportMessageAt(Scanner::Location location, - const char* type, - const char* name_opt) { - log_->LogMessage(location.beg_pos, location.end_pos, type, name_opt); - } - void ReportMessageAt(int start_pos, - int end_pos, - const char* type, - const char* name_opt) { - log_->LogMessage(start_pos, end_pos, type, name_opt); - } - // 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 @@ -622,18 +713,8 @@ class PreParser : public ParserBase { bool* ok); void ParseLazyFunctionLiteralBody(bool* ok); - Identifier ParseIdentifier(AllowEvalOrArgumentsAsIdentifier, bool* ok); - Identifier ParseIdentifierOrStrictReservedWord(bool* is_strict_reserved, - bool* ok); - Identifier ParseIdentifierName(bool* ok); - Identifier ParseIdentifierNameOrGetOrSet(bool* is_get, - bool* is_set, - bool* ok); - // Logs the currently parsed literal as a symbol in the preparser data. void LogSymbol(); - // Log the currently parsed identifier. - Identifier GetIdentifierSymbol(); // Log the currently parsed string literal. Expression GetStringSymbol(); @@ -641,10 +722,6 @@ class PreParser : public ParserBase { scope_->set_language_mode(language_mode); } - virtual bool is_classic_mode() { - return scope_->language_mode() == CLASSIC_MODE; - } - bool is_extended_mode() { return scope_->language_mode() == EXTENDED_MODE; } @@ -658,6 +735,154 @@ class PreParser : public ParserBase { bool parenthesized_function_; }; + +template +void ParserBase::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 + switch (token) { + case Token::EOS: + return ReportMessageAt(source_location, "unexpected_eos"); + case Token::NUMBER: + return ReportMessageAt(source_location, "unexpected_token_number"); + case Token::STRING: + return ReportMessageAt(source_location, "unexpected_token_string"); + case Token::IDENTIFIER: + return ReportMessageAt(source_location, "unexpected_token_identifier"); + case Token::FUTURE_RESERVED_WORD: + return ReportMessageAt(source_location, "unexpected_reserved"); + case Token::YIELD: + case Token::FUTURE_STRICT_RESERVED_WORD: + return ReportMessageAt( + source_location, + this->is_classic_mode() ? "unexpected_token_identifier" + : "unexpected_strict_reserved"); + default: + const char* name = Token::String(token); + ASSERT(name != NULL); + Traits::ReportMessageAt( + source_location, "unexpected_token", Vector(&name, 1)); + } +} + + +template +typename Traits::IdentifierType ParserBase::ParseIdentifier( + AllowEvalOrArgumentsAsIdentifier allow_eval_or_arguments, + bool* ok) { + Token::Value next = Next(); + if (next == Token::IDENTIFIER) { + typename Traits::IdentifierType name = this->GetSymbol(); + if (allow_eval_or_arguments == kDontAllowEvalOrArguments && + !this->is_classic_mode() && this->IsEvalOrArguments(name)) { + ReportMessageAt(scanner()->location(), "strict_eval_arguments"); + *ok = false; + } + return name; + } else if (this->is_classic_mode() && + (next == Token::FUTURE_STRICT_RESERVED_WORD || + (next == Token::YIELD && !this->is_generator()))) { + return this->GetSymbol(); + } else { + this->ReportUnexpectedToken(next); + *ok = false; + return Traits::EmptyIdentifier(); + } +} + + +template +typename Traits::IdentifierType ParserBase< + Traits>::ParseIdentifierOrStrictReservedWord(bool* is_strict_reserved, + bool* ok) { + Token::Value next = Next(); + if (next == Token::IDENTIFIER) { + *is_strict_reserved = false; + } else if (next == Token::FUTURE_STRICT_RESERVED_WORD || + (next == Token::YIELD && !this->is_generator())) { + *is_strict_reserved = true; + } else { + ReportUnexpectedToken(next); + *ok = false; + return Traits::EmptyIdentifier(); + } + return this->GetSymbol(); +} + + +template +typename Traits::IdentifierType ParserBase::ParseIdentifierName( + bool* ok) { + Token::Value next = Next(); + if (next != Token::IDENTIFIER && next != Token::FUTURE_RESERVED_WORD && + next != Token::FUTURE_STRICT_RESERVED_WORD && !Token::IsKeyword(next)) { + this->ReportUnexpectedToken(next); + *ok = false; + return Traits::EmptyIdentifier(); + } + return this->GetSymbol(); +} + + +template +typename Traits::IdentifierType +ParserBase::ParseIdentifierNameOrGetOrSet(bool* is_get, + bool* is_set, + bool* ok) { + typename Traits::IdentifierType 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; + } + return result; +} + + +template +void ParserBase::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 #endif // V8_PREPARSER_H diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc index 22d5056..f3f238c 100644 --- a/test/cctest/test-parsing.cc +++ b/test/cctest/test-parsing.cc @@ -1108,8 +1108,9 @@ enum ParserSyncTestResult { kError }; - -void SetParserFlags(i::ParserBase* parser, i::EnumSet flags) { +template +void SetParserFlags(i::ParserBase* parser, + i::EnumSet flags) { parser->set_allow_lazy(flags.Contains(kAllowLazy)); parser->set_allow_natives_syntax(flags.Contains(kAllowNativesSyntax)); parser->set_allow_harmony_scoping(flags.Contains(kAllowHarmonyScoping)); -- 2.7.4