~ubuntu-branches/ubuntu/intrepid/ecl/intrepid

« back to all changes in this revision

Viewing changes to src/c/package.d

  • Committer: Bazaar Package Importer
  • Author(s): Peter Van Eynde
  • Date: 2006-05-17 02:46:26 UTC
  • Revision ID: james.westby@ubuntu.com-20060517024626-lljr08ftv9g9vefl
Tags: upstream-0.9h-20060510
ImportĀ upstreamĀ versionĀ 0.9h-20060510

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    package.d -- Packages.
 
3
*/
 
4
/*
 
5
    Copyright (c) 1984, Taiichi Yuasa and Masami Hagiya.
 
6
    Copyright (c) 1990, Giuseppe Attardi.
 
7
    Copyright (c) 2001, Juan Jose Garcia Ripoll.
 
8
 
 
9
    ECL is free software; you can redistribute it and/or
 
10
    modify it under the terms of the GNU Library General Public
 
11
    License as published by the Free Software Foundation; either
 
12
    version 2 of the License, or (at your option) any later version.
 
13
 
 
14
    See file '../Copyright' for full details.
 
15
*/
 
16
 
 
17
#include <ecl/ecl.h>
 
18
#include <ecl/internal.h>
 
19
 
 
20
/******************************* ------- ******************************/
 
21
/*
 
22
 * NOTE 1: we only need to use the package locks when reading/writing the hash
 
23
 * tables, or changing the fields of a package.  We do not need the locks to
 
24
 * read lists from the packages (i.e. list of shadowing symbols, used
 
25
 * packages, etc), or from the global environment (cl_core.packages_list) if
 
26
 * we do not destructively modify them (For instance, use ecl_remove_eq
 
27
 * instead of ecl_delete_eq).
 
28
 */
 
29
/*
 
30
 * NOTE 2: Operations between locks must be guaranteed not fail, or, if
 
31
 * they signal an error, they should undo all locks they had before.
 
32
 */
 
33
 
 
34
#define INTERNAL        1
 
35
#define EXTERNAL        2
 
36
#define INHERITED       3
 
37
 
 
38
static void
 
39
FEpackage_error(const char *message, cl_object package, int narg, ...)
 
40
{
 
41
        cl_va_list args;
 
42
        cl_va_start(args, narg, narg, 0);
 
43
        si_signal_simple_error(6,
 
44
                               @'package-error',
 
45
                               Cnil, /* not correctable */
 
46
                               make_constant_string(message), /* format control */
 
47
                               narg? cl_grab_rest_args(args) : cl_list(1,package), /* format args */
 
48
                               @':package', package); /* extra arguments */
 
49
}
 
50
 
 
51
void
 
52
CEpackage_error(const char *message, const char *continue_message, cl_object package, int narg, ...)
 
53
{
 
54
        cl_va_list args;
 
55
        cl_va_start(args, narg, narg, 0);
 
56
        si_signal_simple_error(6,
 
57
                               @'package-error',
 
58
                               make_constant_string(continue_message),
 
59
                               make_constant_string(message), /* format control */
 
60
                               narg? cl_grab_rest_args(args) : cl_list(1,package),
 
61
                               @':package', package);
 
62
}
 
63
 
 
64
static bool
 
65
member_string_eq(cl_object x, cl_object l)
 
66
{
 
67
        /* INV: l is a proper list */
 
68
        for (;  CONSP(l);  l = CDR(l))
 
69
                if (string_eq(x, CAR(l)))
 
70
                        return(TRUE);
 
71
        return(FALSE);
 
72
}
 
73
 
 
74
/*
 
75
        Make_package(n, ns, ul) makes a package with name n,
 
76
        which must be a string or a symbol,
 
77
        and nicknames ns, which must be a list of strings or symbols,
 
78
        and uses packages in list ul, which must be a list of packages
 
79
        or package names i.e. strings or symbols.
 
80
*/
 
81
static cl_object
 
82
make_package_hashtable()
 
83
{
 
84
        cl_object h;
 
85
        cl_index hsize = 128;
 
86
 
 
87
        h = cl_alloc_object(t_hashtable);
 
88
        h->hash.lockable = 0;
 
89
        h->hash.test = htt_pack;
 
90
        h->hash.size = hsize;
 
91
        h->hash.rehash_size = make_shortfloat(1.5f);
 
92
        h->hash.threshold = make_shortfloat(0.75f);
 
93
        h->hash.factor = 0.7;
 
94
        h->hash.entries = 0;
 
95
        h->hash.data = NULL; /* for GC sake */
 
96
        h->hash.data = (struct ecl_hashtable_entry *)cl_alloc(hsize * sizeof(struct ecl_hashtable_entry));
 
97
        return cl_clrhash(h);
 
98
}
 
99
 
 
100
cl_object
 
101
make_package(cl_object name, cl_object nicknames, cl_object use_list)
 
