OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [itcl/] [itcl/] [generic/] [itcl_parse.c] - Blame information for rev 1773

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * ------------------------------------------------------------------------
3
 *      PACKAGE:  [incr Tcl]
4
 *  DESCRIPTION:  Object-Oriented Extensions to Tcl
5
 *
6
 *  [incr Tcl] provides object-oriented extensions to Tcl, much as
7
 *  C++ provides object-oriented extensions to C.  It provides a means
8
 *  of encapsulating related procedures together with their shared data
9
 *  in a local namespace that is hidden from the outside world.  It
10
 *  promotes code re-use through inheritance.  More than anything else,
11
 *  it encourages better organization of Tcl applications through the
12
 *  object-oriented paradigm, leading to code that is easier to
13
 *  understand and maintain.
14
 *
15
 *  Procedures in this file support the new syntax for [incr Tcl]
16
 *  class definitions:
17
 *
18
 *    itcl_class <className> {
19
 *        inherit <base-class>...
20
 *
21
 *        constructor {<arglist>} ?{<init>}? {<body>}
22
 *        destructor {<body>}
23
 *
24
 *        method <name> {<arglist>} {<body>}
25
 *        proc <name> {<arglist>} {<body>}
26
 *        variable <name> ?<init>? ?<config>?
27
 *        common <name> ?<init>?
28
 *
29
 *        public <thing> ?<args>...?
30
 *        protected <thing> ?<args>...?
31
 *        private <thing> ?<args>...?
32
 *    }
33
 *
34
 * ========================================================================
35
 *  AUTHOR:  Michael J. McLennan
36
 *           Bell Labs Innovations for Lucent Technologies
37
 *           mmclennan@lucent.com
38
 *           http://www.tcltk.com/itcl
39
 *
40
 *     RCS:  $Id: itcl_parse.c,v 1.1.1.1 2002-01-16 10:24:46 markom Exp $
41
 * ========================================================================
42
 *           Copyright (c) 1993-1998  Lucent Technologies, Inc.
43
 * ------------------------------------------------------------------------
44
 * See the file "license.terms" for information on usage and redistribution
45
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
46
 */
47
#include "itclInt.h"
48
 
49
/*
50
 *  Info needed for public/protected/private commands:
51
 */
52
typedef struct ProtectionCmdInfo {
53
    int pLevel;               /* protection level */
54
    ItclObjectInfo *info;     /* info regarding all known objects */
55
} ProtectionCmdInfo;
56
 
57
/*
58
 *  FORWARD DECLARATIONS
59
 */
60
static void ItclFreeParserCommandData _ANSI_ARGS_((char* cdata));
61
 
62
 
63
/*
64
 * ------------------------------------------------------------------------
65
 *  Itcl_ParseInit()
66
 *
67
 *  Invoked by Itcl_Init() whenever a new interpeter is created to add
68
 *  [incr Tcl] facilities.  Adds the commands needed to parse class
69
 *  definitions.
70
 * ------------------------------------------------------------------------
71
 */
72
int
73
Itcl_ParseInit(interp, info)
74
    Tcl_Interp *interp;     /* interpreter to be updated */
75
    ItclObjectInfo *info;   /* info regarding all known objects */
76
{
77
    Tcl_Namespace *parserNs;
78
    ProtectionCmdInfo *pInfo;
79
 
80
    /*
81
     *  Create the "itcl::parser" namespace used to parse class
82
     *  definitions.
83
     */
84
    parserNs = Tcl_CreateNamespace(interp, "::itcl::parser",
85
        (ClientData)info, Itcl_ReleaseData);
86
 
87
    if (!parserNs) {
88
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
89
            " (cannot initialize itcl parser)",
90
            (char*)NULL);
91
        return TCL_ERROR;
92
    }
93
    Itcl_PreserveData((ClientData)info);
94
 
95
    /*
96
     *  Add commands for parsing class definitions.
97
     */
98
    Tcl_CreateObjCommand(interp, "::itcl::parser::inherit",
99
        Itcl_ClassInheritCmd, (ClientData)info, (Tcl_CmdDeleteProc*)NULL);
100
 
101
    Tcl_CreateObjCommand(interp, "::itcl::parser::constructor",
102
        Itcl_ClassConstructorCmd, (ClientData)info, (Tcl_CmdDeleteProc*)NULL);
103
 
104
    Tcl_CreateObjCommand(interp, "::itcl::parser::destructor",
105
        Itcl_ClassDestructorCmd, (ClientData)info, (Tcl_CmdDeleteProc*)NULL);
106
 
107
    Tcl_CreateObjCommand(interp, "::itcl::parser::method",
108
        Itcl_ClassMethodCmd, (ClientData)info, (Tcl_CmdDeleteProc*)NULL);
109
 
110
    Tcl_CreateObjCommand(interp, "::itcl::parser::proc",
111
        Itcl_ClassProcCmd, (ClientData)info, (Tcl_CmdDeleteProc*)NULL);
112
 
113
    Tcl_CreateObjCommand(interp, "::itcl::parser::common",
114
        Itcl_ClassCommonCmd, (ClientData)info, (Tcl_CmdDeleteProc*)NULL);
115
 
116
    Tcl_CreateObjCommand(interp, "::itcl::parser::variable",
117
        Itcl_ClassVariableCmd, (ClientData)info, (Tcl_CmdDeleteProc*)NULL);
118
 
119
    pInfo = (ProtectionCmdInfo*)ckalloc(sizeof(ProtectionCmdInfo));
