aboutsummaryrefslogtreecommitdiff
path: root/jim.c
diff options
context:
space:
mode:
authorSteve Bennett <steveb@workware.net.au>2010-03-03 16:04:06 +1000
committerSteve Bennett <steveb@workware.net.au>2010-10-15 11:02:49 +1000
commit6f841c80b5a540c7d3cbf8ea73937019eb88656e (patch)
tree7f6049f2f1cbad8040d0feeb08e5e21ad0ac75da /jim.c
parent8a21e1c0ea44a829f84e526a8302e6effbc4a9b1 (diff)
downloadjimtcl-6f841c80b5a540c7d3cbf8ea73937019eb88656e.zip
jimtcl-6f841c80b5a540c7d3cbf8ea73937019eb88656e.tar.gz
jimtcl-6f841c80b5a540c7d3cbf8ea73937019eb88656e.tar.bz2
Implement 'info frame' and some related procs
info frame allows access to source file/line for earler call frames Implement 'stacktrace' to give a live stacktrace And 'stackdump' to convert a stack trace to readable form Update 'errorInfo' to use 'stackdump' Also fix tailcall to retain source info And implement alias, lambda and curry with tailcall Signed-off-by: Steve Bennett <steveb@workware.net.au>
Diffstat (limited to 'jim.c')
-rw-r--r--jim.c91
1 files changed, 62 insertions, 29 deletions
diff --git a/jim.c b/jim.c
index 90f55ad..d1dd32d 100644
--- a/jim.c
+++ b/jim.c
@@ -116,6 +116,8 @@ static Jim_Obj *Jim_ExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr);
static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype, const char *prefix, const char * const *tablePtr, const char *name);
static void JimDeleteLocalProcs(Jim_Interp *interp);
+static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, const char *filename, int linenr, int argc, Jim_Obj *const *argv);
+static int JimEvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv, const char *filename, int linenr);
static const Jim_HashTableType JimVariablesHashTableType;
@@ -8620,11 +8622,8 @@ static void JimPrngSeed(Jim_Interp *interp, const unsigned char *seed,
#define JIM_EVAL_SARGV_LEN 8 /* static arguments vector length */
#define JIM_EVAL_SINTV_LEN 8 /* static interpolation vector length */
-static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc,
- Jim_Obj *const *argv);
-
/* Handle calls to the [unknown] command */
-static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv, const char *filename, int linenr)
{
Jim_Obj **v, *sv[JIM_EVAL_SARGV_LEN];
int retCode;
@@ -8652,12 +8651,12 @@ static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
/* Make a copy of the arguments vector, but shifted on
* the right of one position. The command name of the
* command will be instead the first argument of the
- * [unknonw] call. */
+ * [unknown] call. */
memcpy(v+1, argv, sizeof(Jim_Obj*)*argc);
v[0] = interp->unknown;
/* Call it */
interp->unknown_called++;
- retCode = Jim_EvalObjVector(interp, argc+1, v);
+ retCode = JimEvalObjVector(interp, argc+1, v, filename, linenr);
interp->unknown_called--;
/* Clean up */
@@ -8675,7 +8674,7 @@ static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
* list object generated by the UpdateStringOfList is made
* in a way that ensures that every list element is a different
* command argument. */
-int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
+static int JimEvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv, const char *filename, int linenr)
{
int i, retcode;
Jim_Cmd *cmdPtr;
@@ -8686,7 +8685,7 @@ int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
/* Command lookup */
cmdPtr = Jim_GetCommand(interp, objv[0], JIM_ERRMSG);
if (cmdPtr == NULL) {
- retcode = JimUnknown(interp, objc, objv);
+ retcode = JimUnknown(interp, objc, objv, filename, linenr);
} else {
/* Call it -- Make sure result is an empty object. */
JimIncrCmdRefCount(cmdPtr);
@@ -8695,7 +8694,7 @@ int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
interp->cmdPrivData = cmdPtr->privData;
retcode = cmdPtr->cmdProc(interp, objc, objv);
} else {
- retcode = JimCallProcedure(interp, cmdPtr, objc, objv);
+ retcode = JimCallProcedure(interp, cmdPtr, filename, linenr, objc, objv);
}
JimDecrCmdRefCount(interp, cmdPtr);
}
@@ -8706,6 +8705,11 @@ int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
return retcode;
}
+int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
+{
+ return JimEvalObjVector(interp, objc, objv, NULL, 0);
+}
+
/* Interpolate the given tokens into a unique Jim_Obj returned by reference
* via *objPtrPtr. This function is only called by Jim_EvalObj().
* The returned object has refcount = 0. */
@@ -8903,6 +8907,28 @@ static void JimDeleteLocalProcs(Jim_Interp *interp)
}
}
+/* If listPtr is a list, call JimEvalObjVector() with the given source info.
+ * Otherwise eval with Jim_EvalObj()
+ */
+int Jim_EvalObjList(Jim_Interp *interp, Jim_Obj *listPtr, const char *filename, int linenr)
+{
+ if (!Jim_IsList(listPtr)) {
+ return Jim_EvalObj(interp, listPtr);
+ }
+ else {
+ int retcode = JIM_OK;
+
+ if (listPtr->internalRep.listValue.len) {
+ Jim_IncrRefCount(listPtr);
+ retcode = JimEvalObjVector(interp,
+ listPtr->internalRep.listValue.len,
+ listPtr->internalRep.listValue.ele, filename, linenr);
+ Jim_DecrRefCount(interp, listPtr);
+ }
+ return retcode;
+ }
+}
+
int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
{
int i, j = 0, len;
@@ -8915,16 +8941,10 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
interp->errorFlag = 0;
- /* If the object is of type "list" and there is no
- * string representation for this object, we can call
+ /* If the object is of type "list", we can call
* a specialized version of Jim_EvalObj() */
- if (Jim_IsList(scriptObjPtr) && scriptObjPtr->internalRep.listValue.len) {
- Jim_IncrRefCount(scriptObjPtr);
- retcode = Jim_EvalObjVector(interp,
- scriptObjPtr->internalRep.listValue.len,
- scriptObjPtr->internalRep.listValue.ele);
- Jim_DecrRefCount(interp, scriptObjPtr);
- return retcode;
+ if (Jim_IsList(scriptObjPtr)) {
+ return Jim_EvalObjList(interp, scriptObjPtr, NULL, 0);
}
Jim_IncrRefCount(scriptObjPtr); /* Make sure it's shared. */
@@ -9089,12 +9109,12 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
interp->cmdPrivData = cmd->privData;
retcode = cmd->cmdProc(interp, argc, argv);
} else {
- retcode = JimCallProcedure(interp, cmd, argc, argv);
+ retcode = JimCallProcedure(interp, cmd, script->fileName, cmdtoken->linenr, argc, argv);
}
JimDecrCmdRefCount(interp, cmd);
} else {
/* Call [unknown] */
- retcode = JimUnknown(interp, argc, argv);
+ retcode = JimUnknown(interp, argc, argv, script->fileName, cmdtoken->linenr);
}
if (interp->signal_level && interp->sigmask) {
/* Check for a signal after each command */
@@ -9141,7 +9161,7 @@ err:
*
* This can be fixed just implementing callframes caching
* in JimCreateCallFrame() and JimFreeCallFrame(). */
-int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc,
+int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, const char *filename, int linenr, int argc,
Jim_Obj *const *argv)
{
int i, d, retcode;
@@ -9196,6 +9216,8 @@ int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc,
callFramePtr->procArgsObjPtr = cmd->argListObjPtr;
callFramePtr->procBodyObjPtr = cmd->bodyObjPtr;
callFramePtr->staticVars = cmd->staticVars;
+ callFramePtr->filename = filename;
+ callFramePtr->line = linenr;
Jim_IncrRefCount(cmd->argListObjPtr);
Jim_IncrRefCount(cmd->bodyObjPtr);
interp->framePtr = callFramePtr;
@@ -9286,7 +9308,8 @@ int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc,
while (retcode == JIM_EVAL) {
Jim_Obj *resultScriptObjPtr = Jim_GetResult(interp);
Jim_IncrRefCount(resultScriptObjPtr);
- retcode = Jim_EvalObj(interp, resultScriptObjPtr);
+ /* Should be a list! */
+ retcode = Jim_EvalObjList(interp, resultScriptObjPtr, filename, linenr);
Jim_DecrRefCount(interp, resultScriptObjPtr);
}
/* Handle the JIM_RETURN return code */
@@ -9792,7 +9815,7 @@ static Jim_Obj *JimVariablesList(Jim_Interp *interp, Jim_Obj *patternObjPtr,
}
static int JimInfoLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr,
- Jim_Obj **objPtrPtr)
+ Jim_Obj **objPtrPtr, int info_level_cmd)
{
Jim_CallFrame *targetCallFrame;
@@ -9804,9 +9827,18 @@ static int JimInfoLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr,
Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr);
return JIM_ERR;
}
- *objPtrPtr = Jim_NewListObj(interp,
- targetCallFrame->argv,
- targetCallFrame->argc);
+ if (info_level_cmd) {
+ *objPtrPtr = Jim_NewListObj(interp,
+ targetCallFrame->argv,
+ targetCallFrame->argc);
+ }
+ else {
+ Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+ Jim_ListAppendElement(interp, listObj, targetCallFrame->argv[0]);
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, targetCallFrame->filename ?: "", -1));
+ Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, targetCallFrame->line));
+ *objPtrPtr = listObj;
+ }
return JIM_OK;
}
@@ -12221,11 +12253,11 @@ static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc,
int mode = 0;
static const char *commands[] = {
- "body", "commands", "procs", "exists", "globals", "level", "locals",
+ "body", "commands", "procs", "exists", "globals", "level", "frame", "locals",
"vars", "version", "patchlevel", "complete", "args", "hostname",
"script", "source", "stacktrace", "nameofexecutable", "returncodes", NULL
};
- enum {INFO_BODY, INFO_COMMANDS, INFO_PROCS, INFO_EXISTS, INFO_GLOBALS, INFO_LEVEL,
+ enum {INFO_BODY, INFO_COMMANDS, INFO_PROCS, INFO_EXISTS, INFO_GLOBALS, INFO_LEVEL, INFO_FRAME,
INFO_LOCALS, INFO_VARS, INFO_VERSION, INFO_PATCHLEVEL, INFO_COMPLETE, INFO_ARGS,
INFO_HOSTNAME, INFO_SCRIPT, INFO_SOURCE, INFO_STACKTRACE, INFO_NAMEOFEXECUTABLE,
INFO_RETURNCODES };
@@ -12312,13 +12344,14 @@ static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc,
break;
case INFO_LEVEL:
+ case INFO_FRAME:
switch (argc) {
case 2:
Jim_SetResultInt(interp, interp->numLevels);
break;
case 3:
- if (JimInfoLevel(interp, argv[2], &objPtr) != JIM_OK) {
+ if (JimInfoLevel(interp, argv[2], &objPtr, cmd == INFO_LEVEL) != JIM_OK) {
return JIM_ERR;
}
Jim_SetResult(interp, objPtr);