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); }