120
    pInfo->pLevel = ITCL_PUBLIC;
121
    pInfo->info = info;
122
 
123
    Tcl_CreateObjCommand(interp, "::itcl::parser::public",
124
        Itcl_ClassProtectionCmd, (ClientData)pInfo,
125
            (Tcl_CmdDeleteProc*) ItclFreeParserCommandData);
126
 
127
    pInfo = (ProtectionCmdInfo*)ckalloc(sizeof(ProtectionCmdInfo));
128
    pInfo->pLevel = ITCL_PROTECTED;
129
    pInfo->info = info;
130
 
131
    Tcl_CreateObjCommand(interp, "::itcl::parser::protected",
132
        Itcl_ClassProtectionCmd, (ClientData)pInfo,
133
            (Tcl_CmdDeleteProc*) ItclFreeParserCommandData);
134
 
135
    pInfo = (ProtectionCmdInfo*)ckalloc(sizeof(ProtectionCmdInfo));
136
    pInfo->pLevel = ITCL_PRIVATE;
137
    pInfo->info = info;
138
 
139
    Tcl_CreateObjCommand(interp, "::itcl::parser::private",
140
        Itcl_ClassProtectionCmd, (ClientData)pInfo,
141
            (Tcl_CmdDeleteProc*) ItclFreeParserCommandData);
142
 
143
    /*
144
     *  Set the runtime variable resolver for the parser namespace,
145
     *  to control access to "common" data members while parsing
146
     *  the class definition.
147
     */
148
    Tcl_SetNamespaceResolvers(parserNs, (Tcl_ResolveCmdProc*)NULL,
149
        Itcl_ParseVarResolver, (Tcl_ResolveCompiledVarProc*)NULL);
150
 
151
    /*
152
     *  Install the "class" command for defining new classes.
153
     */
154
    Tcl_CreateObjCommand(interp, "::itcl::class", Itcl_ClassCmd,
155
        (ClientData)info, Itcl_ReleaseData);
156
    Itcl_PreserveData((ClientData)info);
157
 
158
    return TCL_OK;
159
}
160
 
161
 
162
/*
163
 * ------------------------------------------------------------------------
164
 *  Itcl_ClassCmd()
165
 *
166
 *  Invoked by Tcl whenever the user issues an "itcl::class" command to
167
 *  specify a class definition.  Handles the following syntax:
168
 *
169
 *    itcl::class <className> {
170
 *        inherit <base-class>...
171
 *
172
 *        constructor {<arglist>} ?{<init>}? {<body>}
173
 *        destructor {<body>}
174
 *
175
 *        method <name> {<arglist>} {<body>}
176
 *        proc <name> {<arglist>} {<body>}
177
 *        variable <varname> ?<init>? ?<config>?
178
 *        common <varname> ?<init>?
179
 *
180
 *        public <args>...
181
 *        protected <args>...
182
 *        private <args>...
183
 *    }
184
 *
185
 * ------------------------------------------------------------------------
186
 */
187
int
188
Itcl_ClassCmd(clientData, interp, objc, objv)
189
    ClientData clientData;   /* info for all known objects */
190
    Tcl_Interp *interp;      /* current interpreter */
191
    int objc;                /* number of arguments */
192
    Tcl_Obj *CONST objv[];   /* argument objects */
193
{
194
    ItclObjectInfo* info = (ItclObjectInfo*)clientData;
195
 
196
    int result;
197
    char *className;
198
    Tcl_Namespace *parserNs;
199
    ItclClass *cdefnPtr;
200
    Tcl_CallFrame frame;
201
 
202
    if (objc != 3) {
203
        Tcl_WrongNumArgs(interp, 1, objv, "name { definition }");
204
        return TCL_ERROR;
205
    }
206
    className = Tcl_GetStringFromObj(objv[1], (int*)NULL);
207
 
208
    /*
209
     *  Find the namespace to use as a parser for the class definition.
210
     *  If for some reason it is destroyed, bail out here.
211
     */
212
    parserNs = Tcl_FindNamespace(interp, "::itcl::parser",
213
        (Tcl_Namespace*)NULL, TCL_LEAVE_ERR_MSG);
214
 
215
    if (parserNs == NULL) {
216
        char msg[256];
217
        sprintf(msg, "\n    (while parsing class definition for \"%.100s\")",
218
            className);
219
        Tcl_AddErrorInfo(interp, msg);
220
        return TCL_ERROR;
221
    }
222
 
223
    /*
224
     *  Try to create the specified class and its namespace.
225
     */
226
    if (Itcl_CreateClass(interp, className, info, &cdefnPtr) != TCL_OK) {
227
        return TCL_ERROR;
228
    }
229
 
230
    /*
231
     *  Import the built-in commands from the itcl::builtin namespace.
232
     *  Do this before parsing the class definition, so methods/procs
233
     *  can override the built-in commands.
234
     */
235
    result = Tcl_Import(interp, cdefnPtr->namesp, "::itcl::builtin::*",
236
        /* allowOverwrite */ 1);
237
 
238
    if (result != TCL_OK) {
239
        char msg[256];
240
        sprintf(msg, "\n    (while installing built-in commands for class \"%.100s\")", className);
241
        Tcl_AddErrorInfo(interp, msg);
242
 
243
        Tcl_DeleteNamespace(cdefnPtr->namesp);
244
        return TCL_ERROR;
245
    }
246
 
247
    /*
248
     *  Push this class onto the class definition stack so that it
249
     *  becomes the current context for all commands in the parser.
250
     *  Activate the parser and evaluate the class definition.
251
     */
252
    Itcl_PushStack((ClientData)cdefnPtr, &info->cdefnStack);
253
 
254
    result = Tcl_PushCallFrame(interp, &frame, parserNs,
255
        /* isProcCallFrame */ 0);
256
 
257
    if (result == TCL_OK) {
258
      /* CYGNUS LOCAL - Fix for Tcl8.1 */
259
#if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 0
260
      result = Tcl_EvalObj(interp, objv[2]);
261
#else
262
      result = Tcl_EvalObj(interp, objv[2], 0);
263
#endif
264
      /* END CYGNUS LOCAL */
265
      Tcl_PopCallFrame(interp);
266
    }
267
    Itcl_PopStack(&info->cdefnStack);
268
 
269
    if (result != TCL_OK) {
270
        char msg[256];
271
        sprintf(msg, "\n    (class \"%.200s\" body line %d)",
272
            className, interp->errorLine);
273
        Tcl_AddErrorInfo(interp, msg);
274
 
275
        Tcl_DeleteNamespace(cdefnPtr->namesp);
276
        return TCL_ERROR;
277
    }
278
 
279
    /*
280
     *  At this point, parsing of the class definition has succeeded.
281
     *  Add built-in methods such as "configure" and "cget"--as long
282
     *  as they don't conflict with those defined in the class.
283
     */
284
    if (Itcl_InstallBiMethods(interp, cdefnPtr) != TCL_OK) {
285
        Tcl_DeleteNamespace(cdefnPtr->namesp);
286
        return TCL_ERROR;
287
    }
288
 
289
    /*
290
     *  Build the name resolution tables for all data members.
291
     */
292
    Itcl_BuildVirtualTables(cdefnPtr);
293
 
294
    Tcl_ResetResult(interp);
295
    return TCL_OK;
296
}
297
 
