From 263c28170a916b24a1442687580299e332b732af Mon Sep 17 00:00:00 2001 From: Steve Bennett Date: Wed, 13 Mar 2024 15:32:15 +1000 Subject: [PATCH] generate source info for error messages at top level Now that we rely on eval frames to unwind the stack on error, if an error occurs at the top level it would previously not provide a stack trace. e.g. $ jimsh t.tcl unmatched "[" After this change, the error location is now correctly reported: $ ./jimsh t.tcl t.tcl:8: Error: unmatched "[" Traceback (most recent call last): File "t.tcl", line 8 Signed-off-by: Steve Bennett --- jim.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/jim.c b/jim.c index 65206708..8588b7f3 100644 --- a/jim.c +++ b/jim.c @@ -155,7 +155,6 @@ 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_VarVal *vv); static Jim_VarVal *JimFindVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr); -static void JimSetErrorStack(Jim_Interp *interp); static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); #define JIM_DICT_SUGAR 100 /* Only returned by SetVariableFromAny() */ @@ -3357,6 +3356,7 @@ typedef struct ScriptObj static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); static int JimParseCheckMissing(Jim_Interp *interp, int ch); static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr); +static void JimSetErrorStack(Jim_Interp *interp, ScriptObj *script); void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) { @@ -6050,16 +6050,27 @@ static void JimSetStackTrace(Jim_Interp *interp, Jim_Obj *stackTraceObj) interp->errorFlag = 1; } -static void JimSetErrorStack(Jim_Interp *interp) +static void JimSetErrorStack(Jim_Interp *interp, ScriptObj *script) { if (!interp->errorFlag) { int i; Jim_Obj *stackTrace = Jim_NewListObj(interp, NULL, 0); - for (i = 0; i <= interp->procLevel; i++) { - Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, -i); - if (frame) { - JimAddStackFrame(interp, frame, stackTrace); + if (interp->procLevel == 0 && script) { + /* If this is at the top level and there is a script, use the script info + * rather than the proc info + */ + Jim_ListAppendElement(interp, stackTrace, interp->emptyObj); + Jim_ListAppendElement(interp, stackTrace, script->fileNameObj); + Jim_ListAppendElement(interp, stackTrace, Jim_NewIntObj(interp, script->linenr)); + Jim_ListAppendElement(interp, stackTrace, interp->emptyObj); + } + else { + for (i = 0; i <= interp->procLevel; i++) { + Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, -i); + if (frame) { + JimAddStackFrame(interp, frame, stackTrace); + } } } JimSetStackTrace(interp, stackTrace); @@ -10862,7 +10873,7 @@ static int JimInvokeCommand(Jim_Interp *interp, int objc, Jim_Obj *const *objv) retcode = cmdPtr->u.native.cmdProc(interp, objc, objv); } if (retcode == JIM_ERR) { - JimSetErrorStack(interp); + JimSetErrorStack(interp, NULL); } } @@ -10900,7 +10911,7 @@ static int JimInvokeCommand(Jim_Interp *interp, int objc, Jim_Obj *const *objv) JimDecrCmdRefCount(interp, cmdPtr); if (retcode == JIM_ERR) { - JimSetErrorStack(interp); + JimSetErrorStack(interp, NULL); } if (interp->framePtr->tailcallObj) { @@ -11157,7 +11168,7 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr) Jim_IncrRefCount(scriptObjPtr); /* Make sure it's shared. */ script = JimGetScript(interp, scriptObjPtr); if (JimParseCheckMissing(interp, script->missing) == JIM_ERR) { - JimSetErrorStack(interp); + JimSetErrorStack(interp, script); Jim_DecrRefCount(interp, scriptObjPtr); return JIM_ERR; } @@ -11360,7 +11371,7 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr) /* Possibly add to the error stack trace */ if (retcode == JIM_ERR) { - JimSetErrorStack(interp); + JimSetErrorStack(interp, NULL); } JimPopEvalFrame(interp);