Edits to Chapter 12: Reverted introduction of "SubStatement" [RE: Unresolved 3.1 issue: statements and substatements]

Pratap Lakshman (VJ#SDK) pratapl at microsoft.com
Tue Nov 18 04:20:43 PST 2008


I have reverted the introduction of the SubStatement production from Chapter 12, and restored the original ES3 text for the relevant sections within. I am not posting an update to the spec this week, however, I am posting the changes below (these are based on the "Kona" draft). If you do not see the comments (in the margin) and the edits in red colour, please let me know.
12     Statements

Syntax

Statement [pL1] :

Block
VariableStatement
EmptyStatement
ExpressionStatement
IfStatement
IterationStatement
ContinueStatement
BreakStatement
ReturnStatement
WithStatement
LabelledStatement
SwitchStatement
ThrowStatement
TryStatement

DebuggerStatement

Semantics

A Statement can be part of a LabelledStatement, which itself can be part of a LabelledStatement, and so on. The labels introduced this way are collectively referred to as the "current label set" when describing the semantics of individual statements. A LabelledStatement has no semantic meaning other than the introduction of a label to a label set. The label set of an IterationStatement or a SwitchStatement initially contains the single element empty. The label set of any other statement is initially empty.

Note:

TBD: Implementations have been known to support FunctionDeclaration in a Statement; however there is no uniform support. It is impossible to reconcile their differing semantics, and hence this specification excludes their possibility.

12.1    Block

Syntax

Block :

{ StatementListopt }

StatementList :

Statement
StatementList Statement

Semantics

The production Block : { } is evaluated as follows:

1.       Return (normal, empty, empty).

The production Block : { StatementList }is evaluated as follows:

1.       Evaluate StatementList.

2.       Return Result(1)[pL2] .

12.1.1     Strict Mode Restrictions

A VariableStatement may not occur as a Statement in the StatementList of a Block that is contained in strict mode code. The occurrence of a VariableStatement in such a context must be treated as a syntax error.



12.5    The if Statement[pL3]

Syntax

IfStatement :

if ( Expression ) Statement  else Statement
if ( Expression ) Statement

Each else for which the choice of associated if is ambiguous shall be associated with the nearest possible if that would otherwise have no corresponding else.

Semantics

The production IfStatement : if ( Expression ) Statement else Statement is evaluated as follows:

1.       Evaluate Expression.

2.       Call GetValue(Result(1)).

3.       Call ToBoolean(Result(2)).

4.       If Result(3) is false, go to step 7.

5.       Evaluate the first Statement.

6.       Return Result(5).

7.       Evaluate the second Statement.

8.       Return Result(7).

The production IfStatement : if ( Expression ) Statement is evaluated as follows:

1.       Evaluate Expression.

2.       Call GetValue(Result(1)).

3.       Call ToBoolean(Result(2)).

4.       If Result(3) is false, return (normal, empty, empty).

5.       Evaluate Statement.

6.       Return Result(5).

12.5.1     Strict Mode Restrictions

In strict mode code a Statement that is part of an IfStatement production may not be a VariableStatement nor may it be a LabelledStatment whose Statement production is a VariableStatment. The LabelledStatement restriction also applies if such an VariableStatment is preceeded by multiple labels.[pL4]

12.6    Iteration Statements[pL5]

An iteration statement consists of a header (which consists of a keyword and a parenthesised control construct) and a body (which consists of a Statement).

Syntax

IterationStatement :

do Statement while ( Expression );
while ( Expression ) Statement
for (ExpressionNoInopt; Expressionopt ; Expressionopt ) Statement
for ( var VariableDeclarationListNoIn; Expressionopt ; Expressionopt ) Statement
for ( LeftHandSideExpression in Expression ) Statement
for ( var VariableDeclarationNoIn in Expression ) Statement

Strict Mode Restrictions

A Statement that is an element of an IterationStatement production may not be a VariableStatment nor may it be a LabelledStatment whose Statement production is a VariableStatment. The LabelledStatement restriction also applies if such an VariableStatment is preceeded by multiple labels.[pL6]

12.6.1     The do-while Statement

The production do Statement while ( Expression ); is evaluated as follows:

1.     Let V = empty.

2.     Evaluate Statement.

3.     If Result(2).value is not empty, let V = Result(2).value.

4.     If Result(2).type is continue and Result(2).target is in the current label set, go to step 7.

5.     If Result(2).type is break and Result(2).target is in the current label set, return (normal, V, empty).

6.     If Result(2) is an abrupt completion, return Result(2).

7.     Evaluate Expression.

8.     Call GetValue(Result(7)).

9.     Call ToBoolean(Result(8)).

10.  If Result(9) is true, go to step 2.

11.  Return (normal, V, empty);

12.6.2     The while statement

The production IterationStatement : while ( Expression ) Statement is evaluated as follows:

1.     Let V = empty.

2.     Evaluate Expression.

3.     Call GetValue(Result(2)).

4.     Call ToBoolean(Result(3)).

5.     If Result(4) is false, return (normal, V, empty).

6.     Evaluate Statement.

7.     If Result(6).value is not empty, let V = Result(6).value.

8.     If Result(6).type is continue and Result(6).target is in the current label set, go to 2.

9.     If Result(6).type is break and Result(6).target is in the current label set, return (normal, V, empty).

10.  If Result(6) is an abrupt completion, return Result(6).

11.  Go to step 2.

12.6.3     The for Statement

The production IterationStatement : for (ExpressionNoInopt ; Expressionopt ; Expressionopt) Statement is evaluated as follows:

1.     If ExpressionNoIn is not present, go to step 4.

2.     Evaluate ExpressionNoIn.

3.     Call GetValue(Result(2)). (This value is not used.)

4.     Let V = empty.

5.     If the first Expression is not present, go to step 10.

6.     Evaluate the first Expression.

7.     Call GetValue(Result(6)).

8.     Call ToBoolean(Result(7)).

9.     If Result(8) is false, go to step 19.

10.  Evaluate Statement.

11.  If Result(10).value is not empty, let V = Result(10).value

12.  If Result(10).type is break and Result(10).target is in the current label set, go to step 19.

13.  If Result(10).type is continue and Result(10).target is in the current label set, go to step 15.

14.  If Result(10) is an abrupt completion, return Result(10).

15.  If the second Expression is not present, go to step 5.

16.  Evaluate the second Expression.

17.  Call GetValue(Result(16). (This value is not used.)

18.  Go to step 5.

19.  Return (normal, V, empty).

The production IterationStatement : for ( var VariableDeclarationListNoIn ; Expressionopt ; Expressionopt ) Statement is evaluated as follows:

1.     Evaluate VariableDeclarationListNoIn.

2.     Let V = empty.

3.     If the first Expression is not present, go to step 8.

4.     Evaluate the first Expression.

5.     Call GetValue(Result(4)).

6.     Call ToBoolean(Result(5)).

7.     If Result(6) is false, go to step 17.

8.     Evaluate Statement.

9.     If Result(8).value is not empty, let V = Result(8).value.

10.  If Result(8).type is break and Result(8).target is in the current label set, go to step 17.

11.  If Result(8).type is continue and Result(8).target is in the current label set, go to step 13.

12.  If Result(8) is an abrupt completion, return Result(8).

13.  If the second Expression is not present, go to step 3.

14.  Evaluate the second Expression.

15.  Call GetValue(Result(14)). (This value is not used.)

16.  Go to step 3.

17.  Return (normal, V, empty).

12.6.4     The for-in Statement

The production IterationStatement : for ( LeftHandSideExpression in Expression ) Statement is evaluated as follows:

1.     Evaluate the Expression.

2.     Call GetValue(Result(1)).

3.     If Result(2) is null or undefined, return (normal, V, empty).

4.     Call ToObject(Result(2)).

5.     Let V = empty.

6.     Get the name of the next property of Result(4) whose [[Enumerable]] attribute is true. If there is no such property, go to step 15.

7.     Evaluate the LeftHandSideExpression ( it may be evaluated repeatedly).

8.     Call PutValue(Result(6), Result(7)).

9.     Evaluate Statement.

10.  If Result(9).value is not empty, let V = Result(9).value.

11.  If Result(9).type is break and Result(9).target is in the current label set, go to step 15.

12.  If Result(9).type is continue and Result(9).target is in the current label set, go to step 6.

13.  If Result(9) is an abrupt completion, return Result(9).

14.  Go to step 6.

15.  Return (normal, V, empty).

The production IterationStatement : for ( var VariableDeclarationNoIn in Expression ) Statement is evaluated as follows:



1.     Evaluate VariableDeclarationNoIn.

2.     Evaluate Expression.

3.     Call GetValue(Result(2)).

4.     If Result(3) is null or undefined, return (normal, V, empty).

5.     Call ToObject(Result(3)).

6.     Let V = empty.

7.     Get the name of the next property of Result(5) whose [[Enumerable]] attribute is true. If there is no such property, go to step 16.

8.     Evaluate Result(1) as if it were an Identifier; see step 7 from the previous algorithm (it may be evaluated repeatedly).

9.     Call PutValue(Result(7), Result(8)).

10. Evaluate Statement.

11. If Result(10).value is not empty, let V = Result(10).value.

12. If Result(10).type is break and Result(10).target is in the current label set, go to step 16.

13. If Result(10).type is continue and Result(10).target is in the current label set, go to step 7.

14. If Result(9) is an abrupt completion, return Result(9).

15. Go to step 7.

16. Return (normal, V, empty).

12.10  The with Statement[pL7]

Syntax

WithStatement :

with ( Expression ) Statement

Description

The with statement adds a computed object environment record to the lexical environment of the current execution context, then executes a statement with this augmented scope chain, then restores the lexical environment.

Semantics

The production WithStatement : with ( Expression ) Statement is evaluated as follows:

1.       Evaluate Expression.

2.       Call GetValue(Result(1)).

3.       Call ToObject(Result(2)).

4.       Call NewObjectEnvironmentRecord(O,E) passing Result(3) and the current execution context's LexicalEnvironment as the argument

5.       Set the LexicalEnvironment to Result(4).

6.       Evaluate Statement using the LexicalEnvironment from step 5.

7.       Let C be Result(6). If an exception was thrown in step 6, let C be (throw, V, empty), where V is the exception. (Execution now proceeds as if no exception were thrown.)

8.       Call PopEnvironmentRecord.

9.       Return C.

NOTE

No matter how control leaves the embedded 'Statement', whether normally or by some form of abrupt completion or exception, the LexicalEnvironment is always restored to its former state.


12.11.1   Strict Mode Restrictions

A Statement that is an element of an StatementList that is part of a CauseClause or DefaultClause may not be a VariableStatment nor may it be a LabelledStatment whose Statement production is a VariableStatment. The LabelledStatement restriction also applies if such a VariableStatment is preceeded by multiple labels.[pL8]

pratap

From: es-discuss-bounces at mozilla.org [mailto:es-discuss-bounces at mozilla.org] On Behalf Of Maciej Stachowiak
Sent: Monday, November 10, 2008 4:50 AM
To: Allen Wirfs-Brock
Cc: es3.x-discuss at mozilla.org; es-discuss at mozilla.org
Subject: Re: Unresolved 3.1 issue: statements and substatements


I agree with reverting the breaking change to non-strict mode. In general I think it is unacceptable to make any incompatible changes to standard mode without careful review of implementations and some study of existing Web content to ensure they are safe.

I'm not sure what the benefit is of making the change in strict mode only. It would be nice if ECMAScript were a block-scoped language, but it isn't, and I am not sure disallowing var as an if or switch clause is particularly helpful, especially when it is still allowed inside a block serving in such a clause.

I also agree that labels should be left alone. They are not a very commonly used feature and not especially a programming hazard, so they do not seem worth a special strict mode rule.

 - Maciej

On Nov 9, 2008, at 2:08 PM, Allen Wirfs-Brock wrote:


The ES3 specification has a single grammar production Statement that specifies what can occur in nested statement contexts such as if statement then and else clauses.  This allows for some strange looking but valid code such as:

If (foo)
   var bar = "baz";
else
   var bar = "bam";

for (var i=0;  i<10) var i=i++;

switch (i) {
   case 0 : var s = "one"; break;
   case 1:  var s = "two"; break;
  default: var s = "other";
 }

ES3.1 drafts have split statement into separate Statement and SubStatement productions.  SubStatement excludes VariableStatment (and for a while,  when we had them, function and const statements) and is used in most nested contexts such as the above. In the revised grammar, nested Statement productions only occur as the body of blocks and as function bodies.  The motivation for this split was twofold.  The primary reason was in support of blocks introducing nested lexical declaration environments. There was discussion regarding whether or not such nested declarations without explicit block braces should be considered to be in an implicit lexical block.  In particular, some of us didn't want to further propagate to const and let the var-like possibility of multiple declarations within a lexical block of the same entity. For example, the thinking was that:

If (foo)
   const bar = "baz";
else
   const bar = "bam

should either be illegal or  useless (each const would be in a separate implicit lexical block and would disappear immediately at completion of the block).  The "illegal" possibility was preferred and SubStatement was created as a way to specify that.

The second motivation of the split was a hygienic objection to the occurrence of var  (or any new declarations) in such positions. The belief was that most users who might code such things probably don't understand the actual semantics  involved and may or may not get the result they expected. If this is the case, it is probably better to forbid it.

The exclusion of var from SubStatement is a breaking change to ES3.  Some potentially existing valid ES3 programs that used var in these sorts of nested scenarios would not be valid ES3.1 programs. However, at the time, the combination of the two motivations seemed to carry enough weight to justify the change.

However, we have not included lexical blocks or any new lexical declarations in 3.1 and while we will eventually have them it seems unlikely that var will ever have block local scope. So the first argument doesn't really apply in the context of 3.1. The hygiene based argument is of the sort that we have generally only applied to strict mode restrictions. Strict mode is opt-in so minor breaking changes can be tolerated in strict code.

Recommendation #1:  For non-strict mode code, ES3's support of VariableStatement in nested contexts remains in place. The above code examples remain valid non-strict ES3.1 code. However, ES3.1 strict mode will disallow such usage of VariableStatement. Whether this is accomplished via some variant of the current draft's Statement/SubStatement grammar or via prose restrictions for strict mode is a specification detail that can be resolved after we make this decision.

Assuming we follow that recommendation (or if we don't and continue to apply the restriction to all code) there is still another open question about the strict mode semantics.  It is, can a VariableStatement occur as the Statement of a LabelledStatement.  For example, the following is currently allowed in ES3:

IntegerVariables:
   var i,j,k,l,m,n;
StringVariables:
    var A$,B$, C$;

Odd, but valid in ES3.  More generally, ES3 allows any statement to have a label including all non-compound statements that can't possibly contain a break or continue.

Strict mode could restrict such usages and this is probably a good idea if you believe that one of the purposes of strict mode is to enable early flagging of code whose meaning is likely not to be what a programmer intended.

My opinion (but not a recommendation) is that we should probably just leave LabelledStatment alone for ES3.1, even in strict mode. However, we certainly could specify some strict mode restrictions for it  if there is a consensus that they are desirable. So:

Feedback Request:  Should we restrict usage of LabelledStatment in strict mode or leave it as specified in ES3.

_______________________________________________
Es-discuss mailing list
Es-discuss at mozilla.org<mailto:Es-discuss at mozilla.org>
https://mail.mozilla.org/listinfo/es-discuss

________________________________

 [pL1]Review: The statement/substatement has been reverted because it isn't needed in the absence of lexical blocks in ES3.1

 [pL2]ES3 text restored.

 [pL3]ES3 text restored in this section. Specifically, reverted all SubStatement back to Statement.

 [pL4]New section.

 [pL5]ES3 text restored. Specifically, reverted all SubStatement back to Statement.

 [pL6]Newly specified restriction.

 [pL7]ES3 text restored in this section. Specifically, reverted all SubStatement back to Statement.

 [pL8]New section.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20081118/c7f3a673/attachment-0001.html>


More information about the Es-discuss mailing list