298
 
299
/*
300
 * ------------------------------------------------------------------------
301
 *  Itcl_ClassInheritCmd()
302
 *
303
 *  Invoked by Tcl during the parsing of a class definition whenever
304
 *  the "inherit" command is invoked to define one or more base classes.
305
 *  Handles the following syntax:
306
 *
307
 *      inherit <baseclass> ?<baseclass>...?
308
 *
309
 * ------------------------------------------------------------------------
310
 */
311
int
312
Itcl_ClassInheritCmd(clientData, interp, objc, objv)
313
    ClientData clientData;   /* info for all known objects */
314
    Tcl_Interp *interp;      /* current interpreter */
315
    int objc;                /* number of arguments */
316
    Tcl_Obj *CONST objv[];   /* argument objects */
317
{
318
    ItclObjectInfo *info = (ItclObjectInfo*)clientData;
319
    ItclClass *cdefnPtr = (ItclClass*)Itcl_PeekStack(&info->cdefnStack);
320
 
321
    int result, i, newEntry;
322
    char *token;
323
    Itcl_ListElem *elem, *elem2;
324
    ItclClass *cdPtr, *baseCdefnPtr, *badCdPtr;
325
    ItclHierIter hier;
326
    Itcl_Stack stack;
327
    Tcl_CallFrame frame;
328
 
329
    if (objc < 2) {
330
        Tcl_WrongNumArgs(interp, 1, objv, "class ?class...?");
331
        return TCL_ERROR;
332
    }
333
 
334
    /*
335
     *  In "inherit" statement can only be included once in a
336
     *  class definition.
337
     */
338
    elem = Itcl_FirstListElem(&cdefnPtr->bases);
339
    if (elem != NULL) {
340
        Tcl_AppendToObj(Tcl_GetObjResult(interp), "inheritance \"", -1);
341
 
342
        while (elem) {
343
            cdPtr = (ItclClass*)Itcl_GetListValue(elem);
344
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
345
                cdPtr->name, " ", (char*)NULL);
346
 
347
            elem = Itcl_NextListElem(elem);
348
        }
349
 
350
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
351
            "\" already defined for class \"", cdefnPtr->fullname, "\"",
352
            (char*)NULL);
353
        return TCL_ERROR;
354
    }
355
 
356
    /*
357
     *  Validate each base class and add it to the "bases" list.
358
     */
359
    result = Tcl_PushCallFrame(interp, &frame, cdefnPtr->namesp->parentPtr,
360
        /* isProcCallFrame */ 0);
361
 
362
    if (result != TCL_OK) {
363
        return TCL_ERROR;
364
    }
365
 
366
    for (objc--,objv++; objc > 0; objc--,objv++) {
367
 
368
        /*
369
         *  Make sure that the base class name is known in the
370
         *  parent namespace (currently active).  If not, try
371
         *  to autoload its definition.
372
         */
373
        token = Tcl_GetStringFromObj(*objv, (int*)NULL);
374
        baseCdefnPtr = Itcl_FindClass(interp, token, /* autoload */ 1);
375
        if (!baseCdefnPtr) {
376
            Tcl_Obj *resultPtr = Tcl_GetObjResult(interp);
377
            int errlen;
378
            char *errmsg;
379
 
380
            Tcl_IncrRefCount(resultPtr);
381
            errmsg = Tcl_GetStringFromObj(resultPtr, &errlen);
382
 
383
            Tcl_ResetResult(interp);
384
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
385
                "cannot inherit from \"", token, "\"",
386
                (char*)NULL);
387
 
388
            if (errlen > 0) {
389
                Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
390
                    " (", errmsg, ")", (char*)NULL);
391
            }
392
            Tcl_DecrRefCount(resultPtr);