102
{
 
103
        cl_object x, y, other;
 
104
 
 
105
        name = cl_string(name);
 
106
        assert_type_proper_list(nicknames);
 
107
        assert_type_proper_list(use_list);
 
108
 
 
109
        /* 1) Find a similarly named package in the list of packages to be
 
110
         *    created and use it.
 
111
         */
 
112
        PACKAGE_OP_LOCK();
 
113
        if (cl_core.packages_to_be_created != OBJNULL) {
 
114
                cl_object *p = &cl_core.packages_to_be_created;
 
115
                for (x = *p; x != Cnil; ) {
 
116
                        if (equal(CAAR(x), name)) {
 
117
                                *p = CDR(x);
 
118
                                x = CDAR(x);
 
119
                                goto INTERN;
 
120
                        }
 
121
                        /* FIXME! We should also check the nicknames */
 
122
                        p = &CDR(x);
 
123
                        x = *p;
 
124
                }
 
125
        }
 
126
 
 
127
        /* 2) Otherwise, try to build a new package */
 
128
        if ((other = ecl_find_package_nolock(name)) != Cnil) {
 
129
        ERROR:  PACKAGE_OP_UNLOCK();
 
130
                CEpackage_error("A package with the name ~A already exists.",
 
131
                                "Return existing package",
 
132
                                other, 1, name);
 
133
                return other;
 
134
        }
 
135
        x = cl_alloc_object(t_package);
 
136
        x->pack.internal = make_package_hashtable();
 
137
        x->pack.external = make_package_hashtable();
 
138
        x->pack.name = name;
 
139
#ifdef ECL_THREADS
 
140
#if defined(_MSC_VER) || defined(mingw32)
 
141
        x->pack.lock = CreateMutex(NULL, FALSE, NULL);
 
142
#else
 
143
        {
 
144
        pthread_mutexattr_t attr;
 
145
        pthread_mutexattr_init(&attr);
 
146
        pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
 
147
        pthread_mutex_init(&x->pack.lock, &attr);
 
148
        pthread_mutexattr_destroy(&attr);
 
149
        }
 
150
#endif /* _MSC_VER */
 
151
#endif
 
152
 INTERN:
 
153
        x->pack.nicknames = Cnil;
 
154
        x->pack.shadowings = Cnil;
 
155
        x->pack.uses = Cnil;
 
156
        x->pack.usedby = Cnil;
 
157
        x->pack.locked = FALSE;
 
158
        for (;  !endp(nicknames);  nicknames = CDR(nicknames)) {
 
159
                cl_object nick = cl_string(CAR(nicknames));
 
160
                if ((other = ecl_find_package_nolock(nick)) != Cnil) {
 
161
                        name = nick;
 
162
                        goto ERROR;
 
163
                }
 
164
                x->pack.nicknames = CONS(nick, x->pack.nicknames);
 
165
        }
 
166
        for (;  !endp(use_list);  use_list = CDR(use_list)) {
 
167
                y = si_coerce_to_package(CAR(use_list));
 
168
                x->pack.uses = CONS(y, x->pack.uses);
 
169
                y->pack.usedby = CONS(x, y->pack.usedby);
 
170
        }
 
171
 
 
172
        /* 3) Finally, add it to the list of packages */
 
173
        cl_core.packages = CONS(x, cl_core.packages);
 
174
        PACKAGE_OP_UNLOCK();
 
175
        return(x);
 
176
}
 
177
 
 
178
cl_object
 
179
rename_package(cl_object x, cl_object name, cl_object nicknames)
 
180
{
 
181
        cl_object y;
 
182
 
 
183
        name = cl_string(name);
 
184
        x = si_coerce_to_package(x);
 
185
        if (x->pack.locked)
 
186
                CEpackage_error("Cannot rename locked package ~S.",
 
187
                                "Ignore lock and proceed", x, 0);
 
188
 
 
189
        PACKAGE_OP_LOCK();
 
190
        y = ecl_find_package_nolock(name);
 
191
        if ((y != Cnil) && (y != x)) {
 
192
        ERROR:  PACKAGE_OP_UNLOCK();
 
193
                FEpackage_error("A package with name ~S already exists.", x,
 
194
                                1, name);
 
195
        }
 
196
 
 
197
        x->pack.name = name;
 
198
        x->pack.nicknames = Cnil;
 
199
        assert_type_proper_list(nicknames);
 
200
        for (;  !endp(nicknames);  nicknames = CDR(nicknames)) {
 
201
                cl_object nick = CAR(nicknames);
 
202
                y = ecl_find_package_nolock(nick);
 
203
                if (x == y)
 
204
                        continue;
 
205
                if (y != Cnil) {
 
206
                        name = nick;
 
207
                        goto ERROR;
 
208
                }
 
209
                x->pack.nicknames = CONS(cl_string(nick), x->pack.nicknames);
 
210
        }
 
211
        PACKAGE_OP_UNLOCK();
 
212
        return(x);
 
213
}
 
214
 
 
215
/*
 
216
        ecl_find_package_nolock(n) seaches for a package with name n, where n is
 
217
        a valid string designator, or simply outputs n if it is a
 
218
        package.
 
219
 
 
220
        This is not a locking routine and someone may replace the list of
 
221
        packages while we are scanning it. Nevertheless, the list IS NOT
 
222
        be destructively modified, which means that we are on the safe side.
 
223
        Routines which need to ensure that the package list remains constant
 
224
        should enforce a global lock with PACKAGE_OP_LOCK().
 
225
*/
 
226
cl_object
 
227
ecl_find_package_nolock(cl_object name)
 
228
{
 
229
        cl_object l, p;
 
230
 
 
231
        if (type_of(name) == t_package)
 
232
                return name;
 
233
        name = cl_string(name);
 
234
        /* INV: cl_core.packages is a proper list */
 
235
        for (l = cl_core.packages; CONSP(l); l = CDR(l)) {
 
236
                p = CAR(l);
 
237
                if (string_eq(name, p->pack.name))
 
238
                        return p;
 
239
                if (member_string_eq(name, p->pack.nicknames))
 
240
                        return p;
 
241
        }
 
242
        return Cnil;
 
243
}
 
