/* * Copyright 2016 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SKSL_SYMBOLTABLE #define SKSL_SYMBOLTABLE #include "include/private/SkSLString.h" #include "include/private/SkSLSymbol.h" #include "include/private/SkTArray.h" #include "include/private/SkTHash.h" #include "include/sksl/SkSLErrorReporter.h" #include #include #include namespace SkSL { class Context; class FunctionDeclaration; /** * Maps identifiers to symbols. Functions, in particular, are mapped to either FunctionDeclaration * or UnresolvedFunction depending on whether they are overloaded or not. */ class SymbolTable { public: SymbolTable(const Context& context, bool builtin) : fBuiltin(builtin) , fContext(context) {} SymbolTable(std::shared_ptr parent, bool builtin) : fParent(parent) , fBuiltin(builtin) , fContext(parent->fContext) {} /** Replaces the passed-in SymbolTable with a newly-created child symbol table. */ static void Push(std::shared_ptr* table) { Push(table, (*table)->isBuiltin()); } static void Push(std::shared_ptr* table, bool isBuiltin) { *table = std::make_shared(*table, isBuiltin); } /** * Replaces the passed-in SymbolTable with its parent. If the child symbol table is otherwise * unreferenced, it will be deleted. */ static void Pop(std::shared_ptr* table) { *table = (*table)->fParent; } /** * If the input is a built-in symbol table, returns a new empty symbol table as a child of the * input table. If the input is not a built-in symbol table, returns it as-is. Built-in symbol * tables must not be mutated after creation, so they must be wrapped if mutation is necessary. */ static std::shared_ptr WrapIfBuiltin(std::shared_ptr symbolTable) { if (!symbolTable) { return nullptr; } if (!symbolTable->isBuiltin()) { return symbolTable; } return std::make_shared(std::move(symbolTable), /*builtin=*/false); } /** * Looks up the requested symbol and returns it. If a function has overloads, an * UnresolvedFunction symbol (pointing to all of the candidates) will be added to the symbol * table and returned. */ const Symbol* operator[](skstd::string_view name); /** * Creates a new name for a symbol which already exists; does not take ownership of Symbol*. */ void addAlias(skstd::string_view name, const Symbol* symbol); void addWithoutOwnership(const Symbol* symbol); template const T* add(std::unique_ptr symbol) { const T* ptr = symbol.get(); this->addWithoutOwnership(ptr); this->takeOwnershipOfSymbol(std::move(symbol)); return ptr; } template const T* takeOwnershipOfSymbol(std::unique_ptr symbol) { const T* ptr = symbol.get(); fOwnedSymbols.push_back(std::move(symbol)); return ptr; } template const T* takeOwnershipOfIRNode(std::unique_ptr node) { const T* ptr = node.get(); fOwnedNodes.push_back(std::move(node)); return ptr; } /** * Given type = `float` and arraySize = 5, creates the array type `float[5]` in the symbol * table. The created array type is returned. If zero is passed, the base type is returned * unchanged. */ const Type* addArrayDimension(const Type* type, int arraySize); // Call fn for every symbol in the table. You may not mutate anything. template void foreach(Fn&& fn) const { fSymbols.foreach( [&fn](const SymbolKey& key, const Symbol* symbol) { fn(key.fName, symbol); }); } size_t count() { return fSymbols.count(); } /** Returns true if this is a built-in SymbolTable. */ bool isBuiltin() const { return fBuiltin; } /** * Returns the built-in symbol table that this SymbolTable rests upon. * If this symbol table is already a built-in, it will be returned as-is. */ SkSL::SymbolTable* builtinParent() { return this->isBuiltin() ? this : fParent->builtinParent(); } const String* takeOwnershipOfString(String n); std::shared_ptr fParent; std::vector> fOwnedSymbols; private: struct SymbolKey { skstd::string_view fName; uint32_t fHash; bool operator==(const SymbolKey& that) const { return fName == that.fName; } bool operator!=(const SymbolKey& that) const { return fName != that.fName; } struct Hash { uint32_t operator()(const SymbolKey& key) const { return key.fHash; } }; }; static SymbolKey MakeSymbolKey(skstd::string_view name) { return SymbolKey{name, SkOpts::hash_fn(name.data(), name.size(), 0)}; } const Symbol* lookup(SymbolTable* writableSymbolTable, const SymbolKey& key); static std::vector GetFunctions(const Symbol& s); bool fBuiltin = false; std::vector> fOwnedNodes; std::forward_list fOwnedStrings; SkTHashMap fSymbols; const Context& fContext; friend class Dehydrator; }; /** * While in scope, the passed-in symbol table is replaced with a child symbol table. */ class AutoSymbolTable { public: AutoSymbolTable(std::shared_ptr* s) : fSymbolTable(s) { SkDEBUGCODE(fPrevious = fSymbolTable->get();) SymbolTable::Push(fSymbolTable); } ~AutoSymbolTable() { SymbolTable::Pop(fSymbolTable); SkASSERT(fPrevious == fSymbolTable->get()); } std::shared_ptr* fSymbolTable; SkDEBUGCODE(SymbolTable* fPrevious;) }; } // namespace SkSL #endif