diff --git a/src/parser.cc b/src/parser.cc index f03ec02cec..5e7680e6c1 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -533,78 +533,8 @@ 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(), - this), + : ParserBase(&scanner_, info->isolate()->stack_guard()->real_climit()), isolate_(info->isolate()), symbol_cache_(0, info->zone()), script_(info->script()), @@ -863,6 +793,62 @@ 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, @@ -1095,8 +1081,8 @@ Module* Parser::ParseModuleLiteral(bool* ok) { !it.done(); it.Advance()) { if (scope->LocalLookup(it.name()) == NULL) { Handle name(it.name()); - ParserTraits::ReportMessage("module_export_undefined", - Vector >(&name, 1)); + ReportMessage("module_export_undefined", + Vector >(&name, 1)); *ok = false; return NULL; } @@ -1135,8 +1121,7 @@ Module* Parser::ParseModulePath(bool* ok) { member->interface()->Print(); } #endif - ParserTraits::ReportMessage("invalid_module_path", - Vector >(&name, 1)); + ReportMessage("invalid_module_path", Vector >(&name, 1)); return NULL; } result = member; @@ -1246,8 +1231,7 @@ Block* Parser::ParseImportDeclaration(bool* ok) { module->interface()->Print(); } #endif - ParserTraits::ReportMessage("invalid_module_path", - Vector >(&name, 1)); + ReportMessage("invalid_module_path", Vector >(&name, 1)); return NULL; } VariableProxy* proxy = NewUnresolved(names[i], LET, interface); @@ -1455,7 +1439,8 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) { // Statement: // GeneratorDeclaration if (!top_scope_->is_classic_mode()) { - ReportMessageAt(scanner().peek_location(), "strict_function"); + ReportMessageAt(scanner().peek_location(), "strict_function", + Vector::empty()); *ok = false; return NULL; } @@ -1634,8 +1619,7 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) { var->interface()->Print(); } #endif - ParserTraits::ReportMessage("module_type_error", - Vector >(&name, 1)); + ReportMessage("module_type_error", Vector >(&name, 1)); } } } @@ -1793,6 +1777,12 @@ 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 @@ -1938,7 +1928,8 @@ Block* Parser::ParseVariableDeclarations( Declare(declaration, mode != VAR, CHECK_OK); nvars++; if (declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) { - ReportMessageAt(scanner().location(), "too_many_variables"); + ReportMessageAt(scanner().location(), "too_many_variables", + Vector::empty()); *ok = false; return NULL; } @@ -2241,7 +2232,7 @@ Statement* Parser::ParseContinueStatement(bool* ok) { message = "unknown_label"; args = Vector >(&label, 1); } - ParserTraits::ReportMessageAt(scanner().location(), message, args); + ReportMessageAt(scanner().location(), message, args); *ok = false; return NULL; } @@ -2279,7 +2270,7 @@ Statement* Parser::ParseBreakStatement(ZoneStringList* labels, bool* ok) { message = "unknown_label"; args = Vector >(&label, 1); } - ParserTraits::ReportMessageAt(scanner().location(), message, args); + ReportMessageAt(scanner().location(), message, args); *ok = false; return NULL; } @@ -3022,6 +3013,14 @@ 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); @@ -3864,7 +3863,8 @@ 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"); + ReportMessageAt(scanner().location(), "too_many_arguments", + Vector::empty()); *ok = false; return NULL; } @@ -4095,7 +4095,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral( top_scope_->DeclareParameter(param_name, VAR); num_parameters++; if (num_parameters > Code::kMaxArguments) { - ReportMessageAt(scanner().location(), "too_many_parameters"); + ReportMessageAt(scanner().location(), "too_many_parameters", + Vector::empty()); *ok = false; return NULL; } @@ -4186,10 +4187,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral( if (arg != NULL) { args = Vector(&arg, 1); } - ParserTraits::ReportMessageAt( - Scanner::Location(logger.start(), logger.end()), - logger.message(), - args); + ReportMessageAt(Scanner::Location(logger.start(), logger.end()), + logger.message(), args); *ok = false; return NULL; } @@ -4263,27 +4262,33 @@ 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"); + ReportMessageAt(function_name_location, + "strict_eval_arguments", + Vector::empty()); *ok = false; return NULL; } if (name_is_strict_reserved) { - ReportMessageAt(function_name_location, "unexpected_strict_reserved"); + ReportMessageAt(function_name_location, "unexpected_strict_reserved", + Vector::empty()); *ok = false; return NULL; } if (eval_args_error_log.IsValid()) { - ReportMessageAt(eval_args_error_log, "strict_eval_arguments"); + ReportMessageAt(eval_args_error_log, "strict_eval_arguments", + Vector::empty()); *ok = false; return NULL; } if (dupe_error_loc.IsValid()) { - ReportMessageAt(dupe_error_loc, "strict_param_dupe"); + ReportMessageAt(dupe_error_loc, "strict_param_dupe", + Vector::empty()); *ok = false; return NULL; } if (reserved_loc.IsValid()) { - ReportMessageAt(reserved_loc, "unexpected_strict_reserved"); + ReportMessageAt(reserved_loc, "unexpected_strict_reserved", + Vector::empty()); *ok = false; return NULL; } @@ -4392,8 +4397,7 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) { // Check that the function is defined if it's an inline runtime call. if (function == NULL && name->Get(0) == '_') { - ParserTraits::ReportMessage("not_defined", - Vector >(&name, 1)); + ReportMessage("not_defined", Vector >(&name, 1)); *ok = false; return NULL; } @@ -4403,6 +4407,88 @@ 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); @@ -4415,6 +4501,68 @@ 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() @@ -4440,6 +4588,18 @@ 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) { @@ -4453,12 +4613,28 @@ void Parser::CheckConflictingVarDeclarations(Scope* scope, bool* ok) { Scanner::Location location = position == RelocInfo::kNoPosition ? Scanner::Location::invalid() : Scanner::Location(position, position + 1); - ParserTraits::ReportMessageAt(location, "redeclaration", args); + 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 @@ -5507,7 +5683,7 @@ bool Parser::Parse() { Scanner::Location loc = pre_parse_data->MessageLocation(); const char* message = pre_parse_data->BuildMessage(); Vector args = pre_parse_data->BuildArgs(); - ParserTraits::ReportMessageAt(loc, message, args); + 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 64513d3569..2b0995ace2 100644 --- a/src/parser.h +++ b/src/parser.h @@ -404,44 +404,10 @@ class RegExpParser BASE_EMBEDDED { // ---------------------------------------------------------------------------- // JAVASCRIPT PARSING -class Parser; +// Forward declaration. class SingletonLogger; -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 { +class Parser : public ParserBase { public: explicit Parser(CompilationInfo* info); ~Parser() { @@ -461,8 +427,6 @@ class Parser : public ParserBase { bool Parse(); private: - friend class ParserTraits; - static const int kMaxNumFunctionLocals = 131071; // 2^17-1 enum Mode { @@ -557,6 +521,10 @@ 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(); @@ -573,6 +541,17 @@ 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; @@ -592,6 +571,9 @@ 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 @@ -678,6 +660,8 @@ 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) { @@ -700,10 +684,20 @@ 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 c01acddebd..fa6f217993 100644 --- a/src/preparser.cc +++ b/src/preparser.cc @@ -55,68 +55,6 @@ 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; @@ -297,10 +235,8 @@ PreParser::Statement PreParser::ParseStatement(bool* ok) { Statement statement = ParseFunctionDeclaration(CHECK_OK); Scanner::Location end_location = scanner()->location(); if (!scope_->is_classic_mode()) { - PreParserTraits::ReportMessageAt(start_location.beg_pos, - end_location.end_pos, - "strict_function", - NULL); + ReportMessageAt(start_location.beg_pos, end_location.end_pos, + "strict_function", NULL); *ok = false; return Statement::Default(); } else { @@ -416,14 +352,16 @@ PreParser::Statement PreParser::ParseVariableDeclarations( break; case STRICT_MODE: { Scanner::Location location = scanner()->peek_location(); - ReportMessageAt(location, "strict_const"); + ReportMessageAt(location, "strict_const", NULL); *ok = false; return Statement::Default(); } case EXTENDED_MODE: if (var_context != kSourceElement && var_context != kForStatement) { - ReportMessageAt(scanner()->peek_location(), "unprotected_const"); + Scanner::Location location = scanner()->peek_location(); + ReportMessageAt(location.beg_pos, location.end_pos, + "unprotected_const", NULL); *ok = false; return Statement::Default(); } @@ -438,14 +376,18 @@ 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()) { - ReportMessageAt(scanner()->peek_location(), "illegal_let"); + Scanner::Location location = scanner()->peek_location(); + ReportMessageAt(location.beg_pos, location.end_pos, + "illegal_let", NULL); *ok = false; return Statement::Default(); } Consume(Token::LET); if (var_context != kSourceElement && var_context != kForStatement) { - ReportMessageAt(scanner()->peek_location(), "unprotected_let"); + Scanner::Location location = scanner()->peek_location(); + ReportMessageAt(location.beg_pos, location.end_pos, + "unprotected_let", NULL); *ok = false; return Statement::Default(); } @@ -589,7 +531,8 @@ PreParser::Statement PreParser::ParseWithStatement(bool* ok) { // 'with' '(' Expression ')' Statement Expect(Token::WITH, CHECK_OK); if (!scope_->is_classic_mode()) { - ReportMessageAt(scanner()->location(), "strict_mode_with"); + Scanner::Location location = scanner()->location(); + ReportMessageAt(location, "strict_mode_with", NULL); *ok = false; return Statement::Default(); } @@ -733,7 +676,8 @@ PreParser::Statement PreParser::ParseThrowStatement(bool* ok) { Expect(Token::THROW, CHECK_OK); if (scanner()->HasAnyLineTerminatorBeforeNext()) { - ReportMessageAt(scanner()->location(), "newline_after_throw"); + Scanner::Location pos = scanner()->location(); + ReportMessageAt(pos, "newline_after_throw", NULL); *ok = false; return Statement::Default(); } @@ -761,7 +705,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"); + ReportMessageAt(scanner()->location(), "no_catch_or_finally", NULL); *ok = false; return Statement::Default(); } @@ -844,8 +788,8 @@ PreParser::Expression PreParser::ParseAssignmentExpression(bool accept_IN, expression.IsIdentifier() && expression.AsIdentifier().IsEvalOrArguments()) { Scanner::Location after = scanner()->location(); - PreParserTraits::ReportMessageAt(before.beg_pos, after.end_pos, - "strict_eval_arguments", NULL); + ReportMessageAt(before.beg_pos, after.end_pos, + "strict_eval_arguments", NULL); *ok = false; return Expression::Default(); } @@ -938,8 +882,8 @@ PreParser::Expression PreParser::ParseUnaryExpression(bool* ok) { expression.IsIdentifier() && expression.AsIdentifier().IsEvalOrArguments()) { Scanner::Location after = scanner()->location(); - PreParserTraits::ReportMessageAt(before.beg_pos, after.end_pos, - "strict_eval_arguments", NULL); + ReportMessageAt(before.beg_pos, after.end_pos, + "strict_eval_arguments", NULL); *ok = false; } return Expression::Default(); @@ -961,8 +905,8 @@ PreParser::Expression PreParser::ParsePostfixExpression(bool* ok) { expression.IsIdentifier() && expression.AsIdentifier().IsEvalOrArguments()) { Scanner::Location after = scanner()->location(); - PreParserTraits::ReportMessageAt(before.beg_pos, after.end_pos, - "strict_eval_arguments", NULL); + ReportMessageAt(before.beg_pos, after.end_pos, + "strict_eval_arguments", NULL); *ok = false; return Expression::Default(); } @@ -1305,7 +1249,7 @@ PreParser::Expression PreParser::ParseRegExpLiteral(bool seen_equal, bool* ok) { if (!scanner()->ScanRegExpPattern(seen_equal)) { Next(); - ReportMessageAt(scanner()->location(), "unterminated_regexp"); + ReportMessageAt(scanner()->location(), "unterminated_regexp", NULL); *ok = false; return Expression::Default(); } @@ -1314,7 +1258,7 @@ PreParser::Expression PreParser::ParseRegExpLiteral(bool seen_equal, if (!scanner()->ScanRegExpFlags()) { Next(); - ReportMessageAt(scanner()->location(), "invalid_regexp_flags"); + ReportMessageAt(scanner()->location(), "invalid_regexp_flags", NULL); *ok = false; return Expression::Default(); } @@ -1422,27 +1366,31 @@ 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"); + ReportMessageAt(function_name_location, "strict_eval_arguments", NULL); *ok = false; return Expression::Default(); } if (name_is_strict_reserved) { - ReportMessageAt(function_name_location, "unexpected_strict_reserved"); + ReportMessageAt( + function_name_location, "unexpected_strict_reserved", NULL); *ok = false; return Expression::Default(); } if (eval_args_error_loc.IsValid()) { - ReportMessageAt(eval_args_error_loc, "strict_eval_arguments"); + ReportMessageAt(eval_args_error_loc, "strict_eval_arguments", + Vector::empty()); *ok = false; return Expression::Default(); } if (dupe_error_loc.IsValid()) { - ReportMessageAt(dupe_error_loc, "strict_param_dupe"); + ReportMessageAt(dupe_error_loc, "strict_param_dupe", + Vector::empty()); *ok = false; return Expression::Default(); } if (reserved_error_loc.IsValid()) { - ReportMessageAt(reserved_error_loc, "unexpected_strict_reserved"); + ReportMessageAt(reserved_error_loc, "unexpected_strict_reserved", + Vector::empty()); *ok = false; return Expression::Default(); } @@ -1516,4 +1464,142 @@ 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 62ac5b85d5..bcaab743e5 100644 --- a/src/preparser.h +++ b/src/preparser.h @@ -36,19 +36,18 @@ namespace v8 { namespace internal { // Common base class shared between parser and pre-parser. -template -class ParserBase : public Traits { +class ParserBase { public: - ParserBase(Scanner* scanner, uintptr_t stack_limit, - typename Traits::ParserType this_object) - : Traits(this_object), - scanner_(scanner), + ParserBase(Scanner* scanner, uintptr_t stack_limit) + : 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. @@ -88,6 +87,8 @@ class ParserBase : public Traits { 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(); @@ -131,99 +132,25 @@ class ParserBase : public Traits { } } - 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(); + void ExpectSemicolon(bool* ok); + bool CheckContextualKeyword(Vector keyword); + void ExpectContextualKeyword(Vector keyword, bool* 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; - } - - 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; - } - } + // 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) { - if (token == Token::IN && !accept_IN) - return 0; // 0 precedence will terminate binary expression parsing - return Token::Precedence(token); - } + static int Precedence(Token::Value token, bool accept_IN); // Report syntax errors. - void ReportMessage(const char* message, Vector args) { - Scanner::Location source_location = scanner()->location(); - Traits::ReportMessageAt(source_location, message, args); - } - - 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); + void ReportMessageAt(Scanner::Location location, const char* type) { + ReportMessageAt(location, type, Vector::empty()); + } + virtual void ReportMessageAt(Scanner::Location source_location, + const char* message, + Vector args) = 0; // Used to detect duplicates in object literals. Each of the values // kGetterProperty, kSetterProperty and kValueProperty represents @@ -291,176 +218,6 @@ class ParserBase : public Traits { }; -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. @@ -473,11 +230,8 @@ class PreParserTraits { // 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 @@ -486,7 +240,7 @@ class PreParser : public ParserBase { PreParser(Scanner* scanner, ParserRecorder* log, uintptr_t stack_limit) - : ParserBase(scanner, stack_limit, this), + : ParserBase(scanner, stack_limit), log_(log), scope_(NULL), parenthesized_function_(false) { } @@ -524,8 +278,6 @@ 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 @@ -548,6 +300,142 @@ 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() { @@ -658,6 +546,27 @@ 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 @@ -713,8 +622,18 @@ 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(); @@ -722,6 +641,10 @@ 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; } @@ -735,154 +658,6 @@ 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 f3f238caa9..22d5056f80 100644 --- a/test/cctest/test-parsing.cc +++ b/test/cctest/test-parsing.cc @@ -1108,9 +1108,8 @@ enum ParserSyncTestResult { kError }; -template -void SetParserFlags(i::ParserBase* parser, - i::EnumSet flags) { + +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));