8156615: Catch parameter can be a BindingPattern in ES6 mode
authorsdama
Mon, 14 Nov 2016 22:33:33 -0800
changeset 41983 eb674141ab03
parent 41982 d7226731ac08
child 41984 8b4d9196a120
8156615: Catch parameter can be a BindingPattern in ES6 mode Summary: Added parser support for catch parameter being a binding pattern Reviewed-by: sundar, hannesw, attila Contributed-by: srinivas.dama@oracle.com
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/IRTranslator.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/CatchNode.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java
nashorn/test/script/basic/es6/destructuring.js
nashorn/test/script/basic/es6/destructuring.js.EXPECTED
nashorn/test/script/nosecurity/treeapi/destructuring_catch.js
nashorn/test/script/nosecurity/treeapi/destructuring_catch.js.EXPECTED
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/IRTranslator.java	Fri Nov 11 18:56:37 2016 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/IRTranslator.java	Mon Nov 14 22:33:33 2016 -0800
@@ -384,7 +384,7 @@
         final List<CatchTreeImpl> catchTrees = new ArrayList<>(catchNodes.size());
         for (final CatchNode catchNode : catchNodes) {
             catchTrees.add(new CatchTreeImpl(catchNode,
-                    translateIdent(catchNode.getException()),
+                    translateExpr(catchNode.getException()),
                     (BlockTree) translateBlock(catchNode.getBody()),
                     translateExpr(catchNode.getExceptionCondition())));
         }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java	Fri Nov 11 18:56:37 2016 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java	Mon Nov 14 22:33:33 2016 -0800
