1 /*****
2 * entry.cc
3 * Andy Hammerlindl 2002/08/29
4 *
5 * All variables, built-in functions and user-defined functions reside
6 * within the same namespace. To keep track of all these, table of
7 * "entries" is used.
8 *****/
9
10 #include <iostream>
11
12 #include <cmath>
13 #include <cstring>
14 #include <utility>
15 #include "entry.h"
16 #include "coder.h"
17
18 using std::memset;
19 using types::ty;
20 using types::signature;
21 using types::overloaded;
22 using types::ty_vector;
23 using types::ty_iterator;
24
25 namespace trans {
26
check(action act,coder & c)27 bool entry::pr::check(action act, coder &c) {
28 // We assume PUBLIC permissions and one's without an associated record are not
29 // stored.
30 assert(perm!=PUBLIC && r!=0);
31 return c.inTranslation(r->getLevel()) ||
32 (perm == RESTRICTED && act != WRITE);
33 }
34
report(action act,position pos,coder & c)35 void entry::pr::report(action act, position pos, coder &c) {
36 if (!c.inTranslation(r->getLevel())) {
37 if (perm == PRIVATE) {
38 em.error(pos);
39 em << "accessing private field outside of structure";
40 }
41 else if (perm == RESTRICTED && act == WRITE) {
42 em.error(pos);
43 em << "modifying non-public field outside of structure";
44 }
45 }
46 }
47
entry(entry & e1,entry & e2)48 entry::entry(entry &e1, entry &e2) : where(e2.where), pos(e2.pos) {
49 perms.insert(perms.end(), e1.perms.begin(), e1.perms.end());
50 perms.insert(perms.end(), e2.perms.begin(), e2.perms.end());
51 }
52
entry(entry & base,permission perm,record * r)53 entry::entry(entry &base, permission perm, record *r)
54 : where(base.where), pos(base.pos) {
55 perms.insert(perms.end(), base.perms.begin(), base.perms.end());
56 addPerm(perm, r);
57 }
58
checkPerm(action act,coder & c)59 bool entry::checkPerm(action act, coder &c) {
60 for (mem::list<pr>::iterator p=perms.begin(); p != perms.end(); ++p)
61 if (!p->check(act, c))
62 return false;
63 return true;
64 }
65
reportPerm(action act,position pos,coder & c)66 void entry::reportPerm(action act, position pos, coder &c) {
67 for (mem::list<pr>::iterator p=perms.begin(); p != perms.end(); ++p)
68 p->report(act, pos, c);
69 }
70
71
varEntry(varEntry & qv,varEntry & v)72 varEntry::varEntry(varEntry &qv, varEntry &v)
73 : entry(qv,v), t(v.t),
74 location(new qualifiedAccess(qv.location, qv.getLevel(), v.location)) {}
75
getLevel()76 frame *varEntry::getLevel() {
77 record *r=dynamic_cast<record *>(t);
78 assert(r);
79 return r->getLevel();
80 }
81
encode(action act,position pos,coder & c)82 void varEntry::encode(action act, position pos, coder &c) {
83 reportPerm(act, pos, c);
84 getLocation()->encode(act, pos, c);
85 }
86
encode(action act,position pos,coder & c,frame * top)87 void varEntry::encode(action act, position pos, coder &c, frame *top) {
88 reportPerm(act, pos, c);
89 getLocation()->encode(act, pos, c, top);
90 }
91
qualifyVarEntry(varEntry * qv,varEntry * v)92 varEntry *qualifyVarEntry(varEntry *qv, varEntry *v)
93 {
94 return qv ? (v ? new varEntry(*qv,*v) : qv) : v;
95 }
96
97
add(symbol dest,names_t::value_type & x,varEntry * qualifier,coder & c)98 bool tenv::add(symbol dest,
99 names_t::value_type &x, varEntry *qualifier, coder &c)
100 {
101 if (!x.second.empty()) {
102 tyEntry *ent=x.second.front();
103 if (ent->checkPerm(READ, c)) {
104 enter(dest, qualifyTyEntry(qualifier, ent));
105 return true;
106 }
107 }
108 return false;
109 }
110
add(tenv & source,varEntry * qualifier,coder & c)111 void tenv::add(tenv& source, varEntry *qualifier, coder &c) {
112 // Enter each distinct (unshadowed) name,type pair.
113 for(names_t::iterator p = source.names.begin(); p != source.names.end(); ++p)
114 add(p->first, *p, qualifier, c);
115 }
116
add(symbol src,symbol dest,tenv & source,varEntry * qualifier,coder & c)117 bool tenv::add(symbol src, symbol dest,
118 tenv& source, varEntry *qualifier, coder &c) {
119 names_t::iterator p = source.names.find(src);
120 if (p != source.names.end())
121 return add(dest, *p, qualifier, c);
122 else
123 return false;
124 }
125
126 // To avoid writing qualifiers everywhere.
127 typedef core_venv::cell cell;
128
initTable(size_t capacity)129 void core_venv::initTable(size_t capacity) {
130 // Assert that capacity is a power of two.
131 assert((capacity & (capacity-1)) == 0);
132
133 this->capacity = capacity;
134 size = 0;
135 mask = capacity - 1;
136 table = new (UseGC) cell[capacity];
137 memset(table, 0, sizeof(cell) * capacity);
138 }
139
clear()140 void core_venv::clear() {
141 if (size != 0) {
142 memset(table, 0, sizeof(cell) * capacity);
143 size = 0;
144 }
145 }
146
resize()147 void core_venv::resize() {
148 size_t oldCapacity = capacity;
149 size_t oldSize = size;
150 cell *oldTable = table;
151
152 initTable(capacity * 4);
153
154 for (size_t i = 0; i < oldCapacity; ++i) {
155 cell& b = oldTable[i];
156 if (!b.empty() && !b.isATomb()) {
157 varEntry *old = store(b.name, b.ent);
158
159 // We should not be shadowing anything when reconstructing the table.
160 DEBUG_CACHE_ASSERT(old == 0);
161 }
162 }
163
164 assert(size == oldSize);
165
166 #if DEBUG_CACHE
167 confirm_size();
168
169 for (size_t i = 0; i < oldCapacity; ++i) {
170 cell& b = oldTable[i];
171 if (!b.empty() && !b.isATomb()) {
172 assert(lookup(b.name, b.ent->getType()) == b.ent);
173 }
174 }
175 #endif
176
177 //cout << "resized from " << oldCapacity << " to " << capacity << endl;
178 }
179
cellByIndex(size_t i)180 cell& core_venv::cellByIndex(size_t i) {
181 return table[i & mask];
182 }
183
cellByIndex(size_t i) const184 const cell& core_venv::cellByIndex(size_t i) const {
185 return table[i & mask];
186 }
187
confirm_size()188 void core_venv::confirm_size() {
189 size_t sum = 0;
190 for (size_t i = 0; i < capacity; ++i) {
191 cell& b = table[i];
192 if (!b.empty() && !b.isATomb())
193 ++sum;
194 }
195 assert(sum == size);
196 }
197
storeNew(cell & cell,symbol name,varEntry * ent)198 varEntry *core_venv::storeNew(cell& cell, symbol name, varEntry *ent) {
199 // Store the value into the cell.
200 cell.storeNew(name, ent);
201
202 // We now have a new entry. Update the size.
203 ++size;
204
205 // Check if the hash table has grown too big and needs to be expanded.
206 if (2*size > capacity)
207 resize();
208
209 // Nothing is shadowed.
210 return 0;
211 }
212
213
storeNonSpecialAfterTomb(size_t tombIndex,symbol name,varEntry * ent)214 varEntry *core_venv::storeNonSpecialAfterTomb(size_t tombIndex,
215 symbol name, varEntry *ent) {
216 DEBUG_CACHE_ASSERT(name.notSpecial());
217 DEBUG_CACHE_ASSERT(ent);
218 DEBUG_CACHE_ASSERT(ent->getType());
219
220 signature *sig = ent->getSignature();
221
222 for (size_t i = tombIndex+1; ; ++i)
223 {
224 cell& b = cellByIndex(i);
225
226 if (b.empty())
227 return storeNew(cellByIndex(tombIndex), name, ent);
228
229 if (b.matches(name, sig))
230 return b.replaceWith(name, ent);
231 }
232 }
233
storeSpecialAfterTomb(size_t tombIndex,symbol name,varEntry * ent)234 varEntry *core_venv::storeSpecialAfterTomb(size_t tombIndex,
235 symbol name, varEntry *ent) {
236 DEBUG_CACHE_ASSERT(name.special());
237 DEBUG_CACHE_ASSERT(ent);
238 DEBUG_CACHE_ASSERT(ent->getType());
239
240 ty *t = ent->getType();
241
242 for (size_t i = tombIndex+1; ; ++i)
243 {
244 cell& b = cellByIndex(i);
245
246 if (b.empty())
247 return storeNew(cellByIndex(tombIndex), name, ent);
248
249 if (b.matches(name, t))
250 return b.replaceWith(name, ent);
251 }
252 }
253
hashSig(const signature * sig)254 size_t hashSig(const signature *sig) {
255 return sig ? sig->hash() : 0;
256 }
nonSpecialHash(symbol name,const signature * sig)257 size_t nonSpecialHash(symbol name, const signature *sig) {
258 return name.hash() * 107 + hashSig(sig);
259 }
nonSpecialHash(symbol name,const ty * t)260 size_t nonSpecialHash(symbol name, const ty *t) {
261 DEBUG_CACHE_ASSERT(t);
262 return nonSpecialHash(name, t->getSignature());
263 }
specialHash(symbol name,const ty * t)264 size_t specialHash(symbol name, const ty *t) {
265 DEBUG_CACHE_ASSERT(t);
266 return name.hash() * 107 + t->hash();
267 }
268
storeNonSpecial(symbol name,varEntry * ent)269 varEntry *core_venv::storeNonSpecial(symbol name, varEntry *ent) {
270 DEBUG_CACHE_ASSERT(name.notSpecial());
271 DEBUG_CACHE_ASSERT(ent);
272 DEBUG_CACHE_ASSERT(ent->getType());
273
274 signature *sig = ent->getSignature();
275
276 for (size_t i = nonSpecialHash(name, sig); ; ++i)
277 {
278 cell& b = cellByIndex(i);
279
280 if (b.empty())
281 return storeNew(b, name, ent);
282
283 if (b.matches(name, sig))
284 return b.replaceWith(name, ent);
285
286 if (b.isATomb())
287 return storeNonSpecialAfterTomb(i, name, ent);
288 }
289 }
290
storeSpecial(symbol name,varEntry * ent)291 varEntry *core_venv::storeSpecial(symbol name, varEntry *ent) {
292 DEBUG_CACHE_ASSERT(name.special());
293 DEBUG_CACHE_ASSERT(ent);
294 DEBUG_CACHE_ASSERT(ent->getType());
295
296 ty *t = ent->getType();
297
298 for (size_t i = specialHash(name, t); ; ++i)
299 {
300 cell& b = cellByIndex(i);
301
302 if (b.empty())
303 return storeNew(b, name, ent);
304
305 if (b.matches(name, t))
306 return b.replaceWith(name, ent);
307
308 if (b.isATomb())
309 return storeSpecialAfterTomb(i, name, ent);
310 }
311 }
312
store(symbol name,varEntry * ent)313 varEntry *core_venv::store(symbol name, varEntry *ent) {
314 DEBUG_CACHE_ASSERT(ent);
315 DEBUG_CACHE_ASSERT(ent->getType());
316
317 return name.special() ? storeSpecial(name, ent) :
318 storeNonSpecial(name, ent);
319 }
320
lookupSpecial(symbol name,const ty * t)321 varEntry *core_venv::lookupSpecial(symbol name, const ty *t) {
322 DEBUG_CACHE_ASSERT(name.special());
323 DEBUG_CACHE_ASSERT(t);
324
325 for (size_t i = specialHash(name, t); ; ++i)
326 {
327 cell& b = cellByIndex(i);
328
329 if (b.matches(name, t))
330 return b.ent;
331
332 if (b.empty())
333 return 0;
334 }
335 }
336
lookupNonSpecial(symbol name,const signature * sig)337 varEntry *core_venv::lookupNonSpecial(symbol name, const signature *sig) {
338 DEBUG_CACHE_ASSERT(name.notSpecial());
339
340 for (size_t i = nonSpecialHash(name, sig); ; ++i)
341 {
342 cell& b = cellByIndex(i);
343
344 if (b.matches(name, sig))
345 return b.ent;
346
347 if (b.empty())
348 return 0;
349 }
350 }
351
lookup(symbol name,const ty * t)352 varEntry *core_venv::lookup(symbol name, const ty *t) {
353 DEBUG_CACHE_ASSERT(t);
354
355 return name.special() ? lookupSpecial(name, t) :
356 lookupNonSpecial(name, t->getSignature());
357 }
358
removeNonSpecial(symbol name,const signature * sig)359 void core_venv::removeNonSpecial(symbol name, const signature *sig) {
360 DEBUG_CACHE_ASSERT(name.notSpecial());
361
362 for (size_t i = nonSpecialHash(name, sig); ; ++i)
363 {
364 cell& b = cellByIndex(i);
365
366 if (b.matches(name, sig)) {
367 b.remove();
368 --size;
369 return;
370 }
371
372 DEBUG_CACHE_ASSERT(!b.empty());
373 }
374 }
375
removeSpecial(symbol name,const ty * t)376 void core_venv::removeSpecial(symbol name, const ty *t) {
377 DEBUG_CACHE_ASSERT(name.special());
378 DEBUG_CACHE_ASSERT(t);
379
380 for (size_t i = specialHash(name, t); ; ++i)
381 {
382 cell& b = cellByIndex(i);
383
384 if (b.matches(name, t)) {
385 b.remove();
386 --size;
387 return;
388 }
389
390 DEBUG_CACHE_ASSERT(!b.empty());
391 }
392 }
393
remove(symbol name,const ty * t)394 void core_venv::remove(symbol name, const ty *t) {
395 DEBUG_CACHE_ASSERT(t);
396
397 if (name.special())
398 removeSpecial(name, t);
399 else
400 removeNonSpecial(name, t->getSignature());
401 }
402
403
numFormals(ty * t)404 size_t numFormals(ty *t) {
405 signature *sig = t->getSignature();
406 return sig ? sig->getNumFormals() : 0;
407 }
408
checkName(symbol name)409 void venv::checkName(symbol name)
410 {
411 #if 0
412 // This size test is too slow, even for DEBUG_CACHE.
413 core.confirm_size();
414 #endif
415
416 // Get the type, and make it overloaded if it is not (for uniformity).
417 overloaded o;
418 ty *t = getType(name);
419 if (!t)
420 t = &o;
421 if (!t->isOverloaded()) {
422 o.add(t);
423 t = &o;
424 }
425 assert(t->isOverloaded());
426
427 size_t maxFormals = names[name].maxFormals;
428
429 size_t size = 0;
430 for (ty_iterator i = t->begin(); i != t->end(); ++i) {
431 assert(numFormals(*i) <= maxFormals);
432 varEntry *v = lookByType(name, *i);
433 assert(v);
434 assert(equivalent(v->getType(), *i));
435 ++size;
436 }
437
438 size_t matches = 0;
439 core_venv::const_iterator end = core.end();
440 for (core_venv::const_iterator p = core.begin(); p != end; ++p) {
441 if (p->name == name) {
442 ++matches;
443
444 varEntry *v=p->ent;
445 assert(v);
446 assert(equivalent(t, v->getType()));
447 }
448 }
449 assert(matches == size);
450 }
451
rightKind(ty * t)452 void rightKind(ty *t) {
453 if (t && t->isOverloaded()) {
454 ty_vector& set=((overloaded *)t)->sub;
455 assert(set.size() > 1);
456 }
457 }
458
459 #ifdef DEBUG_CACHE
460 #define RIGHTKIND(t) (rightKind(t))
461 #define CHECKNAME(name) (checkName(name))
462 #else
463 #define RIGHTKIND(t) (void)(t)
464 #define CHECKNAME(name) (void)(name)
465 #endif
466
addType(ty * s)467 void venv::namevalue::addType(ty *s) {
468 RIGHTKIND(t);
469
470 #ifdef DEBUG_CACHE
471 assert(!s->isOverloaded());
472 #endif
473
474 if (t == 0) {
475 maxFormals = numFormals(s);
476 t = s;
477 } else {
478 if (!t->isOverloaded())
479 t = new overloaded(t);
480
481 #ifdef DEBUG_CACHE
482 assert(t->isOverloaded());
483 assert(!equivalent(t, s));
484 #endif
485
486 ((overloaded *)t)->add(s);
487
488 size_t n = numFormals(s);
489 if (n > maxFormals)
490 maxFormals = n;
491 }
492
493 RIGHTKIND(t);
494 }
495
replaceType(ty * new_t,ty * old_t)496 void venv::namevalue::replaceType(ty *new_t, ty *old_t) {
497 #ifdef DEBUG_CACHE
498 assert(t != 0);
499 RIGHTKIND(t);
500 #endif
501
502 // TODO: Test for equivalence.
503
504 if (t->isOverloaded()) {
505 for (ty_iterator i = t->begin(); i != t->end(); ++i) {
506 if (equivalent(old_t, *i)) {
507 *i = new_t;
508 return;
509 }
510 }
511
512 // An error, the type was not found.
513 assert("unreachable code" == 0);
514
515 } else {
516 #ifdef DEBUG_CACHE
517 assert(equivalent(old_t, t));
518 #endif
519 t = new_t;
520 }
521
522 #ifdef DEBUG_CACHE
523 assert(t != 0);
524 RIGHTKIND(t);
525 #endif
526 }
527
528 #ifdef DEBUG_CACHE
popType(ty * s)529 void venv::namevalue::popType(ty *s)
530 #else
531 void venv::namevalue::popType()
532 #endif
533 {
534 #ifdef DEBUG_CACHE
535 assert(t);
536 RIGHTKIND(t);
537 assert(!s->isOverloaded());
538 #endif
539
540 if (t->isOverloaded()) {
541 ty_vector& set=((overloaded *)t)->sub;
542
543 #ifdef DEBUG_CACHE
544 assert(set.size() > 0);
545 assert(equivalent(set.back(), s));
546 #endif
547
548 // We are relying on the fact that this was the last type added to t, and
549 // that type are added by pushing them on the end of the vector.
550 set.pop_back();
551
552 if (set.size() == 1)
553 t = set.front();
554 } else {
555 #ifdef DEBUG_CACHE
556 assert(equivalent(t, s));
557 #endif
558 t = 0;
559 }
560
561 RIGHTKIND(t);
562
563 // Don't try to reduce numFormals as I doubt it is worth the cost of
564 // recalculating.
565 }
566
remove(const addition & a)567 void venv::remove(const addition& a) {
568 CHECKNAME(a.name);
569
570 if (a.shadowed) {
571 varEntry *popEnt = core.store(a.name, a.shadowed);
572
573 DEBUG_CACHE_ASSERT(popEnt);
574
575 // Unshadow the previously shadowed varEntry.
576 names[a.name].replaceType(a.shadowed->getType(), popEnt->getType());
577 }
578 else {
579 // Remove the (name,sig) key completely.
580 #if DEBUG_CACHE
581 varEntry *popEnt = core.lookup(a.name, a.t);
582 assert(popEnt);
583 names[a.name].popType(popEnt->getType());
584 #else
585 names[a.name].popType();
586 #endif
587
588 core.remove(a.name, a.t);
589 }
590
591 CHECKNAME(a.name);
592 }
593
beginScope()594 void venv::beginScope() {
595 if (core.empty()) {
596 assert(scopesizes.empty());
597 ++empty_scopes;
598 } else {
599 scopesizes.push(additions.size());
600 }
601 }
602
endScope()603 void venv::endScope() {
604 if (scopesizes.empty()) {
605 // The corresponding beginScope happened when the venv was empty, so
606 // clear the hash tables to return to that state.
607 core.clear();
608 names.clear();
609
610 assert(empty_scopes > 0);
611 --empty_scopes;
612 } else {
613 size_t scopesize = scopesizes.top();
614 assert(additions.size() >= scopesize);
615 while (additions.size() > scopesize) {
616 remove(additions.top());
617 additions.pop();
618 }
619 scopesizes.pop();
620 }
621 }
622
623 // Adds the definitions of the top-level scope to the level underneath,
624 // and then removes the top scope.
collapseScope()625 void venv::collapseScope() {
626 if (scopesizes.empty()) {
627 // Collapsing an empty scope.
628 assert(empty_scopes > 0);
629 --empty_scopes;
630 } else {
631 // As scopes are stored solely by the number of entries at the beginning
632 // of the scope, popping the top size will put all of the entries into the
633 // next scope down.
634 scopesizes.pop();
635 }
636 }
637
638
enter(symbol name,varEntry * v)639 void venv::enter(symbol name, varEntry *v)
640 {
641 CHECKNAME(name);
642
643 // Store the new variable. If it shadows an older variable, that varEntry
644 // will be returned.
645 varEntry *shadowed = core.store(name, v);
646
647 ty *t = v->getType();
648
649 // Record the addition, so it can be undone during endScope.
650 if (!scopesizes.empty())
651 additions.push(addition(name, t, shadowed));
652
653 if (shadowed)
654 // The new value shadows an old value. They have the same signature, but
655 // possibly different return types. If necessary, update the type stored
656 // by name.
657 names[name].replaceType(t, shadowed->getType());
658 else
659 // Add to the names hash table.
660 names[name].addType(t);
661
662 CHECKNAME(name);
663 }
664
665
lookBySignature(symbol name,signature * sig)666 varEntry *venv::lookBySignature(symbol name, signature *sig) {
667 // Rest arguments are complicated and rare. Don't handle them here.
668 if (sig->hasRest())
669 return 0;
670
671 // Likewise with the special operators.
672 if (name.special())
673 return 0;
674
675 namevalue& nv = names[name];
676
677 // Avoid ambiguities with default parameters.
678 if (nv.maxFormals != sig->getNumFormals())
679 return 0;
680
681 // See if this exactly matches a function in the table.
682 varEntry *ve = core.lookupNonSpecial(name, sig);
683
684 if (!ve)
685 return 0;
686
687 // Keyword-only arguments may cause matching to fail.
688 if (ve->getSignature()->numKeywordOnly > 0)
689 return 0;
690
691 // At this point, any function with an equivalent signature will be equal
692 // to the result of the normal overloaded function resolution. We may
693 // safely return it.
694 return ve;
695 }
696
add(venv & source,varEntry * qualifier,coder & c)697 void venv::add(venv& source, varEntry *qualifier, coder &c)
698 {
699 core_venv::const_iterator end = source.core.end();
700 for (core_venv::const_iterator p = source.core.begin(); p != end; ++p)
701 {
702 DEBUG_CACHE_ASSERT(p->filled());
703
704 varEntry *v=p->ent;
705 if (v->checkPerm(READ, c)) {
706 enter(p->name, qualifyVarEntry(qualifier, v));
707 }
708 }
709 }
710
add(symbol src,symbol dest,venv & source,varEntry * qualifier,coder & c)711 bool venv::add(symbol src, symbol dest,
712 venv& source, varEntry *qualifier, coder &c)
713 {
714 ty *t=source.getType(src);
715
716 if (!t)
717 return false;
718
719 if (t->isOverloaded()) {
720 bool added=false;
721 for (ty_iterator i = t->begin(); i != t->end(); ++i)
722 {
723 varEntry *v=source.lookByType(src, *i);
724 if (v->checkPerm(READ, c)) {
725 enter(dest, qualifyVarEntry(qualifier, v));
726 added=true;
727 }
728 }
729 return added;
730 }
731 else {
732 varEntry *v=source.lookByType(src, t);
733 if (v->checkPerm(READ, c)) {
734 enter(dest, qualifyVarEntry(qualifier, v));
735 return true;
736 }
737 return false;
738 }
739 }
740
741
getType(symbol name)742 ty *venv::getType(symbol name)
743 {
744 return names[name].t;
745 }
746
listValue(symbol name,varEntry * v,record * module)747 void listValue(symbol name, varEntry *v, record *module)
748 {
749 if (!module || v->whereDefined() == module)
750 {
751 if (settings::getSetting<bool>("where"))
752 cout << v->getPos();
753
754 v->getType()->printVar(cout, name);
755
756 cout << ";\n";
757 }
758 }
759
listValues(symbol name,record * module)760 void venv::listValues(symbol name, record *module)
761 {
762 ty *t=getType(name);
763
764 if (t->isOverloaded())
765 for (ty_iterator i = t->begin(); i != t->end(); ++i)
766 listValue(name, lookByType(name, *i), module);
767 else
768 listValue(name, lookByType(name, t), module);
769
770 flush(cout);
771 }
772
list(record * module)773 void venv::list(record *module)
774 {
775 // List all functions and variables.
776 for (namemap::iterator N = names.begin(); N != names.end(); ++N)
777 listValues(N->first, module);
778 }
779
completions(mem::list<symbol> & l,string start)780 void venv::completions(mem::list<symbol >& l, string start)
781 {
782 for(namemap::iterator N = names.begin(); N != names.end(); ++N)
783 if (prefix(start, N->first) && N->second.t)
784 l.push_back(N->first);
785 }
786
787 } // namespace trans
788