393
            goto inheritError;
394
        }
395
 
396
        /*
397
         *  Make sure that the base class is not the same as the
398
         *  class that is being built.
399
         */
400
        if (baseCdefnPtr == cdefnPtr) {
401
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
402
                "class \"", cdefnPtr->name, "\" cannot inherit from itself",
403
                (char*)NULL);
404
            goto inheritError;
405
        }
406
 
407
        Itcl_AppendList(&cdefnPtr->bases, (ClientData)baseCdefnPtr);
408
        Itcl_PreserveData((ClientData)baseCdefnPtr);
409
    }
410
 
411
    /*
412
     *  Scan through the inheritance list to make sure that no
413
     *  class appears twice.
414
     */
415
    elem = Itcl_FirstListElem(&cdefnPtr->bases);
416
    while (elem) {
417
        elem2 = Itcl_NextListElem(elem);
418
        while (elem2) {
419
            if (Itcl_GetListValue(elem) == Itcl_GetListValue(elem2)) {
420
                cdPtr = (ItclClass*)Itcl_GetListValue(elem);
421
                Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
422
                    "class \"", cdefnPtr->fullname,
423
                    "\" cannot inherit base class \"",
424
                    cdPtr->fullname, "\" more than once",
425
                    (char*)NULL);
426
                goto inheritError;
427
            }
428
            elem2 = Itcl_NextListElem(elem2);
429
        }
430
        elem = Itcl_NextListElem(elem);
431
    }
432
 
433
    /*
434
     *  Add each base class and all of its base classes into
435
     *  the heritage for the current class.  Along the way, make
436
     *  sure that no class appears twice in the heritage.
437
     */
438
    Itcl_InitHierIter(&hier, cdefnPtr);
439
    cdPtr = Itcl_AdvanceHierIter(&hier);  /* skip the class itself */
440
    cdPtr = Itcl_AdvanceHierIter(&hier);
441
    while (cdPtr != NULL) {
442
        (void) Tcl_CreateHashEntry(&cdefnPtr->heritage,
443
            (char*)cdPtr, &newEntry);
444
 
445
        if (!newEntry) {
446
            break;
447
        }
448
        cdPtr = Itcl_AdvanceHierIter(&hier);
449
    }
450
    Itcl_DeleteHierIter(&hier);
451
 
452
    /*
453
     *  Same base class found twice in the hierarchy?
454
     *  Then flag error.  Show the list of multiple paths
455
     *  leading to the same base class.
456
     */
457
    if (!newEntry) {
458
        Tcl_Obj *resultPtr = Tcl_GetObjResult(interp);
459
 
460
        badCdPtr = cdPtr;
461
        Tcl_AppendStringsToObj(resultPtr,
462
            "class \"", cdefnPtr->fullname, "\" inherits base class \"",
463
            badCdPtr->fullname, "\" more than once:",
464
            (char*)NULL);
465
 
466
        cdPtr = cdefnPtr;
467
        Itcl_InitStack(&stack);
468
        Itcl_PushStack((ClientData)cdPtr, &stack);
469
 
470
        /*
471
         *  Show paths leading to bad base class
472
         */
473
        while (Itcl_GetStackSize(&stack) > 0) {
474
            cdPtr = (ItclClass*)Itcl_PopStack(&stack);
475
 
476
            if (cdPtr == badCdPtr) {
477
                Tcl_AppendToObj(resultPtr, "\n  ", -1);
478
                for (i=0; i < Itcl_GetStackSize(&stack); i++) {
479
                    if (Itcl_GetStackValue(&stack, i) == NULL) {
480
                        cdPtr = (ItclClass*)Itcl_GetStackValue(&stack, i-1);
481
                        Tcl_AppendStringsToObj(resultPtr,
482
                            cdPtr->name, "->",
483
                            (char*)NULL);
484
                    }
485
                }
486
                Tcl_AppendToObj(resultPtr, badCdPtr->name, -1);
487
            }
488
            else if (!cdPtr) {
489
                (void)Itcl_PopStack(&stack);
490
            }
491
            else {
492
                elem = Itcl_LastListElem(&cdPtr->bases);
493
                if (elem) {
494
                    Itcl_PushStack((ClientData)cdPtr, &stack);
495
                    Itcl_PushStack((ClientData)NULL, &stack);
496
                    while (elem) {
497
                        Itcl_PushStack(Itcl_GetListValue(elem), &stack);
498
                        elem = Itcl_PrevListElem(elem);
499
                    }
500
                }
501
            }
502
        }
503
        Itcl_DeleteStack(&stack);
504
        goto inheritError;
505
    }
506
 
507
    /*
508
     *  At this point, everything looks good.
509
     *  Finish the installation of the base classes.  Update
510
     *  each base class to recognize the current class as a
511
     *  derived class.
512
     */
513
    elem = Itcl_FirstListElem(&cdefnPtr->bases);
514
    while (elem) {
515
        baseCdefnPtr = (ItclClass*)Itcl_GetListValue(elem);
516
 
517
        Itcl_AppendList(&baseCdefnPtr->derived, (ClientData)cdefnPtr);
518
        Itcl_PreserveData((ClientData)cdefnPtr);
519
 
520
        elem = Itcl_NextListElem(elem);
521
    }
522
 
523
    Tcl_PopCallFrame(interp);
524
    return TCL_OK;
525
 
526
 
527
    /*
528
     *  If the "inherit" list cannot be built properly, tear it
529
     *  down and return an error.
530
     */
