Attachment "errorstack2.patch" to
ticket [2868499fff]
added by
ferrieux
2009-10-20 23:12:30.
Index: generic/tclBasic.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclBasic.c,v
retrieving revision 1.404
diff -u -r1.404 tclBasic.c
--- generic/tclBasic.c 11 Sep 2009 20:13:27 -0000 1.404
+++ generic/tclBasic.c 20 Oct 2009 16:07:56 -0000
@@ -530,6 +530,10 @@
iPtr->errorInfo = NULL;
TclNewLiteralStringObj(iPtr->eiVar, "::errorInfo");
Tcl_IncrRefCount(iPtr->eiVar);
+ iPtr->errorStack = Tcl_NewListObj(0, NULL);
+ Tcl_IncrRefCount(iPtr->errorStack);
+ iPtr->useErrorStack=0;
+ iPtr->resetErrorStack = 1;
iPtr->errorCode = NULL;
TclNewLiteralStringObj(iPtr->ecVar, "::errorCode");
Tcl_IncrRefCount(iPtr->ecVar);
@@ -792,6 +796,14 @@
Tcl_RepresentationCmd, NULL, NULL);
/*
+ * TIP 348
+ */
+
+ Tcl_LinkVar(interp, "::tcl::useErrorStack",
+ (char *) &iPtr->useErrorStack,
+ TCL_LINK_INT);
+
+ /*
* Create the 'tailcall' command
*/
@@ -1470,6 +1482,7 @@
Tcl_DecrRefCount(iPtr->errorInfo);
iPtr->errorInfo = NULL;
}
+ Tcl_DecrRefCount(iPtr->errorStack);
if (iPtr->returnOpts) {
Tcl_DecrRefCount(iPtr->returnOpts);
}
@@ -8821,5 +8834,7 @@
* mode: c
* c-basic-offset: 4
* fill-column: 78
+ * tab-width: 8
+ * indent-tabs-mode: nil
* End:
*/
Index: generic/tclCmdIL.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCmdIL.c,v
retrieving revision 1.171
diff -u -r1.171 tclCmdIL.c
--- generic/tclCmdIL.c 20 Aug 2009 10:56:55 -0000 1.171
+++ generic/tclCmdIL.c 20 Oct 2009 16:07:56 -0000
@@ -118,6 +118,9 @@
int objc, Tcl_Obj *const objv[]);
static int InfoDefaultCmd(ClientData dummy, Tcl_Interp *interp,
int objc, Tcl_Obj *const objv[]);
+/* TIP #348 - New 'info' subcommand 'errorstack' */
+static int InfoErrorStackCmd(ClientData dummy, Tcl_Interp *interp,
+ int objc, Tcl_Obj *const objv[]);
/* TIP #280 - New 'info' subcommand 'frame' */
static int InfoFrameCmd(ClientData dummy, Tcl_Interp *interp,
int objc, Tcl_Obj *const objv[]);
@@ -164,6 +167,7 @@
{"complete", InfoCompleteCmd, NULL},
{"coroutine", TclInfoCoroutineCmd, NULL},
{"default", InfoDefaultCmd, NULL},
+ {"errorstack", InfoErrorStackCmd, NULL},
{"exists", TclInfoExistsCmd, TclCompileInfoExistsCmd},
{"frame", InfoFrameCmd, NULL},
{"functions", InfoFunctionsCmd, NULL},
@@ -1017,6 +1021,55 @@
/*
*----------------------------------------------------------------------
*
+ * InfoErrorStackCmd --
+ *
+ * Called to implement the "info errorstack" command that returns information
+ * about the last error's call stack. Handles the following syntax:
+ *
+ * info errorstack ?interp?
+ *
+ * Results:
+ * Returns TCL_OK if successful and TCL_ERROR if there is an error.
+ *
+ * Side effects:
+ * Returns a result in the interpreter's result object. If there is an
+ * error, the result is an error message.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+InfoErrorStackCmd(
+ ClientData dummy, /* Not used. */
+ Tcl_Interp *interp, /* Current interpreter. */
+ int objc, /* Number of arguments. */
+ Tcl_Obj *const objv[]) /* Argument objects. */
+{
+ Tcl_Interp *target;
+ Interp *iPtr;
+
+ if ((objc != 1) && (objc != 2)) {
+ Tcl_WrongNumArgs(interp, 1, objv, "?interp?");
+ return TCL_ERROR;
+ }
+
+ target = interp;
+ if (objc == 2) {
+ target = Tcl_GetSlave(interp, Tcl_GetString(objv[1]));
+ if (target == NULL) {
+ return TCL_ERROR;
+ }
+ }
+
+ iPtr = (Interp *) target;
+ Tcl_SetObjResult(interp, iPtr->errorStack);
+
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TclInfoExistsCmd --
*
* Called to implement the "info exists" command that determines whether
@@ -4388,5 +4441,7 @@
* mode: c
* c-basic-offset: 4
* fill-column: 78
+ * tab-width: 8
+ * indent-tabs-mode: nil
* End:
*/
Index: generic/tclInt.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclInt.h,v
retrieving revision 1.445
diff -u -r1.445 tclInt.h
--- generic/tclInt.h 30 Sep 2009 03:11:26 -0000 1.445
+++ generic/tclInt.h 20 Oct 2009 16:07:57 -0000
@@ -1895,6 +1895,9 @@
Tcl_Obj *eiVar; /* cached ref to ::errorInfo variable. */
Tcl_Obj *errorCode; /* errorCode value (now as a Tcl_Obj). */
Tcl_Obj *ecVar; /* cached ref to ::errorInfo variable. */
+ Tcl_Obj *errorStack; /* ::tcl::errorStack value (as a Tcl_Obj). */
+ int resetErrorStack; /* controls cleaning up of ::errorStack */
+ int useErrorStack; /* linked var gating ::errorStack overhead */
int returnLevel; /* [return -level] parameter. */
/*
Index: generic/tclNamesp.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclNamesp.c,v
retrieving revision 1.193
diff -u -r1.193 tclNamesp.c
--- generic/tclNamesp.c 30 Sep 2009 03:11:26 -0000 1.193
+++ generic/tclNamesp.c 20 Oct 2009 16:07:59 -0000
@@ -7633,6 +7633,41 @@
TCL_GLOBAL_ONLY);
}
}
+
+ /*
+ * TIP #348
+ */
+
+ if (iPtr->useErrorStack) {
+ int len;
+
+ if (Tcl_IsShared(iPtr->errorStack)) {
+ Tcl_Obj *newObj;
+
+ newObj = Tcl_DuplicateObj(iPtr->errorStack);
+ Tcl_DecrRefCount(iPtr->errorStack);
+ Tcl_IncrRefCount(newObj);
+ iPtr->errorStack = newObj;
+ }
+ Tcl_ListObjLength(interp, iPtr->errorStack, &len);
+ if (iPtr->resetErrorStack) {
+ iPtr->resetErrorStack = 0;
+ /* reset while keeping the list intrep as much as possible */
+ Tcl_ListObjReplace(interp, iPtr->errorStack, 0, len, 0, NULL);
+ len=0;
+ }
+ if (iPtr->varFramePtr != iPtr->rootFramePtr) {
+ Tcl_Obj *listPtr;
+ int result;
+
+ listPtr=Tcl_NewListObj(iPtr->varFramePtr->objc,
+ iPtr->varFramePtr->objv);
+ result = Tcl_ListObjReplace(interp, iPtr->errorStack, len, 1, 1, &listPtr);
+ if (result != TCL_OK) {
+ Tcl_DecrRefCount(listPtr);
+ }
+ }
+ }
}
/*
@@ -7640,5 +7675,7 @@
* mode: c
* c-basic-offset: 4
* fill-column: 78
+ * tab-width: 8
+ * indent-tabs-mode: nil
* End:
*/
Index: generic/tclResult.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclResult.c,v
retrieving revision 1.54
diff -u -r1.54 tclResult.c
--- generic/tclResult.c 17 Dec 2008 16:47:38 -0000 1.54
+++ generic/tclResult.c 20 Oct 2009 16:07:59 -0000
@@ -19,7 +19,7 @@
enum returnKeys {
KEY_CODE, KEY_ERRORCODE, KEY_ERRORINFO, KEY_ERRORLINE,
- KEY_LEVEL, KEY_OPTIONS, KEY_LAST
+ KEY_LEVEL, KEY_OPTIONS, KEY_ERRORSTACK, KEY_LAST
};
/*
@@ -922,6 +922,7 @@
Tcl_DecrRefCount(iPtr->errorInfo);
iPtr->errorInfo = NULL;
}
+ iPtr->resetErrorStack = 1;
iPtr->returnLevel = 1;
iPtr->returnCode = TCL_OK;
if (iPtr->returnOpts) {
@@ -1158,6 +1159,7 @@
TclNewLiteralStringObj(keys[KEY_ERRORCODE], "-errorcode");
TclNewLiteralStringObj(keys[KEY_ERRORINFO], "-errorinfo");
TclNewLiteralStringObj(keys[KEY_ERRORLINE], "-errorline");
+ TclNewLiteralStringObj(keys[KEY_ERRORSTACK],"-errorstack");
TclNewLiteralStringObj(keys[KEY_LEVEL], "-level");
TclNewLiteralStringObj(keys[KEY_OPTIONS], "-options");
@@ -1503,6 +1505,9 @@
Tcl_DictObjPut(NULL, options, keys[KEY_ERRORLINE],
Tcl_NewIntObj(iPtr->errorLine));
}
+ if (iPtr->useErrorStack > 1) {
+ Tcl_DictObjPut(NULL, options, keys[KEY_ERRORSTACK], iPtr->errorStack);
+ }
return options;
}
@@ -1624,5 +1629,7 @@
* mode: c
* c-basic-offset: 4
* fill-column: 78
+ * tab-width: 8
+ * indent-tabs-mode: nil
* End:
*/
Index: tests/error.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/error.test,v
retrieving revision 1.22
diff -u -r1.22 error.test
--- tests/error.test 28 Sep 2009 18:02:20 -0000 1.22
+++ tests/error.test 20 Oct 2009 16:08:00 -0000
@@ -152,6 +152,33 @@
set ::errorCode bogus
list [catch {error msg1 msg2 {}} msg] $msg $::errorInfo $::errorCode
} {1 msg1 msg2 {}}
+test error-4.6 {errorStack disabled by default} {
+ proc f x {g $x$x}
+ proc g x {error G:$x}
+ catch {f 12}
+ info errorstack
+} {}
+test error-4.7 {errorStack disabled by useErrorStack} {
+ set ::tcl::useErrorStack 0
+ proc f x {g $x$x}
+ proc g x {error G:$x}
+ catch {f 12}
+ info errorstack
+} {}
+test error-4.8 {errorStack enabled by useErrorStack} -body {
+ set ::tcl::useErrorStack 1
+ proc f x {g $x$x}
+ proc g x {error G:$x}
+ catch {f 12}
+ info errorstack
+} -match glob -result {{g 1212} {f 12} {namespace eval *}}
+test error-4.9 {options dict -errorstack key enabled by useErrorStack} -body {
+ set ::tcl::useErrorStack 2
+ proc f x {g $x$x}
+ proc g x {error G:$x}
+ catch {f 12} m d
+ dict get $d -errorstack
+} -match glob -result {{g 1212} {f 12} {namespace eval *}}
# Errors in error command itself
@@ -207,6 +234,16 @@
catch foo
list $::errorCode
} {NONE}
+test error-6.10 {catch must reset errorStack} -body {
+ set ::tcl::useErrorStack 1
+ proc f x {g $x$x}
+ proc g x {error G:$x}
+ catch {f 12}
+ set e1 [info errorstack]
+ catch {f 13}
+ set e2 [info errorstack]
+ list $e1 $e2
+} -match glob -result {{{g 1212} {f 12} {namespace eval *}} {{g 1313} {f 13} {namespace eval *}}}
test error-7.1 {Bug 1397843} -body {
variable cmds