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

source code of qtshadertools/src/3rdparty/glslang/glslang/MachineIndependent/SymbolTable.h