aboutsummaryrefslogtreecommitdiff
path: root/jim-interp.c
diff options
context:
space:
mode:
authorSteve Bennett <steveb@workware.net.au>2011-06-08 10:00:54 +1000
committerSteve Bennett <steveb@workware.net.au>2016-08-26 11:56:44 +1000
commitf3df2d191f047247bf9ae97b907ae9776eeafc81 (patch)
tree24aab1414a0086f4c843d363c01f30e079aee218 /jim-interp.c
parentdef038d816120c9281e8001c24170047996ebfbc (diff)
downloadjimtcl-f3df2d191f047247bf9ae97b907ae9776eeafc81.zip
jimtcl-f3df2d191f047247bf9ae97b907ae9776eeafc81.tar.gz
jimtcl-f3df2d191f047247bf9ae97b907ae9776eeafc81.tar.bz2
Add support for sub-interpreters
Includes support for aliases in sub-interp These are not identical to Tcl interp, but are conceptually very similar For example: set i [interp] $i alias localcmd parentcmd arg1 $i eval { localcmd x } Invokes: parentcmd arg1 x Signed-off-by: Steve Bennett <steveb@workware.net.au>
Diffstat (limited to 'jim-interp.c')
-rw-r--r--jim-interp.c178
1 files changed, 178 insertions, 0 deletions
diff --git a/jim-interp.c b/jim-interp.c
new file mode 100644
index 0000000..dd80479
--- /dev/null
+++ b/jim-interp.c
@@ -0,0 +1,178 @@
+#include <assert.h>
+
+#include "jim.h"
+#include "jimautoconf.h"
+#include "jim-subcmd.h"
+
+static void JimInterpDelProc(Jim_Interp *interp, void *privData)
+{
+ Jim_FreeInterp((Jim_Interp *)privData);
+}
+
+/* Everything passing between interpreters must be converted to a string */
+static Jim_Obj *JimInterpCopyObj(Jim_Interp *target, Jim_Obj *obj)
+{
+ const char *rep;
+ int len;
+
+ rep = Jim_GetString(obj, &len);
+ return Jim_NewStringObj(target, rep, len);
+}
+
+#define JimInterpCopyResult(to, from) Jim_SetResult((to), JimInterpCopyObj((to), Jim_GetResult((from))))
+
+static int interp_cmd_eval(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int ret;
+ Jim_Interp *child = Jim_CmdPrivData(interp);
+ Jim_Obj *scriptObj;
+ Jim_Obj *targetScriptObj;
+
+ scriptObj = Jim_ConcatObj(interp, argc, argv);
+ targetScriptObj = JimInterpCopyObj(child, scriptObj);
+ Jim_FreeNewObj(interp, scriptObj);
+
+ Jim_IncrRefCount(targetScriptObj);
+ ret = Jim_EvalObj(child, targetScriptObj);
+ Jim_DecrRefCount(child, targetScriptObj);
+
+ JimInterpCopyResult(interp, child);
+ return ret;
+}
+
+static int interp_cmd_delete(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return Jim_DeleteCommand(interp, Jim_String(argv[0]));
+}
+
+static void JimInterpDelAlias(Jim_Interp *interp, void *privData)
+{
+ Jim_Interp *parent = Jim_GetAssocData(interp, "interp.parent");
+ Jim_DecrRefCount(parent, (Jim_Obj *)privData);
+}
+
+static int JimInterpAliasProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int i, ret;
+ Jim_Interp *parent = Jim_GetAssocData(interp, "interp.parent");
+ Jim_Obj *targetPrefixObj = Jim_CmdPrivData(interp);
+ Jim_Obj *targetScriptObj;
+
+ assert(parent);
+
+ /* Build the complete command */
+ targetScriptObj = Jim_DuplicateObj(parent, targetPrefixObj);
+ for (i = 1; i < argc; i++) {
+ Jim_ListAppendElement(parent, targetScriptObj,
+ JimInterpCopyObj(parent, argv[i]));
+ }
+
+ Jim_IncrRefCount(targetScriptObj);
+ ret = Jim_EvalObj(parent, targetScriptObj);
+ Jim_DecrRefCount(parent, targetScriptObj);
+
+ JimInterpCopyResult(interp, parent);
+ return ret;
+}
+
+static int interp_cmd_alias(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Interp *child = Jim_CmdPrivData(interp);
+ Jim_Obj *aliasPrefixList;
+
+ /* The prefix list will be held inside the child, but it still belongs
+ * to the parent!
+ */
+
+ aliasPrefixList = Jim_NewListObj(interp, argv + 1, argc - 1);
+ Jim_IncrRefCount(aliasPrefixList);
+
+ Jim_CreateCommand(child, Jim_String(argv[0]), JimInterpAliasProc, aliasPrefixList, JimInterpDelAlias);
+ return JIM_OK;
+}
+
+static const jim_subcmd_type interp_command_table[] = {
+ { "eval",
+ "script ...",
+ interp_cmd_eval,
+ 1,
+ -1,
+ /* Description: Concat the args and evaluate the script in the interpreter */
+ },
+ { "delete",
+ NULL,
+ interp_cmd_delete,
+ 0,
+ 0,
+ JIM_MODFLAG_FULLARGV,
+ /* Description: Delete this interpreter */
+ },
+ { "alias",
+ "childcmd parentcmd ?arg ...?",
+ interp_cmd_alias,
+ 2,
+ -1,
+ /* Description: Create an alias which refers to a script in the parent interpreter */
+ },
+ { NULL }
+};
+
+static int JimInterpSubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return Jim_CallSubCmd(interp, Jim_ParseSubCmd(interp, interp_command_table, argc, argv), argc, argv);
+}
+
+static void JimInterpCopyVariable(Jim_Interp *target, Jim_Interp *source, const char *var, const char *default_value)
+{
+ Jim_Obj *value = Jim_GetGlobalVariableStr(source, var, JIM_NONE);
+ const char *str;
+
+ str = value ? Jim_String(value) : default_value;
+ if (str) {
+ Jim_SetGlobalVariableStr(target, var, Jim_NewStringObj(target, str, -1));
+ }
+}
+
+/**
+ * [interp] creates a new interpreter.
+ */
+static int JimInterpCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Interp *child;
+ char buf[32];
+
+ if (argc != 1) {
+ Jim_WrongNumArgs(interp, 1, argv, "");
+ return JIM_ERR;
+ }
+
+ /* Create the interpreter command */
+ child = Jim_CreateInterp();
+ Jim_RegisterCoreCommands(child);
+ Jim_InitStaticExtensions(child);
+
+ /* Copy some core variables to the new interpreter */
+ JimInterpCopyVariable(child, interp, "argv", NULL);
+ JimInterpCopyVariable(child, interp, "argc", NULL);
+ JimInterpCopyVariable(child, interp, "argv0", NULL);
+ JimInterpCopyVariable(child, interp, "jim::argv0", NULL);
+ JimInterpCopyVariable(child, interp, "jim::exe", NULL);
+
+ /* Allow the child interpreter to find the parent */
+ Jim_SetAssocData(child, "interp.parent", NULL, interp);
+
+ snprintf(buf, sizeof(buf), "interp.handle%ld", Jim_GetId(interp));
+ Jim_CreateCommand(interp, buf, JimInterpSubCmdProc, child, JimInterpDelProc);
+ Jim_SetResultString(interp, buf, -1);
+ return JIM_OK;
+}
+
+int Jim_interpInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "interp", "1.0", JIM_ERRMSG))
+ return JIM_ERR;
+
+ Jim_CreateCommand(interp, "interp", JimInterpCommand, NULL, NULL);
+
+ return JIM_OK;
+}