break;
}
case Token.TRY:
{
Jump jump = (Jump)node;
Node finallytarget = jump.getFinally();
if (finallytarget != null) {
hasFinally = true;
loops.push(node);
loopEnds.push(finallytarget);
}
break;
}
case Token.TARGET:
case Token.LEAVEWITH:
if (!loopEnds.isEmpty() && loopEnds.peek() == node) {
loopEnds.pop();
loops.pop();
}
break;
case Token.YIELD:
((FunctionNode)tree).addResumptionPoint(node);
break;
case Token.RETURN:
{
boolean isGenerator = tree.getType() == Token.FUNCTION
&& ((FunctionNode)tree).isGenerator();
if (isGenerator) {
node.putIntProp(Node.GENERATOR_END_PROP, 1);
}
/* If we didn't support try/finally, it wouldn't be
* necessary to put LEAVEWITH nodes here... but as
* we do need a series of JSR FINALLY nodes before
* each RETURN, we need to ensure that each finally
* block gets the correct scope... which could mean
* that some LEAVEWITH nodes are necessary.
*/
if (!hasFinally)
break; // skip the whole mess.
Node unwindBlock = null;
for (int i=loops.size()-1; i >= 0; i--) {
Node n = (Node) loops.get(i);
int elemtype = n.getType();
if (elemtype == Token.TRY || elemtype == Token.WITH) {
Node unwind;
if (elemtype == Token.TRY) {
Jump jsrnode = new Jump(Token.JSR);
Node jsrtarget = ((Jump)n).getFinally();
jsrnode.target = jsrtarget;
unwind = jsrnode;
} else {
unwind = new Node(Token.LEAVEWITH);
}
if (unwindBlock == null) {
unwindBlock = new Node(Token.BLOCK,
node.getLineno());
}
unwindBlock.addChildToBack(unwind);
}
}
if (unwindBlock != null) {
Node returnNode = node;
Node returnExpr = returnNode.getFirstChild();
node = replaceCurrent(parent, previous, node, unwindBlock);
if (returnExpr == null || isGenerator) {
unwindBlock.addChildToBack(returnNode);
} else {
Node store = new Node(Token.EXPR_RESULT, returnExpr);
unwindBlock.addChildToFront(store);
returnNode = new Node(Token.RETURN_RESULT);
unwindBlock.addChildToBack(returnNode);
// transform return expression
transformCompilationUnit_r(tree, store, scope,
createScopeObjects,
inStrictMode);
}
// skip transformCompilationUnit_r to avoid infinite loop
continue siblingLoop;
}
break;
}
case Token.BREAK:
case Token.CONTINUE:
{
Jump jump = (Jump)node;
Jump jumpStatement = jump.getJumpStatement();
if (jumpStatement == null) Kit.codeBug();
for (int i = loops.size(); ;) {
if (i == 0) {
// Parser/IRFactory ensure that break/continue
// always has a jump statement associated with it
// which should be found
throw Kit.codeBug();
}
--i;
Node n = (Node) loops.get(i);
if (n == jumpStatement) {
break;
}
int elemtype = n.getType();
if (elemtype == Token.WITH) {
Node leave = new Node(Token.LEAVEWITH);
previous = addBeforeCurrent(parent, previous, node,
leave);
} else if (elemtype == Token.TRY) {
Jump tryNode = (Jump)n;
Jump jsrFinally = new Jump(Token.JSR);
jsrFinally.target = tryNode.getFinally();
previous = addBeforeCurrent(parent, previous, node,
jsrFinally);
}
}