531
inheritError:
532
    Tcl_PopCallFrame(interp);
533
 
534
    elem = Itcl_FirstListElem(&cdefnPtr->bases);
535
    while (elem) {
536
        Itcl_ReleaseData( Itcl_GetListValue(elem) );
537
        elem = Itcl_DeleteListElem(elem);
538
    }
539
    return TCL_ERROR;
540
}
541
 
542
 
543
/*
544
 * ------------------------------------------------------------------------
545
 *  Itcl_ClassProtectionCmd()
546
 *
547
 *  Invoked by Tcl whenever the user issues a protection setting
548
 *  command like "public" or "private".  Creates commands and
549
 *  variables, and assigns a protection level to them.  Protection
550
 *  levels are defined as follows:
551
 *
552
 *    public    => accessible from any namespace
553
 *    protected => accessible from selected namespaces
554
 *    private   => accessible only in the namespace where it was defined
555
 *
556
 *  Handles the following syntax:
557
 *
558
 *    public <command> ?<arg> <arg>...?
559
 *
560
 *  Returns TCL_OK/TCL_ERROR to indicate success/failure.
561
 * ------------------------------------------------------------------------
562
 */
563
int
564
Itcl_ClassProtectionCmd(clientData, interp, objc, objv)
565
    ClientData clientData;   /* protection level (public/protected/private) */
566
    Tcl_Interp *interp;      /* current interpreter */
567
    int objc;                /* number of arguments */
568
    Tcl_Obj *CONST objv[];   /* argument objects */
569
{
570
    ProtectionCmdInfo *pInfo = (ProtectionCmdInfo*)clientData;
571
 
572
    int result;
573
    int oldLevel;
574
 
575
    if (objc < 2) {
576
        Tcl_WrongNumArgs(interp, 1, objv, "command ?arg arg...?");
577
        return TCL_ERROR;
578
    }
579
 
580
    oldLevel = Itcl_Protection(interp, pInfo->pLevel);
581
 
582
    if (objc == 2) {
583
      /* CYGNUS LOCAL - Fix for Tcl8.1 */
584
#if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 0
585
      result = Tcl_EvalObj(interp, objv[1]);
586
#else
587
      result = Tcl_EvalObj(interp, objv[1], 0);
588
#endif
589
      /* END CYGNUS LOCAL */
590
    } else {
591
        result = Itcl_EvalArgs(interp, objc-1, objv+1);
592
    }
593
 
594
    if (result == TCL_BREAK) {
595
        Tcl_SetResult(interp, "invoked \"break\" outside of a loop",
596
            TCL_STATIC);
597
        result = TCL_ERROR;
598
    }
599
    else if (result == TCL_CONTINUE) {
600
        Tcl_SetResult(interp, "invoked \"continue\" outside of a loop",
601
            TCL_STATIC);
602
        result = TCL_ERROR;
603
    }
604
    else if (result != TCL_OK) {
605
        char mesg[256], *token;
606
        token = Tcl_GetStringFromObj(objv[0], (int*)NULL);
607
        sprintf(mesg, "\n    (%.100s body line %d)", token, interp->errorLine);
608
        Tcl_AddErrorInfo(interp, mesg);
609
    }
610
 
611
    Itcl_Protection(interp, oldLevel);
612
    return result;
613
}
614
 
615
 
616
/*
617
 * ------------------------------------------------------------------------
618
 *  Itcl_ClassConstructorCmd()
619
 *
620
 *  Invoked by Tcl during the parsing of a class definition whenever
621
 *  the "constructor" command is invoked to define the constructor
622
 *  for an object.  Handles the following syntax:
623
 *
624
 *      constructor <arglist> ?<init>? <body>
625
 *
626
 * ------------------------------------------------------------------------
627
 */
628
int
629
Itcl_ClassConstructorCmd(clientData, interp, objc, objv)
630
    ClientData clientData;   /* info for all known objects */
631
    Tcl_Interp *interp;      /* current interpreter */
632
    int objc;                /* number of arguments */
633
    Tcl_Obj *CONST objv[];   /* argument objects */
634
{
635
    ItclObjectInfo *info = (ItclObjectInfo*)clientData;
636
    ItclClass *cdefnPtr = (ItclClass*)Itcl_PeekStack(&info->cdefnStack);
637
 
638
    char *name, *arglist, *body;
639
 
640
    if (objc < 3 || objc > 4) {
641
        Tcl_WrongNumArgs(interp, 1, objv, "args ?init? body");
642
        return TCL_ERROR;
643
    }
644
 
645
    name = Tcl_GetStringFromObj(objv[0], (int*)NULL);
646
    if (Tcl_FindHashEntry(&cdefnPtr->functions, name)) {
647
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
648
            "\"", name, "\" already defined in class \"",
649
            cdefnPtr->fullname, "\"",
650
            (char*)NULL);
651
        return TCL_ERROR;
652
    }
653
 
654
    /*
655
     *  If there is an object initialization statement, pick this
656
     *  out and take the last argument as the constructor body.
657
     */
658
    arglist = Tcl_GetStringFromObj(objv[1], (int*)NULL);
659
    if (objc == 3) {
660
        body = Tcl_GetStringFromObj(objv[2], (int*)NULL);
661
    } else {
662
        cdefnPtr->initCode = objv[2];
663
        Tcl_IncrRefCount(cdefnPtr->initCode);
664
        body = Tcl_GetStringFromObj(objv[3], (int*)NULL);
665
    }
666
 
