|
View:
New views
20 Messages
—
Rating Filter:
Alert me
|
| < Prev | 1 - 2 - 3 - 4 | Next > |
|
|
Newly revised Section 10 for ES3.1.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. _______________________________________________ Es4-discuss mailing list Es4-discuss@... https://mail.mozilla.org/listinfo/es4-discuss |
|
|
Re: Newly revised Section 10 for ES3.1.On Jul 9, 2008, at 5:16 PM, Allen Wirfs-Brock wrote:
Although the standard does not allow block-level function declarations, the following will parse and give identical results in all four of the major browsers (it will alert "2"): <script> function g() { if (true) { function f() { alert("1"); } function f() { alert("2"); } } f(); } g(); </script> This example will interoperably alert "1": <script> function g() { if (true) { function f() { alert("1"); } } f(); } g(); </script> As I understand it, your proposal would make the first example a syntax error and the second a runtime error (unless a global function named f is defined). I know from experience that sites do accidentally depend on the intersection of the different IE and Firefox extensions for block-level function declarations (and the Safari and Opera attempts to emulate them). Do you have evidence that leads you to conclude that your proposed behavior is compatible with the Web? I am almost certain it is not. Regards, Maciej _______________________________________________ Es4-discuss mailing list Es4-discuss@... https://mail.mozilla.org/listinfo/es4-discuss |
|
|
Re: Newly revised Section 10 for ES3.1.2008/7/9 Maciej Stachowiak <mjs@...>:
> Although the standard does not allow block-level function declarations I'd understood that, while ES3 didn't specify such declarations, it was not a violation of the standard to have them. I agree with your assessment of the compatibility impact, certainly. Mike _______________________________________________ Es4-discuss mailing list Es4-discuss@... https://mail.mozilla.org/listinfo/es4-discuss |
|
|
Re: Newly revised Section 10 for ES3.1.2008/7/9 Allen Wirfs-Brock <Allen.Wirfs-Brock@...>:
> 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 > > A FunctionDeclaration in a block is not valid in ES3, so apparently that is the reason for your note. > > 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. > This sentence is confusing. eval code is not necessarily global. Reading further down, it seems that you mean to define "top-level" as a new term for what we already know to mean [[Scope]] and then to define a block scope term. It seems that you are aiming to differentiate between function scope and a new type of "block" scope. If my assumption is correct, then creating a new type of "block" scope does not necessitate changing the term [[Scope]] to "top level". [[Scope]] can still be [[Scope]] and block scope can be called whatever you like ([[Block]], [[BlockScope]], et c) Does this sound reasonable? > > > 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. > The global object cannot have parameters, so I should probably assume that top-level means the same thing as [[Scope]] in ES3. When you use a made-up word like "over-writes" it is unclear. It could mean any of: 1) replaces the value 2) replaces the value and attributes 3) shadows a property in the scope chain (some do use the term "override" in this way) It is not clear what you mean. > "Top-level" function declarations are writable. Subsequent declarations or > assignments may change their value. This is an ES3 semantics. > I'm not sure how you understand it, but let me explain how I understand it, and maybe you'll see why what you've written is confusing to me. A FunctionDeclaration creates a property on the Variable object (or replaces the value and attributes if it it already exists). To quote the relevant part of the spec: | 10.1.3 Variable Instantiation | | Every execution context has associated with it a variable object. | Variables and functions declared in the source text are added as | properties of the variable object. For function code, parameters | are added as properties of the variable object. http://bclary.com/2004/11/07/#a-10.1.3 [snip] > > Within in a block, function declarations are read-only bindings. Since > declarations in blocks are new, this is a new semantics. IOW, a FunctionDeclaration creates a property of the BlockScope with the attributes {ReadOnly, DontDelete} > > 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 > Is this a problem in ES3? > · 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. > Five sensible suggestions, but they would be incompatible with ES3.0 (see quote above). [snip] > 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}. > That would be incompatible with ES3. Arguments is not ReadOnly (or "Writable:false"). (Doesn't seem like it would create a problem but this violate your "rule 1") Valid ES3: function z() { arguments = 1; return arguments; } z(); Garrett _______________________________________________ Es4-discuss mailing list Es4-discuss@... https://mail.mozilla.org/listinfo/es4-discuss |
|
|
Re: Newly revised Section 10 for ES3.1.On Wed, Jul 9, 2008 at 6:47 PM, Mike Shaver <mike.shaver@...> wrote:
2008/7/9 Maciej Stachowiak <mjs@...>: I believe the prohibition is in the ES3 syntax definition. -- Cheers, --MarkM _______________________________________________ Es4-discuss mailing list Es4-discuss@... https://mail.mozilla.org/listinfo/es4-discuss |
|
|
Re: Newly revised Section 10 for ES3.1.Hi Maciej, IIUC, these examples work the same in Allen's proposal as the do in ES4. If this does break the web, doesn't ES4 have exactly the same problem?
On Wed, Jul 9, 2008 at 6:33 PM, Maciej Stachowiak <mjs@...> wrote:
-- Cheers, --MarkM _______________________________________________ Es4-discuss mailing list Es4-discuss@... https://mail.mozilla.org/listinfo/es4-discuss |
|
|
Re: Newly revised Section 10 for ES3.1.On Jul 9, 2008, at 6:54 PM, Mark S. Miller wrote:
> On Wed, Jul 9, 2008 at 6:47 PM, Mike Shaver <mike.shaver@...> > wrote: > 2008/7/9 Maciej Stachowiak <mjs@...>: > > > Although the standard does not allow block-level function > declarations > > > I'd understood that, while ES3 didn't specify such declarations, it > > was not a violation of the standard to have them. I agree with your > > assessment of the compatibility impact, certainly. > > I believe the prohibition is in the ES3 syntax definition. ES3 chapter 16: An implementation shall report all errors as specified, except for the following: • An implementation may extend program and regular expression syntax. To permit this, all operations (such as calling eval, using a regular expression literal, or using the Function or RegExp constructor) that are allowed to throw SyntaxError are permitted to exhibit implementation-defined behaviour instead of throwing SyntaxError when they encounter an implementation-defined extension to the program or regular expression syntax. As Maciej notes, all four browsers extend syntax to support functions in sub-statement contexts. There's no prohibition given the chapter 16 language allowing such extensions. Is ES3.1 specifying "reality" (intersection semantics), or something not in the intersection or union of existing browsers' syntax and semantics, that is restrictive and therefore not compatible without a similar allowance for extensions? Chapter 16 is important to carry forward in any 3.1 or 4 successor edition. /be _______________________________________________ Es4-discuss mailing list Es4-discuss@... https://mail.mozilla.org/listinfo/es4-discuss |
|
|
Re: Newly revised Section 10 for ES3.1.On Jul 9, 2008, at 6:58 PM, Mark S. Miller wrote:
> Hi Maciej, IIUC, these examples work the same in Allen's proposal > as the do in ES4. If this does break the web, doesn't ES4 have > exactly the same problem? The idea for ES4 was to change the meaning of function sub-statements only under opt-in versioning. Implementations would do whatever they do today without an explicit type="application/ecmascript;version=4" or equivalent "application/javascript;version=2" on the script tag. /be _______________________________________________ Es4-discuss mailing list Es4-discuss@... https://mail.mozilla.org/listinfo/es4-discuss |
|
|
Re: Newly revised Section 10 for ES3.1.On Wed, Jul 9, 2008 at 7:02 PM, Brendan Eich <brendan@...> wrote:
-- Cheers, --MarkM _______________________________________________ Es4-discuss mailing list Es4-discuss@... https://mail.mozilla.org/listinfo/es4-discuss |