244
 
 
245
cl_object
 
246
si_coerce_to_package(cl_object p)
 
247
{
 
248
        /* INV: ecl_find_package_nolock() signals an error if "p" is neither a package
 
249
           nor a string */
 
250
        cl_object pp = ecl_find_package_nolock(p);
 
251
        if (Null(pp)) {
 
252
                FEpackage_error("There exists no package with name ~S", p, 0);
 
253
        }
 
254
        @(return pp);
 
255
}
 
256
 
 
257
cl_object
 
258
current_package(void)
 
259
{
 
260
        cl_object x;
 
261
 
 
262
        x = symbol_value(@'*package*');
 
263
        if (type_of(x) != t_package) {
 
264
                ECL_SETQ(@'*package*', cl_core.user_package);
 
265
                FEerror("The value of *PACKAGE*, ~S, was not a package",
 
266
                        1, x);
 
267
        }
 
268
        return(x);
 
269
}
 
270
 
 
271
/*
 
272
        Intern(st, p) interns string st in package p.
 
273
*/
 
274
cl_object
 
275
_intern(const char *s, cl_object p)
 
276
{
 
277
        int intern_flag;
 
278
        cl_object str = make_constant_string(s);
 
279
        return intern(str, p, &intern_flag);
 
280
}
 
281
 
 
282
cl_object
 
283
intern(cl_object name, cl_object p, int *intern_flag)
 
284
{
 
285
        cl_object s, ul;
 
286
 
 
287
        assert_type_string(name);
 
288
        p = si_coerce_to_package(p);
 
289
 TRY_AGAIN_LABEL:
 
290
        PACKAGE_LOCK(p);
 
291
        s = gethash_safe(name, p->pack.external, OBJNULL);
 
292
        if (s != OBJNULL) {
 
293
                *intern_flag = EXTERNAL;
 
294
                goto OUTPUT;
 
295
        }
 
296
        /* Keyword package has no intern section nor can it be used */
 
297
        if (p == cl_core.keyword_package) goto INTERN;
 
298
        s = gethash_safe(name, p->pack.internal, OBJNULL);
 
299
        if (s != OBJNULL) {
 
300
                *intern_flag = INTERNAL;
 
301
                goto OUTPUT;
 
302
        }
 
303
        for (ul=p->pack.uses; CONSP(ul); ul = CDR(ul)) {
 
304
                s = gethash_safe(name, CAR(ul)->pack.external, OBJNULL);
 
305
                if (s != OBJNULL) {
 
306
                        *intern_flag = INHERITED;
 
307
                        goto OUTPUT;
 
308
                }
 
309
        }
 
310
 INTERN:
 
311
        if (p->pack.locked) {
 
312
                PACKAGE_UNLOCK(p);
 
313
                CEpackage_error("Cannot intern symbol ~S in locked package ~S.",
 
314
                                "Ignore lock and proceed", p, 2, name, p);
 
315
                goto TRY_AGAIN_LABEL;
 
316
        }
 
317
        s = make_symbol(name);
 
318
        s->symbol.hpack = p;
 
319
        *intern_flag = 0;
 
320
        if (p == cl_core.keyword_package) {
 
321
                s->symbol.stype = stp_constant;
 
322
                ECL_SET(s, s);
 
323
                sethash(name, p->pack.external, s);
 
324
        } else {
 
325
                sethash(name, p->pack.internal, s);
 
326
        }
 
327
 OUTPUT:
 
328
        PACKAGE_UNLOCK(p);
 
329
        return s;
 
330
}
 
331
 
 
332
/*
 
333
        ecl_find_symbol_nolock(st, len, p) searches for string st of length
 
334
        len in package p.
 
335
*/
 
336
cl_object
 
337
ecl_find_symbol_nolock(cl_object name, cl_object p, int *intern_flag)
 
338
{
 
339
        cl_object s, ul;
 
340
 
 
341
        assert_type_string(name);
 
342
        s = gethash_safe(name, p->pack.external, OBJNULL);
 
343
        if (s != OBJNULL) {
 
344
                *intern_flag = EXTERNAL;
 
345
                goto OUTPUT;
 
346
        }
 
347
        if (p == cl_core.keyword_package)
 
348
                goto NOTHING;
 
349
        s = gethash_safe(name, p->pack.internal, OBJNULL);
 
350
        if (s != OBJNULL) {
 
351
                *intern_flag = INTERNAL;
 
352
                goto OUTPUT;
 
353
        }
 
354
        for (ul=p->pack.uses; CONSP(ul); ul = CDR(ul)) {
 
355
                s = gethash_safe(name, CAR(ul)->pack.external, OBJNULL);
 
356
                if (s != OBJNULL) {
 
357
                        *intern_flag = INHERITED;
 
358
                        goto OUTPUT;
 
359
                }
 
360
        }
 
361
 NOTHING:
 
362
        *intern_flag = 0;
 
363
        s = Cnil;
 
364
 OUTPUT:
 
365
        return s;
 
366
}
 
367
 
 
368
cl_object
 
369
ecl_find_symbol(cl_object n, cl_object p, int *intern_flag)
 