667
    if (Itcl_CreateMethod(interp, cdefnPtr, name, arglist, body) != TCL_OK) {
668
        return TCL_ERROR;
669
    }
670
    return TCL_OK;
671
}
672
 
673
 
674
/*
675
 * ------------------------------------------------------------------------
676
 *  Itcl_ClassDestructorCmd()
677
 *
678
 *  Invoked by Tcl during the parsing of a class definition whenever
679
 *  the "destructor" command is invoked to define the destructor
680
 *  for an object.  Handles the following syntax:
681
 *
682
 *      destructor <body>
683
 *
684
 * ------------------------------------------------------------------------
685
 */
686
int
687
Itcl_ClassDestructorCmd(clientData, interp, objc, objv)
688
    ClientData clientData;   /* info for all known objects */
689
    Tcl_Interp *interp;      /* current interpreter */
690
    int objc;                /* number of arguments */
691
    Tcl_Obj *CONST objv[];   /* argument objects */
692
{
693
    ItclObjectInfo *info = (ItclObjectInfo*)clientData;
694
    ItclClass *cdefnPtr = (ItclClass*)Itcl_PeekStack(&info->cdefnStack);
695
 
696
    char *name, *body;
697
 
698
    if (objc != 2) {
699
        Tcl_WrongNumArgs(interp, 1, objv, "body");
700
        return TCL_ERROR;
701
    }
702
 
703
    name = Tcl_GetStringFromObj(objv[0], (int*)NULL);
704
    body = Tcl_GetStringFromObj(objv[1], (int*)NULL);
705
 
706
    if (Tcl_FindHashEntry(&cdefnPtr->functions, name)) {
707
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
708
            "\"", name, "\" already defined in class \"",
709
            cdefnPtr->fullname, "\"",
710
            (char*)NULL);
711
        return TCL_ERROR;
712
    }
713
 
714
    if (Itcl_CreateMethod(interp, cdefnPtr, name, (char*)NULL, body)
715
        != TCL_OK) {
716
        return TCL_ERROR;
717
    }
718
    return TCL_OK;
719
}
720
 
721
/*
722
 * ------------------------------------------------------------------------
723
 *  Itcl_ClassMethodCmd()
724
 *
725
 *  Invoked by Tcl during the parsing of a class definition whenever
726
 *  the "method" command is invoked to define an object method.
727
 *  Handles the following syntax:
728
 *
729
 *      method <name> ?<arglist>? ?<body>?
730
 *
731
 * ------------------------------------------------------------------------
732
 */
733
int
734
Itcl_ClassMethodCmd(clientData, interp, objc, objv)
735
    ClientData clientData;   /* info for all known objects */
736
    Tcl_Interp *interp;      /* current interpreter */
737
    int objc;                /* number of arguments */
738
    Tcl_Obj *CONST objv[];   /* argument objects */
739
{
740
    ItclObjectInfo *info = (ItclObjectInfo*)clientData;
741
    ItclClass *cdefnPtr = (ItclClass*)Itcl_PeekStack(&info->cdefnStack);
742
 
743
    char *name, *arglist, *body;
744
 
745
    if (objc < 2 || objc > 4) {
746
        Tcl_WrongNumArgs(interp, 1, objv, "name ?args? ?body?");
747
        return TCL_ERROR;
748
    }
749
 
750
    name = Tcl_GetStringFromObj(objv[1], (int*)NULL);
751
 
752
    arglist = NULL;
753
    body = NULL;
754
    if (objc >= 3) {
755
        arglist = Tcl_GetStringFromObj(objv[2], (int*)NULL);
756
    }
757
    if (objc >= 4) {
758
        body = Tcl_GetStringFromObj(objv[3], (int*)NULL);
759
    }
760
 
761
    if (Itcl_CreateMethod(interp, cdefnPtr, name, arglist, body) != TCL_OK) {
762
        return TCL_ERROR;
763
    }
764
    return TCL_OK;
765
}
766
 
767
 
768
/*
769
 * ------------------------------------------------------------------------
770
 *  Itcl_ClassProcCmd()
771
 *
772
 *  Invoked by Tcl during the parsing of a class definition whenever
773
 *  the "proc" command is invoked to define a common class proc.
774
 *  A "proc" is like a "method", but only has access to "common"
775
 *  class variables.  Handles the following syntax:
776
 *
777
 *      proc <name> ?<arglist>? ?<body>?
778
 *
779
 * ------------------------------------------------------------------------
780
 */
781
int
782
Itcl_ClassProcCmd(clientData, interp, objc, objv)
783
    ClientData clientData;   /* info for all known objects */
784
    Tcl_Interp *interp;      /* current interpreter */
785
    int objc;                /* number of arguments */
786
    Tcl_Obj *CONST objv[];   /* argument objects */
787
{
788
    ItclObjectInfo *info = (ItclObjectInfo*)clientData;
789
    ItclClass *cdefnPtr = (ItclClass*)Itcl_PeekStack(&info->cdefnStack);
790
    char *name, *arglist, *body;
791
 
792
    if (objc < 2 || objc > 4) {
793
        Tcl_WrongNumArgs(interp, 1, objv, "name ?args? ?body?");
794
        return TCL_ERROR;
795
    }
796
 
797
    name = Tcl_GetStringFromObj(objv[1], (int*)NULL);
798
 
799
    arglist = NULL;
800
    body = NULL;
801
    if (objc >= 3) {
802
        arglist = Tcl_GetStringFromObj(objv[2], (int*)NULL);
803
    }
804
    if (objc >= 4) {
805
        body = Tcl_GetStringFromObj(objv[3], (int*)NULL);
806
    }
807
 
808
    if (Itcl_CreateProc(interp, cdefnPtr, name, arglist, body) != TCL_OK) {
809
        return TCL_ERROR;
810
    }
811
    return TCL_OK;
812
}
813
 
