Title: [220068] trunk
Revision
220068
Author
utatane....@gmail.com
Date
2017-07-31 09:15:32 -0700 (Mon, 31 Jul 2017)

Log Message

[JSC] Support optional catch binding
https://bugs.webkit.org/show_bug.cgi?id=174981

Reviewed by Saam Barati.

JSTests:

* stress/optional-catch-binding-syntax.js: Added.
(testSyntax):
(testSyntaxError):
(catch.catch):
* stress/optional-catch-binding.js: Added.
(shouldBe):
(throwException):

Source/_javascript_Core:

This patch implements optional catch binding proposal[1], which is now stage 3.
This proposal adds a new `catch` brace with no error value binding.

    ```
        try {
            ...
        } catch {
            ...
        }
    ```

Sometimes we do not need to get error value actually. For example, the function returns
boolean which means whether the function succeeds.

    ```
    function parse(result) // -> bool
    {
         try {
             parseInner(result);
         } catch {
             return false;
         }
         return true;
    }
    ```

In the above case, we are not interested in the actual error value. Without this syntax,
we always need to introduce a binding for an error value that is just ignored.

[1]: https://michaelficarra.github.io/optional-catch-binding-proposal/

* bytecompiler/NodesCodegen.cpp:
(JSC::TryNode::emitBytecode):
* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseTryStatement):

LayoutTests:

Rebaseline existing tests.

* js/parser-syntax-check-expected.txt:
* js/script-tests/parser-syntax-check.js:
* sputnik/Conformance/12_Statement/12.14_The_try_Statement/S12.14_A16_T4-expected.txt:
* sputnik/Conformance/12_Statement/12.14_The_try_Statement/S12.14_A16_T4.html:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (220067 => 220068)


--- trunk/JSTests/ChangeLog	2017-07-31 15:13:26 UTC (rev 220067)
+++ trunk/JSTests/ChangeLog	2017-07-31 16:15:32 UTC (rev 220068)
@@ -1,3 +1,18 @@
+2017-07-31  Yusuke Suzuki  <utatane....@gmail.com>
+
+        [JSC] Support optional catch binding
+        https://bugs.webkit.org/show_bug.cgi?id=174981
+
+        Reviewed by Saam Barati.
+
+        * stress/optional-catch-binding-syntax.js: Added.
+        (testSyntax):
+        (testSyntaxError):
+        (catch.catch):
+        * stress/optional-catch-binding.js: Added.
+        (shouldBe):
+        (throwException):
+
 2017-07-28  Mark Lam  <mark....@apple.com>
 
         ObjectToStringAdaptiveStructureWatchpoint should not fire if it's dying imminently.

Added: trunk/JSTests/stress/optional-catch-binding-syntax.js (0 => 220068)


--- trunk/JSTests/stress/optional-catch-binding-syntax.js	                        (rev 0)
+++ trunk/JSTests/stress/optional-catch-binding-syntax.js	2017-07-31 16:15:32 UTC (rev 220068)
@@ -0,0 +1,30 @@
+function testSyntax(script) {
+    try {
+        eval(script);
+    } catch (error) {
+        if (error instanceof SyntaxError)
+            throw new Error("Bad error: " + String(error));
+    }
+}
+
+function testSyntaxError(script, message) {
+    var error = null;
+    try {
+        eval(script);
+    } catch (e) {
+        error = e;
+    }
+    if (!error)
+        throw new Error("Expected syntax error not thrown");
+
+    if (String(error) !== message)
+        throw new Error("Bad error: " + String(error));
+}
+
+testSyntax(`try { } catch { }`);
+testSyntax(`try { } catch { } finally { }`);
+testSyntaxError(`try { } catch { { }`, `SyntaxError: Unexpected end of script`);
+testSyntaxError(`try { } catch () { }`, `SyntaxError: Unexpected token ')'. Expected a parameter pattern or a ')' in parameter list.`);
+testSyntaxError(`try { } catch }`, `SyntaxError: Unexpected token '}'. Expected '(' to start a 'catch' target.`);
+testSyntaxError(`try { } catch {`, `SyntaxError: Unexpected end of script`);
+testSyntaxError(`try { } catch {`, `SyntaxError: Unexpected end of script`);

Added: trunk/JSTests/stress/optional-catch-binding.js (0 => 220068)