370
{
 
371
        n = cl_string(n);
 
372
        p = si_coerce_to_package(p);
 
373
        PACKAGE_LOCK(p);
 
374
        n = ecl_find_symbol_nolock(n, p, intern_flag);
 
375
        PACKAGE_UNLOCK(p);
 
376
        return n;
 
377
}
 
378
 
 
379
bool
 
380
unintern(cl_object s, cl_object p)
 
381
{
 
382
        cl_object x, y, l, hash;
 
383
        bool output = FALSE;
 
384
 
 
385
        assert_type_symbol(s);
 
386
        p = si_coerce_to_package(p);
 
387
 
 
388
 TRY_AGAIN_LABEL:
 
389
        PACKAGE_LOCK(p);
 
390
        hash = p->pack.internal;
 
391
        x = gethash_safe(s->symbol.name, hash, OBJNULL);
 
392
        if (x == s)
 
393
                goto UNINTERN;
 
394
        hash = p->pack.external;
 
395
        x = gethash_safe(s->symbol.name, hash, OBJNULL);
 
396
        if (x != s)
 
397
                goto OUTPUT;
 
398
 UNINTERN:
 
399
        if (p->pack.locked) {
 
400
                PACKAGE_UNLOCK(p);
 
401
                CEpackage_error("Cannot unintern symbol ~S from locked package ~S.",
 
402
                                "Ignore lock and proceed", p, 2, s, p);
 
403
                goto TRY_AGAIN_LABEL;
 
404
        }
 
405
        if (!member_eq(s, p->pack.shadowings))
 
406
                goto NOT_SHADOW;
 
407
        x = OBJNULL;
 
408
        for (l = p->pack.uses; CONSP(l); l = CDR(l)) {
 
409
                y = gethash_safe(s->symbol.name, CAR(l)->pack.external, OBJNULL);
 
410
                if (y != OBJNULL) {
 
411
                        if (x == OBJNULL)
 
412
                                x = y;
 
413
                        else if (x != y) {
 
414
                                PACKAGE_UNLOCK(p);
 
415
                                FEpackage_error("Cannot unintern the shadowing symbol ~S~%"
 
416
                                                "from ~S,~%"
 
417
                                                "because ~S and ~S will cause~%"
 
418
                                                "a name conflict.", p, 4, s, p, x, y);
 
419
                        }
 
420
                }
 
421
        }
 
422
        p->pack.shadowings = ecl_remove_eq(s, p->pack.shadowings);
 
423
 NOT_SHADOW:
 
424
        remhash(s->symbol.name, hash);
 
425
        if (s->symbol.hpack == p)
 
426
                s->symbol.hpack = Cnil;
 
427
        output = TRUE;
 
428
 OUTPUT:
 
429
        PACKAGE_UNLOCK(p);
 
430
        return output;
 
431
}
 
432
 
 
433
void
 
434
cl_export2(cl_object s, cl_object p)
 
435
{
 
436
        cl_object x, l, hash = OBJNULL;
 
437
        int intern_flag;
 
438
 
 
439
        assert_type_symbol(s);
 
440
        p = si_coerce_to_package(p);
 
441
 
 
442
        if (p->pack.locked)
 
443
                CEpackage_error("Cannot export symbol ~S from locked package ~S.",
 
444
                                "Ignore lock and proceed", p, 2, s, p);
 
445
        PACKAGE_LOCK(p);
 
446
        x = ecl_find_symbol_nolock(s->symbol.name, p, &intern_flag);
 
447
        if (!intern_flag) {
 
448
                PACKAGE_UNLOCK(p);
 
449
                CEpackage_error("The symbol ~S is not accessible from ~S and cannot be exported.",
 
450
                                "Import the symbol in the package and proceed.",
 
451
                                p, 2, s, p);
 
452
        }
 
453
        if (x != s) {
 
454
                PACKAGE_UNLOCK(p);
 
455
                FEpackage_error("Cannot export the symbol ~S from ~S,~%"
 
456
                                "because there is already a symbol with the same name~%"
 
457
                                "in the package.", p, 2, s, p);
 
458
        }
 
459
        if (intern_flag == EXTERNAL)
 
460
                goto OUTPUT;
 
461
        if (intern_flag == INTERNAL)
 
462
                hash = p->pack.internal;
 
463
        for (l = p->pack.usedby; CONSP(l); l = CDR(l)) {
 
464
                x = ecl_find_symbol_nolock(s->symbol.name, CAR(l), &intern_flag);
 
465
                if (intern_flag && s != x &&
 
466
                    !member_eq(x, CAR(l)->pack.shadowings)) {
 
467
                        PACKAGE_UNLOCK(p);
 
468
                        FEpackage_error("Cannot export the symbol ~S~%"
 
469
                                        "from ~S,~%"
 
470
                                        "because it will cause a name conflict~%"
 
471
                                        "in ~S.", p, 3, s, p, CAR(l));
 
472
                }
 
473
        }
 
474
        if (hash != OBJNULL)
 
475
                remhash(s->symbol.name, hash);
 
476
        sethash(s->symbol.name, p->pack.external, s);
 
477
 OUTPUT:
 
478
        PACKAGE_UNLOCK(p);
 
479
}
 
480
 
 
481
cl_object
 
482
cl_delete_package(cl_object p)
 
