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/core/SkTypes.h" 12 #include "src/core/SkChecksum.h" 13 #include "src/core/SkTHash.h" 14 #include "src/sksl/ir/SkSLSymbol.h" 15 16 #include <cstddef> 17 #include <cstdint> 18 #include <forward_list> 19 #include <memory> 20 #include <string> 21 #include <string_view> 22 #include <utility> 23 #include <vector> 24 25 namespace SkSL { 26 27 class Context; 28 class Expression; 29 class Position; 30 class Type; 31 32 /** 33 * Maps identifiers to symbols. 34 */ 35 class SymbolTable { 36 public: SymbolTable(bool builtin)37 explicit SymbolTable(bool builtin) 38 : fBuiltin(builtin) {} 39 SymbolTable(SymbolTable * parent,bool builtin)40 explicit SymbolTable(SymbolTable* parent, bool builtin) 41 : fParent(parent) 42 , fBuiltin(builtin) {} 43 44 /** 45 * Creates a new, empty SymbolTable between this SymbolTable and its current parent. 46 * The new symbol table is returned, and is also accessible as `this->fParent`. 47 * The original parent is accessible as `this->fParent->fParent`. 48 */ 49 std::unique_ptr<SymbolTable> insertNewParent(); 50 51 /** 52 * Looks up the requested symbol and returns a const pointer. 53 */ find(std::string_view name)54 const Symbol* find(std::string_view name) const { 55 return this->lookup(MakeSymbolKey(name)); 56 } 57 58 /** 59 * Looks up the requested symbol, only searching the built-in symbol tables. Always const. 60 */ 61 const Symbol* findBuiltinSymbol(std::string_view name) const; 62 63 /** 64 * Looks up the requested symbol and returns a mutable pointer. Use caution--mutating a symbol 65 * will have program-wide impact, and built-in symbol tables must never be mutated. 66 */ findMutable(std::string_view name)67 Symbol* findMutable(std::string_view name) const { 68 return this->lookup(MakeSymbolKey(name)); 69 } 70 71 /** 72 * Looks up the requested symbol and instantiates an Expression reference to it; will return a 73 * VariableReference, TypeReference, FunctionReference, FieldAccess, or nullptr. 74 */ 75 std::unique_ptr<Expression> instantiateSymbolRef(const Context& context, 76 std::string_view name, 77 Position pos); 78 79 /** 80 * Assigns a new name to the passed-in symbol. The old name will continue to exist in the symbol 81 * table and point to the symbol. 82 */ 83 void renameSymbol(const Context& context, Symbol* symbol, std::string_view newName); 84 85 /** 86 * Removes a symbol from the symbol table. If this symbol table had ownership of the symbol, the 87 * symbol is returned (and can be deleted or reinserted as desired); if not, null is returned. 88 * In either event, the name will no longer correspond to the symbol. 89 */ 90 std::unique_ptr<Symbol> removeSymbol(const Symbol* symbol); 91 92 /** 93 * Moves a symbol from this symbol table to another one. If this symbol table had ownership of 94 * the symbol, the ownership will be transferred as well. (If the symbol does not actually exist 95 * in this table at all, it will still be added to the other table.) 96 */ 97 void moveSymbolTo(SymbolTable* otherTable, Symbol* sym, const Context& context); 98 99 /** 100 * Returns true if the name refers to a type (user or built-in) in the current symbol table. 101 */ 102 bool isType(std::string_view name) const; 103 104 /** 105 * Returns true if the name refers to a builtin type. 106 */ 107 bool isBuiltinType(std::string_view name) const; 108 109 /** 110 * Adds a symbol to this symbol table, without conferring ownership. The caller is responsible 111 * for keeping the Symbol alive throughout the lifetime of the program/module. 112 */ 113 void addWithoutOwnershipOrDie(Symbol* symbol); 114 void addWithoutOwnership(const Context& context, Symbol* symbol); 115 116 /** 117 * Adds a symbol to this symbol table, conferring ownership. The symbol table will always be 118 * updated to reference the new symbol. If the symbol already exists, an error will be reported. 119 */ 120 template <typename T> add(const Context & context,std::unique_ptr<T> symbol)121 T* add(const Context& context, std::unique_ptr<T> symbol) { 122 T* ptr = symbol.get(); 123 this->addWithoutOwnership(context, this->takeOwnershipOfSymbol(std::move(symbol))); 124 return ptr; 125 } 126 127 /** 128 * Adds a symbol to this symbol table, conferring ownership. The symbol table will always be 129 * updated to reference the new symbol. If the symbol already exists, abort. 130 */ 131 template <typename T> addOrDie(std::unique_ptr<T> symbol)132 T* addOrDie(std::unique_ptr<T> symbol) { 133 T* ptr = symbol.get(); 134 this->addWithoutOwnershipOrDie(this->takeOwnershipOfSymbol(std::move(symbol))); 135 return ptr; 136 } 137 138 /** 139 * Forces a symbol into this symbol table, without conferring ownership. Replaces any existing 140 * symbol with the same name, if one exists. 141 */ 142 void injectWithoutOwnership(Symbol* symbol); 143 144 /** 145 * Forces a symbol into this symbol table, conferring ownership. Replaces any existing symbol 146 * with the same name, if one exists. 147 */ 148 template <typename T> inject(std::unique_ptr<T> symbol)149 T* inject(std::unique_ptr<T> symbol) { 150 T* ptr = symbol.get(); 151 this->injectWithoutOwnership(this->takeOwnershipOfSymbol(std::move(symbol))); 152 return ptr; 153 } 154 155 /** 156 * Confers ownership of a symbol without adding its name to the lookup table. 157 */ 158 template <typename T> takeOwnershipOfSymbol(std::unique_ptr<T> symbol)159 T* takeOwnershipOfSymbol(std::unique_ptr<T> symbol) { 160 T* ptr = symbol.get(); 161 fOwnedSymbols.push_back(std::move(symbol)); 162 return ptr; 163 } 164 165 /** 166 * Given type = `float` and arraySize = 5, creates the array type `float[5]` in the symbol 167 * table. The created array type is returned. If zero is passed, the base type is returned 168 * unchanged. 169 */ 170 const Type* addArrayDimension(const Context& context, const Type* type, int arraySize); 171 172 // Call fn for every symbol in the table. You may not mutate anything. 173 template <typename Fn> foreach(Fn && fn)174 void foreach(Fn&& fn) const { 175 fSymbols.foreach( 176 [&fn](const SymbolKey& key, const Symbol* symbol) { fn(key.fName, symbol); }); 177 } 178 179 // Checks `this` directly against `other` to see if the two symbol tables have any names in 180 // common. Parent tables are not considered. 181 bool wouldShadowSymbolsFrom(const SymbolTable* other) const; 182 count()183 size_t count() const { 184 return fSymbols.count(); 185 } 186 187 /** Returns true if this is a built-in SymbolTable. */ isBuiltin()188 bool isBuiltin() const { 189 return fBuiltin; 190 } 191 192 const std::string* takeOwnershipOfString(std::string n); 193 194 /** 195 * Indicates that this symbol table's parent is in a different module than this one. 196 */ markModuleBoundary()197 void markModuleBoundary() { 198 fAtModuleBoundary = true; 199 } 200 201 SymbolTable* fParent = nullptr; 202 203 std::vector<std::unique_ptr<Symbol>> fOwnedSymbols; 204 205 private: 206 struct SymbolKey { 207 std::string_view fName; 208 uint32_t fHash; 209 210 bool operator==(const SymbolKey& that) const { return fName == that.fName; } 211 bool operator!=(const SymbolKey& that) const { return fName != that.fName; } 212 struct Hash { operatorSymbolKey::Hash213 uint32_t operator()(const SymbolKey& key) const { return key.fHash; } 214 }; 215 }; 216 MakeSymbolKey(std::string_view name)217 static SymbolKey MakeSymbolKey(std::string_view name) { 218 return SymbolKey{name, SkChecksum::Hash32(name.data(), name.size())}; 219 } 220 221 Symbol* lookup(const SymbolKey& key) const; 222 bool addWithoutOwnership(Symbol* symbol); 223 224 bool fBuiltin = false; 225 bool fAtModuleBoundary = false; 226 std::forward_list<std::string> fOwnedStrings; 227 skia_private::THashMap<SymbolKey, Symbol*, SymbolKey::Hash> fSymbols; 228 }; 229 230 } // namespace SkSL 231 232 #endif 233