814
 
815
/*
816
 * ------------------------------------------------------------------------
817
 *  Itcl_ClassVariableCmd()
818
 *
819
 *  Invoked by Tcl during the parsing of a class definition whenever
820
 *  the "variable" command is invoked to define an instance variable.
821
 *  Handles the following syntax:
822
 *
823
 *      variable <varname> ?<init>? ?<config>?
824
 *
825
 * ------------------------------------------------------------------------
826
 */
827
int
828
Itcl_ClassVariableCmd(clientData, interp, objc, objv)
829
    ClientData clientData;   /* info for all known objects */
830
    Tcl_Interp *interp;      /* current interpreter */
831
    int objc;                /* number of arguments */
832
    Tcl_Obj *CONST objv[];   /* argument objects */
833
{
834
    ItclObjectInfo *info = (ItclObjectInfo*)clientData;
835
    ItclClass *cdefnPtr = (ItclClass*)Itcl_PeekStack(&info->cdefnStack);
836
 
837
    int pLevel;
838
    ItclVarDefn *vdefn;
839
    char *name, *init, *config;
840
 
841
    pLevel = Itcl_Protection(interp, 0);
842
 
843
    if (pLevel == ITCL_PUBLIC) {
844
        if (objc < 2 || objc > 4) {
845
            Tcl_WrongNumArgs(interp, 1, objv, "name ?init? ?config?");
846
            return TCL_ERROR;
847
        }
848
    }
849
    else if ((objc < 2) || (objc > 3)) {
850
        Tcl_WrongNumArgs(interp, 1, objv, "name ?init?");
851
        return TCL_ERROR;
852
    }
853
 
854
    /*
855
     *  Make sure that the variable name does not contain anything
856
     *  goofy like a "::" scope qualifier.
857
     */
858
    name = Tcl_GetStringFromObj(objv[1], (int*)NULL);
859
    if (strstr(name, "::")) {
860
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
861
            "bad variable name \"", name, "\"",
862
            (char*)NULL);
863
        return TCL_ERROR;
864
    }
865
 
866
    init   = NULL;
867
    config = NULL;
868
    if (objc >= 3) {
869
        init = Tcl_GetStringFromObj(objv[2], (int*)NULL);
870
    }
871
    if (objc >= 4) {
872
        config = Tcl_GetStringFromObj(objv[3], (int*)NULL);
873
    }
874
 
875
    if (Itcl_CreateVarDefn(interp, cdefnPtr, name, init, config,
876
        &vdefn) != TCL_OK) {
877
 
878
        return TCL_ERROR;
879
    }
880
 
881
    return TCL_OK;
882
}
883
 
884
 
885
/*
886
 * ------------------------------------------------------------------------
887
 *  Itcl_ClassCommonCmd()
888
 *
889
 *  Invoked by Tcl during the parsing of a class definition whenever
890
 *  the "common" command is invoked to define a variable that is
891
 *  common to all objects in the class.  Handles the following syntax:
892
 *
893
 *      common <varname> ?<init>?
894
 *
895
 * ------------------------------------------------------------------------
896
 */
897
int
898
Itcl_ClassCommonCmd(clientData, interp, objc, objv)
899
    ClientData clientData;   /* info for all known objects */
900
    Tcl_Interp *interp;      /* current interpreter */
901
    int objc;                /* number of arguments */
902
    Tcl_Obj *CONST objv[];   /* argument objects */
903
{
904
    ItclObjectInfo *info = (ItclObjectInfo*)clientData;
905
    ItclClass *cdefnPtr = (ItclClass*)Itcl_PeekStack(&info->cdefnStack);
906
 
907
    int newEntry;
908
    char *name, *init;
909
    ItclVarDefn *vdefn;
910
    Tcl_HashEntry *entry;
911
    Namespace *nsPtr;
912
    Var *varPtr;
913
 
914
    if ((objc < 2) || (objc > 3)) {
915
        Tcl_WrongNumArgs(interp, 1, objv, "varname ?init?");
916
        return TCL_ERROR;
917
    }
918
 
919
    /*
920
     *  Make sure that the variable name does not contain anything
921
     *  goofy like a "::" scope qualifier.
922
     */
923
    name = Tcl_GetStringFromObj(objv[1], (int*)NULL);
924
    if (strstr(name, "::")) {
925
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
926
            "bad variable name \"", name, "\"",
927
            (char*)NULL);
928
        return TCL_ERROR;
929
    }
930
 
931
    init = NULL;
932
    if (objc >= 3) {
933
        init = Tcl_GetStringFromObj(objv[2], (int*)NULL);
934
    }
935
 
936
    if (Itcl_CreateVarDefn(interp, cdefnPtr, name, init, (char*)NULL,
937
        &vdefn) != TCL_OK) {
938
 
939
        return TCL_ERROR;
940
    }
941
    vdefn->member->flags |= ITCL_COMMON;
942
 
943
    /*
944
     *  Create the variable in the namespace associated with the
945
     *  class.  Do this the hard way, to avoid the variable resolver
946
     *  procedures.  These procedures won't work until we rebuild
947
     *  the virtual tables below.
948
     */
949
    nsPtr = (Namespace*)cdefnPtr->namesp;
