| /* |
| * 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/core/SkTypes.h" |
| #include "include/private/SkOpts_spi.h" |
| #include "include/private/SkSLSymbol.h" |
| #include "include/private/SkTHash.h" |
| |
| #include <cstddef> |
| #include <cstdint> |
| #include <forward_list> |
| #include <memory> |
| #include <string> |
| #include <string_view> |
| #include <type_traits> |
| #include <utility> |
| #include <vector> |
| |
| namespace SkSL { |
| |
| class Type; |
| |
| /** |
| * Maps identifiers to symbols. |
| */ |
| class SymbolTable { |
| public: |
| explicit SymbolTable(bool builtin) |
| : fBuiltin(builtin) {} |
| |
| explicit SymbolTable(std::shared_ptr<SymbolTable> parent, bool builtin) |
| : fParent(parent) |
| , fBuiltin(builtin) {} |
| |
| /** Replaces the passed-in SymbolTable with a newly-created child symbol table. */ |
| static void Push(std::shared_ptr<SymbolTable>* table) { |
| Push(table, (*table)->isBuiltin()); |
| } |
| static void Push(std::shared_ptr<SymbolTable>* table, bool isBuiltin) { |
| *table = std::make_shared<SymbolTable>(*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<SymbolTable>* 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<SymbolTable> WrapIfBuiltin(std::shared_ptr<SymbolTable> symbolTable) { |
| if (!symbolTable) { |
| return nullptr; |
| } |
| if (!symbolTable->isBuiltin()) { |
| return symbolTable; |
| } |
| return std::make_shared<SymbolTable>(std::move(symbolTable), /*builtin=*/false); |
| } |
| |
| /** |
| * Looks up the requested symbol and returns a const pointer. |
| */ |
| const Symbol* find(std::string_view name) const { |
| return this->lookup(MakeSymbolKey(name)); |
| } |
| |
| /** |
| * Looks up the requested symbol, only searching the built-in symbol tables. Always const. |
| */ |
| const Symbol* findBuiltinSymbol(std::string_view name) const; |
| |
| /** |
| * Looks up the requested symbol and returns a mutable pointer. Use caution--mutating a symbol |
| * will have program-wide impact, and built-in symbol tables must never be mutated. |
| */ |
| Symbol* findMutable(std::string_view name) const { |
| return this->lookup(MakeSymbolKey(name)); |
| } |
| |
| /** |
| * Assigns a new name to the passed-in symbol. The old name will continue to exist in the symbol |
| * table and point to the symbol. |
| */ |
| void renameSymbol(Symbol* symbol, std::string_view newName); |
| |
| /** |
| * Returns true if the name refers to a type (user or built-in) in the current symbol table. |
| */ |
| bool isType(std::string_view name) const; |
| |
| /** |
| * Returns true if the name refers to a builtin type. |
| */ |
| bool isBuiltinType(std::string_view name) const; |
| |
| /** |
| * Adds a symbol to this symbol table, without conferring ownership. The caller is responsible |
| * for keeping the Symbol alive throughout the lifetime of the program/module. |
| */ |
| void addWithoutOwnership(Symbol* symbol); |
| |
| /** |
| * Adds a symbol to this symbol table, conferring ownership. |
| */ |
| template <typename T> |
| T* add(std::unique_ptr<T> symbol) { |
| T* ptr = symbol.get(); |
| this->addWithoutOwnership(this->takeOwnershipOfSymbol(std::move(symbol))); |
| return ptr; |
| } |
| |
| /** |
| * Forces a symbol into this symbol table, without conferring ownership. Replaces any existing |
| * symbol with the same name, if one exists. |
| */ |
| void injectWithoutOwnership(Symbol* symbol); |
| |
| /** |
| * Forces a symbol into this symbol table, conferring ownership. Replaces any existing symbol |
| * with the same name, if one exists. |
| */ |
| template <typename T> |
| T* inject(std::unique_ptr<T> symbol) { |
| T* ptr = symbol.get(); |
| this->injectWithoutOwnership(this->takeOwnershipOfSymbol(std::move(symbol))); |
| return ptr; |
| } |
| |
| /** |
| * Confers ownership of a symbol without adding its name to the lookup table. |
| */ |
| template <typename T> |
| T* takeOwnershipOfSymbol(std::unique_ptr<T> symbol) { |
| T* ptr = symbol.get(); |
| fOwnedSymbols.push_back(std::move(symbol)); |
| 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 <typename Fn> |
| 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; |
| } |
| |
| const std::string* takeOwnershipOfString(std::string n); |
| |
| /** |
| * Indicates that this symbol table's parent is in a different module than this one. |
| */ |
| void markModuleBoundary() { |
| fAtModuleBoundary = true; |
| } |
| |
| std::shared_ptr<SymbolTable> fParent; |
| |
| std::vector<std::unique_ptr<const Symbol>> fOwnedSymbols; |
| |
| private: |
| struct SymbolKey { |
| std::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(std::string_view name) { |
| return SymbolKey{name, SkOpts::hash_fn(name.data(), name.size(), 0)}; |
| } |
| |
| Symbol* lookup(const SymbolKey& key) const; |
| |
| bool fBuiltin = false; |
| bool fAtModuleBoundary = false; |
| std::forward_list<std::string> fOwnedStrings; |
| SkTHashMap<SymbolKey, Symbol*, SymbolKey::Hash> fSymbols; |
| }; |
| |
| } // namespace SkSL |
| |
| #endif |