diff options
author | Ben Noordhuis <info@bnoordhuis.nl> | 2015-03-27 12:04:12 +0100 |
---|---|---|
committer | Chris Dickinson <christopher.s.dickinson@gmail.com> | 2015-04-28 14:38:16 -0700 |
commit | 36cd5fb9d27b830320e57213f5b8829ffbb93324 (patch) | |
tree | bbab4215d26f8597019135206426fccf27a3089e /deps/v8/src/parser.cc | |
parent | b57cc51d8d3f4ad279591ae8fa6584ee22773b97 (diff) | |
download | node-new-36cd5fb9d27b830320e57213f5b8829ffbb93324.tar.gz |
deps: upgrade v8 to 4.2.77.13
This commit applies some secondary changes in order to make `make test`
pass cleanly:
* disable broken postmortem debugging in common.gypi
* drop obsolete strict mode test in parallel/test-repl
* drop obsolete test parallel/test-v8-features
PR-URL: https://github.com/iojs/io.js/pull/1232
Reviewed-By: Fedor Indutny <fedor@indutny.com>
Diffstat (limited to 'deps/v8/src/parser.cc')
-rw-r--r-- | deps/v8/src/parser.cc | 1680 |
1 files changed, 915 insertions, 765 deletions
diff --git a/deps/v8/src/parser.cc b/deps/v8/src/parser.cc index bfdeaa3276..985a90f8dc 100644 --- a/deps/v8/src/parser.cc +++ b/deps/v8/src/parser.cc @@ -251,27 +251,18 @@ int ParseData::FunctionsSize() { } -void Parser::SetCachedData() { - if (compile_options() == ScriptCompiler::kNoCompileOptions) { +void Parser::SetCachedData(CompilationInfo* info) { + if (compile_options_ == ScriptCompiler::kNoCompileOptions) { cached_parse_data_ = NULL; } else { - DCHECK(info_->cached_data() != NULL); - if (compile_options() == ScriptCompiler::kConsumeParserCache) { - cached_parse_data_ = ParseData::FromCachedData(*info_->cached_data()); + DCHECK(info->cached_data() != NULL); + if (compile_options_ == ScriptCompiler::kConsumeParserCache) { + cached_parse_data_ = ParseData::FromCachedData(*info->cached_data()); } } } -Scope* Parser::NewScope(Scope* parent, ScopeType scope_type) { - DCHECK(ast_value_factory()); - Scope* result = - new (zone()) Scope(parent, scope_type, ast_value_factory(), zone()); - result->Initialize(); - return result; -} - - FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope, int pos, int end_pos) { int materialized_literal_count = -1; @@ -280,8 +271,12 @@ FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope, int parameter_count = 0; const AstRawString* name = ast_value_factory()->empty_string(); - Scope* function_scope = NewScope(scope, FUNCTION_SCOPE); - function_scope->SetStrictMode(STRICT); + + FunctionKind kind = call_super ? FunctionKind::kDefaultSubclassConstructor + : FunctionKind::kDefaultBaseConstructor; + Scope* function_scope = NewScope(scope, FUNCTION_SCOPE, kind); + function_scope->SetLanguageMode( + static_cast<LanguageMode>(scope->language_mode() | STRICT_BIT)); // Set start and end position to the same value function_scope->set_start_position(pos); function_scope->set_end_position(pos); @@ -290,18 +285,18 @@ FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope, { AstNodeFactory function_factory(ast_value_factory()); FunctionState function_state(&function_state_, &scope_, function_scope, - &function_factory); + kind, &function_factory); - body = new (zone()) ZoneList<Statement*>(1, zone()); + body = new (zone()) ZoneList<Statement*>(call_super ? 2 : 1, zone()); + AddAssertIsConstruct(body, pos); if (call_super) { ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(0, zone()); CallRuntime* call = factory()->NewCallRuntime( ast_value_factory()->empty_string(), - Runtime::FunctionForId(Runtime::kDefaultConstructorSuperCall), args, - pos); - body->Add(factory()->NewExpressionStatement(call, pos), zone()); - function_scope->RecordSuperConstructorCallUsage(); + Runtime::FunctionForId(Runtime::kInlineDefaultConstructorCallSuper), + args, pos); + body->Add(factory()->NewReturnStatement(call, pos), zone()); } materialized_literal_count = function_state.materialized_literal_count(); @@ -314,8 +309,7 @@ FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope, materialized_literal_count, expected_property_count, handler_count, parameter_count, FunctionLiteral::kNoDuplicateParameters, FunctionLiteral::ANONYMOUS_EXPRESSION, FunctionLiteral::kIsFunction, - FunctionLiteral::kNotParenthesized, FunctionKind::kDefaultConstructor, - pos); + FunctionLiteral::kNotParenthesized, kind, pos); return function_literal; } @@ -329,8 +323,8 @@ FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope, class Target BASE_EMBEDDED { public: - Target(Target** variable, AstNode* node) - : variable_(variable), node_(node), previous_(*variable) { + Target(Target** variable, BreakableStatement* statement) + : variable_(variable), statement_(statement), previous_(*variable) { *variable = this; } @@ -339,11 +333,11 @@ class Target BASE_EMBEDDED { } Target* previous() { return previous_; } - AstNode* node() { return node_; } + BreakableStatement* statement() { return statement_; } private: Target** variable_; - AstNode* node_; + BreakableStatement* statement_; Target* previous_; }; @@ -388,9 +382,18 @@ class TargetScope BASE_EMBEDDED { // ---------------------------------------------------------------------------- // Implementation of Parser +bool ParserTraits::IsEval(const AstRawString* identifier) const { + return identifier == parser_->ast_value_factory()->eval_string(); +} + + +bool ParserTraits::IsArguments(const AstRawString* identifier) const { + return identifier == parser_->ast_value_factory()->arguments_string(); +} + + bool ParserTraits::IsEvalOrArguments(const AstRawString* identifier) const { - return identifier == parser_->ast_value_factory()->eval_string() || - identifier == parser_->ast_value_factory()->arguments_string(); + return IsEval(identifier) || IsArguments(identifier); } @@ -407,9 +410,8 @@ bool ParserTraits::IsConstructor(const AstRawString* identifier) const { bool ParserTraits::IsThisProperty(Expression* expression) { DCHECK(expression != NULL); Property* property = expression->AsProperty(); - return property != NULL && - property->obj()->AsVariableProxy() != NULL && - property->obj()->AsVariableProxy()->is_this(); + return property != NULL && property->obj()->IsVariableProxy() && + property->obj()->AsVariableProxy()->is_this(); } @@ -433,8 +435,7 @@ void ParserTraits::PushPropertyName(FuncNameInferrer* fni, void ParserTraits::CheckAssigningFunctionLiteralToProperty(Expression* left, Expression* right) { DCHECK(left != NULL); - if (left->AsProperty() != NULL && - right->AsFunctionLiteral() != NULL) { + if (left->IsProperty() && right->IsFunctionLiteral()) { right->AsFunctionLiteral()->set_pretenure(); } } @@ -665,7 +666,7 @@ const AstRawString* ParserTraits::GetNumberAsSymbol(Scanner* scanner) { char array[100]; const char* string = DoubleToCString(double_value, Vector<char>(array, arraysize(array))); - return ast_value_factory()->GetOneByteString(string); + return parser_->ast_value_factory()->GetOneByteString(string); } @@ -718,13 +719,14 @@ Expression* ParserTraits::ExpressionFromIdentifier(const AstRawString* name, int pos, Scope* scope, AstNodeFactory* 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->length(), name->raw_data()); -#endif - Interface* interface = Interface::NewUnknown(parser_->zone()); - return scope->NewUnresolved(factory, name, interface, pos); + + // Arrow function parameters are parsed as an expression. When + // parsing lazily, it is enough to create a VariableProxy in order + // for Traits::DeclareArrowParametersFromExpression() to be able to + // pick the names of the parameters. + return parser_->parsing_lazy_arrow_parameters_ + ? factory->NewVariableProxy(name, false, pos) + : scope->NewUnresolved(factory, name, pos); } @@ -779,22 +781,29 @@ ClassLiteral* ParserTraits::ParseClassLiteral( } -Parser::Parser(CompilationInfo* info, ParseInfo* parse_info) - : ParserBase<ParserTraits>(&scanner_, parse_info->stack_limit, - info->extension(), NULL, info->zone(), this), - scanner_(parse_info->unicode_cache), +Parser::Parser(CompilationInfo* info, uintptr_t stack_limit, uint32_t hash_seed, + UnicodeCache* unicode_cache) + : ParserBase<ParserTraits>(info->zone(), &scanner_, stack_limit, + info->extension(), info->ast_value_factory(), + NULL, this), + scanner_(unicode_cache), reusable_preparser_(NULL), original_scope_(NULL), target_stack_(NULL), + compile_options_(info->compile_options()), cached_parse_data_(NULL), - info_(info), + parsing_lazy_arrow_parameters_(false), has_pending_error_(false), pending_error_message_(NULL), pending_error_arg_(NULL), pending_error_char_arg_(NULL), total_preparse_skipped_(0), - pre_parse_timer_(NULL) { - DCHECK(!script().is_null() || info->source_stream() != NULL); + pre_parse_timer_(NULL), + parsing_on_main_thread_(true) { + // Even though we were passed CompilationInfo, we should not store it in + // Parser - this makes sure that Isolate is not accidentally accessed via + // CompilationInfo during background parsing. + DCHECK(!info->script().is_null() || info->source_stream() != NULL); set_allow_lazy(false); // Must be explicitly enabled. set_allow_natives(FLAG_allow_natives_syntax || info->is_native()); set_allow_harmony_scoping(!info->is_native() && FLAG_harmony_scoping); @@ -806,27 +815,34 @@ Parser::Parser(CompilationInfo* info, ParseInfo* parse_info) set_allow_harmony_templates(FLAG_harmony_templates); set_allow_harmony_sloppy(FLAG_harmony_sloppy); set_allow_harmony_unicode(FLAG_harmony_unicode); + set_allow_harmony_computed_property_names( + FLAG_harmony_computed_property_names); + set_allow_harmony_rest_params(FLAG_harmony_rest_parameters); + set_allow_strong_mode(FLAG_strong_mode); for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount; ++feature) { use_counts_[feature] = 0; } if (info->ast_value_factory() == NULL) { // info takes ownership of AstValueFactory. - info->SetAstValueFactory( - new AstValueFactory(zone(), parse_info->hash_seed)); + info->SetAstValueFactory(new AstValueFactory(zone(), hash_seed)); + ast_value_factory_ = info->ast_value_factory(); } } -FunctionLiteral* Parser::ParseProgram() { +FunctionLiteral* Parser::ParseProgram(CompilationInfo* info) { // TODO(bmeurer): We temporarily need to pass allow_nesting = true here, // see comment for HistogramTimerScope class. - // It's OK to use the counters here, since this function is only called in - // the main thread. - HistogramTimerScope timer_scope(isolate()->counters()->parse(), true); - Handle<String> source(String::cast(script()->source())); - isolate()->counters()->total_parse_size()->Increment(source->length()); + // It's OK to use the Isolate & counters here, since this function is only + // called in the main thread. + DCHECK(parsing_on_main_thread_); + + Isolate* isolate = info->isolate(); + HistogramTimerScope timer_scope(isolate->counters()->parse(), true); + Handle<String> source(String::cast(info->script()->source())); + isolate->counters()->total_parse_size()->Increment(source->length()); base::ElapsedTimer timer; if (FLAG_trace_parse) { timer.Start(); @@ -854,24 +870,24 @@ FunctionLiteral* Parser::ParseProgram() { ExternalTwoByteStringUtf16CharacterStream stream( Handle<ExternalTwoByteString>::cast(source), 0, source->length()); scanner_.Initialize(&stream); - result = DoParseProgram(info(), &top_scope, &eval_scope); + result = DoParseProgram(info, &top_scope, &eval_scope); } else { GenericStringUtf16CharacterStream stream(source, 0, source->length()); scanner_.Initialize(&stream); - result = DoParseProgram(info(), &top_scope, &eval_scope); + result = DoParseProgram(info, &top_scope, &eval_scope); } top_scope->set_end_position(source->length()); if (eval_scope != NULL) { eval_scope->set_end_position(source->length()); } - HandleSourceURLComments(); + HandleSourceURLComments(info); if (FLAG_trace_parse && result != NULL) { double ms = timer.Elapsed().InMillisecondsF(); - if (info()->is_eval()) { + if (info->is_eval()) { PrintF("[parsing eval"); - } else if (info()->script()->name()->IsString()) { - String* name = String::cast(info()->script()->name()); + } else if (info->script()->name()->IsString()) { + String* name = String::cast(info->script()->name()); SmartArrayPointer<char> name_chars = name->ToCString(); PrintF("[parsing script: %s", name_chars.get()); } else { @@ -880,7 +896,7 @@ FunctionLiteral* Parser::ParseProgram() { PrintF(" - took %0.3f ms]\n", ms); } if (produce_cached_parse_data()) { - if (result != NULL) *info_->cached_data() = recorder.GetScriptData(); + if (result != NULL) *info->cached_data() = recorder.GetScriptData(); log_ = NULL; } return result; @@ -889,6 +905,9 @@ FunctionLiteral* Parser::ParseProgram() { FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, Scope** scope, Scope** eval_scope) { + // Note that this function can be called from the main thread or from a + // background thread. We should not access anything Isolate / heap dependent + // via CompilationInfo, and also not pass it forward. DCHECK(scope_ == NULL); DCHECK(target_stack_ == NULL); @@ -897,16 +916,18 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, Scope** scope, *scope = NewScope(scope_, SCRIPT_SCOPE); info->SetScriptScope(*scope); if (!info->context().is_null() && !info->context()->IsNativeContext()) { - *scope = Scope::DeserializeScopeChain(*info->context(), *scope, zone()); + *scope = Scope::DeserializeScopeChain(info->isolate(), zone(), + *info->context(), *scope); // The Scope is backed up by ScopeInfo (which is in the V8 heap); this // means the Parser cannot operate independent of the V8 heap. Tell the // string table to internalize strings and values right after they're - // created. - ast_value_factory()->Internalize(isolate()); + // created. This kind of parsing can only be done in the main thread. + DCHECK(parsing_on_main_thread_); + ast_value_factory()->Internalize(info->isolate()); } original_scope_ = *scope; if (info->is_eval()) { - if (!(*scope)->is_script_scope() || info->strict_mode() == STRICT) { + if (!(*scope)->is_script_scope() || is_strict(info->language_mode())) { *scope = NewScope(*scope, EVAL_SCOPE); } } else if (info->is_global()) { @@ -926,20 +947,27 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, Scope** scope, // Enters 'scope'. AstNodeFactory function_factory(ast_value_factory()); FunctionState function_state(&function_state_, &scope_, *scope, - &function_factory); + kNormalFunction, &function_factory); - scope_->SetStrictMode(info->strict_mode()); + scope_->SetLanguageMode(info->language_mode()); ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone()); bool ok = true; int beg_pos = scanner()->location().beg_pos; - ParseSourceElements(body, Token::EOS, info->is_eval(), true, eval_scope, - &ok); + if (info->is_module()) { + DCHECK(allow_harmony_modules()); + Statement* stmt = ParseModule(&ok); + if (ok) { + body->Add(stmt, zone()); + } + } else { + ParseStatementList(body, Token::EOS, info->is_eval(), eval_scope, &ok); + } - if (ok && strict_mode() == STRICT) { + if (ok && is_strict(language_mode())) { CheckStrictOctalLiteral(beg_pos, scanner()->location().end_pos, &ok); } - if (ok && allow_harmony_scoping() && strict_mode() == STRICT) { + if (ok && allow_harmony_scoping() && is_strict(language_mode())) { CheckConflictingVarDeclarations(scope_, &ok); } @@ -972,17 +1000,18 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, Scope** scope, } -FunctionLiteral* Parser::ParseLazy() { - // It's OK to use the counters here, since this function is only called in - // the main thread. - HistogramTimerScope timer_scope(isolate()->counters()->parse_lazy()); - Handle<String> source(String::cast(script()->source())); - isolate()->counters()->total_parse_size()->Increment(source->length()); +FunctionLiteral* Parser::ParseLazy(CompilationInfo* info) { + // It's OK to use the Isolate & counters here, since this function is only + // called in the main thread. + DCHECK(parsing_on_main_thread_); + HistogramTimerScope timer_scope(info->isolate()->counters()->parse_lazy()); + Handle<String> source(String::cast(info->script()->source())); + info->isolate()->counters()->total_parse_size()->Increment(source->length()); base::ElapsedTimer timer; if (FLAG_trace_parse) { timer.Start(); } - Handle<SharedFunctionInfo> shared_info = info()->shared_info(); + Handle<SharedFunctionInfo> shared_info = info->shared_info(); // Initialize parser state. source = String::Flatten(source); @@ -992,12 +1021,12 @@ FunctionLiteral* Parser::ParseLazy() { Handle<ExternalTwoByteString>::cast(source), shared_info->start_position(), shared_info->end_position()); - result = ParseLazy(&stream); + result = ParseLazy(info, &stream); } else { GenericStringUtf16CharacterStream stream(source, shared_info->start_position(), shared_info->end_position()); - result = ParseLazy(&stream); + result = ParseLazy(info, &stream); } if (FLAG_trace_parse && result != NULL) { @@ -1009,8 +1038,9 @@ FunctionLiteral* Parser::ParseLazy() { } -FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source) { - Handle<SharedFunctionInfo> shared_info = info()->shared_info(); +FunctionLiteral* Parser::ParseLazy(CompilationInfo* info, + Utf16CharacterStream* source) { + Handle<SharedFunctionInfo> shared_info = info->shared_info(); scanner_.Initialize(source); DCHECK(scope_ == NULL); DCHECK(target_stack_ == NULL); @@ -1029,18 +1059,22 @@ FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source) { { // Parse the function literal. Scope* scope = NewScope(scope_, SCRIPT_SCOPE); - info()->SetScriptScope(scope); - if (!info()->closure().is_null()) { - scope = Scope::DeserializeScopeChain(info()->closure()->context(), scope, - zone()); + info->SetScriptScope(scope); + if (!info->closure().is_null()) { + // Ok to use Isolate here, since lazy function parsing is only done in the + // main thread. + DCHECK(parsing_on_main_thread_); + scope = Scope::DeserializeScopeChain(info->isolate(), zone(), + info->closure()->context(), scope); } original_scope_ = scope; AstNodeFactory function_factory(ast_value_factory()); FunctionState function_state(&function_state_, &scope_, scope, - &function_factory); - DCHECK(scope->strict_mode() == SLOPPY || info()->strict_mode() == STRICT); - DCHECK(info()->strict_mode() == shared_info->strict_mode()); - scope->SetStrictMode(shared_info->strict_mode()); + shared_info->kind(), &function_factory); + DCHECK(is_sloppy(scope->language_mode()) || + is_strict(info->language_mode())); + DCHECK(info->language_mode() == shared_info->language_mode()); + scope->SetLanguageMode(shared_info->language_mode()); FunctionLiteral::FunctionType function_type = shared_info->is_expression() ? (shared_info->is_anonymous() ? FunctionLiteral::ANONYMOUS_EXPRESSION @@ -1049,11 +1083,15 @@ FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source) { bool ok = true; if (shared_info->is_arrow()) { + // The first expression being parsed is the parameter list of the arrow + // function. Setting this avoids prevents ExpressionFromIdentifier() + // from creating unresolved variables in already-resolved scopes. + parsing_lazy_arrow_parameters_ = true; Expression* expression = ParseExpression(false, &ok); DCHECK(expression->IsFunctionLiteral()); result = expression->AsFunctionLiteral(); } else if (shared_info->is_default_constructor()) { - result = DefaultConstructor(shared_info->uses_super_constructor_call(), + result = DefaultConstructor(IsSubclassConstructor(shared_info->kind()), scope, shared_info->start_position(), shared_info->end_position()); } else { @@ -1078,11 +1116,10 @@ FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source) { } -void* Parser::ParseSourceElements(ZoneList<Statement*>* processor, - int end_token, bool is_eval, bool is_global, - Scope** eval_scope, bool* ok) { - // SourceElements :: - // (ModuleElement)* <end_token> +void* Parser::ParseStatementList(ZoneList<Statement*>* body, int end_token, + bool is_eval, Scope** eval_scope, bool* ok) { + // StatementList :: + // (StatementListItem)* <end_token> // Allocate a target stack to use for this set of source // elements. This way, all scripts and functions get their own @@ -1090,7 +1127,7 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor, // functions. TargetScope scope(&this->target_stack_); - DCHECK(processor != NULL); + DCHECK(body != NULL); bool directive_prologue = true; // Parsing directive prologue. while (peek() != end_token) { @@ -1099,12 +1136,7 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor, } Scanner::Location token_loc = scanner()->peek_location(); - Statement* stat; - if (is_global && !is_eval) { - stat = ParseModuleElement(NULL, CHECK_OK); - } else { - stat = ParseBlockElement(NULL, CHECK_OK); - } + Statement* stat = ParseStatementListItem(CHECK_OK); if (stat == NULL || stat->IsEmpty()) { directive_prologue = false; // End of directive prologue. continue; @@ -1118,33 +1150,48 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor, if ((e_stat = stat->AsExpressionStatement()) != NULL && (literal = e_stat->expression()->AsLiteral()) != NULL && literal->raw_value()->IsString()) { - // Check "use strict" directive (ES5 14.1) and "use asm" directive. Only - // one can be present. - if (strict_mode() == SLOPPY && + // Check "use strict" directive (ES5 14.1), "use asm" directive, and + // "use strong" directive (experimental). + bool use_strict_found = literal->raw_value()->AsString() == ast_value_factory()->use_strict_string() && token_loc.end_pos - token_loc.beg_pos == - ast_value_factory()->use_strict_string()->length() + 2) { - // TODO(mstarzinger): Global strict eval calls, need their own scope - // as specified in ES5 10.4.2(3). The correct fix would be to always - // 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()) { - DCHECK(scope_->is_script_scope()); - Scope* scope = NewScope(scope_, EVAL_SCOPE); - scope->set_start_position(scope_->start_position()); - scope->set_end_position(scope_->end_position()); - scope_ = scope; - if (eval_scope != NULL) { - // Caller will correct the positions of the ad hoc eval scope. - *eval_scope = scope; + ast_value_factory()->use_strict_string()->length() + 2; + bool use_strong_found = + allow_strong_mode() && + literal->raw_value()->AsString() == + ast_value_factory()->use_strong_string() && + token_loc.end_pos - token_loc.beg_pos == + ast_value_factory()->use_strong_string()->length() + 2; + if (use_strict_found || use_strong_found) { + // Strong mode implies strict mode. If there are several "use strict" + // / "use strong" directives, do the strict mode changes only once. + if (is_sloppy(scope_->language_mode())) { + // TODO(mstarzinger): Global strict eval calls, need their own scope + // as specified in ES5 10.4.2(3). The correct fix would be to always + // 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()) { + DCHECK(scope_->is_script_scope()); + Scope* scope = NewScope(scope_, EVAL_SCOPE); + scope->set_start_position(scope_->start_position()); + scope->set_end_position(scope_->end_position()); + scope_ = scope; + if (eval_scope != NULL) { + // Caller will correct the positions of the ad hoc eval scope. + *eval_scope = scope; + } + mode_ = PARSE_EAGERLY; } - mode_ = PARSE_EAGERLY; + scope_->SetLanguageMode(static_cast<LanguageMode>( + scope_->language_mode() | STRICT_BIT)); + } + + if (use_strong_found) { + scope_->SetLanguageMode(static_cast<LanguageMode>( + scope_->language_mode() | STRONG_BIT)); } - scope_->SetStrictMode(STRICT); - // "use strict" is the only directive for now. - directive_prologue = false; } else if (literal->raw_value()->AsString() == ast_value_factory()->use_asm_string() && token_loc.end_pos - token_loc.beg_pos == @@ -1160,169 +1207,89 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor, } } - processor->Add(stat, zone()); + body->Add(stat, zone()); } return 0; } -Statement* Parser::ParseModuleElement(ZoneList<const AstRawString*>* labels, - bool* ok) { - // (Ecma 262 5th Edition, clause 14): - // SourceElement: +Statement* Parser::ParseStatementListItem(bool* ok) { + // (Ecma 262 6th Edition, 13.1): + // StatementListItem: // Statement - // FunctionDeclaration - // - // In harmony mode we allow additionally the following productions - // ModuleElement: - // LetDeclaration - // ConstDeclaration - // ModuleDeclaration - // ImportDeclaration - // ExportDeclaration - // GeneratorDeclaration + // Declaration switch (peek()) { case Token::FUNCTION: return ParseFunctionDeclaration(NULL, ok); case Token::CLASS: return ParseClassDeclaration(NULL, ok); - case Token::IMPORT: - return ParseImportDeclaration(ok); - case Token::EXPORT: - return ParseExportDeclaration(ok); case Token::CONST: - return ParseVariableStatement(kModuleElement, NULL, ok); + case Token::VAR: + return ParseVariableStatement(kStatementListItem, NULL, ok); case Token::LET: DCHECK(allow_harmony_scoping()); - if (strict_mode() == STRICT) { - return ParseVariableStatement(kModuleElement, NULL, ok); + if (is_strict(language_mode())) { + return ParseVariableStatement(kStatementListItem, NULL, ok); } // Fall through. - default: { - Statement* stmt = ParseStatement(labels, CHECK_OK); - // Handle 'module' as a context-sensitive keyword. - if (FLAG_harmony_modules && - peek() == Token::IDENTIFIER && - !scanner()->HasAnyLineTerminatorBeforeNext() && - stmt != NULL) { - ExpressionStatement* estmt = stmt->AsExpressionStatement(); - if (estmt != NULL && estmt->expression()->AsVariableProxy() != NULL && - estmt->expression()->AsVariableProxy()->raw_name() == - ast_value_factory()->module_string() && - !scanner()->literal_contains_escapes()) { - return ParseModuleDeclaration(NULL, ok); - } - } - return stmt; - } - } -} - - -Statement* Parser::ParseModuleDeclaration(ZoneList<const AstRawString*>* names, - bool* ok) { - // ModuleDeclaration: - // 'module' Identifier Module - - int pos = peek_position(); - const AstRawString* name = - ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK); - -#ifdef DEBUG - if (FLAG_print_interface_details) - PrintF("# Module %.*s ", name->length(), name->raw_data()); -#endif - - Module* module = ParseModule(CHECK_OK); - VariableProxy* proxy = NewUnresolved(name, MODULE, module->interface()); - Declaration* declaration = - factory()->NewModuleDeclaration(proxy, module, scope_, pos); - Declare(declaration, true, CHECK_OK); - -#ifdef DEBUG - if (FLAG_print_interface_details) - PrintF("# Module %.*s ", name->length(), name->raw_data()); - if (FLAG_print_interfaces) { - PrintF("module %.*s: ", name->length(), name->raw_data()); - module->interface()->Print(); + default: + return ParseStatement(NULL, ok); } -#endif - - if (names) names->Add(name, zone()); - if (module->body() == NULL) - return factory()->NewEmptyStatement(pos); - else - return factory()->NewModuleStatement(proxy, module->body(), pos); } -Module* Parser::ParseModule(bool* ok) { - // Module: - // '{' ModuleElement '}' - // '=' ModulePath ';' - // 'at' String ';' +Statement* Parser::ParseModuleItem(bool* ok) { + // (Ecma 262 6th Edition, 15.2): + // ModuleItem : + // ImportDeclaration + // ExportDeclaration + // StatementListItem switch (peek()) { - case Token::LBRACE: - return ParseModuleLiteral(ok); - - case Token::ASSIGN: { - Expect(Token::ASSIGN, CHECK_OK); - Module* result = ParseModulePath(CHECK_OK); - ExpectSemicolon(CHECK_OK); - return result; - } - - default: { - ExpectContextualKeyword(CStrVector("at"), CHECK_OK); - Module* result = ParseModuleUrl(CHECK_OK); - ExpectSemicolon(CHECK_OK); - return result; - } + case Token::IMPORT: + return ParseImportDeclaration(ok); + case Token::EXPORT: + return ParseExportDeclaration(ok); + default: + return ParseStatementListItem(ok); } } -Module* Parser::ParseModuleLiteral(bool* ok) { - // Module: - // '{' ModuleElement '}' +Statement* Parser::ParseModule(bool* ok) { + // (Ecma 262 6th Edition, 15.2): + // Module : + // ModuleBody? + // + // ModuleBody : + // ModuleItem* - int pos = peek_position(); - // Construct block expecting 16 statements. Block* body = factory()->NewBlock(NULL, 16, false, RelocInfo::kNoPosition); -#ifdef DEBUG - if (FLAG_print_interface_details) PrintF("# Literal "); -#endif Scope* scope = NewScope(scope_, MODULE_SCOPE); - - Expect(Token::LBRACE, CHECK_OK); scope->set_start_position(scanner()->location().beg_pos); - scope->SetStrictMode(STRICT); + scope->SetLanguageMode( + static_cast<LanguageMode>(scope->language_mode() | STRICT_BIT)); { BlockState block_state(&scope_, scope); - TargetCollector collector(zone()); - Target target(&this->target_stack_, &collector); - Target target_body(&this->target_stack_, body); - while (peek() != Token::RBRACE) { - Statement* stat = ParseModuleElement(NULL, CHECK_OK); + while (peek() != Token::EOS) { + Statement* stat = ParseModuleItem(CHECK_OK); if (stat && !stat->IsEmpty()) { body->AddStatement(stat, zone()); } } } - Expect(Token::RBRACE, CHECK_OK); scope->set_end_position(scanner()->location().end_pos); body->set_scope(scope); // Check that all exports are bound. - Interface* interface = scope->interface(); - for (Interface::Iterator it = interface->iterator(); - !it.done(); it.Advance()) { + ModuleDescriptor* descriptor = scope->module(); + for (ModuleDescriptor::Iterator it = descriptor->iterator(); !it.done(); + it.Advance()) { if (scope->LookupLocal(it.name()) == NULL) { ParserTraits::ReportMessage("module_export_undefined", it.name()); *ok = false; @@ -1330,196 +1297,284 @@ Module* Parser::ParseModuleLiteral(bool* ok) { } } - interface->MakeModule(ok); - DCHECK(*ok); - interface->Freeze(ok); - DCHECK(*ok); - return factory()->NewModuleLiteral(body, interface, pos); + scope->module()->Freeze(); + return body; } -Module* Parser::ParseModulePath(bool* ok) { - // ModulePath: - // Identifier - // ModulePath '.' Identifier +Literal* Parser::ParseModuleSpecifier(bool* ok) { + // ModuleSpecifier : + // StringLiteral int pos = peek_position(); - Module* result = ParseModuleVariable(CHECK_OK); - while (Check(Token::PERIOD)) { - const AstRawString* name = ParseIdentifierName(CHECK_OK); -#ifdef DEBUG - if (FLAG_print_interface_details) - PrintF("# Path .%.*s ", name->length(), name->raw_data()); -#endif - Module* member = factory()->NewModulePath(result, name, pos); - result->interface()->Add(name, member->interface(), zone(), ok); - if (!*ok) { -#ifdef DEBUG - if (FLAG_print_interfaces) { - PrintF("PATH TYPE ERROR at '%.*s'\n", name->length(), name->raw_data()); - PrintF("result: "); - result->interface()->Print(); - PrintF("member: "); - member->interface()->Print(); - } -#endif - ParserTraits::ReportMessage("invalid_module_path", name); - return NULL; - } - result = member; - } - - return result; + Expect(Token::STRING, CHECK_OK); + return factory()->NewStringLiteral(GetSymbol(scanner()), pos); } -Module* Parser::ParseModuleVariable(bool* ok) { - // ModulePath: - // Identifier - - int pos = peek_position(); - const AstRawString* name = - ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK); -#ifdef DEBUG - if (FLAG_print_interface_details) - PrintF("# Module variable %.*s ", name->length(), name->raw_data()); -#endif - VariableProxy* proxy = scope_->NewUnresolved( - factory(), name, Interface::NewModule(zone()), - scanner()->location().beg_pos); +void* Parser::ParseExportClause(ZoneList<const AstRawString*>* names, + Scanner::Location* reserved_loc, bool* ok) { + // ExportClause : + // '{' '}' + // '{' ExportsList '}' + // '{' ExportsList ',' '}' + // + // ExportsList : + // ExportSpecifier + // ExportsList ',' ExportSpecifier + // + // ExportSpecifier : + // IdentifierName + // IdentifierName 'as' IdentifierName - return factory()->NewModuleVariable(proxy, pos); -} + Expect(Token::LBRACE, CHECK_OK); + Token::Value name_tok; + while ((name_tok = peek()) != Token::RBRACE) { + // Keep track of the first reserved word encountered in case our + // caller needs to report an error. + if (!reserved_loc->IsValid() && + !Token::IsIdentifier(name_tok, STRICT, false)) { + *reserved_loc = scanner()->location(); + } + const AstRawString* name = ParseIdentifierName(CHECK_OK); + names->Add(name, zone()); + const AstRawString* export_name = NULL; + if (CheckContextualKeyword(CStrVector("as"))) { + export_name = ParseIdentifierName(CHECK_OK); + } + // TODO(ES6): Return the export_name as well as the name. + USE(export_name); + if (peek() == Token::RBRACE) break; + Expect(Token::COMMA, CHECK_OK); + } -Module* Parser::ParseModuleUrl(bool* ok) { - // Module: - // String + Expect(Token::RBRACE, CHECK_OK); - int pos = peek_position(); - Expect(Token::STRING, CHECK_OK); - const AstRawString* symbol = GetSymbol(scanner()); + return 0; +} - // TODO(ES6): Request JS resource from environment... -#ifdef DEBUG - if (FLAG_print_interface_details) PrintF("# Url "); -#endif +void* Parser::ParseNamedImports(ZoneList<const AstRawString*>* names, + bool* ok) { + // NamedImports : + // '{' '}' + // '{' ImportsList '}' + // '{' ImportsList ',' '}' + // + // ImportsList : + // ImportSpecifier + // ImportsList ',' ImportSpecifier + // + // ImportSpecifier : + // BindingIdentifier + // IdentifierName 'as' BindingIdentifier - // Create an empty literal as long as the feature isn't finished. - USE(symbol); - Scope* scope = NewScope(scope_, MODULE_SCOPE); - Block* body = factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition); - body->set_scope(scope); - Interface* interface = scope->interface(); - Module* result = factory()->NewModuleLiteral(body, interface, pos); - interface->Freeze(ok); - DCHECK(*ok); - interface->Unify(scope->interface(), zone(), ok); - DCHECK(*ok); - return result; -} + Expect(Token::LBRACE, CHECK_OK); + Token::Value name_tok; + while ((name_tok = peek()) != Token::RBRACE) { + const AstRawString* name = ParseIdentifierName(CHECK_OK); + const AstRawString* import_name = NULL; + // In the presence of 'as', the left-side of the 'as' can + // be any IdentifierName. But without 'as', it must be a valid + // BindingIdentiifer. + if (CheckContextualKeyword(CStrVector("as"))) { + import_name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK); + } else if (!Token::IsIdentifier(name_tok, STRICT, false)) { + *ok = false; + ReportMessageAt(scanner()->location(), "unexpected_reserved"); + return NULL; + } else if (IsEvalOrArguments(name)) { + *ok = false; + ReportMessageAt(scanner()->location(), "strict_eval_arguments"); + return NULL; + } + // TODO(ES6): Return the import_name as well as the name. + names->Add(name, zone()); + USE(import_name); + if (peek() == Token::RBRACE) break; + Expect(Token::COMMA, CHECK_OK); + } -Module* Parser::ParseModuleSpecifier(bool* ok) { - // ModuleSpecifier: - // String - // ModulePath + Expect(Token::RBRACE, CHECK_OK); - if (peek() == Token::STRING) { - return ParseModuleUrl(ok); - } else { - return ParseModulePath(ok); - } + return NULL; } -Block* Parser::ParseImportDeclaration(bool* ok) { - // ImportDeclaration: - // 'import' IdentifierName (',' IdentifierName)* 'from' ModuleSpecifier ';' +Statement* Parser::ParseImportDeclaration(bool* ok) { + // ImportDeclaration : + // 'import' ImportClause 'from' ModuleSpecifier ';' + // 'import' ModuleSpecifier ';' + // + // ImportClause : + // NameSpaceImport + // NamedImports + // ImportedDefaultBinding + // ImportedDefaultBinding ',' NameSpaceImport + // ImportedDefaultBinding ',' NamedImports // - // TODO(ES6): implement destructuring ImportSpecifiers + // NameSpaceImport : + // '*' 'as' ImportedBinding int pos = peek_position(); Expect(Token::IMPORT, CHECK_OK); + + Token::Value tok = peek(); + + // 'import' ModuleSpecifier ';' + if (tok == Token::STRING) { + ParseModuleSpecifier(CHECK_OK); + ExpectSemicolon(CHECK_OK); + return factory()->NewEmptyStatement(pos); + } + + // Parse ImportedDefaultBinding if present. + const AstRawString* imported_default_binding = NULL; + if (tok != Token::MUL && tok != Token::LBRACE) { + imported_default_binding = + ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK); + } + + const AstRawString* module_instance_binding = NULL; ZoneList<const AstRawString*> names(1, zone()); + if (imported_default_binding == NULL || Check(Token::COMMA)) { + switch (peek()) { + case Token::MUL: { + Consume(Token::MUL); + ExpectContextualKeyword(CStrVector("as"), CHECK_OK); + module_instance_binding = + ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK); + break; + } - const AstRawString* name = ParseIdentifierName(CHECK_OK); - names.Add(name, zone()); - while (peek() == Token::COMMA) { - Consume(Token::COMMA); - name = ParseIdentifierName(CHECK_OK); - names.Add(name, zone()); + case Token::LBRACE: + ParseNamedImports(&names, CHECK_OK); + break; + + default: + *ok = false; + ReportUnexpectedToken(scanner()->current_token()); + return NULL; + } } ExpectContextualKeyword(CStrVector("from"), CHECK_OK); - Module* module = ParseModuleSpecifier(CHECK_OK); + Literal* module = ParseModuleSpecifier(CHECK_OK); + USE(module); + ExpectSemicolon(CHECK_OK); - // Generate a separate declaration for each identifier. - // TODO(ES6): once we implement destructuring, make that one declaration. - Block* block = factory()->NewBlock(NULL, 1, true, RelocInfo::kNoPosition); + if (module_instance_binding != NULL) { + // TODO(ES6): Bind name to the Module Instance Object of module. + } + + if (imported_default_binding != NULL) { + // TODO(ES6): Add an appropriate declaration. + } + for (int i = 0; i < names.length(); ++i) { -#ifdef DEBUG - if (FLAG_print_interface_details) - PrintF("# Import %.*s ", name->length(), name->raw_data()); -#endif - Interface* interface = Interface::NewUnknown(zone()); - module->interface()->Add(names[i], interface, zone(), ok); - if (!*ok) { -#ifdef DEBUG - if (FLAG_print_interfaces) { - PrintF("IMPORT TYPE ERROR at '%.*s'\n", name->length(), - name->raw_data()); - PrintF("module: "); - module->interface()->Print(); - } -#endif - ParserTraits::ReportMessage("invalid_module_path", name); - return NULL; + // TODO(ES6): Add an appropriate declaration for each name + } + + return factory()->NewEmptyStatement(pos); +} + + +Statement* Parser::ParseExportDefault(bool* ok) { + // Supports the following productions, starting after the 'default' token: + // 'export' 'default' FunctionDeclaration + // 'export' 'default' ClassDeclaration + // 'export' 'default' AssignmentExpression[In] ';' + + Statement* result = NULL; + switch (peek()) { + case Token::FUNCTION: + // TODO(ES6): Support parsing anonymous function declarations here. + result = ParseFunctionDeclaration(NULL, CHECK_OK); + break; + + case Token::CLASS: + // TODO(ES6): Support parsing anonymous class declarations here. + result = ParseClassDeclaration(NULL, CHECK_OK); + break; + + default: { + int pos = peek_position(); + Expression* expr = ParseAssignmentExpression(true, CHECK_OK); + ExpectSemicolon(CHECK_OK); + result = factory()->NewExpressionStatement(expr, pos); + break; } - VariableProxy* proxy = NewUnresolved(names[i], LET, interface); - Declaration* declaration = - factory()->NewImportDeclaration(proxy, module, scope_, pos); - Declare(declaration, true, CHECK_OK); } - return block; + // TODO(ES6): Add default export to scope_->module() + + return result; } Statement* Parser::ParseExportDeclaration(bool* ok) { // ExportDeclaration: - // 'export' Identifier (',' Identifier)* ';' - // 'export' VariableDeclaration - // 'export' FunctionDeclaration - // 'export' GeneratorDeclaration - // 'export' ModuleDeclaration - // - // TODO(ES6): implement structuring ExportSpecifiers + // 'export' '*' 'from' ModuleSpecifier ';' + // 'export' ExportClause ('from' ModuleSpecifier)? ';' + // 'export' VariableStatement + // 'export' Declaration + // 'export' 'default' ... (handled in ParseExportDefault) + int pos = peek_position(); Expect(Token::EXPORT, CHECK_OK); Statement* result = NULL; ZoneList<const AstRawString*> names(1, zone()); + bool is_export_from = false; switch (peek()) { - case Token::IDENTIFIER: { - int pos = position(); - const AstRawString* name = - ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK); - // Handle 'module' as a context-sensitive keyword. - if (name != ast_value_factory()->module_string()) { - names.Add(name, zone()); - while (peek() == Token::COMMA) { - Consume(Token::COMMA); - name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK); - names.Add(name, zone()); - } - ExpectSemicolon(CHECK_OK); - result = factory()->NewEmptyStatement(pos); - } else { - result = ParseModuleDeclaration(&names, CHECK_OK); + case Token::DEFAULT: + Consume(Token::DEFAULT); + return ParseExportDefault(ok); + + case Token::MUL: { + Consume(Token::MUL); + ExpectContextualKeyword(CStrVector("from"), CHECK_OK); + Literal* module = ParseModuleSpecifier(CHECK_OK); + ExpectSemicolon(CHECK_OK); + // TODO(ES6): Do something with the return value + // of ParseModuleSpecifier. + USE(module); + is_export_from = true; + result = factory()->NewEmptyStatement(pos); + break; + } + + case Token::LBRACE: { + // There are two cases here: + // + // 'export' ExportClause ';' + // and + // 'export' ExportClause FromClause ';' + // + // In the first case, the exported identifiers in ExportClause must + // not be reserved words, while in the latter they may be. We + // pass in a location that gets filled with the first reserved word + // encountered, and then throw a SyntaxError if we are in the + // non-FromClause case. + Scanner::Location reserved_loc = Scanner::Location::invalid(); + ParseExportClause(&names, &reserved_loc, CHECK_OK); + if (CheckContextualKeyword(CStrVector("from"))) { + Literal* module = ParseModuleSpecifier(CHECK_OK); + // TODO(ES6): Do something with the return value + // of ParseModuleSpecifier. + USE(module); + is_export_from = true; + } else if (reserved_loc.IsValid()) { + // No FromClause, so reserved words are invalid in ExportClause. + *ok = false; + ReportMessageAt(reserved_loc, "unexpected_reserved"); + return NULL; } + ExpectSemicolon(CHECK_OK); + result = factory()->NewEmptyStatement(pos); break; } @@ -1534,7 +1589,7 @@ Statement* Parser::ParseExportDeclaration(bool* ok) { case Token::VAR: case Token::LET: case Token::CONST: - result = ParseVariableStatement(kModuleElement, &names, CHECK_OK); + result = ParseVariableStatement(kStatementListItem, &names, CHECK_OK); break; default: @@ -1556,24 +1611,21 @@ Statement* Parser::ParseExportDeclaration(bool* ok) { } } - // Extract declared names into export declarations and interface. - Interface* interface = scope_->interface(); - for (int i = 0; i < names.length(); ++i) { -#ifdef DEBUG - if (FLAG_print_interface_details) - PrintF("# Export %.*s ", names[i]->length(), names[i]->raw_data()); -#endif - Interface* inner = Interface::NewUnknown(zone()); - interface->Add(names[i], inner, zone(), CHECK_OK); - if (!*ok) - return NULL; - VariableProxy* proxy = NewUnresolved(names[i], LET, inner); - USE(proxy); - // TODO(rossberg): Rethink whether we actually need to store export - // declarations (for compilation?). - // ExportDeclaration* declaration = - // factory()->NewExportDeclaration(proxy, scope_, position); - // scope_->AddDeclaration(declaration); + // TODO(ES6): Handle 'export from' once imports are properly implemented. + // For now we just drop such exports on the floor. + if (!is_export_from) { + // Extract declared names into export declarations and module descriptor. + ModuleDescriptor* descriptor = scope_->module(); + for (int i = 0; i < names.length(); ++i) { + // TODO(adamk): Make early errors here provide the right error message + // (duplicate exported names). + descriptor->Add(names[i], zone(), CHECK_OK); + // TODO(rossberg): Rethink whether we actually need to store export + // declarations (for compilation?). + // ExportDeclaration* declaration = + // factory()->NewExportDeclaration(proxy, scope_, position); + // scope_->AddDeclaration(declaration); + } } DCHECK(result != NULL); @@ -1581,41 +1633,22 @@ Statement* Parser::ParseExportDeclaration(bool* ok) { } -Statement* Parser::ParseBlockElement(ZoneList<const AstRawString*>* labels, - bool* ok) { - // (Ecma 262 5th Edition, clause 14): - // SourceElement: - // Statement - // FunctionDeclaration - // - // In harmony mode we allow additionally the following productions - // BlockElement (aka SourceElement): - // LetDeclaration - // ConstDeclaration - // GeneratorDeclaration - // ClassDeclaration +Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels, + bool* ok) { + // Statement :: + // EmptyStatement + // ... - switch (peek()) { - case Token::FUNCTION: - return ParseFunctionDeclaration(NULL, ok); - case Token::CLASS: - return ParseClassDeclaration(NULL, ok); - case Token::CONST: - return ParseVariableStatement(kModuleElement, NULL, ok); - case Token::LET: - DCHECK(allow_harmony_scoping()); - if (strict_mode() == STRICT) { - return ParseVariableStatement(kModuleElement, NULL, ok); - } - // Fall through. - default: - return ParseStatement(labels, ok); + if (peek() == Token::SEMICOLON) { + Next(); + return factory()->NewEmptyStatement(RelocInfo::kNoPosition); } + return ParseSubStatement(labels, ok); } -Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels, - bool* ok) { +Statement* Parser::ParseSubStatement(ZoneList<const AstRawString*>* labels, + bool* ok) { // Statement :: // Block // VariableStatement @@ -1644,6 +1677,11 @@ Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels, return ParseBlock(labels, ok); case Token::SEMICOLON: + if (is_strong(language_mode())) { + ReportMessageAt(scanner()->peek_location(), "strong_empty"); + *ok = false; + return NULL; + } Next(); return factory()->NewEmptyStatement(RelocInfo::kNoPosition); @@ -1703,7 +1741,7 @@ Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels, // In Harmony mode, this case also handles the extension: // Statement: // GeneratorDeclaration - if (strict_mode() == STRICT) { + if (is_strict(language_mode())) { ReportMessageAt(scanner()->peek_location(), "strict_function"); *ok = false; return NULL; @@ -1711,22 +1749,21 @@ Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels, return ParseFunctionDeclaration(NULL, ok); } - case Token::CLASS: - return ParseClassDeclaration(NULL, ok); - case Token::DEBUGGER: return ParseDebuggerStatement(ok); case Token::VAR: - case Token::CONST: return ParseVariableStatement(kStatement, NULL, ok); - case Token::LET: - DCHECK(allow_harmony_scoping()); - if (strict_mode() == STRICT) { + case Token::CONST: + // In ES6 CONST is not allowed as a Statement, only as a + // LexicalDeclaration, however we continue to allow it in sloppy mode for + // backwards compatibility. + if (is_sloppy(language_mode())) { return ParseVariableStatement(kStatement, NULL, ok); } - // Fall through. + + // Fall through. default: return ParseExpressionOrLabelledStatement(labels, ok); } @@ -1734,14 +1771,13 @@ Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels, VariableProxy* Parser::NewUnresolved(const AstRawString* name, - VariableMode mode, Interface* interface) { + VariableMode mode) { // If we are inside a function, a declaration of a var/const variable is a // truly local variable, and the scope of the variable is always the function // scope. // Let/const variables in harmony mode are always added to the immediately // enclosing scope. - return DeclarationScope(mode)->NewUnresolved( - factory(), name, interface, position()); + return DeclarationScope(mode)->NewUnresolved(factory(), name, position()); } @@ -1770,9 +1806,8 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) { var = declaration_scope->LookupLocal(name); if (var == NULL) { // Declare the name. - var = declaration_scope->DeclareLocal(name, mode, - declaration->initialization(), - kNotAssigned, proxy->interface()); + var = declaration_scope->DeclareLocal( + name, mode, declaration->initialization(), kNotAssigned); } else if (IsLexicalVariableMode(mode) || IsLexicalVariableMode(var->mode()) || ((mode == CONST_LEGACY || var->mode() == CONST_LEGACY) && !declaration_scope->is_script_scope())) { @@ -1790,7 +1825,7 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) { // because the var declaration is hoisted to the function scope where 'x' // is already bound. DCHECK(IsDeclaredVariableMode(var->mode())); - if (allow_harmony_scoping() && strict_mode() == STRICT) { + if (allow_harmony_scoping() && is_strict(language_mode())) { // In harmony we treat re-declarations as early errors. See // ES5 16 for a definition of early errors. ParserTraits::ReportMessage("var_redeclaration", name); @@ -1827,19 +1862,17 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) { // For global const variables we bind the proxy to a variable. DCHECK(resolve); // should be set by all callers Variable::Kind kind = Variable::NORMAL; - var = new (zone()) - Variable(declaration_scope, name, mode, true, kind, - kNeedsInitialization, kNotAssigned, proxy->interface()); + var = new (zone()) Variable(declaration_scope, name, mode, true, kind, + kNeedsInitialization, kNotAssigned); } else if (declaration_scope->is_eval_scope() && - declaration_scope->strict_mode() == SLOPPY) { + is_sloppy(declaration_scope->language_mode())) { // For variable declarations in a sloppy eval scope the proxy is bound // to a lookup variable to force a dynamic declaration using the // DeclareLookupSlot runtime function. Variable::Kind kind = Variable::NORMAL; // TODO(sigurds) figure out if kNotAssigned is OK here var = new (zone()) Variable(declaration_scope, name, mode, true, kind, - declaration->initialization(), kNotAssigned, - proxy->interface()); + declaration->initialization(), kNotAssigned); var->AllocateTo(Variable::LOOKUP, -1); resolve = true; } @@ -1870,29 +1903,6 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) { // runtime needs to provide both. if (resolve && var != NULL) { proxy->BindTo(var); - - if (FLAG_harmony_modules) { - bool ok; -#ifdef DEBUG - if (FLAG_print_interface_details) { - PrintF("# Declare %.*s ", var->raw_name()->length(), - var->raw_name()->raw_data()); - } -#endif - proxy->interface()->Unify(var->interface(), zone(), &ok); - if (!ok) { -#ifdef DEBUG - if (FLAG_print_interfaces) { - PrintF("DECLARE TYPE ERROR\n"); - PrintF("proxy: "); - proxy->interface()->Print(); - PrintF("var: "); - var->interface()->Print(); - } -#endif - ParserTraits::ReportMessage("module_type_error", name); - } - } } } @@ -1927,7 +1937,7 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) { // TODO(1240846): It's weird that native function declarations are // introduced dynamically when we meet their declarations, whereas // other functions are set up when entering the surrounding scope. - VariableProxy* proxy = NewUnresolved(name, VAR, Interface::NewValue()); + VariableProxy* proxy = NewUnresolved(name, VAR); Declaration* declaration = factory()->NewVariableDeclaration(proxy, VAR, scope_, pos); Declare(declaration, true, CHECK_OK); @@ -1965,10 +1975,13 @@ Statement* Parser::ParseFunctionDeclaration( // In ES6, a function behaves as a lexical binding, except in // a script scope, or the initial scope of eval or another function. VariableMode mode = - allow_harmony_scoping() && strict_mode() == STRICT && - !(scope_->is_script_scope() || scope_->is_eval_scope() || - scope_->is_function_scope()) ? LET : VAR; - VariableProxy* proxy = NewUnresolved(name, mode, Interface::NewValue()); + is_strong(language_mode()) ? CONST : + allow_harmony_scoping() && is_strict(language_mode()) && + !(scope_->is_script_scope() || scope_->is_eval_scope() || + scope_->is_function_scope()) + ? LET + : VAR; + VariableProxy* proxy = NewUnresolved(name, mode); Declaration* declaration = factory()->NewFunctionDeclaration(proxy, mode, fun, scope_, pos); Declare(declaration, true, CHECK_OK); @@ -1993,7 +2006,7 @@ Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names, // so rewrite it as such. Expect(Token::CLASS, CHECK_OK); - if (!allow_harmony_sloppy() && strict_mode() == SLOPPY) { + if (!allow_harmony_sloppy() && is_sloppy(language_mode())) { ReportMessage("sloppy_lexical"); *ok = false; return NULL; @@ -2006,13 +2019,15 @@ Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names, ClassLiteral* value = ParseClassLiteral(name, scanner()->location(), is_strict_reserved, pos, CHECK_OK); - VariableProxy* proxy = NewUnresolved(name, LET, Interface::NewValue()); + VariableMode mode = is_strong(language_mode()) ? CONST : LET; + VariableProxy* proxy = NewUnresolved(name, mode); Declaration* declaration = - factory()->NewVariableDeclaration(proxy, LET, scope_, pos); + factory()->NewVariableDeclaration(proxy, mode, scope_, pos); Declare(declaration, true, CHECK_OK); proxy->var()->set_initializer_position(pos); - Token::Value init_op = Token::INIT_LET; + Token::Value init_op = + is_strong(language_mode()) ? Token::INIT_CONST : Token::INIT_LET; Assignment* assignment = factory()->NewAssignment(init_op, proxy, value, pos); Statement* assignment_statement = factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition); @@ -2022,7 +2037,7 @@ Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names, Block* Parser::ParseBlock(ZoneList<const AstRawString*>* labels, bool* ok) { - if (allow_harmony_scoping() && strict_mode() == STRICT) { + if (allow_harmony_scoping() && is_strict(language_mode())) { return ParseScopedBlock(labels, ok); } @@ -2053,7 +2068,7 @@ Block* Parser::ParseScopedBlock(ZoneList<const AstRawString*>* labels, // The harmony mode uses block elements instead of statements. // // Block :: - // '{' BlockElement* '}' + // '{' StatementList '}' // Construct block expecting 16 statements. Block* body = @@ -2064,12 +2079,10 @@ Block* Parser::ParseScopedBlock(ZoneList<const AstRawString*>* labels, Expect(Token::LBRACE, CHECK_OK); block_scope->set_start_position(scanner()->location().beg_pos); { BlockState block_state(&scope_, block_scope); - TargetCollector collector(zone()); - Target target(&this->target_stack_, &collector); - Target target_body(&this->target_stack_, body); + Target target(&this->target_stack_, body); while (peek() != Token::RBRACE) { - Statement* stat = ParseBlockElement(NULL, CHECK_OK); + Statement* stat = ParseStatementListItem(CHECK_OK); if (stat && !stat->IsEmpty()) { body->AddStatement(stat, zone()); } @@ -2132,52 +2145,35 @@ Block* Parser::ParseVariableDeclarations( bool is_const = false; Token::Value init_op = Token::INIT_VAR; if (peek() == Token::VAR) { + if (is_strong(language_mode())) { + Scanner::Location location = scanner()->peek_location(); + ReportMessageAt(location, "strong_var"); + *ok = false; + return NULL; + } Consume(Token::VAR); } else if (peek() == Token::CONST) { - // TODO(ES6): The ES6 Draft Rev4 section 12.2.2 reads: - // - // ConstDeclaration : const ConstBinding (',' ConstBinding)* ';' - // - // * It is a Syntax Error if the code that matches this production is not - // contained in extended code. - // - // However disallowing const in sloppy mode will break compatibility with - // existing pages. Therefore we keep allowing const with the old - // non-harmony semantics in sloppy mode. Consume(Token::CONST); - switch (strict_mode()) { - case SLOPPY: - mode = CONST_LEGACY; - init_op = Token::INIT_CONST_LEGACY; - break; - case STRICT: - if (allow_harmony_scoping()) { - if (var_context == kStatement) { - // In strict mode 'const' declarations are only allowed in source - // element positions. - ReportMessage("unprotected_const"); - *ok = false; - return NULL; - } - mode = CONST; - init_op = Token::INIT_CONST; - } else { - ReportMessage("strict_const"); - *ok = false; - return NULL; - } + if (is_sloppy(language_mode())) { + mode = CONST_LEGACY; + init_op = Token::INIT_CONST_LEGACY; + } else { + DCHECK(var_context != kStatement); + // In ES5 const is not allowed in strict mode. + if (!allow_harmony_scoping()) { + ReportMessage("strict_const"); + *ok = false; + return NULL; + } + mode = CONST; + init_op = Token::INIT_CONST; } is_const = true; needs_init = true; - } else if (peek() == Token::LET && strict_mode() == STRICT) { + } else if (peek() == Token::LET && is_strict(language_mode())) { DCHECK(allow_harmony_scoping()); Consume(Token::LET); - if (var_context == kStatement) { - // Let declarations are only allowed in source element positions. - ReportMessage("unprotected_let"); - *ok = false; - return NULL; - } + DCHECK(var_context != kStatement); mode = LET; needs_init = true; init_op = Token::INIT_LET; @@ -2234,9 +2230,7 @@ Block* Parser::ParseVariableDeclarations( needs_init = false; } - Interface* interface = - is_const ? Interface::NewConst() : Interface::NewValue(); - VariableProxy* proxy = NewUnresolved(name, mode, interface); + VariableProxy* proxy = NewUnresolved(name, mode); Declaration* declaration = factory()->NewVariableDeclaration(proxy, mode, scope_, pos); Declare(declaration, mode != VAR, CHECK_OK); @@ -2345,10 +2339,10 @@ Block* Parser::ParseVariableDeclarations( Runtime::FunctionForId(Runtime::kInitializeConstGlobal), arguments, pos); } else { - // Add strict mode. + // Add language mode. // We may want to pass singleton to avoid Literal allocations. - StrictMode strict_mode = initialization_scope->strict_mode(); - arguments->Add(factory()->NewNumberLiteral(strict_mode, pos), zone()); + LanguageMode language_mode = initialization_scope->language_mode(); + arguments->Add(factory()->NewNumberLiteral(language_mode, pos), zone()); // Be careful not to assign a value to the global variable if // we're in a with. The initialization value should not @@ -2400,7 +2394,7 @@ Block* Parser::ParseVariableDeclarations( // if they are inside a 'with' statement - they may change a 'with' object // property). VariableProxy* proxy = - initialization_scope->NewUnresolved(factory(), name, interface); + initialization_scope->NewUnresolved(factory(), name); Assignment* assignment = factory()->NewAssignment(init_op, proxy, value, pos); block->AddStatement( @@ -2440,6 +2434,26 @@ Statement* Parser::ParseExpressionOrLabelledStatement( // ExpressionStatement | LabelledStatement :: // Expression ';' // Identifier ':' Statement + // + // ExpressionStatement[Yield] : + // [lookahead ∉ {{, function, class, let [}] Expression[In, ?Yield] ; + + switch (peek()) { + case Token::FUNCTION: + case Token::LBRACE: + UNREACHABLE(); // Always handled by the callers. + case Token::CLASS: + ReportUnexpectedToken(Next()); + *ok = false; + return nullptr; + + // TODO(arv): Handle `let [` + // https://code.google.com/p/v8/issues/detail?id=3847 + + default: + break; + } + int pos = peek_position(); bool starts_with_idenfifier = peek_any_identifier(); Expression* expr = ParseExpression(true, CHECK_OK); @@ -2484,24 +2498,16 @@ Statement* Parser::ParseExpressionOrLabelledStatement( return ParseNativeDeclaration(ok); } - // Parsed expression statement, or the context-sensitive 'module' keyword. - // Only expect semicolon in the former case. - // Also detect attempts at 'let' declarations in sloppy mode. - if (!FLAG_harmony_modules || peek() != Token::IDENTIFIER || - scanner()->HasAnyLineTerminatorBeforeNext() || - expr->AsVariableProxy() == NULL || - expr->AsVariableProxy()->raw_name() != - ast_value_factory()->module_string() || - scanner()->literal_contains_escapes()) { - if (peek() == Token::IDENTIFIER && expr->AsVariableProxy() != NULL && - expr->AsVariableProxy()->raw_name() == - ast_value_factory()->let_string()) { - ReportMessage("sloppy_lexical", NULL); - *ok = false; - return NULL; - } - ExpectSemicolon(CHECK_OK); + // Parsed expression statement, followed by semicolon. + // Detect attempts at 'let' declarations in sloppy mode. + if (peek() == Token::IDENTIFIER && expr->AsVariableProxy() != NULL && + expr->AsVariableProxy()->raw_name() == + ast_value_factory()->let_string()) { + ReportMessage("sloppy_lexical", NULL); + *ok = false; + return NULL; } + ExpectSemicolon(CHECK_OK); return factory()->NewExpressionStatement(expr, pos); } @@ -2516,11 +2522,11 @@ IfStatement* Parser::ParseIfStatement(ZoneList<const AstRawString*>* labels, Expect(Token::LPAREN, CHECK_OK); Expression* condition = ParseExpression(true, CHECK_OK); Expect(Token::RPAREN, CHECK_OK); - Statement* then_statement = ParseStatement(labels, CHECK_OK); + Statement* then_statement = ParseSubStatement(labels, CHECK_OK); Statement* else_statement = NULL; if (peek() == Token::ELSE) { Next(); - else_statement = ParseStatement(labels, CHECK_OK); + else_statement = ParseSubStatement(labels, CHECK_OK); } else { else_statement = factory()->NewEmptyStatement(RelocInfo::kNoPosition); } @@ -2612,11 +2618,16 @@ Statement* Parser::ParseReturnStatement(bool* ok) { tok == Token::SEMICOLON || tok == Token::RBRACE || tok == Token::EOS) { - return_value = GetLiteralUndefined(position()); + if (IsSubclassConstructor(function_state_->kind())) { + return_value = ThisExpression(scope_, factory(), loc.beg_pos); + } else { + return_value = GetLiteralUndefined(position()); + } } else { return_value = ParseExpression(true, CHECK_OK); } ExpectSemicolon(CHECK_OK); + if (is_generator()) { Expression* generator = factory()->NewVariableProxy( function_state_->generator_object_variable()); @@ -2645,7 +2656,7 @@ Statement* Parser::ParseWithStatement(ZoneList<const AstRawString*>* labels, Expect(Token::WITH, CHECK_OK); int pos = position(); - if (strict_mode() == STRICT) { + if (is_strict(language_mode())) { ReportMessage("strict_mode_with"); *ok = false; return NULL; @@ -2660,7 +2671,7 @@ Statement* Parser::ParseWithStatement(ZoneList<const AstRawString*>* labels, Statement* stmt; { BlockState block_state(&scope_, with_scope); with_scope->set_start_position(scanner()->peek_location().beg_pos); - stmt = ParseStatement(labels, CHECK_OK); + stmt = ParseSubStatement(labels, CHECK_OK); with_scope->set_end_position(scanner()->location().end_pos); } return factory()->NewWithStatement(with_scope, expr, stmt, pos); @@ -2762,12 +2773,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { Expect(Token::TRY, CHECK_OK); int pos = position(); - TargetCollector try_collector(zone()); - Block* try_block; - - { Target target(&this->target_stack_, &try_collector); - try_block = ParseBlock(NULL, CHECK_OK); - } + Block* try_block = ParseBlock(NULL, CHECK_OK); Token::Value tok = peek(); if (tok != Token::CATCH && tok != Token::FINALLY) { @@ -2776,11 +2782,6 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { return NULL; } - // If we can break out from the catch block and there is a finally block, - // then we will need to collect escaping targets from the catch - // block. Since we don't know yet if there will be a finally block, we - // always collect the targets. - TargetCollector catch_collector(zone()); Scope* catch_scope = NULL; Variable* catch_variable = NULL; Block* catch_block = NULL; @@ -2795,7 +2796,6 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { Expect(Token::RPAREN, CHECK_OK); - Target target(&this->target_stack_, &catch_collector); catch_variable = catch_scope->DeclareLocal(name, VAR, kCreatedInitialized); BlockState block_state(&scope_, catch_scope); catch_block = ParseBlock(NULL, CHECK_OK); @@ -2823,7 +2823,6 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { TryCatchStatement* statement = factory()->NewTryCatchStatement( index, try_block, catch_scope, catch_variable, catch_block, RelocInfo::kNoPosition); - statement->set_escaping_targets(try_collector.targets()); try_block = factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition); try_block->AddStatement(statement, zone()); catch_block = NULL; // Clear to indicate it's been handled. @@ -2841,11 +2840,8 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { int index = 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. - try_collector.targets()->AddAll(*catch_collector.targets(), zone()); } - result->set_escaping_targets(try_collector.targets()); return result; } @@ -2860,7 +2856,7 @@ DoWhileStatement* Parser::ParseDoWhileStatement( Target target(&this->target_stack_, loop); Expect(Token::DO, CHECK_OK); - Statement* body = ParseStatement(NULL, CHECK_OK); + Statement* body = ParseSubStatement(NULL, CHECK_OK); Expect(Token::WHILE, CHECK_OK); Expect(Token::LPAREN, CHECK_OK); @@ -2890,26 +2886,13 @@ WhileStatement* Parser::ParseWhileStatement( Expect(Token::LPAREN, CHECK_OK); Expression* cond = ParseExpression(true, CHECK_OK); Expect(Token::RPAREN, CHECK_OK); - Statement* body = ParseStatement(NULL, CHECK_OK); + Statement* body = ParseSubStatement(NULL, CHECK_OK); if (loop != NULL) loop->Initialize(cond, body); return loop; } -bool Parser::CheckInOrOf(bool accept_OF, - ForEachStatement::VisitMode* visit_mode) { - if (Check(Token::IN)) { - *visit_mode = ForEachStatement::ENUMERATE; - return true; - } else if (accept_OF && CheckContextualKeyword(CStrVector("of"))) { - *visit_mode = ForEachStatement::ITERATE; - return true; - } - return false; -} - - void Parser::InitializeForEachStatement(ForEachStatement* stmt, Expression* each, Expression* subject, @@ -3034,8 +3017,7 @@ Statement* Parser::DesugarLetBindingsInForStatement( // For each let variable x: // make statement: temp_x = x. for (int i = 0; i < names->length(); i++) { - VariableProxy* proxy = - NewUnresolved(names->at(i), LET, Interface::NewValue()); + VariableProxy* proxy = NewUnresolved(names->at(i), LET); Variable* temp = scope_->DeclarationScope()->NewTemporary(temp_name); VariableProxy* temp_proxy = factory()->NewVariableProxy(temp); Assignment* assignment = factory()->NewAssignment( @@ -3079,8 +3061,7 @@ Statement* Parser::DesugarLetBindingsInForStatement( // For each let variable x: // make statement: let x = temp_x. for (int i = 0; i < names->length(); i++) { - VariableProxy* proxy = - NewUnresolved(names->at(i), LET, Interface::NewValue()); + VariableProxy* proxy = NewUnresolved(names->at(i), LET); Declaration* declaration = factory()->NewVariableDeclaration(proxy, LET, scope_, pos); Declare(declaration, true, CHECK_OK); @@ -3230,8 +3211,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, bool is_let_identifier_expression = false; if (peek() != Token::SEMICOLON) { if (peek() == Token::VAR || - (peek() == Token::CONST && strict_mode() == SLOPPY)) { - bool is_const = peek() == Token::CONST; + (peek() == Token::CONST && is_sloppy(language_mode()))) { const AstRawString* name = NULL; VariableDeclarationProperties decl_props = kHasNoInitializers; Block* variable_statement = @@ -3241,9 +3221,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, ForEachStatement::VisitMode mode; int each_pos = position(); - if (name != NULL && CheckInOrOf(accept_OF, &mode)) { - Interface* interface = - is_const ? Interface::NewConst() : Interface::NewValue(); + if (name != NULL && CheckInOrOf(accept_OF, &mode, ok)) { + if (!*ok) return nullptr; ForEachStatement* loop = factory()->NewForEachStatement(mode, labels, stmt_pos); Target target(&this->target_stack_, loop); @@ -3251,9 +3230,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, Expression* enumerable = ParseExpression(true, CHECK_OK); Expect(Token::RPAREN, CHECK_OK); - VariableProxy* each = - scope_->NewUnresolved(factory(), name, interface, each_pos); - Statement* body = ParseStatement(NULL, CHECK_OK); + VariableProxy* each = scope_->NewUnresolved(factory(), name, each_pos); + Statement* body = ParseSubStatement(NULL, CHECK_OK); InitializeForEachStatement(loop, each, enumerable, body); Block* result = factory()->NewBlock(NULL, 2, false, RelocInfo::kNoPosition); @@ -3269,7 +3247,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, init = variable_statement; } } else if ((peek() == Token::LET || peek() == Token::CONST) && - strict_mode() == STRICT) { + is_strict(language_mode())) { bool is_const = peek() == Token::CONST; const AstRawString* name = NULL; VariableDeclarationProperties decl_props = kHasNoInitializers; @@ -3281,7 +3259,9 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, ForEachStatement::VisitMode mode; int each_pos = position(); - if (accept_IN && CheckInOrOf(accept_OF, &mode)) { + if (accept_IN && CheckInOrOf(accept_OF, &mode, ok)) { + if (!*ok) return nullptr; + // Rewrite a for-in statement of the form // // for (let/const x in e) b @@ -3310,9 +3290,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, scope_ = for_scope; Expect(Token::RPAREN, CHECK_OK); - VariableProxy* each = scope_->NewUnresolved( - factory(), name, Interface::NewValue(), each_pos); - Statement* body = ParseStatement(NULL, CHECK_OK); + VariableProxy* each = scope_->NewUnresolved(factory(), name, each_pos); + Statement* body = ParseSubStatement(NULL, CHECK_OK); Block* body_block = factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition); Token::Value init_op = is_const ? Token::INIT_CONST : Token::ASSIGN; @@ -3344,7 +3323,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, expression->AsVariableProxy()->raw_name() == ast_value_factory()->let_string(); - if (CheckInOrOf(accept_OF, &mode)) { + if (CheckInOrOf(accept_OF, &mode, ok)) { + if (!*ok) return nullptr; expression = this->CheckAndRewriteReferenceExpression( expression, lhs_location, "invalid_lhs_in_for", CHECK_OK); @@ -3355,7 +3335,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, Expression* enumerable = ParseExpression(true, CHECK_OK); Expect(Token::RPAREN, CHECK_OK); - Statement* body = ParseStatement(NULL, CHECK_OK); + Statement* body = ParseSubStatement(NULL, CHECK_OK); InitializeForEachStatement(loop, expression, enumerable, body); scope_ = saved_scope; for_scope->set_end_position(scanner()->location().end_pos); @@ -3376,7 +3356,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, // Parsed initializer at this point. // Detect attempts at 'let' declarations in sloppy mode. - if (peek() == Token::IDENTIFIER && strict_mode() == SLOPPY && + if (peek() == Token::IDENTIFIER && is_sloppy(language_mode()) && is_let_identifier_expression) { ReportMessage("sloppy_lexical", NULL); *ok = false; @@ -3407,7 +3387,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, } Expect(Token::RPAREN, CHECK_OK); - Statement* body = ParseStatement(NULL, CHECK_OK); + Statement* body = ParseSubStatement(NULL, CHECK_OK); Statement* result = NULL; if (let_bindings.length() > 0) { @@ -3560,6 +3540,10 @@ int ParserTraits::DeclareArrowParametersFromExpression( Expression* expression, Scope* scope, Scanner::Location* dupe_loc, bool* ok) { int num_params = 0; + // Always reset the flag: It only needs to be set for the first expression + // parsed as arrow function parameter list, becauseonly top-level functions + // are parsed lazily. + parser_->parsing_lazy_arrow_parameters_ = false; *ok = CheckAndDeclareArrowParameter(this, expression, scope, &num_params, dupe_loc); return num_params; @@ -3627,11 +3611,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral( Scope* original_declaration_scope = original_scope_->DeclarationScope(); Scope* scope = function_type == FunctionLiteral::DECLARATION && - (!allow_harmony_scoping() || strict_mode() == SLOPPY) && - (original_scope_ == original_declaration_scope || - declaration_scope != original_declaration_scope) - ? NewScope(declaration_scope, FUNCTION_SCOPE) - : NewScope(scope_, FUNCTION_SCOPE); + (!allow_harmony_scoping() || is_sloppy(language_mode())) && + (original_scope_ == original_declaration_scope || + declaration_scope != original_declaration_scope) + ? NewScope(declaration_scope, FUNCTION_SCOPE, kind) + : NewScope(scope_, FUNCTION_SCOPE, kind); ZoneList<Statement*>* body = NULL; int materialized_literal_count = -1; int expected_property_count = -1; @@ -3644,7 +3628,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral( // Parse function body. { AstNodeFactory function_factory(ast_value_factory()); - FunctionState function_state(&function_state_, &scope_, scope, + FunctionState function_state(&function_state_, &scope_, scope, kind, &function_factory); scope_->SetScopeName(function_name); @@ -3670,32 +3654,39 @@ FunctionLiteral* Parser::ParseFunctionLiteral( // 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 // the locations of these errors if they occur and produce the errors later. - Scanner::Location eval_args_error_log = Scanner::Location::invalid(); + Scanner::Location eval_args_error_loc = Scanner::Location::invalid(); Scanner::Location dupe_error_loc = Scanner::Location::invalid(); - Scanner::Location reserved_loc = Scanner::Location::invalid(); + Scanner::Location reserved_error_loc = Scanner::Location::invalid(); + bool is_rest = false; bool done = arity_restriction == FunctionLiteral::GETTER_ARITY || (peek() == Token::RPAREN && arity_restriction != FunctionLiteral::SETTER_ARITY); while (!done) { bool is_strict_reserved = false; + is_rest = peek() == Token::ELLIPSIS && allow_harmony_rest_params(); + if (is_rest) { + Consume(Token::ELLIPSIS); + } + const AstRawString* param_name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK); // Store locations for possible future error reports. - if (!eval_args_error_log.IsValid() && IsEvalOrArguments(param_name)) { - eval_args_error_log = scanner()->location(); + if (!eval_args_error_loc.IsValid() && IsEvalOrArguments(param_name)) { + eval_args_error_loc = scanner()->location(); } - if (!reserved_loc.IsValid() && is_strict_reserved) { - reserved_loc = scanner()->location(); + if (!reserved_error_loc.IsValid() && is_strict_reserved) { + reserved_error_loc = scanner()->location(); } - if (!dupe_error_loc.IsValid() && scope_->IsDeclared(param_name)) { + if (!dupe_error_loc.IsValid() && + scope_->IsDeclaredParameter(param_name)) { duplicate_parameters = FunctionLiteral::kHasDuplicateParameters; dupe_error_loc = scanner()->location(); } - Variable* var = scope_->DeclareParameter(param_name, VAR); - if (scope->strict_mode() == SLOPPY) { + Variable* var = scope_->DeclareParameter(param_name, VAR, is_rest); + if (is_sloppy(scope->language_mode())) { // TODO(sigurds) Mark every parameter as maybe assigned. This is a // conservative approximation necessary to account for parameters // that are assigned via the arguments array. @@ -3710,7 +3701,14 @@ FunctionLiteral* Parser::ParseFunctionLiteral( } if (arity_restriction == FunctionLiteral::SETTER_ARITY) break; done = (peek() == Token::RPAREN); - if (!done) Expect(Token::COMMA, CHECK_OK); + if (!done) { + if (is_rest) { + ReportMessageAt(scanner()->peek_location(), "param_after_rest"); + *ok = false; + return NULL; + } + Expect(Token::COMMA, CHECK_OK); + } } Expect(Token::RPAREN, CHECK_OK); @@ -3725,17 +3723,16 @@ FunctionLiteral* Parser::ParseFunctionLiteral( Variable* fvar = NULL; Token::Value fvar_init_op = Token::INIT_CONST_LEGACY; if (function_type == FunctionLiteral::NAMED_EXPRESSION) { - if (allow_harmony_scoping() && strict_mode() == STRICT) { + if (allow_harmony_scoping() && is_strict(language_mode())) { fvar_init_op = Token::INIT_CONST; } VariableMode fvar_mode = - allow_harmony_scoping() && strict_mode() == STRICT - ? CONST : CONST_LEGACY; + allow_harmony_scoping() && is_strict(language_mode()) ? CONST + : CONST_LEGACY; DCHECK(function_name != NULL); fvar = new (zone()) Variable(scope_, function_name, fvar_mode, true /* is valid LHS */, - Variable::NORMAL, kCreatedInitialized, kNotAssigned, - Interface::NewConst()); + Variable::NORMAL, kCreatedInitialized, kNotAssigned); VariableProxy* proxy = factory()->NewVariableProxy(fvar); VariableDeclaration* fvar_declaration = factory()->NewVariableDeclaration( proxy, fvar_mode, scope_, RelocInfo::kNoPosition); @@ -3785,28 +3782,27 @@ FunctionLiteral* Parser::ParseFunctionLiteral( &expected_property_count, CHECK_OK); } else { body = ParseEagerFunctionBody(function_name, pos, fvar, fvar_init_op, - is_generator, CHECK_OK); + kind, CHECK_OK); materialized_literal_count = function_state.materialized_literal_count(); expected_property_count = function_state.expected_property_count(); handler_count = function_state.handler_count(); } - // Validate strict mode. - // Concise methods use StrictFormalParameters. - if (strict_mode() == STRICT || IsConciseMethod(kind)) { - CheckStrictFunctionNameAndParameters(function_name, - name_is_strict_reserved, - function_name_location, - eval_args_error_log, - dupe_error_loc, - reserved_loc, - CHECK_OK); - } - if (strict_mode() == STRICT) { + // Validate name and parameter names. We can do this only after parsing the + // function, since the function can declare itself strict. + CheckFunctionName(language_mode(), kind, function_name, + name_is_strict_reserved, function_name_location, + CHECK_OK); + const bool use_strict_params = is_rest || IsConciseMethod(kind); + CheckFunctionParameterNames(language_mode(), use_strict_params, + eval_args_error_loc, dupe_error_loc, + reserved_error_loc, CHECK_OK); + + if (is_strict(language_mode())) { CheckStrictOctalLiteral(scope->start_position(), scope->end_position(), CHECK_OK); } - if (allow_harmony_scoping() && strict_mode() == STRICT) { + if (allow_harmony_scoping() && is_strict(language_mode())) { CheckConflictingVarDeclarations(scope, CHECK_OK); } } @@ -3818,6 +3814,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral( FunctionLiteral::kIsFunction, parenthesized, kind, pos); function_literal->set_function_token_position(function_token_pos); + if (scope->has_rest_parameter()) { + // TODO(caitp): enable optimization of functions with rest params + function_literal->set_dont_optimize_reason(kRestParameter); + } + if (fni_ != NULL && should_infer_name) fni_->AddFunction(function_literal); return function_literal; } @@ -3849,7 +3850,8 @@ void Parser::SkipLazyFunctionBody(const AstRawString* function_name, total_preparse_skipped_ += scope_->end_position() - function_block_pos; *materialized_literal_count = entry.literal_count(); *expected_property_count = entry.property_count(); - scope_->SetStrictMode(entry.strict_mode()); + scope_->SetLanguageMode(entry.language_mode()); + if (entry.uses_super_property()) scope_->RecordSuperPropertyUsage(); return; } cached_parse_data_->Reject(); @@ -3880,27 +3882,48 @@ void Parser::SkipLazyFunctionBody(const AstRawString* function_name, total_preparse_skipped_ += scope_->end_position() - function_block_pos; *materialized_literal_count = logger.literals(); *expected_property_count = logger.properties(); - scope_->SetStrictMode(logger.strict_mode()); + scope_->SetLanguageMode(logger.language_mode()); + if (logger.scope_uses_super_property()) { + scope_->RecordSuperPropertyUsage(); + } if (produce_cached_parse_data()) { DCHECK(log_); // Position right after terminal '}'. int body_end = scanner()->location().end_pos; log_->LogFunction(function_block_pos, body_end, *materialized_literal_count, - *expected_property_count, scope_->strict_mode()); + *expected_property_count, scope_->language_mode(), + scope_->uses_super_property()); } } +void Parser::AddAssertIsConstruct(ZoneList<Statement*>* body, int pos) { + ZoneList<Expression*>* arguments = + new (zone()) ZoneList<Expression*>(0, zone()); + CallRuntime* construct_check = factory()->NewCallRuntime( + ast_value_factory()->is_construct_call_string(), + Runtime::FunctionForId(Runtime::kInlineIsConstructCall), arguments, pos); + CallRuntime* non_callable_error = factory()->NewCallRuntime( + ast_value_factory()->empty_string(), + Runtime::FunctionForId(Runtime::kThrowConstructorNonCallableError), + arguments, pos); + IfStatement* if_statement = factory()->NewIfStatement( + factory()->NewUnaryOperation(Token::NOT, construct_check, pos), + factory()->NewReturnStatement(non_callable_error, pos), + factory()->NewEmptyStatement(pos), pos); + body->Add(if_statement, zone()); +} + + ZoneList<Statement*>* Parser::ParseEagerFunctionBody( const AstRawString* function_name, int pos, Variable* fvar, - Token::Value fvar_init_op, bool is_generator, bool* ok) { + Token::Value fvar_init_op, FunctionKind kind, bool* ok) { // Everything inside an eagerly parsed function will be parsed eagerly // (see comment above). ParsingModeScope parsing_mode(this, PARSE_EAGERLY); ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(8, zone()); if (fvar != NULL) { - VariableProxy* fproxy = scope_->NewUnresolved( - factory(), function_name, Interface::NewConst()); + VariableProxy* fproxy = scope_->NewUnresolved(factory(), function_name); fproxy->BindTo(fvar); body->Add(factory()->NewExpressionStatement( factory()->NewAssignment(fvar_init_op, @@ -3910,8 +3933,15 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody( RelocInfo::kNoPosition), zone()); } + + // For concise constructors, check that they are constructed, + // not called. + if (i::IsConstructor(kind)) { + AddAssertIsConstruct(body, pos); + } + // For generators, allocate and yield an iterator on function entry. - if (is_generator) { + if (IsGeneratorFunction(kind)) { ZoneList<Expression*>* arguments = new(zone()) ZoneList<Expression*>(0, zone()); CallRuntime* allocation = factory()->NewCallRuntime( @@ -3930,9 +3960,9 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody( yield, RelocInfo::kNoPosition), zone()); } - ParseSourceElements(body, Token::RBRACE, false, false, NULL, CHECK_OK); + ParseStatementList(body, Token::RBRACE, false, NULL, CHECK_OK); - if (is_generator) { + if (IsGeneratorFunction(kind)) { VariableProxy* get_proxy = factory()->NewVariableProxy( function_state_->generator_object_variable()); Expression* undefined = @@ -3943,6 +3973,14 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody( yield, RelocInfo::kNoPosition), zone()); } + if (IsSubclassConstructor(kind)) { + body->Add( + factory()->NewReturnStatement( + this->ThisExpression(scope_, factory(), RelocInfo::kNoPosition), + RelocInfo::kNoPosition), + zone()); + } + Expect(Token::RBRACE, CHECK_OK); scope_->set_end_position(scanner()->location().end_pos); @@ -3960,7 +3998,8 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser( DCHECK_EQ(Token::LBRACE, scanner()->current_token()); if (reusable_preparser_ == NULL) { - reusable_preparser_ = new PreParser(&scanner_, NULL, stack_limit_); + reusable_preparser_ = new PreParser(zone(), &scanner_, ast_value_factory(), + NULL, stack_limit_); reusable_preparser_->set_allow_lazy(true); reusable_preparser_->set_allow_natives(allow_natives()); reusable_preparser_->set_allow_harmony_scoping(allow_harmony_scoping()); @@ -3975,11 +4014,14 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser( reusable_preparser_->set_allow_harmony_templates(allow_harmony_templates()); reusable_preparser_->set_allow_harmony_sloppy(allow_harmony_sloppy()); reusable_preparser_->set_allow_harmony_unicode(allow_harmony_unicode()); - } - PreParser::PreParseResult result = - reusable_preparser_->PreParseLazyFunction(strict_mode(), - is_generator(), - logger); + reusable_preparser_->set_allow_harmony_computed_property_names( + allow_harmony_computed_property_names()); + reusable_preparser_->set_allow_harmony_rest_params( + allow_harmony_rest_params()); + reusable_preparser_->set_allow_strong_mode(allow_strong_mode()); + } + PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction( + language_mode(), function_state_->kind(), logger); if (pre_parse_timer_ != NULL) { pre_parse_timer_->Stop(); } @@ -4005,12 +4047,13 @@ ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name, Scope* block_scope = NewScope(scope_, BLOCK_SCOPE); BlockState block_state(&scope_, block_scope); - scope_->SetStrictMode(STRICT); + scope_->SetLanguageMode( + static_cast<LanguageMode>(scope_->language_mode() | STRICT_BIT)); scope_->SetScopeName(name); VariableProxy* proxy = NULL; if (name != NULL) { - proxy = NewUnresolved(name, CONST, Interface::NewConst()); + proxy = NewUnresolved(name, CONST); Declaration* declaration = factory()->NewVariableDeclaration(proxy, CONST, block_scope, pos); Declare(declaration, true, CHECK_OK); @@ -4024,21 +4067,28 @@ ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name, block_scope->set_start_position(scanner()->location().end_pos); } + + ClassLiteralChecker checker(this); ZoneList<ObjectLiteral::Property*>* properties = NewPropertyList(4, zone()); - Expression* constructor = NULL; + FunctionLiteral* constructor = NULL; bool has_seen_constructor = false; Expect(Token::LBRACE, CHECK_OK); + const bool has_extends = extends != nullptr; while (peek() != Token::RBRACE) { if (Check(Token::SEMICOLON)) continue; if (fni_ != NULL) fni_->Enter(); const bool in_class = true; const bool is_static = false; + bool is_computed_name = false; // Classes do not care about computed + // property names here. ObjectLiteral::Property* property = ParsePropertyDefinition( - NULL, in_class, is_static, &has_seen_constructor, CHECK_OK); + &checker, in_class, has_extends, is_static, &is_computed_name, + &has_seen_constructor, CHECK_OK); if (has_seen_constructor && constructor == NULL) { - constructor = GetPropertyValue(property); + constructor = GetPropertyValue(property)->AsFunctionLiteral(); + DCHECK_NOT_NULL(constructor); } else { properties->Add(property, zone()); } @@ -4153,9 +4203,7 @@ void Parser::CheckConflictingVarDeclarations(Scope* scope, bool* ok) { bool Parser::TargetStackContainsLabel(const AstRawString* label) { for (Target* t = target_stack_; t != NULL; t = t->previous()) { - BreakableStatement* stat = t->node()->AsBreakableStatement(); - if (stat != NULL && ContainsLabel(stat->labels(), label)) - return true; + if (ContainsLabel(t->statement()->labels(), label)) return true; } return false; } @@ -4165,11 +4213,9 @@ BreakableStatement* Parser::LookupBreakTarget(const AstRawString* label, bool* ok) { bool anonymous = label == NULL; for (Target* t = target_stack_; t != NULL; t = t->previous()) { - BreakableStatement* stat = t->node()->AsBreakableStatement(); - if (stat == NULL) continue; + BreakableStatement* stat = t->statement(); if ((anonymous && stat->is_target_for_anonymous()) || (!anonymous && ContainsLabel(stat->labels(), label))) { - RegisterTargetUse(stat->break_target(), t->previous()); return stat; } } @@ -4181,12 +4227,11 @@ IterationStatement* Parser::LookupContinueTarget(const AstRawString* label, bool* ok) { bool anonymous = label == NULL; for (Target* t = target_stack_; t != NULL; t = t->previous()) { - IterationStatement* stat = t->node()->AsIterationStatement(); + IterationStatement* stat = t->statement()->AsIterationStatement(); if (stat == NULL) continue; DCHECK(stat->is_target_for_anonymous()); if (anonymous || ContainsLabel(stat->labels(), label)) { - RegisterTargetUse(stat->continue_target(), t->previous()); return stat; } } @@ -4194,36 +4239,26 @@ IterationStatement* Parser::LookupContinueTarget(const AstRawString* label, } -void Parser::RegisterTargetUse(Label* target, Target* stop) { - // Register that a break target found at the given stop in the - // target stack has been used from the top of the target stack. Add - // the break target to any TargetCollectors passed on the stack. - for (Target* t = target_stack_; t != stop; t = t->previous()) { - TargetCollector* collector = t->node()->AsTargetCollector(); - if (collector != NULL) collector->AddTarget(target, zone()); - } -} - - -void Parser::HandleSourceURLComments() { +void Parser::HandleSourceURLComments(CompilationInfo* info) { if (scanner_.source_url()->length() > 0) { - Handle<String> source_url = scanner_.source_url()->Internalize(isolate()); - info_->script()->set_source_url(*source_url); + Handle<String> source_url = + scanner_.source_url()->Internalize(info->isolate()); + info->script()->set_source_url(*source_url); } if (scanner_.source_mapping_url()->length() > 0) { Handle<String> source_mapping_url = - scanner_.source_mapping_url()->Internalize(isolate()); - info_->script()->set_source_mapping_url(*source_mapping_url); + scanner_.source_mapping_url()->Internalize(info->isolate()); + info->script()->set_source_mapping_url(*source_mapping_url); } } -void Parser::ThrowPendingError() { +void Parser::ThrowPendingError(Isolate* isolate, Handle<Script> script) { DCHECK(ast_value_factory()->IsInternalized()); if (has_pending_error_) { - MessageLocation location(script(), pending_error_location_.beg_pos, + MessageLocation location(script, pending_error_location_.beg_pos, pending_error_location_.end_pos); - Factory* factory = isolate()->factory(); + Factory* factory = isolate->factory(); bool has_arg = pending_error_arg_ != NULL || pending_error_char_arg_ != NULL; Handle<FixedArray> elements = factory->NewFixedArray(has_arg ? 1 : 0); @@ -4236,7 +4271,7 @@ void Parser::ThrowPendingError() { .ToHandleChecked(); elements->set(0, *arg_string); } - isolate()->debug()->OnCompileError(script()); + isolate->debug()->OnCompileError(script); Handle<JSArray> array = factory->NewJSArrayWithElements(elements); Handle<Object> error; @@ -4244,21 +4279,39 @@ void Parser::ThrowPendingError() { pending_error_is_reference_error_ ? factory->NewReferenceError(pending_error_message_, array) : factory->NewSyntaxError(pending_error_message_, array); - if (maybe_error.ToHandle(&error)) isolate()->Throw(*error, &location); + + if (maybe_error.ToHandle(&error)) { + Handle<JSObject> jserror = Handle<JSObject>::cast(error); + + Handle<Name> key_start_pos = factory->error_start_pos_symbol(); + JSObject::SetProperty(jserror, key_start_pos, + handle(Smi::FromInt(location.start_pos()), isolate), + SLOPPY).Check(); + + Handle<Name> key_end_pos = factory->error_end_pos_symbol(); + JSObject::SetProperty(jserror, key_end_pos, + handle(Smi::FromInt(location.end_pos()), isolate), + SLOPPY).Check(); + + Handle<Name> key_script = factory->error_script_symbol(); + JSObject::SetProperty(jserror, key_script, script, SLOPPY).Check(); + + isolate->Throw(*error, &location); + } } } -void Parser::Internalize() { +void Parser::Internalize(CompilationInfo* info) { // Internalize strings. - ast_value_factory()->Internalize(isolate()); + ast_value_factory()->Internalize(info->isolate()); // Error processing. - if (info()->function() == NULL) { + if (info->function() == NULL) { if (stack_overflow()) { - isolate()->StackOverflow(); + info->isolate()->StackOverflow(); } else { - ThrowPendingError(); + ThrowPendingError(info->isolate(), info->script()); } } @@ -4266,10 +4319,10 @@ void Parser::Internalize() { for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount; ++feature) { for (int i = 0; i < use_counts_[feature]; ++i) { - isolate()->CountUsage(v8::Isolate::UseCounterFeature(feature)); + info->isolate()->CountUsage(v8::Isolate::UseCounterFeature(feature)); } } - isolate()->counters()->total_preparse_skipped()->Increment( + info->isolate()->counters()->total_preparse_skipped()->Increment( total_preparse_skipped_); } @@ -4278,11 +4331,10 @@ void Parser::Internalize() { // Regular expressions -RegExpParser::RegExpParser(FlatStringReader* in, - Handle<String>* error, - bool multiline, +RegExpParser::RegExpParser(FlatStringReader* in, Handle<String>* error, + bool multiline, bool unicode, Isolate* isolate, Zone* zone) - : isolate_(zone->isolate()), + : isolate_(isolate), zone_(zone), error_(error), captures_(NULL), @@ -4292,6 +4344,7 @@ RegExpParser::RegExpParser(FlatStringReader* in, capture_count_(0), has_more_(true), multiline_(multiline), + unicode_(unicode), simple_(false), contains_anchor_(false), is_scanned_for_captures_(false), @@ -4348,6 +4401,13 @@ bool RegExpParser::simple() { } +bool RegExpParser::IsSyntaxCharacter(uc32 c) { + return c == '^' || c == '$' || c == '\\' || c == '.' || c == '*' || + c == '+' || c == '?' || c == '(' || c == ')' || c == '[' || c == ']' || + c == '{' || c == '}' || c == '|'; +} + + RegExpTree* RegExpParser::ReportError(Vector<const char> message) { failed_ = true; *error_ = isolate()->factory()->NewStringFromAscii(message).ToHandleChecked(); @@ -4564,9 +4624,15 @@ RegExpTree* RegExpParser::ParseDisjunction() { } uc32 first_digit = Next(); if (first_digit == '8' || first_digit == '9') { - // Treat as identity escape - builder->AddCharacter(first_digit); - Advance(2); + // If the 'u' flag is present, only syntax characters can be escaped, + // no other identity escapes are allowed. If the 'u' flag is not + // present, all identity escapes are allowed. + if (!FLAG_harmony_unicode_regexps || !unicode_) { + builder->AddCharacter(first_digit); + Advance(2); + } else { + return ReportError(CStrVector("Invalid escape")); + } break; } } @@ -4622,25 +4688,41 @@ RegExpTree* RegExpParser::ParseDisjunction() { uc32 value; if (ParseHexEscape(2, &value)) { builder->AddCharacter(value); - } else { + } else if (!FLAG_harmony_unicode_regexps || !unicode_) { builder->AddCharacter('x'); + } else { + // If the 'u' flag is present, invalid escapes are not treated as + // identity escapes. + return ReportError(CStrVector("Invalid escape")); } break; } case 'u': { Advance(2); uc32 value; - if (ParseHexEscape(4, &value)) { + if (ParseUnicodeEscape(&value)) { builder->AddCharacter(value); - } else { + } else if (!FLAG_harmony_unicode_regexps || !unicode_) { builder->AddCharacter('u'); + } else { + // If the 'u' flag is present, invalid escapes are not treated as + // identity escapes. + return ReportError(CStrVector("Invalid unicode escape")); } break; } default: - // Identity escape. - builder->AddCharacter(Next()); - Advance(2); + Advance(); + // If the 'u' flag is present, only syntax characters can be escaped, no + // other identity escapes are allowed. If the 'u' flag is not present, + // all identity escapes are allowed. + if (!FLAG_harmony_unicode_regexps || !unicode_ || + IsSyntaxCharacter(current())) { + builder->AddCharacter(current()); + Advance(); + } else { + return ReportError(CStrVector("Invalid escape")); + } break; } break; @@ -4883,11 +4965,10 @@ uc32 RegExpParser::ParseOctalLiteral() { } -bool RegExpParser::ParseHexEscape(int length, uc32 *value) { +bool RegExpParser::ParseHexEscape(int length, uc32* value) { int start = position(); uc32 val = 0; - bool done = false; - for (int i = 0; !done; i++) { + for (int i = 0; i < length; ++i) { uc32 c = current(); int d = HexValue(c); if (d < 0) { @@ -4896,15 +4977,52 @@ bool RegExpParser::ParseHexEscape(int length, uc32 *value) { } val = val * 16 + d; Advance(); - if (i == length - 1) { - done = true; - } } *value = val; return true; } +bool RegExpParser::ParseUnicodeEscape(uc32* value) { + // Accept both \uxxxx and \u{xxxxxx} (if harmony unicode escapes are + // allowed). In the latter case, the number of hex digits between { } is + // arbitrary. \ and u have already been read. + if (current() == '{' && FLAG_harmony_unicode_regexps && unicode_) { + int start = position(); + Advance(); + if (ParseUnlimitedLengthHexNumber(0x10ffff, value)) { + if (current() == '}') { + Advance(); + return true; + } + } + Reset(start); + return false; + } + // \u but no {, or \u{...} escapes not allowed. + return ParseHexEscape(4, value); +} + + +bool RegExpParser::ParseUnlimitedLengthHexNumber(int max_value, uc32* value) { + uc32 x = 0; + int d = HexValue(current()); + if (d < 0) { + return false; + } + while (d >= 0) { + x = x * 16 + d; + if (x > max_value) { + return false; + } + Advance(); + d = HexValue(current()); + } + *value = x; + return true; +} + + uc32 RegExpParser::ParseClassCharacterEscape() { DCHECK(current() == '\\'); DCHECK(has_next() && !IsSpecialClassEscape(Next())); @@ -4959,27 +5077,42 @@ uc32 RegExpParser::ParseClassCharacterEscape() { if (ParseHexEscape(2, &value)) { return value; } - // If \x is not followed by a two-digit hexadecimal, treat it - // as an identity escape. - return 'x'; + if (!FLAG_harmony_unicode_regexps || !unicode_) { + // If \x is not followed by a two-digit hexadecimal, treat it + // as an identity escape. + return 'x'; + } + // If the 'u' flag is present, invalid escapes are not treated as + // identity escapes. + ReportError(CStrVector("Invalid escape")); + return 0; } case 'u': { Advance(); uc32 value; - if (ParseHexEscape(4, &value)) { + if (ParseUnicodeEscape(&value)) { return value; } - // If \u is not followed by a four-digit hexadecimal, treat it - // as an identity escape. - return 'u'; + if (!FLAG_harmony_unicode_regexps || !unicode_) { + return 'u'; + } + // If the 'u' flag is present, invalid escapes are not treated as + // identity escapes. + ReportError(CStrVector("Invalid unicode escape")); + return 0; } default: { - // Extended identity escape. We accept any character that hasn't - // been matched by a more specific case, not just the subset required - // by the ECMAScript specification. uc32 result = current(); - Advance(); - return result; + // If the 'u' flag is present, only syntax characters can be escaped, no + // other identity escapes are allowed. If the 'u' flag is not present, all + // identity escapes are allowed. + if (!FLAG_harmony_unicode_regexps || !unicode_ || + IsSyntaxCharacter(result)) { + Advance(); + return result; + } + ReportError(CStrVector("Invalid escape")); + return 0; } } return 0; @@ -5085,12 +5218,11 @@ RegExpTree* RegExpParser::ParseCharacterClass() { // ---------------------------------------------------------------------------- // The Parser interface. -bool RegExpParser::ParseRegExp(FlatStringReader* input, - bool multiline, - RegExpCompileData* result, - Zone* zone) { +bool RegExpParser::ParseRegExp(Isolate* isolate, Zone* zone, + FlatStringReader* input, bool multiline, + bool unicode, RegExpCompileData* result) { DCHECK(result != NULL); - RegExpParser parser(input, &result->error, multiline, zone); + RegExpParser parser(input, &result->error, multiline, unicode, isolate, zone); RegExpTree* tree = parser.ParsePattern(); if (parser.failed()) { DCHECK(tree == NULL); @@ -5108,49 +5240,67 @@ bool RegExpParser::ParseRegExp(FlatStringReader* input, } -bool Parser::Parse() { - DCHECK(info()->function() == NULL); +bool Parser::ParseStatic(CompilationInfo* info, bool allow_lazy) { + Parser parser(info, info->isolate()->stack_guard()->real_climit(), + info->isolate()->heap()->HashSeed(), + info->isolate()->unicode_cache()); + parser.set_allow_lazy(allow_lazy); + if (parser.Parse(info)) { + info->SetLanguageMode(info->function()->language_mode()); + return true; + } + return false; +} + + +bool Parser::Parse(CompilationInfo* info) { + DCHECK(info->function() == NULL); FunctionLiteral* result = NULL; - pre_parse_timer_ = isolate()->counters()->pre_parse(); + // Ok to use Isolate here; this function is only called in the main thread. + DCHECK(parsing_on_main_thread_); + Isolate* isolate = info->isolate(); + pre_parse_timer_ = isolate->counters()->pre_parse(); if (FLAG_trace_parse || allow_natives() || extension_ != NULL) { // If intrinsics are allowed, the Parser cannot operate independent of the // V8 heap because of Runtime. Tell the string table to internalize strings // and values right after they're created. - ast_value_factory()->Internalize(isolate()); + ast_value_factory()->Internalize(isolate); } - if (info()->is_lazy()) { - DCHECK(!info()->is_eval()); - if (info()->shared_info()->is_function()) { - result = ParseLazy(); + if (info->is_lazy()) { + DCHECK(!info->is_eval()); + if (info->shared_info()->is_function()) { + result = ParseLazy(info); } else { - result = ParseProgram(); + result = ParseProgram(info); } } else { - SetCachedData(); - result = ParseProgram(); + SetCachedData(info); + result = ParseProgram(info); } - info()->SetFunction(result); + info->SetFunction(result); - Internalize(); + Internalize(info); DCHECK(ast_value_factory()->IsInternalized()); return (result != NULL); } -void Parser::ParseOnBackground() { - DCHECK(info()->function() == NULL); +void Parser::ParseOnBackground(CompilationInfo* info) { + parsing_on_main_thread_ = false; + + DCHECK(info->function() == NULL); FunctionLiteral* result = NULL; fni_ = new (zone()) FuncNameInferrer(ast_value_factory(), zone()); CompleteParserRecorder recorder; if (produce_cached_parse_data()) log_ = &recorder; - DCHECK(info()->source_stream() != NULL); - ExternalStreamingStream stream(info()->source_stream(), - info()->source_stream_encoding()); + DCHECK(info->source_stream() != NULL); + ExternalStreamingStream stream(info->source_stream(), + info->source_stream_encoding()); scanner_.Initialize(&stream); - DCHECK(info()->context().is_null() || info()->context()->IsNativeContext()); + DCHECK(info->context().is_null() || info->context()->IsNativeContext()); // When streaming, we don't know the length of the source until we have parsed // it. The raw data can be UTF-8, so we wouldn't know the source length until @@ -5160,20 +5310,20 @@ void Parser::ParseOnBackground() { // scopes) and set their end position after we know the script length. Scope* top_scope = NULL; Scope* eval_scope = NULL; - result = DoParseProgram(info(), &top_scope, &eval_scope); + result = DoParseProgram(info, &top_scope, &eval_scope); top_scope->set_end_position(scanner()->location().end_pos); if (eval_scope != NULL) { eval_scope->set_end_position(scanner()->location().end_pos); } - info()->SetFunction(result); + info->SetFunction(result); // We cannot internalize on a background thread; a foreground task will take // care of calling Parser::Internalize just before compilation. if (produce_cached_parse_data()) { - if (result != NULL) *info_->cached_data() = recorder.GetScriptData(); + if (result != NULL) *info->cached_data() = recorder.GetScriptData(); log_ = NULL; } } |