summaryrefslogtreecommitdiffstats
path: root/generic/tclResolve.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclResolve.c')
-rw-r--r--generic/tclResolve.c424
1 files changed, 424 insertions, 0 deletions
diff --git a/generic/tclResolve.c b/generic/tclResolve.c
new file mode 100644
index 0000000..974737e
--- /dev/null
+++ b/generic/tclResolve.c
@@ -0,0 +1,424 @@
+/*
+ * tclResolve.c --
+ *
+ * Contains hooks for customized command/variable name resolution
+ * schemes. These hooks allow extensions like [incr Tcl] to add their own
+ * name resolution rules to the Tcl language. Rules can be applied to a
+ * particular namespace, to the interpreter as a whole, or both.
+ *
+ * Copyright (c) 1998 Lucent Technologies, Inc.
+ *
+ * See the file "license.terms" for information on usage and redistribution of
+ * this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ */
+
+#include "tclInt.h"
+
+/*
+ * Declarations for functions local to this file:
+ */
+
+static void BumpCmdRefEpochs(Namespace *nsPtr);
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_AddInterpResolvers --
+ *
+ * Adds a set of command/variable resolution functions to an interpreter.
+ * These functions are consulted when commands are resolved in
+ * Tcl_FindCommand, and when variables are resolved in TclLookupVar and
+ * LookupCompiledLocal. Each namespace may also have its own set of
+ * resolution functions which take precedence over those for the
+ * interpreter.
+ *
+ * When a name is resolved, it is handled as follows. First, the name is
+ * passed to the resolution functions for the namespace. If not resolved,
+ * the name is passed to each of the resolution functions added to the
+ * interpreter. Finally, if still not resolved, the name is handled using
+ * the default Tcl rules for name resolution.
+ *
+ * Results:
+ * Returns pointers to the current name resolution functions in the
+ * cmdProcPtr, varProcPtr and compiledVarProcPtr arguments.
+ *
+ * Side effects:
+ * If a compiledVarProc is specified, this function bumps the
+ * compileEpoch for the interpreter, forcing all code to be recompiled.
+ * If a cmdProc is specified, this function bumps the cmdRefEpoch in all
+ * namespaces, forcing commands to be resolved again using the new rules.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_AddInterpResolvers(
+ Tcl_Interp *interp, /* Interpreter whose name resolution rules are
+ * being modified. */
+ const char *name, /* Name of this resolution scheme. */
+ Tcl_ResolveCmdProc *cmdProc,/* New function for command resolution. */
+ Tcl_ResolveVarProc *varProc,/* Function for variable resolution at
+ * runtime. */
+ Tcl_ResolveCompiledVarProc *compiledVarProc)
+ /* Function for variable resolution at compile
+ * time. */
+{
+ Interp *iPtr = (Interp *) interp;
+ ResolverScheme *resPtr;
+ unsigned len;
+
+ /*
+ * Since we're adding a new name resolution scheme, we must force all code
+ * to be recompiled to use the new scheme. If there are new compiled
+ * variable resolution rules, bump the compiler epoch to invalidate
+ * compiled code. If there are new command resolution rules, bump the
+ * cmdRefEpoch in all namespaces.
+ */
+
+ if (compiledVarProc) {
+ iPtr->compileEpoch++;
+ }
+ if (cmdProc) {
+ BumpCmdRefEpochs(iPtr->globalNsPtr);
+ }
+
+ /*
+ * Look for an existing scheme with the given name. If found, then replace
+ * its rules.
+ */
+
+ for (resPtr=iPtr->resolverPtr ; resPtr!=NULL ; resPtr=resPtr->nextPtr) {
+ if (*name == *resPtr->name && strcmp(name, resPtr->name) == 0) {
+ resPtr->cmdResProc = cmdProc;
+ resPtr->varResProc = varProc;
+ resPtr->compiledVarResProc = compiledVarProc;
+ return;
+ }
+ }
+
+ /*
+ * Otherwise, this is a new scheme. Add it to the FRONT of the linked
+ * list, so that it overrides existing schemes.
+ */
+
+ resPtr = ckalloc(sizeof(ResolverScheme));
+ len = strlen(name) + 1;
+ resPtr->name = ckalloc(len);
+ memcpy(resPtr->name, name, len);
+ resPtr->cmdResProc = cmdProc;
+ resPtr->varResProc = varProc;
+ resPtr->compiledVarResProc = compiledVarProc;
+ resPtr->nextPtr = iPtr->resolverPtr;
+ iPtr->resolverPtr = resPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_GetInterpResolvers --
+ *
+ * Looks for a set of command/variable resolution functions with the
+ * given name in an interpreter. These functions are registered by
+ * calling Tcl_AddInterpResolvers.
+ *
+ * Results:
+ * If the name is recognized, this function returns non-zero, along with
+ * pointers to the name resolution functions in the Tcl_ResolverInfo
+ * structure. If the name is not recognized, this function returns zero.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_GetInterpResolvers(
+ Tcl_Interp *interp, /* Interpreter whose name resolution rules are
+ * being queried. */
+ const char *name, /* Look for a scheme with this name. */
+ Tcl_ResolverInfo *resInfoPtr)
+ /* Returns pointers to the functions, if
+ * found */
+{
+ Interp *iPtr = (Interp *) interp;
+ ResolverScheme *resPtr;
+
+ /*
+ * Look for an existing scheme with the given name. If found, then return
+ * pointers to its functions.
+ */
+
+ for (resPtr=iPtr->resolverPtr ; resPtr!=NULL ; resPtr=resPtr->nextPtr) {
+ if (*name == *resPtr->name && strcmp(name, resPtr->name) == 0) {
+ resInfoPtr->cmdResProc = resPtr->cmdResProc;
+ resInfoPtr->varResProc = resPtr->varResProc;
+ resInfoPtr->compiledVarResProc = resPtr->compiledVarResProc;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_RemoveInterpResolvers --
+ *
+ * Removes a set of command/variable resolution functions previously
+ * added by Tcl_AddInterpResolvers. The next time a command/variable name
+ * is resolved, these functions won't be consulted.
+ *
+ * Results:
+ * Returns non-zero if the name was recognized and the resolution scheme
+ * was deleted. Returns zero otherwise.
+ *
+ * Side effects:
+ * If a scheme with a compiledVarProc was deleted, this function bumps
+ * the compileEpoch for the interpreter, forcing all code to be
+ * recompiled. If a scheme with a cmdProc was deleted, this function
+ * bumps the cmdRefEpoch in all namespaces, forcing commands to be
+ * resolved again using the new rules.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_RemoveInterpResolvers(
+ Tcl_Interp *interp, /* Interpreter whose name resolution rules are
+ * being modified. */
+ const char *name) /* Name of the scheme to be removed. */
+{
+ Interp *iPtr = (Interp *) interp;
+ ResolverScheme **prevPtrPtr, *resPtr;
+
+ /*
+ * Look for an existing scheme with the given name.
+ */
+
+ prevPtrPtr = &iPtr->resolverPtr;
+ for (resPtr=iPtr->resolverPtr ; resPtr!=NULL ; resPtr=resPtr->nextPtr) {
+ if (*name == *resPtr->name && strcmp(name, resPtr->name) == 0) {
+ break;
+ }
+ prevPtrPtr = &resPtr->nextPtr;
+ }
+
+ /*
+ * If we found the scheme, delete it.
+ */
+
+ if (resPtr) {
+ /*
+ * If we're deleting a scheme with compiled variable resolution rules,
+ * bump the compiler epoch to invalidate compiled code. If we're
+ * deleting a scheme with command resolution rules, bump the
+ * cmdRefEpoch in all namespaces.
+ */
+
+ if (resPtr->compiledVarResProc) {
+ iPtr->compileEpoch++;
+ }
+ if (resPtr->cmdResProc) {
+ BumpCmdRefEpochs(iPtr->globalNsPtr);
+ }
+
+ *prevPtrPtr = resPtr->nextPtr;
+ ckfree(resPtr->name);
+ ckfree(resPtr);
+
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * BumpCmdRefEpochs --
+ *
+ * This function is used to bump the cmdRefEpoch counters in the
+ * specified namespace and all of its child namespaces. It is used
+ * whenever name resolution schemes are added/removed from an
+ * interpreter, to invalidate all command references.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Bumps the cmdRefEpoch in the specified namespace and its children,
+ * recursively.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+BumpCmdRefEpochs(
+ Namespace *nsPtr) /* Namespace being modified. */
+{
+ Tcl_HashEntry *entry;
+ Tcl_HashSearch search;
+
+ nsPtr->cmdRefEpoch++;
+
+#ifndef BREAK_NAMESPACE_COMPAT
+ for (entry = Tcl_FirstHashEntry(&nsPtr->childTable, &search);
+ entry != NULL; entry = Tcl_NextHashEntry(&search)) {
+ Namespace *childNsPtr = Tcl_GetHashValue(entry);
+
+ BumpCmdRefEpochs(childNsPtr);
+ }
+#else
+ if (nsPtr->childTablePtr != NULL) {
+ for (entry = Tcl_FirstHashEntry(nsPtr->childTablePtr, &search);
+ entry != NULL; entry = Tcl_NextHashEntry(&search)) {
+ Namespace *childNsPtr = Tcl_GetHashValue(entry);
+
+ BumpCmdRefEpochs(childNsPtr);
+ }
+ }
+#endif
+ TclInvalidateNsPath(nsPtr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_SetNamespaceResolvers --
+ *
+ * Sets the command/variable resolution functions for a namespace,
+ * thereby changing the way that command/variable names are interpreted.
+ * This allows extension writers to support different name resolution
+ * schemes, such as those for object-oriented packages.
+ *
+ * Command resolution is handled by a function of the following type:
+ *
+ * typedef int (Tcl_ResolveCmdProc)(Tcl_Interp *interp,
+ * const char *name, Tcl_Namespace *context,
+ * int flags, Tcl_Command *rPtr);
+ *
+ * Whenever a command is executed or Tcl_FindCommand is invoked within
+ * the namespace, this function is called to resolve the command name. If
+ * this function is able to resolve the name, it should return the status
+ * code TCL_OK, along with the corresponding Tcl_Command in the rPtr
+ * argument. Otherwise, the function can return TCL_CONTINUE, and the
+ * command will be treated under the usual name resolution rules. Or, it
+ * can return TCL_ERROR, and the command will be considered invalid.
+ *
+ * Variable resolution is handled by two functions. The first is called
+ * whenever a variable needs to be resolved at compile time:
+ *
+ * typedef int (Tcl_ResolveCompiledVarProc)(Tcl_Interp *interp,
+ * const char *name, Tcl_Namespace *context,
+ * Tcl_ResolvedVarInfo *rPtr);
+ *
+ * If this function is able to resolve the name, it should return the
+ * status code TCL_OK, along with variable resolution info in the rPtr
+ * argument; this info will be used to set up compiled locals in the call
+ * frame at runtime. The function may also return TCL_CONTINUE, and the
+ * variable will be treated under the usual name resolution rules. Or, it
+ * can return TCL_ERROR, and the variable will be considered invalid.
+ *
+ * Another function is used whenever a variable needs to be resolved at
+ * runtime but it is not recognized as a compiled local. (For example,
+ * the variable may be requested via Tcl_FindNamespaceVar.) This function
+ * has the following type:
+ *
+ * typedef int (Tcl_ResolveVarProc)(Tcl_Interp *interp,
+ * const char *name, Tcl_Namespace *context,
+ * int flags, Tcl_Var *rPtr);
+ *
+ * This function is quite similar to the compile-time version. It returns
+ * the same status codes, but if variable resolution succeeds, this
+ * function returns a Tcl_Var directly via the rPtr argument.
+ *
+ * Results:
+ * Nothing.
+ *
+ * Side effects:
+ * Bumps the command epoch counter for the namespace, invalidating all
+ * command references in that namespace. Also bumps the resolver epoch
+ * counter for the namespace, forcing all code in the namespace to be
+ * recompiled.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_SetNamespaceResolvers(
+ Tcl_Namespace *namespacePtr,/* Namespace whose resolution rules are being
+ * modified. */
+ Tcl_ResolveCmdProc *cmdProc,/* Function for command resolution */
+ Tcl_ResolveVarProc *varProc,/* Function for variable resolution at
+ * run-time */
+ Tcl_ResolveCompiledVarProc *compiledVarProc)
+ /* Function for variable resolution at compile
+ * time. */
+{
+ Namespace *nsPtr = (Namespace *) namespacePtr;
+
+ /*
+ * Plug in the new command resolver, and bump the epoch counters so that
+ * all code will have to be recompiled and all commands will have to be
+ * resolved again using the new policy.
+ */
+
+ nsPtr->cmdResProc = cmdProc;
+ nsPtr->varResProc = varProc;
+ nsPtr->compiledVarResProc = compiledVarProc;
+
+ nsPtr->cmdRefEpoch++;
+ nsPtr->resolverEpoch++;
+ TclInvalidateNsPath(nsPtr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_GetNamespaceResolvers --
+ *
+ * Returns the current command/variable resolution functions for a
+ * namespace. By default, these functions are NULL. New functions can be
+ * installed by calling Tcl_SetNamespaceResolvers, to provide new name
+ * resolution rules.
+ *
+ * Results:
+ * Returns non-zero if any name resolution functions have been assigned
+ * to this namespace; also returns pointers to the functions in the
+ * Tcl_ResolverInfo structure. Returns zero otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_GetNamespaceResolvers(
+ Tcl_Namespace *namespacePtr,/* Namespace whose resolution rules are being
+ * modified. */
+ Tcl_ResolverInfo *resInfoPtr)
+ /* Returns: pointers for all name resolution
+ * functions assigned to this namespace. */
+{
+ Namespace *nsPtr = (Namespace *) namespacePtr;
+
+ resInfoPtr->cmdResProc = nsPtr->cmdResProc;
+ resInfoPtr->varResProc = nsPtr->varResProc;
+ resInfoPtr->compiledVarResProc = nsPtr->compiledVarResProc;
+
+ if (nsPtr->cmdResProc != NULL || nsPtr->varResProc != NULL ||
+ nsPtr->compiledVarResProc != NULL) {
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 4
+ * fill-column: 78
+ * End:
+ */