CeresEngine 0.2.0
A game development framework
Loading...
Searching...
No Matches
SymbolTable.hpp
Go to the documentation of this file.
1//
2// CeresEngine - A game development framework
3//
4// Created by Rogiel Sulzbach.
5// Copyright (c) 2018-2022 Rogiel Sulzbach. All rights reserved.
6//
7
8#pragma once
9
11
18
20
21#include <functional>
22
24
25 // Returns the ranked distance between the two strings.
26 UInt32 stringDistance(const String& a, const String& b);
27
29
30 [[noreturn]] void runtimeErrIdentAlreadyDeclared(const String& ident, const AST* prevDeclarationAST = nullptr);
31
32 template<typename SymbolType> AST* fetchASTFromSymbol(const SymbolType& symbol);
33
34 template<typename T> struct GenericDefaultValue {
35 static T get() { return nullptr; }
36 };
37
38 template<> struct GenericDefaultValue<bool> {
39 static bool get() { return false; }
40 };
41
42 // Common symbol table class with a single scope.
43 template<typename SymbolType> class SymbolTable {
44 public:
45 // Callback function when a symbol is about to be overriden. Must return true to allow a symbol override.
47
48 // Callback function when a symbol is about to be released from its scope.
49 using OnReleaseProc = UniqueFunction<void(const SymbolType& symbol) const>;
50
51 // Search predicate function signature.
52 using SearchPredicateProc = UniqueFunction<bool(const SymbolType& symbol) const>;
53
55
56 // Opens a new scope.
57 void openScope() {
58 mScopeStack.push({});
59 mSymTableAnonymous.push_back({});
60 }
61
62 // Closes the active scope.
63 void closeScope(const OnReleaseProc& releaseProc = nullptr) {
64 if(!mScopeStack.empty()) {
66 for(const auto& ident : mScopeStack.top()) {
67 auto it = mSymTable.find(ident);
68 if(it != mSymTable.end()) {
70 if(releaseProc) {
71 releaseProc(it->second.top().symbol);
72 }
73
75 it->second.pop();
76 if(it->second.empty()) {
78 mSymTable.erase(it);
79 }
80 }
81 }
82
83 if(releaseProc) {
85 for(const auto& sym : mSymTableAnonymous.back()) {
86 releaseProc(sym.symbol);
87 }
88 }
89
91 mScopeStack.pop();
92 mSymTableAnonymous.pop_back();
93 }
94 }
95
98 bool register_(const String& ident, SymbolType symbol, const OnOverrideProc& overrideProc = nullptr, const bool throwOnFailure = true) {
100 if(mScopeStack.empty()) {
102 }
103
104 if(ident.empty()) {
106 mSymTableAnonymous.back().push_back({symbol, getScopeLevel()});
107 } else {
109 auto it = mSymTable.find(ident);
110 if(it != mSymTable.end() && !it->second.empty()) {
111 auto& entry = it->second.top();
112 if(entry.symbol && entry.scopeLevel == getScopeLevel()) {
114 if(overrideProc && overrideProc(entry.symbol)) {
115 return true;
116 }
117 if(throwOnFailure) {
119 } else {
120 return false;
121 }
122 }
123 }
124
126 mSymTable[ident].push({symbol, getScopeLevel()});
127 mScopeStack.top().push_back(ident);
128 }
129
130 return true;
131 }
132
133 // Returns the symbol with the specified identifer which is in the deepest scope, or null if there is no such symbol.
134 [[nodiscard]] SymbolType fetch(const String& ident) const {
135 auto it = mSymTable.find(ident);
136 if(it != mSymTable.end() && !it->second.empty()) {
137 return it->second.top().symbol;
138 }
140 }
141
142 // Returns the symbol with the specified identifer which is in the current scope, or null if there is no such symbol.
144 auto it = mSymTable.find(ident);
145 if(it != mSymTable.end() && !it->second.empty()) {
146 const auto& sym = it->second.top();
147 if(sym.scopeLevel == getScopeLevel()) {
148 return sym.symbol;
149 }
150 }
152 }
153
154 // Returns the first symbol in the scope hierarchy for which the search predicate returns true.
156 if(searchPredicate) {
158 for(const auto& sym : mSymTable) {
159 if(!sym.second.empty()) {
160 const auto& symRef = sym.second.top().symbol;
162 return symRef;
163 }
164 }
165 }
166
168 if(!mSymTableAnonymous.empty()) {
169 for(auto scope = mSymTableAnonymous.rbegin(); scope != mSymTableAnonymous.rend(); ++scope) {
170 for(const auto& sym : *scope) {
171 if(searchPredicate(sym.symbol)) {
172 return sym.symbol;
173 }
174 }
175 }
176 }
177 }
179 }
180
181 // Returns an identifier that is similar to the specified identifier (for suggestions of typos)
182 [[nodiscard]] String fetchSimilar(const String& ident) const {
184 const String* similar = nullptr;
185 UInt32 dist = static_cast<UInt32>(~0);
186
187 for(const auto& symbol : mSymTable) {
188 auto d = stringDistance(ident, symbol.first);
189 if(d < dist) {
190 similar = (&symbol.first);
191 dist = d;
192 }
193 }
194
196 if(similar != nullptr && dist < ident.size()) {
197 return *similar;
198 }
199
201 return "";
202 }
203
204 // Returns current scope level.
205 [[nodiscard]] std::size_t getScopeLevel() const { return mScopeStack.size(); }
206
207 // Returns true if the symbol table is currently inside the global scope (i.e. scope level = 1).
208 [[nodiscard]] bool isInsideGlobalScope() const { return (getScopeLevel() == 1); }
209
210 private:
211 struct Symbol {
213 std::size_t scopeLevel;
214 };
215
216 // Stores the scope stack for all identifiable symbols.
218
219 // Stores the scope stack for all anonymous symbols.
221
225 };
226
227 // AST symbol table type.
229
230 // AST symbol class for the AST, that allows overloaded symbol (for functions).
232 public:
234
235 // Adds the specified AST reference to this overloaded symbol, and return true if the overload is valid.
237
238 // Fetches any AST. If there is more than one reference, an std::runtime_error is thrown.
239 [[nodiscard]] AST* fetch(bool throwOnFailure = true) const;
240
241 // Returns the VarDecl AST node.
243
247
248 // Returns the FunctionDecl AST node (if the function is not overloaded).
250
251 // Returns the FunctionDecl AST node for the specified argument type denoter list (used to derive the overloaded function).
253
254 private:
257 };
258
260
261 // AST symbol table type for ovloading.
263
264 // Template to fetch AST node from a generic symbol type.
265 template<typename SymbolType> AST* fetchASTFromSymbol(const SymbolType& symbol) { return nullptr; }
266
267 template<> inline AST* fetchASTFromSymbol<ASTSymbolOverloadPtr>(const ASTSymbolOverloadPtr& symbol) { return symbol->fetch(false); }
268
269} // namespace CeresEngine::ShaderCompiler
FunctionDeclaration * fetchFunctionDeclaration(bool throwOnFailure=true) const
Vector< AST * > mRefs
Definition SymbolTable.hpp:256
String mIdent
Definition SymbolTable.hpp:255
FunctionDeclaration * fetchFunctionDeclaration(const Vector< TypeDenoterPtr > &argTypeDenoters) const
Declaration * fetchType(bool throwOnFailure=true) const
Fetches a type declaration (StructDecl, AliasDecl).
ASTSymbolOverload(const String &ident, AST *ast)
VarDeclaration * fetchVarDeclaration(bool throwOnFailure=true) const
AST * fetch(bool throwOnFailure=true) const
Definition SymbolTable.hpp:43
SymbolType fetch(const String &ident) const
Definition SymbolTable.hpp:134
UniqueFunction< bool(const SymbolType &symbol) const > SearchPredicateProc
Definition SymbolTable.hpp:52
Map< String, Stack< Symbol > > mSymTable
Definition SymbolTable.hpp:217
UniqueFunction< void(const SymbolType &symbol) const > OnReleaseProc
Definition SymbolTable.hpp:49
bool isInsideGlobalScope() const
Definition SymbolTable.hpp:208
UniqueFunction< bool(SymbolType &prevSymbol) const > OnOverrideProc
Definition SymbolTable.hpp:46
void openScope()
Definition SymbolTable.hpp:57
std::size_t getScopeLevel() const
Definition SymbolTable.hpp:205
Vector< Vector< Symbol > > mSymTableAnonymous
Definition SymbolTable.hpp:220
String fetchSimilar(const String &ident) const
Definition SymbolTable.hpp:182
bool register_(const String &ident, SymbolType symbol, const OnOverrideProc &overrideProc=nullptr, const bool throwOnFailure=true)
Registers the specified symbol in the current scope (if the identifier is not empty).
Definition SymbolTable.hpp:98
void closeScope(const OnReleaseProc &releaseProc=nullptr)
Definition SymbolTable.hpp:63
SymbolTable()
Definition SymbolTable.hpp:54
Stack< Vector< String > > mScopeStack
Stores all identifiers for the current stack.
Definition SymbolTable.hpp:224
SymbolType fetchFromCurrentScope(const String &ident) const
Definition SymbolTable.hpp:143
SymbolType find(const SearchPredicateProc &searchPredicate) const
Definition SymbolTable.hpp:155
Definition AST.hpp:33
AST * fetchASTFromSymbol< ASTSymbolOverloadPtr >(const ASTSymbolOverloadPtr &symbol)
Definition SymbolTable.hpp:267
void runtimeErrIdentAlreadyDeclared(const String &ident, const AST *prevDeclarationAST=nullptr)
UInt32 stringDistance(const String &a, const String &b)
AST * fetchASTFromSymbol(const SymbolType &symbol)
Definition SymbolTable.hpp:265
SPtr< ASTSymbolOverload > ASTSymbolOverloadPtr
Definition SymbolTable.hpp:259
std::stack< T, Container > Stack
The Stack class is a container adapter that gives the programmer the functionality of a stack - speci...
Definition Stack.hpp:18
std::shared_ptr< T > SPtr
SPtr is a smart pointer that retains shared ownership of an object through a pointer.
Definition SmartPtr.hpp:37
std::vector< T, ScopedAllocatorAdaptor< StdAllocator< T, RawAllocator > > > Vector
Vector is a sequence container that encapsulates dynamic size arrays.
Definition Vector.hpp:17
std::uint32_t UInt32
Definition DataTypes.hpp:23
FunctionBase< true, false, fu2::capacity_default, true, false, Signatures... > UniqueFunction
An owning non copyable function wrapper for arbitrary callable types.
Definition Function.hpp:59
constexpr size_t hash(const T &v)
Generates a hash for the provided type.
Definition Hash.hpp:25
std::map< Key, T, Compare, ScopedAllocatorAdaptor< StdAllocator< Pair< const Key, T >, RawAllocator > > > Map
Map is a sorted associative container that contains key-value pairs with unique keys.
Definition Map.hpp:24
static bool get()
Definition SymbolTable.hpp:39
static T get()
Definition SymbolTable.hpp:35
std::size_t scopeLevel
Definition SymbolTable.hpp:213
SymbolType symbol
Definition SymbolTable.hpp:212