--- trunk/JSTests/stress/optional-catch-binding.js	                        (rev 0)
+++ trunk/JSTests/stress/optional-catch-binding.js	2017-07-31 16:15:32 UTC (rev 220068)
@@ -0,0 +1,50 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function throwException() {
+    throw new Error(`Cocoa`);
+}
+
+shouldBe(function () {
+    try {
+        throwException();
+    } catch {
+        return true;
+    }
+    return false;
+}(), true);
+
+shouldBe(function () {
+    var ok = false;
+    try {
+        throwException();
+    } catch {
+        ok = true;
+        return false;
+    } finally {
+        return ok;
+    }
+    return false;
+}(), true);
+
+shouldBe(function () {
+    let value = 'Cocoa';
+    try {
+        throwException();
+    } catch {
+        let value = 'Cappuccino';
+        return value;
+    }
+}(), 'Cappuccino');
+
+shouldBe(function () {
+    var value = 'Cocoa';
+    try {
+        throwException();
+    } catch {
+        let value = 'Cappuccino';
+    }
+    return value;
+}(), 'Cocoa');

Modified: trunk/LayoutTests/ChangeLog (220067 => 220068)


--- trunk/LayoutTests/ChangeLog	2017-07-31 15:13:26 UTC (rev 220067)
+++ trunk/LayoutTests/ChangeLog	2017-07-31 16:15:32 UTC (rev 220068)
@@ -1,3 +1,17 @@
+2017-07-31  Yusuke Suzuki  <utatane....@gmail.com>
+
+        [JSC] Support optional catch binding
+        https://bugs.webkit.org/show_bug.cgi?id=174981
+
+        Reviewed by Saam Barati.
+
+        Rebaseline existing tests.
+
+        * js/parser-syntax-check-expected.txt:
+        * js/script-tests/parser-syntax-check.js:
+        * sputnik/Conformance/12_Statement/12.14_The_try_Statement/S12.14_A16_T4-expected.txt:
+        * sputnik/Conformance/12_Statement/12.14_The_try_Statement/S12.14_A16_T4.html:
+
 2017-07-31  Per Arne Vollan  <pvol...@apple.com>
 
         Many web-platform tests are slow on Windows.

Modified: trunk/LayoutTests/js/parser-syntax-check-expected.txt (220067 => 220068)


--- trunk/LayoutTests/js/parser-syntax-check-expected.txt	2017-07-31 15:13:26 UTC (rev 220067)
+++ trunk/LayoutTests/js/parser-syntax-check-expected.txt	2017-07-31 16:15:32 UTC (rev 220068)
@@ -631,8 +631,8 @@
 PASS Invalid: "function f() { try {} finally {} catch(e) {} }". Produced the following syntax error: "SyntaxError: Unexpected keyword 'catch'"
 PASS Invalid: "try {} catch (...) {}". Produced the following syntax error: "SyntaxError: Unexpected token '...'. Expected a parameter pattern or a ')' in parameter list."
 PASS Invalid: "function f() { try {} catch (...) {} }". Produced the following syntax error: "SyntaxError: Unexpected token '...'. Expected a parameter pattern or a ')' in parameter list."
-PASS Invalid: "try {} catch {}". Produced the following syntax error: "SyntaxError: Unexpected token '{'. Expected '(' to start a 'catch' target."
-PASS Invalid: "function f() { try {} catch {} }". Produced the following syntax error: "SyntaxError: Unexpected token '{'. Expected '(' to start a 'catch' target."
+PASS Valid:   "try {} catch {}"
+PASS Valid:   "function f() { try {} catch {} }"
 PASS Valid:   "if (a) try {} finally {} else b;"
 PASS Valid:   "function f() { if (a) try {} finally {} else b; }"
 PASS Valid:   "if (--a()) do with(1) try {} catch(ke) { f() ; g() } while (a in b) else {}" with ReferenceError

Modified: trunk/LayoutTests/js/script-tests/parser-syntax-check.js (220067 => 220068)


--- trunk/LayoutTests/js/script-tests/parser-syntax-check.js	2017-07-31 15:13:26 UTC (rev 220067)
+++ trunk/LayoutTests/js/script-tests/parser-syntax-check.js	2017-07-31 16:15:32 UTC (rev 220068)
@@ -411,7 +411,7 @@
 invalid("try {} finally");
 invalid("try {} finally {} catch(e) {}");
 invalid("try {} catch (...) {}");
-invalid("try {} catch {}");
+valid  ("try {} catch {}");
 valid  ("if (a) try {} finally {} else b;");
 valid  ("if (--a()) do with(1) try {} catch(ke) { f() ; g() } while (a in b) else {}");
 invalid("if (a) try {} else b; catch (e) { }");

