Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/tcl8.5.2/generic/tclResolve.c @ 64

Last change on this file since 64 was 25, checked in by landauf, 16 years ago

added tcl to libs

File size: 13.1 KB
Line 
1/*
2 * tclResolve.c --
3 *
4 *      Contains hooks for customized command/variable name resolution
5 *      schemes. These hooks allow extensions like [incr Tcl] to add their own
6 *      name resolution rules to the Tcl language. Rules can be applied to a
7 *      particular namespace, to the interpreter as a whole, or both.
8 *
9 * Copyright (c) 1998 Lucent Technologies, Inc.
10 *
11 * See the file "license.terms" for information on usage and redistribution of
12 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
13 *
14 * RCS: @(#) $Id: tclResolve.c,v 1.9 2007/04/05 13:20:49 dkf Exp $
15 */
16
17#include "tclInt.h"
18
19/*
20 * Declarations for functions local to this file:
21 */
22
23static void             BumpCmdRefEpochs(Namespace *nsPtr);
24
25/*
26 *----------------------------------------------------------------------
27 *
28 * Tcl_AddInterpResolvers --
29 *
30 *      Adds a set of command/variable resolution functions to an interpreter.
31 *      These functions are consulted when commands are resolved in
32 *      Tcl_FindCommand, and when variables are resolved in TclLookupVar and
33 *      LookupCompiledLocal. Each namespace may also have its own set of
34 *      resolution functions which take precedence over those for the
35 *      interpreter.
36 *
37 *      When a name is resolved, it is handled as follows. First, the name is
38 *      passed to the resolution functions for the namespace. If not resolved,
39 *      the name is passed to each of the resolution functions added to the
40 *      interpreter. Finally, if still not resolved, the name is handled using
41 *      the default Tcl rules for name resolution.
42 *
43 * Results:
44 *      Returns pointers to the current name resolution functions in the
45 *      cmdProcPtr, varProcPtr and compiledVarProcPtr arguments.
46 *
47 * Side effects:
48 *      If a compiledVarProc is specified, this function bumps the
49 *      compileEpoch for the interpreter, forcing all code to be recompiled.
50 *      If a cmdProc is specified, this function bumps the cmdRefEpoch in all
51 *      namespaces, forcing commands to be resolved again using the new rules.
52 *
53 *----------------------------------------------------------------------
54 */
55
56void
57Tcl_AddInterpResolvers(
58    Tcl_Interp *interp,         /* Interpreter whose name resolution rules are
59                                 * being modified. */
60    CONST char *name,           /* Name of this resolution scheme. */
61    Tcl_ResolveCmdProc *cmdProc,/* New function for command resolution. */
62    Tcl_ResolveVarProc *varProc,/* Function for variable resolution at
63                                 * runtime. */
64    Tcl_ResolveCompiledVarProc *compiledVarProc)
65                                /* Function for variable resolution at compile
66                                 * time. */
67{
68    Interp *iPtr = (Interp *) interp;
69    ResolverScheme *resPtr;
70
71    /*
72     * Since we're adding a new name resolution scheme, we must force all code
73     * to be recompiled to use the new scheme. If there are new compiled
74     * variable resolution rules, bump the compiler epoch to invalidate
75     * compiled code. If there are new command resolution rules, bump the
76     * cmdRefEpoch in all namespaces.
77     */
78
79    if (compiledVarProc) {
80        iPtr->compileEpoch++;
81    }
82    if (cmdProc) {
83        BumpCmdRefEpochs(iPtr->globalNsPtr);
84    }
85
86    /*
87     * Look for an existing scheme with the given name. If found, then replace
88     * its rules.
89     */
90
91    for (resPtr=iPtr->resolverPtr ; resPtr!=NULL ; resPtr=resPtr->nextPtr) {
92        if (*name == *resPtr->name && strcmp(name, resPtr->name) == 0) {
93            resPtr->cmdResProc = cmdProc;
94            resPtr->varResProc = varProc;
95            resPtr->compiledVarResProc = compiledVarProc;
96            return;
97        }
98    }
99
100    /*
101     * Otherwise, this is a new scheme. Add it to the FRONT of the linked
102     * list, so that it overrides existing schemes.
103     */
104
105    resPtr = (ResolverScheme *) ckalloc(sizeof(ResolverScheme));
106    resPtr->name = (char *) ckalloc((unsigned)(strlen(name) + 1));
107    strcpy(resPtr->name, name);
108    resPtr->cmdResProc = cmdProc;
109    resPtr->varResProc = varProc;
110    resPtr->compiledVarResProc = compiledVarProc;
111    resPtr->nextPtr = iPtr->resolverPtr;
112    iPtr->resolverPtr = resPtr;
113}
114
115/*
116 *----------------------------------------------------------------------
117 *
118 * Tcl_GetInterpResolvers --
119 *
120 *      Looks for a set of command/variable resolution functions with the
121 *      given name in an interpreter. These functions are registered by
122 *      calling Tcl_AddInterpResolvers.
123 *
124 * Results:
125 *      If the name is recognized, this function returns non-zero, along with
126 *      pointers to the name resolution functions in the Tcl_ResolverInfo
127 *      structure. If the name is not recognized, this function returns zero.
128 *
129 * Side effects:
130 *      None.
131 *
132 *----------------------------------------------------------------------
133 */
134
135int
136Tcl_GetInterpResolvers(
137    Tcl_Interp *interp,         /* Interpreter whose name resolution rules are
138                                 * being queried. */
139    CONST char *name,           /* Look for a scheme with this name. */
140    Tcl_ResolverInfo *resInfoPtr)
141                                /* Returns pointers to the functions, if
142                                 * found */
143{
144    Interp *iPtr = (Interp *) interp;
145    ResolverScheme *resPtr;
146
147    /*
148     * Look for an existing scheme with the given name. If found, then return
149     * pointers to its functions.
150     */
151
152    for (resPtr=iPtr->resolverPtr ; resPtr!=NULL ; resPtr=resPtr->nextPtr) {
153        if (*name == *resPtr->name && strcmp(name, resPtr->name) == 0) {
154            resInfoPtr->cmdResProc = resPtr->cmdResProc;
155            resInfoPtr->varResProc = resPtr->varResProc;
156            resInfoPtr->compiledVarResProc = resPtr->compiledVarResProc;
157            return 1;
158        }
159    }
160
161    return 0;
162}
163
164/*
165 *----------------------------------------------------------------------
166 *
167 * Tcl_RemoveInterpResolvers --
168 *
169 *      Removes a set of command/variable resolution functions previously
170 *      added by Tcl_AddInterpResolvers. The next time a command/variable name
171 *      is resolved, these functions won't be consulted.
172 *
173 * Results:
174 *      Returns non-zero if the name was recognized and the resolution scheme
175 *      was deleted. Returns zero otherwise.
176 *
177 * Side effects:
178 *      If a scheme with a compiledVarProc was deleted, this function bumps
179 *      the compileEpoch for the interpreter, forcing all code to be
180 *      recompiled. If a scheme with a cmdProc was deleted, this function
181 *      bumps the cmdRefEpoch in all namespaces, forcing commands to be
182 *      resolved again using the new rules.
183 *
184 *----------------------------------------------------------------------
185 */
186
187int
188Tcl_RemoveInterpResolvers(
189    Tcl_Interp *interp,         /* Interpreter whose name resolution rules are
190                                 * being modified. */
191    CONST char *name)           /* Name of the scheme to be removed. */
192{
193    Interp *iPtr = (Interp *) interp;
194    ResolverScheme **prevPtrPtr, *resPtr;
195
196    /*
197     * Look for an existing scheme with the given name.
198     */
199
200    prevPtrPtr = &iPtr->resolverPtr;
201    for (resPtr=iPtr->resolverPtr ; resPtr!=NULL ; resPtr=resPtr->nextPtr) {
202        if (*name == *resPtr->name && strcmp(name, resPtr->name) == 0) {
203            break;
204        }
205        prevPtrPtr = &resPtr->nextPtr;
206    }
207
208    /*
209     * If we found the scheme, delete it.
210     */
211
212    if (resPtr) {
213        /*
214         * If we're deleting a scheme with compiled variable resolution rules,
215         * bump the compiler epoch to invalidate compiled code. If we're
216         * deleting a scheme with command resolution rules, bump the
217         * cmdRefEpoch in all namespaces.
218         */
219
220        if (resPtr->compiledVarResProc) {
221            iPtr->compileEpoch++;
222        }
223        if (resPtr->cmdResProc) {
224            BumpCmdRefEpochs(iPtr->globalNsPtr);
225        }
226
227        *prevPtrPtr = resPtr->nextPtr;
228        ckfree(resPtr->name);
229        ckfree((char *) resPtr);
230
231        return 1;
232    }
233    return 0;
234}
235
236/*
237 *----------------------------------------------------------------------
238 *
239 * BumpCmdRefEpochs --
240 *
241 *      This function is used to bump the cmdRefEpoch counters in the
242 *      specified namespace and all of its child namespaces. It is used
243 *      whenever name resolution schemes are added/removed from an
244 *      interpreter, to invalidate all command references.
245 *
246 * Results:
247 *      None.
248 *
249 * Side effects:
250 *      Bumps the cmdRefEpoch in the specified namespace and its children,
251 *      recursively.
252 *
253 *----------------------------------------------------------------------
254 */
255
256static void
257BumpCmdRefEpochs(
258    Namespace *nsPtr)           /* Namespace being modified. */
259{
260    Tcl_HashEntry *entry;
261    Tcl_HashSearch search;
262
263    nsPtr->cmdRefEpoch++;
264
265    for (entry = Tcl_FirstHashEntry(&nsPtr->childTable, &search);
266            entry != NULL; entry = Tcl_NextHashEntry(&search)) {
267        Namespace *childNsPtr = (Namespace *) Tcl_GetHashValue(entry);
268        BumpCmdRefEpochs(childNsPtr);
269    }
270    TclInvalidateNsPath(nsPtr);
271}
272
273/*
274 *----------------------------------------------------------------------
275 *
276 * Tcl_SetNamespaceResolvers --
277 *
278 *      Sets the command/variable resolution functions for a namespace,
279 *      thereby changing the way that command/variable names are interpreted.
280 *      This allows extension writers to support different name resolution
281 *      schemes, such as those for object-oriented packages.
282 *
283 *      Command resolution is handled by a function of the following type:
284 *
285 *        typedef int (*Tcl_ResolveCmdProc)(Tcl_Interp *interp,
286 *                CONST char *name, Tcl_Namespace *context,
287 *                int flags, Tcl_Command *rPtr);
288 *
289 *      Whenever a command is executed or Tcl_FindCommand is invoked within
290 *      the namespace, this function is called to resolve the command name. If
291 *      this function is able to resolve the name, it should return the status
292 *      code TCL_OK, along with the corresponding Tcl_Command in the rPtr
293 *      argument. Otherwise, the function can return TCL_CONTINUE, and the
294 *      command will be treated under the usual name resolution rules. Or, it
295 *      can return TCL_ERROR, and the command will be considered invalid.
296 *
297 *      Variable resolution is handled by two functions. The first is called
298 *      whenever a variable needs to be resolved at compile time:
299 *
300 *        typedef int (*Tcl_ResolveCompiledVarProc)(Tcl_Interp *interp,
301 *                CONST char *name, Tcl_Namespace *context,
302 *                Tcl_ResolvedVarInfo *rPtr);
303 *
304 *      If this function is able to resolve the name, it should return the
305 *      status code TCL_OK, along with variable resolution info in the rPtr
306 *      argument; this info will be used to set up compiled locals in the call
307 *      frame at runtime. The function may also return TCL_CONTINUE, and the
308 *      variable will be treated under the usual name resolution rules. Or, it
309 *      can return TCL_ERROR, and the variable will be considered invalid.
310 *
311 *      Another function is used whenever a variable needs to be resolved at
312 *      runtime but it is not recognized as a compiled local. (For example,
313 *      the variable may be requested via Tcl_FindNamespaceVar.) This function
314 *      has the following type:
315 *
316 *        typedef int (*Tcl_ResolveVarProc)(Tcl_Interp *interp,
317 *                CONST char *name, Tcl_Namespace *context,
318 *                int flags, Tcl_Var *rPtr);
319 *
320 *      This function is quite similar to the compile-time version. It returns
321 *      the same status codes, but if variable resolution succeeds, this
322 *      function returns a Tcl_Var directly via the rPtr argument.
323 *
324 * Results:
325 *      Nothing.
326 *
327 * Side effects:
328 *      Bumps the command epoch counter for the namespace, invalidating all
329 *      command references in that namespace. Also bumps the resolver epoch
330 *      counter for the namespace, forcing all code in the namespace to be
331 *      recompiled.
332 *
333 *----------------------------------------------------------------------
334 */
335
336void
337Tcl_SetNamespaceResolvers(
338    Tcl_Namespace *namespacePtr,/* Namespace whose resolution rules are being
339                                 * modified. */
340    Tcl_ResolveCmdProc *cmdProc,/* Function for command resolution */
341    Tcl_ResolveVarProc *varProc,/* Function for variable resolution at
342                                 * run-time */
343    Tcl_ResolveCompiledVarProc *compiledVarProc)
344                                /* Function for variable resolution at compile
345                                 * time. */
346{
347    Namespace *nsPtr = (Namespace *) namespacePtr;
348
349    /*
350     * Plug in the new command resolver, and bump the epoch counters so that
351     * all code will have to be recompiled and all commands will have to be
352     * resolved again using the new policy.
353     */
354
355    nsPtr->cmdResProc = cmdProc;
356    nsPtr->varResProc = varProc;
357    nsPtr->compiledVarResProc = compiledVarProc;
358
359    nsPtr->cmdRefEpoch++;
360    nsPtr->resolverEpoch++;
361    TclInvalidateNsPath(nsPtr);
362}
363
364/*
365 *----------------------------------------------------------------------
366 *
367 * Tcl_GetNamespaceResolvers --
368 *
369 *      Returns the current command/variable resolution functions for a
370 *      namespace. By default, these functions are NULL. New functions can be
371 *      installed by calling Tcl_SetNamespaceResolvers, to provide new name
372 *      resolution rules.
373 *
374 * Results:
375 *      Returns non-zero if any name resolution functions have been assigned
376 *      to this namespace; also returns pointers to the functions in the
377 *      Tcl_ResolverInfo structure. Returns zero otherwise.
378 *
379 * Side effects:
380 *      None.
381 *
382 *----------------------------------------------------------------------
383 */
384
385int
386Tcl_GetNamespaceResolvers(
387    Tcl_Namespace *namespacePtr,/* Namespace whose resolution rules are being
388                                 * modified. */
389    Tcl_ResolverInfo *resInfoPtr)
390                                /* Returns: pointers for all name resolution
391                                 * functions assigned to this namespace. */
392{
393    Namespace *nsPtr = (Namespace *) namespacePtr;
394
395    resInfoPtr->cmdResProc = nsPtr->cmdResProc;
396    resInfoPtr->varResProc = nsPtr->varResProc;
397    resInfoPtr->compiledVarResProc = nsPtr->compiledVarResProc;
398
399    if (nsPtr->cmdResProc != NULL || nsPtr->varResProc != NULL ||
400            nsPtr->compiledVarResProc != NULL) {
401        return 1;
402    }
403    return 0;
404}
405
406/*
407 * Local Variables:
408 * mode: c
409 * c-basic-offset: 4
410 * fill-column: 78
411 * End:
412 */
Note: See TracBrowser for help on using the repository browser.