summaryrefslogtreecommitdiff
path: root/deps/v8/src/parser.cc
diff options
context:
space:
mode:
authorChris Dickinson <christopher.s.dickinson@gmail.com>2015-05-05 13:48:55 -0700
committerRod Vagg <rod@vagg.org>2015-08-04 11:56:09 -0700
commitd58e780504bdba6c5897c48428fd984c5b5f96fe (patch)
tree033f1568ae3f9f077aceb843b42eb1ed1739ce0f /deps/v8/src/parser.cc
parent21d31c08e7d0b6865e52452750b20b05e6dca443 (diff)
downloadnode-new-d58e780504bdba6c5897c48428fd984c5b5f96fe.tar.gz
deps: update v8 to 4.3.61.21
* @indutny's SealHandleScope patch (484bebc38319fc7c622478037922ad73b2edcbf9) has been cherry picked onto the top of V8 to make it compile. * There's some test breakage in contextify. * This was merged at the request of the TC. PR-URL: https://github.com/iojs/io.js/pull/1632
Diffstat (limited to 'deps/v8/src/parser.cc')
-rw-r--r--deps/v8/src/parser.cc850
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 {