Reinstate intialiser syntax in for-in loops
authoroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 15 Mar 2014 18:48:51 +0000 (18:48 +0000)
committeroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 15 Mar 2014 18:48:51 +0000 (18:48 +0000)
https://bugs.webkit.org/show_bug.cgi?id=130269

Reviewed by Michael Saboff.

Source/JavaScriptCore:

Disallowing the initialiser broke some sites so this patch re-allows
the syntax.  We still disallow the syntax in 'of' and pattern based
enumeration.

* parser/ASTBuilder.h:
(JSC::ASTBuilder::isBindingNode):
* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseVarDeclarationList):
(JSC::Parser<LexerType>::parseForStatement):
* parser/SyntaxChecker.h:
(JSC::SyntaxChecker::operatorStackPop):

LayoutTests:

Update and add test.

* js/parser-syntax-check-expected.txt:
* js/script-tests/parser-syntax-check.js:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@165682 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/js/parser-syntax-check-expected.txt
LayoutTests/js/script-tests/parser-syntax-check.js
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/parser/ASTBuilder.h
Source/JavaScriptCore/parser/Parser.cpp
Source/JavaScriptCore/parser/SyntaxChecker.h

index c76e4c9348f9344c96ee9f69a9f71c8ccd0aee84..42c49872357fda5c81bb86b3012ca8d045b63e10 100644 (file)
@@ -1,3 +1,15 @@
+2014-03-14  Oliver Hunt  <oliver@apple.com>
+
+        Reinstate intialiser syntax in for-in loops
+        https://bugs.webkit.org/show_bug.cgi?id=130269
+
+        Reviewed by Michael Saboff.
+
+        Update and add test.
+
+        * js/parser-syntax-check-expected.txt:
+        * js/script-tests/parser-syntax-check.js:
+
 2014-03-14  Mark Lam  <mark.lam@apple.com>
 
         Accessing __lookupGetter__ and __lookupSetter__ should not crash the VM when undefined.
index 673e40fdd0f63666b1a248093de038e192233021..f913759e49800f4cf57d6956c15ca0e46d1c1465 100644 (file)
@@ -431,8 +431,10 @@ PASS Valid:   "for ((a ? b : c) in c) break"
 PASS Valid:   "function f() { for ((a ? b : c) in c) break }"
 PASS Valid:   "for (var a in b in c) break"
 PASS Valid:   "function f() { for (var a in b in c) break }"
-PASS Invalid: "for (var a = 5 += 6 in b) break"
-PASS Invalid: "function f() { for (var a = 5 += 6 in b) break }"
+PASS Valid:   "for (var a = 5 += 6 in b) break"
+PASS Valid:   "function f() { for (var a = 5 += 6 in b) break }"
+PASS Valid:   "for (var a = debug('should not be hit') in b) break"
+PASS Valid:   "function f() { for (var a = debug('should not be hit') in b) break }"
 PASS Invalid: "for (var a += 5 in b) break"
 PASS Invalid: "function f() { for (var a += 5 in b) break }"
 PASS Invalid: "for (var a = in b) break"
@@ -443,8 +445,8 @@ PASS Invalid: "for (var a = -6, b in b) break"
 PASS Invalid: "function f() { for (var a = -6, b in b) break }"
 PASS Invalid: "for (var a, b = 8 in b) break"
 PASS Invalid: "function f() { for (var a, b = 8 in b) break }"
-PASS Invalid: "for (var a = (b in c) in d) break"
-PASS Invalid: "function f() { for (var a = (b in c) in d) break }"
+PASS Valid:   "for (var a = (b in c) in d) break"
+PASS Valid:   "function f() { for (var a = (b in c) in d) break }"
 PASS Invalid: "for (var a = (b in c in d) break"
 PASS Invalid: "function f() { for (var a = (b in c in d) break }"
 PASS Invalid: "for (var (a) in b) { }"
index 987ffd87af1061c9889049eff479755aaf31f17e..6e91d523e36633f6ed72ac4ae6febea52c357bf4 100644 (file)
@@ -284,13 +284,14 @@ valid  ("for ((a, b) in c) break");
 invalid("for (a ? b : c in c) break");
 valid  ("for ((a ? b : c) in c) break");
 valid  ("for (var a in b in c) break");
-invalid("for (var a = 5 += 6 in b) break");
+valid("for (var a = 5 += 6 in b) break");
+valid("for (var a = debug('should not be hit') in b) break");
 invalid("for (var a += 5 in b) break");
 invalid("for (var a = in b) break");
 invalid("for (var a, b in b) break");
 invalid("for (var a = -6, b in b) break");
 invalid("for (var a, b = 8 in b) break");
-invalid("for (var a = (b in c) in d) break");
+valid("for (var a = (b in c) in d) break");
 invalid("for (var a = (b in c in d) break");
 invalid("for (var (a) in b) { }");
 valid  ("for (var a = 7, b = c < d >= d ; f()[6]++ ; --i()[1]++ ) {}");