Modified: trunk/LayoutTests/sputnik/Conformance/12_Statement/12.14_The_try_Statement/S12.14_A16_T4-expected.txt (220067 => 220068)


--- trunk/LayoutTests/sputnik/Conformance/12_Statement/12.14_The_try_Statement/S12.14_A16_T4-expected.txt	2017-07-31 15:13:26 UTC (rev 220067)
+++ trunk/LayoutTests/sputnik/Conformance/12_Statement/12.14_The_try_Statement/S12.14_A16_T4-expected.txt	2017-07-31 16:15:32 UTC (rev 220068)
@@ -1,7 +1,6 @@
-CONSOLE MESSAGE: line 78: SyntaxError: Unexpected token '{'. Expected '(' to start a 'catch' target.
 S12.14_A16_T4
 
-PASS Expected parsing failure
+PASS No error detected
 
 TEST COMPLETE
 

Modified: trunk/LayoutTests/sputnik/Conformance/12_Statement/12.14_The_try_Statement/S12.14_A16_T4.html (220067 => 220068)


--- trunk/LayoutTests/sputnik/Conformance/12_Statement/12.14_The_try_Statement/S12.14_A16_T4.html	2017-07-31 15:13:26 UTC (rev 220067)
+++ trunk/LayoutTests/sputnik/Conformance/12_Statement/12.14_The_try_Statement/S12.14_A16_T4.html	2017-07-31 16:15:32 UTC (rev 220068)
@@ -86,11 +86,11 @@
 
 <script>
 if (!successfullyParsed)
-    printTestPassed('Expected parsing failure');
+    printTestFailed('Expected parsing failure');
 else if (sputnikException)
-    printTestPassed(sputnikException);
+    printTestFailed(sputnikException);
 else
-    printTestFailed("No error detected");
+    printTestPassed("No error detected");
 testPrint('<br /><span class="pass">TEST COMPLETE</span>');
 </script>
 </body>

Modified: trunk/Source/_javascript_Core/ChangeLog (220067 => 220068)


--- trunk/Source/_javascript_Core/ChangeLog	2017-07-31 15:13:26 UTC (rev 220067)
+++ trunk/Source/_javascript_Core/ChangeLog	2017-07-31 16:15:32 UTC (rev 220068)
@@ -1,5 +1,48 @@
 2017-07-31  Yusuke Suzuki  <utatane....@gmail.com>
 
+        [JSC] Support optional catch binding
+        https://bugs.webkit.org/show_bug.cgi?id=174981
+
+        Reviewed by Saam Barati.
+
+        This patch implements optional catch binding proposal[1], which is now stage 3.
+        This proposal adds a new `catch` brace with no error value binding.
+
+            ```
+                try {
+                    ...
+                } catch {
+                    ...
+                }
+            ```
+
+        Sometimes we do not need to get error value actually. For example, the function returns
+        boolean which means whether the function succeeds.
+
+            ```
+            function parse(result) // -> bool
+            {
+                 try {
+                     parseInner(result);
+                 } catch {
+                     return false;
+                 }
+                 return true;
+            }
+            ```
+
+        In the above case, we are not interested in the actual error value. Without this syntax,
+        we always need to introduce a binding for an error value that is just ignored.
+
+        [1]: https://michaelficarra.github.io/optional-catch-binding-proposal/
+
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::TryNode::emitBytecode):
+        * parser/Parser.cpp:
+        (JSC::Parser<LexerType>::parseTryStatement):
+
+2017-07-31  Yusuke Suzuki  <utatane....@gmail.com>
+
         Merge WTFThreadData to Thread::current
         https://bugs.webkit.org/show_bug.cgi?id=174716
 

Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (220067 => 220068)


--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2017-07-31 15:13:26 UTC (rev 220067)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2017-07-31 16:15:32 UTC (rev 220068)
@@ -3413,8 +3413,11 @@
             tryData = generator.pushTry(*catchLabel, *finallyViaThrowLabel, HandlerType::Finally);
         }
 
-        generator.emitPushCatchScope(m_lexicalVariables);
-        m_catchPattern->bindValue(generator, thrownValueRegister.get());
+        if (m_catchPattern) {
+            generator.emitPushCatchScope(m_lexicalVariables);
+            m_catchPattern->bindValue(generator, thrownValueRegister.get());
+        }
+
         generator.emitProfileControlFlow(m_tryBlock->endOffset() + 1);
         if (m_finallyBlock)
             generator.emitNode(dst, m_catchBlock);
