Step 4 of the [Runtime Semantics: Evaluation] for the production `IfStatement : if ( Expression ) Statement` has been changed to return `NormalCompletion(undefined)` based on the proposed completion reform.
That means the following code will now return `undefined` instead of `"pre"`:
---
eval("'pre'; if(false) {'if-true'}")
---
This code is not affected by the proposed completion reform, so it still returns `"pre"`:
---
eval("'pre'; if(true) {}")
---
However `IfStatement : if ( Expression ) Statement else Statement` has not been changed and therefore the following code also preserves the completion value of previous ECMAScript versions, i.e. it returns `"pre"`:
---
eval("'pre'; if(false) {'if-true'} else {}")
---
To ensure `if (<cond>) {<stmt>}` and `if (<cond>) {<stmt>} else {}` yield the same result, [Runtime Semantics: Evaluation] for the production `IfStatement : if ( Expression ) Statement else Statement` needs to be changed as follows (Note: I've changed step 4 in addition to step 5 to cover both cases):
---
1. leave-as-is
2. leave-as-is
3. leave-as-is
4. If exprValue is true, then
a. Let stmt be the result of evaluating the first Statement
b. ReturnIfAbrupt(stmt)
c. If stmt.[[value]] is not empty, return stmt
d. Return NormalCompletion(undefined)
5. Else,
a. Let stmt be the result of evaluating the second Statement
b. ReturnIfAbrupt(stmt)
c. If stmt.[[value]] is not empty, return stmt
d. Return NormalCompletion(undefined)
---
Applying that change will lead to changing [Runtime Semantics: Evaluation] for the production `IfStatement : if ( Expression ) Statement` as follows:
---
1. leave-as-is
2. leave-as-is
3. leave-as-is
4. If exprValue is false, return NormalCompletion(undefined)
5. Else,
a. Let stmt be the result of evaluating Statement
b. ReturnIfAbrupt(stmt)
c. If stmt.[[value]] is not empty, return stmt
d. Return NormalCompletion(undefined)
---
Similar problems can be shown for the While-Statement, for example consider:
---
eval("'pre'; while(false);")
eval("'pre'; while(true)break;")
---
With the current changes for the completion reform, the first eval() call will return `undefined` whereas the second call will return `"pre"`. I'd expect both calls to yield the same result, that means `undefined`.
sounds right....
Also, my reading of the completion reform proposal, is that every Statement except EmptyStatement (and Declarations) should have a non-empty value.
this means that a BlockStatemnt like:
{ }
should return NormalCompletion(undefind).
and that
while (true) {break};
should also evaluate to NormalCopletion(undefined);
But
while (true) {42; break};
should also evaluate to NormalCopletion(42);
dherman, Do you agree???
On a related note, `finally`'s completion value semantics may also need to be changed. When a `finally` statement returns with an abrupt completion, its completion value is used whereas when it returns with a normal completion the `try`-statement's completion value is used. I'm not sure if this is intended...
---
"in-try" === eval("while(true){ try{ 'in-try' }finally{ 'in-finally'; } break; }")
"in-finally" === eval("while(true){ try{ 'in-try' }finally{ 'in-finally'; break; } }")
---
fixed in rev34 editor's draft
fixed a rather nasty bug in LabelledEvaluation of BreakableStatement
Also, {} at the statement list level is now equivalent to an empty statement. That maintains legacy compat for eval('1; {}') which had been explicitly document as having a value of 1; This fix doesn't change control structure the completion values of statements like :
if (true) {}
Those all still have completion values of undefined.
Added, missing undefined completion defaulting to WithStatement
Also, dealt with force empty try and catch blocks to NormalCompetion(undefined). Break in finally get's turned in NormalCompletion(undefined) by enclosing Breakable or LabelledStatment
fixed in rev34