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 QtShaderTools { |
73 | namespace glslang { |
74 | |
75 | // |
76 | // Symbol base class. (Can build functions or variables out of these...) |
77 | // |
78 | |
79 | class TVariable; |
80 | class TFunction; |
81 | class TAnonMember; |
82 | |
83 | typedef TVector<const char*> TExtensionList; |
84 | |
85 | class TSymbol { |
86 | public: |
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 | |
127 | protected: |
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 | // |
155 | class TVariable : public TSymbol { |
156 | public: |
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 | |
200 | protected: |
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 | // |
220 | struct 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 | // |
240 | class TFunction : public TSymbol { |
241 | public: |
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 | |
334 | protected: |
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 | // |
364 | class TAnonMember : public TSymbol { |
365 | public: |
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 | |
397 | protected: |
398 | explicit TAnonMember(const TAnonMember&); |
399 | TAnonMember& operator=(const TAnonMember&); |
400 | |
401 | TVariable& anonContainer; |
402 | unsigned int memberNumber; |
403 | int anonId; |
404 | }; |
405 | |
406 | class TSymbolTableLevel { |
407 | public: |
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 | |
588 | protected: |
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 | |
605 | class TSymbolTable { |
606 | public: |
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 | // |
641 | protected: |
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 |
647 | public: |
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 | |
940 | protected: |
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 | |