| Index: src/parser.cc
|
| diff --git a/src/parser.cc b/src/parser.cc
|
| index 68823e6c1f708a84cbba432187eac0972c397b43..5e7680e6c19df12853d7ee850fc9bf65010f41fc 100644
|
| --- a/src/parser.cc
|
| +++ b/src/parser.cc
|
| @@ -46,6 +46,49 @@
|
| namespace v8 {
|
| namespace internal {
|
|
|
| +// PositionStack is used for on-stack allocation of token positions for
|
| +// new expressions. Please look at ParseNewExpression.
|
| +
|
| +class PositionStack {
|
| + public:
|
| + explicit PositionStack(bool* ok) : top_(NULL), ok_(ok) {}
|
| + ~PositionStack() {
|
| + ASSERT(!*ok_ || is_empty());
|
| + USE(ok_);
|
| + }
|
| +
|
| + class Element {
|
| + public:
|
| + Element(PositionStack* stack, int value) {
|
| + previous_ = stack->top();
|
| + value_ = value;
|
| + stack->set_top(this);
|
| + }
|
| +
|
| + private:
|
| + Element* previous() { return previous_; }
|
| + int value() { return value_; }
|
| + friend class PositionStack;
|
| + Element* previous_;
|
| + int value_;
|
| + };
|
| +
|
| + bool is_empty() { return top_ == NULL; }
|
| + int pop() {
|
| + ASSERT(!is_empty());
|
| + int result = top_->value();
|
| + top_ = top_->previous();
|
| + return result;
|
| + }
|
| +
|
| + private:
|
| + Element* top() { return top_; }
|
| + void set_top(Element* value) { top_ = value; }
|
| + Element* top_;
|
| + bool* ok_;
|
| +};
|
| +
|
| +
|
| RegExpBuilder::RegExpBuilder(Zone* zone)
|
| : zone_(zone),
|
| pending_empty_(false),
|
| @@ -207,18 +250,18 @@ void RegExpBuilder::AddQuantifierToAtom(
|
|
|
|
|
| Handle<String> Parser::LookupSymbol(int symbol_id) {
|
| - // If there is no preparser symbol data, a negative number will be passed. In
|
| - // that case, we'll just read the literal from Scanner. This also guards
|
| - // against corrupt preparse data where the symbol id is larger than the symbol
|
| - // count.
|
| - if (symbol_id < 0 ||
|
| - (pre_parse_data_ && symbol_id >= pre_parse_data_->symbol_count())) {
|
| - if (scanner()->is_literal_ascii()) {
|
| + // Length of symbol cache is the number of identified symbols.
|
| + // If we are larger than that, or negative, it's not a cached symbol.
|
| + // This might also happen if there is no preparser symbol data, even
|
| + // if there is some preparser data.
|
| + if (static_cast<unsigned>(symbol_id)
|
| + >= static_cast<unsigned>(symbol_cache_.length())) {
|
| + if (scanner().is_literal_ascii()) {
|
| return isolate()->factory()->InternalizeOneByteString(
|
| - Vector<const uint8_t>::cast(scanner()->literal_ascii_string()));
|
| + Vector<const uint8_t>::cast(scanner().literal_ascii_string()));
|
| } else {
|
| return isolate()->factory()->InternalizeTwoByteString(
|
| - scanner()->literal_utf16_string());
|
| + scanner().literal_utf16_string());
|
| }
|
| }
|
| return LookupCachedSymbol(symbol_id);
|
| @@ -234,12 +277,12 @@ Handle<String> Parser::LookupCachedSymbol(int symbol_id) {
|
| }
|
| Handle<String> result = symbol_cache_.at(symbol_id);
|
| if (result.is_null()) {
|
| - if (scanner()->is_literal_ascii()) {
|
| + if (scanner().is_literal_ascii()) {
|
| result = isolate()->factory()->InternalizeOneByteString(
|
| - Vector<const uint8_t>::cast(scanner()->literal_ascii_string()));
|
| + Vector<const uint8_t>::cast(scanner().literal_ascii_string()));
|
| } else {
|
| result = isolate()->factory()->InternalizeTwoByteString(
|
| - scanner()->literal_utf16_string());
|
| + scanner().literal_utf16_string());
|
| }
|
| symbol_cache_.at(symbol_id) = result;
|
| return result;
|
| @@ -420,6 +463,54 @@ class TargetScope BASE_EMBEDDED {
|
|
|
|
|
| // ----------------------------------------------------------------------------
|
| +// FunctionState and BlockState together implement the parser's scope stack.
|
| +// The parser's current scope is in top_scope_. The BlockState and
|
| +// FunctionState constructors push on the scope stack and the destructors
|
| +// pop. They are also used to hold the parser's per-function and per-block
|
| +// state.
|
| +
|
| +class Parser::BlockState BASE_EMBEDDED {
|
| + public:
|
| + BlockState(Parser* parser, Scope* scope)
|
| + : parser_(parser),
|
| + outer_scope_(parser->top_scope_) {
|
| + parser->top_scope_ = scope;
|
| + }
|
| +
|
| + ~BlockState() { parser_->top_scope_ = outer_scope_; }
|
| +
|
| + private:
|
| + Parser* parser_;
|
| + Scope* outer_scope_;
|
| +};
|
| +
|
| +
|
| +Parser::FunctionState::FunctionState(Parser* parser, Scope* scope)
|
| + : next_materialized_literal_index_(JSFunction::kLiteralsPrefixSize),
|
| + next_handler_index_(0),
|
| + expected_property_count_(0),
|
| + generator_object_variable_(NULL),
|
| + parser_(parser),
|
| + outer_function_state_(parser->current_function_state_),
|
| + outer_scope_(parser->top_scope_),
|
| + saved_ast_node_id_(parser->zone()->isolate()->ast_node_id()),
|
| + factory_(parser->zone()) {
|
| + parser->top_scope_ = scope;
|
| + parser->current_function_state_ = this;
|
| + parser->zone()->isolate()->set_ast_node_id(BailoutId::FirstUsable().ToInt());
|
| +}
|
| +
|
| +
|
| +Parser::FunctionState::~FunctionState() {
|
| + parser_->top_scope_ = outer_scope_;
|
| + parser_->current_function_state_ = outer_function_state_;
|
| + if (outer_function_state_ != NULL) {
|
| + parser_->isolate()->set_ast_node_id(saved_ast_node_id_);
|
| + }
|
| +}
|
| +
|
| +
|
| +// ----------------------------------------------------------------------------
|
| // The CHECK_OK macro is a convenient macro to enforce error
|
| // handling for functions that may fail (by returning !*ok).
|
| //
|
| @@ -442,171 +533,22 @@ class TargetScope BASE_EMBEDDED {
|
| // ----------------------------------------------------------------------------
|
| // Implementation of Parser
|
|
|
| -bool ParserTraits::IsEvalOrArguments(Handle<String> 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<const char*> args) {
|
| - MessageLocation location(parser_->script_,
|
| - source_location.beg_pos,
|
| - source_location.end_pos);
|
| - Factory* factory = parser_->isolate()->factory();
|
| - Handle<FixedArray> elements = factory->NewFixedArray(args.length());
|
| - for (int i = 0; i < args.length(); i++) {
|
| - Handle<String> arg_string = factory->NewStringFromUtf8(CStrVector(args[i]));
|
| - elements->set(i, *arg_string);
|
| - }
|
| - Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
|
| - Handle<Object> result = factory->NewSyntaxError(message, array);
|
| - parser_->isolate()->Throw(*result, &location);
|
| -}
|
| -
|
| -
|
| -void ParserTraits::ReportMessage(const char* message,
|
| - Vector<Handle<String> > args) {
|
| - Scanner::Location source_location = parser_->scanner()->location();
|
| - ReportMessageAt(source_location, message, args);
|
| -}
|
| -
|
| -
|
| -void ParserTraits::ReportMessageAt(Scanner::Location source_location,
|
| - const char* message,
|
| - Vector<Handle<String> > args) {
|
| - MessageLocation location(parser_->script_,
|
| - source_location.beg_pos,
|
| - source_location.end_pos);
|
| - Factory* factory = parser_->isolate()->factory();
|
| - Handle<FixedArray> elements = factory->NewFixedArray(args.length());
|
| - for (int i = 0; i < args.length(); i++) {
|
| - elements->set(i, *args[i]);
|
| - }
|
| - Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
|
| - Handle<Object> result = factory->NewSyntaxError(message, array);
|
| - parser_->isolate()->Throw(*result, &location);
|
| -}
|
| -
|
| -
|
| -Handle<String> ParserTraits::GetSymbol(Scanner* scanner) {
|
| - int symbol_id = -1;
|
| - if (parser_->pre_parse_data() != NULL) {
|
| - symbol_id = parser_->pre_parse_data()->GetSymbolIdentifier();
|
| - }
|
| - return parser_->LookupSymbol(symbol_id);
|
| -}
|
| -
|
| -
|
| -Handle<String> ParserTraits::NextLiteralString(Scanner* scanner,
|
| - PretenureFlag tenured) {
|
| - if (scanner->is_next_literal_ascii()) {
|
| - return parser_->isolate_->factory()->NewStringFromAscii(
|
| - scanner->next_literal_ascii_string(), tenured);
|
| - } else {
|
| - return parser_->isolate_->factory()->NewStringFromTwoByte(
|
| - scanner->next_literal_utf16_string(), tenured);
|
| - }
|
| -}
|
| -
|
| -
|
| -Expression* ParserTraits::ThisExpression(
|
| - Scope* scope,
|
| - AstNodeFactory<AstConstructionVisitor>* factory) {
|
| - return factory->NewVariableProxy(scope->receiver());
|
| -}
|
| -
|
| -
|
| -Expression* ParserTraits::ExpressionFromLiteral(
|
| - Token::Value token, int pos,
|
| - Scanner* scanner,
|
| - AstNodeFactory<AstConstructionVisitor>* factory) {
|
| - Factory* isolate_factory = parser_->isolate()->factory();
|
| - switch (token) {
|
| - case Token::NULL_LITERAL:
|
| - return factory->NewLiteral(isolate_factory->null_value(), pos);
|
| - case Token::TRUE_LITERAL:
|
| - return factory->NewLiteral(isolate_factory->true_value(), pos);
|
| - case Token::FALSE_LITERAL:
|
| - return factory->NewLiteral(isolate_factory->false_value(), pos);
|
| - case Token::NUMBER: {
|
| - ASSERT(scanner->is_literal_ascii());
|
| - double value = StringToDouble(parser_->isolate()->unicode_cache(),
|
| - scanner->literal_ascii_string(),
|
| - ALLOW_HEX | ALLOW_OCTAL |
|
| - ALLOW_IMPLICIT_OCTAL | ALLOW_BINARY);
|
| - return factory->NewNumberLiteral(value, pos);
|
| - }
|
| - default:
|
| - ASSERT(false);
|
| - }
|
| - return NULL;
|
| -}
|
| -
|
| -
|
| -Expression* ParserTraits::ExpressionFromIdentifier(
|
| - Handle<String> name, int pos, Scope* scope,
|
| - AstNodeFactory<AstConstructionVisitor>* factory) {
|
| - if (parser_->fni_ != NULL) parser_->fni_->PushVariableName(name);
|
| - // The name may refer to a module instance object, so its type is unknown.
|
| -#ifdef DEBUG
|
| - if (FLAG_print_interface_details)
|
| - PrintF("# Variable %s ", name->ToAsciiArray());
|
| -#endif
|
| - Interface* interface = Interface::NewUnknown(parser_->zone());
|
| - return scope->NewUnresolved(factory, name, interface, pos);
|
| -}
|
| -
|
| -
|
| -Expression* ParserTraits::ExpressionFromString(
|
| - int pos, Scanner* scanner,
|
| - AstNodeFactory<AstConstructionVisitor>* factory) {
|
| - Handle<String> symbol = GetSymbol(scanner);
|
| - if (parser_->fni_ != NULL) parser_->fni_->PushLiteralName(symbol);
|
| - return factory->NewLiteral(symbol, pos);
|
| -}
|
| -
|
| -
|
| -Literal* ParserTraits::GetLiteralTheHole(
|
| - int position, AstNodeFactory<AstConstructionVisitor>* factory) {
|
| - return factory->NewLiteral(parser_->isolate()->factory()->the_hole_value(),
|
| - RelocInfo::kNoPosition);
|
| -}
|
| -
|
| -
|
| -Expression* ParserTraits::ParseObjectLiteral(bool* ok) {
|
| - return parser_->ParseObjectLiteral(ok);
|
| -}
|
| -
|
| -
|
| -Expression* ParserTraits::ParseAssignmentExpression(bool accept_IN, bool* ok) {
|
| - return parser_->ParseAssignmentExpression(accept_IN, ok);
|
| -}
|
| -
|
| -
|
| -Expression* ParserTraits::ParseV8Intrinsic(bool* ok) {
|
| - return parser_->ParseV8Intrinsic(ok);
|
| -}
|
| -
|
| -
|
| Parser::Parser(CompilationInfo* info)
|
| - : ParserBase<ParserTraits>(&scanner_,
|
| - info->isolate()->stack_guard()->real_climit(),
|
| - info->extension(),
|
| - info->zone(),
|
| - this),
|
| + : ParserBase(&scanner_, info->isolate()->stack_guard()->real_climit()),
|
| isolate_(info->isolate()),
|
| symbol_cache_(0, info->zone()),
|
| script_(info->script()),
|
| scanner_(isolate_->unicode_cache()),
|
| reusable_preparser_(NULL),
|
| + top_scope_(NULL),
|
| original_scope_(NULL),
|
| + current_function_state_(NULL),
|
| target_stack_(NULL),
|
| + extension_(info->extension()),
|
| pre_parse_data_(NULL),
|
| fni_(NULL),
|
| + parenthesized_function_(false),
|
| + zone_(info->zone()),
|
| info_(info) {
|
| ASSERT(!script_.is_null());
|
| isolate_->set_ast_node_id(0);
|
| @@ -668,14 +610,14 @@ FunctionLiteral* Parser::ParseProgram() {
|
|
|
| FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info,
|
| Handle<String> source) {
|
| - ASSERT(scope_ == NULL);
|
| + ASSERT(top_scope_ == NULL);
|
| ASSERT(target_stack_ == NULL);
|
| if (pre_parse_data_ != NULL) pre_parse_data_->Initialize();
|
|
|
| Handle<String> no_name = isolate()->factory()->empty_string();
|
|
|
| FunctionLiteral* result = NULL;
|
| - { Scope* scope = NewScope(scope_, GLOBAL_SCOPE);
|
| + { Scope* scope = NewScope(top_scope_, GLOBAL_SCOPE);
|
| info->SetGlobalScope(scope);
|
| if (!info->context().is_null()) {
|
| scope = Scope::DeserializeScopeChain(*info->context(), scope, zone());
|
| @@ -701,19 +643,19 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info,
|
| ParsingModeScope parsing_mode(this, mode);
|
|
|
| // Enters 'scope'.
|
| - FunctionState function_state(&function_state_, &scope_, scope, zone());
|
| + FunctionState function_state(this, scope);
|
|
|
| - scope_->SetLanguageMode(info->language_mode());
|
| + top_scope_->SetLanguageMode(info->language_mode());
|
| ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone());
|
| bool ok = true;
|
| - int beg_pos = scanner()->location().beg_pos;
|
| + int beg_pos = scanner().location().beg_pos;
|
| ParseSourceElements(body, Token::EOS, info->is_eval(), true, &ok);
|
| - if (ok && !scope_->is_classic_mode()) {
|
| - CheckOctalLiteral(beg_pos, scanner()->location().end_pos, &ok);
|
| + if (ok && !top_scope_->is_classic_mode()) {
|
| + CheckOctalLiteral(beg_pos, scanner().location().end_pos, &ok);
|
| }
|
|
|
| if (ok && is_extended_mode()) {
|
| - CheckConflictingVarDeclarations(scope_, &ok);
|
| + CheckConflictingVarDeclarations(top_scope_, &ok);
|
| }
|
|
|
| if (ok && info->parse_restriction() == ONLY_SINGLE_FUNCTION_LITERAL) {
|
| @@ -729,7 +671,7 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info,
|
| if (ok) {
|
| result = factory()->NewFunctionLiteral(
|
| no_name,
|
| - scope_,
|
| + top_scope_,
|
| body,
|
| function_state.materialized_literal_count(),
|
| function_state.expected_property_count(),
|
| @@ -742,7 +684,6 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info,
|
| FunctionLiteral::kNotGenerator,
|
| 0);
|
| result->set_ast_properties(factory()->visitor()->ast_properties());
|
| - result->set_slot_processor(factory()->visitor()->slot_processor());
|
| result->set_dont_optimize_reason(
|
| factory()->visitor()->dont_optimize_reason());
|
| } else if (stack_overflow()) {
|
| @@ -795,7 +736,7 @@ FunctionLiteral* Parser::ParseLazy() {
|
| FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source) {
|
| Handle<SharedFunctionInfo> shared_info = info()->shared_info();
|
| scanner_.Initialize(source);
|
| - ASSERT(scope_ == NULL);
|
| + ASSERT(top_scope_ == NULL);
|
| ASSERT(target_stack_ == NULL);
|
|
|
| Handle<String> name(String::cast(shared_info->name()));
|
| @@ -809,14 +750,14 @@ FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source) {
|
|
|
| {
|
| // Parse the function literal.
|
| - Scope* scope = NewScope(scope_, GLOBAL_SCOPE);
|
| + Scope* scope = NewScope(top_scope_, GLOBAL_SCOPE);
|
| info()->SetGlobalScope(scope);
|
| if (!info()->closure().is_null()) {
|
| scope = Scope::DeserializeScopeChain(info()->closure()->context(), scope,
|
| zone());
|
| }
|
| original_scope_ = scope;
|
| - FunctionState function_state(&function_state_, &scope_, scope, zone());
|
| + FunctionState function_state(this, scope);
|
| ASSERT(scope->language_mode() != STRICT_MODE || !info()->is_classic_mode());
|
| ASSERT(scope->language_mode() != EXTENDED_MODE ||
|
| info()->is_extended_mode());
|
| @@ -852,6 +793,62 @@ FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source) {
|
| }
|
|
|
|
|
| +Handle<String> 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<const char*> args) {
|
| + Scanner::Location source_location = scanner().location();
|
| + ReportMessageAt(source_location, message, args);
|
| +}
|
| +
|
| +
|
| +void Parser::ReportMessage(const char* message, Vector<Handle<String> > args) {
|
| + Scanner::Location source_location = scanner().location();
|
| + ReportMessageAt(source_location, message, args);
|
| +}
|
| +
|
| +
|
| +void Parser::ReportMessageAt(Scanner::Location source_location,
|
| + const char* message,
|
| + Vector<const char*> args) {
|
| + MessageLocation location(script_,
|
| + source_location.beg_pos,
|
| + source_location.end_pos);
|
| + Factory* factory = isolate()->factory();
|
| + Handle<FixedArray> elements = factory->NewFixedArray(args.length());
|
| + for (int i = 0; i < args.length(); i++) {
|
| + Handle<String> arg_string = factory->NewStringFromUtf8(CStrVector(args[i]));
|
| + elements->set(i, *arg_string);
|
| + }
|
| + Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
|
| + Handle<Object> result = factory->NewSyntaxError(message, array);
|
| + isolate()->Throw(*result, &location);
|
| +}
|
| +
|
| +
|
| +void Parser::ReportMessageAt(Scanner::Location source_location,
|
| + const char* message,
|
| + Vector<Handle<String> > args) {
|
| + MessageLocation location(script_,
|
| + source_location.beg_pos,
|
| + source_location.end_pos);
|
| + Factory* factory = isolate()->factory();
|
| + Handle<FixedArray> elements = factory->NewFixedArray(args.length());
|
| + for (int i = 0; i < args.length(); i++) {
|
| + elements->set(i, *args[i]);
|
| + }
|
| + Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
|
| + Handle<Object> result = factory->NewSyntaxError(message, array);
|
| + isolate()->Throw(*result, &location);
|
| +}
|
| +
|
| +
|
| void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
|
| int end_token,
|
| bool is_eval,
|
| @@ -874,7 +871,7 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
|
| directive_prologue = false;
|
| }
|
|
|
| - Scanner::Location token_loc = scanner()->peek_location();
|
| + Scanner::Location token_loc = scanner().peek_location();
|
| Statement* stat;
|
| if (is_global && !is_eval) {
|
| stat = ParseModuleElement(NULL, CHECK_OK);
|
| @@ -897,7 +894,7 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
|
| Handle<String> directive = Handle<String>::cast(literal->value());
|
|
|
| // Check "use strict" directive (ES5 14.1).
|
| - if (scope_->is_classic_mode() &&
|
| + if (top_scope_->is_classic_mode() &&
|
| directive->Equals(isolate()->heap()->use_strict_string()) &&
|
| token_loc.end_pos - token_loc.beg_pos ==
|
| isolate()->heap()->use_strict_string()->length() + 2) {
|
| @@ -906,16 +903,16 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
|
| // add this scope in DoParseProgram(), but that requires adaptations
|
| // all over the code base, so we go with a quick-fix for now.
|
| // In the same manner, we have to patch the parsing mode.
|
| - if (is_eval && !scope_->is_eval_scope()) {
|
| - ASSERT(scope_->is_global_scope());
|
| - Scope* scope = NewScope(scope_, EVAL_SCOPE);
|
| - scope->set_start_position(scope_->start_position());
|
| - scope->set_end_position(scope_->end_position());
|
| - scope_ = scope;
|
| + if (is_eval && !top_scope_->is_eval_scope()) {
|
| + ASSERT(top_scope_->is_global_scope());
|
| + Scope* scope = NewScope(top_scope_, EVAL_SCOPE);
|
| + scope->set_start_position(top_scope_->start_position());
|
| + scope->set_end_position(top_scope_->end_position());
|
| + top_scope_ = scope;
|
| mode_ = PARSE_EAGERLY;
|
| }
|
| // TODO(ES6): Fix entering extended mode, once it is specified.
|
| - scope_->SetLanguageMode(allow_harmony_scoping()
|
| + top_scope_->SetLanguageMode(allow_harmony_scoping()
|
| ? EXTENDED_MODE : STRICT_MODE);
|
| // "use strict" is the only directive for now.
|
| directive_prologue = false;
|
| @@ -964,14 +961,14 @@ Statement* Parser::ParseModuleElement(ZoneStringList* labels,
|
| // Handle 'module' as a context-sensitive keyword.
|
| if (FLAG_harmony_modules &&
|
| peek() == Token::IDENTIFIER &&
|
| - !scanner()->HasAnyLineTerminatorBeforeNext() &&
|
| + !scanner().HasAnyLineTerminatorBeforeNext() &&
|
| stmt != NULL) {
|
| ExpressionStatement* estmt = stmt->AsExpressionStatement();
|
| if (estmt != NULL &&
|
| estmt->expression()->AsVariableProxy() != NULL &&
|
| estmt->expression()->AsVariableProxy()->name()->Equals(
|
| isolate()->heap()->module_string()) &&
|
| - !scanner()->literal_contains_escapes()) {
|
| + !scanner().literal_contains_escapes()) {
|
| return ParseModuleDeclaration(NULL, ok);
|
| }
|
| }
|
| @@ -996,7 +993,7 @@ Statement* Parser::ParseModuleDeclaration(ZoneStringList* names, bool* ok) {
|
| Module* module = ParseModule(CHECK_OK);
|
| VariableProxy* proxy = NewUnresolved(name, MODULE, module->interface());
|
| Declaration* declaration =
|
| - factory()->NewModuleDeclaration(proxy, module, scope_, pos);
|
| + factory()->NewModuleDeclaration(proxy, module, top_scope_, pos);
|
| Declare(declaration, true, CHECK_OK);
|
|
|
| #ifdef DEBUG
|
| @@ -1054,14 +1051,14 @@ Module* Parser::ParseModuleLiteral(bool* ok) {
|
| #ifdef DEBUG
|
| if (FLAG_print_interface_details) PrintF("# Literal ");
|
| #endif
|
| - Scope* scope = NewScope(scope_, MODULE_SCOPE);
|
| + Scope* scope = NewScope(top_scope_, MODULE_SCOPE);
|
|
|
| Expect(Token::LBRACE, CHECK_OK);
|
| - scope->set_start_position(scanner()->location().beg_pos);
|
| + scope->set_start_position(scanner().location().beg_pos);
|
| scope->SetLanguageMode(EXTENDED_MODE);
|
|
|
| {
|
| - BlockState block_state(&scope_, scope);
|
| + BlockState block_state(this, scope);
|
| TargetCollector collector(zone());
|
| Target target(&this->target_stack_, &collector);
|
| Target target_body(&this->target_stack_, body);
|
| @@ -1075,7 +1072,7 @@ Module* Parser::ParseModuleLiteral(bool* ok) {
|
| }
|
|
|
| Expect(Token::RBRACE, CHECK_OK);
|
| - scope->set_end_position(scanner()->location().end_pos);
|
| + scope->set_end_position(scanner().location().end_pos);
|
| body->set_scope(scope);
|
|
|
| // Check that all exports are bound.
|
| @@ -1084,8 +1081,8 @@ Module* Parser::ParseModuleLiteral(bool* ok) {
|
| !it.done(); it.Advance()) {
|
| if (scope->LocalLookup(it.name()) == NULL) {
|
| Handle<String> name(it.name());
|
| - ParserTraits::ReportMessage("module_export_undefined",
|
| - Vector<Handle<String> >(&name, 1));
|
| + ReportMessage("module_export_undefined",
|
| + Vector<Handle<String> >(&name, 1));
|
| *ok = false;
|
| return NULL;
|
| }
|
| @@ -1124,8 +1121,7 @@ Module* Parser::ParseModulePath(bool* ok) {
|
| member->interface()->Print();
|
| }
|
| #endif
|
| - ParserTraits::ReportMessage("invalid_module_path",
|
| - Vector<Handle<String> >(&name, 1));
|
| + ReportMessage("invalid_module_path", Vector<Handle<String> >(&name, 1));
|
| return NULL;
|
| }
|
| result = member;
|
| @@ -1145,9 +1141,9 @@ Module* Parser::ParseModuleVariable(bool* ok) {
|
| if (FLAG_print_interface_details)
|
| PrintF("# Module variable %s ", name->ToAsciiArray());
|
| #endif
|
| - VariableProxy* proxy = scope_->NewUnresolved(
|
| + VariableProxy* proxy = top_scope_->NewUnresolved(
|
| factory(), name, Interface::NewModule(zone()),
|
| - scanner()->location().beg_pos);
|
| + scanner().location().beg_pos);
|
|
|
| return factory()->NewModuleVariable(proxy, pos);
|
| }
|
| @@ -1169,7 +1165,7 @@ Module* Parser::ParseModuleUrl(bool* ok) {
|
|
|
| // Create an empty literal as long as the feature isn't finished.
|
| USE(symbol);
|
| - Scope* scope = NewScope(scope_, MODULE_SCOPE);
|
| + Scope* scope = NewScope(top_scope_, MODULE_SCOPE);
|
| Block* body = factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition);
|
| body->set_scope(scope);
|
| Interface* interface = scope->interface();
|
| @@ -1235,13 +1231,12 @@ Block* Parser::ParseImportDeclaration(bool* ok) {
|
| module->interface()->Print();
|
| }
|
| #endif
|
| - ParserTraits::ReportMessage("invalid_module_path",
|
| - Vector<Handle<String> >(&name, 1));
|
| + ReportMessage("invalid_module_path", Vector<Handle<String> >(&name, 1));
|
| return NULL;
|
| }
|
| VariableProxy* proxy = NewUnresolved(names[i], LET, interface);
|
| Declaration* declaration =
|
| - factory()->NewImportDeclaration(proxy, module, scope_, pos);
|
| + factory()->NewImportDeclaration(proxy, module, top_scope_, pos);
|
| Declare(declaration, true, CHECK_OK);
|
| }
|
|
|
| @@ -1296,12 +1291,12 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
|
|
|
| default:
|
| *ok = false;
|
| - ReportUnexpectedToken(scanner()->current_token());
|
| + ReportUnexpectedToken(scanner().current_token());
|
| return NULL;
|
| }
|
|
|
| // Extract declared names into export declarations and interface.
|
| - Interface* interface = scope_->interface();
|
| + Interface* interface = top_scope_->interface();
|
| for (int i = 0; i < names.length(); ++i) {
|
| #ifdef DEBUG
|
| if (FLAG_print_interface_details)
|
| @@ -1316,8 +1311,8 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
|
| // TODO(rossberg): Rethink whether we actually need to store export
|
| // declarations (for compilation?).
|
| // ExportDeclaration* declaration =
|
| - // factory()->NewExportDeclaration(proxy, scope_, position);
|
| - // scope_->AddDeclaration(declaration);
|
| + // factory()->NewExportDeclaration(proxy, top_scope_, position);
|
| + // top_scope_->AddDeclaration(declaration);
|
| }
|
|
|
| ASSERT(result != NULL);
|
| @@ -1443,8 +1438,9 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
|
| // In Harmony mode, this case also handles the extension:
|
| // Statement:
|
| // GeneratorDeclaration
|
| - if (!scope_->is_classic_mode()) {
|
| - ReportMessageAt(scanner()->peek_location(), "strict_function");
|
| + if (!top_scope_->is_classic_mode()) {
|
| + ReportMessageAt(scanner().peek_location(), "strict_function",
|
| + Vector<const char*>::empty());
|
| *ok = false;
|
| return NULL;
|
| }
|
| @@ -1623,8 +1619,7 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
|
| var->interface()->Print();
|
| }
|
| #endif
|
| - ParserTraits::ReportMessage("module_type_error",
|
| - Vector<Handle<String> >(&name, 1));
|
| + ReportMessage("module_type_error", Vector<Handle<String> >(&name, 1));
|
| }
|
| }
|
| }
|
| @@ -1663,7 +1658,7 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) {
|
| // other functions are set up when entering the surrounding scope.
|
| VariableProxy* proxy = NewUnresolved(name, VAR, Interface::NewValue());
|
| Declaration* declaration =
|
| - factory()->NewVariableDeclaration(proxy, VAR, scope_, pos);
|
| + factory()->NewVariableDeclaration(proxy, VAR, top_scope_, pos);
|
| Declare(declaration, true, CHECK_OK);
|
| NativeFunctionLiteral* lit = factory()->NewNativeFunctionLiteral(
|
| name, extension_, RelocInfo::kNoPosition);
|
| @@ -1687,7 +1682,7 @@ Statement* Parser::ParseFunctionDeclaration(ZoneStringList* names, bool* ok) {
|
| Handle<String> name = ParseIdentifierOrStrictReservedWord(
|
| &is_strict_reserved, CHECK_OK);
|
| FunctionLiteral* fun = ParseFunctionLiteral(name,
|
| - scanner()->location(),
|
| + scanner().location(),
|
| is_strict_reserved,
|
| is_generator,
|
| pos,
|
| @@ -1699,10 +1694,10 @@ Statement* Parser::ParseFunctionDeclaration(ZoneStringList* names, bool* ok) {
|
| // In extended mode, a function behaves as a lexical binding, except in the
|
| // global scope.
|
| VariableMode mode =
|
| - is_extended_mode() && !scope_->is_global_scope() ? LET : VAR;
|
| + is_extended_mode() && !top_scope_->is_global_scope() ? LET : VAR;
|
| VariableProxy* proxy = NewUnresolved(name, mode, Interface::NewValue());
|
| Declaration* declaration =
|
| - factory()->NewFunctionDeclaration(proxy, mode, fun, scope_, pos);
|
| + factory()->NewFunctionDeclaration(proxy, mode, fun, top_scope_, pos);
|
| Declare(declaration, true, CHECK_OK);
|
| if (names) names->Add(name, zone());
|
| return factory()->NewEmptyStatement(RelocInfo::kNoPosition);
|
| @@ -1710,7 +1705,7 @@ Statement* Parser::ParseFunctionDeclaration(ZoneStringList* names, bool* ok) {
|
|
|
|
|
| Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) {
|
| - if (scope_->is_extended_mode()) return ParseScopedBlock(labels, ok);
|
| + if (top_scope_->is_extended_mode()) return ParseScopedBlock(labels, ok);
|
|
|
| // Block ::
|
| // '{' Statement* '}'
|
| @@ -1743,12 +1738,12 @@ Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) {
|
| // Construct block expecting 16 statements.
|
| Block* body =
|
| factory()->NewBlock(labels, 16, false, RelocInfo::kNoPosition);
|
| - Scope* block_scope = NewScope(scope_, BLOCK_SCOPE);
|
| + Scope* block_scope = NewScope(top_scope_, BLOCK_SCOPE);
|
|
|
| // Parse the statements and collect escaping labels.
|
| Expect(Token::LBRACE, CHECK_OK);
|
| - block_scope->set_start_position(scanner()->location().beg_pos);
|
| - { BlockState block_state(&scope_, block_scope);
|
| + block_scope->set_start_position(scanner().location().beg_pos);
|
| + { BlockState block_state(this, block_scope);
|
| TargetCollector collector(zone());
|
| Target target(&this->target_stack_, &collector);
|
| Target target_body(&this->target_stack_, body);
|
| @@ -1761,7 +1756,7 @@ Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) {
|
| }
|
| }
|
| Expect(Token::RBRACE, CHECK_OK);
|
| - block_scope->set_end_position(scanner()->location().end_pos);
|
| + block_scope->set_end_position(scanner().location().end_pos);
|
| block_scope = block_scope->FinalizeBlockScope();
|
| body->set_scope(block_scope);
|
| return body;
|
| @@ -1782,6 +1777,12 @@ Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context,
|
| }
|
|
|
|
|
| +bool Parser::IsEvalOrArguments(Handle<String> 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
|
| @@ -1830,7 +1831,7 @@ Block* Parser::ParseVariableDeclarations(
|
| // existing pages. Therefore we keep allowing const with the old
|
| // non-harmony semantics in classic mode.
|
| Consume(Token::CONST);
|
| - switch (scope_->language_mode()) {
|
| + switch (top_scope_->language_mode()) {
|
| case CLASSIC_MODE:
|
| mode = CONST;
|
| init_op = Token::INIT_CONST;
|
| @@ -1923,11 +1924,12 @@ Block* Parser::ParseVariableDeclarations(
|
| is_const ? Interface::NewConst() : Interface::NewValue();
|
| VariableProxy* proxy = NewUnresolved(name, mode, interface);
|
| Declaration* declaration =
|
| - factory()->NewVariableDeclaration(proxy, mode, scope_, pos);
|
| + factory()->NewVariableDeclaration(proxy, mode, top_scope_, pos);
|
| 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<const char*>::empty());
|
| *ok = false;
|
| return NULL;
|
| }
|
| @@ -1942,7 +1944,7 @@ Block* Parser::ParseVariableDeclarations(
|
| //
|
| // var v; v = x;
|
| //
|
| - // In particular, we need to re-lookup 'v' (in scope_, not
|
| + // In particular, we need to re-lookup 'v' (in top_scope_, not
|
| // declaration_scope) as it may be a different 'v' than the 'v' in the
|
| // declaration (e.g., if we are inside a 'with' statement or 'catch'
|
| // block).
|
| @@ -1960,7 +1962,7 @@ Block* Parser::ParseVariableDeclarations(
|
| // one - there is no re-lookup (see the last parameter of the
|
| // Declare() call above).
|
|
|
| - Scope* initialization_scope = is_const ? declaration_scope : scope_;
|
| + Scope* initialization_scope = is_const ? declaration_scope : top_scope_;
|
| Expression* value = NULL;
|
| int pos = -1;
|
| // Harmony consts have non-optional initializers.
|
| @@ -2151,7 +2153,7 @@ Statement* Parser::ParseExpressionOrLabelledStatement(ZoneStringList* labels,
|
| // Remove the "ghost" variable that turned out to be a label
|
| // from the top scope. This way, we don't try to resolve it
|
| // during the scope processing.
|
| - scope_->RemoveUnresolved(var);
|
| + top_scope_->RemoveUnresolved(var);
|
| Expect(Token::COLON, CHECK_OK);
|
| return ParseStatement(labels, ok);
|
| }
|
| @@ -2161,12 +2163,12 @@ Statement* Parser::ParseExpressionOrLabelledStatement(ZoneStringList* labels,
|
| // no line-terminator between the two words.
|
| if (extension_ != NULL &&
|
| peek() == Token::FUNCTION &&
|
| - !scanner()->HasAnyLineTerminatorBeforeNext() &&
|
| + !scanner().HasAnyLineTerminatorBeforeNext() &&
|
| expr != NULL &&
|
| expr->AsVariableProxy() != NULL &&
|
| expr->AsVariableProxy()->name()->Equals(
|
| isolate()->heap()->native_string()) &&
|
| - !scanner()->literal_contains_escapes()) {
|
| + !scanner().literal_contains_escapes()) {
|
| return ParseNativeDeclaration(ok);
|
| }
|
|
|
| @@ -2174,11 +2176,11 @@ Statement* Parser::ParseExpressionOrLabelledStatement(ZoneStringList* labels,
|
| // Only expect semicolon in the former case.
|
| if (!FLAG_harmony_modules ||
|
| peek() != Token::IDENTIFIER ||
|
| - scanner()->HasAnyLineTerminatorBeforeNext() ||
|
| + scanner().HasAnyLineTerminatorBeforeNext() ||
|
| expr->AsVariableProxy() == NULL ||
|
| !expr->AsVariableProxy()->name()->Equals(
|
| isolate()->heap()->module_string()) ||
|
| - scanner()->literal_contains_escapes()) {
|
| + scanner().literal_contains_escapes()) {
|
| ExpectSemicolon(CHECK_OK);
|
| }
|
| return factory()->NewExpressionStatement(expr, pos);
|
| @@ -2215,7 +2217,7 @@ Statement* Parser::ParseContinueStatement(bool* ok) {
|
| Expect(Token::CONTINUE, CHECK_OK);
|
| Handle<String> label = Handle<String>::null();
|
| Token::Value tok = peek();
|
| - if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
|
| + if (!scanner().HasAnyLineTerminatorBeforeNext() &&
|
| tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
|
| // ECMA allows "eval" or "arguments" as labels even in strict mode.
|
| label = ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
|
| @@ -2230,7 +2232,7 @@ Statement* Parser::ParseContinueStatement(bool* ok) {
|
| message = "unknown_label";
|
| args = Vector<Handle<String> >(&label, 1);
|
| }
|
| - ParserTraits::ReportMessageAt(scanner()->location(), message, args);
|
| + ReportMessageAt(scanner().location(), message, args);
|
| *ok = false;
|
| return NULL;
|
| }
|
| @@ -2247,7 +2249,7 @@ Statement* Parser::ParseBreakStatement(ZoneStringList* labels, bool* ok) {
|
| Expect(Token::BREAK, CHECK_OK);
|
| Handle<String> label;
|
| Token::Value tok = peek();
|
| - if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
|
| + if (!scanner().HasAnyLineTerminatorBeforeNext() &&
|
| tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
|
| // ECMA allows "eval" or "arguments" as labels even in strict mode.
|
| label = ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
|
| @@ -2268,7 +2270,7 @@ Statement* Parser::ParseBreakStatement(ZoneStringList* labels, bool* ok) {
|
| message = "unknown_label";
|
| args = Vector<Handle<String> >(&label, 1);
|
| }
|
| - ParserTraits::ReportMessageAt(scanner()->location(), message, args);
|
| + ReportMessageAt(scanner().location(), message, args);
|
| *ok = false;
|
| return NULL;
|
| }
|
| @@ -2290,7 +2292,7 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
|
| Token::Value tok = peek();
|
| Statement* result;
|
| Expression* return_value;
|
| - if (scanner()->HasAnyLineTerminatorBeforeNext() ||
|
| + if (scanner().HasAnyLineTerminatorBeforeNext() ||
|
| tok == Token::SEMICOLON ||
|
| tok == Token::RBRACE ||
|
| tok == Token::EOS) {
|
| @@ -2301,7 +2303,7 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
|
| ExpectSemicolon(CHECK_OK);
|
| if (is_generator()) {
|
| Expression* generator = factory()->NewVariableProxy(
|
| - function_state_->generator_object_variable());
|
| + current_function_state_->generator_object_variable());
|
| Expression* yield = factory()->NewYield(
|
| generator, return_value, Yield::FINAL, pos);
|
| result = factory()->NewExpressionStatement(yield, pos);
|
| @@ -2314,7 +2316,7 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
|
| // function. See ECMA-262, section 12.9, page 67.
|
| //
|
| // To be consistent with KJS we report the syntax error at runtime.
|
| - Scope* declaration_scope = scope_->DeclarationScope();
|
| + Scope* declaration_scope = top_scope_->DeclarationScope();
|
| if (declaration_scope->is_global_scope() ||
|
| declaration_scope->is_eval_scope()) {
|
| Handle<String> message = isolate()->factory()->illegal_return_string();
|
| @@ -2333,7 +2335,7 @@ Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) {
|
| Expect(Token::WITH, CHECK_OK);
|
| int pos = position();
|
|
|
| - if (!scope_->is_classic_mode()) {
|
| + if (!top_scope_->is_classic_mode()) {
|
| ReportMessage("strict_mode_with", Vector<const char*>::empty());
|
| *ok = false;
|
| return NULL;
|
| @@ -2343,13 +2345,13 @@ Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) {
|
| Expression* expr = ParseExpression(true, CHECK_OK);
|
| Expect(Token::RPAREN, CHECK_OK);
|
|
|
| - scope_->DeclarationScope()->RecordWithStatement();
|
| - Scope* with_scope = NewScope(scope_, WITH_SCOPE);
|
| + top_scope_->DeclarationScope()->RecordWithStatement();
|
| + Scope* with_scope = NewScope(top_scope_, WITH_SCOPE);
|
| Statement* stmt;
|
| - { BlockState block_state(&scope_, with_scope);
|
| - with_scope->set_start_position(scanner()->peek_location().beg_pos);
|
| + { BlockState block_state(this, with_scope);
|
| + with_scope->set_start_position(scanner().peek_location().beg_pos);
|
| stmt = ParseStatement(labels, CHECK_OK);
|
| - with_scope->set_end_position(scanner()->location().end_pos);
|
| + with_scope->set_end_position(scanner().location().end_pos);
|
| }
|
| return factory()->NewWithStatement(with_scope, expr, stmt, pos);
|
| }
|
| @@ -2423,7 +2425,7 @@ Statement* Parser::ParseThrowStatement(bool* ok) {
|
|
|
| Expect(Token::THROW, CHECK_OK);
|
| int pos = position();
|
| - if (scanner()->HasAnyLineTerminatorBeforeNext()) {
|
| + if (scanner().HasAnyLineTerminatorBeforeNext()) {
|
| ReportMessage("newline_after_throw", Vector<const char*>::empty());
|
| *ok = false;
|
| return NULL;
|
| @@ -2478,8 +2480,8 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
|
| Consume(Token::CATCH);
|
|
|
| Expect(Token::LPAREN, CHECK_OK);
|
| - catch_scope = NewScope(scope_, CATCH_SCOPE);
|
| - catch_scope->set_start_position(scanner()->location().beg_pos);
|
| + catch_scope = NewScope(top_scope_, CATCH_SCOPE);
|
| + catch_scope->set_start_position(scanner().location().beg_pos);
|
| name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
|
|
|
| Expect(Token::RPAREN, CHECK_OK);
|
| @@ -2489,10 +2491,10 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
|
| catch_variable =
|
| catch_scope->DeclareLocal(name, mode, kCreatedInitialized);
|
|
|
| - BlockState block_state(&scope_, catch_scope);
|
| + BlockState block_state(this, catch_scope);
|
| catch_block = ParseBlock(NULL, CHECK_OK);
|
|
|
| - catch_scope->set_end_position(scanner()->location().end_pos);
|
| + catch_scope->set_end_position(scanner().location().end_pos);
|
| tok = peek();
|
| }
|
|
|
| @@ -2511,7 +2513,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
|
| if (catch_block != NULL && finally_block != NULL) {
|
| // If we have both, create an inner try/catch.
|
| ASSERT(catch_scope != NULL && catch_variable != NULL);
|
| - int index = function_state_->NextHandlerIndex();
|
| + int index = current_function_state_->NextHandlerIndex();
|
| TryCatchStatement* statement = factory()->NewTryCatchStatement(
|
| index, try_block, catch_scope, catch_variable, catch_block,
|
| RelocInfo::kNoPosition);
|
| @@ -2525,12 +2527,12 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
|
| if (catch_block != NULL) {
|
| ASSERT(finally_block == NULL);
|
| ASSERT(catch_scope != NULL && catch_variable != NULL);
|
| - int index = function_state_->NextHandlerIndex();
|
| + int index = current_function_state_->NextHandlerIndex();
|
| result = factory()->NewTryCatchStatement(
|
| index, try_block, catch_scope, catch_variable, catch_block, pos);
|
| } else {
|
| ASSERT(finally_block != NULL);
|
| - int index = function_state_->NextHandlerIndex();
|
| + int index = current_function_state_->NextHandlerIndex();
|
| result = factory()->NewTryFinallyStatement(
|
| index, try_block, finally_block, pos);
|
| // Combine the jump targets of the try block and the possible catch block.
|
| @@ -2610,9 +2612,9 @@ void Parser::InitializeForEachStatement(ForEachStatement* stmt,
|
|
|
| if (for_of != NULL) {
|
| Factory* heap_factory = isolate()->factory();
|
| - Variable* iterator = scope_->DeclarationScope()->NewTemporary(
|
| + Variable* iterator = top_scope_->DeclarationScope()->NewTemporary(
|
| heap_factory->dot_iterator_string());
|
| - Variable* result = scope_->DeclarationScope()->NewTemporary(
|
| + Variable* result = top_scope_->DeclarationScope()->NewTemporary(
|
| heap_factory->dot_result_string());
|
|
|
| Expression* assign_iterator;
|
| @@ -2679,13 +2681,13 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
| Statement* init = NULL;
|
|
|
| // Create an in-between scope for let-bound iteration variables.
|
| - Scope* saved_scope = scope_;
|
| - Scope* for_scope = NewScope(scope_, BLOCK_SCOPE);
|
| - scope_ = for_scope;
|
| + Scope* saved_scope = top_scope_;
|
| + Scope* for_scope = NewScope(top_scope_, BLOCK_SCOPE);
|
| + top_scope_ = for_scope;
|
|
|
| Expect(Token::FOR, CHECK_OK);
|
| Expect(Token::LPAREN, CHECK_OK);
|
| - for_scope->set_start_position(scanner()->location().beg_pos);
|
| + for_scope->set_start_position(scanner().location().beg_pos);
|
| if (peek() != Token::SEMICOLON) {
|
| if (peek() == Token::VAR || peek() == Token::CONST) {
|
| bool is_const = peek() == Token::CONST;
|
| @@ -2708,15 +2710,15 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
| Expect(Token::RPAREN, CHECK_OK);
|
|
|
| VariableProxy* each =
|
| - scope_->NewUnresolved(factory(), name, interface);
|
| + top_scope_->NewUnresolved(factory(), name, interface);
|
| Statement* body = ParseStatement(NULL, CHECK_OK);
|
| InitializeForEachStatement(loop, each, enumerable, body);
|
| Block* result =
|
| factory()->NewBlock(NULL, 2, false, RelocInfo::kNoPosition);
|
| result->AddStatement(variable_statement, zone());
|
| result->AddStatement(loop, zone());
|
| - scope_ = saved_scope;
|
| - for_scope->set_end_position(scanner()->location().end_pos);
|
| + top_scope_ = saved_scope;
|
| + for_scope->set_end_position(scanner().location().end_pos);
|
| for_scope = for_scope->FinalizeBlockScope();
|
| ASSERT(for_scope == NULL);
|
| // Parsed for-in loop w/ variable/const declaration.
|
| @@ -2754,20 +2756,20 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
| Handle<String> tempstr =
|
| heap_factory->NewConsString(heap_factory->dot_for_string(), name);
|
| Handle<String> tempname = heap_factory->InternalizeString(tempstr);
|
| - Variable* temp = scope_->DeclarationScope()->NewTemporary(tempname);
|
| + Variable* temp = top_scope_->DeclarationScope()->NewTemporary(tempname);
|
| VariableProxy* temp_proxy = factory()->NewVariableProxy(temp);
|
| ForEachStatement* loop =
|
| factory()->NewForEachStatement(mode, labels, pos);
|
| Target target(&this->target_stack_, loop);
|
|
|
| // The expression does not see the loop variable.
|
| - scope_ = saved_scope;
|
| + top_scope_ = saved_scope;
|
| Expression* enumerable = ParseExpression(true, CHECK_OK);
|
| - scope_ = for_scope;
|
| + top_scope_ = for_scope;
|
| Expect(Token::RPAREN, CHECK_OK);
|
|
|
| VariableProxy* each =
|
| - scope_->NewUnresolved(factory(), name, Interface::NewValue());
|
| + top_scope_->NewUnresolved(factory(), name, Interface::NewValue());
|
| Statement* body = ParseStatement(NULL, CHECK_OK);
|
| Block* body_block =
|
| factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition);
|
| @@ -2779,8 +2781,8 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
| body_block->AddStatement(assignment_statement, zone());
|
| body_block->AddStatement(body, zone());
|
| InitializeForEachStatement(loop, temp_proxy, enumerable, body_block);
|
| - scope_ = saved_scope;
|
| - for_scope->set_end_position(scanner()->location().end_pos);
|
| + top_scope_ = saved_scope;
|
| + for_scope->set_end_position(scanner().location().end_pos);
|
| for_scope = for_scope->FinalizeBlockScope();
|
| body_block->set_scope(for_scope);
|
| // Parsed for-in loop w/ let declaration.
|
| @@ -2813,8 +2815,8 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
|
|
| Statement* body = ParseStatement(NULL, CHECK_OK);
|
| InitializeForEachStatement(loop, expression, enumerable, body);
|
| - scope_ = saved_scope;
|
| - for_scope->set_end_position(scanner()->location().end_pos);
|
| + top_scope_ = saved_scope;
|
| + for_scope->set_end_position(scanner().location().end_pos);
|
| for_scope = for_scope->FinalizeBlockScope();
|
| ASSERT(for_scope == NULL);
|
| // Parsed for-in loop.
|
| @@ -2848,8 +2850,8 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
| Expect(Token::RPAREN, CHECK_OK);
|
|
|
| Statement* body = ParseStatement(NULL, CHECK_OK);
|
| - scope_ = saved_scope;
|
| - for_scope->set_end_position(scanner()->location().end_pos);
|
| + top_scope_ = saved_scope;
|
| + for_scope->set_end_position(scanner().location().end_pos);
|
| for_scope = for_scope->FinalizeBlockScope();
|
| if (for_scope != NULL) {
|
| // Rewrite a for statement of the form
|
| @@ -2876,6 +2878,23 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
| }
|
|
|
|
|
| +// Precedence = 1
|
| +Expression* Parser::ParseExpression(bool accept_IN, bool* ok) {
|
| + // Expression ::
|
| + // AssignmentExpression
|
| + // Expression ',' AssignmentExpression
|
| +
|
| + Expression* result = ParseAssignmentExpression(accept_IN, CHECK_OK);
|
| + while (peek() == Token::COMMA) {
|
| + Expect(Token::COMMA, CHECK_OK);
|
| + int pos = position();
|
| + Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
|
| + result = factory()->NewBinaryOperation(Token::COMMA, result, right, pos);
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +
|
| // Precedence = 2
|
| Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
|
| // AssignmentExpression ::
|
| @@ -2907,7 +2926,7 @@ Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
|
| expression = NewThrowReferenceError(message);
|
| }
|
|
|
| - if (!scope_->is_classic_mode()) {
|
| + if (!top_scope_->is_classic_mode()) {
|
| // Assignment to eval or arguments is disallowed in strict mode.
|
| CheckStrictModeLValue(expression, CHECK_OK);
|
| }
|
| @@ -2927,7 +2946,7 @@ Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
|
| property != NULL &&
|
| property->obj()->AsVariableProxy() != NULL &&
|
| property->obj()->AsVariableProxy()->is_this()) {
|
| - function_state_->AddProperty();
|
| + current_function_state_->AddProperty();
|
| }
|
|
|
| // If we assign a function literal to a property we pretenure the
|
| @@ -2963,11 +2982,11 @@ Expression* Parser::ParseYieldExpression(bool* ok) {
|
| Yield::Kind kind =
|
| Check(Token::MUL) ? Yield::DELEGATING : Yield::SUSPEND;
|
| Expression* generator_object = factory()->NewVariableProxy(
|
| - function_state_->generator_object_variable());
|
| + current_function_state_->generator_object_variable());
|
| Expression* expression = ParseAssignmentExpression(false, CHECK_OK);
|
| Yield* yield = factory()->NewYield(generator_object, expression, kind, pos);
|
| if (kind == Yield::DELEGATING) {
|
| - yield->set_index(function_state_->NextHandlerIndex());
|
| + yield->set_index(current_function_state_->NextHandlerIndex());
|
| }
|
| return yield;
|
| }
|
| @@ -2994,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);
|
| @@ -3131,7 +3158,7 @@ Expression* Parser::ParseUnaryExpression(bool* ok) {
|
| }
|
|
|
| // "delete identifier" is a syntax error in strict mode.
|
| - if (op == Token::DELETE && !scope_->is_classic_mode()) {
|
| + if (op == Token::DELETE && !top_scope_->is_classic_mode()) {
|
| VariableProxy* operand = expression->AsVariableProxy();
|
| if (operand != NULL && !operand->is_this()) {
|
| ReportMessage("strict_delete", Vector<const char*>::empty());
|
| @@ -3179,7 +3206,7 @@ Expression* Parser::ParseUnaryExpression(bool* ok) {
|
| expression = NewThrowReferenceError(message);
|
| }
|
|
|
| - if (!scope_->is_classic_mode()) {
|
| + if (!top_scope_->is_classic_mode()) {
|
| // Prefix expression operand in strict mode may not be eval or arguments.
|
| CheckStrictModeLValue(expression, CHECK_OK);
|
| }
|
| @@ -3201,7 +3228,7 @@ Expression* Parser::ParsePostfixExpression(bool* ok) {
|
| // LeftHandSideExpression ('++' | '--')?
|
|
|
| Expression* expression = ParseLeftHandSideExpression(CHECK_OK);
|
| - if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
|
| + if (!scanner().HasAnyLineTerminatorBeforeNext() &&
|
| Token::IsCountOp(peek())) {
|
| // Signal a reference error if the expression is an invalid
|
| // left-hand side expression. We could report this as a syntax
|
| @@ -3213,7 +3240,7 @@ Expression* Parser::ParsePostfixExpression(bool* ok) {
|
| expression = NewThrowReferenceError(message);
|
| }
|
|
|
| - if (!scope_->is_classic_mode()) {
|
| + if (!top_scope_->is_classic_mode()) {
|
| // Postfix expression operand in strict mode may not be eval or arguments.
|
| CheckStrictModeLValue(expression, CHECK_OK);
|
| }
|
| @@ -3234,7 +3261,12 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
|
| // LeftHandSideExpression ::
|
| // (NewExpression | MemberExpression) ...
|
|
|
| - Expression* result = ParseMemberWithNewPrefixesExpression(CHECK_OK);
|
| + Expression* result;
|
| + if (peek() == Token::NEW) {
|
| + result = ParseNewExpression(CHECK_OK);
|
| + } else {
|
| + result = ParseMemberExpression(CHECK_OK);
|
| + }
|
|
|
| while (true) {
|
| switch (peek()) {
|
| @@ -3249,7 +3281,7 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
|
|
|
| case Token::LPAREN: {
|
| int pos;
|
| - if (scanner()->current_token() == Token::IDENTIFIER) {
|
| + if (scanner().current_token() == Token::IDENTIFIER) {
|
| // For call of an identifier we want to report position of
|
| // the identifier as position of the call in the stack trace.
|
| pos = position();
|
| @@ -3279,7 +3311,7 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
|
| VariableProxy* callee = result->AsVariableProxy();
|
| if (callee != NULL &&
|
| callee->IsVariable(isolate()->factory()->eval_string())) {
|
| - scope_->DeclarationScope()->RecordEvalCall();
|
| + top_scope_->DeclarationScope()->RecordEvalCall();
|
| }
|
| result = factory()->NewCall(result, args, pos);
|
| if (fni_ != NULL) fni_->RemoveLastFunction();
|
| @@ -3303,54 +3335,54 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
|
| }
|
|
|
|
|
| -Expression* Parser::ParseMemberWithNewPrefixesExpression(bool* ok) {
|
| +Expression* Parser::ParseNewPrefix(PositionStack* stack, bool* ok) {
|
| // NewExpression ::
|
| // ('new')+ MemberExpression
|
|
|
| - // The grammar for new expressions is pretty warped. We can have several 'new'
|
| - // keywords following each other, and then a MemberExpression. When we see '('
|
| - // after the MemberExpression, it's associated with the rightmost unassociated
|
| - // 'new' to create a NewExpression with arguments. However, a NewExpression
|
| - // can also occur without arguments.
|
| -
|
| - // Examples of new expression:
|
| - // new foo.bar().baz means (new (foo.bar)()).baz
|
| - // new foo()() means (new foo())()
|
| - // new new foo()() means (new (new foo())())
|
| - // new new foo means new (new foo)
|
| - // new new foo() means new (new foo())
|
| - // new new foo().bar().baz means (new (new foo()).bar()).baz
|
| -
|
| + // The grammar for new expressions is pretty warped. The keyword
|
| + // 'new' can either be a part of the new expression (where it isn't
|
| + // followed by an argument list) or a part of the member expression,
|
| + // where it must be followed by an argument list. To accommodate
|
| + // this, we parse the 'new' keywords greedily and keep track of how
|
| + // many we have parsed. This information is then passed on to the
|
| + // member expression parser, which is only allowed to match argument
|
| + // lists as long as it has 'new' prefixes left
|
| + Expect(Token::NEW, CHECK_OK);
|
| + PositionStack::Element pos(stack, position());
|
| +
|
| + Expression* result;
|
| if (peek() == Token::NEW) {
|
| - Consume(Token::NEW);
|
| - int new_pos = position();
|
| - Expression* result = ParseMemberWithNewPrefixesExpression(CHECK_OK);
|
| - if (peek() == Token::LPAREN) {
|
| - // NewExpression with arguments.
|
| - ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
|
| - result = factory()->NewCallNew(result, args, new_pos);
|
| - // The expression can still continue with . or [ after the arguments.
|
| - result = ParseMemberExpressionContinuation(result, CHECK_OK);
|
| - return result;
|
| - }
|
| - // NewExpression without arguments.
|
| - return factory()->NewCallNew(
|
| - result, new(zone()) ZoneList<Expression*>(0, zone()), new_pos);
|
| + result = ParseNewPrefix(stack, CHECK_OK);
|
| + } else {
|
| + result = ParseMemberWithNewPrefixesExpression(stack, CHECK_OK);
|
| + }
|
| +
|
| + if (!stack->is_empty()) {
|
| + int last = stack->pop();
|
| + result = factory()->NewCallNew(
|
| + result, new(zone()) ZoneList<Expression*>(0, zone()), last);
|
| }
|
| - // No 'new' keyword.
|
| - return ParseMemberExpression(ok);
|
| + return result;
|
| +}
|
| +
|
| +
|
| +Expression* Parser::ParseNewExpression(bool* ok) {
|
| + PositionStack stack(ok);
|
| + return ParseNewPrefix(&stack, ok);
|
| }
|
|
|
|
|
| Expression* Parser::ParseMemberExpression(bool* ok) {
|
| + return ParseMemberWithNewPrefixesExpression(NULL, ok);
|
| +}
|
| +
|
| +
|
| +Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack,
|
| + bool* ok) {
|
| // MemberExpression ::
|
| // (PrimaryExpression | FunctionLiteral)
|
| // ('[' Expression ']' | '.' Identifier | Arguments)*
|
|
|
| - // The '[' Expression ']' and '.' Identifier parts are parsed by
|
| - // ParseMemberExpressionContinuation, and the Arguments part is parsed by the
|
| - // caller.
|
| -
|
| // Parse the initial primary or function expression.
|
| Expression* result = NULL;
|
| if (peek() == Token::FUNCTION) {
|
| @@ -3363,7 +3395,7 @@ Expression* Parser::ParseMemberExpression(bool* ok) {
|
| if (peek_any_identifier()) {
|
| name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved_name,
|
| CHECK_OK);
|
| - function_name_location = scanner()->location();
|
| + function_name_location = scanner().location();
|
| }
|
| FunctionLiteral::FunctionType function_type = name.is_null()
|
| ? FunctionLiteral::ANONYMOUS_EXPRESSION
|
| @@ -3379,22 +3411,13 @@ Expression* Parser::ParseMemberExpression(bool* ok) {
|
| result = ParsePrimaryExpression(CHECK_OK);
|
| }
|
|
|
| - result = ParseMemberExpressionContinuation(result, CHECK_OK);
|
| - return result;
|
| -}
|
| -
|
| -
|
| -Expression* Parser::ParseMemberExpressionContinuation(Expression* expression,
|
| - bool* ok) {
|
| - // Parses this part of MemberExpression:
|
| - // ('[' Expression ']' | '.' Identifier)*
|
| while (true) {
|
| switch (peek()) {
|
| case Token::LBRACK: {
|
| Consume(Token::LBRACK);
|
| int pos = position();
|
| Expression* index = ParseExpression(true, CHECK_OK);
|
| - expression = factory()->NewProperty(expression, index, pos);
|
| + result = factory()->NewProperty(result, index, pos);
|
| if (fni_ != NULL) {
|
| if (index->IsPropertyName()) {
|
| fni_->PushLiteralName(index->AsLiteral()->AsPropertyName());
|
| @@ -3410,17 +3433,23 @@ Expression* Parser::ParseMemberExpressionContinuation(Expression* expression,
|
| Consume(Token::PERIOD);
|
| int pos = position();
|
| Handle<String> name = ParseIdentifierName(CHECK_OK);
|
| - expression = factory()->NewProperty(
|
| - expression, factory()->NewLiteral(name, pos), pos);
|
| + result = factory()->NewProperty(
|
| + result, factory()->NewLiteral(name, pos), pos);
|
| if (fni_ != NULL) fni_->PushLiteralName(name);
|
| break;
|
| }
|
| + case Token::LPAREN: {
|
| + if ((stack == NULL) || stack->is_empty()) return result;
|
| + // Consume one of the new prefixes (already parsed).
|
| + ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
|
| + int pos = stack->pop();
|
| + result = factory()->NewCallNew(result, args, pos);
|
| + break;
|
| + }
|
| default:
|
| - return expression;
|
| + return result;
|
| }
|
| }
|
| - ASSERT(false);
|
| - return NULL;
|
| }
|
|
|
|
|
| @@ -3447,6 +3476,152 @@ void Parser::ReportInvalidPreparseData(Handle<String> name, bool* ok) {
|
| }
|
|
|
|
|
| +Expression* Parser::ParsePrimaryExpression(bool* ok) {
|
| + // PrimaryExpression ::
|
| + // 'this'
|
| + // 'null'
|
| + // 'true'
|
| + // 'false'
|
| + // Identifier
|
| + // Number
|
| + // String
|
| + // ArrayLiteral
|
| + // ObjectLiteral
|
| + // RegExpLiteral
|
| + // '(' Expression ')'
|
| +
|
| + int pos = peek_position();
|
| + Expression* result = NULL;
|
| + switch (peek()) {
|
| + case Token::THIS: {
|
| + Consume(Token::THIS);
|
| + result = factory()->NewVariableProxy(top_scope_->receiver());
|
| + break;
|
| + }
|
| +
|
| + case Token::NULL_LITERAL:
|
| + Consume(Token::NULL_LITERAL);
|
| + result = factory()->NewLiteral(isolate()->factory()->null_value(), pos);
|
| + break;
|
| +
|
| + case Token::TRUE_LITERAL:
|
| + Consume(Token::TRUE_LITERAL);
|
| + result = factory()->NewLiteral(isolate()->factory()->true_value(), pos);
|
| + break;
|
| +
|
| + case Token::FALSE_LITERAL:
|
| + Consume(Token::FALSE_LITERAL);
|
| + result = factory()->NewLiteral(isolate()->factory()->false_value(), pos);
|
| + break;
|
| +
|
| + case Token::IDENTIFIER:
|
| + case Token::YIELD:
|
| + case Token::FUTURE_STRICT_RESERVED_WORD: {
|
| + // Using eval or arguments in this context is OK even in strict mode.
|
| + Handle<String> name = ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
|
| + if (fni_ != NULL) fni_->PushVariableName(name);
|
| + // The name may refer to a module instance object, so its type is unknown.
|
| +#ifdef DEBUG
|
| + if (FLAG_print_interface_details)
|
| + PrintF("# Variable %s ", name->ToAsciiArray());
|
| +#endif
|
| + Interface* interface = Interface::NewUnknown(zone());
|
| + result = top_scope_->NewUnresolved(factory(), name, interface, pos);
|
| + break;
|
| + }
|
| +
|
| + case Token::NUMBER: {
|
| + Consume(Token::NUMBER);
|
| + ASSERT(scanner().is_literal_ascii());
|
| + double value = StringToDouble(isolate()->unicode_cache(),
|
| + scanner().literal_ascii_string(),
|
| + ALLOW_HEX | ALLOW_OCTAL |
|
| + ALLOW_IMPLICIT_OCTAL | ALLOW_BINARY);
|
| + result = factory()->NewNumberLiteral(value, pos);
|
| + break;
|
| + }
|
| +
|
| + case Token::STRING: {
|
| + Consume(Token::STRING);
|
| + Handle<String> symbol = GetSymbol();
|
| + result = factory()->NewLiteral(symbol, pos);
|
| + if (fni_ != NULL) fni_->PushLiteralName(symbol);
|
| + break;
|
| + }
|
| +
|
| + case Token::ASSIGN_DIV:
|
| + result = ParseRegExpLiteral(true, CHECK_OK);
|
| + break;
|
| +
|
| + case Token::DIV:
|
| + result = ParseRegExpLiteral(false, CHECK_OK);
|
| + break;
|
| +
|
| + case Token::LBRACK:
|
| + result = ParseArrayLiteral(CHECK_OK);
|
| + break;
|
| +
|
| + case Token::LBRACE:
|
| + result = ParseObjectLiteral(CHECK_OK);
|
| + break;
|
| +
|
| + case Token::LPAREN:
|
| + Consume(Token::LPAREN);
|
| + // Heuristically try to detect immediately called functions before
|
| + // seeing the call parentheses.
|
| + parenthesized_function_ = (peek() == Token::FUNCTION);
|
| + result = ParseExpression(true, CHECK_OK);
|
| + Expect(Token::RPAREN, CHECK_OK);
|
| + break;
|
| +
|
| + case Token::MOD:
|
| + if (allow_natives_syntax() || extension_ != NULL) {
|
| + result = ParseV8Intrinsic(CHECK_OK);
|
| + break;
|
| + }
|
| + // If we're not allowing special syntax we fall-through to the
|
| + // default case.
|
| +
|
| + default: {
|
| + Token::Value tok = Next();
|
| + ReportUnexpectedToken(tok);
|
| + *ok = false;
|
| + return NULL;
|
| + }
|
| + }
|
| +
|
| + return result;
|
| +}
|
| +
|
| +
|
| +Expression* Parser::ParseArrayLiteral(bool* ok) {
|
| + // ArrayLiteral ::
|
| + // '[' Expression? (',' Expression?)* ']'
|
| +
|
| + int pos = peek_position();
|
| + ZoneList<Expression*>* values = new(zone()) ZoneList<Expression*>(4, zone());
|
| + Expect(Token::LBRACK, CHECK_OK);
|
| + while (peek() != Token::RBRACK) {
|
| + Expression* elem;
|
| + if (peek() == Token::COMMA) {
|
| + elem = GetLiteralTheHole(peek_position());
|
| + } else {
|
| + elem = ParseAssignmentExpression(true, CHECK_OK);
|
| + }
|
| + values->Add(elem, zone());
|
| + if (peek() != Token::RBRACK) {
|
| + Expect(Token::COMMA, CHECK_OK);
|
| + }
|
| + }
|
| + Expect(Token::RBRACK, CHECK_OK);
|
| +
|
| + // Update the scope information before the pre-parsing bailout.
|
| + int literal_index = current_function_state_->NextMaterializedLiteralIndex();
|
| +
|
| + return factory()->NewArrayLiteral(values, literal_index, pos);
|
| +}
|
| +
|
| +
|
| bool CompileTimeValue::IsCompileTimeValue(Expression* expression) {
|
| if (expression->AsLiteral() != NULL) return true;
|
| MaterializedLiteral* lit = expression->AsMaterializedLiteral();
|
| @@ -3503,7 +3678,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
|
| int number_of_boilerplate_properties = 0;
|
| bool has_function = false;
|
|
|
| - ObjectLiteralChecker checker(this, scope_->language_mode());
|
| + ObjectLiteralChecker checker(this, top_scope_->language_mode());
|
|
|
| Expect(Token::LBRACE, CHECK_OK);
|
|
|
| @@ -3549,7 +3724,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
|
| : GetSymbol();
|
| FunctionLiteral* value =
|
| ParseFunctionLiteral(name,
|
| - scanner()->location(),
|
| + scanner().location(),
|
| false, // reserved words are allowed here
|
| false, // not a generator
|
| RelocInfo::kNoPosition,
|
| @@ -3590,9 +3765,9 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
|
| }
|
| case Token::NUMBER: {
|
| Consume(Token::NUMBER);
|
| - ASSERT(scanner()->is_literal_ascii());
|
| + ASSERT(scanner().is_literal_ascii());
|
| double value = StringToDouble(isolate()->unicode_cache(),
|
| - scanner()->literal_ascii_string(),
|
| + scanner().literal_ascii_string(),
|
| ALLOW_HEX | ALLOW_OCTAL |
|
| ALLOW_IMPLICIT_OCTAL | ALLOW_BINARY);
|
| key = factory()->NewNumberLiteral(value, next_pos);
|
| @@ -3624,7 +3799,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
|
| // Mark top-level object literals that contain function literals and
|
| // pretenure the literal so it can be added as a constant function
|
| // property.
|
| - if (scope_->DeclarationScope()->is_global_scope() &&
|
| + if (top_scope_->DeclarationScope()->is_global_scope() &&
|
| value->AsFunctionLiteral() != NULL) {
|
| has_function = true;
|
| value->AsFunctionLiteral()->set_pretenure();
|
| @@ -3647,7 +3822,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
|
| Expect(Token::RBRACE, CHECK_OK);
|
|
|
| // Computation of literal_index must happen before pre parse bailout.
|
| - int literal_index = function_state_->NextMaterializedLiteralIndex();
|
| + int literal_index = current_function_state_->NextMaterializedLiteralIndex();
|
|
|
| return factory()->NewObjectLiteral(properties,
|
| literal_index,
|
| @@ -3657,6 +3832,26 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
|
| }
|
|
|
|
|
| +Expression* Parser::ParseRegExpLiteral(bool seen_equal, bool* ok) {
|
| + int pos = peek_position();
|
| + if (!scanner().ScanRegExpPattern(seen_equal)) {
|
| + Next();
|
| + ReportMessage("unterminated_regexp", Vector<const char*>::empty());
|
| + *ok = false;
|
| + return NULL;
|
| + }
|
| +
|
| + int literal_index = current_function_state_->NextMaterializedLiteralIndex();
|
| +
|
| + Handle<String> js_pattern = NextLiteralString(TENURED);
|
| + scanner().ScanRegExpFlags();
|
| + Handle<String> js_flags = NextLiteralString(TENURED);
|
| + Next();
|
| +
|
| + return factory()->NewRegExpLiteral(js_pattern, js_flags, literal_index, pos);
|
| +}
|
| +
|
| +
|
| ZoneList<Expression*>* Parser::ParseArguments(bool* ok) {
|
| // Arguments ::
|
| // '(' (AssignmentExpression)*[','] ')'
|
| @@ -3668,7 +3863,8 @@ ZoneList<Expression*>* 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<const char*>::empty());
|
| *ok = false;
|
| return NULL;
|
| }
|
| @@ -3825,14 +4021,14 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
| // one relative to the deserialized scope chain. Otherwise we must be
|
| // compiling a function in an inner declaration scope in the eval, e.g. a
|
| // nested function, and hoisting works normally relative to that.
|
| - Scope* declaration_scope = scope_->DeclarationScope();
|
| + Scope* declaration_scope = top_scope_->DeclarationScope();
|
| Scope* original_declaration_scope = original_scope_->DeclarationScope();
|
| Scope* scope =
|
| function_type == FunctionLiteral::DECLARATION && !is_extended_mode() &&
|
| (original_scope_ == original_declaration_scope ||
|
| declaration_scope != original_declaration_scope)
|
| ? NewScope(declaration_scope, FUNCTION_SCOPE)
|
| - : NewScope(scope_, FUNCTION_SCOPE);
|
| + : NewScope(top_scope_, FUNCTION_SCOPE);
|
| ZoneList<Statement*>* body = NULL;
|
| int materialized_literal_count = -1;
|
| int expected_property_count = -1;
|
| @@ -3845,23 +4041,23 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
| FunctionLiteral::IsGeneratorFlag generator = is_generator
|
| ? FunctionLiteral::kIsGenerator
|
| : FunctionLiteral::kNotGenerator;
|
| - DeferredFeedbackSlotProcessor* slot_processor;
|
| AstProperties ast_properties;
|
| BailoutReason dont_optimize_reason = kNoReason;
|
| // Parse function body.
|
| - { FunctionState function_state(&function_state_, &scope_, scope, zone());
|
| - scope_->SetScopeName(function_name);
|
| + { FunctionState function_state(this, scope);
|
| + top_scope_->SetScopeName(function_name);
|
|
|
| if (is_generator) {
|
| // For generators, allocating variables in contexts is currently a win
|
| // because it minimizes the work needed to suspend and resume an
|
| // activation.
|
| - scope_->ForceContextAllocation();
|
| + top_scope_->ForceContextAllocation();
|
|
|
| // Calling a generator returns a generator object. That object is stored
|
| // in a temporary variable, a definition that is used by "yield"
|
| - // expressions. This also marks the FunctionState as a generator.
|
| - Variable* temp = scope_->DeclarationScope()->NewTemporary(
|
| + // expressions. Presence of a variable for the generator object in the
|
| + // FunctionState indicates that this function is a generator.
|
| + Variable* temp = top_scope_->DeclarationScope()->NewTemporary(
|
| isolate()->factory()->dot_generator_object_string());
|
| function_state.set_generator_object_variable(temp);
|
| }
|
| @@ -3869,7 +4065,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
| // FormalParameterList ::
|
| // '(' (Identifier)*[','] ')'
|
| Expect(Token::LPAREN, CHECK_OK);
|
| - scope->set_start_position(scanner()->location().beg_pos);
|
| + scope->set_start_position(scanner().location().beg_pos);
|
|
|
| // We don't yet know if the function will be strict, so we cannot yet
|
| // produce errors for parameter names or duplicates. However, we remember
|
| @@ -3886,20 +4082,21 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
|
|
| // Store locations for possible future error reports.
|
| if (!eval_args_error_log.IsValid() && IsEvalOrArguments(param_name)) {
|
| - eval_args_error_log = scanner()->location();
|
| + eval_args_error_log = scanner().location();
|
| }
|
| if (!reserved_loc.IsValid() && is_strict_reserved) {
|
| - reserved_loc = scanner()->location();
|
| + reserved_loc = scanner().location();
|
| }
|
| - if (!dupe_error_loc.IsValid() && scope_->IsDeclared(param_name)) {
|
| + if (!dupe_error_loc.IsValid() && top_scope_->IsDeclared(param_name)) {
|
| duplicate_parameters = FunctionLiteral::kHasDuplicateParameters;
|
| - dupe_error_loc = scanner()->location();
|
| + dupe_error_loc = scanner().location();
|
| }
|
|
|
| - scope_->DeclareParameter(param_name, VAR);
|
| + 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<const char*>::empty());
|
| *ok = false;
|
| return NULL;
|
| }
|
| @@ -3921,20 +4118,17 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
| if (function_type == FunctionLiteral::NAMED_EXPRESSION) {
|
| if (is_extended_mode()) fvar_init_op = Token::INIT_CONST_HARMONY;
|
| VariableMode fvar_mode = is_extended_mode() ? CONST_HARMONY : CONST;
|
| - fvar = new(zone()) Variable(scope_,
|
| + fvar = new(zone()) Variable(top_scope_,
|
| function_name, fvar_mode, true /* is valid LHS */,
|
| Variable::NORMAL, kCreatedInitialized, Interface::NewConst());
|
| VariableProxy* proxy = factory()->NewVariableProxy(fvar);
|
| VariableDeclaration* fvar_declaration = factory()->NewVariableDeclaration(
|
| - proxy, fvar_mode, scope_, RelocInfo::kNoPosition);
|
| - scope_->DeclareFunctionVar(fvar_declaration);
|
| + proxy, fvar_mode, top_scope_, RelocInfo::kNoPosition);
|
| + top_scope_->DeclareFunctionVar(fvar_declaration);
|
| }
|
|
|
| - // Determine if the function can be parsed lazily. Lazy parsing is different
|
| - // from lazy compilation; we need to parse more eagerly than we compile.
|
| -
|
| - // We can only parse lazily if we also compile lazily. The heuristics for
|
| - // lazy compilation are:
|
| + // Determine whether the function will be lazily compiled.
|
| + // The heuristics are:
|
| // - It must not have been prohibited by the caller to Parse (some callers
|
| // need a full AST).
|
| // - The outer scope must allow lazy compilation of inner functions.
|
| @@ -3944,31 +4138,12 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
| // compiled.
|
| // These are all things we can know at this point, without looking at the
|
| // function itself.
|
| -
|
| - // In addition, we need to distinguish between these cases:
|
| - // (function foo() {
|
| - // bar = function() { return 1; }
|
| - // })();
|
| - // and
|
| - // (function foo() {
|
| - // var a = 1;
|
| - // bar = function() { return a; }
|
| - // })();
|
| -
|
| - // Now foo will be parsed eagerly and compiled eagerly (optimization: assume
|
| - // parenthesis before the function means that it will be called
|
| - // immediately). The inner function *must* be parsed eagerly to resolve the
|
| - // possible reference to the variable in foo's scope. However, it's possible
|
| - // that it will be compiled lazily.
|
| -
|
| - // To make this additional case work, both Parser and PreParser implement a
|
| - // logic where only top-level functions will be parsed lazily.
|
| - bool is_lazily_parsed = (mode() == PARSE_LAZILY &&
|
| - scope_->AllowsLazyCompilation() &&
|
| - !parenthesized_function_);
|
| + bool is_lazily_compiled = (mode() == PARSE_LAZILY &&
|
| + top_scope_->AllowsLazyCompilation() &&
|
| + !parenthesized_function_);
|
| parenthesized_function_ = false; // The bit was set for this function only.
|
|
|
| - if (is_lazily_parsed) {
|
| + if (is_lazily_compiled) {
|
| int function_block_pos = position();
|
| FunctionEntry entry;
|
| if (pre_parse_data_ != NULL) {
|
| @@ -3982,7 +4157,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
| // to check.
|
| ReportInvalidPreparseData(function_name, CHECK_OK);
|
| }
|
| - scanner()->SeekForward(entry.end_pos() - 1);
|
| + scanner().SeekForward(entry.end_pos() - 1);
|
|
|
| scope->set_end_position(entry.end_pos());
|
| Expect(Token::RBRACE, CHECK_OK);
|
| @@ -3990,22 +4165,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
| scope->end_position() - function_block_pos);
|
| materialized_literal_count = entry.literal_count();
|
| expected_property_count = entry.property_count();
|
| - scope_->SetLanguageMode(entry.language_mode());
|
| + top_scope_->SetLanguageMode(entry.language_mode());
|
| } else {
|
| - // This case happens when we have preparse data but it doesn't contain
|
| - // an entry for the function. As a safety net, fall back to eager
|
| - // parsing. It is unclear whether PreParser's laziness analysis can
|
| - // produce different results than the Parser's laziness analysis (see
|
| - // https://codereview.chromium.org/7565003 ). This safety net is
|
| - // guarding against the case where Parser thinks a function should be
|
| - // lazily parsed, but PreParser thinks it should be eagerly parsed --
|
| - // in that case we fall back to eager parsing in Parser, too. Note
|
| - // that the opposite case is worse: if PreParser thinks a function
|
| - // should be lazily parsed, but Parser thinks it should be eagerly
|
| - // parsed, it will never advance the preparse data beyond that
|
| - // function and all further laziness will fail (all functions will be
|
| - // parsed eagerly).
|
| - is_lazily_parsed = false;
|
| + is_lazily_compiled = false;
|
| }
|
| } else {
|
| // With no preparser data, we partially parse the function, without
|
| @@ -4025,10 +4187,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
| if (arg != NULL) {
|
| args = Vector<const char*>(&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;
|
| }
|
| @@ -4038,17 +4198,15 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
| scope->end_position() - function_block_pos);
|
| materialized_literal_count = logger.literals();
|
| expected_property_count = logger.properties();
|
| - scope_->SetLanguageMode(logger.language_mode());
|
| + top_scope_->SetLanguageMode(logger.language_mode());
|
| }
|
| }
|
|
|
| - if (!is_lazily_parsed) {
|
| - // Everything inside an eagerly parsed function will be parsed eagerly
|
| - // (see comment above).
|
| + if (!is_lazily_compiled) {
|
| ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
|
| body = new(zone()) ZoneList<Statement*>(8, zone());
|
| if (fvar != NULL) {
|
| - VariableProxy* fproxy = scope_->NewUnresolved(
|
| + VariableProxy* fproxy = top_scope_->NewUnresolved(
|
| factory(), function_name, Interface::NewConst());
|
| fproxy->BindTo(fvar);
|
| body->Add(factory()->NewExpressionStatement(
|
| @@ -4068,11 +4226,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
| Runtime::FunctionForId(Runtime::kCreateJSGeneratorObject),
|
| arguments, pos);
|
| VariableProxy* init_proxy = factory()->NewVariableProxy(
|
| - function_state_->generator_object_variable());
|
| + current_function_state_->generator_object_variable());
|
| Assignment* assignment = factory()->NewAssignment(
|
| Token::INIT_VAR, init_proxy, allocation, RelocInfo::kNoPosition);
|
| VariableProxy* get_proxy = factory()->NewVariableProxy(
|
| - function_state_->generator_object_variable());
|
| + current_function_state_->generator_object_variable());
|
| Yield* yield = factory()->NewYield(
|
| get_proxy, assignment, Yield::INITIAL, RelocInfo::kNoPosition);
|
| body->Add(factory()->NewExpressionStatement(
|
| @@ -4083,7 +4241,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
|
|
| if (is_generator) {
|
| VariableProxy* get_proxy = factory()->NewVariableProxy(
|
| - function_state_->generator_object_variable());
|
| + current_function_state_->generator_object_variable());
|
| Expression *undefined = factory()->NewLiteral(
|
| isolate()->factory()->undefined_value(), RelocInfo::kNoPosition);
|
| Yield* yield = factory()->NewYield(
|
| @@ -4097,34 +4255,40 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
| handler_count = function_state.handler_count();
|
|
|
| Expect(Token::RBRACE, CHECK_OK);
|
| - scope->set_end_position(scanner()->location().end_pos);
|
| + scope->set_end_position(scanner().location().end_pos);
|
| }
|
|
|
| // Validate strict mode. We can do this only after parsing the function,
|
| // since the function can declare itself strict.
|
| - if (!scope_->is_classic_mode()) {
|
| + 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<const char*>::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<const char*>::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<const char*>::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<const char*>::empty());
|
| *ok = false;
|
| return NULL;
|
| }
|
| if (reserved_loc.IsValid()) {
|
| - ReportMessageAt(reserved_loc, "unexpected_strict_reserved");
|
| + ReportMessageAt(reserved_loc, "unexpected_strict_reserved",
|
| + Vector<const char*>::empty());
|
| *ok = false;
|
| return NULL;
|
| }
|
| @@ -4133,7 +4297,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
| CHECK_OK);
|
| }
|
| ast_properties = *factory()->visitor()->ast_properties();
|
| - slot_processor = factory()->visitor()->slot_processor();
|
| dont_optimize_reason = factory()->visitor()->dont_optimize_reason();
|
| }
|
|
|
| @@ -4157,7 +4320,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
| pos);
|
| function_literal->set_function_token_position(function_token_pos);
|
| function_literal->set_ast_properties(&ast_properties);
|
| - function_literal->set_slot_processor(slot_processor);
|
| function_literal->set_dont_optimize_reason(dont_optimize_reason);
|
|
|
| if (fni_ != NULL && should_infer_name) fni_->AddFunction(function_literal);
|
| @@ -4168,7 +4330,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
| PreParser::PreParseResult Parser::LazyParseFunctionLiteral(
|
| SingletonLogger* logger) {
|
| HistogramTimerScope preparse_scope(isolate()->counters()->pre_parse());
|
| - ASSERT_EQ(Token::LBRACE, scanner()->current_token());
|
| + ASSERT_EQ(Token::LBRACE, scanner().current_token());
|
|
|
| if (reusable_preparser_ == NULL) {
|
| intptr_t stack_limit = isolate()->stack_guard()->real_climit();
|
| @@ -4183,7 +4345,7 @@ PreParser::PreParseResult Parser::LazyParseFunctionLiteral(
|
| allow_harmony_numeric_literals());
|
| }
|
| PreParser::PreParseResult result =
|
| - reusable_preparser_->PreParseLazyFunction(scope_->language_mode(),
|
| + reusable_preparser_->PreParseLazyFunction(top_scope_->language_mode(),
|
| is_generator(),
|
| logger);
|
| return result;
|
| @@ -4203,7 +4365,7 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) {
|
| if (extension_ != NULL) {
|
| // The extension structures are only accessible while parsing the
|
| // very first time not when reparsing because of lazy compilation.
|
| - scope_->DeclarationScope()->ForceEagerCompilation();
|
| + top_scope_->DeclarationScope()->ForceEagerCompilation();
|
| }
|
|
|
| const Runtime::Function* function = Runtime::FunctionForName(name);
|
| @@ -4235,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<Handle<String> >(&name, 1));
|
| + ReportMessage("not_defined", Vector<Handle<String> >(&name, 1));
|
| *ok = false;
|
| return NULL;
|
| }
|
| @@ -4246,12 +4407,162 @@ 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<const char> 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<const char> 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<const char*>(&name, 1));
|
| + }
|
| +}
|
| +
|
| +
|
| Literal* Parser::GetLiteralUndefined(int position) {
|
| return factory()->NewLiteral(
|
| isolate()->factory()->undefined_value(), position);
|
| }
|
|
|
|
|
| +Literal* Parser::GetLiteralTheHole(int position) {
|
| + return factory()->NewLiteral(
|
| + isolate()->factory()->the_hole_value(), RelocInfo::kNoPosition);
|
| +}
|
| +
|
| +
|
| +// 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<String> Parser::ParseIdentifier(
|
| + AllowEvalOrArgumentsAsIdentifier allow_eval_or_arguments,
|
| + bool* ok) {
|
| + Token::Value next = Next();
|
| + if (next == Token::IDENTIFIER) {
|
| + Handle<String> name = GetSymbol();
|
| + if (allow_eval_or_arguments == kDontAllowEvalOrArguments &&
|
| + !top_scope_->is_classic_mode() && IsEvalOrArguments(name)) {
|
| + ReportMessage("strict_eval_arguments", Vector<const char*>::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<String>();
|
| + }
|
| +}
|
| +
|
| +
|
| +// Parses and identifier or a strict mode future reserved word, and indicate
|
| +// whether it is strict mode future reserved.
|
| +Handle<String> 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<String>();
|
| + }
|
| + return GetSymbol();
|
| +}
|
| +
|
| +
|
| +Handle<String> 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<String>();
|
| + }
|
| + return GetSymbol();
|
| +}
|
| +
|
| +
|
| void Parser::MarkAsLValue(Expression* expression) {
|
| VariableProxy* proxy = expression != NULL
|
| ? expression->AsVariableProxy()
|
| @@ -4265,7 +4576,7 @@ void Parser::MarkAsLValue(Expression* expression) {
|
| // in strict mode.
|
| void Parser::CheckStrictModeLValue(Expression* expression,
|
| bool* ok) {
|
| - ASSERT(!scope_->is_classic_mode());
|
| + ASSERT(!top_scope_->is_classic_mode());
|
| VariableProxy* lhs = expression != NULL
|
| ? expression->AsVariableProxy()
|
| : NULL;
|
| @@ -4277,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) {
|
| @@ -4290,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<String> Parser::ParseIdentifierNameOrGetOrSet(bool* is_get,
|
| + bool* is_set,
|
| + bool* ok) {
|
| + Handle<String> result = ParseIdentifierName(ok);
|
| + if (!*ok) return Handle<String>();
|
| + 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
|
|
|
| @@ -5344,7 +5683,7 @@ bool Parser::Parse() {
|
| Scanner::Location loc = pre_parse_data->MessageLocation();
|
| const char* message = pre_parse_data->BuildMessage();
|
| Vector<const char*> 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]);
|
|
|