Newly revised Section 10 for ES3.1.
Allen Wirfs-Brock
Allen.Wirfs-Brock at microsoft.com
Wed Jul 9 17:16:22 PDT 2008
I've just finished reworking section 10 to better accommodate block scoped function declarations and const statements. In the course of this I had to make various decisions about the semantics. The primary purpose of this message is to provide visibility to those decisions and to get feedback on them.
In introducing const statements and block scoped function declaration I tried to apply two over-riding principles:
1) Anything that is valid to do in ES3 continues to have the exact same semantics.
2) Anything thing that is new (or non-standard) and would not be valid in ES3 should have a semantics that is rational and consistent with a future introduction of block scoped Let variable bindings
Here are the results:
All var declarations continue to be hoisted to "top-level" execution context. Vars never have block level scope or extent.
("top-level" mean the global code, eval code, or the top-level of a function.
Function declarations and const declarations are processed in parallel within a lexical contour (top-level or block). Neither has precedence over the other, unlike the manner in which function declarations take precedence over formal parameters in ES3.
A "top-level" function declaration over-writes any like-named formal parameters or preceding like-named function declarations. This is an ES3 semantics.
"Top-level" function declarations are writable. Subsequent declarations or assignments may change their value. This is an ES3 semantics.
A "top-level" const declaration may not have the same name as a formal parameter or any other "top-level" declaration (including consts, vars, and functions). Since consts are new, this is a new semantics.
Const and function declarations within blocks must be uniquely named, such a declaration may not over-write a preceding declaration in the same block and an attempt to do so is a syntax error. Such declarations, of course, shadow any like named declarations in enclosing scopes. Since consts and function declarations in blocks are new, this is a new semantics.
For scoping purposes, const and function declarations are "hoisted" to the top of their defining block. There may be only one, consistent binding of a name within a block. Functions are initialized on block entry, consts are initialized when they are reached in execution flow. Accessing the value of a const before it is initialized throws an exception. Since consts and function declarations in blocks are new, this is a new semantics.
Within in a block, function declarations are read-only bindings. Since declarations in blocks are new, this is a new semantics.
Can anybody from ES4 comment on how closely this matches the current ES4 spec for block scoped consts and nested function declarations.
In the course of this, I noticed a number of conditions that plausibly might be restricted in the cautious subset, but currently aren't specified as such:
* Illegal for a function to have duplicately named formal parameters
* Illegal for a function to contain a top level function declaration with a function name that is the same as a formal parameter.
* Illegal to have multiple top level function declarations for the same function name
* Illegal to have a function declaration with the same name as var declaration.
* Illegal for a function to contain a var declaration with the same name as a formal parameter.
* Illegal to assign to a top-level function name.
Does anybody want to advocate for including these restrictions in the cautious subset.
The following is the revised version of section 10. Review by additional eyeballs would be appreciated.
10 Execution Contexts
When control is transferred to ECMAScript executable code, control is entering an execution context. Active execution contexts logically form a stack. The top execution context on this logical stack is the running execution context.
10.1 Definitions
10.1.1 Function Objects
There are two types of Function objects:
Program functions are defined in source text by a FunctionDeclaration or created dynamically either by using a FunctionExpression or by using the built-in Function object as a constructor.
Internal functions are built-in objects of the language, such as parseInt and Math.exp. An implementation may also provide implementation-dependent internal functions that are not described in this specification. These functions do not necessarily contain executable code defined by the ECMAScript grammar, in which case they are excluded from this discussion of execution contexts.
10.1.2 Types of Executable Code
There are five types of ECMAScript executable code:
Global code is source text that is treated as an ECMAScript Program.. The global code of a particular Program does not include any source text that is parsed as part of a Block or of a FunctionBody except that it does include the code of any VariableDeclaration that is parsed as part of such a Block or as part of a Block nested at any level within such a Block.
Eval code is the source text supplied to the built-in eval function. More precisely, if the parameter to the built-in eval function is a string, it is treated as an ECMAScript Program. The eval code for a particular invocation of eval is the global code portion of the string parameter. The eval code for a particular invocation of eval does not include any source text that is parsed as part of a Block or a FunctionBody except that it does include the code of any VariableDeclaration that is parsed as part of such a Block or as part of a Block nested at any level within such a Block.
Function code is source text that is parsed as part of a FunctionBody. The function code of a particular FunctionBody does not include any source text that is parsed as part of a Block or a FunctionBody except that it does include the code of any VariableDeclaration that is parsed as part of such a Block or as part of a Block nested at any level within such a Block.
Function code also denotes the source text supplied when using the built-in Function object as a constructor. More precisely, the last parameter provided to the Function constructor is converted to a string and treated as the FunctionBody. If more than one parameter is provided to the Function constructor, all parameters except the last one are converted to strings and concatenated together, separated by commas. The resulting string is interpreted as the FormalParameterList for the FunctionBody defined by the last parameter. The function code for a particular instantiation of a Function does not include any source text that is parsed as part of a nested FunctionBody. The function code for a particular instantiation of a Function does not include any source text that is parsed as part of a Block or a FunctionBody except that it does include the code of any VariableDeclaration that is parsed as part of such a Block or as part of a Block nested at any level within such a Block.
Lexical Block code is the source code that that is parsed as the StatementList of a Block. The lexical block code of a particular StatementList does not include any source text that is parsed as part of a nested FunctionBody.
10.1.2.3 Applying Usage Subsets to Executable code
Each occurence of one of these types of code may be restricted to use a defined subset of the complete ECMAScript language.
* Global code is unrestricted unless the Program that defines the code includes a UseSubsetDirective.
* Eval code inherits the restrictions of the execution context in which the eval operator appears, but its execution context may be further restricted if the Program that defines the eval code includes a UseSubsetDirective. In that case, the restrictions of the execution context are the union of the restrictions of the inherited execution context and the restrictions specified by the UseSubsetDirective. Such a unioning of restrictions is the equivalent of intersecting the specified usage subsets.
* Function code made by evaluating a FunctionDeclaration or a FunctionExpression, function code supplied as the last argument to the Function constructor, and lexical block code all inherit the restrictions of the execution context in which the evaluation occurs.
10.1.3 Environment Bindings Instantiation
Every execution context has associated with it an environment object. For all kinds of execution contexts, constants and functions declared in the source text are added as properties of the environment object. For global code, eval code, and function code variables declared in the source text are also added as properties of the environment object . For function code, parameters are added as properties of the environment object.
Which object is used as the environment object and what attributes are used for the properties depends on the type of code, but the remainder of the behaviour is generic. On entering an execution context, the properties are bound to the environment object in the following order:
For function code: for each formal parameter, as defined in the FormalParameterList, create a named data property of the environment object whose name is the Identifier and whose attributes are determined by the type of code. The values of the parameters are supplied by the caller as arguments to [[Call]]. If the caller supplies fewer parameter values than there are formal parameters, the extra formal parameters have value undefined. If two or more formal parameters share the same name, hence the same property, the corresponding property is given the value that was supplied for the last parameter with this name. If the value of this last parameter was not supplied by the caller, the value of the corresponding property is undefined.
For lexical block code: if the lexical block has any block parameters, create for each block parameter a named data property of the environment object whose name, value, are determined by evaluation context of the Block and whose attributes are {[[Writable]]: true, [[Enumerable]]: false, [[Flexible: false]]}. Only a TryStatement creates lexical block contexts with block parameters.
For all of the FunctionDeclaration and ConstantDeclaration in the code perform the following algorithm. Semantically, this step must follow the creation of FormalParameterList or block parameter properties:
1. Let CTX be the current execution context and its associated environment object.
2. For each FunctionDeclaration and ConstantDeclaration, D in the code in source code order,
a. Let N be the Identifer in D.
b. If D is a ConstantDeclaration then
i.If CTX already contains a property named N, throw a SyntaxError exception.
ii.Create a named data property in CTX whose name is N, whose [[Const]] attribute is Unitialized, whose [[Writable]] attribute is false, and whose value is set to undefined.
c. If D is a FunctionDeclaration then
i.If CTX already contains a property named N, then
1. If CTX is the execution context of a Block, throw a SyntaxError exception.
2. If the existing property has a [[Const]] attribute, throw a SyntaxError exception otherwise the value and attributes of the existing property will be replaced by the actions of step 2cii below.
ii. Create a named data property in CTX whose name is N and whose value is the result returned by creating a Function object as described in 13.
d. Other attributes of the named data property are determined by the type of code
For execution contexts that are not lexical blocks: For each VariableDeclaration or VariableDeclarationNoIn in the code (including VariableDeclarations contained within Blocks that are within the code), create a property of the environment object whose name is the Identifier in the VariableDeclaration or VariableDeclarationNoIn, whose value is undefined and whose attributes are determined by the type of code. If there is already a property of the environment object with the name of a declared variable and the property has a [[Const]] attribute throw a SyntaxError exception, otherwise the value of the existing property and its attributes are not changed. Semantically, this step must follow the creation of the FormalParameterList and the FunctionDeclaration and ConstantDeclaration properties. In particular, if a declared variable has the same name as a declared function or formal parameter, the variable declaration does not disturb the existing property.
10.1.3.1 Usage Subset Restrictions
When defined within an execution context subset restricted to the cautious subset, a function may not have two or more formal parameters that have the same name. An attempt to create a such a function with conflicting parameters names will fail, either statically, if expressed as a FunctionDeclaration or FunctionExpression, or dynamically by throwing a SyntaxError exception, if expressed in a call to the Function constructor.
10.1.4 Scope Chain and Identifier Resolution
Every execution context has associated with it a scope chain. A scope chain is a list of objects that are searched when evaluating an Identifier. When control enters an execution context, a scope chain is created and populated with an initial set of objects, depending on the type of code. During execution within an execution context, the scope chain of the execution context is affected only by Blocks, with statements (see 12.10) and catch clauses (see 12.14).
During execution, the syntactic production PrimaryExpression : Identifier is evaluated using the following algorithm:
1. Get the next object in the scope chain. If there isn't one, go to step 5.
2. Call the [[HasProperty]] method of Result(1), passing the Identifier as the property name.
3. If Result(2) is true, return a value of type Reference whose base object is Result(1) and whose property name is the Identifier.
4. Go to step 1.
5. Return a value of type Reference whose base object is null and whose property name is the Identifier.
The result of evaluating an identifier is always a value of type Reference with its member name component equal to the identifier string.
10.1.5 Global Object
There is a unique global object (15.1), which is created before control enters any execution context. Initially the global object has the following properties:
Standard built-in objects such as Math, String, Date, parseInt, etc. These have attributes { [[Enumerable]]: false }.
Additional host defined properties. This may include a property whose value is the global object itself; for example, in the HTML document object model the window property of the global object is the global object itself.
As control enters execution contexts, and as ECMAScript code is executed, additional properties may be added to the global object and the initial properties may be changed.
10.1.6 Activation Object
When control enters an execution context for function code or a lexical block, an object called the activation object is created and associated with the execution context.
If the execution context is for function code, the activation object is initialised with a property with name arguments and attributes { [[Writable]]: true, [[Enumerable]]: false, [[Flexible]]: false }. The initial value of this property is the arguments object described below.
The activation object is then used as the environment object for the purposes of environment bindings instantiation.
The activation object is purely a specification mechanism. It is impossible for an ECMAScript program to access the activation object. It can access members of the activation object, but not the activation object itself. When the call operation is applied to a Reference value whose base object is an activation object, null is used as the this value of the call.
10.1.6.1 Usage Subset cautious Restrictions
For functions defined within an execution subset restricted to the cautious subset, the activation object is only initialized with an "arguments" property if the function mentions "arguments" freely in its body. In which case the "arguments" property is initialized with attributes {[[Writable]]: false, [[Enumerable]]: false, [[Flexible]]: false}.
10.1.7 This
There is a this value associated with every active execution context. The this value depends on the caller and the type of code being executed and is determined when control enters the execution context. The this value associated with an execution context is immutable.
10.1.8 Arguments Object
When control enters an execution context for function code, an arguments object is created (see above) and initialised as follows:
The value of the internal [[Prototype]] property of the arguments object is the original Array prototype object, the one that is the initial value of Array.prototype (see 15.4.3.1).
A property is created with name callee and property attributes { [[Writable]]: false, [[Enumerable]]: false, [[Flexible]]: false }. The initial value of this property is the Function object being executed. This allows anonymous functions to be recursive.
A property is created with name length and property attributes { [[Enumerable]]: false }. The initial value of this property is the number of actual parameter values supplied by the caller.
For each non-negative integer, arg, less than the value of the length property, a property is created with name ToString(arg) and property attributes { [[Writable]]: true, [[Enumerable]]: false, [[Flexible]]: false }. The initial value of this property is the value of the corresponding actual parameter supplied by the caller. The first actual parameter value corresponds to arg = 0, the second to arg = 1, and so on. In the case when arg is less than the number of formal parameters for the Function object, this property shares its value with the corresponding property of the activation object. This means that changing this property changes the corresponding property of the activation object and vice versa.
10.1.8.1 Usage Subset cautious Restrictions
For functions defined within an execution subset restricted to the cautious subset, an arguments object is only created if the function mentions "arguments" freely in its body.
If a arguments object is created, a callee property is not created.
The arguments object does not share properties with the activation object. Changing the value of a arguments object property does not change the value of the corresponding activation object property and vice versa.
10.2 Entering An Execution Context
Every function and constructor call enters a new execution context, even if a function is calling itself recursively. Every evalution of a Block enters enters a new execution context which is exited when the block evaluation completes. Every return exits an execution context. A thrown exception, if not caught, may also exit one or more execution contexts.
When control enters an execution context, the scope chain is created and initialised, environment bindings instantiation is performed, and the this value is determined.
The initialisation of the scope chain, environment bindings instantiation, and the determination of the this value depend on the type of code being entered.
10.2.1 Global Code
The scope chain is created and initialised to contain the global object and no others.
Environment bindings instantiation is performed using the global object as the environment object and using property attributes { [[Writable]]: true, [[Enumerable]]: true, [[Flexible]]: false }.
The this value is the global object.
10.2.2 Eval Code
When control enters an execution context for eval code, the previous active execution context, referred to as the calling context, is used to determine the scope chain, the environment object, and the this value. If there is no calling context, then initialising the scope chain, environment bindings instantiation, and determination of the this value are performed just as for global code.
The scope chain is initialised to contain the same objects, in the same order, as the calling context's scope chain. This includes objects added to the calling context's scope chain by Blocks, with statements and catch clauses.
Environment bindings instantiation is performed using the calling context's environment object and using the property attributes { [[Writable]]: true, [[Enumerable]]: true, [[Flexible]]: true }.
The this value is the same as the this value of the calling context.
10.2.2.1 Usage Subset cautious Restrictions
If either the execution context for the eval code or the execution context in which the eval operator was executed is subset restricted to the cautious subset, the eval code cannot instantiate variables, functions, or constants in the lexical context of its eval operator.
Instead, a new environment object is created and appended to the head of the calling context's scope chain and that environment object is used for environment bindings instantiation of the eval code.
10.2.3 Function Code
The scope chain is initialised to contain the activation object followed by the objects in the scope chain stored in the [[Scope]] property of the Function object.
Environment bindings instantiation is performed using the activation object as the environment object and using property attributes { [[Writable]]: true, [[Enumerable]]: true, [[Flexible]]: false }.
The caller provides the this value.
10.2.4 Lexical Block Code
A new activation object is created for use as the environment object. The scope chain is initialised to contain the new activation object followed by the objects in the current execution context's scope chain.
Environment bindings instantiation is performed using the new object as the environment object and using property attributes { [[Writable]]: false, [[Enumerable]]: false, [[Flexible]]: false }.
The this value is the same as the this value of the previously current context.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.mozilla.org/pipermail/es-discuss/attachments/20080709/ab3f1fd7/attachment-0002.html
More information about the Es4-discuss
mailing list