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