index 0fed77ee10909e8008a29b05b808804314148676..3ff4053d48972dff182866ed62b554245874899b 100644 (file)
@@ -1,3 +1,22 @@
+2014-03-14  Oliver Hunt  <oliver@apple.com>
+
+        Reinstate intialiser syntax in for-in loops
+        https://bugs.webkit.org/show_bug.cgi?id=130269
+
+        Reviewed by Michael Saboff.
+
+        Disallowing the initialiser broke some sites so this patch re-allows
+        the syntax.  We still disallow the syntax in 'of' and pattern based
+        enumeration.
+
+        * parser/ASTBuilder.h:
+        (JSC::ASTBuilder::isBindingNode):
+        * parser/Parser.cpp:
+        (JSC::Parser<LexerType>::parseVarDeclarationList):
+        (JSC::Parser<LexerType>::parseForStatement):
+        * parser/SyntaxChecker.h:
+        (JSC::SyntaxChecker::operatorStackPop):
+
 2014-03-14  Mark Lam  <mark.lam@apple.com>
 
         Accessing __lookupGetter__ and __lookupSetter__ should not crash the VM when undefined.
index 97499269ddb8ddaeb5fd5b2c95d101429fa34eca..a237cd2aed6574723674ec4cd7faf0179268f652 100644 (file)
@@ -406,6 +406,11 @@ public:
         return result;
     }
 
+    bool isBindingNode(const DeconstructionPattern& pattern)
+    {
+        return pattern->isBindingNode();
+    }
+
     StatementNode* createEmptyStatement(const JSTokenLocation& location) { return new (m_vm) EmptyStatementNode(location); }
 
     StatementNode* createVarStatement(const JSTokenLocation& location, ExpressionNode* expr, int start, int end)
index 749928b2c5329da543c70d5d01c8bd82ea8a6cf3..c01bf92cdcc0660791bae7aa2502bab3e59cafa3 100644 (file)
@@ -486,6 +486,7 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseVarDeclarati
                 next(TreeBuilder::DontBuildStrings); // consume '='
                 TreeExpression rhs = parseExpression(context);
                 node = context.createDeconstructingAssignment(location, pattern, rhs);
+                lastInitializer = rhs;
             }
         }
         
@@ -734,18 +735,21 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseForStatement(
         if (match(SEMICOLON))
             goto standardForLoop;
         
-        failIfFalse(declarations == 1, "must declare variables after 'var'");
-        failIfTrue(forInInitializer, "Cannot use initialiser syntax in a for-in loop");
-        
+        failIfFalse(declarations == 1, "can only declare a single variable in an enumeration");
+        failIfTrueIfStrict(forInInitializer, "Cannot use initialiser syntax in a strict mode enumeration");
+
+        if (forInInitializer)
+            failIfFalse(context.isBindingNode(forInTarget), "Cannot use initialiser syntax when binding to a pattern during enumeration");
+
         // Handle for-in with var declaration
         JSTextPosition inLocation = tokenStartPosition();
         bool isOfEnumeration = false;
         if (!consume(INTOKEN)) {
             failIfFalse(match(IDENT) && *m_token.m_data.ident == m_vm->propertyNames->of, "Expected either 'in' or 'of' in enumeration syntax");
             isOfEnumeration = true;
+            failIfTrue(forInInitializer, "Cannot use initialiser syntax in a for-of enumeration");
             next();
         }
-        
         TreeExpression expr = parseExpression(context);
         failIfFalse(expr, "Expected expression to enumerate");
         JSTextPosition exprEnd = lastTokenEndPosition();
index 0328b1273a224c1f1f09987708ebdd24df4b6758..021e1283242b5a064cad39cb5a550a9d6f60e9ea 100644 (file)
@@ -111,9 +111,10 @@ public:
     typedef int Clause;
     typedef int ConstDeclList;
     typedef int BinaryOperand;
+    enum { BindingDeconstruction = 1, ArrayDeconstruction, ObjectDeconstruction };
     typedef int DeconstructionPattern;
-    typedef int ArrayPattern;
-    typedef int ObjectPattern;
+    typedef DeconstructionPattern ArrayPattern;
+    typedef DeconstructionPattern ObjectPattern;
 
     static const bool CreatesAST = false;
     static const bool NeedsFreeVariableInfo = false;
@@ -265,7 +266,7 @@ public:
     
     ArrayPattern createArrayPattern(const JSTokenLocation&)
     {
-        return 1;
+        return ArrayDeconstruction;
     }
     void appendArrayPatternSkipEntry(ArrayPattern, const JSTokenLocation&)
     {
@@ -275,15 +276,21 @@ public:
     }
     ObjectPattern createObjectPattern(const JSTokenLocation&)
     {
-        return 1;
+        return ObjectDeconstruction;
     }
     void appendObjectPatternEntry(ArrayPattern, const JSTokenLocation&, bool, const Identifier&, DeconstructionPattern)
     {
     }
     DeconstructionPattern createBindingLocation(const JSTokenLocation&, const Identifier&, const JSTextPosition&, const JSTextPosition&)
     {
-        return 1;
+        return BindingDeconstruction;
     }
+
+    bool isBindingNode(DeconstructionPattern pattern)
+    {
+        return pattern == BindingDeconstruction;
+    }
+
 private:
     int m_topBinaryExpr;
     int m_topUnaryToken;