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 "src/sksl/SkSLErrorReporter.h" 16 17 #include <forward_list> 18 #include <memory> 19 #include <vector> 20 21 namespace SkSL { 22 23 class FunctionDeclaration; 24 25 /** 26 * Maps identifiers to symbols. Functions, in particular, are mapped to either FunctionDeclaration 27 * or UnresolvedFunction depending on whether they are overloaded or not. 28 */ 29 class SymbolTable { 30 public: SymbolTable(ErrorReporter * errorReporter,bool builtin)31 SymbolTable(ErrorReporter* errorReporter, bool builtin) 32 : fBuiltin(builtin) 33 , fErrorReporter(*errorReporter) {} 34 SymbolTable(std::shared_ptr<SymbolTable> parent,bool builtin)35 SymbolTable(std::shared_ptr<SymbolTable> parent, bool builtin) 36 : fParent(parent) 37 , fBuiltin(builtin) 38 , fErrorReporter(parent->fErrorReporter) {} 39 40 /** 41 * If the input is a built-in symbol table, returns a new empty symbol table as a child of the 42 * input table. If the input is not a built-in symbol table, returns it as-is. Built-in symbol 43 * tables must not be mutated after creation, so they must be wrapped if mutation is necessary. 44 */ WrapIfBuiltin(std::shared_ptr<SymbolTable> symbolTable)45 static std::shared_ptr<SymbolTable> WrapIfBuiltin(std::shared_ptr<SymbolTable> symbolTable) { 46 if (!symbolTable) { 47 return nullptr; 48 } 49 if (!symbolTable->isBuiltin()) { 50 return symbolTable; 51 } 52 return std::make_shared<SymbolTable>(std::move(symbolTable), /*builtin=*/false); 53 } 54 55 /** 56 * Looks up the requested symbol and returns it. If a function has overloads, an 57 * UnresolvedFunction symbol (pointing to all of the candidates) will be added to the symbol 58 * table and returned. 59 */ 60 const Symbol* operator[](StringFragment name); 61 62 /** 63 * Creates a new name for a symbol which already exists; does not take ownership of Symbol*. 64 */ 65 void addAlias(StringFragment name, const Symbol* symbol); 66 67 void addWithoutOwnership(const Symbol* symbol); 68 69 template <typename T> add(std::unique_ptr<T> symbol)70 const T* add(std::unique_ptr<T> symbol) { 71 const T* ptr = symbol.get(); 72 this->addWithoutOwnership(ptr); 73 this->takeOwnershipOfSymbol(std::move(symbol)); 74 return ptr; 75 } 76 77 template <typename T> takeOwnershipOfSymbol(std::unique_ptr<T> symbol)78 const T* takeOwnershipOfSymbol(std::unique_ptr<T> symbol) { 79 const T* ptr = symbol.get(); 80 fOwnedSymbols.push_back(std::move(symbol)); 81 return ptr; 82 } 83 84 template <typename T> takeOwnershipOfIRNode(std::unique_ptr<T> node)85 const T* takeOwnershipOfIRNode(std::unique_ptr<T> node) { 86 const T* ptr = node.get(); 87 fOwnedNodes.push_back(std::move(node)); 88 return ptr; 89 } 90 91 /** 92 * Given type = `float` and arraySize = 5, creates the array type `float[5]` in the symbol 93 * table. The created array type is returned. `kUnsizedArray` can be passed as a `[]` dimension. 94 * If zero is passed, the base type is returned unchanged. 95 */ 96 const Type* addArrayDimension(const Type* type, int arraySize); 97 98 // Call fn for every symbol in the table. You may not mutate anything. 99 template <typename Fn> foreach(Fn && fn)100 void foreach(Fn&& fn) const { 101 fSymbols.foreach( 102 [&fn](const SymbolKey& key, const Symbol* symbol) { fn(key.fName, symbol); }); 103 } 104 count()105 size_t count() { 106 return fSymbols.count(); 107 } 108 109 /** Returns true if this is a built-in SymbolTable. */ isBuiltin()110 bool isBuiltin() const { 111 return fBuiltin; 112 } 113 114 const String* takeOwnershipOfString(String n); 115 116 std::shared_ptr<SymbolTable> fParent; 117 118 std::vector<std::unique_ptr<const Symbol>> fOwnedSymbols; 119 120 private: 121 struct SymbolKey { 122 StringFragment fName; 123 uint32_t fHash; 124 125 bool operator==(const SymbolKey& that) const { return fName == that.fName; } 126 bool operator!=(const SymbolKey& that) const { return fName != that.fName; } 127 struct Hash { operatorSymbolKey::Hash128 uint32_t operator()(const SymbolKey& key) const { return key.fHash; } 129 }; 130 }; 131 MakeSymbolKey(StringFragment name)132 static SymbolKey MakeSymbolKey(StringFragment name) { 133 return SymbolKey{name, SkOpts::hash_fn(name.data(), name.size(), 0)}; 134 } 135 136 const Symbol* lookup(SymbolTable* writableSymbolTable, const SymbolKey& key); 137 138 static std::vector<const FunctionDeclaration*> GetFunctions(const Symbol& s); 139 140 bool fBuiltin = false; 141 std::vector<std::unique_ptr<IRNode>> fOwnedNodes; 142 std::forward_list<String> fOwnedStrings; 143 SkTHashMap<SymbolKey, const Symbol*, SymbolKey::Hash> fSymbols; 144 ErrorReporter& fErrorReporter; 145 146 friend class Dehydrator; 147 }; 148 149 } // namespace SkSL 150 151 #endif 152