tclResolve.c

Go to the documentation of this file.
00001 /*
00002  * tclResolve.c --
00003  *
00004  *      Contains hooks for customized command/variable name resolution
00005  *      schemes. These hooks allow extensions like [incr Tcl] to add their own
00006  *      name resolution rules to the Tcl language. Rules can be applied to a
00007  *      particular namespace, to the interpreter as a whole, or both.
00008  *
00009  * Copyright (c) 1998 Lucent Technologies, Inc.
00010  *
00011  * See the file "license.terms" for information on usage and redistribution of
00012  * this file, and for a DISCLAIMER OF ALL WARRANTIES.
00013  *
00014  * RCS: @(#) $Id: tclResolve.c,v 1.9 2007/04/05 13:20:49 dkf Exp $
00015  */
00016 
00017 #include "tclInt.h"
00018 
00019 /*
00020  * Declarations for functions local to this file:
00021  */
00022 
00023 static void             BumpCmdRefEpochs(Namespace *nsPtr);
00024 
00025 /*
00026  *----------------------------------------------------------------------
00027  *
00028  * Tcl_AddInterpResolvers --
00029  *
00030  *      Adds a set of command/variable resolution functions to an interpreter.
00031  *      These functions are consulted when commands are resolved in
00032  *      Tcl_FindCommand, and when variables are resolved in TclLookupVar and
00033  *      LookupCompiledLocal. Each namespace may also have its own set of
00034  *      resolution functions which take precedence over those for the
00035  *      interpreter.
00036  *
00037  *      When a name is resolved, it is handled as follows. First, the name is
00038  *      passed to the resolution functions for the namespace. If not resolved,
00039  *      the name is passed to each of the resolution functions added to the
00040  *      interpreter. Finally, if still not resolved, the name is handled using
00041  *      the default Tcl rules for name resolution.
00042  *
00043  * Results:
00044  *      Returns pointers to the current name resolution functions in the
00045  *      cmdProcPtr, varProcPtr and compiledVarProcPtr arguments.
00046  *
00047  * Side effects:
00048  *      If a compiledVarProc is specified, this function bumps the
00049  *      compileEpoch for the interpreter, forcing all code to be recompiled.
00050  *      If a cmdProc is specified, this function bumps the cmdRefEpoch in all
00051  *      namespaces, forcing commands to be resolved again using the new rules.
00052  *
00053  *----------------------------------------------------------------------
00054  */
00055 
00056 void
00057 Tcl_AddInterpResolvers(
00058     Tcl_Interp *interp,         /* Interpreter whose name resolution rules are
00059                                  * being modified. */
00060     CONST char *name,           /* Name of this resolution scheme. */
00061     Tcl_ResolveCmdProc *cmdProc,/* New function for command resolution. */
00062     Tcl_ResolveVarProc *varProc,/* Function for variable resolution at
00063                                  * runtime. */
00064     Tcl_ResolveCompiledVarProc *compiledVarProc)
00065                                 /* Function for variable resolution at compile
00066                                  * time. */
00067 {
00068     Interp *iPtr = (Interp *) interp;
00069     ResolverScheme *resPtr;
00070 
00071     /*
00072      * Since we're adding a new name resolution scheme, we must force all code
00073      * to be recompiled to use the new scheme. If there are new compiled
00074      * variable resolution rules, bump the compiler epoch to invalidate
00075      * compiled code. If there are new command resolution rules, bump the
00076      * cmdRefEpoch in all namespaces.
00077      */
00078 
00079     if (compiledVarProc) {
00080         iPtr->compileEpoch++;
00081     }
00082     if (cmdProc) {
00083         BumpCmdRefEpochs(iPtr->globalNsPtr);
00084     }
00085 
00086     /*
00087      * Look for an existing scheme with the given name. If found, then replace
00088      * its rules.
00089      */
00090 
00091     for (resPtr=iPtr->resolverPtr ; resPtr!=NULL ; resPtr=resPtr->nextPtr) {
00092         if (*name == *resPtr->name && strcmp(name, resPtr->name) == 0) {
00093             resPtr->cmdResProc = cmdProc;
00094             resPtr->varResProc = varProc;
00095             resPtr->compiledVarResProc = compiledVarProc;
00096             return;
00097         }
00098     }
00099 
00100     /*
00101      * Otherwise, this is a new scheme. Add it to the FRONT of the linked
00102      * list, so that it overrides existing schemes.
00103      */
00104 
00105     resPtr = (ResolverScheme *) ckalloc(sizeof(ResolverScheme));
00106     resPtr->name = (char *) ckalloc((unsigned)(strlen(name) + 1));
00107     strcpy(resPtr->name, name);
00108     resPtr->cmdResProc = cmdProc;
00109     resPtr->varResProc = varProc;
00110     resPtr->compiledVarResProc = compiledVarProc;
00111     resPtr->nextPtr = iPtr->resolverPtr;
00112     iPtr->resolverPtr = resPtr;
00113 }
00114 
00115 /*
00116  *----------------------------------------------------------------------
00117  *
00118  * Tcl_GetInterpResolvers --
00119  *
00120  *      Looks for a set of command/variable resolution functions with the
00121  *      given name in an interpreter. These functions are registered by
00122  *      calling Tcl_AddInterpResolvers.
00123  *
00124  * Results:
00125  *      If the name is recognized, this function returns non-zero, along with
00126  *      pointers to the name resolution functions in the Tcl_ResolverInfo
00127  *      structure. If the name is not recognized, this function returns zero.
00128  *
00129  * Side effects:
00130  *      None.
00131  *
00132  *----------------------------------------------------------------------
00133  */
00134 
00135 int
00136 Tcl_GetInterpResolvers(
00137     Tcl_Interp *interp,         /* Interpreter whose name resolution rules are
00138                                  * being queried. */
00139     CONST char *name,           /* Look for a scheme with this name. */
00140     Tcl_ResolverInfo *resInfoPtr)
00141                                 /* Returns pointers to the functions, if
00142                                  * found */
00143 {
00144     Interp *iPtr = (Interp *) interp;
00145     ResolverScheme *resPtr;
00146 
00147     /*
00148      * Look for an existing scheme with the given name. If found, then return
00149      * pointers to its functions.
00150      */
00151 
00152     for (resPtr=iPtr->resolverPtr ; resPtr!=NULL ; resPtr=resPtr->nextPtr) {
00153         if (*name == *resPtr->name && strcmp(name, resPtr->name) == 0) {
00154             resInfoPtr->cmdResProc = resPtr->cmdResProc;
00155             resInfoPtr->varResProc = resPtr->varResProc;
00156             resInfoPtr->compiledVarResProc = resPtr->compiledVarResProc;
00157             return 1;
00158         }
00159     }
00160 
00161     return 0;
00162 }
00163 
00164 /*
00165  *----------------------------------------------------------------------
00166  *
00167  * Tcl_RemoveInterpResolvers --
00168  *
00169  *      Removes a set of command/variable resolution functions previously
00170  *      added by Tcl_AddInterpResolvers. The next time a command/variable name
00171  *      is resolved, these functions won't be consulted.
00172  *
00173  * Results:
00174  *      Returns non-zero if the name was recognized and the resolution scheme
00175  *      was deleted. Returns zero otherwise.
00176  *
00177  * Side effects:
00178  *      If a scheme with a compiledVarProc was deleted, this function bumps
00179  *      the compileEpoch for the interpreter, forcing all code to be
00180  *      recompiled. If a scheme with a cmdProc was deleted, this function
00181  *      bumps the cmdRefEpoch in all namespaces, forcing commands to be
00182  *      resolved again using the new rules.
00183  *
00184  *----------------------------------------------------------------------
00185  */
00186 
00187 int
00188 Tcl_RemoveInterpResolvers(
00189     Tcl_Interp *interp,         /* Interpreter whose name resolution rules are
00190                                  * being modified. */
00191     CONST char *name)           /* Name of the scheme to be removed. */
00192 {
00193     Interp *iPtr = (Interp *) interp;
00194     ResolverScheme **prevPtrPtr, *resPtr;
00195 
00196     /*
00197      * Look for an existing scheme with the given name.
00198      */
00199 
00200     prevPtrPtr = &iPtr->resolverPtr;
00201     for (resPtr=iPtr->resolverPtr ; resPtr!=NULL ; resPtr=resPtr->nextPtr) {
00202         if (*name == *resPtr->name && strcmp(name, resPtr->name) == 0) {
00203             break;
00204         }
00205         prevPtrPtr = &resPtr->nextPtr;
00206     }
00207 
00208     /*
00209      * If we found the scheme, delete it.
00210      */
00211 
00212     if (resPtr) {
00213         /*
00214          * If we're deleting a scheme with compiled variable resolution rules,
00215          * bump the compiler epoch to invalidate compiled code. If we're
00216          * deleting a scheme with command resolution rules, bump the
00217          * cmdRefEpoch in all namespaces.
00218          */
00219 
00220         if (resPtr->compiledVarResProc) {
00221             iPtr->compileEpoch++;
00222         }
00223         if (resPtr->cmdResProc) {
00224             BumpCmdRefEpochs(iPtr->globalNsPtr);
00225         }
00226 
00227         *prevPtrPtr = resPtr->nextPtr;
00228         ckfree(resPtr->name);
00229         ckfree((char *) resPtr);
00230 
00231         return 1;
00232     }
00233     return 0;
00234 }
00235 
00236 /*
00237  *----------------------------------------------------------------------
00238  *
00239  * BumpCmdRefEpochs --
00240  *
00241  *      This function is used to bump the cmdRefEpoch counters in the
00242  *      specified namespace and all of its child namespaces. It is used
00243  *      whenever name resolution schemes are added/removed from an
00244  *      interpreter, to invalidate all command references.
00245  *
00246  * Results:
00247  *      None.
00248  *
00249  * Side effects:
00250  *      Bumps the cmdRefEpoch in the specified namespace and its children,
00251  *      recursively.
00252  *
00253  *----------------------------------------------------------------------
00254  */
00255 
00256 static void
00257 BumpCmdRefEpochs(
00258     Namespace *nsPtr)           /* Namespace being modified. */
00259 {
00260     Tcl_HashEntry *entry;
00261     Tcl_HashSearch search;
00262 
00263     nsPtr->cmdRefEpoch++;
00264 
00265     for (entry = Tcl_FirstHashEntry(&nsPtr->childTable, &search);
00266             entry != NULL; entry = Tcl_NextHashEntry(&search)) {
00267         Namespace *childNsPtr = (Namespace *) Tcl_GetHashValue(entry);
00268         BumpCmdRefEpochs(childNsPtr);
00269     }
00270     TclInvalidateNsPath(nsPtr);
00271 }
00272 
00273 /*
00274  *----------------------------------------------------------------------
00275  *
00276  * Tcl_SetNamespaceResolvers --
00277  *
00278  *      Sets the command/variable resolution functions for a namespace,
00279  *      thereby changing the way that command/variable names are interpreted.
00280  *      This allows extension writers to support different name resolution
00281  *      schemes, such as those for object-oriented packages.
00282  *
00283  *      Command resolution is handled by a function of the following type:
00284  *
00285  *        typedef int (*Tcl_ResolveCmdProc)(Tcl_Interp *interp,
00286  *                CONST char *name, Tcl_Namespace *context,
00287  *                int flags, Tcl_Command *rPtr);
00288  *
00289  *      Whenever a command is executed or Tcl_FindCommand is invoked within
00290  *      the namespace, this function is called to resolve the command name. If
00291  *      this function is able to resolve the name, it should return the status
00292  *      code TCL_OK, along with the corresponding Tcl_Command in the rPtr
00293  *      argument. Otherwise, the function can return TCL_CONTINUE, and the
00294  *      command will be treated under the usual name resolution rules. Or, it
00295  *      can return TCL_ERROR, and the command will be considered invalid.
00296  *
00297  *      Variable resolution is handled by two functions. The first is called
00298  *      whenever a variable needs to be resolved at compile time:
00299  *
00300  *        typedef int (*Tcl_ResolveCompiledVarProc)(Tcl_Interp *interp,
00301  *                CONST char *name, Tcl_Namespace *context,
00302  *                Tcl_ResolvedVarInfo *rPtr);
00303  *
00304  *      If this function is able to resolve the name, it should return the
00305  *      status code TCL_OK, along with variable resolution info in the rPtr
00306  *      argument; this info will be used to set up compiled locals in the call
00307  *      frame at runtime. The function may also return TCL_CONTINUE, and the
00308  *      variable will be treated under the usual name resolution rules. Or, it
00309  *      can return TCL_ERROR, and the variable will be considered invalid.
00310  *
00311  *      Another function is used whenever a variable needs to be resolved at
00312  *      runtime but it is not recognized as a compiled local. (For example,
00313  *      the variable may be requested via Tcl_FindNamespaceVar.) This function
00314  *      has the following type:
00315  *
00316  *        typedef int (*Tcl_ResolveVarProc)(Tcl_Interp *interp,
00317  *                CONST char *name, Tcl_Namespace *context,
00318  *                int flags, Tcl_Var *rPtr);
00319  *
00320  *      This function is quite similar to the compile-time version. It returns
00321  *      the same status codes, but if variable resolution succeeds, this
00322  *      function returns a Tcl_Var directly via the rPtr argument.
00323  *
00324  * Results:
00325  *      Nothing.
00326  *
00327  * Side effects:
00328  *      Bumps the command epoch counter for the namespace, invalidating all
00329  *      command references in that namespace. Also bumps the resolver epoch
00330  *      counter for the namespace, forcing all code in the namespace to be
00331  *      recompiled.
00332  *
00333  *----------------------------------------------------------------------
00334  */
00335 
00336 void
00337 Tcl_SetNamespaceResolvers(
00338     Tcl_Namespace *namespacePtr,/* Namespace whose resolution rules are being
00339                                  * modified. */
00340     Tcl_ResolveCmdProc *cmdProc,/* Function for command resolution */
00341     Tcl_ResolveVarProc *varProc,/* Function for variable resolution at
00342                                  * run-time */
00343     Tcl_ResolveCompiledVarProc *compiledVarProc)
00344                                 /* Function for variable resolution at compile
00345                                  * time. */
00346 {
00347     Namespace *nsPtr = (Namespace *) namespacePtr;
00348 
00349     /*
00350      * Plug in the new command resolver, and bump the epoch counters so that
00351      * all code will have to be recompiled and all commands will have to be
00352      * resolved again using the new policy.
00353      */
00354 
00355     nsPtr->cmdResProc = cmdProc;
00356     nsPtr->varResProc = varProc;
00357     nsPtr->compiledVarResProc = compiledVarProc;
00358 
00359     nsPtr->cmdRefEpoch++;
00360     nsPtr->resolverEpoch++;
00361     TclInvalidateNsPath(nsPtr);
00362 }
00363 
00364 /*
00365  *----------------------------------------------------------------------
00366  *
00367  * Tcl_GetNamespaceResolvers --
00368  *
00369  *      Returns the current command/variable resolution functions for a
00370  *      namespace. By default, these functions are NULL. New functions can be
00371  *      installed by calling Tcl_SetNamespaceResolvers, to provide new name
00372  *      resolution rules.
00373  *
00374  * Results:
00375  *      Returns non-zero if any name resolution functions have been assigned
00376  *      to this namespace; also returns pointers to the functions in the
00377  *      Tcl_ResolverInfo structure. Returns zero otherwise.
00378  *
00379  * Side effects:
00380  *      None.
00381  *
00382  *----------------------------------------------------------------------
00383  */
00384 
00385 int
00386 Tcl_GetNamespaceResolvers(
00387     Tcl_Namespace *namespacePtr,/* Namespace whose resolution rules are being
00388                                  * modified. */
00389     Tcl_ResolverInfo *resInfoPtr)
00390                                 /* Returns: pointers for all name resolution
00391                                  * functions assigned to this namespace. */
00392 {
00393     Namespace *nsPtr = (Namespace *) namespacePtr;
00394 
00395     resInfoPtr->cmdResProc = nsPtr->cmdResProc;
00396     resInfoPtr->varResProc = nsPtr->varResProc;
00397     resInfoPtr->compiledVarResProc = nsPtr->compiledVarResProc;
00398 
00399     if (nsPtr->cmdResProc != NULL || nsPtr->varResProc != NULL ||
00400             nsPtr->compiledVarResProc != NULL) {
00401         return 1;
00402     }
00403     return 0;
00404 }
00405 
00406 /*
00407  * Local Variables:
00408  * mode: c
00409  * c-basic-offset: 4
00410  * fill-column: 78
00411  * End:
00412  */



Generated on Wed Mar 12 12:18:21 2008 by  doxygen 1.5.1