Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Try optional catch binding #916

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/org/mozilla/javascript/CodeGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ private void visitStatement(Node node, int initialStackDepth) {
{
int localIndex = getLocalBlockRef(node);
int scopeIndex = node.getExistingIntProp(Node.CATCH_SCOPE_PROP);
String name = child.getString();
String name = child.getType() == Token.NAME ? child.getString() : "";
child = child.getNext();
visitExpression(child, 0); // load expression object
addStringPrefix(name);
Expand Down
40 changes: 25 additions & 15 deletions src/org/mozilla/javascript/IRFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -1236,27 +1236,34 @@ private Node transformTry(TryStatement node) {
Node catchBlocks = new Block();
for (CatchClause cc : node.getCatchClauses()) {
decompiler.addToken(Token.CATCH);
decompiler.addToken(Token.LP);

String varName = cc.getVarName().getIdentifier();
decompiler.addName(varName);

Name varName = cc.getVarName();
Node catchCond = null;
AstNode ccc = cc.getCatchCondition();
if (ccc != null) {
decompiler.addName(" ");
decompiler.addToken(Token.IF);
catchCond = transform(ccc);
} else {
catchCond = new EmptyExpression();
Node varNameNode = null;

if (varName != null) {
decompiler.addToken(Token.LP);
decompiler.addName(varName.getIdentifier());

varNameNode = createName(varName.getIdentifier());

AstNode ccc = cc.getCatchCondition();
if (ccc != null) {
decompiler.addName(" ");
decompiler.addToken(Token.IF);
catchCond = transform(ccc);
} else {
catchCond = new EmptyExpression();
}

decompiler.addToken(Token.RP);
}
decompiler.addToken(Token.RP);
decompiler.addEOL(Token.LC);

Node body = transform(cc.getBody());
decompiler.addEOL(Token.RC);

catchBlocks.addChildToBack(createCatch(varName, catchCond, body, cc.getLineno()));
catchBlocks.addChildToBack(createCatch(varNameNode, catchCond, body, cc.getLineno()));
}
Node finallyBlock = null;
if (node.getFinallyBlock() != null) {
Expand Down Expand Up @@ -1529,11 +1536,14 @@ private static Node createString(String string) {
* @param stmts the statements in the catch clause
* @param lineno the starting line number of the catch clause
*/
private Node createCatch(String varName, Node catchCond, Node stmts, int lineno) {
private Node createCatch(Node varName, Node catchCond, Node stmts, int lineno) {
if (varName == null) {
varName = new Node(Token.EMPTY);
}
if (catchCond == null) {
catchCond = new Node(Token.EMPTY);
}
return new Node(Token.CATCH, createName(varName), catchCond, stmts, lineno);
return new Node(Token.CATCH, varName, catchCond, stmts, lineno);
}

private static Node initFunction(
Expand Down
79 changes: 54 additions & 25 deletions src/org/mozilla/javascript/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -1637,39 +1637,68 @@ private TryStatement tryStatement() throws IOException {
reportError("msg.catch.unreachable");
}
int catchPos = ts.tokenBeg, lp = -1, rp = -1, guardPos = -1;
if (mustMatchToken(Token.LP, "msg.no.paren.catch", true)) lp = ts.tokenBeg;
Name varName = null;
AstNode catchCond = null;

mustMatchToken(Token.NAME, "msg.bad.catchcond", true);
switch (peekToken()) {
case Token.LP:
{
matchToken(Token.LP, true);
lp = ts.tokenBeg;
mustMatchToken(Token.NAME, "msg.bad.catchcond", true);

varName = createNameNode();
Comment jsdocNodeForName = getAndResetJsDoc();
if (jsdocNodeForName != null) {
varName.setJsDocNode(jsdocNodeForName);
}
String varNameString = varName.getIdentifier();
if (inUseStrictDirective) {
if ("eval".equals(varNameString)
|| "arguments".equals(varNameString)) {
reportError("msg.bad.id.strict", varNameString);
}
}

Name varName = createNameNode();
Comment jsdocNodeForName = getAndResetJsDoc();
if (jsdocNodeForName != null) {
varName.setJsDocNode(jsdocNodeForName);
}
String varNameString = varName.getIdentifier();
if (inUseStrictDirective) {
if ("eval".equals(varNameString) || "arguments".equals(varNameString)) {
reportError("msg.bad.id.strict", varNameString);
}
}
if (matchToken(Token.IF, true)) {
guardPos = ts.tokenBeg;
catchCond = expr();
} else {
sawDefaultCatch = true;
}

AstNode catchCond = null;
if (matchToken(Token.IF, true)) {
guardPos = ts.tokenBeg;
catchCond = expr();
} else {
sawDefaultCatch = true;
if (mustMatchToken(Token.RP, "msg.bad.catchcond", true)) {
rp = ts.tokenBeg;
}
mustMatchToken(Token.LC, "msg.no.brace.catchblock", true);
}
break;
case Token.LC:
if (compilerEnv.getLanguageVersion() >= Context.VERSION_ES6) {
matchToken(Token.LC, true);
} else {
reportError("msg.no.paren.catch");
}
break;
default:
reportError("msg.no.paren.catch");
break;
}

if (mustMatchToken(Token.RP, "msg.bad.catchcond", true)) rp = ts.tokenBeg;
mustMatchToken(Token.LC, "msg.no.brace.catchblock", true);

Block catchBlock = (Block) statements();
tryEnd = getNodeEnd(catchBlock);
Scope catchScope = new Scope(catchPos);
CatchClause catchNode = new CatchClause(catchPos);
catchNode.setLineno(ts.lineno);
pushScope(catchScope);
try {
statements(catchScope);
} finally {
popScope();
}

tryEnd = getNodeEnd(catchScope);
catchNode.setVarName(varName);
catchNode.setCatchCondition(catchCond);
catchNode.setBody(catchBlock);
catchNode.setBody(catchScope);
if (guardPos != -1) {
catchNode.setIfPosition(guardPos - catchPos);
}
Expand Down
4 changes: 3 additions & 1 deletion src/org/mozilla/javascript/ScriptRuntime.java
Original file line number Diff line number Diff line change
Expand Up @@ -4108,7 +4108,9 @@ public static Scriptable newCatchScope(

NativeObject catchScopeObject = new NativeObject();
// See ECMA 12.4
catchScopeObject.defineProperty(exceptionName, obj, ScriptableObject.PERMANENT);
if (exceptionName != null) {
catchScopeObject.defineProperty(exceptionName, obj, ScriptableObject.PERMANENT);
}

if (isVisible(cx, t)) {
// Add special Rhino object __exception__ defined in the catch
Expand Down
57 changes: 26 additions & 31 deletions src/org/mozilla/javascript/ast/CatchClause.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
import org.mozilla.javascript.Token;

/**
* Node representing a catch-clause of a try-statement.
* Node type is {@link Token#CATCH}.
* Node representing a catch-clause of a try-statement. Node type is {@link Token#CATCH}.
*
* <pre><i>CatchClause</i> :
* <b>catch</b> ( <i><b>Identifier</b></i> [<b>if</b> Expression] ) Block</pre>
Expand All @@ -19,7 +18,7 @@ public class CatchClause extends AstNode {

private Name varName;
private AstNode catchCondition;
private Block body;
private Scope body;
private int ifPosition = -1;
private int lp = -1;
private int rp = -1;
Expand All @@ -28,8 +27,7 @@ public class CatchClause extends AstNode {
type = Token.CATCH;
}

public CatchClause() {
}
public CatchClause() {}

public CatchClause(int pos) {
super(pos);
Expand All @@ -41,6 +39,7 @@ public CatchClause(int pos, int len) {

/**
* Returns catch variable node
*
* @return catch variable
*/
public Name getVarName() {
Expand All @@ -49,17 +48,20 @@ public Name getVarName() {

/**
* Sets catch variable node, and sets its parent to this node.
*
* @param varName catch variable
* @throws IllegalArgumentException if varName is {@code null}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still holds true?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1b473d6 I fixed.

*/
public void setVarName(Name varName) {
assertNotNull(varName);
this.varName = varName;
varName.setParent(this);
if (varName != null) {
varName.setParent(this);
}
}

/**
* Returns catch condition node, if present
*
* @return catch condition node, {@code null} if not present
*/
public AstNode getCatchCondition() {
Expand All @@ -68,69 +70,61 @@ public AstNode getCatchCondition() {

/**
* Sets catch condition node, and sets its parent to this node.
* @param catchCondition catch condition node. Can be {@code null}.
*
* @param catchCondition catch condition node. Can be {@code null}.
*/
public void setCatchCondition(AstNode catchCondition) {
this.catchCondition = catchCondition;
if (catchCondition != null)
if (catchCondition != null) {
catchCondition.setParent(this);
}
}

/**
* Returns catch body
*/
public Block getBody() {
/** Returns catch body */
public Scope getBody() {
return body;
}

/**
* Sets catch body, and sets its parent to this node.
*
* @throws IllegalArgumentException if body is {@code null}
*/
public void setBody(Block body) {
public void setBody(Scope body) {
assertNotNull(body);
this.body = body;
body.setParent(this);
}

/**
* Returns left paren position
*/
/** Returns left paren position */
public int getLp() {
return lp;
}

/**
* Sets left paren position
*/
/** Sets left paren position */
public void setLp(int lp) {
this.lp = lp;
}

/**
* Returns right paren position
*/
/** Returns right paren position */
public int getRp() {
return rp;
}

/**
* Sets right paren position
*/
/** Sets right paren position */
public void setRp(int rp) {
this.rp = rp;
}

/**
* Sets both paren positions
*/
/** Sets both paren positions */
public void setParens(int lp, int rp) {
this.lp = lp;
this.rp = rp;
}

/**
* Returns position of "if" keyword
*
* @return position of "if" keyword, if present, or -1
*/
public int getIfPosition() {
Expand All @@ -139,6 +133,7 @@ public int getIfPosition() {

/**
* Sets position of "if" keyword
*
* @param ifPosition position of "if" keyword, if present, or -1
*/
public void setIfPosition(int ifPosition) {
Expand All @@ -161,8 +156,8 @@ public String toSource(int depth) {
}

/**
* Visits this node, the catch var name node, the condition if
* non-{@code null}, and the catch body.
* Visits this node, the catch var name node, the condition if non-{@code null}, and the catch
* body.
*/
@Override
public void visit(NodeVisitor v) {
Expand Down
11 changes: 9 additions & 2 deletions src/org/mozilla/javascript/optimizer/BodyCodegen.java
Original file line number Diff line number Diff line change
Expand Up @@ -692,7 +692,10 @@ private void generateStatement(Node node) {
int local = getLocalBlockRegister(node);
int scopeIndex = node.getExistingIntProp(Node.CATCH_SCOPE_PROP);

String name = child.getString(); // name of exception
String name = null;
if (child.getType() == Token.NAME) {
name = child.getString(); // name of exception
}
child = child.getNext();
generateExpression(child, node); // load expression object
if (scopeIndex == 0) {
Expand All @@ -701,7 +704,11 @@ private void generateStatement(Node node) {
// Load previous catch scope object
cfw.addALoad(local);
}
cfw.addPush(name);
if (name != null) {
cfw.addPush(name);
} else {
cfw.add(ByteCode.ACONST_NULL);
}
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);

Expand Down
Loading