8156615: Catch parameter can be a BindingPattern in ES6 mode

Added parser support for catch parameter being a binding pattern

Reviewed-by: sundar, hannesw, attila
This commit is contained in:
Srinivas Dama 2016-11-14 22:33:33 -08:00 committed by Srinivas Dama
parent 8a2f4e80e4
commit d867ed9a8d
11 changed files with 544 additions and 25 deletions

View File

@ -384,7 +384,7 @@ final class IRTranslator extends SimpleNodeVisitor {
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())));
}

View File

@ -462,7 +462,7 @@ final class AssignSymbols extends SimpleNodeVisitor implements Loggable {
@Override
public boolean enterCatchNode(final CatchNode catchNode) {
final IdentNode exception = catchNode.getException();
final IdentNode exception = catchNode.getExceptionIdentifier();
final Block block = lc.getCurrentBlock();
start(catchNode);

View File

@ -3255,7 +3255,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
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();

View File

@ -1053,7 +1053,7 @@ final class LocalVariableTypesCalculator extends SimpleNodeVisitor {
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) {

View File

@ -177,6 +177,15 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> implements Lo
return checkEval(callNode.setFunction(markerFunction(callNode.getFunction())));
}
@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);

View File

@ -35,8 +35,8 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
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 @@ public final class CatchNode extends Statement {
* @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 final class CatchNode extends Statement {
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,13 +114,24 @@ public final class CatchNode extends Statement {
}
/**
* 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 @@ public final class CatchNode extends Statement {
/**
* 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);
}

View File

@ -2619,13 +2619,23 @@ public class Parser extends AbstractParser implements Loggable {
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();
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");
}
// ECMA 12.4.1 strict mode restrictions
verifyStrictIdent(exception, "catch argument");
// Nashorn extension: catch clause can have optional
// condition. So, a single try can have more than one

View File

@ -62,4 +62,11 @@ check("(function({ x }) { return x; })()");
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 } }) { }");

View File

@ -70,3 +70,24 @@ for (var [[x, y, z] = [4, 5, 6]] = [7, 8, 9]; iterCount < 1; ) ;
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 } }) { }
^

View File

@ -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))
}
})))

View File

@ -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"
}
]