diff options
Diffstat (limited to 'deps/v8/src/parser.cc')
-rw-r--r-- | deps/v8/src/parser.cc | 850 |
1 files changed, 483 insertions, 367 deletions
diff --git a/deps/v8/src/parser.cc b/deps/v8/src/parser.cc index 985a90f8dc..8ed20ee212 100644 --- a/deps/v8/src/parser.cc +++ b/deps/v8/src/parser.cc @@ -23,6 +23,75 @@ namespace v8 { namespace internal { +ScriptData::ScriptData(const byte* data, int length) + : owns_data_(false), rejected_(false), data_(data), length_(length) { + if (!IsAligned(reinterpret_cast<intptr_t>(data), kPointerAlignment)) { + byte* copy = NewArray<byte>(length); + DCHECK(IsAligned(reinterpret_cast<intptr_t>(copy), kPointerAlignment)); + CopyBytes(copy, data, length); + data_ = copy; + AcquireDataOwnership(); + } +} + + +ParseInfo::ParseInfo(Zone* zone) + : zone_(zone), + flags_(0), + source_stream_(nullptr), + source_stream_encoding_(ScriptCompiler::StreamedSource::ONE_BYTE), + extension_(nullptr), + compile_options_(ScriptCompiler::kNoCompileOptions), + script_scope_(nullptr), + unicode_cache_(nullptr), + stack_limit_(0), + hash_seed_(0), + cached_data_(nullptr), + ast_value_factory_(nullptr), + literal_(nullptr), + scope_(nullptr) {} + + +ParseInfo::ParseInfo(Zone* zone, Handle<JSFunction> function) + : ParseInfo(zone, Handle<SharedFunctionInfo>(function->shared())) { + set_closure(function); + set_context(Handle<Context>(function->context())); +} + + +ParseInfo::ParseInfo(Zone* zone, Handle<SharedFunctionInfo> shared) + : ParseInfo(zone) { + isolate_ = shared->GetIsolate(); + + set_lazy(); + set_hash_seed(isolate_->heap()->HashSeed()); + set_stack_limit(isolate_->stack_guard()->real_climit()); + set_unicode_cache(isolate_->unicode_cache()); + set_language_mode(shared->language_mode()); + set_shared_info(shared); + + Handle<Script> script(Script::cast(shared->script())); + set_script(script); + if (!script.is_null() && script->type()->value() == Script::TYPE_NATIVE) { + set_native(); + } +} + + +ParseInfo::ParseInfo(Zone* zone, Handle<Script> script) : ParseInfo(zone) { + isolate_ = script->GetIsolate(); + + set_hash_seed(isolate_->heap()->HashSeed()); + set_stack_limit(isolate_->stack_guard()->real_climit()); + set_unicode_cache(isolate_->unicode_cache()); + set_script(script); + + if (script->type()->value() == Script::TYPE_NATIVE) { + set_native(); + } +} + + RegExpBuilder::RegExpBuilder(Zone* zone) : zone_(zone), pending_empty_(false), @@ -251,7 +320,7 @@ int ParseData::FunctionsSize() { } -void Parser::SetCachedData(CompilationInfo* info) { +void Parser::SetCachedData(ParseInfo* info) { if (compile_options_ == ScriptCompiler::kNoCompileOptions) { cached_parse_data_ = NULL; } else { @@ -600,56 +669,46 @@ Expression* ParserTraits::NewThrowError( void ParserTraits::ReportMessageAt(Scanner::Location source_location, - const char* message, - const char* arg, - bool is_reference_error) { + const char* message, const char* arg, + ParseErrorType error_type) { if (parser_->stack_overflow()) { // Suppress the error message (syntax error or such) in the presence of a // stack overflow. The isolate allows only one pending exception at at time // and we want to report the stack overflow later. return; } - parser_->has_pending_error_ = true; - parser_->pending_error_location_ = source_location; - parser_->pending_error_message_ = message; - parser_->pending_error_char_arg_ = arg; - parser_->pending_error_arg_ = NULL; - parser_->pending_error_is_reference_error_ = is_reference_error; + parser_->pending_error_handler_.ReportMessageAt(source_location.beg_pos, + source_location.end_pos, + message, arg, error_type); } -void ParserTraits::ReportMessage(const char* message, - const char* arg, - bool is_reference_error) { +void ParserTraits::ReportMessage(const char* message, const char* arg, + ParseErrorType error_type) { Scanner::Location source_location = parser_->scanner()->location(); - ReportMessageAt(source_location, message, arg, is_reference_error); + ReportMessageAt(source_location, message, arg, error_type); } -void ParserTraits::ReportMessage(const char* message, - const AstRawString* arg, - bool is_reference_error) { +void ParserTraits::ReportMessage(const char* message, const AstRawString* arg, + ParseErrorType error_type) { Scanner::Location source_location = parser_->scanner()->location(); - ReportMessageAt(source_location, message, arg, is_reference_error); + ReportMessageAt(source_location, message, arg, error_type); } void ParserTraits::ReportMessageAt(Scanner::Location source_location, - const char* message, - const AstRawString* arg, - bool is_reference_error) { + const char* message, const AstRawString* arg, + ParseErrorType error_type) { if (parser_->stack_overflow()) { // Suppress the error message (syntax error or such) in the presence of a // stack overflow. The isolate allows only one pending exception at at time // and we want to report the stack overflow later. return; } - parser_->has_pending_error_ = true; - parser_->pending_error_location_ = source_location; - parser_->pending_error_message_ = message; - parser_->pending_error_char_arg_ = NULL; - parser_->pending_error_arg_ = arg; - parser_->pending_error_is_reference_error_ = is_reference_error; + parser_->pending_error_handler_.ReportMessageAt(source_location.beg_pos, + source_location.end_pos, + message, arg, error_type); } @@ -704,6 +763,10 @@ Literal* ParserTraits::ExpressionFromLiteral(Token::Value token, int pos, return factory->NewBooleanLiteral(true, pos); case Token::FALSE_LITERAL: return factory->NewBooleanLiteral(false, pos); + case Token::SMI: { + int value = scanner->smi_value(); + return factory->NewSmiLiteral(value, pos); + } case Token::NUMBER: { double value = scanner->DoubleValue(); return factory->NewNumberLiteral(value, pos); @@ -716,7 +779,9 @@ Literal* ParserTraits::ExpressionFromLiteral(Token::Value token, int pos, Expression* ParserTraits::ExpressionFromIdentifier(const AstRawString* name, - int pos, Scope* scope, + int start_position, + int end_position, + Scope* scope, AstNodeFactory* factory) { if (parser_->fni_ != NULL) parser_->fni_->PushVariableName(name); @@ -725,8 +790,10 @@ Expression* ParserTraits::ExpressionFromIdentifier(const AstRawString* name, // 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); + ? factory->NewVariableProxy(name, Variable::NORMAL, start_position, + end_position) + : scope->NewUnresolved(factory, name, start_position, + end_position); } @@ -781,38 +848,31 @@ ClassLiteral* ParserTraits::ParseClassLiteral( } -Parser::Parser(CompilationInfo* info, uintptr_t stack_limit, uint32_t hash_seed, - UnicodeCache* unicode_cache) - : ParserBase<ParserTraits>(info->zone(), &scanner_, stack_limit, +Parser::Parser(ParseInfo* info) + : ParserBase<ParserTraits>(info->zone(), &scanner_, info->stack_limit(), info->extension(), info->ast_value_factory(), NULL, this), - scanner_(unicode_cache), + scanner_(info->unicode_cache()), reusable_preparser_(NULL), original_scope_(NULL), target_stack_(NULL), compile_options_(info->compile_options()), cached_parse_data_(NULL), 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), parsing_on_main_thread_(true) { - // Even though we were passed CompilationInfo, we should not store it in + // Even though we were passed ParseInfo, we should not store it in // Parser - this makes sure that Isolate is not accidentally accessed via - // CompilationInfo during background parsing. + // ParseInfo during background parsing. DCHECK(!info->script().is_null() || info->source_stream() != NULL); - set_allow_lazy(false); // Must be explicitly enabled. + set_allow_lazy(info->allow_lazy_parsing()); set_allow_natives(FLAG_allow_natives_syntax || info->is_native()); - set_allow_harmony_scoping(!info->is_native() && FLAG_harmony_scoping); set_allow_harmony_modules(!info->is_native() && FLAG_harmony_modules); set_allow_harmony_arrow_functions(FLAG_harmony_arrow_functions); set_allow_harmony_numeric_literals(FLAG_harmony_numeric_literals); set_allow_harmony_classes(FLAG_harmony_classes); set_allow_harmony_object_literals(FLAG_harmony_object_literals); - 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( @@ -825,13 +885,14 @@ Parser::Parser(CompilationInfo* info, uintptr_t stack_limit, uint32_t hash_seed, } if (info->ast_value_factory() == NULL) { // info takes ownership of AstValueFactory. - info->SetAstValueFactory(new AstValueFactory(zone(), hash_seed)); + info->set_ast_value_factory(new AstValueFactory(zone(), info->hash_seed())); + info->set_ast_value_factory_owned(); ast_value_factory_ = info->ast_value_factory(); } } -FunctionLiteral* Parser::ParseProgram(CompilationInfo* info) { +FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) { // TODO(bmeurer): We temporarily need to pass allow_nesting = true here, // see comment for HistogramTimerScope class. @@ -839,7 +900,6 @@ FunctionLiteral* Parser::ParseProgram(CompilationInfo* info) { // 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()); @@ -880,7 +940,7 @@ FunctionLiteral* Parser::ParseProgram(CompilationInfo* info) { if (eval_scope != NULL) { eval_scope->set_end_position(source->length()); } - HandleSourceURLComments(info); + HandleSourceURLComments(isolate, info->script()); if (FLAG_trace_parse && result != NULL) { double ms = timer.Elapsed().InMillisecondsF(); @@ -903,18 +963,18 @@ FunctionLiteral* Parser::ParseProgram(CompilationInfo* info) { } -FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, Scope** scope, +FunctionLiteral* Parser::DoParseProgram(ParseInfo* 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. + // via ParseInfo, and also not pass it forward. DCHECK(scope_ == NULL); DCHECK(target_stack_ == NULL); FunctionLiteral* result = NULL; { *scope = NewScope(scope_, SCRIPT_SCOPE); - info->SetScriptScope(*scope); + info->set_script_scope(*scope); if (!info->context().is_null() && !info->context()->IsNativeContext()) { *scope = Scope::DeserializeScopeChain(info->isolate(), zone(), *info->context(), *scope); @@ -930,8 +990,8 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, Scope** scope, if (!(*scope)->is_script_scope() || is_strict(info->language_mode())) { *scope = NewScope(*scope, EVAL_SCOPE); } - } else if (info->is_global()) { - *scope = NewScope(*scope, SCRIPT_SCOPE); + } else if (info->is_module()) { + *scope = NewScope(*scope, MODULE_SCOPE); } (*scope)->set_start_position(0); // End position will be set by the caller. @@ -955,19 +1015,13 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, Scope** scope, int beg_pos = scanner()->location().beg_pos; if (info->is_module()) { DCHECK(allow_harmony_modules()); - Statement* stmt = ParseModule(&ok); - if (ok) { - body->Add(stmt, zone()); - } + ParseModuleItemList(body, &ok); } else { ParseStatementList(body, Token::EOS, info->is_eval(), eval_scope, &ok); } if (ok && is_strict(language_mode())) { CheckStrictOctalLiteral(beg_pos, scanner()->location().end_pos, &ok); - } - - if (ok && allow_harmony_scoping() && is_strict(language_mode())) { CheckConflictingVarDeclarations(scope_, &ok); } @@ -1000,13 +1054,13 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, Scope** scope, } -FunctionLiteral* Parser::ParseLazy(CompilationInfo* info) { +FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* 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()); + HistogramTimerScope timer_scope(isolate->counters()->parse_lazy()); Handle<String> source(String::cast(info->script()->source())); - info->isolate()->counters()->total_parse_size()->Increment(source->length()); + isolate->counters()->total_parse_size()->Increment(source->length()); base::ElapsedTimer timer; if (FLAG_trace_parse) { timer.Start(); @@ -1021,12 +1075,12 @@ FunctionLiteral* Parser::ParseLazy(CompilationInfo* info) { Handle<ExternalTwoByteString>::cast(source), shared_info->start_position(), shared_info->end_position()); - result = ParseLazy(info, &stream); + result = ParseLazy(isolate, info, &stream); } else { GenericStringUtf16CharacterStream stream(source, shared_info->start_position(), shared_info->end_position()); - result = ParseLazy(info, &stream); + result = ParseLazy(isolate, info, &stream); } if (FLAG_trace_parse && result != NULL) { @@ -1038,7 +1092,7 @@ FunctionLiteral* Parser::ParseLazy(CompilationInfo* info) { } -FunctionLiteral* Parser::ParseLazy(CompilationInfo* info, +FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info, Utf16CharacterStream* source) { Handle<SharedFunctionInfo> shared_info = info->shared_info(); scanner_.Initialize(source); @@ -1059,12 +1113,12 @@ FunctionLiteral* Parser::ParseLazy(CompilationInfo* info, { // Parse the function literal. Scope* scope = NewScope(scope_, SCRIPT_SCOPE); - info->SetScriptScope(scope); + info->set_script_scope(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(), + scope = Scope::DeserializeScopeChain(isolate, zone(), info->closure()->context(), scope); } original_scope_ = scope; @@ -1088,8 +1142,24 @@ FunctionLiteral* Parser::ParseLazy(CompilationInfo* info, // from creating unresolved variables in already-resolved scopes. parsing_lazy_arrow_parameters_ = true; Expression* expression = ParseExpression(false, &ok); - DCHECK(expression->IsFunctionLiteral()); - result = expression->AsFunctionLiteral(); + if (ok) { + // Scanning must end at the same position that was recorded + // previously. If not, parsing has been interrupted due to a + // stack overflow, at which point the partially parsed arrow + // function concise body happens to be a valid expression. This + // is a problem only for arrow functions with single statement + // bodies, since there is no end token such as "}" for normal + // functions. + if (scanner()->location().end_pos == shared_info->end_position()) { + // The pre-parser saw an arrow function here, so the full parser + // must produce a FunctionLiteral. + DCHECK(expression->IsFunctionLiteral()); + result = expression->AsFunctionLiteral(); + } else { + result = NULL; + ok = false; + } + } } else if (shared_info->is_default_constructor()) { result = DefaultConstructor(IsSubclassConstructor(shared_info->kind()), scope, shared_info->start_position(), @@ -1135,8 +1205,27 @@ void* Parser::ParseStatementList(ZoneList<Statement*>* body, int end_token, directive_prologue = false; } + Token::Value token = peek(); Scanner::Location token_loc = scanner()->peek_location(); + Scanner::Location old_super_loc = function_state_->super_call_location(); Statement* stat = ParseStatementListItem(CHECK_OK); + Scanner::Location super_loc = function_state_->super_call_location(); + + if (is_strong(language_mode()) && + i::IsConstructor(function_state_->kind()) && + !old_super_loc.IsValid() && super_loc.IsValid() && + token != Token::SUPER) { + // TODO(rossberg): This is more permissive than spec'ed, it allows e.g. + // super(), 1; + // super() + ""; + // super() = 0; + // That should still be safe, though, thanks to left-to-right evaluation. + // The proper check would be difficult to implement in the preparser. + ReportMessageAt(super_loc, "strong_super_call_nested"); + *ok = false; + return NULL; + } + if (stat == NULL || stat->IsEmpty()) { directive_prologue = false; // End of directive prologue. continue; @@ -1229,7 +1318,6 @@ Statement* Parser::ParseStatementListItem(bool* ok) { case Token::VAR: return ParseVariableStatement(kStatementListItem, NULL, ok); case Token::LET: - DCHECK(allow_harmony_scoping()); if (is_strict(language_mode())) { return ParseVariableStatement(kStatementListItem, NULL, ok); } @@ -1258,7 +1346,7 @@ Statement* Parser::ParseModuleItem(bool* ok) { } -Statement* Parser::ParseModule(bool* ok) { +void* Parser::ParseModuleItemList(ZoneList<Statement*>* body, bool* ok) { // (Ecma 262 6th Edition, 15.2): // Module : // ModuleBody? @@ -1266,53 +1354,48 @@ Statement* Parser::ParseModule(bool* ok) { // ModuleBody : // ModuleItem* - Block* body = factory()->NewBlock(NULL, 16, false, RelocInfo::kNoPosition); - Scope* scope = NewScope(scope_, MODULE_SCOPE); - scope->set_start_position(scanner()->location().beg_pos); - scope->SetLanguageMode( - static_cast<LanguageMode>(scope->language_mode() | STRICT_BIT)); - - { - BlockState block_state(&scope_, scope); + DCHECK(scope_->is_module_scope()); + scope_->SetLanguageMode( + static_cast<LanguageMode>(scope_->language_mode() | STRICT_BIT)); - while (peek() != Token::EOS) { - Statement* stat = ParseModuleItem(CHECK_OK); - if (stat && !stat->IsEmpty()) { - body->AddStatement(stat, zone()); - } + while (peek() != Token::EOS) { + Statement* stat = ParseModuleItem(CHECK_OK); + if (stat && !stat->IsEmpty()) { + body->Add(stat, zone()); } } - scope->set_end_position(scanner()->location().end_pos); - body->set_scope(scope); - // Check that all exports are bound. - ModuleDescriptor* descriptor = scope->module(); + 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()); + if (scope_->LookupLocal(it.local_name()) == NULL) { + // TODO(adamk): Pass both local_name and export_name once ParserTraits + // supports multiple arg error messages. + // Also try to report this at a better location. + ParserTraits::ReportMessage("module_export_undefined", it.local_name()); *ok = false; return NULL; } } - scope->module()->Freeze(); - return body; + scope_->module()->Freeze(); + return NULL; } -Literal* Parser::ParseModuleSpecifier(bool* ok) { +const AstRawString* Parser::ParseModuleSpecifier(bool* ok) { // ModuleSpecifier : // StringLiteral - int pos = peek_position(); Expect(Token::STRING, CHECK_OK); - return factory()->NewStringLiteral(GetSymbol(scanner()), pos); + return GetSymbol(scanner()); } -void* Parser::ParseExportClause(ZoneList<const AstRawString*>* names, +void* Parser::ParseExportClause(ZoneList<const AstRawString*>* export_names, + ZoneList<Scanner::Location>* export_locations, + ZoneList<const AstRawString*>* local_names, Scanner::Location* reserved_loc, bool* ok) { // ExportClause : // '{' '}' @@ -1337,14 +1420,17 @@ void* Parser::ParseExportClause(ZoneList<const AstRawString*>* names, !Token::IsIdentifier(name_tok, STRICT, false)) { *reserved_loc = scanner()->location(); } - const AstRawString* name = ParseIdentifierName(CHECK_OK); - names->Add(name, zone()); + const AstRawString* local_name = ParseIdentifierName(CHECK_OK); 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 (export_name == NULL) { + export_name = local_name; + } + export_names->Add(export_name, zone()); + local_names->Add(local_name, zone()); + export_locations->Add(scanner()->location(), zone()); if (peek() == Token::RBRACE) break; Expect(Token::COMMA, CHECK_OK); } @@ -1355,8 +1441,7 @@ void* Parser::ParseExportClause(ZoneList<const AstRawString*>* names, } -void* Parser::ParseNamedImports(ZoneList<const AstRawString*>* names, - bool* ok) { +ZoneList<ImportDeclaration*>* Parser::ParseNamedImports(int pos, bool* ok) { // NamedImports : // '{' '}' // '{' ImportsList '}' @@ -1372,34 +1457,38 @@ void* Parser::ParseNamedImports(ZoneList<const AstRawString*>* names, 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; + ZoneList<ImportDeclaration*>* result = + new (zone()) ZoneList<ImportDeclaration*>(1, zone()); + while (peek() != Token::RBRACE) { + const AstRawString* import_name = ParseIdentifierName(CHECK_OK); + const AstRawString* local_name = import_name; // In the presence of 'as', the left-side of the 'as' can // be any IdentifierName. But without 'as', it must be a valid - // BindingIdentiifer. + // BindingIdentifier. if (CheckContextualKeyword(CStrVector("as"))) { - import_name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK); - } else if (!Token::IsIdentifier(name_tok, STRICT, false)) { + local_name = ParseIdentifierName(CHECK_OK); + } + if (!Token::IsIdentifier(scanner()->current_token(), STRICT, false)) { *ok = false; - ReportMessageAt(scanner()->location(), "unexpected_reserved"); + ReportMessage("unexpected_reserved"); return NULL; - } else if (IsEvalOrArguments(name)) { + } else if (IsEvalOrArguments(local_name)) { *ok = false; - ReportMessageAt(scanner()->location(), "strict_eval_arguments"); + ReportMessage("strict_eval_arguments"); return NULL; } - // TODO(ES6): Return the import_name as well as the name. - names->Add(name, zone()); - USE(import_name); + VariableProxy* proxy = NewUnresolved(local_name, IMPORT); + ImportDeclaration* declaration = + factory()->NewImportDeclaration(proxy, import_name, NULL, scope_, pos); + Declare(declaration, true, CHECK_OK); + result->Add(declaration, zone()); if (peek() == Token::RBRACE) break; Expect(Token::COMMA, CHECK_OK); } Expect(Token::RBRACE, CHECK_OK); - return NULL; + return result; } @@ -1425,32 +1514,39 @@ Statement* Parser::ParseImportDeclaration(bool* ok) { // 'import' ModuleSpecifier ';' if (tok == Token::STRING) { - ParseModuleSpecifier(CHECK_OK); + const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK); ExpectSemicolon(CHECK_OK); + // TODO(ES6): Add module to the requested modules of scope_->module(). + USE(module_specifier); return factory()->NewEmptyStatement(pos); } // Parse ImportedDefaultBinding if present. - const AstRawString* imported_default_binding = NULL; + ImportDeclaration* import_default_declaration = NULL; if (tok != Token::MUL && tok != Token::LBRACE) { - imported_default_binding = + const AstRawString* local_name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK); + VariableProxy* proxy = NewUnresolved(local_name, IMPORT); + import_default_declaration = factory()->NewImportDeclaration( + proxy, ast_value_factory()->default_string(), NULL, scope_, pos); + Declare(import_default_declaration, true, CHECK_OK); } const AstRawString* module_instance_binding = NULL; - ZoneList<const AstRawString*> names(1, zone()); - if (imported_default_binding == NULL || Check(Token::COMMA)) { + ZoneList<ImportDeclaration*>* named_declarations = NULL; + if (import_default_declaration == NULL || Check(Token::COMMA)) { switch (peek()) { case Token::MUL: { Consume(Token::MUL); ExpectContextualKeyword(CStrVector("as"), CHECK_OK); module_instance_binding = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK); + // TODO(ES6): Add an appropriate declaration. break; } case Token::LBRACE: - ParseNamedImports(&names, CHECK_OK); + named_declarations = ParseNamedImports(pos, CHECK_OK); break; default: @@ -1461,21 +1557,21 @@ Statement* Parser::ParseImportDeclaration(bool* ok) { } ExpectContextualKeyword(CStrVector("from"), CHECK_OK); - Literal* module = ParseModuleSpecifier(CHECK_OK); - USE(module); - + const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK); ExpectSemicolon(CHECK_OK); if (module_instance_binding != NULL) { - // TODO(ES6): Bind name to the Module Instance Object of module. + // TODO(ES6): Set the module specifier for the module namespace binding. } - if (imported_default_binding != NULL) { - // TODO(ES6): Add an appropriate declaration. + if (import_default_declaration != NULL) { + import_default_declaration->set_module_specifier(module_specifier); } - for (int i = 0; i < names.length(); ++i) { - // TODO(ES6): Add an appropriate declaration for each name + if (named_declarations != NULL) { + for (int i = 0; i < named_declarations->length(); ++i) { + named_declarations->at(i)->set_module_specifier(module_specifier); + } } return factory()->NewEmptyStatement(pos); @@ -1488,16 +1584,20 @@ Statement* Parser::ParseExportDefault(bool* ok) { // 'export' 'default' ClassDeclaration // 'export' 'default' AssignmentExpression[In] ';' + Expect(Token::DEFAULT, CHECK_OK); + Scanner::Location default_loc = scanner()->location(); + + ZoneList<const AstRawString*> names(1, zone()); Statement* result = NULL; switch (peek()) { case Token::FUNCTION: // TODO(ES6): Support parsing anonymous function declarations here. - result = ParseFunctionDeclaration(NULL, CHECK_OK); + result = ParseFunctionDeclaration(&names, CHECK_OK); break; case Token::CLASS: // TODO(ES6): Support parsing anonymous class declarations here. - result = ParseClassDeclaration(NULL, CHECK_OK); + result = ParseClassDeclaration(&names, CHECK_OK); break; default: { @@ -1509,7 +1609,20 @@ Statement* Parser::ParseExportDefault(bool* ok) { } } - // TODO(ES6): Add default export to scope_->module() + const AstRawString* default_string = ast_value_factory()->default_string(); + + DCHECK_LE(names.length(), 1); + if (names.length() == 1) { + scope_->module()->AddLocalExport(default_string, names.first(), zone(), ok); + if (!*ok) { + ParserTraits::ReportMessageAt(default_loc, "duplicate_export", + default_string); + return NULL; + } + } else { + // TODO(ES6): Assign result to a const binding with the name "*default*" + // and add an export entry with "*default*" as the local name. + } return result; } @@ -1528,23 +1641,18 @@ Statement* Parser::ParseExportDeclaration(bool* ok) { Statement* result = NULL; ZoneList<const AstRawString*> names(1, zone()); - bool is_export_from = false; switch (peek()) { 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); + const AstRawString* module_specifier = 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; + // TODO(ES6): scope_->module()->AddStarExport(...) + USE(module_specifier); + return factory()->NewEmptyStatement(pos); } case Token::LBRACE: { @@ -1560,13 +1668,14 @@ Statement* Parser::ParseExportDeclaration(bool* ok) { // 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); + ZoneList<const AstRawString*> export_names(1, zone()); + ZoneList<Scanner::Location> export_locations(1, zone()); + ZoneList<const AstRawString*> local_names(1, zone()); + ParseExportClause(&export_names, &export_locations, &local_names, + &reserved_loc, CHECK_OK); + const AstRawString* indirect_export_module_specifier = NULL; 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; + indirect_export_module_specifier = ParseModuleSpecifier(CHECK_OK); } else if (reserved_loc.IsValid()) { // No FromClause, so reserved words are invalid in ExportClause. *ok = false; @@ -1574,8 +1683,25 @@ Statement* Parser::ParseExportDeclaration(bool* ok) { return NULL; } ExpectSemicolon(CHECK_OK); - result = factory()->NewEmptyStatement(pos); - break; + const int length = export_names.length(); + DCHECK_EQ(length, local_names.length()); + DCHECK_EQ(length, export_locations.length()); + if (indirect_export_module_specifier == NULL) { + for (int i = 0; i < length; ++i) { + scope_->module()->AddLocalExport(export_names[i], local_names[i], + zone(), ok); + if (!*ok) { + ParserTraits::ReportMessageAt(export_locations[i], + "duplicate_export", export_names[i]); + return NULL; + } + } + } else { + for (int i = 0; i < length; ++i) { + // TODO(ES6): scope_->module()->AddIndirectExport(...);( + } + } + return factory()->NewEmptyStatement(pos); } case Token::FUNCTION: @@ -1598,37 +1724,18 @@ Statement* Parser::ParseExportDeclaration(bool* ok) { return NULL; } - // Every export of a module may be assigned. + // Extract declared names into export declarations. + ModuleDescriptor* descriptor = scope_->module(); for (int i = 0; i < names.length(); ++i) { - Variable* var = scope_->Lookup(names[i]); - if (var == NULL) { - // TODO(sigurds) This is an export that has no definition yet, - // not clear what to do in this case. - continue; - } - if (!IsImmutableVariableMode(var->mode())) { - var->set_maybe_assigned(); - } - } - - // 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); + descriptor->AddLocalExport(names[i], names[i], zone(), ok); + if (!*ok) { + // TODO(adamk): Possibly report this error at the right place. + ParserTraits::ReportMessage("duplicate_export", names[i]); + return NULL; } } - DCHECK(result != NULL); + DCHECK_NOT_NULL(result); return result; } @@ -1777,11 +1884,13 @@ VariableProxy* Parser::NewUnresolved(const AstRawString* name, // scope. // Let/const variables in harmony mode are always added to the immediately // enclosing scope. - return DeclarationScope(mode)->NewUnresolved(factory(), name, position()); + return DeclarationScope(mode)->NewUnresolved(factory(), name, + scanner()->location().beg_pos, + scanner()->location().end_pos); } -void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) { +Variable* Parser::Declare(Declaration* declaration, bool resolve, bool* ok) { VariableProxy* proxy = declaration->proxy(); DCHECK(proxy->raw_name() != NULL); const AstRawString* name = proxy->raw_name(); @@ -1807,10 +1916,14 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) { if (var == NULL) { // Declare the name. 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())) { + name, mode, declaration->initialization(), + declaration->IsFunctionDeclaration() ? Variable::FUNCTION + : Variable::NORMAL, + kNotAssigned); + } else if (IsLexicalVariableMode(mode) || + IsLexicalVariableMode(var->mode()) || + ((mode == CONST_LEGACY || var->mode() == CONST_LEGACY) && + !declaration_scope->is_script_scope())) { // The name was declared in this scope before; check for conflicting // re-declarations. We have a conflict if either of the declarations is // not a var (in script scope, we also have to ignore legacy const for @@ -1825,12 +1938,12 @@ 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() && is_strict(language_mode())) { + if (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); *ok = false; - return; + return nullptr; } Expression* expression = NewThrowTypeError( "var_redeclaration", name, declaration->position()); @@ -1862,7 +1975,7 @@ 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, + var = new (zone()) Variable(declaration_scope, name, mode, kind, kNeedsInitialization, kNotAssigned); } else if (declaration_scope->is_eval_scope() && is_sloppy(declaration_scope->language_mode())) { @@ -1871,7 +1984,7 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) { // 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, + var = new (zone()) Variable(declaration_scope, name, mode, kind, declaration->initialization(), kNotAssigned); var->AllocateTo(Variable::LOOKUP, -1); resolve = true; @@ -1904,6 +2017,7 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) { if (resolve && var != NULL) { proxy->BindTo(var); } + return var; } @@ -1975,12 +2089,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 = - 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; + is_strong(language_mode()) + ? CONST + : 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); @@ -2024,7 +2139,7 @@ Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names, Declaration* declaration = factory()->NewVariableDeclaration(proxy, mode, scope_, pos); Declare(declaration, true, CHECK_OK); - proxy->var()->set_initializer_position(pos); + proxy->var()->set_initializer_position(position()); Token::Value init_op = is_strong(language_mode()) ? Token::INIT_CONST : Token::INIT_LET; @@ -2037,7 +2152,7 @@ Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names, Block* Parser::ParseBlock(ZoneList<const AstRawString*>* labels, bool* ok) { - if (allow_harmony_scoping() && is_strict(language_mode())) { + if (is_strict(language_mode())) { return ParseScopedBlock(labels, ok); } @@ -2159,19 +2274,12 @@ Block* Parser::ParseVariableDeclarations( 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 && is_strict(language_mode())) { - DCHECK(allow_harmony_scoping()); Consume(Token::LET); DCHECK(var_context != kStatement); mode = LET; @@ -2233,7 +2341,9 @@ Block* Parser::ParseVariableDeclarations( VariableProxy* proxy = NewUnresolved(name, mode); Declaration* declaration = factory()->NewVariableDeclaration(proxy, mode, scope_, pos); - Declare(declaration, mode != VAR, CHECK_OK); + Variable* var = Declare(declaration, mode != VAR, CHECK_OK); + DCHECK_NOT_NULL(var); + DCHECK(!proxy->is_resolved() || proxy->var() == var); nvars++; if (declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) { ReportMessage("too_many_variables"); @@ -2287,11 +2397,11 @@ Block* Parser::ParseVariableDeclarations( fni_->RemoveLastFunction(); } if (decl_props != NULL) *decl_props = kHasInitializers; - } - - // Record the end position of the initializer. - if (proxy->is_resolved()) { - proxy->var()->set_initializer_position(position()); + // End position of the initializer is after the assignment expression. + var->set_initializer_position(scanner()->location().end_pos); + } else { + // End position of the initializer is after the variable. + var->set_initializer_position(position()); } // Make sure that 'const x' and 'let x' initialize 'x' to undefined. @@ -2610,6 +2720,7 @@ Statement* Parser::ParseReturnStatement(bool* ok) { // reported (underlining). Expect(Token::RETURN, CHECK_OK); Scanner::Location loc = scanner()->location(); + function_state_->set_return_location(loc); Token::Value tok = peek(); Statement* result; @@ -2624,6 +2735,14 @@ Statement* Parser::ParseReturnStatement(bool* ok) { return_value = GetLiteralUndefined(position()); } } else { + if (is_strong(language_mode()) && + i::IsConstructor(function_state_->kind())) { + int pos = peek_position(); + ReportMessageAt(Scanner::Location(pos, pos + 1), + "strong_constructor_return_value"); + *ok = false; + return NULL; + } return_value = ParseExpression(true, CHECK_OK); } ExpectSemicolon(CHECK_OK); @@ -2680,8 +2799,8 @@ Statement* Parser::ParseWithStatement(ZoneList<const AstRawString*>* labels, CaseClause* Parser::ParseCaseClause(bool* default_seen_ptr, bool* ok) { // CaseClause :: - // 'case' Expression ':' Statement* - // 'default' ':' Statement* + // 'case' Expression ':' StatementList + // 'default' ':' StatementList Expression* label = NULL; // NULL expression indicates default case if (peek() == Token::CASE) { @@ -2703,7 +2822,7 @@ CaseClause* Parser::ParseCaseClause(bool* default_seen_ptr, bool* ok) { while (peek() != Token::CASE && peek() != Token::DEFAULT && peek() != Token::RBRACE) { - Statement* stat = ParseStatement(NULL, CHECK_OK); + Statement* stat = ParseStatementListItem(CHECK_OK); statements->Add(stat, zone()); } @@ -2796,7 +2915,8 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { Expect(Token::RPAREN, CHECK_OK); - catch_variable = catch_scope->DeclareLocal(name, VAR, kCreatedInitialized); + catch_variable = catch_scope->DeclareLocal(name, VAR, kCreatedInitialized, + Variable::NORMAL); BlockState block_state(&scope_, catch_scope); catch_block = ParseBlock(NULL, CHECK_OK); @@ -2910,25 +3030,51 @@ void Parser::InitializeForEachStatement(ForEachStatement* stmt, Expression* result_done; Expression* assign_each; - // var iterator = subject[Symbol.iterator](); + // iterator = subject[Symbol.iterator]() assign_iterator = factory()->NewAssignment( Token::ASSIGN, factory()->NewVariableProxy(iterator), GetIterator(subject, factory()), subject->position()); - // var result = iterator.next(); + // !%_IsSpecObject(result = iterator.next()) && + // %ThrowIteratorResultNotAnObject(result) { + // result = iterator.next() Expression* iterator_proxy = factory()->NewVariableProxy(iterator); Expression* next_literal = factory()->NewStringLiteral( ast_value_factory()->next_string(), RelocInfo::kNoPosition); Expression* next_property = factory()->NewProperty( iterator_proxy, next_literal, RelocInfo::kNoPosition); ZoneList<Expression*>* next_arguments = - new(zone()) ZoneList<Expression*>(0, zone()); + new (zone()) ZoneList<Expression*>(0, zone()); Expression* next_call = factory()->NewCall(next_property, next_arguments, subject->position()); Expression* result_proxy = factory()->NewVariableProxy(result); next_result = factory()->NewAssignment(Token::ASSIGN, result_proxy, next_call, subject->position()); + + // %_IsSpecObject(...) + ZoneList<Expression*>* is_spec_object_args = + new (zone()) ZoneList<Expression*>(1, zone()); + is_spec_object_args->Add(next_result, zone()); + Expression* is_spec_object_call = factory()->NewCallRuntime( + ast_value_factory()->is_spec_object_string(), + Runtime::FunctionForId(Runtime::kInlineIsSpecObject), + is_spec_object_args, subject->position()); + + // %ThrowIteratorResultNotAnObject(result) + Expression* result_proxy_again = factory()->NewVariableProxy(result); + ZoneList<Expression*>* throw_arguments = + new (zone()) ZoneList<Expression*>(1, zone()); + throw_arguments->Add(result_proxy_again, zone()); + Expression* throw_call = factory()->NewCallRuntime( + ast_value_factory()->throw_iterator_result_not_an_object_string(), + Runtime::FunctionForId(Runtime::kThrowIteratorResultNotAnObject), + throw_arguments, subject->position()); + + next_result = factory()->NewBinaryOperation( + Token::AND, factory()->NewUnaryOperation( + Token::NOT, is_spec_object_call, subject->position()), + throw_call, subject->position()); } // result.done @@ -2962,8 +3108,8 @@ void Parser::InitializeForEachStatement(ForEachStatement* stmt, } -Statement* Parser::DesugarLetBindingsInForStatement( - Scope* inner_scope, ZoneList<const AstRawString*>* names, +Statement* Parser::DesugarLexicalBindingsInForStatement( + Scope* inner_scope, bool is_const, ZoneList<const AstRawString*>* names, ForStatement* loop, Statement* init, Expression* cond, Statement* next, Statement* body, bool* ok) { // ES6 13.6.3.4 specifies that on each loop iteration the let variables are @@ -2973,16 +3119,16 @@ Statement* Parser::DesugarLetBindingsInForStatement( // // We rewrite a for statement of the form // - // labels: for (let x = i; cond; next) body + // labels: for (let/const x = i; cond; next) body // // into // // { - // let x = i; + // let/const x = i; // temp_x = x; // first = 1; // outer: for (;;) { - // let x = temp_x; + // let/const x = temp_x; // if (first == 1) { // first = 0; // } else { @@ -3009,12 +3155,12 @@ Statement* Parser::DesugarLetBindingsInForStatement( Block* outer_block = factory()->NewBlock(NULL, names->length() + 3, false, RelocInfo::kNoPosition); - // Add statement: let x = i. + // Add statement: let/const x = i. outer_block->AddStatement(init, zone()); const AstRawString* temp_name = ast_value_factory()->dot_for_string(); - // For each let variable x: + // For each lexical variable x: // make statement: temp_x = x. for (int i = 0; i < names->length(); i++) { VariableProxy* proxy = NewUnresolved(names->at(i), LET); @@ -3055,23 +3201,24 @@ Statement* Parser::DesugarLetBindingsInForStatement( Block* inner_block = factory()->NewBlock(NULL, names->length() + 4, false, RelocInfo::kNoPosition); - int pos = scanner()->location().beg_pos; ZoneList<Variable*> inner_vars(names->length(), zone()); // For each let variable x: - // make statement: let x = temp_x. + // make statement: let/const x = temp_x. + VariableMode mode = is_const ? CONST : LET; for (int i = 0; i < names->length(); i++) { - VariableProxy* proxy = NewUnresolved(names->at(i), LET); - Declaration* declaration = - factory()->NewVariableDeclaration(proxy, LET, scope_, pos); + VariableProxy* proxy = NewUnresolved(names->at(i), mode); + Declaration* declaration = factory()->NewVariableDeclaration( + proxy, mode, scope_, RelocInfo::kNoPosition); Declare(declaration, true, CHECK_OK); inner_vars.Add(declaration->proxy()->var(), zone()); VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i)); - Assignment* assignment = factory()->NewAssignment( - Token::INIT_LET, proxy, temp_proxy, pos); - Statement* assignment_statement = factory()->NewExpressionStatement( - assignment, pos); - proxy->var()->set_initializer_position(pos); + Assignment* assignment = + factory()->NewAssignment(is_const ? Token::INIT_CONST : Token::INIT_LET, + proxy, temp_proxy, RelocInfo::kNoPosition); + Statement* assignment_statement = + factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition); + proxy->var()->set_initializer_position(init->position()); inner_block->AddStatement(assignment_statement, zone()); } @@ -3083,8 +3230,8 @@ Statement* Parser::DesugarLetBindingsInForStatement( { Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition); VariableProxy* first_proxy = factory()->NewVariableProxy(first); - compare = - factory()->NewCompareOperation(Token::EQ, first_proxy, const1, pos); + compare = factory()->NewCompareOperation(Token::EQ, first_proxy, const1, + RelocInfo::kNoPosition); } Statement* clear_first = NULL; // Make statement: first = 0. @@ -3096,8 +3243,8 @@ Statement* Parser::DesugarLetBindingsInForStatement( clear_first = factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition); } - Statement* clear_first_or_next = factory()->NewIfStatement( - compare, clear_first, next, RelocInfo::kNoPosition); + Statement* clear_first_or_next = + factory()->NewIfStatement(compare, clear_first, next, next->position()); inner_block->AddStatement(clear_first_or_next, zone()); } @@ -3118,8 +3265,8 @@ Statement* Parser::DesugarLetBindingsInForStatement( { Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition); VariableProxy* flag_proxy = factory()->NewVariableProxy(flag); - flag_cond = - factory()->NewCompareOperation(Token::EQ, flag_proxy, const1, pos); + flag_cond = factory()->NewCompareOperation(Token::EQ, flag_proxy, const1, + RelocInfo::kNoPosition); } // Create chain of expressions "flag = 0, temp_x = x, ..." @@ -3135,9 +3282,11 @@ Statement* Parser::DesugarLetBindingsInForStatement( } // Make the comma-separated list of temp_x = x assignments. + int inner_var_proxy_pos = scanner()->location().beg_pos; for (int i = 0; i < names->length(); i++) { VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i)); - VariableProxy* proxy = factory()->NewVariableProxy(inner_vars.at(i), pos); + VariableProxy* proxy = + factory()->NewVariableProxy(inner_vars.at(i), inner_var_proxy_pos); Assignment* assignment = factory()->NewAssignment( Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition); compound_next = factory()->NewBinaryOperation( @@ -3171,8 +3320,8 @@ Statement* Parser::DesugarLetBindingsInForStatement( { Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition); VariableProxy* flag_proxy = factory()->NewVariableProxy(flag); - compare = - factory()->NewCompareOperation(Token::EQ, flag_proxy, const1, pos); + compare = factory()->NewCompareOperation(Token::EQ, flag_proxy, const1, + RelocInfo::kNoPosition); } Statement* stop = factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition); @@ -3197,8 +3346,9 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement int stmt_pos = peek_position(); + bool is_const = false; Statement* init = NULL; - ZoneList<const AstRawString*> let_bindings(1, zone()); + ZoneList<const AstRawString*> lexical_bindings(1, zone()); // Create an in-between scope for let-bound iteration variables. Scope* saved_scope = scope_; @@ -3219,7 +3369,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, CHECK_OK); bool accept_OF = decl_props == kHasNoInitializers; ForEachStatement::VisitMode mode; - int each_pos = position(); + int each_beg_pos = scanner()->location().beg_pos; + int each_end_pos = scanner()->location().end_pos; if (name != NULL && CheckInOrOf(accept_OF, &mode, ok)) { if (!*ok) return nullptr; @@ -3230,7 +3381,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, each_pos); + VariableProxy* each = + scope_->NewUnresolved(factory(), name, each_beg_pos, each_end_pos); Statement* body = ParseSubStatement(NULL, CHECK_OK); InitializeForEachStatement(loop, each, enumerable, body); Block* result = @@ -3248,16 +3400,17 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, } } else if ((peek() == Token::LET || peek() == Token::CONST) && is_strict(language_mode())) { - bool is_const = peek() == Token::CONST; + is_const = peek() == Token::CONST; const AstRawString* name = NULL; VariableDeclarationProperties decl_props = kHasNoInitializers; Block* variable_statement = - ParseVariableDeclarations(kForStatement, &decl_props, &let_bindings, - &name, CHECK_OK); + ParseVariableDeclarations(kForStatement, &decl_props, + &lexical_bindings, &name, CHECK_OK); bool accept_IN = name != NULL && decl_props != kHasInitializers; bool accept_OF = decl_props == kHasNoInitializers; ForEachStatement::VisitMode mode; - int each_pos = position(); + int each_beg_pos = scanner()->location().beg_pos; + int each_end_pos = scanner()->location().end_pos; if (accept_IN && CheckInOrOf(accept_OF, &mode, ok)) { if (!*ok) return nullptr; @@ -3279,7 +3432,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, // implementing stack allocated block scoped variables. Variable* temp = scope_->DeclarationScope()->NewTemporary( ast_value_factory()->dot_for_string()); - VariableProxy* temp_proxy = factory()->NewVariableProxy(temp, each_pos); + VariableProxy* temp_proxy = + factory()->NewVariableProxy(temp, each_beg_pos, each_end_pos); ForEachStatement* loop = factory()->NewForEachStatement(mode, labels, stmt_pos); Target target(&this->target_stack_, loop); @@ -3290,7 +3444,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, scope_ = for_scope; Expect(Token::RPAREN, CHECK_OK); - VariableProxy* each = scope_->NewUnresolved(factory(), name, each_pos); + VariableProxy* each = + scope_->NewUnresolved(factory(), name, each_beg_pos, each_end_pos); Statement* body = ParseSubStatement(NULL, CHECK_OK); Block* body_block = factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition); @@ -3367,7 +3522,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, // If there are let bindings, then condition and the next statement of the // for loop must be parsed in a new scope. Scope* inner_scope = NULL; - if (let_bindings.length() > 0) { + if (lexical_bindings.length() > 0) { inner_scope = NewScope(for_scope, BLOCK_SCOPE); inner_scope->set_start_position(scanner()->location().beg_pos); scope_ = inner_scope; @@ -3390,10 +3545,11 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels, Statement* body = ParseSubStatement(NULL, CHECK_OK); Statement* result = NULL; - if (let_bindings.length() > 0) { + if (lexical_bindings.length() > 0) { scope_ = for_scope; - result = DesugarLetBindingsInForStatement(inner_scope, &let_bindings, loop, - init, cond, next, body, CHECK_OK); + result = DesugarLexicalBindingsInForStatement( + inner_scope, is_const, &lexical_bindings, loop, init, cond, + next, body, CHECK_OK); scope_ = saved_scope; for_scope->set_end_position(scanner()->location().end_pos); } else { @@ -3512,6 +3668,10 @@ bool CheckAndDeclareArrowParameter(ParserTraits* traits, Expression* expression, return false; } + // When the variable was seen, it was recorded as unresolved in the outer + // scope. But it's really not unresolved. + scope->outer_scope()->RemoveUnresolved(expression->AsVariableProxy()); + scope->DeclareParameter(raw_name, VAR); ++(*num_params); return true; @@ -3609,13 +3769,12 @@ FunctionLiteral* Parser::ParseFunctionLiteral( // nested function, and hoisting works normally relative to that. Scope* declaration_scope = scope_->DeclarationScope(); Scope* original_declaration_scope = original_scope_->DeclarationScope(); - Scope* scope = - function_type == FunctionLiteral::DECLARATION && - (!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); + Scope* scope = function_type == FunctionLiteral::DECLARATION && + 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; @@ -3723,16 +3882,15 @@ 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() && is_strict(language_mode())) { + if (is_strict(language_mode())) { fvar_init_op = Token::INIT_CONST; } VariableMode fvar_mode = - allow_harmony_scoping() && is_strict(language_mode()) ? CONST - : CONST_LEGACY; + 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); + Variable(scope_, function_name, fvar_mode, Variable::NORMAL, + kCreatedInitialized, kNotAssigned); VariableProxy* proxy = factory()->NewVariableProxy(fvar); VariableDeclaration* fvar_declaration = factory()->NewVariableDeclaration( proxy, fvar_mode, scope_, RelocInfo::kNoPosition); @@ -3802,9 +3960,17 @@ FunctionLiteral* Parser::ParseFunctionLiteral( CheckStrictOctalLiteral(scope->start_position(), scope->end_position(), CHECK_OK); } - if (allow_harmony_scoping() && is_strict(language_mode())) { + if (is_strict(language_mode())) { CheckConflictingVarDeclarations(scope, CHECK_OK); } + if (is_strong(language_mode()) && IsSubclassConstructor(kind)) { + if (!function_state.super_call_location().IsValid()) { + ReportMessageAt(function_name_location, "strong_super_call_missing", + kReferenceError); + *ok = false; + return nullptr; + } + } } FunctionLiteral* function_literal = factory()->NewFunctionLiteral( @@ -3870,7 +4036,7 @@ void Parser::SkipLazyFunctionBody(const AstRawString* function_name, if (logger.has_error()) { ParserTraits::ReportMessageAt( Scanner::Location(logger.start(), logger.end()), logger.message(), - logger.argument_opt(), logger.is_reference_error()); + logger.argument_opt(), logger.error_type()); *ok = false; return; } @@ -4002,7 +4168,6 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser( 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()); reusable_preparser_->set_allow_harmony_modules(allow_harmony_modules()); reusable_preparser_->set_allow_harmony_arrow_functions( allow_harmony_arrow_functions()); @@ -4011,7 +4176,6 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser( reusable_preparser_->set_allow_harmony_classes(allow_harmony_classes()); reusable_preparser_->set_allow_harmony_object_literals( allow_harmony_object_literals()); - 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()); reusable_preparser_->set_allow_harmony_computed_property_names( @@ -4045,7 +4209,11 @@ ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name, return NULL; } + // Create a block scope which is additionally tagged as class scope; this is + // important for resolving variable references to the class name in the strong + // mode. Scope* block_scope = NewScope(scope_, BLOCK_SCOPE); + block_scope->tag_as_class_scope(); BlockState block_state(&scope_, block_scope); scope_->SetLanguageMode( static_cast<LanguageMode>(scope_->language_mode() | STRICT_BIT)); @@ -4074,6 +4242,7 @@ ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name, 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; @@ -4108,12 +4277,14 @@ ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name, } block_scope->set_end_position(end_pos); - block_scope = block_scope->FinalizeBlockScope(); if (name != NULL) { DCHECK_NOT_NULL(proxy); - DCHECK_NOT_NULL(block_scope); proxy->var()->set_initializer_position(end_pos); + } else { + // Unnamed classes should not have scopes (the scope will be empty). + DCHECK_EQ(block_scope->num_var_or_const(), 0); + block_scope = nullptr; } return factory()->NewClassLiteral(name, block_scope, proxy, extends, @@ -4239,79 +4410,30 @@ IterationStatement* Parser::LookupContinueTarget(const AstRawString* label, } -void Parser::HandleSourceURLComments(CompilationInfo* info) { +void Parser::HandleSourceURLComments(Isolate* isolate, Handle<Script> script) { if (scanner_.source_url()->length() > 0) { - Handle<String> source_url = - scanner_.source_url()->Internalize(info->isolate()); - info->script()->set_source_url(*source_url); + Handle<String> source_url = scanner_.source_url()->Internalize(isolate); + script->set_source_url(*source_url); } if (scanner_.source_mapping_url()->length() > 0) { Handle<String> source_mapping_url = - scanner_.source_mapping_url()->Internalize(info->isolate()); - info->script()->set_source_mapping_url(*source_mapping_url); + scanner_.source_mapping_url()->Internalize(isolate); + script->set_source_mapping_url(*source_mapping_url); } } -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, - pending_error_location_.end_pos); - 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); - if (pending_error_arg_ != NULL) { - Handle<String> arg_string = pending_error_arg_->string(); - elements->set(0, *arg_string); - } else if (pending_error_char_arg_ != NULL) { - Handle<String> arg_string = - factory->NewStringFromUtf8(CStrVector(pending_error_char_arg_)) - .ToHandleChecked(); - elements->set(0, *arg_string); - } - isolate->debug()->OnCompileError(script); - - Handle<JSArray> array = factory->NewJSArrayWithElements(elements); - Handle<Object> error; - MaybeHandle<Object> maybe_error = - pending_error_is_reference_error_ - ? factory->NewReferenceError(pending_error_message_, array) - : factory->NewSyntaxError(pending_error_message_, array); - - 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(CompilationInfo* info) { +void Parser::Internalize(Isolate* isolate, Handle<Script> script, bool error) { // Internalize strings. - ast_value_factory()->Internalize(info->isolate()); + ast_value_factory()->Internalize(isolate); // Error processing. - if (info->function() == NULL) { + if (error) { if (stack_overflow()) { - info->isolate()->StackOverflow(); + isolate->StackOverflow(); } else { - ThrowPendingError(info->isolate(), info->script()); + DCHECK(pending_error_handler_.has_pending_error()); + pending_error_handler_.ThrowPendingError(isolate, script); } } @@ -4319,10 +4441,10 @@ void Parser::Internalize(CompilationInfo* info) { for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount; ++feature) { for (int i = 0; i < use_counts_[feature]; ++i) { - info->isolate()->CountUsage(v8::Isolate::UseCounterFeature(feature)); + isolate->CountUsage(v8::Isolate::UseCounterFeature(feature)); } } - info->isolate()->counters()->total_preparse_skipped()->Increment( + isolate->counters()->total_preparse_skipped()->Increment( total_preparse_skipped_); } @@ -5240,20 +5362,17 @@ bool RegExpParser::ParseRegExp(Isolate* isolate, Zone* zone, } -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); +bool Parser::ParseStatic(ParseInfo* info) { + Parser parser(info); if (parser.Parse(info)) { - info->SetLanguageMode(info->function()->language_mode()); + info->set_language_mode(info->function()->language_mode()); return true; } return false; } -bool Parser::Parse(CompilationInfo* info) { +bool Parser::Parse(ParseInfo* info) { DCHECK(info->function() == NULL); FunctionLiteral* result = NULL; // Ok to use Isolate here; this function is only called in the main thread. @@ -5270,23 +5389,23 @@ bool Parser::Parse(CompilationInfo* info) { if (info->is_lazy()) { DCHECK(!info->is_eval()); if (info->shared_info()->is_function()) { - result = ParseLazy(info); + result = ParseLazy(isolate, info); } else { - result = ParseProgram(info); + result = ParseProgram(isolate, info); } } else { SetCachedData(info); - result = ParseProgram(info); + result = ParseProgram(isolate, info); } - info->SetFunction(result); + info->set_literal(result); - Internalize(info); + Internalize(isolate, info->script(), result == NULL); DCHECK(ast_value_factory()->IsInternalized()); return (result != NULL); } -void Parser::ParseOnBackground(CompilationInfo* info) { +void Parser::ParseOnBackground(ParseInfo* info) { parsing_on_main_thread_ = false; DCHECK(info->function() == NULL); @@ -5317,7 +5436,7 @@ void Parser::ParseOnBackground(CompilationInfo* info) { eval_scope->set_end_position(scanner()->location().end_pos); } - info->SetFunction(result); + info->set_literal(result); // We cannot internalize on a background thread; a foreground task will take // care of calling Parser::Internalize just before compilation. @@ -5363,27 +5482,24 @@ Expression* Parser::CloseTemplateLiteral(TemplateLiteralState* state, int start, if (!tag) { // Build tree of BinaryOps to simplify code-generation - Expression* expr = NULL; + Expression* expr = cooked_strings->at(0); + int i = 0; + while (i < expressions->length()) { + Expression* sub = expressions->at(i++); + Expression* cooked_str = cooked_strings->at(i); + + // Let middle be ToString(sub). + ZoneList<Expression*>* args = + new (zone()) ZoneList<Expression*>(1, zone()); + args->Add(sub, zone()); + Expression* middle = factory()->NewCallRuntime( + ast_value_factory()->to_string_string(), NULL, args, + sub->position()); - if (expressions->length() == 0) { - // Simple case: treat as string literal - expr = cooked_strings->at(0); - } else { - int i; - Expression* cooked_str = cooked_strings->at(0); expr = factory()->NewBinaryOperation( - Token::ADD, cooked_str, expressions->at(0), cooked_str->position()); - for (i = 1; i < expressions->length(); ++i) { - cooked_str = cooked_strings->at(i); - expr = factory()->NewBinaryOperation( - Token::ADD, expr, factory()->NewBinaryOperation( - Token::ADD, cooked_str, expressions->at(i), - cooked_str->position()), - cooked_str->position()); - } - cooked_str = cooked_strings->at(i); - expr = factory()->NewBinaryOperation(Token::ADD, expr, cooked_str, - cooked_str->position()); + Token::ADD, factory()->NewBinaryOperation( + Token::ADD, expr, middle, expr->position()), + cooked_str, sub->position()); } return expr; } else { |