blob: e3bea7a5c7c2baa067069e04d32a757b8425beb8 [file] [log] [blame]
* Copyright 2016 Google Inc.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
#include "include/private/SkSLString.h"
#include "include/private/SkSLSymbol.h"
#include "include/private/SkTArray.h"
#include "include/private/SkTHash.h"
#include "src/sksl/SkSLErrorReporter.h"
#include <deque>
#include <memory>
#include <vector>
namespace SkSL {
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 {
SymbolTable(ErrorReporter* errorReporter, bool builtin)
: fBuiltin(builtin)
, fErrorReporter(*errorReporter) {}
SymbolTable(std::shared_ptr<SymbolTable> parent, bool builtin)
: fParent(parent)
, fBuiltin(builtin)
, fErrorReporter(parent->fErrorReporter) {}
* 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 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[](StringFragment name);
* Creates a new name for a symbol which already exists; does not take ownership of Symbol*.
void addAlias(StringFragment name, const Symbol* symbol);
void addWithoutOwnership(const Symbol* symbol);
template <typename T>
const T* add(std::unique_ptr<T> symbol) {
const T* ptr = symbol.get();
return ptr;
template <typename T>
const T* takeOwnershipOfSymbol(std::unique_ptr<T> symbol) {
const T* ptr = symbol.get();
return ptr;
template <typename T>
const T* takeOwnershipOfIRNode(std::unique_ptr<T> node) {
const T* ptr = node.get();
return ptr;
* Given type = `float` and arraySize = 5, creates the array type `float[5]` in the symbol
* table. The created array type is returned. `kUnsizedArray` can be passed as a `[]` dimension.
* 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 {
[&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 String* takeOwnershipOfString(String n);
std::shared_ptr<SymbolTable> fParent;
std::vector<std::unique_ptr<const Symbol>> fOwnedSymbols;
struct SymbolKey {
StringFragment 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(StringFragment name) {
return SymbolKey{name, SkOpts::hash_fn(, name.size(), 0)};
const Symbol* lookup(SymbolTable* writableSymbolTable, const SymbolKey& key);
static std::vector<const FunctionDeclaration*> GetFunctions(const Symbol& s);
bool fBuiltin = false;
std::vector<std::unique_ptr<IRNode>> fOwnedNodes;
// A deque is used here because insertion is guaranteed not to invalidate the pointers inside.
std::deque<String> fOwnedStrings;
SkTHashMap<SymbolKey, const Symbol*, SymbolKey::Hash> fSymbols;
ErrorReporter& fErrorReporter;
friend class Dehydrator;
} // namespace SkSL