483
{
 
484
        cl_object hash, list;
 
485
        cl_index i;
 
486
 
 
487
        /* 1) Try to remove the package from the global list */
 
488
        p = ecl_find_package_nolock(p);
 
489
        if (Null(p)) {
 
490
                CEpackage_error("Package ~S not found. Cannot delete it.",
 
491
                                "Ignore error and continue", p, 0);
 
492
                @(return Cnil);
 
493
        }
 
494
        if (p->pack.locked)
 
495
                CEpackage_error("Cannot delete locked package ~S.",
 
496
                                "Ignore lock and proceed", p, 0);
 
497
        if (p == cl_core.lisp_package || p == cl_core.keyword_package) {
 
498
                FEpackage_error("Cannot remove package ~S", p, 0);
 
499
        }
 
500
 
 
501
        /* 2) Now remove the package from the other packages that use it
 
502
         *    and empty the package.
 
503
         */
 
504
        if (Null(p->pack.name)) {
 
505
                @(return Cnil)
 
506
        }
 
507
        for (list = p->pack.uses; !endp(list); list = CDR(list))
 
508
                unuse_package(CAR(list), p);
 
509
        for (list = p->pack.usedby; !endp(list); list = CDR(list))
 
510
                unuse_package(p, CAR(list));
 
511
        PACKAGE_LOCK(p);
 
512
        for (hash = p->pack.internal, i = 0; i < hash->hash.size; i++)
 
513
                if (hash->hash.data[i].key != OBJNULL) {
 
514
                        cl_object s = hash->hash.data[i].value;
 
515
                        if (s->symbol.hpack == p)
 
516
                                s->symbol.hpack = Cnil;
 
517
                }
 
518
        cl_clrhash(p->pack.internal);
 
519
        for (hash = p->pack.external, i = 0; i < hash->hash.size; i++)
 
520
                if (hash->hash.data[i].key != OBJNULL) {
 
521
                        cl_object s = hash->hash.data[i].value;
 
522
                        if (s->symbol.hpack == p)
 
523
                                s->symbol.hpack = Cnil;
 
524
                }
 
525
        cl_clrhash(p->pack.external);
 
526
        p->pack.shadowings = Cnil;
 
527
        p->pack.name = Cnil;
 
528
        PACKAGE_UNLOCK(p);
 
529
 
 
530
        /* 2) Only at the end, remove the package from the list of packages. */
 
531
        PACKAGE_OP_LOCK();
 
532
        cl_core.packages = ecl_remove_eq(p, cl_core.packages);
 
533
        PACKAGE_OP_UNLOCK();
 
534
        @(return Ct)
 
535
}
 
536
 
 
537
void
 
538
cl_unexport2(cl_object s, cl_object p)
 
539
{
 
540
        int intern_flag;
 
541
        cl_object x;
 
542
 
 
543
        assert_type_symbol(s);
 
544
        p = si_coerce_to_package(p);
 
545
        if (p == cl_core.keyword_package)
 
546
                FEpackage_error("Cannot unexport a symbol from the keyword package.",
 
547
                                cl_core.keyword_package, 0);
 
548
        if (p->pack.locked)
 
549
                CEpackage_error("Cannot unexport symbol ~S from locked package ~S.",
 
550
                                "Ignore lock and proceed", p, 2, s, p);
 
551
        PACKAGE_LOCK(p);
 
552
        x = ecl_find_symbol_nolock(s->symbol.name, p, &intern_flag);
 
553
        if (intern_flag == 0) {
 
554
                PACKAGE_UNLOCK(p);
 
555
                FEpackage_error("Cannot unexport ~S because it does not belong to package ~S.",
 
556
                                p, 2, s, p);
 
557
        }
 
558
        if (intern_flag != EXTERNAL) {
 
559
                /* According to ANSI & Cltl, internal symbols are
 
560
                   ignored in unexport */
 
561
                (void)0;
 
562
        } else {
 
563
                remhash(s->symbol.name, p->pack.external);
 
564
                sethash(s->symbol.name, p->pack.internal, s);
 
565
        }
 
566
        PACKAGE_UNLOCK(p);
 
567
}
 
568
 
 
569
void
 
570
cl_import2(cl_object s, cl_object p)
 
571
{
 
572
        int intern_flag;
 
573
        cl_object x;
 
574
 
 
575
        assert_type_symbol(s);
 
576
        p = si_coerce_to_package(p);
 
577
        if (p->pack.locked)
 
578
                CEpackage_error("Cannot import symbol ~S into locked package ~S.",
 
579
                                "Ignore lock and proceed", p, 2, s, p);
 
580
        PACKAGE_LOCK(p);
 
581
        x = ecl_find_symbol_nolock(s->symbol.name, p, &intern_flag);
 
582
        if (intern_flag) {
 
583
                if (x != s) {
 
584
                        PACKAGE_UNLOCK(p);
 
585
                        CEpackage_error("Cannot import the symbol ~S "
 
586
                                        "from package ~A,~%"
 
587
                                        "because there is already a symbol with the same name~%"
 
588
                                        "in the package.",
 
589
                                        "Ignore conflict and proceed", p, 2, s, p);
 
590
                }
 
591
                if (intern_flag == INTERNAL || intern_flag == EXTERNAL)
 
592
                        goto OUTPUT;
 
593
        }
 
594
        sethash(s->symbol.name, p->pack.internal, s);
 
595
        if (Null(s->symbol.hpack))
 
596
                s->symbol.hpack = p;
 
597
 OUTPUT:
 
598
        PACKAGE_UNLOCK(p);
 
599
}
 
