Block* Parser::DeclarationParsingResult::BuildInitializationBlock(
ZoneList<const AstRawString*>* names, bool* ok) {
- Block* result =
- descriptor.parser->factory()->NewBlock(NULL, 1, true, descriptor.pos);
+ Block* result = descriptor.parser->factory()->NewBlock(
+ NULL, 1, true, descriptor.declaration_pos);
for (auto declaration : declarations) {
PatternRewriter::DeclareAndInitializeVariables(
result, &descriptor, &declaration, names, CHECK_OK);
// BindingPattern '=' AssignmentExpression
parsing_result->descriptor.parser = this;
- parsing_result->descriptor.pos = peek_position();
+ parsing_result->descriptor.declaration_pos = peek_position();
+ parsing_result->descriptor.initialization_pos = peek_position();
parsing_result->descriptor.mode = VAR;
// True if the binding needs initialization. 'let' and 'const' declared
// bindings are created uninitialized by their declaration nodes and
bool is_let_identifier_expression = false;
DeclarationParsingResult parsing_result;
if (peek() != Token::SEMICOLON) {
- if (peek() == Token::VAR ||
- (peek() == Token::CONST && is_sloppy(language_mode()))) {
+ if (peek() == Token::VAR || peek() == Token::CONST ||
+ (peek() == Token::LET && is_strict(language_mode()))) {
ParseVariableDeclarations(kForStatement, &parsing_result, CHECK_OK);
- Block* variable_statement =
- parsing_result.BuildInitializationBlock(nullptr, CHECK_OK);
+ is_const = parsing_result.descriptor.mode == CONST;
int num_decl = parsing_result.declarations.length();
bool accept_IN = num_decl >= 1;
*ok = false;
return nullptr;
}
- ForEachStatement* loop =
- factory()->NewForEachStatement(mode, labels, stmt_pos);
- Target target(&this->target_stack_, loop);
- Expression* enumerable = ParseExpression(true, CHECK_OK);
- Expect(Token::RPAREN, CHECK_OK);
-
- VariableProxy* each =
- scope_->NewUnresolved(factory(), parsing_result.SingleName(),
- Variable::NORMAL, each_beg_pos, each_end_pos);
- Statement* body = ParseSubStatement(NULL, CHECK_OK);
- InitializeForEachStatement(loop, each, enumerable, body);
- Block* result =
- factory()->NewBlock(NULL, 2, false, RelocInfo::kNoPosition);
- result->AddStatement(variable_statement, zone());
- result->AddStatement(loop, zone());
- scope_ = saved_scope;
- for_scope->set_end_position(scanner()->location().end_pos);
- for_scope = for_scope->FinalizeBlockScope();
- DCHECK(for_scope == NULL);
- // Parsed for-in loop w/ variable/const declaration.
- return result;
- } else {
- init = variable_statement;
- }
- } else if ((peek() == Token::LET || peek() == Token::CONST) &&
- is_strict(language_mode())) {
- is_const = peek() == Token::CONST;
- ParseVariableDeclarations(kForStatement, &parsing_result, CHECK_OK);
- DCHECK(parsing_result.descriptor.pos != RelocInfo::kNoPosition);
-
- int num_decl = parsing_result.declarations.length();
- bool accept_IN = num_decl >= 1;
- bool accept_OF = true;
- ForEachStatement::VisitMode mode;
- 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;
- if (num_decl != 1) {
- const char* loop_type =
- mode == ForEachStatement::ITERATE ? "for-of" : "for-in";
- ParserTraits::ReportMessageAt(
- parsing_result.bindings_loc,
- MessageTemplate::kForInOfLoopMultiBindings, loop_type);
- *ok = false;
- return nullptr;
- }
- if (parsing_result.first_initializer_loc.IsValid() &&
- (is_strict(language_mode()) || mode == ForEachStatement::ITERATE)) {
- if (mode == ForEachStatement::ITERATE) {
- ReportMessageAt(parsing_result.first_initializer_loc,
- MessageTemplate::kForOfLoopInitializer);
- } else {
- ReportMessageAt(parsing_result.first_initializer_loc,
- MessageTemplate::kForInLoopInitializer);
- }
- *ok = false;
- return nullptr;
+ DCHECK(parsing_result.declarations.length() == 1);
+ Block* init_block = nullptr;
+
+ // special case for legacy for (var/const x =.... in)
+ if (is_sloppy(language_mode()) &&
+ !IsLexicalVariableMode(parsing_result.descriptor.mode) &&
+ parsing_result.declarations[0].initializer != nullptr) {
+ VariableProxy* single_var = scope_->NewUnresolved(
+ factory(), parsing_result.SingleName(), Variable::NORMAL,
+ each_beg_pos, each_end_pos);
+ init_block = factory()->NewBlock(
+ nullptr, 2, true, parsing_result.descriptor.declaration_pos);
+ init_block->AddStatement(
+ factory()->NewExpressionStatement(
+ factory()->NewAssignment(
+ Token::ASSIGN, single_var,
+ parsing_result.declarations[0].initializer,
+ RelocInfo::kNoPosition),
+ RelocInfo::kNoPosition),
+ zone());
}
- // Rewrite a for-in statement of the form
+
+ // Rewrite a for-in/of statement of the form
//
- // for (let/const x in e) b
+ // for (let/const/var x in/of e) b
//
// into
//
// <let x' be a temporary variable>
- // for (x' in e) {
- // let/const x;
+ // for (x' in/of e) {
+ // let/const/var x;
// x = x';
// b;
// }
- // TODO(keuchel): Move the temporary variable to the block scope, after
- // implementing stack allocated block scoped variables.
Variable* temp = scope_->DeclarationScope()->NewTemporary(
ast_value_factory()->dot_for_string());
- 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);
- // The expression does not see the loop variable.
+ // The expression does not see the lexical loop variables.
scope_ = saved_scope;
Expression* enumerable = ParseExpression(true, CHECK_OK);
scope_ = for_scope;
Expect(Token::RPAREN, CHECK_OK);
Statement* body = ParseSubStatement(NULL, CHECK_OK);
+
Block* body_block =
factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition);
- auto each_initialization_block = factory()->NewBlock(
- nullptr, 1, true, parsing_result.descriptor.pos);
+ auto each_initialization_block =
+ factory()->NewBlock(nullptr, 1, true, RelocInfo::kNoPosition);
{
DCHECK(parsing_result.declarations.length() == 1);
DeclarationParsingResult::Declaration decl =
parsing_result.declarations[0];
- decl.initializer = temp_proxy;
+ auto descriptor = parsing_result.descriptor;
+ descriptor.declaration_pos = RelocInfo::kNoPosition;
+ decl.initializer = factory()->NewVariableProxy(temp);
+
PatternRewriter::DeclareAndInitializeVariables(
- each_initialization_block, &parsing_result.descriptor, &decl,
- &lexical_bindings, CHECK_OK);
+ each_initialization_block, &descriptor, &decl,
+ IsLexicalVariableMode(descriptor.mode) ? &lexical_bindings
+ : nullptr,
+ CHECK_OK);
}
body_block->AddStatement(each_initialization_block, zone());
body_block->AddStatement(body, zone());
+ VariableProxy* temp_proxy =
+ factory()->NewVariableProxy(temp, each_beg_pos, each_end_pos);
InitializeForEachStatement(loop, temp_proxy, enumerable, body_block);
scope_ = saved_scope;
for_scope->set_end_position(scanner()->location().end_pos);
for_scope = for_scope->FinalizeBlockScope();
- body_block->set_scope(for_scope);
- // Parsed for-in loop w/ let declaration.
- return loop;
+ if (for_scope != nullptr) {
+ body_block->set_scope(for_scope);
+ }
+ // Parsed for-in loop w/ variable declarations.
+ if (init_block != nullptr) {
+ init_block->AddStatement(loop, zone());
+ return init_block;
+ } else {
+ return loop;
+ }
} else {
- init = parsing_result.BuildInitializationBlock(&lexical_bindings,
- CHECK_OK);
+ init = parsing_result.BuildInitializationBlock(
+ IsLexicalVariableMode(parsing_result.descriptor.mode)
+ ? &lexical_bindings
+ : nullptr,
+ CHECK_OK);
}
} else {
Scanner::Location lhs_location = scanner()->peek_location();
ForEachStatement::VisitMode mode;
bool accept_OF = expression->IsVariableProxy();
is_let_identifier_expression =
- expression->IsVariableProxy() &&
- expression->AsVariableProxy()->raw_name() ==
- ast_value_factory()->let_string();
+ expression->IsVariableProxy() &&
+ expression->AsVariableProxy()->raw_name() ==
+ ast_value_factory()->let_string();
if (CheckInOrOf(accept_OF, &mode, ok)) {
if (!*ok) return nullptr;
VariableMode mode;
bool is_const;
bool needs_init;
- int pos;
+ int declaration_pos;
+ int initialization_pos;
Token::Value init_op;
};
const AstRawString* name = pattern->raw_name();
VariableProxy* proxy = parser->NewUnresolved(name, descriptor_->mode);
Declaration* declaration = factory()->NewVariableDeclaration(
- proxy, descriptor_->mode, descriptor_->scope, descriptor_->pos);
+ proxy, descriptor_->mode, descriptor_->scope,
+ descriptor_->declaration_pos);
Variable* var = parser->Declare(declaration, descriptor_->mode != VAR, ok_);
if (!*ok_) return;
DCHECK_NOT_NULL(var);
ZoneList<Expression*>* arguments =
new (zone()) ZoneList<Expression*>(3, zone());
// We have at least 1 parameter.
- arguments->Add(factory()->NewStringLiteral(name, descriptor_->pos), zone());
+ arguments->Add(
+ factory()->NewStringLiteral(name, descriptor_->declaration_pos),
+ zone());
CallRuntime* initialize;
if (descriptor_->is_const) {
initialize = factory()->NewCallRuntime(
ast_value_factory()->initialize_const_global_string(),
Runtime::FunctionForId(Runtime::kInitializeConstGlobal), arguments,
- descriptor_->pos);
+ descriptor_->initialization_pos);
} else {
// Add language mode.
// We may want to pass singleton to avoid Literal allocations.
LanguageMode language_mode = initialization_scope->language_mode();
- arguments->Add(
- factory()->NewNumberLiteral(language_mode, descriptor_->pos), zone());
+ arguments->Add(factory()->NewNumberLiteral(language_mode,
+ descriptor_->declaration_pos),
+ zone());
// Be careful not to assign a value to the global variable if
// we're in a with. The initialization value should not
initialize = factory()->NewCallRuntime(
ast_value_factory()->initialize_var_global_string(),
Runtime::FunctionForId(Runtime::kInitializeVarGlobal), arguments,
- descriptor_->pos);
+ descriptor_->declaration_pos);
} else {
initialize = NULL;
}
DCHECK_NOT_NULL(proxy->var());
DCHECK_NOT_NULL(value);
Assignment* assignment = factory()->NewAssignment(
- descriptor_->init_op, proxy, value, descriptor_->pos);
+ descriptor_->init_op, proxy, value, descriptor_->initialization_pos);
block_->AddStatement(
factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
zone());
// property).
VariableProxy* proxy = initialization_scope->NewUnresolved(factory(), name);
Assignment* assignment = factory()->NewAssignment(
- descriptor_->init_op, proxy, value, descriptor_->pos);
+ descriptor_->init_op, proxy, value, descriptor_->initialization_pos);
block_->AddStatement(
factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
zone());
}
+TEST(DestructuringDisallowPatternsInForVarIn) {
+ i::FLAG_harmony_destructuring = true;
+ static const ParserFlag always_flags[] = {kAllowHarmonyDestructuring};
+ const char* context_data[][2] = {
+ {"", ""}, {"function f() {", "}"}, {NULL, NULL}};
+ // clang-format off
+ const char* error_data[] = {
+ "for (var {x} = {} in null);",
+ "for (var {x} = {} of null);",
+ "for (let x = {} in null);",
+ "for (let x = {} of null);",
+ NULL};
+ // clang-format on
+ RunParserSyncTest(context_data, error_data, kError, NULL, 0, always_flags,
+ arraysize(always_flags));
+
+ // clang-format off
+ const char* success_data[] = {
+ "for (var x = {} in null);",
+ NULL};
+ // clang-format on
+ RunParserSyncTest(context_data, success_data, kSuccess, NULL, 0, always_flags,
+ arraysize(always_flags));
+}
+
+
TEST(SpreadArray) {
i::FLAG_harmony_spread_arrays = true;
f();
Debug.setListener(null); // Break z
-print(JSON.stringify(log));
+print("log:\n"+ JSON.stringify(log));
// The let declaration differs from var in that the loop variable
// is declared in every iteration.
var expected = [
// Entry
"a2","b2",
- // Empty for-in-var: var decl, get enumerable
- "c7","c16",
+ // Empty for-in-var: get enumerable
+ "c16",
// Empty for-in: get enumerable
"d12",
- // For-in-var: var decl, get enumerable, assign, body, assign, body, ...
- "e7","e16","e11","E4","e11","E4","e11","E4","e11",
+ // For-in-var: get enumerable, assign, body, assign, body, ...
+ "e16","e11","E4","e11","E4","e11","E4","e11",
// For-in: get enumerable, assign, body, assign, body, ...
"f12","f7","F4","f7","F4","f7","F4","f7",
- // For-in-let: get enumerable, next, new let, body, next, new let, ...
- "g16","g11","g7","G4","g11","g7","G4","g11","g7","G4","g11",
- // For-of-var: var decl, next(), body, next(), body, ...
- "h7","h16","H4","h16","H4","h16","H4","h16",
+ // For-in-let: get enumerable, next, body, next, ...
+ "g16","g11","G4","g11","G4","g11","G4","g11",
+ // For-of-var: next(), body, next(), body, ...
+ "h16","H4","h16","H4","h16","H4","h16",
// For-of: next(), body, next(), body, ...
"i12","I4","i12","I4","i12","I4","i12",
- // For-of-let: next(), new let, body, next(), new let, ...
- "j16","j7","J4","j16","j7","J4","j16","j7","J4","j16",
+ // For-of-let: next(), body, next(), ...
+ "j16","J4","j16","J4","j16","J4","j16",
// For-var: var decl, condition, body, next, condition, body, ...
"k7","k20","K4","k23","k20","K4","k23","k20","K4","k23","k20",
// For: init, condition, body, next, condition, body, ...
// Exit.
"y0","z0",
]
+print("expected:\n"+ JSON.stringify(log));
assertArrayEquals(expected, log);
assertEquals(48, s);
assertSame(-(i+1), fy());
}
- var o = { 'a1':1, 'b2':2 };
- o.__proto__ = null;
+ var o = { __proto__:null, 'a1':1, 'b2':2 };
let sx = '';
let sy = '';
for (let [x,y] in o) {
assertEquals('ab', sx);
assertEquals('12', sy);
}());
+
+
+(function TestForEachVars() {
+ var a = [{x:1, y:-1}, {x:2,y:-2}, {x:3,y:-3}];
+ var sumX = 0;
+ var sumY = 0;
+ var fs = [];
+ for (var {x,y} of a) {
+ sumX += x;
+ sumY += y;
+ fs.push({fx : function() { return x; }, fy : function() { return y }});
+ }
+ assertSame(6, sumX);
+ assertSame(-6, sumY);
+ assertSame(3, fs.length);
+ for (var i = 0; i < fs.length; i++) {
+ var {fx,fy} = fs[i];
+ assertSame(3, fx());
+ assertSame(-3, fy());
+ }
+
+ var o = { __proto__:null, 'a1':1, 'b2':2 };
+ var sx = '';
+ var sy = '';
+ for (var [x,y] in o) {
+ sx += x;
+ sy += y;
+ }
+ assertEquals('ab', sx);
+ assertEquals('12', sy);
+}());