1 /* 2 * Copyright 2016 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef SKSL_SYMBOLTABLE 9 #define SKSL_SYMBOLTABLE 10 11 #include "include/private/SkSLString.h" 12 #include "include/private/SkSLSymbol.h" 13 #include "include/private/SkTArray.h" 14 #include "include/private/SkTHash.h" 15 #include "include/sksl/SkSLErrorReporter.h" 16 17 #include <forward_list> 18 #include <memory> 19 #include <vector> 20 21 namespace SkSL { 22 23 class Context; 24 class FunctionDeclaration; 25 26 /** 27 * Maps identifiers to symbols. Functions, in particular, are mapped to either FunctionDeclaration 28 * or UnresolvedFunction depending on whether they are overloaded or not. 29 */ 30 class SymbolTable { 31 public: SymbolTable(const Context & context,bool builtin)32 SymbolTable(const Context& context, bool builtin) 33 : fBuiltin(builtin) 34 , fContext(context) {} 35 SymbolTable(std::shared_ptr<SymbolTable> parent,bool builtin)36 SymbolTable(std::shared_ptr<SymbolTable> parent, bool builtin) 37 : fParent(parent) 38 , fBuiltin(builtin) 39 , fContext(parent->fContext) {} 40 41 /** Replaces the passed-in SymbolTable with a newly-created child symbol table. */ Push(std::shared_ptr<SymbolTable> * table)42 static void Push(std::shared_ptr<SymbolTable>* table) { 43 Push(table, (*table)->isBuiltin()); 44 } Push(std::shared_ptr<SymbolTable> * table,bool isBuiltin)45 static void Push(std::shared_ptr<SymbolTable>* table, bool isBuiltin) { 46 *table = std::make_shared<SymbolTable>(*table, isBuiltin); 47 } 48 49 /** 50 * Replaces the passed-in SymbolTable with its parent. If the child symbol table is otherwise 51 * unreferenced, it will be deleted. 52 */ Pop(std::shared_ptr<SymbolTable> * table)53 static void Pop(std::shared_ptr<SymbolTable>* table) { 54 *table = (*table)->fParent; 55 } 56 57 /** 58 * If the input is a built-in symbol table, returns a new empty symbol table as a child of the 59 * input table. If the input is not a built-in symbol table, returns it as-is. Built-in symbol 60 * tables must not be mutated after creation, so they must be wrapped if mutation is necessary. 61 */ WrapIfBuiltin(std::shared_ptr<SymbolTable> symbolTable)62 static std::shared_ptr<SymbolTable> WrapIfBuiltin(std::shared_ptr<SymbolTable> symbolTable) { 63 if (!symbolTable) { 64 return nullptr; 65 } 66 if (!symbolTable->isBuiltin()) { 67 return symbolTable; 68 } 69 return std::make_shared<SymbolTable>(std::move(symbolTable), /*builtin=*/false); 70 } 71 72 /** 73 * Looks up the requested symbol and returns it. If a function has overloads, an 74 * UnresolvedFunction symbol (pointing to all of the candidates) will be added to the symbol 75 * table and returned. 76 */ 77 const Symbol* operator[](std::string_view name); 78 79 void addWithoutOwnership(const Symbol* symbol); 80 81 template <typename T> add(std::unique_ptr<T> symbol)82 const T* add(std::unique_ptr<T> symbol) { 83 const T* ptr = symbol.get(); 84 this->addWithoutOwnership(ptr); 85 this->takeOwnershipOfSymbol(std::move(symbol)); 86 return ptr; 87 } 88 89 template <typename T> takeOwnershipOfSymbol(std::unique_ptr<T> symbol)90 const T* takeOwnershipOfSymbol(std::unique_ptr<T> symbol) { 91 const T* ptr = symbol.get(); 92 fOwnedSymbols.push_back(std::move(symbol)); 93 return ptr; 94 } 95 96 template <typename T> takeOwnershipOfIRNode(std::unique_ptr<T> node)97 const T* takeOwnershipOfIRNode(std::unique_ptr<T> node) { 98 const T* ptr = node.get(); 99 fOwnedNodes.push_back(std::move(node)); 100 return ptr; 101 } 102 103 /** 104 * Given type = `float` and arraySize = 5, creates the array type `float[5]` in the symbol 105 * table. The created array type is returned. If zero is passed, the base type is returned 106 * unchanged. 107 */ 108 const Type* addArrayDimension(const Type* type, int arraySize); 109 110 // Call fn for every symbol in the table. You may not mutate anything. 111 template <typename Fn> foreach(Fn && fn)112 void foreach(Fn&& fn) const { 113 fSymbols.foreach( 114 [&fn](const SymbolKey& key, const Symbol* symbol) { fn(key.fName, symbol); }); 115 } 116 count()117 size_t count() { 118 return fSymbols.count(); 119 } 120 121 /** Returns true if this is a built-in SymbolTable. */ isBuiltin()122 bool isBuiltin() const { 123 return fBuiltin; 124 } 125 126 /** 127 * Returns the built-in symbol table that this SymbolTable rests upon. 128 * If this symbol table is already a built-in, it will be returned as-is. 129 */ builtinParent()130 SkSL::SymbolTable* builtinParent() { 131 return this->isBuiltin() ? this : fParent->builtinParent(); 132 } 133 134 const std::string* takeOwnershipOfString(std::string n); 135 136 std::shared_ptr<SymbolTable> fParent; 137 138 std::vector<std::unique_ptr<const Symbol>> fOwnedSymbols; 139 140 private: 141 struct SymbolKey { 142 std::string_view fName; 143 uint32_t fHash; 144 145 bool operator==(const SymbolKey& that) const { return fName == that.fName; } 146 bool operator!=(const SymbolKey& that) const { return fName != that.fName; } 147 struct Hash { operatorSymbolKey::Hash148 uint32_t operator()(const SymbolKey& key) const { return key.fHash; } 149 }; 150 }; 151 MakeSymbolKey(std::string_view name)152 static SymbolKey MakeSymbolKey(std::string_view name) { 153 return SymbolKey{name, SkOpts::hash_fn(name.data(), name.size(), 0)}; 154 } 155 156 const Symbol* lookup(SymbolTable* writableSymbolTable, const SymbolKey& key); 157 158 static std::vector<const FunctionDeclaration*> GetFunctions(const Symbol& s); 159 160 bool fBuiltin = false; 161 std::vector<std::unique_ptr<IRNode>> fOwnedNodes; 162 std::forward_list<std::string> fOwnedStrings; 163 SkTHashMap<SymbolKey, const Symbol*, SymbolKey::Hash> fSymbols; 164 const Context& fContext; 165 166 friend class Dehydrator; 167 }; 168 169 /** 170 * While in scope, the passed-in symbol table is replaced with a child symbol table. 171 */ 172 class AutoSymbolTable { 173 public: AutoSymbolTable(std::shared_ptr<SymbolTable> * s)174 AutoSymbolTable(std::shared_ptr<SymbolTable>* s) 175 : fSymbolTable(s) { 176 SkDEBUGCODE(fPrevious = fSymbolTable->get();) 177 SymbolTable::Push(fSymbolTable); 178 } 179 ~AutoSymbolTable()180 ~AutoSymbolTable() { 181 SymbolTable::Pop(fSymbolTable); 182 SkASSERT(fPrevious == fSymbolTable->get()); 183 } 184 185 std::shared_ptr<SymbolTable>* fSymbolTable; 186 SkDEBUGCODE(SymbolTable* fPrevious;) 187 }; 188 189 } // namespace SkSL 190 191 #endif 192