Skip to content

Commit

Permalink
Emit 'for...of' loop when LHS is a var
Browse files Browse the repository at this point in the history
  • Loading branch information
JsonFreeman committed Mar 5, 2015
1 parent b784a42 commit e417e1d
Showing 1 changed file with 95 additions and 0 deletions.
95 changes: 95 additions & 0 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3444,6 +3444,10 @@ module ts {
}

function emitForInOrForOfStatement(node: ForInStatement | ForOfStatement) {
if (languageVersion < ScriptTarget.ES6 && node.kind === SyntaxKind.ForOfStatement) {
return emitDownLevelForOfStatement(node);
}

var endPos = emitToken(SyntaxKind.ForKeyword, node.pos);
write(" ");
endPos = emitToken(SyntaxKind.OpenParenToken, endPos);
Expand All @@ -3470,6 +3474,97 @@ module ts {
emitToken(SyntaxKind.CloseParenToken, node.expression.end);
emitEmbeddedStatement(node.statement);
}

function emitDownLevelForOfStatement(node: ForOfStatement) {
// The following ES6 code:
//
// for (var v of expr) { }
//
// should be emitted as
//
// for (var v, _i = 0, _a = expr; _i < _a.length; _i++) {
// v = _a[_i];
// }
//
// where _a and _i are temps emitted to capture the RHS and the counter,
// respectively.
// When the left hand side is an expression instead of a var declaration,
// the "var v" is not emitted.
// When the left hand side is a let/const, the v is renamed if there is
// another v in scope.
// Note that all assignments to the LHS are emitted in the body, including
// all destructuring.
// Note also that because an extra statement is needed to assign to the LHS,
// for-of bodies are always emitted as blocks.

var endPos = emitToken(SyntaxKind.ForKeyword, node.pos);
write(" ");
endPos = emitToken(SyntaxKind.OpenParenToken, endPos);
if (node.initializer.kind === SyntaxKind.VariableDeclarationList) {
var variableDeclarationList = <VariableDeclarationList>node.initializer;
if (variableDeclarationList.declarations.length >= 1) {
write("var ");
var decl = variableDeclarationList.declarations[0];
// TODO handle binding patterns
emit(decl.name);
write(", ");
}
}

// Do not call create recordTempDeclaration because we are declaring the temps

This comment has been minimized.

Copy link
@DanielRosenwasser

DanielRosenwasser Mar 6, 2015

Member

createAndRecord

This comment has been minimized.

Copy link
@JsonFreeman

JsonFreeman Mar 6, 2015

Author Contributor

What about it?

This comment has been minimized.

Copy link
@JsonFreeman

JsonFreeman Mar 6, 2015

Author Contributor

Oh, I will remove the word 'create'

// right here. Recording means they will be declared later.
var counter = createTempVariable(node, /*forLoopVariable*/ true);
var rhsReference = createTempVariable(node, /*forLoopVariable*/ false);

// _i = 0,
emit(counter);
write(" = 0, ");

// _a = expr;
emit(rhsReference);
write(" = ");
emit(node.expression);
write("; ");

// _i < _a.length;
emit(counter);
write(" < ");
emit(rhsReference);
write(".length; ");

// _i++)
emit(counter);
write("++");
emitToken(SyntaxKind.CloseParenToken, node.expression.end);

// Body
write(" {");
writeLine();
increaseIndent();

// Initialize LHS
// v = _a[_i];
if (decl) {
emit(decl.name);
write(" = ");
emit(rhsReference)
write("[");
emit(counter);
write("];");
writeLine();
}

if (node.statement.kind === SyntaxKind.Block) {
emitLines((<Block>node.statement).statements);
}
else {
emit(node.statement);
}

writeLine();
decreaseIndent();
write("}");
}

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

0 comments on commit e417e1d

Please sign in to comment.