Merge pull request #523 from amdrexu/feature2
[platform/upstream/glslang.git] / glslang / MachineIndependent / SymbolTable.h
1 //
2 //Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
3 //Copyright (C) 2013 LunarG, Inc.
4 //
5 //All rights reserved.
6 //
7 //Redistribution and use in source and binary forms, with or without
8 //modification, are permitted provided that the following conditions
9 //are met:
10 //
11 //    Redistributions of source code must retain the above copyright
12 //    notice, this list of conditions and the following disclaimer.
13 //
14 //    Redistributions in binary form must reproduce the above
15 //    copyright notice, this list of conditions and the following
16 //    disclaimer in the documentation and/or other materials provided
17 //    with the distribution.
18 //
19 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
20 //    contributors may be used to endorse or promote products derived
21 //    from this software without specific prior written permission.
22 //
23 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 //POSSIBILITY OF SUCH DAMAGE.
35 //
36
37 #ifndef _SYMBOL_TABLE_INCLUDED_
38 #define _SYMBOL_TABLE_INCLUDED_
39
40 //
41 // Symbol table for parsing.  Has these design characteristics:
42 //
43 // * Same symbol table can be used to compile many shaders, to preserve
44 //   effort of creating and loading with the large numbers of built-in
45 //   symbols.
46 //
47 // -->  This requires a copy mechanism, so initial pools used to create
48 //   the shared information can be popped.  Done through "clone"
49 //   methods.
50 //
51 // * Name mangling will be used to give each function a unique name
52 //   so that symbol table lookups are never ambiguous.  This allows
53 //   a simpler symbol table structure.
54 //
55 // * Pushing and popping of scope, so symbol table will really be a stack
56 //   of symbol tables.  Searched from the top, with new inserts going into
57 //   the top.
58 //
59 // * Constants:  Compile time constant symbols will keep their values
60 //   in the symbol table.  The parser can substitute constants at parse
61 //   time, including doing constant folding and constant propagation.
62 //
63 // * No temporaries:  Temporaries made from operations (+, --, .xy, etc.)
64 //   are tracked in the intermediate representation, not the symbol table.
65 //
66
67 #include "../Include/Common.h"
68 #include "../Include/intermediate.h"
69 #include "../Include/InfoSink.h"
70
71 namespace glslang {
72
73 //
74 // Symbol base class.  (Can build functions or variables out of these...)
75 //
76
77 class TVariable;
78 class TFunction;
79 class TAnonMember;
80
81 class TSymbol {
82 public:
83     POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
84     explicit TSymbol(const TString *n) :  name(n), numExtensions(0), extensions(0), writable(true) { }
85     virtual TSymbol* clone() const = 0;
86     virtual ~TSymbol() { }  // rely on all symbol owned memory coming from the pool
87
88     virtual const TString& getName() const { return *name; }
89     virtual void changeName(const TString* newName) { name = newName; }
90     virtual const TString& getMangledName() const { return getName(); }
91     virtual TFunction* getAsFunction() { return 0; }
92     virtual const TFunction* getAsFunction() const { return 0; }
93     virtual TVariable* getAsVariable() { return 0; }
94     virtual const TVariable* getAsVariable() const { return 0; }
95     virtual const TAnonMember* getAsAnonMember() const { return 0; }
96     virtual const TType& getType() const = 0;
97     virtual TType& getWritableType() = 0;
98     virtual void setUniqueId(int id) { uniqueId = id; }
99     virtual int getUniqueId() const { return uniqueId; }
100     virtual void setExtensions(int num, const char* const exts[])
101     {
102         assert(extensions == 0);
103         assert(num > 0);
104         numExtensions = num;
105         extensions = NewPoolObject(exts[0], num);
106         for (int e = 0; e < num; ++e)
107             extensions[e] = exts[e];
108     }
109     virtual int getNumExtensions() const { return numExtensions; }
110     virtual const char** getExtensions() const { return extensions; }
111     virtual void dump(TInfoSink &infoSink) const = 0;
112
113     virtual bool isReadOnly() const { return ! writable; }
114     virtual void makeReadOnly() { writable = false; }
115
116 protected:
117     explicit TSymbol(const TSymbol&);
118     TSymbol& operator=(const TSymbol&);
119
120     const TString *name;
121     unsigned int uniqueId;      // For cross-scope comparing during code generation
122
123     // For tracking what extensions must be present 
124     // (don't use if correct version/profile is present).
125     int numExtensions;
126     const char** extensions; // an array of pointers to existing constant char strings
127
128     //
129     // N.B.: Non-const functions that will be generally used should assert on this,
130     // to avoid overwriting shared symbol-table information.
131     //
132     bool writable;
133 };
134
135 //
136 // Variable class, meaning a symbol that's not a function.
137 //
138 // There could be a separate class hierarchy for Constant variables;
139 // Only one of int, bool, or float, (or none) is correct for
140 // any particular use, but it's easy to do this way, and doesn't
141 // seem worth having separate classes, and "getConst" can't simply return
142 // different values for different types polymorphically, so this is
143 // just simple and pragmatic.
144 //
145 class TVariable : public TSymbol {
146 public:
147     TVariable(const TString *name, const TType& t, bool uT = false )
148         : TSymbol(name), 
149           userType(uT),
150           constSubtree(nullptr),
151           anonId(-1) { type.shallowCopy(t); }
152     virtual TVariable* clone() const;
153     virtual ~TVariable() { }
154
155     virtual TVariable* getAsVariable() { return this; }
156     virtual const TVariable* getAsVariable() const { return this; }
157     virtual const TType& getType() const { return type; }
158     virtual TType& getWritableType() { assert(writable); return type; }
159     virtual bool isUserType() const { return userType; }
160     virtual const TConstUnionArray& getConstArray() const { return constArray; }
161     virtual TConstUnionArray& getWritableConstArray() { assert(writable); return constArray; }
162     virtual void setConstArray(const TConstUnionArray& array) { constArray = array; }
163     virtual void setConstSubtree(TIntermTyped* subtree) { constSubtree = subtree; }
164     virtual TIntermTyped* getConstSubtree() const { return constSubtree; }
165     virtual void setAnonId(int i) { anonId = i; }
166     virtual int getAnonId() const { return anonId; }
167
168     virtual void dump(TInfoSink &infoSink) const;
169
170 protected:
171     explicit TVariable(const TVariable&);
172     TVariable& operator=(const TVariable&);
173
174     TType type;
175     bool userType;
176     // we are assuming that Pool Allocator will free the memory allocated to unionArray
177     // when this object is destroyed
178
179     // TODO: these two should be a union
180     // A variable could be a compile-time constant, or a specialization
181     // constant, or neither, but never both.
182     TConstUnionArray constArray;  // for compile-time constant value
183     TIntermTyped* constSubtree;   // for specialization constant computation
184     int anonId;                   // the ID used for anonymous blocks: TODO: see if uniqueId could serve a dual purpose
185 };
186
187 //
188 // The function sub-class of symbols and the parser will need to
189 // share this definition of a function parameter.
190 //
191 struct TParameter {
192     TString *name;
193     TType* type;
194     void copyParam(const TParameter& param) 
195     {
196         if (param.name)
197             name = NewPoolTString(param.name->c_str());
198         else
199             name = 0;
200         type = param.type->clone();
201     }
202 };
203
204 //
205 // The function sub-class of a symbol.
206 //
207 class TFunction : public TSymbol {
208 public:
209     explicit TFunction(TOperator o) :
210         TSymbol(0),
211         op(o),
212         defined(false), prototyped(false) { }
213     TFunction(const TString *name, const TType& retType, TOperator tOp = EOpNull) :
214         TSymbol(name),
215         mangledName(*name + '('),
216         op(tOp),
217         defined(false), prototyped(false) { returnType.shallowCopy(retType); }
218     virtual TFunction* clone() const;
219     virtual ~TFunction();
220
221     virtual TFunction* getAsFunction() { return this; }
222     virtual const TFunction* getAsFunction() const { return this; }
223
224     virtual void addParameter(TParameter& p)
225     {
226         assert(writable);
227         parameters.push_back(p);
228         p.type->appendMangledName(mangledName);
229     }
230
231     virtual const TString& getMangledName() const { return mangledName; }
232     virtual const TType& getType() const { return returnType; }
233     virtual TType& getWritableType() { return returnType; }
234     virtual void relateToOperator(TOperator o) { assert(writable); op = o; }
235     virtual TOperator getBuiltInOp() const { return op; }
236     virtual void setDefined() { assert(writable); defined = true; }
237     virtual bool isDefined() const { return defined; }
238     virtual void setPrototyped() { assert(writable); prototyped = true; }
239     virtual bool isPrototyped() const { return prototyped; }
240
241     virtual int getParamCount() const { return static_cast<int>(parameters.size()); }
242     virtual TParameter& operator[](int i) { assert(writable); return parameters[i]; }
243     virtual const TParameter& operator[](int i) const { return parameters[i]; }
244
245     virtual void dump(TInfoSink &infoSink) const;
246
247 protected:
248     explicit TFunction(const TFunction&);
249     TFunction& operator=(const TFunction&);
250
251     typedef TVector<TParameter> TParamList;
252     TParamList parameters;
253     TType returnType;
254     TString mangledName;
255     TOperator op;
256     bool defined;
257     bool prototyped;
258 };
259
260 //
261 // Members of anonymous blocks are a kind of TSymbol.  They are not hidden in
262 // the symbol table behind a container; rather they are visible and point to
263 // their anonymous container.  (The anonymous container is found through the
264 // member, not the other way around.)
265 //
266 class TAnonMember : public TSymbol {
267 public:
268     TAnonMember(const TString* n, unsigned int m, const TVariable& a, int an) : TSymbol(n), anonContainer(a), memberNumber(m), anonId(an) { }
269     virtual TAnonMember* clone() const;
270     virtual ~TAnonMember() { }
271
272     virtual const TAnonMember* getAsAnonMember() const { return this; }
273     virtual const TVariable& getAnonContainer() const { return anonContainer; }
274     virtual unsigned int getMemberNumber() const { return memberNumber; }
275     
276     virtual const TType& getType() const
277     {
278         const TTypeList& types = *anonContainer.getType().getStruct();
279         return *types[memberNumber].type;
280     }
281
282     virtual TType& getWritableType()
283     {
284         assert(writable);
285         const TTypeList& types = *anonContainer.getType().getStruct();
286         return *types[memberNumber].type;
287     }
288     
289     virtual int getAnonId() const { return anonId; }
290     virtual void dump(TInfoSink &infoSink) const;
291
292 protected:
293     explicit TAnonMember(const TAnonMember&);
294     TAnonMember& operator=(const TAnonMember&);
295
296     const TVariable& anonContainer;
297     unsigned int memberNumber;
298     int anonId;
299 };
300
301 class TSymbolTableLevel {
302 public:
303     POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
304     TSymbolTableLevel() : defaultPrecision(0), anonId(0) { }
305     ~TSymbolTableLevel();
306
307     bool insert(TSymbol& symbol, bool separateNameSpaces)
308     {
309         //
310         // returning true means symbol was added to the table with no semantic errors
311         //
312         const TString& name = symbol.getName();
313         if (name == "") {
314             symbol.getAsVariable()->setAnonId(anonId++);
315             // An empty name means an anonymous container, exposing its members to the external scope.
316             // Give it a name and insert its members in the symbol table, pointing to the container.
317             char buf[20];
318             snprintf(buf, 20, "%s%d", AnonymousPrefix, symbol.getAsVariable()->getAnonId());
319             symbol.changeName(NewPoolTString(buf));
320
321             return insertAnonymousMembers(symbol, 0);
322         } else {
323             // Check for redefinition errors:
324             // - STL itself will tell us if there is a direct name collision, with name mangling, at this level
325             // - additionally, check for function-redefining-variable name collisions
326             const TString& insertName = symbol.getMangledName();
327             if (symbol.getAsFunction()) {
328                 // make sure there isn't a variable of this name
329                 if (! separateNameSpaces && level.find(name) != level.end())
330                     return false;
331
332                 // insert, and whatever happens is okay
333                 level.insert(tLevelPair(insertName, &symbol));
334
335                 return true;
336             } else
337                 return level.insert(tLevelPair(insertName, &symbol)).second;
338         }
339     }
340
341     // Add more members to an already inserted aggregate object
342     bool amend(TSymbol& symbol, int firstNewMember)
343     {
344         // See insert() for comments on basic explanation of insert.
345         // This operates similarly, but more simply.
346         // Only supporting amend of anonymous blocks so far.
347         if (IsAnonymous(symbol.getName()))
348             return insertAnonymousMembers(symbol, firstNewMember);
349         else
350             return false;
351     }
352
353     bool insertAnonymousMembers(TSymbol& symbol, int firstMember)
354     {
355         const TTypeList& types = *symbol.getAsVariable()->getType().getStruct();
356         for (unsigned int m = firstMember; m < types.size(); ++m) {
357             TAnonMember* member = new TAnonMember(&types[m].type->getFieldName(), m, *symbol.getAsVariable(), symbol.getAsVariable()->getAnonId());
358             if (! level.insert(tLevelPair(member->getMangledName(), member)).second)
359                 return false;
360         }
361
362         return true;
363     }
364
365     TSymbol* find(const TString& name) const
366     {
367         tLevel::const_iterator it = level.find(name);
368         if (it == level.end()) 
369             return 0;
370         else
371             return (*it).second;
372     }
373
374     void findFunctionNameList(const TString& name, TVector<const TFunction*>& list)
375     {
376         size_t parenAt = name.find_first_of('(');
377         TString base(name, 0, parenAt + 1);
378
379         tLevel::const_iterator begin = level.lower_bound(base);
380         base[parenAt] = ')';  // assume ')' is lexically after '('
381         tLevel::const_iterator end = level.upper_bound(base);
382         for (tLevel::const_iterator it = begin; it != end; ++it)
383             list.push_back(it->second->getAsFunction());
384     }
385
386     // See if there is already a function in the table having the given non-function-style name.
387     bool hasFunctionName(const TString& name) const
388     {
389         tLevel::const_iterator candidate = level.lower_bound(name);
390         if (candidate != level.end()) {
391             const TString& candidateName = (*candidate).first;
392             TString::size_type parenAt = candidateName.find_first_of('(');
393             if (parenAt != candidateName.npos && candidateName.compare(0, parenAt, name) == 0)
394
395                 return true;
396         }
397
398         return false;
399     }
400
401     // See if there is a variable at this level having the given non-function-style name.
402     // Return true if name is found, and set variable to true if the name was a variable.
403     bool findFunctionVariableName(const TString& name, bool& variable) const
404     {
405         tLevel::const_iterator candidate = level.lower_bound(name);
406         if (candidate != level.end()) {
407             const TString& candidateName = (*candidate).first;
408             TString::size_type parenAt = candidateName.find_first_of('(');
409             if (parenAt == candidateName.npos) {
410                 // not a mangled name
411                 if (candidateName == name) {
412                     // found a variable name match
413                     variable = true;
414                     return true;
415                 }
416             } else {
417                 // a mangled name
418                 if (candidateName.compare(0, parenAt, name) == 0) {
419                     // found a function name match
420                     variable = false;
421                     return true;
422                 }
423             }
424         }
425
426         return false;
427     }
428
429     // Use this to do a lazy 'push' of precision defaults the first time
430     // a precision statement is seen in a new scope.  Leave it at 0 for
431     // when no push was needed.  Thus, it is not the current defaults,
432     // it is what to restore the defaults to when popping a level.
433     void setPreviousDefaultPrecisions(const TPrecisionQualifier *p)
434     {
435         // can call multiple times at one scope, will only latch on first call,
436         // as we're tracking the previous scope's values, not the current values
437         if (defaultPrecision != 0)
438             return;
439
440         defaultPrecision = new TPrecisionQualifier[EbtNumTypes];
441         for (int t = 0; t < EbtNumTypes; ++t)
442             defaultPrecision[t] = p[t];
443     }
444
445     void getPreviousDefaultPrecisions(TPrecisionQualifier *p)
446     {
447         // can be called for table level pops that didn't set the
448         // defaults
449         if (defaultPrecision == 0 || p == 0)
450             return;
451
452         for (int t = 0; t < EbtNumTypes; ++t)
453             p[t] = defaultPrecision[t];
454     }
455
456     void relateToOperator(const char* name, TOperator op);
457     void setFunctionExtensions(const char* name, int num, const char* const extensions[]);
458     void dump(TInfoSink &infoSink) const;
459     TSymbolTableLevel* clone() const;
460     void readOnly();
461
462 protected:
463     explicit TSymbolTableLevel(TSymbolTableLevel&);
464     TSymbolTableLevel& operator=(TSymbolTableLevel&);
465
466     typedef std::map<TString, TSymbol*, std::less<TString>, pool_allocator<std::pair<const TString, TSymbol*> > > tLevel;
467     typedef const tLevel::value_type tLevelPair;
468     typedef std::pair<tLevel::iterator, bool> tInsertResult;
469
470     tLevel level;  // named mappings
471     TPrecisionQualifier *defaultPrecision;
472     int anonId;
473 };
474
475 class TSymbolTable {
476 public:
477     TSymbolTable() : uniqueId(0), noBuiltInRedeclarations(false), separateNameSpaces(false), adoptedLevels(0)
478     {
479         //
480         // This symbol table cannot be used until push() is called.
481         //
482     }
483     ~TSymbolTable()
484     {
485         // this can be called explicitly; safest to code it so it can be called multiple times
486
487         // don't deallocate levels passed in from elsewhere
488         while (table.size() > adoptedLevels)
489             pop(0);
490     }
491     
492     void adoptLevels(TSymbolTable& symTable)
493     {
494         for (unsigned int level = 0; level < symTable.table.size(); ++level) {
495             table.push_back(symTable.table[level]);
496             ++adoptedLevels;
497         }
498         uniqueId = symTable.uniqueId;
499         noBuiltInRedeclarations = symTable.noBuiltInRedeclarations;
500         separateNameSpaces = symTable.separateNameSpaces;
501     }
502
503     //
504     // While level adopting is generic, the methods below enact a the following
505     // convention for levels:
506     //   0: common built-ins shared across all stages, all compiles, only one copy for all symbol tables
507     //   1: per-stage built-ins, shared across all compiles, but a different copy per stage
508     //   2: built-ins specific to a compile, like resources that are context-dependent, or redeclared built-ins
509     //   3: user-shader globals
510     //
511 protected:
512     static const int globalLevel = 3;
513     bool isSharedLevel(int level)  { return level <= 1; }              // exclude all per-compile levels
514     bool isBuiltInLevel(int level) { return level <= 2; }              // exclude user globals
515     bool isGlobalLevel(int level)  { return level <= globalLevel; }    // include user globals
516 public:
517     bool isEmpty() { return table.size() == 0; }
518     bool atBuiltInLevel() { return isBuiltInLevel(currentLevel()); }
519     bool atGlobalLevel()  { return isGlobalLevel(currentLevel()); }
520
521     void setNoBuiltInRedeclarations() { noBuiltInRedeclarations = true; }
522     void setSeparateNameSpaces() { separateNameSpaces = true; }
523     
524     void push()
525     {
526         table.push_back(new TSymbolTableLevel);
527     }
528
529     void pop(TPrecisionQualifier *p)
530     {
531         table[currentLevel()]->getPreviousDefaultPrecisions(p);
532         delete table.back();
533         table.pop_back();
534     }
535
536     //
537     // Insert a visible symbol into the symbol table so it can
538     // be found later by name.
539     //
540     // Returns false if the was a name collision.
541     //
542     bool insert(TSymbol& symbol)
543     {
544         symbol.setUniqueId(++uniqueId);
545
546         // make sure there isn't a function of this variable name
547         if (! separateNameSpaces && ! symbol.getAsFunction() && table[currentLevel()]->hasFunctionName(symbol.getName()))
548             return false;
549             
550         // check for not overloading or redefining a built-in function
551         if (noBuiltInRedeclarations) {
552             if (atGlobalLevel() && currentLevel() > 0) {
553                 if (table[0]->hasFunctionName(symbol.getName()))
554                     return false;
555                 if (currentLevel() > 1 && table[1]->hasFunctionName(symbol.getName()))
556                     return false;
557             }
558         }
559
560         return table[currentLevel()]->insert(symbol, separateNameSpaces);
561     }
562
563     // Add more members to an already inserted aggregate object
564     bool amend(TSymbol& symbol, int firstNewMember)
565     {
566         // See insert() for comments on basic explanation of insert.
567         // This operates similarly, but more simply.
568         return table[currentLevel()]->amend(symbol, firstNewMember);
569     }
570
571     //
572     // To allocate an internal temporary, which will need to be uniquely
573     // identified by the consumer of the AST, but never need to 
574     // found by doing a symbol table search by name, hence allowed an
575     // arbitrary name in the symbol with no worry of collision.
576     //
577     void makeInternalVariable(TSymbol& symbol)
578     {
579         symbol.setUniqueId(++uniqueId);
580     }
581
582     //
583     // Copy a variable or anonymous member's structure from a shared level so that
584     // it can be added (soon after return) to the symbol table where it can be
585     // modified without impacting other users of the shared table.
586     //
587     TSymbol* copyUpDeferredInsert(TSymbol* shared)
588     {
589         if (shared->getAsVariable()) {
590             TSymbol* copy = shared->clone();
591             copy->setUniqueId(shared->getUniqueId());
592             return copy;
593         } else {
594             const TAnonMember* anon = shared->getAsAnonMember();
595             assert(anon);
596             TVariable* container = anon->getAnonContainer().clone();
597             container->changeName(NewPoolTString(""));
598             container->setUniqueId(anon->getAnonContainer().getUniqueId());
599             return container;
600         }
601     }
602
603     TSymbol* copyUp(TSymbol* shared)
604     {
605         TSymbol* copy = copyUpDeferredInsert(shared);
606         table[globalLevel]->insert(*copy, separateNameSpaces);
607         if (shared->getAsVariable())
608             return copy;
609         else {
610             // return the copy of the anonymous member
611             return table[globalLevel]->find(shared->getName());
612         }
613     }
614
615     TSymbol* find(const TString& name, bool* builtIn = 0, bool *currentScope = 0)
616     {
617         int level = currentLevel();
618         TSymbol* symbol;
619         do {
620             symbol = table[level]->find(name);
621             --level;
622         } while (symbol == 0 && level >= 0);
623         level++;
624         if (builtIn)
625             *builtIn = isBuiltInLevel(level);
626         if (currentScope)
627             *currentScope = isGlobalLevel(currentLevel()) || level == currentLevel();  // consider shared levels as "current scope" WRT user globals
628
629         return symbol;
630     }
631
632     bool isFunctionNameVariable(const TString& name) const
633     {
634         if (separateNameSpaces)
635             return false;
636
637         int level = currentLevel();
638         do {
639             bool variable;
640             bool found = table[level]->findFunctionVariableName(name, variable);
641             if (found)
642                 return variable;
643             --level;
644         } while (level >= 0);
645
646         return false;
647     }
648
649     void findFunctionNameList(const TString& name, TVector<const TFunction*>& list, bool& builtIn)
650     {
651         // For user levels, return the set found in the first scope with a match
652         builtIn = false;
653         int level = currentLevel();
654         do {
655             table[level]->findFunctionNameList(name, list);
656             --level;
657         } while (list.empty() && level >= globalLevel);
658
659         if (! list.empty())
660             return;
661
662         // Gather across all built-in levels; they don't hide each other
663         builtIn = true;
664         do {
665             table[level]->findFunctionNameList(name, list);
666             --level;
667         } while (level >= 0);
668     }
669
670     void relateToOperator(const char* name, TOperator op)
671     {
672         for (unsigned int level = 0; level < table.size(); ++level)
673             table[level]->relateToOperator(name, op);
674     }
675     
676     void setFunctionExtensions(const char* name, int num, const char* const extensions[])
677     {
678         for (unsigned int level = 0; level < table.size(); ++level)
679             table[level]->setFunctionExtensions(name, num, extensions);
680     }
681
682     void setVariableExtensions(const char* name, int num, const char* const extensions[])
683     {
684         TSymbol* symbol = find(TString(name));
685         if (symbol)
686             symbol->setExtensions(num, extensions);
687     }
688
689     int getMaxSymbolId() { return uniqueId; }
690     void dump(TInfoSink &infoSink) const;
691     void copyTable(const TSymbolTable& copyOf);
692
693     void setPreviousDefaultPrecisions(TPrecisionQualifier *p) { table[currentLevel()]->setPreviousDefaultPrecisions(p); }
694
695     void readOnly()
696     {
697         for (unsigned int level = 0; level < table.size(); ++level)
698             table[level]->readOnly();
699     }
700
701 protected:
702     TSymbolTable(TSymbolTable&);
703     TSymbolTable& operator=(TSymbolTableLevel&);
704
705     int currentLevel() const { return static_cast<int>(table.size()) - 1; }
706
707     std::vector<TSymbolTableLevel*> table;
708     int uniqueId;     // for unique identification in code generation
709     bool noBuiltInRedeclarations;
710     bool separateNameSpaces;
711     unsigned int adoptedLevels;
712 };
713
714 } // end namespace glslang
715
716 #endif // _SYMBOL_TABLE_INCLUDED_