• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
3 // Copyright (C) 2013 LunarG, Inc.
4 // Copyright (C) 2015-2018 Google, Inc.
5 //
6 // All rights reserved.
7 //
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions
10 // are met:
11 //
12 //    Redistributions of source code must retain the above copyright
13 //    notice, this list of conditions and the following disclaimer.
14 //
15 //    Redistributions in binary form must reproduce the above
16 //    copyright notice, this list of conditions and the following
17 //    disclaimer in the documentation and/or other materials provided
18 //    with the distribution.
19 //
20 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
21 //    contributors may be used to endorse or promote products derived
22 //    from this software without specific prior written permission.
23 //
24 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 // POSSIBILITY OF SUCH DAMAGE.
36 //
37 
38 #ifndef _SYMBOL_TABLE_INCLUDED_
39 #define _SYMBOL_TABLE_INCLUDED_
40 
41 //
42 // Symbol table for parsing.  Has these design characteristics:
43 //
44 // * Same symbol table can be used to compile many shaders, to preserve
45 //   effort of creating and loading with the large numbers of built-in
46 //   symbols.
47 //
48 // -->  This requires a copy mechanism, so initial pools used to create
49 //   the shared information can be popped.  Done through "clone"
50 //   methods.
51 //
52 // * Name mangling will be used to give each function a unique name
53 //   so that symbol table lookups are never ambiguous.  This allows
54 //   a simpler symbol table structure.
55 //
56 // * Pushing and popping of scope, so symbol table will really be a stack
57 //   of symbol tables.  Searched from the top, with new inserts going into
58 //   the top.
59 //
60 // * Constants:  Compile time constant symbols will keep their values
61 //   in the symbol table.  The parser can substitute constants at parse
62 //   time, including doing constant folding and constant propagation.
63 //
64 // * No temporaries:  Temporaries made from operations (+, --, .xy, etc.)
65 //   are tracked in the intermediate representation, not the symbol table.
66 //
67 
68 #include "../Include/Common.h"
69 #include "../Include/intermediate.h"
70 #include "../Include/InfoSink.h"
71 
72 namespace glslang {
73 
74 //
75 // Symbol base class.  (Can build functions or variables out of these...)
76 //
77 
78 class TVariable;
79 class TFunction;
80 class TAnonMember;
81 
82 typedef TVector<const char*> TExtensionList;
83 
84 class TSymbol {
85 public:
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator ())86     POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
87     explicit TSymbol(const TString *n) :  name(n), uniqueId(0), extensions(nullptr), writable(true) { }
88     virtual TSymbol* clone() const = 0;
~TSymbol()89     virtual ~TSymbol() { }  // rely on all symbol owned memory coming from the pool
90 
getName()91     virtual const TString& getName() const { return *name; }
changeName(const TString * newName)92     virtual void changeName(const TString* newName) { name = newName; }
addPrefix(const char * prefix)93     virtual void addPrefix(const char* prefix)
94     {
95         TString newName(prefix);
96         newName.append(*name);
97         changeName(NewPoolTString(newName.c_str()));
98     }
getMangledName()99     virtual const TString& getMangledName() const { return getName(); }
getAsFunction()100     virtual TFunction* getAsFunction() { return nullptr; }
getAsFunction()101     virtual const TFunction* getAsFunction() const { return nullptr; }
getAsVariable()102     virtual TVariable* getAsVariable() { return nullptr; }
getAsVariable()103     virtual const TVariable* getAsVariable() const { return nullptr; }
getAsAnonMember()104     virtual const TAnonMember* getAsAnonMember() const { return nullptr; }
105     virtual const TType& getType() const = 0;
106     virtual TType& getWritableType() = 0;
setUniqueId(long long id)107     virtual void setUniqueId(long long id) { uniqueId = id; }
getUniqueId()108     virtual long long getUniqueId() const { return uniqueId; }
setExtensions(int numExts,const char * const exts[])109     virtual void setExtensions(int numExts, const char* const exts[])
110     {
111         assert(extensions == nullptr);
112         assert(numExts > 0);
113         extensions = NewPoolObject(extensions);
114         for (int e = 0; e < numExts; ++e)
115             extensions->push_back(exts[e]);
116     }
getNumExtensions()117     virtual int getNumExtensions() const { return extensions == nullptr ? 0 : (int)extensions->size(); }
getExtensions()118     virtual const char** getExtensions() const { return extensions->data(); }
119 
120 #if !defined(GLSLANG_WEB)
121     virtual void dump(TInfoSink& infoSink, bool complete = false) const = 0;
122     void dumpExtensions(TInfoSink& infoSink) const;
123 #endif
124 
isReadOnly()125     virtual bool isReadOnly() const { return ! writable; }
makeReadOnly()126     virtual void makeReadOnly() { writable = false; }
127 
128 protected:
129     explicit TSymbol(const TSymbol&);
130     TSymbol& operator=(const TSymbol&);
131 
132     const TString *name;
133     unsigned long long uniqueId;      // For cross-scope comparing during code generation
134 
135     // For tracking what extensions must be present
136     // (don't use if correct version/profile is present).
137     TExtensionList* extensions; // an array of pointers to existing constant char strings
138 
139     //
140     // N.B.: Non-const functions that will be generally used should assert on this,
141     // to avoid overwriting shared symbol-table information.
142     //
143     bool writable;
144 };
145 
146 //
147 // Variable class, meaning a symbol that's not a function.
148 //
149 // There could be a separate class hierarchy for Constant variables;
150 // Only one of int, bool, or float, (or none) is correct for
151 // any particular use, but it's easy to do this way, and doesn't
152 // seem worth having separate classes, and "getConst" can't simply return
153 // different values for different types polymorphically, so this is
154 // just simple and pragmatic.
155 //
156 class TVariable : public TSymbol {
157 public:
158     TVariable(const TString *name, const TType& t, bool uT = false )
TSymbol(name)159         : TSymbol(name),
160           userType(uT),
161           constSubtree(nullptr),
162           memberExtensions(nullptr),
163           anonId(-1)
164         { type.shallowCopy(t); }
165     virtual TVariable* clone() const;
~TVariable()166     virtual ~TVariable() { }
167 
getAsVariable()168     virtual TVariable* getAsVariable() { return this; }
getAsVariable()169     virtual const TVariable* getAsVariable() const { return this; }
getType()170     virtual const TType& getType() const { return type; }
getWritableType()171     virtual TType& getWritableType() { assert(writable); return type; }
isUserType()172     virtual bool isUserType() const { return userType; }
getConstArray()173     virtual const TConstUnionArray& getConstArray() const { return constArray; }
getWritableConstArray()174     virtual TConstUnionArray& getWritableConstArray() { assert(writable); return constArray; }
setConstArray(const TConstUnionArray & array)175     virtual void setConstArray(const TConstUnionArray& array) { constArray = array; }
setConstSubtree(TIntermTyped * subtree)176     virtual void setConstSubtree(TIntermTyped* subtree) { constSubtree = subtree; }
getConstSubtree()177     virtual TIntermTyped* getConstSubtree() const { return constSubtree; }
setAnonId(int i)178     virtual void setAnonId(int i) { anonId = i; }
getAnonId()179     virtual int getAnonId() const { return anonId; }
180 
setMemberExtensions(int member,int numExts,const char * const exts[])181     virtual void setMemberExtensions(int member, int numExts, const char* const exts[])
182     {
183         assert(type.isStruct());
184         assert(numExts > 0);
185         if (memberExtensions == nullptr) {
186             memberExtensions = NewPoolObject(memberExtensions);
187             memberExtensions->resize(type.getStruct()->size());
188         }
189         for (int e = 0; e < numExts; ++e)
190             (*memberExtensions)[member].push_back(exts[e]);
191     }
hasMemberExtensions()192     virtual bool hasMemberExtensions() const { return memberExtensions != nullptr; }
getNumMemberExtensions(int member)193     virtual int getNumMemberExtensions(int member) const
194     {
195         return memberExtensions == nullptr ? 0 : (int)(*memberExtensions)[member].size();
196     }
getMemberExtensions(int member)197     virtual const char** getMemberExtensions(int member) const { return (*memberExtensions)[member].data(); }
198 
199 #if !defined(GLSLANG_WEB)
200     virtual void dump(TInfoSink& infoSink, bool complete = false) const;
201 #endif
202 
203 protected:
204     explicit TVariable(const TVariable&);
205     TVariable& operator=(const TVariable&);
206 
207     TType type;
208     bool userType;
209 
210     // we are assuming that Pool Allocator will free the memory allocated to unionArray
211     // when this object is destroyed
212 
213     TConstUnionArray constArray;               // for compile-time constant value
214     TIntermTyped* constSubtree;                // for specialization constant computation
215     TVector<TExtensionList>* memberExtensions; // per-member extension list, allocated only when needed
216     int anonId; // the ID used for anonymous blocks: TODO: see if uniqueId could serve a dual purpose
217 };
218 
219 //
220 // The function sub-class of symbols and the parser will need to
221 // share this definition of a function parameter.
222 //
223 struct TParameter {
224     TString *name;
225     TType* type;
226     TIntermTyped* defaultValue;
copyParamTParameter227     TParameter& copyParam(const TParameter& param)
228     {
229         if (param.name)
230             name = NewPoolTString(param.name->c_str());
231         else
232             name = nullptr;
233         type = param.type->clone();
234         defaultValue = param.defaultValue;
235         return *this;
236     }
getDeclaredBuiltInTParameter237     TBuiltInVariable getDeclaredBuiltIn() const { return type->getQualifier().declaredBuiltIn; }
238 };
239 
240 //
241 // The function sub-class of a symbol.
242 //
243 class TFunction : public TSymbol {
244 public:
TFunction(TOperator o)245     explicit TFunction(TOperator o) :
246         TSymbol(nullptr),
247         op(o),
248         defined(false), prototyped(false), implicitThis(false), illegalImplicitThis(false), defaultParamCount(0) { }
249     TFunction(const TString *name, const TType& retType, TOperator tOp = EOpNull) :
TSymbol(name)250         TSymbol(name),
251         mangledName(*name + '('),
252         op(tOp),
253         defined(false), prototyped(false), implicitThis(false), illegalImplicitThis(false), defaultParamCount(0)
254     {
255         returnType.shallowCopy(retType);
256         declaredBuiltIn = retType.getQualifier().builtIn;
257     }
258     virtual TFunction* clone() const override;
259     virtual ~TFunction();
260 
getAsFunction()261     virtual TFunction* getAsFunction() override { return this; }
getAsFunction()262     virtual const TFunction* getAsFunction() const override { return this; }
263 
264     // Install 'p' as the (non-'this') last parameter.
265     // Non-'this' parameters are reflected in both the list of parameters and the
266     // mangled name.
addParameter(TParameter & p)267     virtual void addParameter(TParameter& p)
268     {
269         assert(writable);
270         parameters.push_back(p);
271         p.type->appendMangledName(mangledName);
272 
273         if (p.defaultValue != nullptr)
274             defaultParamCount++;
275     }
276 
277     // Install 'this' as the first parameter.
278     // 'this' is reflected in the list of parameters, but not the mangled name.
addThisParameter(TType & type,const char * name)279     virtual void addThisParameter(TType& type, const char* name)
280     {
281         TParameter p = { NewPoolTString(name), new TType, nullptr };
282         p.type->shallowCopy(type);
283         parameters.insert(parameters.begin(), p);
284     }
285 
addPrefix(const char * prefix)286     virtual void addPrefix(const char* prefix) override
287     {
288         TSymbol::addPrefix(prefix);
289         mangledName.insert(0, prefix);
290     }
291 
removePrefix(const TString & prefix)292     virtual void removePrefix(const TString& prefix)
293     {
294         assert(mangledName.compare(0, prefix.size(), prefix) == 0);
295         mangledName.erase(0, prefix.size());
296     }
297 
getMangledName()298     virtual const TString& getMangledName() const override { return mangledName; }
getType()299     virtual const TType& getType() const override { return returnType; }
getDeclaredBuiltInType()300     virtual TBuiltInVariable getDeclaredBuiltInType() const { return declaredBuiltIn; }
getWritableType()301     virtual TType& getWritableType() override { return returnType; }
relateToOperator(TOperator o)302     virtual void relateToOperator(TOperator o) { assert(writable); op = o; }
getBuiltInOp()303     virtual TOperator getBuiltInOp() const { return op; }
setDefined()304     virtual void setDefined() { assert(writable); defined = true; }
isDefined()305     virtual bool isDefined() const { return defined; }
setPrototyped()306     virtual void setPrototyped() { assert(writable); prototyped = true; }
isPrototyped()307     virtual bool isPrototyped() const { return prototyped; }
setImplicitThis()308     virtual void setImplicitThis() { assert(writable); implicitThis = true; }
hasImplicitThis()309     virtual bool hasImplicitThis() const { return implicitThis; }
setIllegalImplicitThis()310     virtual void setIllegalImplicitThis() { assert(writable); illegalImplicitThis = true; }
hasIllegalImplicitThis()311     virtual bool hasIllegalImplicitThis() const { return illegalImplicitThis; }
312 
313     // Return total number of parameters
getParamCount()314     virtual int getParamCount() const { return static_cast<int>(parameters.size()); }
315     // Return number of parameters with default values.
getDefaultParamCount()316     virtual int getDefaultParamCount() const { return defaultParamCount; }
317     // Return number of fixed parameters (without default values)
getFixedParamCount()318     virtual int getFixedParamCount() const { return getParamCount() - getDefaultParamCount(); }
319 
320     virtual TParameter& operator[](int i) { assert(writable); return parameters[i]; }
321     virtual const TParameter& operator[](int i) const { return parameters[i]; }
322 
323 #ifndef GLSLANG_WEB
setSpirvInstruction(const TSpirvInstruction & inst)324     virtual void setSpirvInstruction(const TSpirvInstruction& inst)
325     {
326         relateToOperator(EOpSpirvInst);
327         spirvInst = inst;
328     }
getSpirvInstruction()329     virtual const TSpirvInstruction& getSpirvInstruction() const { return spirvInst; }
330 #endif
331 
332 #if !defined(GLSLANG_WEB)
333     virtual void dump(TInfoSink& infoSink, bool complete = false) const override;
334 #endif
335 
336 protected:
337     explicit TFunction(const TFunction&);
338     TFunction& operator=(const TFunction&);
339 
340     typedef TVector<TParameter> TParamList;
341     TParamList parameters;
342     TType returnType;
343     TBuiltInVariable declaredBuiltIn;
344 
345     TString mangledName;
346     TOperator op;
347     bool defined;
348     bool prototyped;
349     bool implicitThis;         // True if this function is allowed to see all members of 'this'
350     bool illegalImplicitThis;  // True if this function is not supposed to have access to dynamic members of 'this',
351                                // even if it finds member variables in the symbol table.
352                                // This is important for a static member function that has member variables in scope,
353                                // but is not allowed to use them, or see hidden symbols instead.
354     int  defaultParamCount;
355 
356 #ifndef GLSLANG_WEB
357     TSpirvInstruction spirvInst; // SPIR-V instruction qualifiers
358 #endif
359 };
360 
361 //
362 // Members of anonymous blocks are a kind of TSymbol.  They are not hidden in
363 // the symbol table behind a container; rather they are visible and point to
364 // their anonymous container.  (The anonymous container is found through the
365 // member, not the other way around.)
366 //
367 class TAnonMember : public TSymbol {
368 public:
TAnonMember(const TString * n,unsigned int m,TVariable & a,int an)369     TAnonMember(const TString* n, unsigned int m, TVariable& a, int an) : TSymbol(n), anonContainer(a), memberNumber(m), anonId(an) { }
370     virtual TAnonMember* clone() const override;
~TAnonMember()371     virtual ~TAnonMember() { }
372 
getAsAnonMember()373     virtual const TAnonMember* getAsAnonMember() const override { return this; }
getAnonContainer()374     virtual const TVariable& getAnonContainer() const { return anonContainer; }
getMemberNumber()375     virtual unsigned int getMemberNumber() const { return memberNumber; }
376 
getType()377     virtual const TType& getType() const override
378     {
379         const TTypeList& types = *anonContainer.getType().getStruct();
380         return *types[memberNumber].type;
381     }
382 
getWritableType()383     virtual TType& getWritableType() override
384     {
385         assert(writable);
386         const TTypeList& types = *anonContainer.getType().getStruct();
387         return *types[memberNumber].type;
388     }
389 
setExtensions(int numExts,const char * const exts[])390     virtual void setExtensions(int numExts, const char* const exts[]) override
391     {
392         anonContainer.setMemberExtensions(memberNumber, numExts, exts);
393     }
getNumExtensions()394     virtual int getNumExtensions() const override { return anonContainer.getNumMemberExtensions(memberNumber); }
getExtensions()395     virtual const char** getExtensions() const override { return anonContainer.getMemberExtensions(memberNumber); }
396 
getAnonId()397     virtual int getAnonId() const { return anonId; }
398 #if !defined(GLSLANG_WEB)
399     virtual void dump(TInfoSink& infoSink, bool complete = false) const override;
400 #endif
401 
402 protected:
403     explicit TAnonMember(const TAnonMember&);
404     TAnonMember& operator=(const TAnonMember&);
405 
406     TVariable& anonContainer;
407     unsigned int memberNumber;
408     int anonId;
409 };
410 
411 class TSymbolTableLevel {
412 public:
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator ())413     POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
414     TSymbolTableLevel() : defaultPrecision(nullptr), anonId(0), thisLevel(false) { }
415     ~TSymbolTableLevel();
416 
insert(const TString & name,TSymbol * symbol)417     bool insert(const TString& name, TSymbol* symbol) {
418         return level.insert(tLevelPair(name, symbol)).second;
419     }
420 
421     bool insert(TSymbol& symbol, bool separateNameSpaces, const TString& forcedKeyName = TString())
422     {
423         //
424         // returning true means symbol was added to the table with no semantic errors
425         //
426         const TString& name = symbol.getName();
427         if (forcedKeyName.length()) {
428             return level.insert(tLevelPair(forcedKeyName, &symbol)).second;
429         }
430         else if (name == "") {
431             symbol.getAsVariable()->setAnonId(anonId++);
432             // An empty name means an anonymous container, exposing its members to the external scope.
433             // Give it a name and insert its members in the symbol table, pointing to the container.
434             char buf[20];
435             snprintf(buf, 20, "%s%d", AnonymousPrefix, symbol.getAsVariable()->getAnonId());
436             symbol.changeName(NewPoolTString(buf));
437 
438             return insertAnonymousMembers(symbol, 0);
439         } else {
440             // Check for redefinition errors:
441             // - STL itself will tell us if there is a direct name collision, with name mangling, at this level
442             // - additionally, check for function-redefining-variable name collisions
443             const TString& insertName = symbol.getMangledName();
444             if (symbol.getAsFunction()) {
445                 // make sure there isn't a variable of this name
446                 if (! separateNameSpaces && level.find(name) != level.end())
447                     return false;
448 
449                 // insert, and whatever happens is okay
450                 level.insert(tLevelPair(insertName, &symbol));
451 
452                 return true;
453             } else
454                 return level.insert(tLevelPair(insertName, &symbol)).second;
455         }
456     }
457 
458     // Add more members to an already inserted aggregate object
amend(TSymbol & symbol,int firstNewMember)459     bool amend(TSymbol& symbol, int firstNewMember)
460     {
461         // See insert() for comments on basic explanation of insert.
462         // This operates similarly, but more simply.
463         // Only supporting amend of anonymous blocks so far.
464         if (IsAnonymous(symbol.getName()))
465             return insertAnonymousMembers(symbol, firstNewMember);
466         else
467             return false;
468     }
469 
insertAnonymousMembers(TSymbol & symbol,int firstMember)470     bool insertAnonymousMembers(TSymbol& symbol, int firstMember)
471     {
472         const TTypeList& types = *symbol.getAsVariable()->getType().getStruct();
473         for (unsigned int m = firstMember; m < types.size(); ++m) {
474             TAnonMember* member = new TAnonMember(&types[m].type->getFieldName(), m, *symbol.getAsVariable(), symbol.getAsVariable()->getAnonId());
475             if (! level.insert(tLevelPair(member->getMangledName(), member)).second)
476                 return false;
477         }
478 
479         return true;
480     }
481 
retargetSymbol(const TString & from,const TString & to)482     void retargetSymbol(const TString& from, const TString& to) {
483         tLevel::const_iterator fromIt = level.find(from);
484         tLevel::const_iterator toIt = level.find(to);
485         if (fromIt == level.end() || toIt == level.end())
486             return;
487         delete fromIt->second;
488         level[from] = toIt->second;
489         retargetedSymbols.push_back({from, to});
490     }
491 
find(const TString & name)492     TSymbol* find(const TString& name) const
493     {
494         tLevel::const_iterator it = level.find(name);
495         if (it == level.end())
496             return nullptr;
497         else
498             return (*it).second;
499     }
500 
findFunctionNameList(const TString & name,TVector<const TFunction * > & list)501     void findFunctionNameList(const TString& name, TVector<const TFunction*>& list)
502     {
503         size_t parenAt = name.find_first_of('(');
504         TString base(name, 0, parenAt + 1);
505 
506         tLevel::const_iterator begin = level.lower_bound(base);
507         base[parenAt] = ')';  // assume ')' is lexically after '('
508         tLevel::const_iterator end = level.upper_bound(base);
509         for (tLevel::const_iterator it = begin; it != end; ++it)
510             list.push_back(it->second->getAsFunction());
511     }
512 
513     // See if there is already a function in the table having the given non-function-style name.
hasFunctionName(const TString & name)514     bool hasFunctionName(const TString& name) const
515     {
516         tLevel::const_iterator candidate = level.lower_bound(name);
517         if (candidate != level.end()) {
518             const TString& candidateName = (*candidate).first;
519             TString::size_type parenAt = candidateName.find_first_of('(');
520             if (parenAt != candidateName.npos && candidateName.compare(0, parenAt, name) == 0)
521 
522                 return true;
523         }
524 
525         return false;
526     }
527 
528     // See if there is a variable at this level having the given non-function-style name.
529     // Return true if name is found, and set variable to true if the name was a variable.
findFunctionVariableName(const TString & name,bool & variable)530     bool findFunctionVariableName(const TString& name, bool& variable) const
531     {
532         tLevel::const_iterator candidate = level.lower_bound(name);
533         if (candidate != level.end()) {
534             const TString& candidateName = (*candidate).first;
535             TString::size_type parenAt = candidateName.find_first_of('(');
536             if (parenAt == candidateName.npos) {
537                 // not a mangled name
538                 if (candidateName == name) {
539                     // found a variable name match
540                     variable = true;
541                     return true;
542                 }
543             } else {
544                 // a mangled name
545                 if (candidateName.compare(0, parenAt, name) == 0) {
546                     // found a function name match
547                     variable = false;
548                     return true;
549                 }
550             }
551         }
552 
553         return false;
554     }
555 
556     // Use this to do a lazy 'push' of precision defaults the first time
557     // a precision statement is seen in a new scope.  Leave it at 0 for
558     // when no push was needed.  Thus, it is not the current defaults,
559     // it is what to restore the defaults to when popping a level.
setPreviousDefaultPrecisions(const TPrecisionQualifier * p)560     void setPreviousDefaultPrecisions(const TPrecisionQualifier *p)
561     {
562         // can call multiple times at one scope, will only latch on first call,
563         // as we're tracking the previous scope's values, not the current values
564         if (defaultPrecision != nullptr)
565             return;
566 
567         defaultPrecision = new TPrecisionQualifier[EbtNumTypes];
568         for (int t = 0; t < EbtNumTypes; ++t)
569             defaultPrecision[t] = p[t];
570     }
571 
getPreviousDefaultPrecisions(TPrecisionQualifier * p)572     void getPreviousDefaultPrecisions(TPrecisionQualifier *p)
573     {
574         // can be called for table level pops that didn't set the
575         // defaults
576         if (defaultPrecision == nullptr || p == nullptr)
577             return;
578 
579         for (int t = 0; t < EbtNumTypes; ++t)
580             p[t] = defaultPrecision[t];
581     }
582 
583     void relateToOperator(const char* name, TOperator op);
584     void setFunctionExtensions(const char* name, int num, const char* const extensions[]);
585 #if !defined(GLSLANG_WEB)
586     void dump(TInfoSink& infoSink, bool complete = false) const;
587 #endif
588     TSymbolTableLevel* clone() const;
589     void readOnly();
590 
setThisLevel()591     void setThisLevel() { thisLevel = true; }
isThisLevel()592     bool isThisLevel() const { return thisLevel; }
593 
594 protected:
595     explicit TSymbolTableLevel(TSymbolTableLevel&);
596     TSymbolTableLevel& operator=(TSymbolTableLevel&);
597 
598     typedef std::map<TString, TSymbol*, std::less<TString>, pool_allocator<std::pair<const TString, TSymbol*> > > tLevel;
599     typedef const tLevel::value_type tLevelPair;
600     typedef std::pair<tLevel::iterator, bool> tInsertResult;
601 
602     tLevel level;  // named mappings
603     TPrecisionQualifier *defaultPrecision;
604     // pair<FromName, ToName>
605     TVector<std::pair<TString, TString>> retargetedSymbols;
606     int anonId;
607     bool thisLevel;  // True if this level of the symbol table is a structure scope containing member function
608                      // that are supposed to see anonymous access to member variables.
609 };
610 
611 class TSymbolTable {
612 public:
TSymbolTable()613     TSymbolTable() : uniqueId(0), noBuiltInRedeclarations(false), separateNameSpaces(false), adoptedLevels(0)
614     {
615         //
616         // This symbol table cannot be used until push() is called.
617         //
618     }
~TSymbolTable()619     ~TSymbolTable()
620     {
621         // this can be called explicitly; safest to code it so it can be called multiple times
622 
623         // don't deallocate levels passed in from elsewhere
624         while (table.size() > adoptedLevels)
625             pop(nullptr);
626     }
627 
adoptLevels(TSymbolTable & symTable)628     void adoptLevels(TSymbolTable& symTable)
629     {
630         for (unsigned int level = 0; level < symTable.table.size(); ++level) {
631             table.push_back(symTable.table[level]);
632             ++adoptedLevels;
633         }
634         uniqueId = symTable.uniqueId;
635         noBuiltInRedeclarations = symTable.noBuiltInRedeclarations;
636         separateNameSpaces = symTable.separateNameSpaces;
637     }
638 
639     //
640     // While level adopting is generic, the methods below enact a the following
641     // convention for levels:
642     //   0: common built-ins shared across all stages, all compiles, only one copy for all symbol tables
643     //   1: per-stage built-ins, shared across all compiles, but a different copy per stage
644     //   2: built-ins specific to a compile, like resources that are context-dependent, or redeclared built-ins
645     //   3: user-shader globals
646     //
647 protected:
648     static const uint32_t LevelFlagBitOffset = 56;
649     static const int globalLevel = 3;
isSharedLevel(int level)650     static bool isSharedLevel(int level)  { return level <= 1; }            // exclude all per-compile levels
isBuiltInLevel(int level)651     static bool isBuiltInLevel(int level) { return level <= 2; }            // exclude user globals
isGlobalLevel(int level)652     static bool isGlobalLevel(int level)  { return level <= globalLevel; }  // include user globals
653 public:
isEmpty()654     bool isEmpty() { return table.size() == 0; }
atBuiltInLevel()655     bool atBuiltInLevel() { return isBuiltInLevel(currentLevel()); }
atGlobalLevel()656     bool atGlobalLevel()  { return isGlobalLevel(currentLevel()); }
isBuiltInSymbol(long long uniqueId)657     static bool isBuiltInSymbol(long long uniqueId) {
658         int level = static_cast<int>(uniqueId >> LevelFlagBitOffset);
659         return isBuiltInLevel(level);
660     }
661     static constexpr uint64_t uniqueIdMask = (1LL << LevelFlagBitOffset) - 1;
662     static const uint32_t MaxLevelInUniqueID = 127;
setNoBuiltInRedeclarations()663     void setNoBuiltInRedeclarations() { noBuiltInRedeclarations = true; }
setSeparateNameSpaces()664     void setSeparateNameSpaces() { separateNameSpaces = true; }
665 
push()666     void push()
667     {
668         table.push_back(new TSymbolTableLevel);
669         updateUniqueIdLevelFlag();
670     }
671 
672     // Make a new symbol-table level to represent the scope introduced by a structure
673     // containing member functions, such that the member functions can find anonymous
674     // references to member variables.
675     //
676     // 'thisSymbol' should have a name of "" to trigger anonymous structure-member
677     // symbol finds.
pushThis(TSymbol & thisSymbol)678     void pushThis(TSymbol& thisSymbol)
679     {
680         assert(thisSymbol.getName().size() == 0);
681         table.push_back(new TSymbolTableLevel);
682         updateUniqueIdLevelFlag();
683         table.back()->setThisLevel();
684         insert(thisSymbol);
685     }
686 
pop(TPrecisionQualifier * p)687     void pop(TPrecisionQualifier *p)
688     {
689         table[currentLevel()]->getPreviousDefaultPrecisions(p);
690         delete table.back();
691         table.pop_back();
692         updateUniqueIdLevelFlag();
693     }
694 
695     //
696     // Insert a visible symbol into the symbol table so it can
697     // be found later by name.
698     //
699     // Returns false if the was a name collision.
700     //
insert(TSymbol & symbol)701     bool insert(TSymbol& symbol)
702     {
703         symbol.setUniqueId(++uniqueId);
704 
705         // make sure there isn't a function of this variable name
706         if (! separateNameSpaces && ! symbol.getAsFunction() && table[currentLevel()]->hasFunctionName(symbol.getName()))
707             return false;
708 
709         // check for not overloading or redefining a built-in function
710         if (noBuiltInRedeclarations) {
711             if (atGlobalLevel() && currentLevel() > 0) {
712                 if (table[0]->hasFunctionName(symbol.getName()))
713                     return false;
714                 if (currentLevel() > 1 && table[1]->hasFunctionName(symbol.getName()))
715                     return false;
716             }
717         }
718 
719         return table[currentLevel()]->insert(symbol, separateNameSpaces);
720     }
721 
722     // Add more members to an already inserted aggregate object
amend(TSymbol & symbol,int firstNewMember)723     bool amend(TSymbol& symbol, int firstNewMember)
724     {
725         // See insert() for comments on basic explanation of insert.
726         // This operates similarly, but more simply.
727         return table[currentLevel()]->amend(symbol, firstNewMember);
728     }
729 
730     // Update the level info in symbol's unique ID to current level
amendSymbolIdLevel(TSymbol & symbol)731     void amendSymbolIdLevel(TSymbol& symbol)
732     {
733         // clamp level to avoid overflow
734         uint64_t level = (uint32_t)currentLevel() > MaxLevelInUniqueID ? MaxLevelInUniqueID : currentLevel();
735         uint64_t symbolId = symbol.getUniqueId();
736         symbolId &= uniqueIdMask;
737         symbolId |= (level << LevelFlagBitOffset);
738         symbol.setUniqueId(symbolId);
739     }
740     //
741     // To allocate an internal temporary, which will need to be uniquely
742     // identified by the consumer of the AST, but never need to
743     // found by doing a symbol table search by name, hence allowed an
744     // arbitrary name in the symbol with no worry of collision.
745     //
makeInternalVariable(TSymbol & symbol)746     void makeInternalVariable(TSymbol& symbol)
747     {
748         symbol.setUniqueId(++uniqueId);
749     }
750 
751     //
752     // Copy a variable or anonymous member's structure from a shared level so that
753     // it can be added (soon after return) to the symbol table where it can be
754     // modified without impacting other users of the shared table.
755     //
copyUpDeferredInsert(TSymbol * shared)756     TSymbol* copyUpDeferredInsert(TSymbol* shared)
757     {
758         if (shared->getAsVariable()) {
759             TSymbol* copy = shared->clone();
760             copy->setUniqueId(shared->getUniqueId());
761             return copy;
762         } else {
763             const TAnonMember* anon = shared->getAsAnonMember();
764             assert(anon);
765             TVariable* container = anon->getAnonContainer().clone();
766             container->changeName(NewPoolTString(""));
767             container->setUniqueId(anon->getAnonContainer().getUniqueId());
768             return container;
769         }
770     }
771 
copyUp(TSymbol * shared)772     TSymbol* copyUp(TSymbol* shared)
773     {
774         TSymbol* copy = copyUpDeferredInsert(shared);
775         table[globalLevel]->insert(*copy, separateNameSpaces);
776         if (shared->getAsVariable())
777             return copy;
778         else {
779             // return the copy of the anonymous member
780             return table[globalLevel]->find(shared->getName());
781         }
782     }
783 
784     // Normal find of a symbol, that can optionally say whether the symbol was found
785     // at a built-in level or the current top-scope level.
786     TSymbol* find(const TString& name, bool* builtIn = nullptr, bool* currentScope = nullptr, int* thisDepthP = nullptr)
787     {
788         int level = currentLevel();
789         TSymbol* symbol;
790         int thisDepth = 0;
791         do {
792             if (table[level]->isThisLevel())
793                 ++thisDepth;
794             symbol = table[level]->find(name);
795             --level;
796         } while (symbol == nullptr && level >= 0);
797         level++;
798         if (builtIn)
799             *builtIn = isBuiltInLevel(level);
800         if (currentScope)
801             *currentScope = isGlobalLevel(currentLevel()) || level == currentLevel();  // consider shared levels as "current scope" WRT user globals
802         if (thisDepthP != nullptr) {
803             if (! table[level]->isThisLevel())
804                 thisDepth = 0;
805             *thisDepthP = thisDepth;
806         }
807 
808         return symbol;
809     }
810 
retargetSymbol(const TString & from,const TString & to)811     void retargetSymbol(const TString& from, const TString& to) {
812         int level = currentLevel();
813         table[level]->retargetSymbol(from, to);
814     }
815 
816 
817     // Find of a symbol that returns how many layers deep of nested
818     // structures-with-member-functions ('this' scopes) deep the symbol was
819     // found in.
find(const TString & name,int & thisDepth)820     TSymbol* find(const TString& name, int& thisDepth)
821     {
822         int level = currentLevel();
823         TSymbol* symbol;
824         thisDepth = 0;
825         do {
826             if (table[level]->isThisLevel())
827                 ++thisDepth;
828             symbol = table[level]->find(name);
829             --level;
830         } while (symbol == nullptr && level >= 0);
831 
832         if (! table[level + 1]->isThisLevel())
833             thisDepth = 0;
834 
835         return symbol;
836     }
837 
isFunctionNameVariable(const TString & name)838     bool isFunctionNameVariable(const TString& name) const
839     {
840         if (separateNameSpaces)
841             return false;
842 
843         int level = currentLevel();
844         do {
845             bool variable;
846             bool found = table[level]->findFunctionVariableName(name, variable);
847             if (found)
848                 return variable;
849             --level;
850         } while (level >= 0);
851 
852         return false;
853     }
854 
findFunctionNameList(const TString & name,TVector<const TFunction * > & list,bool & builtIn)855     void findFunctionNameList(const TString& name, TVector<const TFunction*>& list, bool& builtIn)
856     {
857         // For user levels, return the set found in the first scope with a match
858         builtIn = false;
859         int level = currentLevel();
860         do {
861             table[level]->findFunctionNameList(name, list);
862             --level;
863         } while (list.empty() && level >= globalLevel);
864 
865         if (! list.empty())
866             return;
867 
868         // Gather across all built-in levels; they don't hide each other
869         builtIn = true;
870         do {
871             table[level]->findFunctionNameList(name, list);
872             --level;
873         } while (level >= 0);
874     }
875 
relateToOperator(const char * name,TOperator op)876     void relateToOperator(const char* name, TOperator op)
877     {
878         for (unsigned int level = 0; level < table.size(); ++level)
879             table[level]->relateToOperator(name, op);
880     }
881 
setFunctionExtensions(const char * name,int num,const char * const extensions[])882     void setFunctionExtensions(const char* name, int num, const char* const extensions[])
883     {
884         for (unsigned int level = 0; level < table.size(); ++level)
885             table[level]->setFunctionExtensions(name, num, extensions);
886     }
887 
setVariableExtensions(const char * name,int numExts,const char * const extensions[])888     void setVariableExtensions(const char* name, int numExts, const char* const extensions[])
889     {
890         TSymbol* symbol = find(TString(name));
891         if (symbol == nullptr)
892             return;
893 
894         symbol->setExtensions(numExts, extensions);
895     }
896 
setVariableExtensions(const char * blockName,const char * name,int numExts,const char * const extensions[])897     void setVariableExtensions(const char* blockName, const char* name, int numExts, const char* const extensions[])
898     {
899         TSymbol* symbol = find(TString(blockName));
900         if (symbol == nullptr)
901             return;
902         TVariable* variable = symbol->getAsVariable();
903         assert(variable != nullptr);
904 
905         const TTypeList& structure = *variable->getAsVariable()->getType().getStruct();
906         for (int member = 0; member < (int)structure.size(); ++member) {
907             if (structure[member].type->getFieldName().compare(name) == 0) {
908                 variable->setMemberExtensions(member, numExts, extensions);
909                 return;
910             }
911         }
912     }
913 
getMaxSymbolId()914     long long getMaxSymbolId() { return uniqueId; }
915 #if !defined(GLSLANG_WEB)
916     void dump(TInfoSink& infoSink, bool complete = false) const;
917 #endif
918     void copyTable(const TSymbolTable& copyOf);
919 
setPreviousDefaultPrecisions(TPrecisionQualifier * p)920     void setPreviousDefaultPrecisions(TPrecisionQualifier *p) { table[currentLevel()]->setPreviousDefaultPrecisions(p); }
921 
readOnly()922     void readOnly()
923     {
924         for (unsigned int level = 0; level < table.size(); ++level)
925             table[level]->readOnly();
926     }
927 
928     // Add current level in the high-bits of unique id
updateUniqueIdLevelFlag()929     void updateUniqueIdLevelFlag() {
930         // clamp level to avoid overflow
931         uint64_t level = (uint32_t)currentLevel() > MaxLevelInUniqueID ? MaxLevelInUniqueID : currentLevel();
932         uniqueId &= uniqueIdMask;
933         uniqueId |= (level << LevelFlagBitOffset);
934     }
935 
overwriteUniqueId(long long id)936     void overwriteUniqueId(long long id)
937     {
938         uniqueId = id;
939         updateUniqueIdLevelFlag();
940     }
941 
942 protected:
943     TSymbolTable(TSymbolTable&);
944     TSymbolTable& operator=(TSymbolTableLevel&);
945 
currentLevel()946     int currentLevel() const { return static_cast<int>(table.size()) - 1; }
947     std::vector<TSymbolTableLevel*> table;
948     long long uniqueId;     // for unique identification in code generation
949     bool noBuiltInRedeclarations;
950     bool separateNameSpaces;
951     unsigned int adoptedLevels;
952 };
953 
954 } // end namespace glslang
955 
956 #endif // _SYMBOL_TABLE_INCLUDED_
957