12.6.3 for statement

2010-05-23

Code: (Meta Ecma)
function evaluate(for ( ExpressionNoIn(opt) ; Expression(1)(opt) ; Expression(2)(opt) ) Statement) {
if (ExpressionNoIn) { // "is present"
var exprRef = evaluate(ExpressionNoIn);
GetValue(exprRef); // return value is unused, but can have observable side effects
}
var V = undefined;
while (true) { // this is a repeat
// condition part
if (Expression(1)) { // "first expression present"
var testExprRef = evaluate(Expression(1));
// strict false? or falsy?
if (GetValue(testExprRef) === false) return Completion('normal', V, undefined);
}
// statement part
var stmt = evaluate(Statement);
if (stmt.value !== undefined) V = stmt.value;
if (stmt.type == 'break' && labels.indexOf(stmt.target) >= 0) return Completion('normal', V, undefined);
// continue statement with known label should just skip this check
if (stmt.type != 'continue' || labels.indexOf(stmt.target) < 0) {
if (stmt.isAbrubt()) return stmt;
}
// increment part
if (Expression(2)) {
var incExprRef = evaluate(Expression(2));
GetValue(incExprRef); // returned value unused
}
}
}

As you can see in the main loop of the algorithm, the for loop will evaluate the condition, the Statement and then the incrementing Expression. This means that for will not call the incrementing Expression before the first execution of the Statement.

This algorithm is almost identical to the for loop with a var, except that because the VariableDeclarationListNoIn is not optional, it is always evaluated.

Code: (Meta Ecma)
function evaluate(for ( var VariableDeclarationListNoIn ; Expression(1)(opt) ; Expression(2)(opt) ) Statement) {
evaluate(VariableDeclarationListNoIn); // results unused, what happens on throw?
var V = undefined;
while (true) { // this is a repeat
// condition part
if (Expression(1)) { // "first expression present"
var testExprRef = evaluate(Expression(1));
// strict false? or falsy?
if (GetValue(testExprRef) === false) return Completion('normal', V, undefined);
}
// statement part
var stmt = evaluate(Statement);
if (stmt.value !== undefined) V = stmt.value;
if (stmt.type == 'break' && labels.indexOf(stmt.target) >= 0) return Completion('normal', V, undefined);
// continue statement with known label should just skip this check
if (stmt.type != 'continue' || labels.indexOf(stmt.target) < 0) {
if (stmt.isAbrubt()) return stmt;
}
// increment part
if (Expression(2)) {
var incExprRef = evaluate(Expression(2));
GetValue(incExprRef); // returned value unused
}
}
}