600
 
 
601
void
 
602
shadowing_import(cl_object s, cl_object p)
 
603
{
 
604
        int intern_flag;
 
605
        cl_object x;
 
606
 
 
607
        assert_type_symbol(s);
 
608
        p = si_coerce_to_package(p);
 
609
        if (p->pack.locked)
 
610
                CEpackage_error("Cannot shadowing-import symbol ~S into locked package ~S.",
 
611
                                "Ignore lock and proceed", p, 2, s, p);
 
612
 
 
613
        PACKAGE_LOCK(p);
 
614
        x = ecl_find_symbol_nolock(s->symbol.name, p, &intern_flag);
 
615
        if (intern_flag && intern_flag != INHERITED) {
 
616
                if (x == s) {
 
617
                        if (!member_eq(x, p->pack.shadowings))
 
618
                                p->pack.shadowings
 
619
                                = CONS(x, p->pack.shadowings);
 
620
                        goto OUTPUT;
 
621
                }
 
622
                if(member_eq(x, p->pack.shadowings))
 
623
                        p->pack.shadowings = ecl_remove_eq(x, p->pack.shadowings);
 
624
                if (intern_flag == INTERNAL)
 
625
                        remhash(x->symbol.name, p->pack.internal);
 
626
                else
 
627
                        remhash(x->symbol.name, p->pack.external);
 
628
                if (x->symbol.hpack == p)
 
629
                        x->symbol.hpack = Cnil;
 
630
        }
 
631
        p->pack.shadowings = CONS(s, p->pack.shadowings);
 
632
        sethash(s->symbol.name, p->pack.internal, s);
 
633
 OUTPUT:
 
634
        PACKAGE_UNLOCK(p);
 
635
}
 
636
 
 
637
void
 
638
shadow(cl_object s, cl_object p)
 
639
{
 
640
        int intern_flag;
 
641
        cl_object x;
 
642
 
 
643
        /* Contrary to CLTL, in ANSI CL, SHADOW operates on strings. */
 
644
        s = cl_string(s);
 
645
        p = si_coerce_to_package(p);
 
646
        if (p->pack.locked)
 
647
                CEpackage_error("Cannot shadow symbol ~S in locked package ~S.",
 
648
                                "Ignore lock and proceed", p, 2, s, p);
 
649
        PACKAGE_LOCK(p);
 
650
        x = ecl_find_symbol_nolock(s, p, &intern_flag);
 
651
        if (intern_flag != INTERNAL && intern_flag != EXTERNAL) {
 
652
                x = make_symbol(s);
 
653
                sethash(x->symbol.name, p->pack.internal, x);
 
654
                x->symbol.hpack = p;
 
655
        }
 
656
        p->pack.shadowings = CONS(x, p->pack.shadowings);
 
657
        PACKAGE_UNLOCK(p);
 
658
}
 
659
 
 
660
void
 
661
use_package(cl_object x, cl_object p)
 
662
{
 
663
        struct ecl_hashtable_entry *hash_entries;
 
664
        cl_index i, hash_length;
 
665
        int intern_flag;
 
666
 
 
667
        x = si_coerce_to_package(x);
 
668
        if (x == cl_core.keyword_package)
 
669
                FEpackage_error("Cannot use keyword package.", cl_core.keyword_package, 0);
 
670
        p = si_coerce_to_package(p);
 
671
        if (p->pack.locked)
 
672
                CEpackage_error("Cannot use package ~S in locked package ~S.",
 
673
                                "Ignore lock and proceed",
 
674
                                p, 2, x, p);
 
675
        if (p == cl_core.keyword_package)
 
676
                FEpackage_error("Cannot use in keyword package.", cl_core.keyword_package, 0);
 
677
        if (p == x)
 
678
                return;
 
679
        if (member_eq(x, p->pack.uses))
 
680
                return;
 
681
 
 
682
        PACKAGE_LOCK(x);
 
683
        PACKAGE_LOCK(p);
 
684
        hash_entries = x->pack.external->hash.data;
 
685
        hash_length = x->pack.external->hash.size;
 
686
        for (i = 0;  i < hash_length;  i++)
 
687
                if (hash_entries[i].key != OBJNULL) {
 
688
                        cl_object here = hash_entries[i].value;
 
689
                        cl_object there = ecl_find_symbol_nolock(here->symbol.name, p, &intern_flag);
 
690
                        if (intern_flag && here != there
 
691
                            && ! member_eq(there, p->pack.shadowings)) {
 
692
                                PACKAGE_UNLOCK(x);
 
693
                                PACKAGE_UNLOCK(p);
 
694
                                FEpackage_error("Cannot use ~S~%"
 
695
                                                "from ~S,~%"
 
696
                                                "because ~S and ~S will cause~%"
 
697
                                                "a name conflict.", p, 4, x, p, here, there);
 
698
                        }
 
699
                }
 
700
        p->pack.uses = CONS(x, p->pack.uses);
 
701
        x->pack.usedby = CONS(p, x->pack.usedby);
 
702
        PACKAGE_UNLOCK(x);
 
703
        PACKAGE_UNLOCK(p);
 
704
}
 
705
 
 
706
void
 
707
unuse_package(cl_object x, cl_object p)
 
