Commit 7ffdb519 authored by dslomov's avatar dslomov Committed by Commit bot

[destructuring] Grand for statement parsing unification.

Also support patterns in ``for (var p in/of ...)``

This CL extends the rewriting we used to do for ``for (let p in/of...)`` to
``for (var p in/of ...)``. For all for..in/of loop declaring variable,
we rewrite
   for (var/let/const pattern in/of e) b
into
   for (x' in/of e) { var/let/const pattern = e; b }

This adds a small complication for debugger: for a statement
   for (var v in/of e) ...
we used to have
   var v;
   for (v in/of e) ...
and there was a separate breakpoint on ``var v`` line.
This breakpoint is actually useless since it is immediately followed by
a breakpoint on evaluation of ``e``, so this CL removes that breakpoint
location.

Similiraly, for let, it used to be that
  for (let v in/of e) ...
became
  for (x' in/of e) { let v; v  = x'; ... }
``let v``generetaed a useless breakpoint (with the location at the
loop's head. This CL removes that breakpoint as well.

R=arv@chromium.org,rossberg@chromium.org
BUG=v8:811
LOG=N

Review URL: https://codereview.chromium.org/1149043005

Cr-Commit-Position: refs/heads/master@{#28565}
parent a40e85d6
This diff is collapsed.
...@@ -950,7 +950,8 @@ class Parser : public ParserBase<ParserTraits> { ...@@ -950,7 +950,8 @@ class Parser : public ParserBase<ParserTraits> {
VariableMode mode; VariableMode mode;
bool is_const; bool is_const;
bool needs_init; bool needs_init;
int pos; int declaration_pos;
int initialization_pos;
Token::Value init_op; Token::Value init_op;
}; };
......
...@@ -51,7 +51,8 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { ...@@ -51,7 +51,8 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
const AstRawString* name = pattern->raw_name(); const AstRawString* name = pattern->raw_name();
VariableProxy* proxy = parser->NewUnresolved(name, descriptor_->mode); VariableProxy* proxy = parser->NewUnresolved(name, descriptor_->mode);
Declaration* declaration = factory()->NewVariableDeclaration( 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_); Variable* var = parser->Declare(declaration, descriptor_->mode != VAR, ok_);
if (!*ok_) return; if (!*ok_) return;
DCHECK_NOT_NULL(var); DCHECK_NOT_NULL(var);
...@@ -126,7 +127,9 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { ...@@ -126,7 +127,9 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
ZoneList<Expression*>* arguments = ZoneList<Expression*>* arguments =
new (zone()) ZoneList<Expression*>(3, zone()); new (zone()) ZoneList<Expression*>(3, zone());
// We have at least 1 parameter. // 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; CallRuntime* initialize;
if (descriptor_->is_const) { if (descriptor_->is_const) {
...@@ -140,13 +143,14 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { ...@@ -140,13 +143,14 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
initialize = factory()->NewCallRuntime( initialize = factory()->NewCallRuntime(
ast_value_factory()->initialize_const_global_string(), ast_value_factory()->initialize_const_global_string(),
Runtime::FunctionForId(Runtime::kInitializeConstGlobal), arguments, Runtime::FunctionForId(Runtime::kInitializeConstGlobal), arguments,
descriptor_->pos); descriptor_->initialization_pos);
} else { } else {
// Add language mode. // Add language mode.
// We may want to pass singleton to avoid Literal allocations. // We may want to pass singleton to avoid Literal allocations.
LanguageMode language_mode = initialization_scope->language_mode(); LanguageMode language_mode = initialization_scope->language_mode();
arguments->Add( arguments->Add(factory()->NewNumberLiteral(language_mode,
factory()->NewNumberLiteral(language_mode, descriptor_->pos), zone()); descriptor_->declaration_pos),
zone());
// Be careful not to assign a value to the global variable if // Be careful not to assign a value to the global variable if
// we're in a with. The initialization value should not // we're in a with. The initialization value should not
...@@ -160,7 +164,7 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { ...@@ -160,7 +164,7 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
initialize = factory()->NewCallRuntime( initialize = factory()->NewCallRuntime(
ast_value_factory()->initialize_var_global_string(), ast_value_factory()->initialize_var_global_string(),
Runtime::FunctionForId(Runtime::kInitializeVarGlobal), arguments, Runtime::FunctionForId(Runtime::kInitializeVarGlobal), arguments,
descriptor_->pos); descriptor_->declaration_pos);
} else { } else {
initialize = NULL; initialize = NULL;
} }
...@@ -184,7 +188,7 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { ...@@ -184,7 +188,7 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
DCHECK_NOT_NULL(proxy->var()); DCHECK_NOT_NULL(proxy->var());
DCHECK_NOT_NULL(value); DCHECK_NOT_NULL(value);
Assignment* assignment = factory()->NewAssignment( Assignment* assignment = factory()->NewAssignment(
descriptor_->init_op, proxy, value, descriptor_->pos); descriptor_->init_op, proxy, value, descriptor_->initialization_pos);
block_->AddStatement( block_->AddStatement(
factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition), factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
zone()); zone());
...@@ -200,7 +204,7 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { ...@@ -200,7 +204,7 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
// property). // property).
VariableProxy* proxy = initialization_scope->NewUnresolved(factory(), name); VariableProxy* proxy = initialization_scope->NewUnresolved(factory(), name);
Assignment* assignment = factory()->NewAssignment( Assignment* assignment = factory()->NewAssignment(
descriptor_->init_op, proxy, value, descriptor_->pos); descriptor_->init_op, proxy, value, descriptor_->initialization_pos);
block_->AddStatement( block_->AddStatement(
factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition), factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
zone()); zone());
......
...@@ -6525,6 +6525,32 @@ TEST(DestructuringNegativeTests) { ...@@ -6525,6 +6525,32 @@ TEST(DestructuringNegativeTests) {
} }
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) { TEST(SpreadArray) {
i::FLAG_harmony_spread_arrays = true; i::FLAG_harmony_spread_arrays = true;
......
...@@ -81,28 +81,28 @@ Debug.setListener(listener); ...@@ -81,28 +81,28 @@ Debug.setListener(listener);
f(); f();
Debug.setListener(null); // Break z 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 // The let declaration differs from var in that the loop variable
// is declared in every iteration. // is declared in every iteration.
var expected = [ var expected = [
// Entry // Entry
"a2","b2", "a2","b2",
// Empty for-in-var: var decl, get enumerable // Empty for-in-var: get enumerable
"c7","c16", "c16",
// Empty for-in: get enumerable // Empty for-in: get enumerable
"d12", "d12",
// For-in-var: var decl, get enumerable, assign, body, assign, body, ... // For-in-var: get enumerable, assign, body, assign, body, ...
"e7","e16","e11","E4","e11","E4","e11","E4","e11", "e16","e11","E4","e11","E4","e11","E4","e11",
// For-in: get enumerable, assign, body, assign, body, ... // For-in: get enumerable, assign, body, assign, body, ...
"f12","f7","F4","f7","F4","f7","F4","f7", "f12","f7","F4","f7","F4","f7","F4","f7",
// For-in-let: get enumerable, next, new let, body, next, new let, ... // For-in-let: get enumerable, next, body, next, ...
"g16","g11","g7","G4","g11","g7","G4","g11","g7","G4","g11", "g16","g11","G4","g11","G4","g11","G4","g11",
// For-of-var: var decl, next(), body, next(), body, ... // For-of-var: next(), body, next(), body, ...
"h7","h16","H4","h16","H4","h16","H4","h16", "h16","H4","h16","H4","h16","H4","h16",
// For-of: next(), body, next(), body, ... // For-of: next(), body, next(), body, ...
"i12","I4","i12","I4","i12","I4","i12", "i12","I4","i12","I4","i12","I4","i12",
// For-of-let: next(), new let, body, next(), new let, ... // For-of-let: next(), body, next(), ...
"j16","j7","J4","j16","j7","J4","j16","j7","J4","j16", "j16","J4","j16","J4","j16","J4","j16",
// For-var: var decl, condition, body, next, condition, body, ... // For-var: var decl, condition, body, next, condition, body, ...
"k7","k20","K4","k23","k20","K4","k23","k20","K4","k23","k20", "k7","k20","K4","k23","k20","K4","k23","k20","K4","k23","k20",
// For: init, condition, body, next, condition, body, ... // For: init, condition, body, next, condition, body, ...
...@@ -110,6 +110,7 @@ var expected = [ ...@@ -110,6 +110,7 @@ var expected = [
// Exit. // Exit.
"y0","z0", "y0","z0",
] ]
print("expected:\n"+ JSON.stringify(log));
assertArrayEquals(expected, log); assertArrayEquals(expected, log);
assertEquals(48, s); assertEquals(48, s);
......
...@@ -645,8 +645,7 @@ ...@@ -645,8 +645,7 @@
assertSame(-(i+1), fy()); assertSame(-(i+1), fy());
} }
var o = { 'a1':1, 'b2':2 }; var o = { __proto__:null, 'a1':1, 'b2':2 };
o.__proto__ = null;
let sx = ''; let sx = '';
let sy = ''; let sy = '';
for (let [x,y] in o) { for (let [x,y] in o) {
...@@ -656,3 +655,34 @@ ...@@ -656,3 +655,34 @@
assertEquals('ab', sx); assertEquals('ab', sx);
assertEquals('12', sy); 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);
}());
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment