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[](skstd::string_view name); 78 79 /** 80 * Creates a new name for a symbol which already exists; does not take ownership of Symbol*. 81 */ 82 void addAlias(skstd::string_view name, const Symbol* symbol); 83 84 void addWithoutOwnership(const Symbol* symbol); 85 86 template <typename T> add(std::unique_ptr<T> symbol)87 const T* add(std::unique_ptr<T> symbol) { 88 const T* ptr = symbol.get(); 89 this->addWithoutOwnership(ptr); 90 this->takeOwnershipOfSymbol(std::move(symbol)); 91 return ptr; 92 } 93 94 template <typename T> takeOwnershipOfSymbol(std::unique_ptr<T> symbol)95 const T* takeOwnershipOfSymbol(std::unique_ptr<T> symbol) { 96 const T* ptr = symbol.get(); 97 fOwnedSymbols.push_back(std::move(symbol)); 98 return ptr; 99 } 100 101 template <typename T> takeOwnershipOfIRNode(std::unique_ptr<T> node)102 const T* takeOwnershipOfIRNode(std::unique_ptr<T> node) { 103 const T* ptr = node.get(); 104 fOwnedNodes.push_back(std::move(node)); 105 return ptr; 106 } 107 108 /** 109 * Given type = `float` and arraySize = 5, creates the array type `float[5]` in the symbol 110 * table. The created array type is returned. If zero is passed, the base type is returned 111 * unchanged. 112 */ 113 const Type* addArrayDimension(const Type* type, int arraySize); 114 115 // Call fn for every symbol in the table. You may not mutate anything. 116 template <typename Fn> foreach(Fn && fn)117 void foreach(Fn&& fn) const { 118 fSymbols.foreach( 119 [&fn](const SymbolKey& key, const Symbol* symbol) { fn(key.fName, symbol); }); 120 } 121 count()122 size_t count() { 123 return fSymbols.count(); 124 } 125 126 /** Returns true if this is a built-in SymbolTable. */ isBuiltin()127 bool isBuiltin() const { 128 return fBuiltin; 129 } 130 131 /** 132 * Returns the built-in symbol table that this SymbolTable rests upon. 133 * If this symbol table is already a built-in, it will be returned as-is. 134 */ builtinParent()135 SkSL::SymbolTable* builtinParent() { 136 return this->isBuiltin() ? this : fParent->builtinParent(); 137 } 138 139 const String* takeOwnershipOfString(String n); 140 141 std::shared_ptr<SymbolTable> fParent; 142 143 std::vector<std::unique_ptr<const Symbol>> fOwnedSymbols; 144 145 private: 146 struct SymbolKey { 147 skstd::string_view fName; 148 uint32_t fHash; 149 150 bool operator==(const SymbolKey& that) const { return fName == that.fName; } 151 bool operator!=(const SymbolKey& that) const { return fName != that.fName; } 152 struct Hash { operatorSymbolKey::Hash153 uint32_t operator()(const SymbolKey& key) const { return key.fHash; } 154 }; 155 }; 156 MakeSymbolKey(skstd::string_view name)157 static SymbolKey MakeSymbolKey(skstd::string_view name) { 158 return SymbolKey{name, SkOpts::hash_fn(name.data(), name.size(), 0)}; 159 } 160 161 const Symbol* lookup(SymbolTable* writableSymbolTable, const SymbolKey& key); 162 163 static std::vector<const FunctionDeclaration*> GetFunctions(const Symbol& s); 164 165 bool fBuiltin = false; 166 std::vector<std::unique_ptr<IRNode>> fOwnedNodes; 167 std::forward_list<String> fOwnedStrings; 168 SkTHashMap<SymbolKey, const Symbol*, SymbolKey::Hash> fSymbols; 169 const Context& fContext; 170 171 friend class Dehydrator; 172 }; 173 174 /** 175 * While in scope, the passed-in symbol table is replaced with a child symbol table. 176 */ 177 class AutoSymbolTable { 178 public: AutoSymbolTable(std::shared_ptr<SymbolTable> * s)179 AutoSymbolTable(std::shared_ptr<SymbolTable>* s) 180 : fSymbolTable(s) { 181 SkDEBUGCODE(fPrevious = fSymbolTable->get();) 182 SymbolTable::Push(fSymbolTable); 183 } 184 ~AutoSymbolTable()185 ~AutoSymbolTable() { 186 SymbolTable::Pop(fSymbolTable); 187 SkASSERT(fPrevious == fSymbolTable->get()); 188 } 189 190 std::shared_ptr<SymbolTable>* fSymbolTable; 191 SkDEBUGCODE(SymbolTable* fPrevious;) 192 }; 193 194 } // namespace SkSL 195 196 #endif 197