708
{
 
709
        x = si_coerce_to_package(x);
 
710
        p = si_coerce_to_package(p);
 
711
        if (p->pack.locked)
 
712
                CEpackage_error("Cannot unuse package ~S from locked package ~S.",
 
713
                                "Ignore lock and proceed",
 
714
                                p, 2, x, p);
 
715
        PACKAGE_LOCK(x);
 
716
        PACKAGE_LOCK(p);
 
717
        p->pack.uses = ecl_remove_eq(x, p->pack.uses);
 
718
        x->pack.usedby = ecl_remove_eq(p, x->pack.usedby);
 
719
        PACKAGE_UNLOCK(p);
 
720
        PACKAGE_UNLOCK(x);
 
721
}
 
722
 
 
723
@(defun make_package (pack_name &key nicknames (use CONS(cl_core.lisp_package, Cnil)))
 
724
@
 
725
        /* INV: make_package() performs type checking */
 
726
        @(return make_package(pack_name, nicknames, use))
 
727
@)
 
728
 
 
729
cl_object
 
730
si_select_package(cl_object pack_name)
 
731
{
 
732
        cl_object p = si_coerce_to_package(pack_name);
 
733
        @(return (ECL_SETQ(@'*package*', p)))
 
734
}
 
735
 
 
736
cl_object
 
737
cl_find_package(cl_object p)
 
738
{
 
739
        @(return ecl_find_package_nolock(p))
 
740
}
 
741
 
 
742
cl_object
 
743
cl_package_name(cl_object p)
 
744
{
 
745
        /* FIXME: name should be a fresh one */
 
746
        p = si_coerce_to_package(p);
 
747
        @(return p->pack.name)
 
748
}
 
749
 
 
750
cl_object
 
751
cl_package_nicknames(cl_object p)
 
752
{
 
753
        /* FIXME: list should be a fresh one */
 
754
        p = si_coerce_to_package(p);
 
755
        @(return p->pack.nicknames)
 
756
}
 
757
 
 
758
@(defun rename_package (pack new_name &o new_nicknames)
 
759
@
 
760
        /* INV: rename_package() type checks and coerces pack to package */
 
761
        @(return rename_package(pack, new_name, new_nicknames))
 
762
@)
 
763
 
 
764
cl_object
 
765
cl_package_use_list(cl_object p)
 
766
{
 
767
        return cl_copy_list(si_coerce_to_package(p)->pack.uses);
 
768
}
 
769
 
 
770
cl_object
 
771
cl_package_used_by_list(cl_object p)
 
772
{
 
773
        return cl_copy_list(si_coerce_to_package(p)->pack.usedby);
 
774
}
 
775
 
 
776
cl_object
 
777
cl_package_shadowing_symbols(cl_object p)
 
778
{
 
779
        return cl_copy_list(si_coerce_to_package(p)->pack.shadowings);
 
780
}
 
781
 
 
782
cl_object
 
783
si_package_lock(cl_object p, cl_object t)
 
784
{
 
785
        p = si_coerce_to_package(p);
 
786
        p->pack.locked = (t != Cnil);
 
787
        @(return p)
 
788
}
 
789
 
 
790
cl_object
 
791
cl_list_all_packages()
 
792
{
 
793
        return cl_copy_list(cl_core.packages);
 
794
}
 
795
 
 
796
@(defun intern (strng &optional (p current_package()) &aux sym)
 
797
        int intern_flag;
 
798
@
 
799
        sym = intern(strng, p, &intern_flag);
 
800
        if (intern_flag == INTERNAL)
 
801
                @(return sym @':internal')
 
802
        if (intern_flag == EXTERNAL)
 
803
                @(return sym @':external')
 
804
        if (intern_flag == INHERITED)
 
805
                @(return sym @':inherited')
 
806
        @(return sym Cnil)
 
807
@)
 
808
 
 
809
@(defun find_symbol (strng &optional (p current_package()))
 
810
        cl_object x;
 
811
        int intern_flag;
 
812
@
 
813
        x = ecl_find_symbol(strng, p, &intern_flag);
 
814
        if (intern_flag == INTERNAL)
 
815
                @(return x @':internal')
 
816
        if (intern_flag == EXTERNAL)
 
817
                @(return x @':external')
 
818
        if (intern_flag == INHERITED)
 
819
                @(return x @':inherited')
 
820
        @(return Cnil Cnil)
 
821
@)
 
822
 
 
823
@(defun unintern (symbl &optional (p current_package()))
 
824
@
 
825
        @(return (unintern(symbl, p) ? Ct : Cnil))
 
826
@)
 
827
 
 
828
@(defun export (symbols &o (pack current_package()))
 
829
        cl_object l;
 
830
@
 
831
BEGIN:
 
832
        switch (type_of(symbols)) {
 
833
        case t_symbol:
 
834
                if (Null(symbols))
 
835
                        break;
 
836
                cl_export2(symbols, pack);
 
837
                break;
 
838
 
 
839
        case t_cons:
 
840
                pack = si_coerce_to_package(pack);
 
841
                for (l = symbols;  !endp(l);  l = CDR(l))
 
842
                        cl_export2(CAR(l), pack);
 
843
                break;
 
844
 
 
845
        default:
 
846
                assert_type_symbol(symbols);
 
847
                goto BEGIN;
 
848
        }
 
849
        @(return Ct)
 
850
@)
 
