docs: private Node createTryCatchFinally(Node tryBlock, Node catchBlocks,
                                         Node finallyBlock, int lineno)
      {
          boolean hasFinally = (finallyBlock != null)
                               && (finallyBlock.getType() != Token.BLOCK
                                   || finallyBlock.hasChildren());
  
          // short circuit
          if (tryBlock.getType() == Token.BLOCK && !tryBlock.hasChildren()
              && !hasFinally)
          {
              return tryBlock;
          }
  
          boolean hasCatch = catchBlocks.hasChildren();
  
          // short circuit
          if (!hasFinally && !hasCatch)  {
              // bc finally might be an empty block...
              return tryBlock;
          }
  
          Node handlerBlock  = new Node(Token.LOCAL_BLOCK);
          Jump pn = new Jump(Token.TRY, tryBlock, lineno);
          pn.putProp(Node.LOCAL_BLOCK_PROP, handlerBlock);
  
          if (hasCatch) {
              // jump around catch code
              Node endCatch = Node.newTarget();
              pn.addChildToBack(makeJump(Token.GOTO, endCatch));
  
              // make a TARGET for the catch that the tcf node knows about
              Node catchTarget = Node.newTarget();
              pn.target = catchTarget;
              // mark it
              pn.addChildToBack(catchTarget);
  
              //
              //  Given
              //
              //   try {
              //       tryBlock;
              //   } catch (e if condition1) {
              //       something1;
              //   ...
              //
              //   } catch (e if conditionN) {
              //       somethingN;
              //   } catch (e) {
              //       somethingDefault;
              //   }
              //
              //  rewrite as
              //
              //   try {
              //       tryBlock;
              //       goto after_catch:
              //   } catch (x) {
              //       with (newCatchScope(e, x)) {
              //           if (condition1) {
              //               something1;
              //               goto after_catch;
              //           }
              //       }
              //   ...
              //       with (newCatchScope(e, x)) {
              //           if (conditionN) {
              //               somethingN;
              //               goto after_catch;
              //           }
              //       }
              //       with (newCatchScope(e, x)) {
              //           somethingDefault;
              //           goto after_catch;
              //       }
              //   }
              // after_catch:
              //
              // If there is no default catch, then the last with block
              // arround  "somethingDefault;" is replaced by "rethrow;"
  
              // It is assumed that catch handler generation will store
              // exeception object in handlerBlock register
  
              // Block with local for exception scope objects
              Node catchScopeBlock = new Node(Token.LOCAL_BLOCK);
  
              // expects catchblocks children to be (cond block) pairs.
              Node cb = catchBlocks.getFirstChild();
              boolean hasDefault = false;
              int scopeIndex = 0;
              while (cb != null) {
                  int catchLineNo = cb.getLineno();
  
                  Node name = cb.getFirstChild();
                  Node cond = name.getNext();
                  Node catchStatement = cond.getNext();
                  cb.removeChild(name);
                  cb.removeChild(cond);
                  cb.removeChild(catchStatement);
  
                  // Add goto to the catch statement to jump out of catch
                  // but prefix it with LEAVEWITH since try..catch produces
                  // "with"code in order to limit the scope of the exception
                  // object.
                  catchStatement.addChildToBack(new Node(Token.LEAVEWITH));
                  catchStatement.addChildToBack(makeJump(Token.GOTO, endCatch));
  
                  // Create condition "if" when present
                  Node condStmt;
                  if (cond.getType() == Token.EMPTY) {
                      condStmt = catchStatement;
                      hasDefault = true;
                  } else {
                      condStmt = createIf(cond, catchStatement, null,
                                          catchLineNo);
                  }
  
                  // Generate code to create the scope object and store
                  // it in catchScopeBlock register
                  Node catchScope = new Node(Token.CATCH_SCOPE, name,
                                             createUseLocal(handlerBlock));
                  catchScope.putProp(Node.LOCAL_BLOCK_PROP, catchScopeBlock);
                  catchScope.putIntProp(Node.CATCH_SCOPE_PROP, scopeIndex);
                  catchScopeBlock.addChildToBack(catchScope);
  
                  // Add with statement based on catch scope object
                  catchScopeBlock.addChildToBack(
                      createWith(createUseLocal(catchScopeBlock), condStmt,
                                 catchLineNo));
  
                  // move to next cb
                  cb = cb.getNext();
                  ++scopeIndex;
              }
              pn.addChildToBack(catchScopeBlock);
              if (!hasDefault) {
                  // Generate code to rethrow if no catch clause was executed
                  Node rethrow = new Node(Token.RETHROW);
                  rethrow.putProp(Node.LOCAL_BLOCK_PROP, handlerBlock);
                  pn.addChildToBack(rethrow);
              }
  
              pn.addChildToBack(endCatch);
          }
  
          if (hasFinally) {
              Node finallyTarget = Node.newTarget();
              pn.setFinally(finallyTarget);
  
              // add jsr finally to the try block
              pn.addChildToBack(makeJump(Token.JSR, finallyTarget));
  
              // jump around finally code
              Node finallyEnd = Node.newTarget();
              pn.addChildToBack(makeJump(Token.GOTO, finallyEnd));
  
              pn.addChildToBack(finallyTarget);
              Node fBlock = new Node(Token.FINALLY, finallyBlock);
              fBlock.putProp(Node.LOCAL_BLOCK_PROP, handlerBlock);
              pn.addChildToBack(fBlock);
  
              pn.addChildToBack(finallyEnd);
          }
          handlerBlock.addChildToBack(pn);
          return handlerBlock;
      }