aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Bennett <steveb@workware.net.au>2023-05-18 15:34:26 +1000
committerSteve Bennett <steveb@workware.net.au>2023-06-21 09:17:47 +1000
commit0b08e74e656c6bfb65c6f38657be05bb463f54e6 (patch)
treefaa80db8a2cd6f24cf890ad6730c00f4d7dd2738
parentf07c53e38d55f0c7c648b7818798138d91053527 (diff)
downloadjimtcl-0b08e74e656c6bfb65c6f38657be05bb463f54e6.zip
jimtcl-0b08e74e656c6bfb65c6f38657be05bb463f54e6.tar.gz
jimtcl-0b08e74e656c6bfb65c6f38657be05bb463f54e6.tar.bz2
core: Display errors in a more "pythonesque" way
A typical error message now looks like this: t4.tcl:2: Error: syntax error in expression: "blah" Traceback (most recent call last): File "t4.tcl", line 14 c 1 2 3 File "t4.tcl", line 10, in c b a c File "t4.tcl", line 6, in b a A14 File "t4.tcl", line 2, in a expr blah This is produced by stackdump (that can be replaced), called by errorInfo. Note that now stacktraces (stacktrace, info stacktrace, $opts(-errorinfo)) include the running command at each level in addition to proc, file, line. In order for scripts to detect this new format, a new entry tcl_platform entry has been added: tcl_platform(stackFormat) = 4 (to signify 4 elements per frame) In addition, instead of building the error stack frame as the stack is unwound in response to an error, instead the entire current stack trace is captured by stacktrace. This means that the trace extends beyond the try/catch right back to the initial interpreter command. The 'stacktrace' command is now implemented in C based on the same code that generates the error stacktrace. Signed-off-by: Steve Bennett <steveb@workware.net.au>
-rw-r--r--jim-package.c3
-rw-r--r--jim.c283
-rw-r--r--jim.h6
-rw-r--r--stdlib.tcl39
-rw-r--r--tcltest.tcl46
-rw-r--r--tests/error.test12
-rw-r--r--tests/event.test6
-rw-r--r--tests/infoframe.test30
-rw-r--r--tests/misc.test13
-rw-r--r--tests/stacktrace.test84
10 files changed, 234 insertions, 288 deletions
diff --git a/jim-package.c b/jim-package.c
index 1d42197..be53688 100644
--- a/jim-package.c
+++ b/jim-package.c
@@ -181,9 +181,6 @@ static int package_cmd_provide(Jim_Interp *interp, int argc, Jim_Obj *const *arg
*/
static int package_cmd_require(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
- /* package require failing is important enough to add to the stack */
- interp->addStackTrace++;
-
return Jim_PackageRequire(interp, Jim_String(argv[0]), JIM_ERRMSG);
}
diff --git a/jim.c b/jim.c
index 012c0e4..908cc31 100644
--- a/jim.c
+++ b/jim.c
@@ -150,6 +150,7 @@ static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen);
static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len);
static int JimSetNewVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr, Jim_Var *var);
static Jim_Var *JimFindVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr);
+static void JimSetErrorStack(Jim_Interp *interp);
/* Fast access to the int (wide) value of an object which is known to be of int type */
#define JimWideValue(objPtr) (objPtr)->internalRep.wideValue
@@ -3748,12 +3749,10 @@ static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
objPtr->typePtr = &scriptObjType;
}
-static void JimAddErrorToStack(Jim_Interp *interp, ScriptObj *script);
-
/**
* Returns the parsed script.
* Note that if there is any possibility that the script is not valid,
- * call JimScriptValid() to check
+ * call JimParseCheckMissing() to check
*/
static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr)
{
@@ -3769,21 +3768,6 @@ static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr)
return (ScriptObj *)Jim_GetIntRepPtr(objPtr);
}
-/**
- * Returns 1 if the script is valid (parsed ok), otherwise returns 0
- * and leaves an error message in the interp result.
- *
- */
-static int JimScriptValid(Jim_Interp *interp, ScriptObj *script)
-{
- if (JimParseCheckMissing(interp, script->missing) == JIM_ERR) {
- JimAddErrorToStack(interp, script);
- return 0;
- }
- return 1;
-}
-
-
/* -----------------------------------------------------------------------------
* Commands
* ---------------------------------------------------------------------------*/
@@ -5686,7 +5670,6 @@ Jim_Interp *Jim_CreateInterp(void)
i->trueObj = Jim_NewIntObj(i, 1);
i->falseObj = Jim_NewIntObj(i, 0);
i->framePtr = i->topFramePtr = JimCreateCallFrame(i, NULL, i->emptyObj);
- i->errorFileNameObj = i->emptyObj;
i->result = i->emptyObj;
i->stackTrace = Jim_NewListObj(i, NULL, 0);
i->unknown = Jim_NewStringObj(i, "unknown", -1);
@@ -5695,7 +5678,6 @@ Jim_Interp *Jim_CreateInterp(void)
i->nullScriptObj = Jim_NewEmptyStringObj(i);
i->evalFrame = &i->topEvalFrame;
Jim_IncrRefCount(i->emptyObj);
- Jim_IncrRefCount(i->errorFileNameObj);
Jim_IncrRefCount(i->result);
Jim_IncrRefCount(i->stackTrace);
Jim_IncrRefCount(i->unknown);
@@ -5718,6 +5700,7 @@ Jim_Interp *Jim_CreateInterp(void)
Jim_SetVariableStrWithStr(i, "tcl_platform(bootstrap)", "0");
Jim_SetVariableStr(i, "tcl_platform(pointerSize)", Jim_NewIntObj(i, sizeof(void *)));
Jim_SetVariableStr(i, "tcl_platform(wordSize)", Jim_NewIntObj(i, sizeof(jim_wide)));
+ Jim_SetVariableStr(i, "tcl_platform(stackFormat)", Jim_NewIntObj(i, 4));
return i;
}
@@ -5746,7 +5729,6 @@ void Jim_FreeInterp(Jim_Interp *i)
Jim_DecrRefCount(i, i->errorProc);
Jim_DecrRefCount(i, i->unknown);
Jim_DecrRefCount(i, i->defer);
- Jim_DecrRefCount(i, i->errorFileNameObj);
Jim_DecrRefCount(i, i->nullScriptObj);
/* This will disard any cached commands */
@@ -5924,76 +5906,75 @@ static Jim_EvalFrame *JimGetEvalFrameByProcLevel(Jim_Interp *interp, int proclev
return NULL;
}
+/* Find the proc for a given eval frame.
+ * When a proc is called (JimCallProcedure), the command name is stored in the eval frame.
+ * So to find the proc that called the code that is currently executing, we need
+ * to look back through eval frames until we find one that has a command name
+ */
+static Jim_Obj *JimProcForEvalFrame(Jim_Interp *interp, Jim_EvalFrame *frame)
+{
+ /* If at the lowest level or if this level called a proc directly, go
+ * look for the caller
+ */
+ if (frame == interp->evalFrame || (frame->cmd && frame->cmd->cmdNameObj)) {
+ Jim_EvalFrame *e;
+ for (e = frame->parent; e; e = e->parent) {
+ if (e->cmd && e->cmd->isproc && e->cmd->cmdNameObj) {
+ break;
+ }
+ }
+ if (e && e->cmd && e->cmd->cmdNameObj) {
+ return e->cmd->cmdNameObj;
+ }
+ }
+ return NULL;
+}
-static void JimResetStackTrace(Jim_Interp *interp)
+/**
+ * Append stack trace info (proc, file, line, cmd) from the eval frame
+ * to listObj
+ */
+static void JimAddStackFrame(Jim_Interp *interp, Jim_EvalFrame *frame, Jim_Obj *listObj)
{
- Jim_DecrRefCount(interp, interp->stackTrace);
- interp->stackTrace = Jim_NewListObj(interp, NULL, 0);
- Jim_IncrRefCount(interp->stackTrace);
+ Jim_Obj *procNameObj = JimProcForEvalFrame(interp, frame);
+ Jim_Obj *fileNameObj = interp->emptyObj;
+ int linenr = 1;
+
+ if (frame->scriptObj) {
+ ScriptObj *script = JimGetScript(interp, frame->scriptObj);
+ fileNameObj = script->fileNameObj;
+ linenr = script->linenr;
+ }
+
+ Jim_ListAppendElement(interp, listObj, procNameObj ? procNameObj : interp->emptyObj);
+ Jim_ListAppendElement(interp, listObj, fileNameObj);
+ Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, linenr));
+ Jim_ListAppendElement(interp, listObj, Jim_NewListObj(interp, frame->argv, frame->argc));
}
static void JimSetStackTrace(Jim_Interp *interp, Jim_Obj *stackTraceObj)
{
- int len;
-
/* Increment reference first in case these are the same object */
Jim_IncrRefCount(stackTraceObj);
Jim_DecrRefCount(interp, interp->stackTrace);
interp->stackTrace = stackTraceObj;
interp->errorFlag = 1;
-
- /* This is a bit ugly.
- * If the filename of the last entry of the stack trace is empty,
- * the next stack level should be added.
- */
- len = Jim_ListLength(interp, interp->stackTrace);
- if (len >= 3) {
- if (Jim_Length(Jim_ListGetIndex(interp, interp->stackTrace, len - 2)) == 0) {
- interp->addStackTrace = 1;
- }
- }
}
-static void JimAppendStackTrace(Jim_Interp *interp, const char *procname,
- Jim_Obj *fileNameObj, int linenr)
+static void JimSetErrorStack(Jim_Interp *interp)
{
- if (strcmp(procname, "unknown") == 0) {
- procname = "";
- }
- if (!*procname && !Jim_Length(fileNameObj)) {
- /* No useful info here */
- return;
- }
-
- if (Jim_IsShared(interp->stackTrace)) {
- Jim_DecrRefCount(interp, interp->stackTrace);
- interp->stackTrace = Jim_DuplicateObj(interp, interp->stackTrace);
- Jim_IncrRefCount(interp->stackTrace);
- }
-
- /* If we have no procname but the previous element did, merge with that frame */
- if (!*procname && Jim_Length(fileNameObj)) {
- /* Just a filename. Check the previous entry */
- int len = Jim_ListLength(interp, interp->stackTrace);
+ if (!interp->errorFlag) {
+ int i;
+ Jim_Obj *stackTrace = Jim_NewListObj(interp, NULL, 0);
- if (len >= 3) {
- Jim_Obj *objPtr = Jim_ListGetIndex(interp, interp->stackTrace, len - 3);
- if (Jim_Length(objPtr)) {
- /* Yes, the previous level had procname */
- objPtr = Jim_ListGetIndex(interp, interp->stackTrace, len - 2);
- if (Jim_Length(objPtr) == 0) {
- /* But no filename, so merge the new info with that frame */
- ListSetIndex(interp, interp->stackTrace, len - 2, fileNameObj, 0);
- ListSetIndex(interp, interp->stackTrace, len - 1, Jim_NewIntObj(interp, linenr), 0);
- return;
- }
+ for (i = 0; i <= interp->procLevel; i++) {
+ Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, -i);
+ if (frame) {
+ JimAddStackFrame(interp, frame, stackTrace);
}
}
+ JimSetStackTrace(interp, stackTrace);
}
-
- Jim_ListAppendElement(interp, interp->stackTrace, Jim_NewStringObj(interp, procname, -1));
- Jim_ListAppendElement(interp, interp->stackTrace, fileNameObj);
- Jim_ListAppendElement(interp, interp->stackTrace, Jim_NewIntObj(interp, linenr));
}
int Jim_SetAssocData(Jim_Interp *interp, const char *key, Jim_InterpDeleteProc * delProc,
@@ -10759,10 +10740,7 @@ static int JimInvokeCommand(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
}
interp->evalDepth++;
prevPrivData = interp->cmdPrivData;
- /* XXX We should consider creating a struct here (on the stack) with a back pointer
- * so that the entire call chain can be walked. This would allow 'info frame' to walk
- * the full call chain, not just call frames
- */
+
tailcall:
interp->evalFrame->argc = objc;
@@ -10780,6 +10758,9 @@ tailcall:
interp->cmdPrivData = cmdPtr->u.native.privData;
retcode = cmdPtr->u.native.cmdProc(interp, objc, objv);
}
+ if (retcode == JIM_ERR) {
+ JimSetErrorStack(interp);
+ }
}
if (tailcallObj) {
@@ -10788,6 +10769,10 @@ tailcall:
tailcallObj = NULL;
}
+ /* These are now invalid */
+ interp->evalFrame->argc = 0;
+ interp->evalFrame->argv = NULL;
+
/* If a tailcall is returned for this frame, loop to invoke the new command */
if (retcode == JIM_EVAL && interp->framePtr->tailcallObj) {
JimDecrCmdRefCount(interp, cmdPtr);
@@ -10811,6 +10796,10 @@ tailcall:
out:
JimDecrCmdRefCount(interp, cmdPtr);
+ if (retcode == JIM_ERR) {
+ JimSetErrorStack(interp);
+ }
+
if (interp->framePtr->tailcallObj) {
/* We might have skipped invoking a tailcall, perhaps because of an error
* in defer handling so cleanup now
@@ -10870,41 +10859,6 @@ int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix, int objc, Jim_Obj *co
return ret;
}
-static void JimAddErrorToStack(Jim_Interp *interp, ScriptObj *script)
-{
- if (!interp->errorFlag) {
- /* This is the first error, so save the file/line information and reset the stack */
- interp->errorFlag = 1;
- Jim_IncrRefCount(script->fileNameObj);
- Jim_DecrRefCount(interp, interp->errorFileNameObj);
- interp->errorFileNameObj = script->fileNameObj;
- interp->errorLine = script->linenr;
-
- JimResetStackTrace(interp);
- /* Always add a level where the error first occurs */
- interp->addStackTrace++;
- }
-
- /* Now if this is an "interesting" level, add it to the stack trace */
- if (interp->addStackTrace > 0) {
- /* Add the stack info for the current level */
-
- JimAppendStackTrace(interp, Jim_String(interp->errorProc), script->fileNameObj, script->linenr);
-
- /* Note: if we didn't have a filename for this level,
- * don't clear the addStackTrace flag
- * so we can pick it up at the next level
- */
- if (Jim_Length(script->fileNameObj)) {
- interp->addStackTrace = 0;
- }
-
- Jim_DecrRefCount(interp, interp->errorProc);
- interp->errorProc = interp->emptyObj;
- Jim_IncrRefCount(interp->errorProc);
- }
-}
-
static int JimSubstOneToken(Jim_Interp *interp, const ScriptToken *token, Jim_Obj **objPtrPtr)
{
Jim_Obj *objPtr;
@@ -11060,7 +11014,6 @@ static int JimEvalObjList(Jim_Interp *interp, Jim_Obj *listPtr)
JimPanic((Jim_IsList(listPtr) == 0, "JimEvalObjList() invoked on non-list."));
- /* XXX should we pass listPtr as scriptObj here? */
JimPushEvalFrame(interp, &frame, NULL);
if (listPtr->internalRep.listValue.len) {
@@ -11099,7 +11052,8 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
Jim_IncrRefCount(scriptObjPtr); /* Make sure it's shared. */
script = JimGetScript(interp, scriptObjPtr);
- if (!JimScriptValid(interp, script)) {
+ if (JimParseCheckMissing(interp, script->missing) == JIM_ERR) {
+ JimSetErrorStack(interp);
Jim_DecrRefCount(interp, scriptObjPtr);
return JIM_ERR;
}
@@ -11151,6 +11105,7 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
JimPushEvalFrame(interp, &frame, scriptObjPtr);
+ /* Collect a new error stack trace if an error occurs */
interp->errorFlag = 0;
argv = sargv;
@@ -11301,12 +11256,7 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
/* Possibly add to the error stack trace */
if (retcode == JIM_ERR) {
- JimAddErrorToStack(interp, script);
- }
- /* Propagate the addStackTrace value through 'return -code error' */
- else if (retcode != JIM_RETURN || interp->returnCode != JIM_ERR) {
- /* No need to add stack trace */
- interp->addStackTrace = 0;
+ JimSetErrorStack(interp);
}
JimPopEvalFrame(interp);
@@ -11538,12 +11488,6 @@ badargset:
interp->returnLevel = 0;
}
}
- else if (retcode == JIM_ERR) {
- interp->addStackTrace++;
- Jim_DecrRefCount(interp, interp->errorProc);
- interp->errorProc = argv[0];
- Jim_IncrRefCount(interp->errorProc);
- }
interp->procLevel--;
return retcode;
@@ -11639,10 +11583,6 @@ int Jim_EvalFile(Jim_Interp *interp, const char *filename)
interp->returnLevel = 0;
}
}
- if (retcode == JIM_ERR) {
- /* EvalFile changes context, so add a stack frame here */
- interp->addStackTrace++;
- }
Jim_DecrRefCount(interp, scriptObjPtr);
@@ -11957,54 +11897,36 @@ static int JimInfoFrame(Jim_Interp *interp, Jim_Obj *levelObjPtr, Jim_Obj **objP
long level;
if (Jim_GetLong(interp, levelObjPtr, &level) == JIM_OK) {
- Jim_EvalFrame *targetEvalFrame = JimGetEvalFrameByProcLevel(interp, level);
- if (targetEvalFrame) {
+ Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, level);
+ if (frame) {
Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
- int linenr;
- Jim_Obj *fileNameObj;
- /*Jim_EvalFrame *procEvalFrame;*/
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "type", -1));
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "source", -1));
- if (targetEvalFrame->scriptObj) {
- ScriptObj *script = JimGetScript(interp, targetEvalFrame->scriptObj);
- linenr = script->linenr;
- fileNameObj = script->fileNameObj;
+ if (frame->scriptObj) {
+ ScriptObj *script = JimGetScript(interp, frame->scriptObj);
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "line", -1));
- Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, linenr));
+ Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, script->linenr));
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "file", -1));
- Jim_ListAppendElement(interp, listObj, fileNameObj);
+ Jim_ListAppendElement(interp, listObj, script->fileNameObj);
}
#ifndef JIM_NO_INTROSPECTION
{
- Jim_Obj *cmdObj = Jim_NewListObj(interp, targetEvalFrame->argv, targetEvalFrame->argc);
+ Jim_Obj *cmdObj = Jim_NewListObj(interp, frame->argv, frame->argc);
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "cmd", -1));
Jim_ListAppendElement(interp, listObj, cmdObj);
}
#endif
- /* XXX explain how this works */
- if (targetEvalFrame == interp->evalFrame || (targetEvalFrame->cmd && targetEvalFrame->cmd->isproc && targetEvalFrame->cmd->cmdNameObj)) {
- Jim_EvalFrame *e, *p = NULL;
- for (e = targetEvalFrame->parent; e; e = e->parent) {
- if (e->cmd && e->cmd->isproc && e->cmd->cmdNameObj) {
- p = e;
- break;
- }
- }
- if (p && p->level) {
- if (p->cmd && p->cmd->isproc) {
- if (p->cmd->cmdNameObj) {
- Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "proc", -1));
- Jim_ListAppendElement(interp, listObj, p->cmd->cmdNameObj);
- }
- }
+ {
+ Jim_Obj *procNameObj = JimProcForEvalFrame(interp, frame);
+ if (procNameObj) {
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "proc", -1));
+ Jim_ListAppendElement(interp, listObj, procNameObj);
}
}
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "level", -1));
- Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, interp->framePtr->level - targetEvalFrame->framePtr->level));
- Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "proclevel", -1));
- Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, targetEvalFrame->procLevel));
+ Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, interp->framePtr->level - frame->framePtr->level));
*objPtrPtr = listObj;
return JIM_OK;
@@ -13733,10 +13655,6 @@ static int Jim_EvalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
rc = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
}
- if (rc == JIM_ERR) {
- /* eval is "interesting", so add a stack frame here */
- interp->addStackTrace++;
- }
return rc;
}
@@ -13844,6 +13762,37 @@ static int Jim_ContinueCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const
return JimBreakContinueHelper(interp, argc, argv, JIM_CONTINUE);
}
+/* [stacktrace] */
+static int Jim_StacktraceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *listObj;
+ int i;
+ jim_wide skip = 0;
+ jim_wide last = 0;
+
+ if (argc > 1) {
+ if (Jim_GetWideExpr(interp, argv[1], &skip) != JIM_OK) {
+ return JIM_ERR;
+ }
+ }
+ if (argc > 2) {
+ if (Jim_GetWideExpr(interp, argv[2], &last) != JIM_OK) {
+ return JIM_ERR;
+ }
+ }
+
+ listObj = Jim_NewListObj(interp, NULL, 0);
+ for (i = skip; i <= interp->procLevel; i++) {
+ Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, -i);
+ if (frame->procLevel < last) {
+ break;
+ }
+ JimAddStackFrame(interp, frame, listObj);
+ }
+ Jim_SetResult(interp, listObj);
+ return JIM_OK;
+}
+
/* [return] */
static int Jim_ReturnCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
@@ -14851,7 +14800,7 @@ wrongargs:
}
else {
exitCode = Jim_EvalObj(interp, argv[idx]);
- /* Don't want any caught error included in a later stack trace */
+ /* Once caught, a new error will set a stack trace again */
interp->errorFlag = 0;
}
interp->signal_level -= sig;
@@ -16117,7 +16066,6 @@ static int Jim_ErrorCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar
JimSetStackTrace(interp, argv[2]);
return JIM_ERR;
}
- interp->addStackTrace++;
return JIM_ERR;
}
@@ -16443,6 +16391,7 @@ static const struct {
{"local", Jim_LocalCoreCommand},
{"upcall", Jim_UpcallCoreCommand},
{"apply", Jim_ApplyCoreCommand},
+ {"stacktrace", Jim_StacktraceCoreCommand},
{NULL, NULL},
};
diff --git a/jim.h b/jim.h
index a8d8cbb..0d5ab0a 100644
--- a/jim.h
+++ b/jim.h
@@ -540,9 +540,9 @@ typedef struct Jim_PrngState {
* ---------------------------------------------------------------------------*/
typedef struct Jim_Interp {
Jim_Obj *result; /* object returned by the last command called. */
- int errorLine; /* Error line where an error occurred. */
- Jim_Obj *errorFileNameObj; /* Error file where an error occurred. */
- int addStackTrace; /* > 0 if a level should be added to the stack trace */
+ int unused_errorLine; /* Error line where an error occurred. */
+ Jim_Obj *unused_errorFileNameObj; /* Error file where an error occurred. */
+ int unused_addStackTrace;
int maxCallFrameDepth; /* Used for infinite loop detection. */
int maxEvalDepth; /* Used for infinite loop detection. */
int evalDepth; /* Current eval depth */
diff --git a/stdlib.tcl b/stdlib.tcl
index 5945185..289acbf 100644
--- a/stdlib.tcl
+++ b/stdlib.tcl
@@ -33,39 +33,28 @@ proc function {value} {
return $value
}
-# Returns a live stack trace as a list of proc filename line ...
-# with 3 entries for each stack frame (proc),
-# (deepest level first)
-proc stacktrace {{skip 0}} {
- set frames {}
- loop level $skip+1 [info frame] {
- set frame [info frame -$level]
- if {[dict exists $frame proc]} {
- lappend frames $frame(proc) $frame(file) $frame(line)
- }
- }
- return $frames
-}
-
# Returns a human-readable version of a stack trace
proc stackdump {stacktrace} {
set lines {}
- foreach {l f p} [lreverse $stacktrace] {
+ lappend lines "Traceback (most recent call last):"
+ foreach {cmd l f p} [lreverse $stacktrace] {
set line {}
- if {$p ne ""} {
- append line "in procedure '$p' "
- if {$f ne ""} {
- append line "called "
- }
- }
if {$f ne ""} {
- append line "at file \"$f\", line $l"
+ append line " File \"$f\", line $l"
+ }
+ if {$p ne ""} {
+ append line ", in $p"
}
if {$line ne ""} {
lappend lines $line
+ if {$cmd ne ""} {
+ lappend lines " $cmd"
+ }
}
}
- join $lines \n
+ if {[llength $lines] > 1} {
+ return [join $lines \n]
+ }
}
# Add the given script to $jim::defer, to be evaluated when the current
@@ -81,10 +70,8 @@ proc errorInfo {msg {stacktrace ""}} {
if {$stacktrace eq ""} {
# By default add the stack backtrace and the live stacktrace
set stacktrace [info stacktrace]
- # omit the procedure 'errorInfo' from the stack
- lappend stacktrace {*}[stacktrace 1]
}
- lassign $stacktrace p f l
+ lassign $stacktrace p f l cmd
if {$f ne ""} {
set result "$f:$l: Error: "
}
diff --git a/tcltest.tcl b/tcltest.tcl
index 2b8d3d8..9478dcd 100644
--- a/tcltest.tcl
+++ b/tcltest.tcl
@@ -78,11 +78,20 @@ proc skiptest {{msg {}}} {
# Also convert proc name ::a into a for compatibility between Tcl and Jim
proc basename-stacktrace {stacktrace} {
set result {}
- foreach {p f l} $stacktrace {
- if {[string match ::* $p]} {
+ foreach {p f l cmd} $stacktrace {
+ if {[string match *tcltest-* $f]} {
+ #break
+ }
+ if {$p eq "::tcltest::RunTest"} {
+ set p test
+ } elseif {[string match ::* $p]} {
set p [string range $p 2 end]
}
- lappend result $p [file tail $f] $l
+ set cmd [string map [list \n \\n] $cmd]
+ if {[string length $cmd] > 20} {
+ set cmd [string range $cmd 0 20]...
+ }
+ lappend result $p [file tail $f] $l $cmd
}
return $result
}
@@ -101,28 +110,23 @@ if {[catch {info version}]} {
proc testreport {} {
::tcltest::cleanupTests
}
- proc stacktrace {{skip 0}} {
- set trace {}
- # Need to skip info frame 0 and this (stacktrace) level
- incr skip 1
- set maxlevel [info frame]
- for {set level $skip} {$level < $maxlevel} {incr level} {
+ proc stacktrace {{skip 0} {last 0}} {
+ set frames {}
+ incr skip
+ for {set level $skip} {$level < [info frame] - $last} {incr level} {
set frame [info frame -$level]
- if {[dict get $frame type] eq "source" && [dict exists $frame proc]} {
+ puts $frame
+ if {[dict get $frame type] ne "source"} {
+ continue
+ }
+ if {[dict exists $frame proc]} {
set proc [dict get $frame proc]
- # make it look like it is running under Jim tcltest
- if {$proc eq "::tcltest::RunTest"} {
- set proc test
- } else {
- set proc [string range $proc 2 end]
- }
- lappend trace $proc [dict get $frame file] [dict get $frame line]
- if {$proc eq "test"} {
- break
- }
+ } else {
+ set proc ""
}
+ lappend frames $proc [dict get $frame file] [dict get $frame line] [dict get $frame cmd]
}
- return $trace
+ return $frames
}
return
}
diff --git a/tests/error.test b/tests/error.test
index d226900..5669b7b 100644
--- a/tests/error.test
+++ b/tests/error.test
@@ -11,12 +11,12 @@ proc b {} {
}
}
-test error-1.1 "Rethrow caught error" {
+test error-1.1 {Rethrow caught error} -body {
set rc [catch {b} msg]
#puts stderr "error-1.1\n[errorInfo $msg]\n"
list $rc $msg [basename-stacktrace [info stacktrace]]
-} {1 {error thrown from a} {{} error.test 4 a error.test 8 b error.test 15}}
+} -result {1 {error thrown from a} {a error.test 4 error\ \{error\ thrown\ f... b error.test 8 a test error.test 15 b {} error.test 14 test\ error-1.1\ \{Rethr...}}
proc c {} {
a
@@ -30,22 +30,22 @@ proc e {} {
d
}
-test error-1.2 "Modify stacktrace" {
+test error-1.2 {Modify stacktrace} -body {
set rc [catch {e} msg]
set st [info stacktrace]
# Now elide one entry from the stacktrace
#puts [errorInfo $msg]
set newst {}
- foreach {p f l} $st {
+ foreach {p f l cmd} $st {
if {$p ne "d"} {
- lappend newst $p $f $l
+ lappend newst $p $f $l $cmd
}
}
# Now rethrow with the new stack
set rc [catch {error $msg $newst} msg]
#puts [errorInfo $msg]
basename-stacktrace [info stacktrace]
-} {{} error.test 4 a error.test 22 c error.test 26 e error.test 34}
+} -result {a error.test 4 error\ \{error\ thrown\ f... c error.test 22 a e error.test 30 d test error.test 34 e {} error.test 33 test\ error-1.2\ \{Modif...}
# Package should be able to invoke exit, which should exit if not caught
test error-2.1 "Exit from package" {
diff --git a/tests/event.test b/tests/event.test
index 278f4e3..b95f76e 100644
--- a/tests/event.test
+++ b/tests/event.test
@@ -92,7 +92,11 @@ test event-7.4 {bgerror throws an error} -constraints jim -body {
update
}
} -result {stdin:3: Error: inside bgerror
-at file "stdin", line 3}
+Traceback (most recent call last):
+ File "stdin", line 6
+ bgerror err1
+ File "stdin", line 3, in bgerror
+ error {inside bgerror}}
# end of bgerror tests
catch {rename bgerror {}}
diff --git a/tests/infoframe.test b/tests/infoframe.test
index e8544b1..ef827bc 100644
--- a/tests/infoframe.test
+++ b/tests/infoframe.test
@@ -1,44 +1,50 @@
source [file dirname [info script]]/testing.tcl
-proc a {n} {
+proc a {n args} {
if {$n eq "trace"} {
- return [basename-stacktrace [stacktrace]]
+ return [basename-stacktrace [stacktrace {*}$args]]
}
set frame [info frame $n]
if {![dict exists $frame proc]} {
dict set frame proc {}
}
- basename-stacktrace [list [dict get $frame proc] [file tail [dict get $frame file]] [dict get $frame line]]
+ basename-stacktrace [list [dict get $frame proc] [file tail [dict get $frame file]] [dict get $frame line] [dict get $frame cmd]]
}
-proc b {n} {
- a $n
+proc b {args} {
+ a {*}$args
}
-proc c {n} {
- b $n
+proc c {args} {
+ b {*}$args
}
# --- Don't change line numbers above
test info-frame-1.1 {Current command} -body {
c 0
-} -result {a infoframe.test 7}
+} -result {a infoframe.test 7 {info frame 0}}
test info-frame-1.2 {Current Proc} -body {
c -1
-} -result {b infoframe.test 15}
+} -result {b infoframe.test 15 {a -1}}
test info-frame-1.3 Caller -body {
c -2
-} -result {c infoframe.test 19}
+} -result {c infoframe.test 19 {b -2}}
test info-frame-1.4 {Caller of Caller} -body {
c -3
-} -result {test infoframe.test 37}
+} -result {test infoframe.test 37 {c -3}}
test stacktrace-1.1 {Full stack trace} -body {
c trace
-} -result {a infoframe.test 5 b infoframe.test 15 c infoframe.test 19 test infoframe.test 41}
+} -result {a infoframe.test 5 stacktrace b infoframe.test 15 {a trace} c infoframe.test 19 {b trace} test infoframe.test 41 {c trace} {} infoframe.test 40 test\ stacktrace-1.1\ \{...}
+
+test stacktrace-1.2 {Stack trace with limited depth} -body {
+ # This will limit the stack trace to omit "this" level and below
+ c trace 0 [info frame]
+} -result {a infoframe.test 5 {stacktrace 0 2} b infoframe.test 15 {a trace 0 2} c infoframe.test 19 {b trace 0 2}}
+
testreport
diff --git a/tests/misc.test b/tests/misc.test
index a997057..cffb0a6 100644
--- a/tests/misc.test
+++ b/tests/misc.test
@@ -301,25 +301,24 @@ test catch-1.9 "catch no error has no -errorinfo" {
list $rc [info exists opts(-errorinfo)]
} {0 0}
-test return-1.1 "return can rethrow an error" {
+test return-1.1 {return can rethrow an error} -body {
proc a {} { error "from a" }
proc b {} { catch {a} msg opts; return {*}$opts $msg }
set rc [catch {b} msg opts]
- list $rc $msg [llength $opts(-errorinfo)]
-} {1 {from a} 9}
+ list $rc $msg [basename-stacktrace $opts(-errorinfo)]
+} -result {1 {from a} {a misc.test 305 {error {from a}} b misc.test 306 a test misc.test 307 b {} misc.test 304 test\ return-1.1\ \{retu...}}
-test return-1.2 "error can rethrow an error" {
+test return-1.2 {error can rethrow an error} -body {
proc a {} { error "from a" }
proc b {} { catch {a} msg; error $msg [info stacktrace] }
set rc [catch {b} msg opts]
- list $rc $msg [llength $opts(-errorinfo)]
-} {1 {from a} 9}
+ list $rc $msg [basename-stacktrace $opts(-errorinfo)]
+} -result {1 {from a} {a misc.test 312 {error {from a}} b misc.test 313 a test misc.test 314 b {} misc.test 311 test\ return-1.2\ \{erro...}}
test return-1.3 "return can rethrow no error" {
proc a {} { return "from a" }
proc b {} { catch {a} msg opts; return {*}$opts $msg }
set rc [catch {b} msg opts]
- #list $rc $msg [llength $opts(-errorinfo)]
list $rc $msg [info exists opts(-errorinfo)]
} {0 {from a} 0}
diff --git a/tests/stacktrace.test b/tests/stacktrace.test
index 9dcc657..4d6b432 100644
--- a/tests/stacktrace.test
+++ b/tests/stacktrace.test
@@ -34,13 +34,13 @@ proc main {} {
error "from unknown"
}
- test err-10.1 "Stacktrace on error from unknown (badcmd, call)" {
+ test err-10.1 {Stacktrace on error from unknown (badcmd, call)} -body {
set rc [catch {error_caller badcmd call} msg]
#puts stderr "err-10.1\n[errorInfo $msg]\n"
#puts stderr "\terr-10.1 {[list $rc $msg [basename-stacktrace [info stacktrace]]]}"
list $rc $msg [basename-stacktrace [info stacktrace]]
- } {1 {from unknown} {{} stacktrace.test 34 {} errors.tcl 6 error_generator errors.tcl 44 error_caller stacktrace.test 38}}
+ } -result {1 {from unknown} {unknown stacktrace.test 34 {error {from unknown}} error_generator errors.tcl 6 {unknown bogus command...} error_caller errors.tcl 44 {error_generator badcm...} test stacktrace.test 38 {error_caller badcmd c...} main stacktrace.test 37 test\ err-10.1\ \{Stackt... {} stacktrace.test 127 main}}
rename unknown ""
@@ -74,50 +74,50 @@ proc main {} {
}
set expected {
- err-1.1 {1 {invalid command name "bogus"} {{} errors.tcl 6 error_generator errors.tcl 44 error_caller stacktrace.test 25}}
- err-1.2 {1 {invalid command name "bogus"} {{} errors.tcl 6 error_generator errors.tcl 47 error_caller stacktrace.test 25}}
- err-1.3 {1 {invalid command name "bogus"} {{} errors.tcl 6 error_generator errors.tcl 50 error_caller stacktrace.test 25}}
- err-1.4 {1 {invalid command name "bogus"} {{} errors.tcl 6 error_generator errors.tcl 53 error_caller stacktrace.test 25}}
- err-2.1 {1 {can't read "bogus": no such variable} {{} errors.tcl 9 error_generator errors.tcl 44 error_caller stacktrace.test 25}}
- err-2.2 {1 {can't read "bogus": no such variable} {{} errors.tcl 9 error_generator errors.tcl 47 error_caller stacktrace.test 25}}
- err-2.3 {1 {can't read "bogus": no such variable} {{} errors.tcl 9 error_generator errors.tcl 50 error_caller stacktrace.test 25}}
- err-2.4 {1 {can't read "bogus": no such variable} {{} errors.tcl 9 error_generator errors.tcl 53 error_caller stacktrace.test 25}}
- err-3.1 {1 {unmatched "["} {{} errors.tcl 62 error_badproc errors.tcl 33 error_generator errors.tcl 44 error_caller stacktrace.test 25}}
- err-3.2 {1 {unmatched "["} {{} errors.tcl 62 error_badproc errors.tcl 33 error_generator errors.tcl 47 error_caller stacktrace.test 25}}
- err-3.3 {1 {unmatched "["} {{} errors.tcl 62 error_badproc errors.tcl 33 error_generator errors.tcl 50 error_caller stacktrace.test 25}}
- err-3.4 {1 {unmatched "["} {{} errors.tcl 62 error_badproc errors.tcl 33 error_generator errors.tcl 53 error_caller stacktrace.test 25}}
- err-4.1 {1 bogus {{} errors.tcl 12 error_generator errors.tcl 44 error_caller stacktrace.test 25}}
- err-4.2 {1 bogus {{} errors.tcl 12 error_generator errors.tcl 47 error_caller stacktrace.test 25}}
- err-4.3 {1 bogus {{} errors.tcl 12 error_generator errors.tcl 50 error_caller stacktrace.test 25}}
- err-4.4 {1 bogus {{} errors.tcl 12 error_generator errors.tcl 53 error_caller stacktrace.test 25}}
- err-5.1 {1 {can't read "bogus": no such variable} {{} errors.tcl 15 error_generator errors.tcl 44 error_caller stacktrace.test 25}}
- err-5.2 {1 {can't read "bogus": no such variable} {{} errors.tcl 15 error_generator errors.tcl 47 error_caller stacktrace.test 25}}
- err-5.3 {1 {can't read "bogus": no such variable} {{} errors.tcl 15 error_generator errors.tcl 50 error_caller stacktrace.test 25}}
- err-5.4 {1 {can't read "bogus": no such variable} {{} errors.tcl 15 error_generator errors.tcl 53 error_caller stacktrace.test 25}}
- err-6.1 {1 {can't read "bogus": no such variable} {{} errors.tcl 18 error_generator errors.tcl 44 error_caller stacktrace.test 25}}
- err-6.2 {1 {can't read "bogus": no such variable} {{} errors.tcl 18 error_generator errors.tcl 47 error_caller stacktrace.test 25}}
- err-6.3 {1 {can't read "bogus": no such variable} {{} errors.tcl 18 error_generator errors.tcl 50 error_caller stacktrace.test 25}}
- err-6.4 {1 {can't read "bogus": no such variable} {{} errors.tcl 18 error_generator errors.tcl 53 error_caller stacktrace.test 25}}
+ err-1.1 {1 {invalid command name "bogus"} {error_generator errors.tcl 6 {} error_caller errors.tcl 44 {error_generator badcm...} test stacktrace.test 25 {error_caller badcmd c...} main stacktrace.test 24 test\ err-1.1\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-1.2 {1 {invalid command name "bogus"} {error_generator errors.tcl 6 {} error_caller errors.tcl 47 {error_generator badcm...} test stacktrace.test 25 {error_caller badcmd u...} main stacktrace.test 24 test\ err-1.2\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-1.3 {1 {invalid command name "bogus"} {error_generator errors.tcl 6 {} error_caller errors.tcl 50 {error_generator badcm...} test stacktrace.test 25 {error_caller badcmd e...} main stacktrace.test 24 test\ err-1.3\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-1.4 {1 {invalid command name "bogus"} {error_generator errors.tcl 6 {} error_caller {} 1 {error_generator badcm...} test stacktrace.test 25 {error_caller badcmd e...} main stacktrace.test 24 test\ err-1.4\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-2.1 {1 {can't read "bogus": no such variable} {error_generator errors.tcl 9 {set bogus} error_caller errors.tcl 44 {error_generator badva...} test stacktrace.test 25 {error_caller badvar c...} main stacktrace.test 24 test\ err-2.1\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-2.2 {1 {can't read "bogus": no such variable} {error_generator errors.tcl 9 {set bogus} error_caller errors.tcl 47 {error_generator badva...} test stacktrace.test 25 {error_caller badvar u...} main stacktrace.test 24 test\ err-2.2\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-2.3 {1 {can't read "bogus": no such variable} {error_generator errors.tcl 9 {set bogus} error_caller errors.tcl 50 {error_generator badva...} test stacktrace.test 25 {error_caller badvar e...} main stacktrace.test 24 test\ err-2.3\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-2.4 {1 {can't read "bogus": no such variable} {error_generator errors.tcl 9 {set bogus} error_caller {} 1 {error_generator badva...} test stacktrace.test 25 {error_caller badvar e...} main stacktrace.test 24 test\ err-2.4\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-3.1 {1 {unmatched "["} {error_generator errors.tcl 33 error_badproc error_generator errors.tcl 33 error_badproc error_caller errors.tcl 44 {error_generator badpr...} test stacktrace.test 25 {error_caller badproc ...} main stacktrace.test 24 test\ err-3.1\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-3.2 {1 {unmatched "["} {error_generator errors.tcl 33 error_badproc error_generator errors.tcl 33 error_badproc error_caller errors.tcl 47 {error_generator badpr...} test stacktrace.test 25 {error_caller badproc ...} main stacktrace.test 24 test\ err-3.2\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-3.3 {1 {unmatched "["} {error_generator errors.tcl 33 error_badproc error_generator errors.tcl 33 error_badproc error_caller errors.tcl 50 {error_generator badpr...} test stacktrace.test 25 {error_caller badproc ...} main stacktrace.test 24 test\ err-3.3\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-3.4 {1 {unmatched "["} {error_generator errors.tcl 33 error_badproc error_generator errors.tcl 33 error_badproc error_caller {} 1 {error_generator badpr...} test stacktrace.test 25 {error_caller badproc ...} main stacktrace.test 24 test\ err-3.4\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-4.1 {1 bogus {error_generator errors.tcl 12 {error bogus} error_caller errors.tcl 44 {error_generator error...} test stacktrace.test 25 {error_caller error ca...} main stacktrace.test 24 test\ err-4.1\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-4.2 {1 bogus {error_generator errors.tcl 12 {error bogus} error_caller errors.tcl 47 {error_generator error...} test stacktrace.test 25 {error_caller error up...} main stacktrace.test 24 test\ err-4.2\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-4.3 {1 bogus {error_generator errors.tcl 12 {error bogus} error_caller errors.tcl 50 {error_generator error...} test stacktrace.test 25 {error_caller error ev...} main stacktrace.test 24 test\ err-4.3\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-4.4 {1 bogus {error_generator errors.tcl 12 {error bogus} error_caller {} 1 {error_generator error...} test stacktrace.test 25 {error_caller error ev...} main stacktrace.test 24 test\ err-4.4\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-5.1 {1 {can't read "bogus": no such variable} {error_generator errors.tcl 15 {} error_caller errors.tcl 44 {error_generator inter...} test stacktrace.test 25 {error_caller interpba...} main stacktrace.test 24 test\ err-5.1\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-5.2 {1 {can't read "bogus": no such variable} {error_generator errors.tcl 15 {} error_caller errors.tcl 47 {error_generator inter...} test stacktrace.test 25 {error_caller interpba...} main stacktrace.test 24 test\ err-5.2\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-5.3 {1 {can't read "bogus": no such variable} {error_generator errors.tcl 15 {} error_caller errors.tcl 50 {error_generator inter...} test stacktrace.test 25 {error_caller interpba...} main stacktrace.test 24 test\ err-5.3\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-5.4 {1 {can't read "bogus": no such variable} {error_generator errors.tcl 15 {} error_caller {} 1 {error_generator inter...} test stacktrace.test 25 {error_caller interpba...} main stacktrace.test 24 test\ err-5.4\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-6.1 {1 {can't read "bogus": no such variable} {error_generator errors.tcl 18 {} error_caller errors.tcl 44 {error_generator inter...} test stacktrace.test 25 {error_caller interpba...} main stacktrace.test 24 test\ err-6.1\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-6.2 {1 {can't read "bogus": no such variable} {error_generator errors.tcl 18 {} error_caller errors.tcl 47 {error_generator inter...} test stacktrace.test 25 {error_caller interpba...} main stacktrace.test 24 test\ err-6.2\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-6.3 {1 {can't read "bogus": no such variable} {error_generator errors.tcl 18 {} error_caller errors.tcl 50 {error_generator inter...} test stacktrace.test 25 {error_caller interpba...} main stacktrace.test 24 test\ err-6.3\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-6.4 {1 {can't read "bogus": no such variable} {error_generator errors.tcl 18 {} error_caller {} 1 {error_generator inter...} test stacktrace.test 25 {error_caller interpba...} main stacktrace.test 24 test\ err-6.4\ \{Stacktr... {} stacktrace.test 127 main}}
err-7.1 {1 {from dummyproc
-Can't load package dummy} {{} dummy.tcl 3 dummyproc dummy.tcl 6 {} errors.tcl 21 error_generator errors.tcl 44 error_caller stacktrace.test 25}}
+Can't load package dummy} {dummyproc dummy.tcl 3 error\ \{from\ dummyproc... error_generator dummy.tcl 6 dummyproc error_caller errors.tcl 44 {error_generator packa...} test stacktrace.test 25 {error_caller package ...} main stacktrace.test 24 test\ err-7.1\ \{Stacktr... {} stacktrace.test 127 main}}
err-7.2 {1 {from dummyproc
-Can't load package dummy} {{} dummy.tcl 3 dummyproc dummy.tcl 6 {} errors.tcl 21 error_generator errors.tcl 47 error_caller stacktrace.test 25}}
+Can't load package dummy} {dummyproc dummy.tcl 3 error\ \{from\ dummyproc... error_generator dummy.tcl 6 dummyproc error_caller errors.tcl 47 {error_generator packa...} test stacktrace.test 25 {error_caller package ...} main stacktrace.test 24 test\ err-7.2\ \{Stacktr... {} stacktrace.test 127 main}}
err-7.3 {1 {from dummyproc
-Can't load package dummy} {{} dummy.tcl 3 dummyproc dummy.tcl 6 {} errors.tcl 21 error_generator errors.tcl 50 error_caller stacktrace.test 25}}
+Can't load package dummy} {dummyproc dummy.tcl 3 error\ \{from\ dummyproc... error_generator dummy.tcl 6 dummyproc error_caller errors.tcl 50 {error_generator packa...} test stacktrace.test 25 {error_caller package ...} main stacktrace.test 24 test\ err-7.3\ \{Stacktr... {} stacktrace.test 127 main}}
err-7.4 {1 {from dummyproc
-Can't load package dummy} {{} dummy.tcl 3 dummyproc dummy.tcl 6 {} errors.tcl 21 error_generator errors.tcl 53 error_caller stacktrace.test 25}}
- err-8.1 {1 {from dummyproc} {{} dummy.tcl 3 dummyproc dummy.tcl 6 {} errors.tcl 24 error_generator errors.tcl 44 error_caller stacktrace.test 25}}
- err-8.2 {1 {from dummyproc} {{} dummy.tcl 3 dummyproc dummy.tcl 6 {} errors.tcl 24 error_generator errors.tcl 47 error_caller stacktrace.test 25}}
- err-8.3 {1 {from dummyproc} {{} dummy.tcl 3 dummyproc dummy.tcl 6 {} errors.tcl 24 error_generator errors.tcl 50 error_caller stacktrace.test 25}}
- err-8.4 {1 {from dummyproc} {{} dummy.tcl 3 dummyproc dummy.tcl 6 {} errors.tcl 24 error_generator errors.tcl 53 error_caller stacktrace.test 25}}
- err-9.1 {1 {Can't load package bogus} {{} errors.tcl 27 error_generator errors.tcl 44 error_caller stacktrace.test 25}}
- err-9.2 {1 {Can't load package bogus} {{} errors.tcl 27 error_generator errors.tcl 47 error_caller stacktrace.test 25}}
- err-9.3 {1 {Can't load package bogus} {{} errors.tcl 27 error_generator errors.tcl 50 error_caller stacktrace.test 25}}
- err-9.4 {1 {Can't load package bogus} {{} errors.tcl 27 error_generator errors.tcl 53 error_caller stacktrace.test 25}}
- err-10.1 {1 failure {{} errors.tcl 44 error_caller stacktrace.test 25}}
- err-10.2 {1 failure {{} errors.tcl 47 error_caller stacktrace.test 25}}
- err-10.3 {1 failure {{} errors.tcl 50 error_caller stacktrace.test 25}}
- err-10.4 {1 failure {{} errors.tcl 53 error_caller stacktrace.test 25}}
+Can't load package dummy} {dummyproc dummy.tcl 3 error\ \{from\ dummyproc... error_generator dummy.tcl 6 dummyproc error_caller {} 1 {error_generator packa...} test stacktrace.test 25 {error_caller package ...} main stacktrace.test 24 test\ err-7.4\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-8.1 {1 {from dummyproc} {dummyproc dummy.tcl 3 error\ \{from\ dummyproc... error_generator dummy.tcl 6 dummyproc error_caller errors.tcl 44 {error_generator sourc...} test stacktrace.test 25 {error_caller source c...} main stacktrace.test 24 test\ err-8.1\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-8.2 {1 {from dummyproc} {dummyproc dummy.tcl 3 error\ \{from\ dummyproc... error_generator dummy.tcl 6 dummyproc error_caller errors.tcl 47 {error_generator sourc...} test stacktrace.test 25 {error_caller source u...} main stacktrace.test 24 test\ err-8.2\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-8.3 {1 {from dummyproc} {dummyproc dummy.tcl 3 error\ \{from\ dummyproc... error_generator dummy.tcl 6 dummyproc error_caller errors.tcl 50 {error_generator sourc...} test stacktrace.test 25 {error_caller source e...} main stacktrace.test 24 test\ err-8.3\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-8.4 {1 {from dummyproc} {dummyproc dummy.tcl 3 error\ \{from\ dummyproc... error_generator dummy.tcl 6 dummyproc error_caller {} 1 {error_generator sourc...} test stacktrace.test 25 {error_caller source e...} main stacktrace.test 24 test\ err-8.4\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-9.1 {1 {Can't load package bogus} {error_generator errors.tcl 27 {package require bogus...} error_caller errors.tcl 44 {error_generator badpa...} test stacktrace.test 25 {error_caller badpacka...} main stacktrace.test 24 test\ err-9.1\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-9.2 {1 {Can't load package bogus} {error_generator errors.tcl 27 {package require bogus...} error_caller errors.tcl 47 {error_generator badpa...} test stacktrace.test 25 {error_caller badpacka...} main stacktrace.test 24 test\ err-9.2\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-9.3 {1 {Can't load package bogus} {error_generator errors.tcl 27 {package require bogus...} error_caller errors.tcl 50 {error_generator badpa...} test stacktrace.test 25 {error_caller badpacka...} main stacktrace.test 24 test\ err-9.3\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-9.4 {1 {Can't load package bogus} {error_generator errors.tcl 27 {package require bogus...} error_caller {} 1 {error_generator badpa...} test stacktrace.test 25 {error_caller badpacka...} main stacktrace.test 24 test\ err-9.4\ \{Stacktr... {} stacktrace.test 127 main}}
+ err-10.1 {1 failure {error_caller errors.tcl 44 {error_generator retur...} test stacktrace.test 25 {error_caller returnco...} main stacktrace.test 24 test\ err-10.1\ \{Stackt... {} stacktrace.test 127 main}}
+ err-10.2 {1 failure {error_caller errors.tcl 47 {error_generator retur...} test stacktrace.test 25 {error_caller returnco...} main stacktrace.test 24 test\ err-10.2\ \{Stackt... {} stacktrace.test 127 main}}
+ err-10.3 {1 failure {error_caller errors.tcl 50 {error_generator retur...} test stacktrace.test 25 {error_caller returnco...} main stacktrace.test 24 test\ err-10.3\ \{Stackt... {} stacktrace.test 127 main}}
+ err-10.4 {1 failure {error_caller {} 1 {error_generator retur...} test stacktrace.test 25 {error_caller returnco...} main stacktrace.test 24 test\ err-10.4\ \{Stackt... {} stacktrace.test 127 main}}
}
# Set this to output expected results to stderr