Annex A of 5th Edition
Hello Joseph
A.3
UnaryExpression: As written, it is suggested that the following is legal (which seems illegal): ++++++++5; ++typeof++5;
I think it shoud raise ReferenceError (in ES5) or SyntaxError (in ES6)
in ES5 because of section 16 Errors
Attempts to call PutValue on any value for which an early determination can
be made that the value is not a Reference (for example, executing the assignment statement 3=4).
code.google.com/p/esprima/issues/detail?id=81 is also interesting resource
in ES6 because of section 11.13 Assignment Operators people.mozilla.org/~jorendorff/es6-draft.html#sec-11.13 Static Semantics: Early Errors
Because example expression isn't Identifier, ArrayPattern or ObjectPattern, so early Syntax Error should be raised.
If I missed something, please point out.
, Yusuke Suzuki
Oops, sorry
in ES6
because of section 11.13 Assignment Operators people.mozilla.org/~jorendorff/es6-draft.html#sec-11.13 Static Semantics: Early Errors Because example expression isn't Identifier, ArrayPattern or ObjectPattern, so early Syntax Error should be raised.
This is the case of AssignmentExpression. In postfix / prefix operator, ecma-international.org/ecma-262/5.1/#sec-11.3
Because of section 16, PutValue should raise ReferenceError as early error, so I think above example should raise ReferenceError as early error (in ES5 and ES6)
From "Joseph Spencer" <js.developer.undefined at gmail.com>
ExpressionStatement:
Is the prevention of the token { an error in this context? Initially I thought it was to give parse flow over to the Block Production, until I realized that the following 'should' be a valid ExpressionStatement: {a:5}?5:4;
The spec uses lookahead restrictions on top of an LR(1) validated (ES3 era, needs revalidation) grammar. This is by design, not an error, and yes, it intentionally makes expression statements such as
{lol:42} ? "always" : "never";
be early errors.
The simplicity and tried-and-true LR validation are worth it. Anyone being clever can parenthesize. But of course your example is contrived, and it's rare but not unheared of to want { at start of an expression statement.
Same goes for 'function', and IME that lookahead restriction bites a bit more often, but people know to parenthesize.
It's an honor to get replies from you guys!
I feel more educated now about the grammar, and the negative lookahead for { makes sense now for ExpressionStatements as I didn't realize that object literals weren't considered ExpressionStatements.
Would the following make more sense for UnaryExpressions?
PostfixExpression: Identifier [no LineTerminator here] ++ Identifier [no LineTerminator here] --
PrefixExpression: ++ [no LineTerminator here] Identifier -- [no LineTerminator here] Identifier
UnaryExpression: LeftHandSideExpression PostfixExpression PrefixExpression delete UnaryExpression void UnaryExpression typeof UnaryExpression
- UnaryExpression
- UnaryExpression ~ UnaryExpression ! UnaryExpression
The grammar you think might make more sense is clearly broken, it does not produce
++a[i]
or
x.y.z--
Why are you trying to change the grammar?
My apologies on that one. I meant to type the following:
PostfixExpression: LeftHandSideExpression [no LineTerminator here] ++ LeftHandSideExpression [no LineTerminator here] --
PrefixExpression: ++ [no LineTerminator here] LeftHandSideExpression -- [no LineTerminator here] LeftHandSideExpression
It appears to me that as currently written the following is considered valid sytax:
++++someVar;
I hadn't thought about es3 compatability though, so I could see the reasoning in keeping it as is. As a noobie (and most likely someone in dire need of correction ;) approaching this , it seems to me that there are a few loose ends in the grammar. For instance, the following statements seem allowable by the grammar as currently written:
++typeof someVar; ++new Date(); ++null;
My knowledge is lacking on this though, so I am probably missing something. I was surprised to find that the following is valid syntax and a perfectly legal FunctionDeclaration, but throws a ReferenceError when executed:
function failPlease(){ alert(++++a); }
On Sep 6, 2012, at 12:17 PM, Joseph Spencer wrote:
My apologies on that one. I meant to type the following:
PostfixExpression: LeftHandSideExpression [no LineTerminator here] ++ LeftHandSideExpression [no LineTerminator here] --
PrefixExpression: ++ [no LineTerminator here] LeftHandSideExpression -- [no LineTerminator here] LeftHandSideExpression
It appears to me that as currently written the following is considered valid sytax:
++++someVar;
I hadn't thought about es3 compatability though, so I could see the reasoning in keeping it as is. As a noobie (and most likely someone in dire need of correction ;) approaching this , it seems to me that there are a few loose ends in the grammar. For instance, the following statements seem allowable by the grammar as currently written:
++typeof someVar; ++new Date(); ++null;
My knowledge is lacking on this though, so I am probably missing something. I was surprised to find that the following is valid syntax and a perfectly legal FunctionDeclaration, but throws a ReferenceError when executed:
function failPlease(){ alert(++++a); }
According to the specification, those all should produce runtime ReferenceError exceptions. However, at least Firefox, reports them as early syntax errors. Technically, that is out of conformance with the spec.
Based upon that evidence, it would appear that FF implements a grammar that is closer to you are suggesting rather than what is in the spec. In either case there is an error, but the FF implementation prevents the entire Program unit from running.
Chrome appears to follow the spec a little closer. Observe the following:
var someVar = 5;
//valid syntax, throws ReferenceError function passPlease(){ alert(++++someVar); }
//invalid syntax, throws SyntaxError function failPlease(){ alert(someVar++++); }
Allen Wirfs-Brock wrote:
On Sep 6, 2012, at 12:17 PM, Joseph Spencer wrote:
My apologies on that one. I meant to type the following:
PostfixExpression: LeftHandSideExpression [no LineTerminator here] ++ LeftHandSideExpression [no LineTerminator here] --
PrefixExpression: ++ [no LineTerminator here] LeftHandSideExpression -- [no LineTerminator here] LeftHandSideExpression
It appears to me that as currently written the following is considered valid sytax:
++++someVar;
I hadn't thought about es3 compatability though, so I could see the reasoning in keeping it as is. As a noobie (and most likely someone in dire need of correction ;) approaching this , it seems to me that there are a few loose ends in the grammar. For instance, the following statements seem allowable by the grammar as currently written:
++typeof someVar; ++new Date(); ++null;
My knowledge is lacking on this though, so I am probably missing something. I was surprised to find that the following is valid syntax and a perfectly legal FunctionDeclaration, but throws a ReferenceError when executed:
function failPlease(){ alert(++++a); }
According to the specification, those all should produce runtime ReferenceError exceptions. However, at least Firefox, reports them as early syntax errors. Technically, that is out of conformance with the spec.
Really? Clause 16 says:
"An implementation must treat any instance of the following kinds of errors as an early error:
- ...
- Attempts to call PutValue on any value for which an early determination can be made that the value is not a Reference (for example, executing the assignment statement 3=4)."
How are we not conforming?
Based upon that evidence, it would appear that FF implements a grammar that is closer to you are suggesting rather than what is in the spec.
No. We implement a recursive descent parser that follows the grammar but does early error checking based on parse tree inspection.
Joseph Spencer wrote:
My apologies on that one. I meant to type the following:
PostfixExpression: LeftHandSideExpression [no LineTerminator here] ++ LeftHandSideExpression [no LineTerminator here] --
PrefixExpression: ++ [no LineTerminator here] LeftHandSideExpression -- [no LineTerminator here] LeftHandSideExpression
It appears to me that as currently written the following is considered valid sytax:
++++someVar;
Yes, that is goofy. It dates back to ES1 -- if memory serves (and it may not at this late date), my original Netscape 2 "Mocha" JS engine did not parse this.
However, I think it may fall out of a desire by Microsoft back in the ES1 days to support the goofy ability of "host objects" to return References (ECMA-262 spec term).
I hadn't thought about es3 compatability though, so I could see the reasoning in keeping it as is.
Yeah, engine implementors have no good incentive to tweak here, and some legitimate fear of a breaking change that would only lose market share.
On Sep 6, 2012, at 4:35 PM, Brendan Eich wrote:
Allen Wirfs-Brock wrote:
According to the specification, those all should produce runtime ReferenceError exceptions. However, at least Firefox, reports them as early syntax errors. Technically, that is out of conformance with the spec.
Really? Clause 16 says:
"An implementation must treat any instance of the following kinds of errors as an early error:
- ...
- Attempts to call PutValue on any value for which an early determination can be made that the value is not a Reference (for example, executing the assignment statement 3=4)."
How are we not conforming?
Correct, I forgot about clause 16. Probably a good indication that some of these operators need an informative note referring to that Clause 16 requirement.
Wow, thanks for the reference to clause 16 (c16). I'm having a blast getting further into the spec and it really helps to have these conversations about it!
I believe its safe to say then that operating on c16 alone, FF handles the spec appropriately and Chrome probably gave too much heed to this:
"An early error is an error that can be detected and reported prior to the evaluation of any construct in the <i>Program</i> containing the
error" - c16
This must account for why the following doesn't throw an early error in Chrome:
function passes(){alert(++++someVar);}
In either case, it appears that Annex A is slightly out of sync with c16, and may benefit from being updated.
Would it not be beneficial to bring Annex A into greater conformity with the rest of the spec at this point?
Such changes seem relatively safe (to a noobie that is ;), as any code produced moving forward by devs would still parse just fine under older implementations that allowed for the unwanted syntax. It seems that doing so would also bring the ecosystem of implementations into greater alignment moving forward.
Joseph Spencer wrote:
Would it not be beneficial to bring Annex A into greater conformity with the rest of the spec at this point?
Maybe, but there's non-zero risk and the work has non-trivial opportunity cost. If you can come up with a minimal set of changes and propose them here, I'll take a look and see if TC39 has the budget to consider them.
On Sep 6, 2012, at 10:19 PM, Joseph Spencer wrote:
Would it not be beneficial to bring Annex A into greater conformity with the rest of the spec at this point?
Such changes seem relatively safe (to a noobie that is ;), as any code produced moving forward by devs would still parse just fine under older implementations that allowed for the unwanted syntax. It seems that doing so would also bring the ecosystem of implementations into greater alignment moving forward.
Annex A is just a informative summary of the normative BNF that is scattered through-out the rest of the document, so I think what you are really suggesting that w try to express more of the static semantics using the normative grammar. For the ES6 spec. I'm actually going in a different direction which is more algorithmic specification of the static semantic restrictions on syntactically valid programs. Many of these restrictions concern non-local feature interactions that are difficult or impossible to express purely using a non-attributed BNF. If you haven't already, you should take a look at the ES6 draft harmony:specification_drafts
Just this morning, I wrote static semantic rules that cover the Postfix and PrefixExpression (and other assignment contexts) that you had noted.
The attached should correct the following productions that are allowed by the current BNF in Annex A:
new undefined() new null() null() null.a() 5() 5.a ++++a a++++ ++\n\n\n\n LeftHandSideExpression null=5 5=5 this=6
Note: NaN and undefined aren't included in A.1 Lexical Grammar; however, Infinity is. Is this by design? My proposal adds them to A.1.
In spite of being NumericLiterals, Infinity and NaN are currently
referrable e.g. Infinity.a NaN.a. This is reflected in my
proposal, but should probably be removed as referable if
compatability isn't a concern here.
Let me know if there is anything that you find objectionable. I submit this with all humility, so feel free to critique / reject it in any way you see fit.
Thanks for the link! I checked out the .doc and see what you mean.
Especially for the following cases:
- detecting global assignment when "use strict"; has been declared
- var a = { duplicate:"not allowed", get duplicate(){return "not allowed"}, set duplicate(){throw "This isn't allowed"} }; etc.
Those two cases aren't covered by any BNF I've seen, and probably can't be without introducing more logic as you've endeavored. I see value in getting as close as possible with plain BNF, and then adding more algorithmic details as needed / required without making it completely un-readable.
So yes, I think that is what I'm suggesting. I think as we've seen with our Chromie friends, Annex A will probably be more adhered to at times than what is defined elsewhere in the spec (with to valid syntax) as it provides a complete overview of the grammar in roughly 20 pages or so. There does come a point where you have to delve further, hence the @See directives on the right.
On Sat, Sep 8, 2012 at 4:06 AM, Joseph Spencer <js.developer.undefined at gmail.com> wrote:
Note: NaN and undefined aren't included in A.1 Lexical Grammar; however, Infinity is. Is this by design? My proposal adds them to A.1.
NaN, undefined, and Infinity aren't keywords in JS. They're just global constants (see 15.1.1.1 through 15.1.1.3.)
You can make variables with those names... which makes for some funny-looking code, but it's allowed and for compatibility we mustn't change it:
function f(undefined) {
var NaN = "not a number", Infinity = 9999;
if (undefined)
return Infinity;
throw NaN;
}
Infinity appears in A.2, not A.1; Number("Infinity") uses that grammar. But in ordinary JS code Infinity is just an identifier.
Allen, for completeness, it'd be nice to point out the treatment of "Infinity" in the Note in section 9.3.1. I filed a bug: ecmascript#649
On Sat, Sep 8, 2012 at 8:54 AM, Jason Orendorff <jason.orendorff at gmail.com>wrote:
On Sat, Sep 8, 2012 at 4:06 AM, Joseph Spencer <js.developer.undefined at gmail.com> wrote:
Note: NaN and undefined aren't included in A.1 Lexical Grammar; however, Infinity is. Is this by design? My proposal adds them to A.1.
NaN, undefined, and Infinity aren't keywords in JS. They're just global constants (see 15.1.1.1 through 15.1.1.3.)
They could be contextual keywords inside of modules, which would fix the wart going forward w/o breaking backcompat.
Ahh, I see that now. You can disregard what I noted about those Constants.
null however is defined in A.1, which still leaves much of my proposed BNF on the table so please browse the rest of it.
I modified most Productions above the UnaryExpression in A.3.
It was necessary as well to change the rules for LeftHandSideExpression for what is currently written allows this: 5=5.
Did my attachments come through ok?
Thanks,
another problem with your grammar is that that NumericLiterals need to be Referable. For example the following is valid ES code:
0.0.toLocaleString()
But these are just details that could be fixed. There are many grammars that describe any language and creating one is a design activity that involves many trade-offs. The shape of the grammar also has many impacts upon the organization and content of a language specification. Your grammar seems like a perfectly fine approach to describing ECMAScript expressions. However, we currently have a different grammar that originated over 15 years ago. In general, we try to incrementally extend that grammar rather than do major refactorings. We prefer to only do major refactoring when it is necessary in order to express the specification of major new or under specified features. This approach lets us focus on the work of specifying new features rather than just shuffling the existing spec. and reduces the risk of introducing unintended specification bugs.
Another concern is that the entire grammar really needs to be revalidated after major changes. The last time the grammar was validated was for ES3 (1999) and we don't currently have the tools or people in place to validate it again (any volunteers out there??).
Bottom line: You seem to have a reasonable approach to the expression grammar. There are pros and cons that could be debated about your formulation relative to the current formulation. But, what your formulation accomplishes can (and has) already been dealt with using techniques that don't require grammar changes. Since we have lots of other work to do to finish ES6, refactoring the grammar along your lines just doesn't seem like a good use of resources at this time.
On Saturday, September 8, 2012 at 11:05 AM, Dean Landolt wrote:
On Sat, Sep 8, 2012 at 8:54 AM, Jason Orendorff <jason.orendorff at gmail.com (mailto:jason.orendorff at gmail.com)> wrote:
On Sat, Sep 8, 2012 at 4:06 AM, Joseph Spencer <js.developer.undefined at gmail.com (mailto:js.developer.undefined at gmail.com)> wrote:
Note: NaN and undefined aren't included in A.1 Lexical Grammar; however, Infinity is. Is this by design? My proposal adds them to A.1.
NaN, undefined, and Infinity aren't keywords in JS. They're just global constants (see 15.1.1.1 through 15.1.1.3.)
They could be contextual keywords inside of modules, which would fix the wart going forward w/o breaking backcompat.
I agree with the motivation, but having "two faces" (contextual and not) may create confusion.
Hello All,
This is my very first posting to this group!!! I'm very excited to be a part of ECMAScript development, even if it be minute.
My intention in sending this came about while writing an ECMAScript build tool and reading through the Production definitions of the language outlined in Annex A of ECMAScript 5th Edition.
A.4 ExpressionStatement:
Is the prevention of the token { an error in this context? Initially I thought it was to give parse flow over to the Block Production, until I realized that the following 'should' be a valid ExpressionStatement: {a:5}?5:4;
A.3 UnaryExpression: As written, it is suggested that the following is legal (which seems illegal): ++++++++5; ++typeof++5;
Please forgive me if my findings are false, and advise where my understanding is lacking.
-Joseph Spencer