@@ -462,7 +462,7 @@
 
     @Override
     public boolean enterCatchNode(final CatchNode catchNode) {
-        final IdentNode exception = catchNode.getException();
+        final IdentNode exception = catchNode.getExceptionIdentifier();
         final Block     block     = lc.getCurrentBlock();
 
         start(catchNode);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java	Fri Nov 11 18:56:37 2016 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java	Mon Nov 14 22:33:33 2016 -0800
@@ -3255,7 +3255,7 @@
             enterBlock(catchBlock);
 
             final CatchNode  catchNode          = (CatchNode)catchBlocks.get(i).getStatements().get(0);
-            final IdentNode  exception          = catchNode.getException();
+            final IdentNode  exception          = catchNode.getExceptionIdentifier();
             final Expression exceptionCondition = catchNode.getExceptionCondition();
             final Block      catchBody          = catchNode.getBody();
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java	Fri Nov 11 18:56:37 2016 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java	Mon Nov 14 22:33:33 2016 -0800
@@ -1053,7 +1053,7 @@
 
         joinOnLabel(catchLabel);
         for(final CatchNode catchNode: tryNode.getCatches()) {
-            final IdentNode exception = catchNode.getException();
+            final IdentNode exception = catchNode.getExceptionIdentifier();
             onAssignment(exception, LvarType.OBJECT);
             final Expression condition = catchNode.getExceptionCondition();
             if(condition != null) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java	Fri Nov 11 18:56:37 2016 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java	Mon Nov 14 22:33:33 2016 -0800
@@ -178,6 +178,15 @@
     }
 
     @Override
+    public boolean enterCatchNode(final CatchNode catchNode) {
+        Expression exception = catchNode.getException();
+        if ((exception != null) && !(exception instanceof IdentNode)) {
+            throwNotImplementedYet("es6.destructuring", exception);
+        }
+        return true;
+    }
+
+    @Override
     public Node leaveCatchNode(final CatchNode catchNode) {
         return addStatement(catchNode);
     }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/CatchNode.java	Fri Nov 11 18:56:37 2016 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/CatchNode.java	Mon Nov 14 22:33:33 2016 -0800
@@ -35,8 +35,8 @@
 public final class CatchNode extends Statement {
     private static final long serialVersionUID = 1L;
 
-    /** Exception identifier. */
-    private final IdentNode exception;
+    /** Exception binding identifier or binding pattern. */
+    private final Expression exception;
 
     /** Exception condition. */
     private final Expression exceptionCondition;
@@ -52,21 +52,27 @@
      * @param lineNumber         lineNumber
      * @param token              token
      * @param finish             finish
-     * @param exception          variable name of exception
+     * @param exception          variable name or pattern of exception
      * @param exceptionCondition exception condition
      * @param body               catch body
      * @param isSyntheticRethrow true if this node is a synthetically generated rethrow node.
      */
-    public CatchNode(final int lineNumber, final long token, final int finish, final IdentNode exception,
+    public CatchNode(final int lineNumber, final long token, final int finish, final Expression exception,
             final Expression exceptionCondition, final Block body, final boolean isSyntheticRethrow) {
         super(lineNumber, token, finish);
-        this.exception          = exception == null ? null : exception.setIsInitializedHere();
+        if (exception instanceof IdentNode) {
+            this.exception = ((IdentNode) exception).setIsInitializedHere();
+        } else if ((exception instanceof LiteralNode.ArrayLiteralNode) || (exception instanceof ObjectNode)) {
+            this.exception = exception;
+        } else {
+            throw new IllegalArgumentException("invalid catch parameter");
+        }
         this.exceptionCondition = exceptionCondition;
-        this.body               = body;
+        this.body = body;
         this.isSyntheticRethrow = isSyntheticRethrow;
     }
 
-    private CatchNode(final CatchNode catchNode, final IdentNode exception, final Expression exceptionCondition,
+    private CatchNode(final CatchNode catchNode, final Expression exception, final Expression exceptionCondition,
             final Block body, final boolean isSyntheticRethrow) {
         super(catchNode);
         this.exception          = exception;
@@ -83,11 +89,10 @@
     public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
         if (visitor.enterCatchNode(this)) {
             return visitor.leaveCatchNode(
-                setException((IdentNode)exception.accept(visitor)).
-                setExceptionCondition(exceptionCondition == null ? null : (Expression)exceptionCondition.accept(visitor)).
-                setBody((Block)body.accept(visitor)));
+                    setException((Expression) exception.accept(visitor)).
+                            setExceptionCondition(exceptionCondition == null ? null : (Expression) exceptionCondition.accept(visitor)).
+                            setBody((Block) body.accept(visitor)));
         }
-
         return this;
     }
 
@@ -109,14 +114,25 @@
     }
 
     /**
-     * Get the identifier representing the exception thrown
-     * @return the exception identifier
+     * Get the binding pattern representing the exception thrown
+     *
+     * @return the exception binding pattern
      */
-    public IdentNode getException() {
+    public Expression getException() {
         return exception;
     }
 
     /**
+     * Get the identifier representing the exception thrown
+     *
+     * @return the exception identifier
+     * @throws ClassCastException if exception set is not binding identifier
+     */
+    public IdentNode getExceptionIdentifier() {
+        return (IdentNode) exception;
+    }
+
+    /**
      * Get the exception condition for this catch block
      * @return the exception condition
      */
@@ -146,13 +162,19 @@
 
     /**
      * Resets the exception of a catch block
-     * @param exception new exception
+     *
+     * @param exception new exception which can be binding identifier or binding
+     * pattern
      * @return new catch node if changed, same otherwise
      */
-    public CatchNode setException(final IdentNode exception) {
+    public CatchNode setException(final Expression exception) {
         if (this.exception == exception) {
             return this;
         }
+        /*check if exception is legitimate*/
+        if (!((exception instanceof IdentNode) || (exception instanceof LiteralNode.ArrayLiteralNode) || (exception instanceof ObjectNode))) {
+            throw new IllegalArgumentException("invalid catch parameter");
+        }
         return new CatchNode(this, exception, exceptionCondition, body, isSyntheticRethrow);
     }
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java	Fri Nov 11 18:56:37 2016 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java	Mon Nov 14 22:33:33 2016 -0800
@@ -2619,13 +2619,23 @@
                 next();
                 expect(LPAREN);
 
-                // FIXME: ES6 catch parameter can be a BindingIdentifier or a BindingPattern
-                // We need to generalize this here!
+                // ES6 catch parameter can be a BindingIdentifier or a BindingPattern
                 // http://www.ecma-international.org/ecma-262/6.0/
-                final IdentNode exception = getIdent();
-
-                // ECMA 12.4.1 strict mode restrictions
-                verifyStrictIdent(exception, "catch argument");
+                final String contextString = "catch argument";
+                final Expression exception = bindingIdentifierOrPattern(contextString);
+                final boolean isDestructuring = !(exception instanceof IdentNode);
+                if (isDestructuring) {
+                    verifyDestructuringBindingPattern(exception, new Consumer<IdentNode>() {
+                        @Override
+                        public void accept(final IdentNode identNode) {
+                            verifyIdent(identNode, contextString);
+                        }
+                    });
+                } else {
+                    // ECMA 12.4.1 strict mode restrictions
+                    verifyStrictIdent((IdentNode) exception, "catch argument");
+                }
+
 
                 // Nashorn extension: catch clause can have optional
                 // condition. So, a single try can have more than one
--- a/nashorn/test/script/basic/es6/destructuring.js	Fri Nov 11 18:56:37 2016 +0100
+++ b/nashorn/test/script/basic/es6/destructuring.js	Mon Nov 14 22:33:33 2016 -0800
@@ -62,4 +62,11 @@
 check("(function([x]) { return x; })()");
 check("for (var [[x, y, z] = [4, 5, 6]] = [7, 8, 9]; iterCount < 1; ) ;");
 check("for ([ arrow = () => {} ] of [[]]) ;");
+check("try { throw null;} catch({}) { }");
+check("try { throw {} } catch ({}) { }");
+check("try { throw [] } catch ([,]) { }");
+check("try { throw { w: [7, undefined, ] }} catch ({ w: [x, y, z] = [4, 5, 6] }) { }");
+check("try { throw { a: 2, b: 3} } catch ({a, b}) { }");
+check("try { throw [null] } catch ([[x]]) { }");
+check("try { throw { w: undefined } } catch ({ w: { x, y, z } = { x: 4, y: 5, z: 6 } }) { }");
 
--- a/nashorn/test/script/basic/es6/destructuring.js.EXPECTED	Fri Nov 11 18:56:37 2016 +0100
+++ b/nashorn/test/script/basic/es6/destructuring.js.EXPECTED	Mon Nov 14 22:33:33 2016 -0800
@@ -70,3 +70,24 @@
 java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:0 ES6 destructuring is not yet implemented
 for ([ arrow = () => {} ] of [[]]) ;
 ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:25 ES6 destructuring is not yet implemented
+try { throw null;} catch({}) { }
+                         ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:24 ES6 destructuring is not yet implemented
+try { throw {} } catch ({}) { }
+                        ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:24 ES6 destructuring is not yet implemented
+try { throw [] } catch ([,]) { }
+                        ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:44 ES6 destructuring is not yet implemented
+try { throw { w: [7, undefined, ] }} catch ({ w: [x, y, z] = [4, 5, 6] }) { }
+                                            ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:35 ES6 destructuring is not yet implemented
+try { throw { a: 2, b: 3} } catch ({a, b}) { }
+                                   ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:28 ES6 destructuring is not yet implemented
+try { throw [null] } catch ([[x]]) { }
+                            ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:38 ES6 destructuring is not yet implemented
+try { throw { w: undefined } } catch ({ w: { x, y, z } = { x: 4, y: 5, z: 6 } }) { }
+                                      ^
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/nosecurity/treeapi/destructuring_catch.js	Mon Nov 14 22:33:33 2016 -0800
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Tests to check representation of ES6 catch parameter as binding pattern.
+ *
+ * @test
+ * @option -scripting
+ * @run
+ */
+
+load(__DIR__ + "utils.js")
+
+var code = <<EOF
+
+try { throw null;} catch({}) { }
+try { throw {} } catch ({}) { }
+try { throw [] } catch ([,]) { }
+try { throw { w: [7, undefined, ] }} catch ({ w: [x, y, z] = [4, 5, 6] }) { }
+try { throw { a: 2, b: 3} } catch ({a, b}) { }
+try { throw [null] } catch ([[x]]) { }
+try { throw { w: undefined } } catch ({ w: { x, y, z } = { x: 4, y: 5, z: 6 } }) { }
+
+EOF
+
+parse("destructuring_catch.js", code, "--language=es6", new (Java.extend(visitor_es6, {
+    visitCatch : function (node, obj) {
+        obj.push(convert(node))
+    }
+})))
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/nosecurity/treeapi/destructuring_catch.js.EXPECTED	Mon Nov 14 22:33:33 2016 -0800
@@ -0,0 +1,399 @@
+[
+  {
+    "condition": "null",
+    "endPosition": "33",
+    "kind": "CATCH",
+    "parameter": {
+      "endPosition": "28",
+      "kind": "OBJECT_LITERAL",
+      "startPosition": "26",
+      "properties": []
+    },
+    "block": {
+      "endPosition": "33",
+      "kind": "BLOCK",
+      "statements": [],
+      "startPosition": "30"
+    },
+    "startPosition": "20"
+  },
+  {
+    "condition": "null",
+    "endPosition": "65",
+    "kind": "CATCH",
+    "parameter": {
+      "endPosition": "60",
+      "kind": "OBJECT_LITERAL",
+      "startPosition": "58",
+      "properties": []
+    },
+    "block": {
+      "endPosition": "65",
+      "kind": "BLOCK",
+      "statements": [],
+      "startPosition": "62"
+    },
+    "startPosition": "51"
+  },
+  {
+    "condition": "null",
+    "endPosition": "98",
+    "kind": "CATCH",
+    "parameter": {
+      "endPosition": "93",
+      "kind": "ARRAY_LITERAL",
+      "elements": [
+        null
+      ],
+      "startPosition": "90"
+    },
+    "block": {
+      "endPosition": "98",
+      "kind": "BLOCK",
+      "statements": [],
+      "startPosition": "95"
+    },
+    "startPosition": "83"
+  },
+  {
+    "condition": "null",
+    "endPosition": "176",
+    "kind": "CATCH",
+    "parameter": {
+      "endPosition": "171",
+      "kind": "OBJECT_LITERAL",
+      "startPosition": "143",
+      "properties": [
+        {
+          "getter": "null",
+          "endPosition": "169",
+          "kind": "PROPERTY",
+          "setter": "null",
+          "value": {
+            "expression": {
+              "endPosition": "169",
+              "kind": "ARRAY_LITERAL",
+              "elements": [
+                {
+                  "endPosition": "162",
+                  "kind": "NUMBER_LITERAL",
+                  "value": "4",
+                  "startPosition": "161"
+                },
+                {
+                  "endPosition": "165",
+                  "kind": "NUMBER_LITERAL",
+                  "value": "5",
+                  "startPosition": "164"
+                },
+                {
+                  "endPosition": "168",
+                  "kind": "NUMBER_LITERAL",
+                  "value": "6",
+                  "startPosition": "167"
+                }
+              ],
+              "startPosition": "160"
+            },
+            "endPosition": "169",
+            "kind": "ASSIGNMENT",
+            "variable": {
+              "endPosition": "157",
+              "kind": "ARRAY_LITERAL",
+              "elements": [
+                {
+                  "endPosition": "150",
+                  "kind": "IDENTIFIER",
+                  "name": "x",
+                  "startPosition": "149"
+                },
+                {
+                  "endPosition": "153",
+                  "kind": "IDENTIFIER",
+                  "name": "y",
+                  "startPosition": "152"
+                },
+                {
+                  "endPosition": "156",
+                  "kind": "IDENTIFIER",
+                  "name": "z",
+                  "startPosition": "155"
+                }
+              ],
+              "startPosition": "148"
+            },
+            "startPosition": "148"
+          },
+          "startPosition": "145",
+          "key": {
+            "endPosition": "146",
+            "kind": "IDENTIFIER",
+            "name": "w",
+            "startPosition": "145"
+          }
+        }
+      ]
+    },
+    "block": {
+      "endPosition": "176",
+      "kind": "BLOCK",
+      "statements": [],
+      "startPosition": "173"
+    },
+    "startPosition": "136"
+  },
+  {
+    "condition": "null",
+    "endPosition": "223",
+    "kind": "CATCH",
+    "parameter": {
+      "endPosition": "218",
+      "kind": "OBJECT_LITERAL",
+      "startPosition": "212",
+      "properties": [
+        {
+          "getter": "null",
+          "endPosition": "214",
+          "kind": "PROPERTY",
+          "setter": "null",
+          "value": {
+            "endPosition": "214",
+            "kind": "IDENTIFIER",
+            "name": "a",
+            "startPosition": "213"
+          },
+          "startPosition": "213",
+          "key": {
+            "endPosition": "214",
+            "kind": "IDENTIFIER",
+            "name": "a",
+            "startPosition": "213"
+          }
+        },
+        {
+          "getter": "null",
+          "endPosition": "217",
+          "kind": "PROPERTY",
+          "setter": "null",
+          "value": {
+            "endPosition": "217",
+            "kind": "IDENTIFIER",
+            "name": "b",
+            "startPosition": "216"
+          },
+          "startPosition": "216",
+          "key": {
+            "endPosition": "217",
+            "kind": "IDENTIFIER",
+            "name": "b",
+            "startPosition": "216"
+          }
+        }
+      ]
+    },
+    "block": {
+      "endPosition": "223",
+      "kind": "BLOCK",
+      "statements": [],
+      "startPosition": "220"
+    },
+    "startPosition": "205"
+  },
+  {
+    "condition": "null",
+    "endPosition": "262",
+    "kind": "CATCH",
+    "parameter": {
+      "endPosition": "257",
+      "kind": "ARRAY_LITERAL",
+      "elements": [
+        {
+          "endPosition": "256",
+          "kind": "ARRAY_LITERAL",
+          "elements": [
+            {
+              "endPosition": "255",
+              "kind": "IDENTIFIER",
+              "name": "x",
+              "startPosition": "254"
+            }
+          ],
+          "startPosition": "253"
+        }
+      ],
+      "startPosition": "252"
+    },
+    "block": {
+      "endPosition": "262",
+      "kind": "BLOCK",
+      "statements": [],
+      "startPosition": "259"
+    },
+    "startPosition": "245"
+  },
+  {
+    "condition": "null",
+    "endPosition": "347",
+    "kind": "CATCH",
+    "parameter": {
+      "endPosition": "342",
+      "kind": "OBJECT_LITERAL",
+      "startPosition": "301",
+      "properties": [
+        {
+          "getter": "null",
+          "endPosition": "340",
+          "kind": "PROPERTY",
+          "setter": "null",
+          "value": {
+            "expression": {
+              "endPosition": "340",
+              "kind": "OBJECT_LITERAL",
+              "startPosition": "320",
+              "properties": [
+                {
+                  "getter": "null",
+                  "endPosition": "326",
+                  "kind": "PROPERTY",
+                  "setter": "null",
+                  "value": {
+                    "endPosition": "326",
+                    "kind": "NUMBER_LITERAL",
+                    "value": "4",
+                    "startPosition": "325"
+                  },
+                  "startPosition": "322",
+                  "key": {
+                    "endPosition": "323",
+                    "kind": "IDENTIFIER",
+                    "name": "x",
+                    "startPosition": "322"
+                  }
+                },
+                {
+                  "getter": "null",
+                  "endPosition": "332",
+                  "kind": "PROPERTY",
+                  "setter": "null",
+                  "value": {
+                    "endPosition": "332",
+                    "kind": "NUMBER_LITERAL",
+                    "value": "5",
+                    "startPosition": "331"
+                  },
+                  "startPosition": "328",
+                  "key": {
+                    "endPosition": "329",
+                    "kind": "IDENTIFIER",
+                    "name": "y",
+                    "startPosition": "328"
+                  }
+                },
+                {
+                  "getter": "null",
+                  "endPosition": "338",
+                  "kind": "PROPERTY",
+                  "setter": "null",
+                  "value": {
+                    "endPosition": "338",
+                    "kind": "NUMBER_LITERAL",
+                    "value": "6",
+                    "startPosition": "337"
+                  },
+                  "startPosition": "334",
+                  "key": {
+                    "endPosition": "335",
+                    "kind": "IDENTIFIER",
+                    "name": "z",
+                    "startPosition": "334"
+                  }
+                }
+              ]
+            },
+            "endPosition": "340",
+            "kind": "ASSIGNMENT",
+            "variable": {
+              "endPosition": "317",
+              "kind": "OBJECT_LITERAL",
+              "startPosition": "306",
+              "properties": [
+                {
+                  "getter": "null",
+                  "endPosition": "309",
+                  "kind": "PROPERTY",
+                  "setter": "null",
+                  "value": {
+                    "endPosition": "309",
+                    "kind": "IDENTIFIER",
+                    "name": "x",
+                    "startPosition": "308"
+                  },
+                  "startPosition": "308",
+                  "key": {
+                    "endPosition": "309",
+                    "kind": "IDENTIFIER",
+                    "name": "x",
+                    "startPosition": "308"
+                  }
+                },
+                {
+                  "getter": "null",
+                  "endPosition": "312",
+                  "kind": "PROPERTY",
+                  "setter": "null",
+                  "value": {
+                    "endPosition": "312",
+                    "kind": "IDENTIFIER",
+                    "name": "y",
+                    "startPosition": "311"
+                  },
+                  "startPosition": "311",
+                  "key": {
+                    "endPosition": "312",
+                    "kind": "IDENTIFIER",
+                    "name": "y",
+                    "startPosition": "311"
+                  }
+                },
+                {
+                  "getter": "null",
+                  "endPosition": "315",
+                  "kind": "PROPERTY",
+                  "setter": "null",
+                  "value": {
+                    "endPosition": "315",
+                    "kind": "IDENTIFIER",
+                    "name": "z",
+                    "startPosition": "314"
+                  },
+                  "startPosition": "314",
+                  "key": {
+                    "endPosition": "315",
+                    "kind": "IDENTIFIER",
+                    "name": "z",
+                    "startPosition": "314"
+                  }
+                }
+              ]
+            },
+            "startPosition": "306"
+          },
+          "startPosition": "303",
+          "key": {
+            "endPosition": "304",
+            "kind": "IDENTIFIER",
+            "name": "w",
+            "startPosition": "303"
+          }
+        }
+      ]
+    },
+    "block": {
+      "endPosition": "347",
+      "kind": "BLOCK",
+      "statements": [],
+      "startPosition": "344"
+    },
+    "startPosition": "294"
+  }
+]