950
    entry = Tcl_CreateHashEntry(&nsPtr->varTable,
951
        vdefn->member->name, &newEntry);
952
 
953
    varPtr = _TclNewVar();
954
    varPtr->hPtr = entry;
955
    varPtr->nsPtr = nsPtr;
956
    varPtr->flags |= VAR_NAMESPACE_VAR;
957
    varPtr->refCount++;    /* one use by namespace */
958
    varPtr->refCount++;    /* another use by class */
959
 
960
    Tcl_SetHashValue(entry, varPtr);
961
 
962
    /*
963
     *  TRICKY NOTE:  Make sure to rebuild the virtual tables for this
964
     *    class so that this variable is ready to access.  The variable
965
     *    resolver for the parser namespace needs this info to find the
966
     *    variable if the developer tries to set it within the class
967
     *    definition.
968
     *
969
     *  If an initialization value was specified, then initialize
970
     *  the variable now.
971
     */
972
    Itcl_BuildVirtualTables(cdefnPtr);
973
 
974
    if (init) {
975
        init = Tcl_SetVar(interp, vdefn->member->name, init,
976
            TCL_NAMESPACE_ONLY);
977
 
978
        if (!init) {
979
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
980
                "cannot initialize common variable \"",
981
                vdefn->member->name, "\"",
982
                (char*)NULL);
983
            return TCL_ERROR;
984
        }
985
    }
986
    return TCL_OK;
987
}
988
 
989
 
990
/*
991
 * ------------------------------------------------------------------------
992
 *  Itcl_ParseVarResolver()
993
 *
994
 *  Used by the "parser" namespace to resolve variable accesses to
995
 *  common variables.  The runtime resolver procedure is consulted
996
 *  whenever a variable is accessed within the namespace.  It can
997
 *  deny access to certain variables, or perform special lookups itself.
998
 *
999
 *  This procedure allows access only to "common" class variables that
1000
 *  have been declared within the class or inherited from another class.
1001
 *  A "set" command can be used to initialized common data members within
1002
 *  the body of the class definition itself:
1003
 *
1004
 *    itcl::class Foo {
1005
 *        common colors
1006
 *        set colors(red)   #ff0000
1007
 *        set colors(green) #00ff00
1008
 *        set colors(blue)  #0000ff
1009
 *        ...
1010
 *    }
1011
 *
1012
 *    itcl::class Bar {
1013
 *        inherit Foo
1014
 *        set colors(gray)  #a0a0a0
1015
 *        set colors(white) #ffffff
1016
 *
1017
 *        common numbers
1018
 *        set numbers(0) zero
1019
 *        set numbers(1) one
1020
 *    }
1021
 *
1022
 * ------------------------------------------------------------------------
1023
 */
1024
/* ARGSUSED */
1025
int
1026
Itcl_ParseVarResolver(interp, name, contextNs, flags, rPtr)
1027
    Tcl_Interp *interp;        /* current interpreter */
1028
    char* name;                /* name of the variable being accessed */
1029
    Tcl_Namespace *contextNs;  /* namespace context */
1030
    int flags;                 /* TCL_GLOBAL_ONLY => global variable
1031
                                * TCL_NAMESPACE_ONLY => namespace variable */
1032
    Tcl_Var* rPtr;             /* returns: Tcl_Var for desired variable */
1033
{
1034
    ItclObjectInfo *info = (ItclObjectInfo*)contextNs->clientData;
1035
    ItclClass *cdefnPtr = (ItclClass*)Itcl_PeekStack(&info->cdefnStack);
1036
 
1037
    Tcl_HashEntry *entry;
1038
    ItclVarLookup *vlookup;
1039
 
1040
    /*
1041
     *  See if the requested variable is a recognized "common" member.
1042
     *  If it is, make sure that access is allowed.
1043
     */
1044
    entry = Tcl_FindHashEntry(&cdefnPtr->resolveVars, name);
1045
    if (entry) {
1046
        vlookup = (ItclVarLookup*)Tcl_GetHashValue(entry);
1047
 
1048
        if ((vlookup->vdefn->member->flags & ITCL_COMMON) != 0) {
1049
            if (!vlookup->accessible) {
1050
                Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1051
                    "can't access \"", name, "\": ",
1052
                    Itcl_ProtectionStr(vlookup->vdefn->member->protection),
1053
                    " variable",
1054
                    (char*)NULL);
1055
                return TCL_ERROR;
1056
            }
1057
            *rPtr = vlookup->var.common;
1058
            return TCL_OK;
1059
        }
1060
    }
1061
 
1062
    /*
1063
     *  If the variable is not recognized, return TCL_CONTINUE and
1064
     *  let lookup continue via the normal name resolution rules.
1065
     *  This is important for variables like "errorInfo"
1066
     *  that might get set while the parser namespace is active.
1067
     */
1068
    return TCL_CONTINUE;
1069
}
1070
 
1071
/*
1072
 * ------------------------------------------------------------------------
1073
 *  ItclFreeParserCommandData()
1074
 *
1075
 *  This callback will free() up memory dynamically allocated
1076
 *  and passed as the ClientData argument to Tcl_CreateObjCommand.
1077
 *  This callback is required because one can not simply pass
1078
 *  a pointer to the free() or ckfree() to Tcl_CreateObjCommand.
1079
 * ------------------------------------------------------------------------
1080
 */
1081
static void
1082
ItclFreeParserCommandData(cdata)
1083
    char* cdata;  /* client data to be destroyed */
1084
{
1085
    ckfree(cdata);
1086
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.