public TCL.CompletionCode cmdProc( Interp interp, TclObject[] argv )
    {
      // Create the call frame and parameter bindings

      CallFrame frame = interp.newCallFrame( this, argv );

      // Execute the body

      interp.pushDebugStack( srcFileName, srcLineNumber );
      try
      {
        Parser.eval2( interp, body.array, body.index, body_length, 0 );
      }
      catch ( TclException e )
      {
        TCL.CompletionCode code = e.getCompletionCode();
        if ( code == TCL.CompletionCode.RETURN )
        {
          TCL.CompletionCode realCode = interp.updateReturnInfo();
          if ( realCode != TCL.CompletionCode.OK )
          {
            e.setCompletionCode( realCode );
            throw;
          }
        }
        else if ( code == TCL.CompletionCode.ERROR )
        {

          interp.addErrorInfo( "\n    (procedure \"" + argv[0] + "\" line " + interp.errorLine + ")" );
          throw;
        }
        else if ( code == TCL.CompletionCode.BREAK )
        {
          throw new TclException( interp, "invoked \"break\" outside of a loop" );
        }
        else if ( code == TCL.CompletionCode.CONTINUE )
        {
          throw new TclException( interp, "invoked \"continue\" outside of a loop" );
        }
        else
        {
          throw;
        }
      }
      finally
      {
        interp.popDebugStack();

        // The check below is a hack.  The problem is that there
        // could be unset traces on the variables, which cause
        // scripts to be evaluated.  This will clear the
        // errInProgress flag, losing stack trace information if
        // the procedure was exiting with an error.  The code
        // below preserves the flag.  Unfortunately, that isn't
        // really enough: we really should preserve the errorInfo
        // variable too (otherwise a nested error in the trace
        // script will trash errorInfo).  What's really needed is
        // a general-purpose mechanism for saving and restoring
        // interpreter state.

        if ( interp.errInProgress )
        {
          frame.dispose();
          interp.errInProgress = true;
        }
        else
        {
          frame.dispose();
        }
      }
      return TCL.CompletionCode.RETURN;
    }