anchor.diff:      });
     };
   
  -  visitCatchClause(ast.CatchClause node) => (f, r, s) {
  -    // TODO(kmillikin): handle 'on T catch' clauses.
  -    return visit(node.body)(f, r, s);
  -  };
  +  _translateCatchClause(ast.CatchClause node, f, r, s) {
  +    var savedBlock = currentBlock;
  +    var catchBlock = currentBlock = emptyBlock();
  +    visit(node.body)(f, r, s);
  +    currentBlock = savedBlock;
  +    var parameters = [node.exceptionParameter.name];
  +    if (node.stackTraceParameter != null) {
  +      parameters.add(node.stackTraceParameter.name);
  +    }
  +    var args = [functionExpression(parameters, catchBlock)];
  +    if (node.onKeyword != null) {
  +      // We do not need to worry about `e` shadowing anything.
  +      args.add(functionExpression(['e'],
  +          AstFactory.isExpression(identifier('e'), false, node.exceptionType)));
  +    }
  +    return args;
  +  }
   
     visitTryStatement(ast.TryStatement node) => (f, r, s) {
       ast.Expression newJumpTarget(ast.Expression target) {
  
positive.code: 
    bool visitTryStatement(ast.TryStatement node) {
      var result = visit(node.body);
      if (node.catchClauses.isNotEmpty) {
        if (node.catchClauses.length != 1) {
          throw 'Analysis: unimplemented(TryStatement)';
        }
        if (visit(node.catchClauses.first)) result = true;
      }
      if (node.finallyBlock != null) {
        if (visit(node.finallyBlock)) result = true;
  
negative.code:   unreachable(node) => throw 'Unreachable(${node.runtimeType})';
    visitAnnotation(node) => unreachable(node);
    visitArgumentList(node) => unreachable(node);
    visitCatchClause(node) => unreachable(node);
    visitComment(node) => unreachable(node);
    visitCommentReference(node) => unreachable(node);
    visitConstructorFieldInitializer(node) => unreachable(node);
  