851
 
 
852
@(defun unexport (symbols &o (pack current_package()))
 
853
        cl_object l;
 
854
@
 
855
BEGIN:
 
856
        switch (type_of(symbols)) {
 
857
        case t_symbol:
 
858
                if (Null(symbols))
 
859
                        break;
 
860
                cl_unexport2(symbols, pack);
 
861
                break;
 
862
 
 
863
        case t_cons:
 
864
                pack = si_coerce_to_package(pack);
 
865
                for (l = symbols;  !endp(l);  l = CDR(l))
 
866
                        cl_unexport2(CAR(l), pack);
 
867
                break;
 
868
 
 
869
        default:
 
870
                assert_type_symbol(symbols);
 
871
                goto BEGIN;
 
872
        }
 
873
        @(return Ct)
 
874
@)
 
875
 
 
876
@(defun import (symbols &o (pack current_package()))
 
877
        cl_object l;
 
878
@
 
879
BEGIN:
 
880
        switch (type_of(symbols)) {
 
881
        case t_symbol:
 
882
                if (Null(symbols))
 
883
                        break;
 
884
                cl_import2(symbols, pack);
 
885
                break;
 
886
 
 
887
        case t_cons:
 
888
                pack = si_coerce_to_package(pack);
 
889
                for (l = symbols;  !endp(l);  l = CDR(l))
 
890
                        cl_import2(CAR(l), pack);
 
891
                break;
 
892
 
 
893
        default:
 
894
                assert_type_symbol(symbols);
 
895
                goto BEGIN;
 
896
        }
 
897
        @(return Ct)
 
898
@)
 
899
 
 
900
@(defun shadowing_import (symbols &o (pack current_package()))
 
901
        cl_object l;
 
902
@
 
903
BEGIN:
 
904
        switch (type_of(symbols)) {
 
905
        case t_symbol:
 
906
                if (Null(symbols))
 
907
                        break;
 
908
                shadowing_import(symbols, pack);
 
909
                break;
 
910
 
 
911
        case t_cons:
 
912
                pack = si_coerce_to_package(pack);
 
913
                for (l = symbols;  !endp(l);  l = CDR(l))
 
914
                        shadowing_import(CAR(l), pack);
 
915
                break;
 
916
 
 
917
        default:
 
918
                assert_type_symbol(symbols);
 
919
                goto BEGIN;
 
920
        }
 
921
        @(return Ct)
 
922
@)
 
923
 
 
924
@(defun shadow (symbols &o (pack current_package()))
 
925
        cl_object l;
 
926
@
 
927
BEGIN:
 
928
        switch (type_of(symbols)) {
 
929
        case t_string:
 
930
        case t_symbol:
 
931
        case t_character:
 
932
                /* Arguments to SHADOW may be: string designators ... */
 
933
                if (Null(symbols))
 
934
                        break;
 
935
                shadow(symbols, pack);
 
936
                break;
 
937
        case t_cons:
 
938
                /* ... or lists of string designators */
 
939
                pack = si_coerce_to_package(pack);
 
940
                for (l = symbols;  !endp(l);  l = CDR(l))
 
941
                        shadow(CAR(l), pack);
 
942
                break;
 
943
        default:
 
944
                assert_type_string(symbols);
 
945
                goto BEGIN;
 
946
        }
 
947
        @(return Ct)
 
948
@)
 
949
 
 
950
@(defun use_package (pack &o (pa current_package()))
 
951
        cl_object l;
 
952
@
 
953
BEGIN:
 
954
        switch (type_of(pack)) {
 
955
        case t_symbol:
 
956
                if (Null(pack))
 
957
                        break;
 
958
        case t_character:
 
959
        case t_string:
 
960
        case t_package:
 
961
                use_package(pack, pa);
 
962
                break;
 
963
 
 
964
        case t_cons:
 
965
                pa = si_coerce_to_package(pa);
 
966
                for (l = pack;  !endp(l);  l = CDR(l))
 
967
                        use_package(CAR(l), pa);
 
968
                break;
 
969
 
 
970
        default:
 
971
                assert_type_package(pack);
 
972
                goto BEGIN;
 
973
        }
 
974
        @(return Ct)
 
975
@)
 
976
 
 
977
@(defun unuse_package (pack &o (pa current_package()))
 
978
        cl_object l;
 
979
@
 
980
BEGIN:
 
981
        switch (type_of(pack)) {
 
982
        case t_symbol:
 
983
                if (Null(pack))
 
984
                        break;
 
985
        case t_character:
 
986
        case t_string:
 
987
        case t_package:
 
988
                unuse_package(pack, pa);
 
989
                break;
 
990
 
 
991
        case t_cons:
 
992
                pa = si_coerce_to_package(pa);
 
993
                for (l = pack;  !endp(l);  l = CDR(l))
 
994
                        unuse_package(CAR(l), pa);
 
995
                break;
 
996
 
 
997
        default:
 
998
                assert_type_package(pack);
 
999
                goto BEGIN;
 
1000
        }
 
1001
        @(return Ct)
 
1002
@)
 
1003
 
 
1004
cl_object
 
1005
si_package_hash_tables(cl_object p)
 
1006
{
 
1007
        cl_object he, hi, u;
 
1008
        assert_type_package(p);
 
1009
        PACKAGE_LOCK(p);
 
1010
        he = si_copy_hash_table(p->pack.external);
 
1011
        hi = si_copy_hash_table(p->pack.internal);
 
1012
        u = cl_copy_list(p->pack.uses);
 
1013
        PACKAGE_UNLOCK(p);
 
1014
        @(return he hi u)
 
1015
}