class SymbolTable{ private: enum Kind { kModule, kFunction, kBlock, }; std::forward_list>> Scopes; public: struct ModuleScope { SymbolTable& tables_ref; ModuleScope(SymbolTable& tables) : tables_ref(tables) { tables.enter(kModule); } ~ModuleScope() { tables_ref.exit(); } }; struct FunctionScope { SymbolTable& tables_ref; FunctionScope(SymbolTable& tables) : tables_ref(tables) { tables.enter(kFunction); } ~FunctionScope() { tables_ref.exit(); } }; struct BlockScope { SymbolTable& tables_ref; BlockScope(SymbolTable& tables) : tables_ref(tables) { tables.enter(kBlock); } ~BlockScope() { tables_ref.exit(); } }; SymbolTable() = default; bool isModuleScope() const { return Scopes.front().first == kModule; } bool isFunctionScope() const { return Scopes.front().first == kFunction; } bool isBlockScope() const { return Scopes.front().first == kBlock; } Value *lookup(const std::string &name) const { for (auto &scope : Scopes) { auto iter = scope.second.find(name); if (iter != scope.second.end()) return iter->second; } return nullptr; } auto insert(const std::string &name, Value *value) { assert(not Scopes.empty()); return Scopes.front().second.emplace(name, value); } private: void enter(Kind kind) { Scopes.emplace_front(); Scopes.front().first = kind; } void exit() { Scopes.pop_front(); } };