12.11 switch statement

2010-05-23

SwitchStatement :
switch ( Expression ) CaseBlock

CaseBlock :
{ CaseClause(opt) }
{ CaseClause(opt) DefaultClause CaseClauses(opt) }

CaseClauses :
CaseClause
CaseClauses CaseClause

CaseClause :
case Expression : StatementList(opt)

DefaultClause :
default : StatementList(opt)

The switch allows you to check the value of some Expression against multiple values easily and act in some way if one matches. Javascript allows a default case to occur before the last clause of a switch. The default clause will still only fire if none of the other clauses (so even those declared later) matches the Expression. This allows you to let the default case fall through other cases.

Note that strict comparison (===) is used!

Code: (Meta Ecma)
function evaluate(switch ( Expression ) CaseBlock) {
var exprRef = evaluate(Expression);
var R = evaluate(CaseBlock, GetValue(exprRef)); // parameter?
if (R.type == 'break' && labels.indexOf(R.target) >= 0) return Completion('normal', R.value, undefined);
return R;
}


Code: (Meta Ecma)
function evaluate({ CaseClauses(opt) }, input) { // input is a parameter, see above
var V = undefined;
var A = CaseClause; // List
var searching = true;
var i =0;
while (searching) {
if (i >= A.length) return Completion('normal', V, undefined);
var C = A[i++];
var clauseSelector = evaluate(C);
if (input === clauseSelector) {
searching = false;
if (C.StatementList) {
var R = evaluate(C.StatementList);
if (R.isAbrubt()) return R;
V = R.value;
}
}
}
// fall through until the end or a return/break.
while (true) { // repeat
if (i >= A.length) return Completion('normal', V, undefined);
var C = A[i++];
if (C.StatementList) {
var R = evaluate(C.StatementList);
if (R.isAbrubt()) return R;
V = R.value;
}
}
}

Note that the above algorithm contains no default clause. That's where the next algorithm is for. The default clause is not optional for it.

Code: (Meta Ecma)
function evaluate({ CaseClauses(1)(opt) DefaultClause CaseClauses(2)(opt) }, input) { // input is a parameter, see above
var V = undefined;
var A = CaseClause(1); // List in source text order
var B = CaseClause(2); // List in source text order
var found = true;
var i =0;
var C;
while (C = CaseClause(1)[i++]) {
if (!found) {
var clauseSelector = evaluate(C);
if (input === clauseSelector) found = true;
}
// if found, execute Statement
if (found) {
if (C.StatementList) {
var R = evaluate(C.StatementList);
if (R.value !== undefined) V = R.value; // this might be a problem for meta, if "undefined" was returned instead of "empty", V would not be replaced... would this ever be a problem?
if (R.isAbrubt()) return Completion(R.type, V, R.target);
}
}
}
var foundInB = false;
if (!found) {
i = 0;
while (!foundInB && i < B.length) {
C = B[i++];
var clauseSelector = evaluate(C);
if (input === clauseSelector) {
foundInB = true;
if (C.StatementList) {
var R = evaluate(C.StatementList);
if (R.value !== undefined) V = R.value;
if (R.isAbrubt()) return Completion(R.type, V, R.target);
}
}
}
}
if (!foundInB && DefaultClause.StatementList) {
var R = evaluate(DefaultClause.StatementList);
if (R.value !== undefined) V = R.value;
if (R.isAbrubt()) return Completion(R.type, V, R.target);
}
// uses i left from previous B enumeration
while (true) {
if (i >= B.length) return Completion('normal', V, undefined);
var C = B[i++];
var clauseSelector = evaluate(C);
if (C.StatementList) {
var R = evaluate(C.StatementList);
if (R.value !== undefined) V = R.value;
if (R.isAbrubt()) return Completion(R.type, V, R.target);
}
}
}


Is this algorithm missing the default clause resetting the i so it will process B from the start?


Code: (Meta Ecma)
function evaluate(case Expression : StatementList(opt)) {
var exprRef = evaluate(Expression);
return GetValue(exprRef);
}


Note that evaluating a case clause does not execute its associated StatementList. It only evaluates the expression and returns the value.