Skip to content

Commit e417e1d

Browse files
committed
Emit 'for...of' loop when LHS is a var
1 parent b784a42 commit e417e1d

File tree

1 file changed

+95
-0
lines changed

1 file changed

+95
-0
lines changed

src/compiler/emitter.ts

+95
Original file line numberDiff line numberDiff line change
@@ -3444,6 +3444,10 @@ module ts {
34443444
}
34453445

34463446
function emitForInOrForOfStatement(node: ForInStatement | ForOfStatement) {
3447+
if (languageVersion < ScriptTarget.ES6 && node.kind === SyntaxKind.ForOfStatement) {
3448+
return emitDownLevelForOfStatement(node);
3449+
}
3450+
34473451
var endPos = emitToken(SyntaxKind.ForKeyword, node.pos);
34483452
write(" ");
34493453
endPos = emitToken(SyntaxKind.OpenParenToken, endPos);
@@ -3470,6 +3474,97 @@ module ts {
34703474
emitToken(SyntaxKind.CloseParenToken, node.expression.end);
34713475
emitEmbeddedStatement(node.statement);
34723476
}
3477+
3478+
function emitDownLevelForOfStatement(node: ForOfStatement) {
3479+
// The following ES6 code:
3480+
//
3481+
// for (var v of expr) { }
3482+
//
3483+
// should be emitted as
3484+
//
3485+
// for (var v, _i = 0, _a = expr; _i < _a.length; _i++) {
3486+
// v = _a[_i];
3487+
// }
3488+
//
3489+
// where _a and _i are temps emitted to capture the RHS and the counter,
3490+
// respectively.
3491+
// When the left hand side is an expression instead of a var declaration,
3492+
// the "var v" is not emitted.
3493+
// When the left hand side is a let/const, the v is renamed if there is
3494+
// another v in scope.
3495+
// Note that all assignments to the LHS are emitted in the body, including
3496+
// all destructuring.
3497+
// Note also that because an extra statement is needed to assign to the LHS,
3498+
// for-of bodies are always emitted as blocks.
3499+
3500+
var endPos = emitToken(SyntaxKind.ForKeyword, node.pos);
3501+
write(" ");
3502+
endPos = emitToken(SyntaxKind.OpenParenToken, endPos);
3503+
if (node.initializer.kind === SyntaxKind.VariableDeclarationList) {
3504+
var variableDeclarationList = <VariableDeclarationList>node.initializer;
3505+
if (variableDeclarationList.declarations.length >= 1) {
3506+
write("var ");
3507+
var decl = variableDeclarationList.declarations[0];
3508+
// TODO handle binding patterns
3509+
emit(decl.name);
3510+
write(", ");
3511+
}
3512+
}
3513+
3514+
// Do not call create recordTempDeclaration because we are declaring the temps
3515+
// right here. Recording means they will be declared later.
3516+
var counter = createTempVariable(node, /*forLoopVariable*/ true);
3517+
var rhsReference = createTempVariable(node, /*forLoopVariable*/ false);
3518+
3519+
// _i = 0,
3520+
emit(counter);
3521+
write(" = 0, ");
3522+
3523+
// _a = expr;
3524+
emit(rhsReference);
3525+
write(" = ");
3526+
emit(node.expression);
3527+
write("; ");
3528+
3529+
// _i < _a.length;
3530+
emit(counter);
3531+
write(" < ");
3532+
emit(rhsReference);
3533+
write(".length; ");
3534+
3535+
// _i++)
3536+
emit(counter);
3537+
write("++");
3538+
emitToken(SyntaxKind.CloseParenToken, node.expression.end);
3539+
3540+
// Body
3541+
write(" {");
3542+
writeLine();
3543+
increaseIndent();
3544+
3545+
// Initialize LHS
3546+
// v = _a[_i];
3547+
if (decl) {
3548+
emit(decl.name);
3549+
write(" = ");
3550+
emit(rhsReference)
3551+
write("[");
3552+
emit(counter);
3553+
write("];");
3554+
writeLine();
3555+
}
3556+
3557+
if (node.statement.kind === SyntaxKind.Block) {
3558+
emitLines((<Block>node.statement).statements);
3559+
}
3560+
else {
3561+
emit(node.statement);
3562+
}
3563+
3564+
writeLine();
3565+
decreaseIndent();
3566+
write("}");
3567+
}
34733568

34743569
function emitBreakOrContinueStatement(node: BreakOrContinueStatement) {
34753570
emitToken(node.kind === SyntaxKind.BreakStatement ? SyntaxKind.BreakKeyword : SyntaxKind.ContinueKeyword, node.pos);

0 commit comments

Comments
 (0)