@@ -3421,8 +3424,10 @@
         else
             generator.emitNodeInTailPosition(dst, m_catchBlock);
         generator.emitLoad(thrownValueRegister.get(), jsUndefined());
-        generator.emitPopCatchScope(m_lexicalVariables);
 
+        if (m_catchPattern)
+            generator.emitPopCatchScope(m_lexicalVariables);
+
         if (m_finallyBlock) {
             generator.emitSetCompletionType(CompletionType::Normal);
             generator.emitJump(*finallyLabel);

Modified: trunk/Source/_javascript_Core/parser/Parser.cpp (220067 => 220068)


--- trunk/Source/_javascript_Core/parser/Parser.cpp	2017-07-31 15:13:26 UTC (rev 220067)
+++ trunk/Source/_javascript_Core/parser/Parser.cpp	2017-07-31 16:15:32 UTC (rev 220068)
@@ -1633,27 +1633,32 @@
     if (match(CATCH)) {
         next();
         
-        handleProductionOrFail(OPENPAREN, "(", "start", "'catch' target");
-        AutoPopScopeRef catchScope(this, pushScope());
-        catchScope->setIsLexicalScope();
-        catchScope->preventVarDeclarations();
-        const Identifier* ident = nullptr;
-        if (matchSpecIdentifier()) {
-            ident = m_token.m_data.ident;
-            catchPattern = context.createBindingLocation(m_token.m_location, *ident, m_token.m_startPosition, m_token.m_endPosition, AssignmentContext::DeclarationStatement);
-            next();
-            failIfTrueIfStrict(catchScope->declareLexicalVariable(ident, false) & DeclarationResult::InvalidStrictMode, "Cannot declare a catch variable named '", ident->impl(), "' in strict mode");
+        if (match(OPENBRACE)) {
+            catchBlock = parseBlockStatement(context);
+            failIfFalse(catchBlock, "Unable to parse 'catch' block");
         } else {
-            catchPattern = parseDestructuringPattern(context, DestructuringKind::DestructureToCatchParameters, ExportType::NotExported);
-            failIfFalse(catchPattern, "Cannot parse this destructuring pattern");
+            handleProductionOrFail(OPENPAREN, "(", "start", "'catch' target");
+            AutoPopScopeRef catchScope(this, pushScope());
+            catchScope->setIsLexicalScope();
+            catchScope->preventVarDeclarations();
+            const Identifier* ident = nullptr;
+            if (matchSpecIdentifier()) {
+                ident = m_token.m_data.ident;
+                catchPattern = context.createBindingLocation(m_token.m_location, *ident, m_token.m_startPosition, m_token.m_endPosition, AssignmentContext::DeclarationStatement);
+                next();
+                failIfTrueIfStrict(catchScope->declareLexicalVariable(ident, false) & DeclarationResult::InvalidStrictMode, "Cannot declare a catch variable named '", ident->impl(), "' in strict mode");
+            } else {
+                catchPattern = parseDestructuringPattern(context, DestructuringKind::DestructureToCatchParameters, ExportType::NotExported);
+                failIfFalse(catchPattern, "Cannot parse this destructuring pattern");
+            }
+            handleProductionOrFail(CLOSEPAREN, ")", "end", "'catch' target");
+            matchOrFail(OPENBRACE, "Expected exception handler to be a block statement");
+            catchBlock = parseBlockStatement(context);
+            failIfFalse(catchBlock, "Unable to parse 'catch' block");
+            catchEnvironment = catchScope->finalizeLexicalEnvironment();
+            RELEASE_ASSERT(!ident || (catchEnvironment.size() == 1 && catchEnvironment.contains(ident->impl())));
+            popScope(catchScope, TreeBuilder::NeedsFreeVariableInfo);
         }
-        handleProductionOrFail(CLOSEPAREN, ")", "end", "'catch' target");
-        matchOrFail(OPENBRACE, "Expected exception handler to be a block statement");
-        catchBlock = parseBlockStatement(context);
-        failIfFalse(catchBlock, "Unable to parse 'catch' block");
-        catchEnvironment = catchScope->finalizeLexicalEnvironment();
-        RELEASE_ASSERT(!ident || (catchEnvironment.size() == 1 && catchEnvironment.contains(ident->impl())));
-        popScope(catchScope, TreeBuilder::NeedsFreeVariableInfo);
     }
     
     if (match(FINALLY)) {
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to