/* * 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 "src/core/SkChecksum.h" #include "src/core/SkTHash.h" #include "src/sksl/ir/SkSLSymbol.h" #include #include #include #include #include #include #include #include namespace SkSL { class Context; class Expression; class Position; class Type; /** * Maps identifiers to symbols. */ class SymbolTable { public: explicit SymbolTable(bool builtin) : fBuiltin(builtin) {} explicit SymbolTable(SymbolTable* parent, bool builtin) : fParent(parent) , fBuiltin(builtin) {} /** * Creates a new, empty SymbolTable between this SymbolTable and its current parent. * The new symbol table is returned, and is also accessible as `this->fParent`. * The original parent is accessible as `this->fParent->fParent`. */ std::unique_ptr insertNewParent(); /** * 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)); } /** * Looks up the requested symbol and instantiates an Expression reference to it; will return a * VariableReference, TypeReference, FunctionReference, FieldAccess, or nullptr. */ std::unique_ptr instantiateSymbolRef(const Context& context, std::string_view name, Position pos); /** * 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(const Context& context, Symbol* symbol, std::string_view newName); /** * Removes a symbol from the symbol table. If this symbol table had ownership of the symbol, the * symbol is returned (and can be deleted or reinserted as desired); if not, null is returned. * In either event, the name will no longer correspond to the symbol. */ std::unique_ptr removeSymbol(const Symbol* symbol); /** * Moves a symbol from this symbol table to another one. If this symbol table had ownership of * the symbol, the ownership will be transferred as well. (If the symbol does not actually exist * in this table at all, it will still be added to the other table.) */ void moveSymbolTo(SymbolTable* otherTable, Symbol* sym, const Context& context); /** * 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 addWithoutOwnershipOrDie(Symbol* symbol); void addWithoutOwnership(const Context& context, Symbol* symbol); /** * Adds a symbol to this symbol table, conferring ownership. The symbol table will always be * updated to reference the new symbol. If the symbol already exists, an error will be reported. */ template T* add(const Context& context, std::unique_ptr symbol) { T* ptr = symbol.get(); this->addWithoutOwnership(context, this->takeOwnershipOfSymbol(std::move(symbol))); return ptr; } /** * Adds a symbol to this symbol table, conferring ownership. The symbol table will always be * updated to reference the new symbol. If the symbol already exists, abort. */ template T* addOrDie(std::unique_ptr symbol) { T* ptr = symbol.get(); this->addWithoutOwnershipOrDie(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 T* inject(std::unique_ptr 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 T* takeOwnershipOfSymbol(std::unique_ptr 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 Context& context, 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); }); } // Checks `this` directly against `other` to see if the two symbol tables have any names in // common. Parent tables are not considered. bool wouldShadowSymbolsFrom(const SymbolTable* other) const; size_t count() const { 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; } SymbolTable* fParent = nullptr; std::vector> 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, SkChecksum::Hash32(name.data(), name.size())}; } Symbol* lookup(const SymbolKey& key) const; bool addWithoutOwnership(Symbol* symbol); bool fBuiltin = false; bool fAtModuleBoundary = false; std::forward_list fOwnedStrings; skia_private::THashMap fSymbols; }; } // namespace SkSL #endif