diff options
author | Steve Bennett <steveb@workware.net.au> | 2011-06-08 10:00:54 +1000 |
---|---|---|
committer | Steve Bennett <steveb@workware.net.au> | 2016-08-26 11:56:44 +1000 |
commit | f3df2d191f047247bf9ae97b907ae9776eeafc81 (patch) | |
tree | 24aab1414a0086f4c843d363c01f30e079aee218 /jim-interp.c | |
parent | def038d816120c9281e8001c24170047996ebfbc (diff) | |
download | jimtcl-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.c | 178 |
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; +} |