• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef SKSL_SYMBOLTABLE
9 #define SKSL_SYMBOLTABLE
10 
11 #include "include/private/SkSLString.h"
12 #include "include/private/SkSLSymbol.h"
13 #include "include/private/SkTArray.h"
14 #include "include/private/SkTHash.h"
15 #include "include/sksl/SkSLErrorReporter.h"
16 
17 #include <forward_list>
18 #include <memory>
19 #include <vector>
20 
21 namespace SkSL {
22 
23 class Context;
24 class FunctionDeclaration;
25 
26 /**
27  * Maps identifiers to symbols. Functions, in particular, are mapped to either FunctionDeclaration
28  * or UnresolvedFunction depending on whether they are overloaded or not.
29  */
30 class SymbolTable {
31 public:
SymbolTable(const Context & context,bool builtin)32     SymbolTable(const Context& context, bool builtin)
33     : fBuiltin(builtin)
34     , fContext(context) {}
35 
SymbolTable(std::shared_ptr<SymbolTable> parent,bool builtin)36     SymbolTable(std::shared_ptr<SymbolTable> parent, bool builtin)
37     : fParent(parent)
38     , fBuiltin(builtin)
39     , fContext(parent->fContext) {}
40 
41     /** Replaces the passed-in SymbolTable with a newly-created child symbol table. */
Push(std::shared_ptr<SymbolTable> * table)42     static void Push(std::shared_ptr<SymbolTable>* table) {
43         Push(table, (*table)->isBuiltin());
44     }
Push(std::shared_ptr<SymbolTable> * table,bool isBuiltin)45     static void Push(std::shared_ptr<SymbolTable>* table, bool isBuiltin) {
46         *table = std::make_shared<SymbolTable>(*table, isBuiltin);
47     }
48 
49     /**
50      * Replaces the passed-in SymbolTable with its parent. If the child symbol table is otherwise
51      * unreferenced, it will be deleted.
52      */
Pop(std::shared_ptr<SymbolTable> * table)53     static void Pop(std::shared_ptr<SymbolTable>* table) {
54         *table = (*table)->fParent;
55     }
56 
57     /**
58      * If the input is a built-in symbol table, returns a new empty symbol table as a child of the
59      * input table. If the input is not a built-in symbol table, returns it as-is. Built-in symbol
60      * tables must not be mutated after creation, so they must be wrapped if mutation is necessary.
61      */
WrapIfBuiltin(std::shared_ptr<SymbolTable> symbolTable)62     static std::shared_ptr<SymbolTable> WrapIfBuiltin(std::shared_ptr<SymbolTable> symbolTable) {
63         if (!symbolTable) {
64             return nullptr;
65         }
66         if (!symbolTable->isBuiltin()) {
67             return symbolTable;
68         }
69         return std::make_shared<SymbolTable>(std::move(symbolTable), /*builtin=*/false);
70     }
71 
72     /**
73      * Looks up the requested symbol and returns it. If a function has overloads, an
74      * UnresolvedFunction symbol (pointing to all of the candidates) will be added to the symbol
75      * table and returned.
76      */
77     const Symbol* operator[](std::string_view name);
78 
79     void addWithoutOwnership(const Symbol* symbol);
80 
81     template <typename T>
add(std::unique_ptr<T> symbol)82     const T* add(std::unique_ptr<T> symbol) {
83         const T* ptr = symbol.get();
84         this->addWithoutOwnership(ptr);
85         this->takeOwnershipOfSymbol(std::move(symbol));
86         return ptr;
87     }
88 
89     template <typename T>
takeOwnershipOfSymbol(std::unique_ptr<T> symbol)90     const T* takeOwnershipOfSymbol(std::unique_ptr<T> symbol) {
91         const T* ptr = symbol.get();
92         fOwnedSymbols.push_back(std::move(symbol));
93         return ptr;
94     }
95 
96     template <typename T>
takeOwnershipOfIRNode(std::unique_ptr<T> node)97     const T* takeOwnershipOfIRNode(std::unique_ptr<T> node) {
98         const T* ptr = node.get();
99         fOwnedNodes.push_back(std::move(node));
100         return ptr;
101     }
102 
103     /**
104      * Given type = `float` and arraySize = 5, creates the array type `float[5]` in the symbol
105      * table. The created array type is returned. If zero is passed, the base type is returned
106      * unchanged.
107      */
108     const Type* addArrayDimension(const Type* type, int arraySize);
109 
110     // Call fn for every symbol in the table.  You may not mutate anything.
111     template <typename Fn>
foreach(Fn && fn)112     void foreach(Fn&& fn) const {
113         fSymbols.foreach(
114                 [&fn](const SymbolKey& key, const Symbol* symbol) { fn(key.fName, symbol); });
115     }
116 
count()117     size_t count() {
118         return fSymbols.count();
119     }
120 
121     /** Returns true if this is a built-in SymbolTable. */
isBuiltin()122     bool isBuiltin() const {
123         return fBuiltin;
124     }
125 
126     /**
127      * Returns the built-in symbol table that this SymbolTable rests upon.
128      * If this symbol table is already a built-in, it will be returned as-is.
129      */
builtinParent()130     SkSL::SymbolTable* builtinParent() {
131         return this->isBuiltin() ? this : fParent->builtinParent();
132     }
133 
134     const std::string* takeOwnershipOfString(std::string n);
135 
136     std::shared_ptr<SymbolTable> fParent;
137 
138     std::vector<std::unique_ptr<const Symbol>> fOwnedSymbols;
139 
140 private:
141     struct SymbolKey {
142         std::string_view fName;
143         uint32_t       fHash;
144 
145         bool operator==(const SymbolKey& that) const { return fName == that.fName; }
146         bool operator!=(const SymbolKey& that) const { return fName != that.fName; }
147         struct Hash {
operatorSymbolKey::Hash148             uint32_t operator()(const SymbolKey& key) const { return key.fHash; }
149         };
150     };
151 
MakeSymbolKey(std::string_view name)152     static SymbolKey MakeSymbolKey(std::string_view name) {
153         return SymbolKey{name, SkOpts::hash_fn(name.data(), name.size(), 0)};
154     }
155 
156     const Symbol* lookup(SymbolTable* writableSymbolTable, const SymbolKey& key);
157 
158     static std::vector<const FunctionDeclaration*> GetFunctions(const Symbol& s);
159 
160     bool fBuiltin = false;
161     std::vector<std::unique_ptr<IRNode>> fOwnedNodes;
162     std::forward_list<std::string> fOwnedStrings;
163     SkTHashMap<SymbolKey, const Symbol*, SymbolKey::Hash> fSymbols;
164     const Context& fContext;
165 
166     friend class Dehydrator;
167 };
168 
169 /**
170  * While in scope, the passed-in symbol table is replaced with a child symbol table.
171  */
172 class AutoSymbolTable {
173 public:
AutoSymbolTable(std::shared_ptr<SymbolTable> * s)174     AutoSymbolTable(std::shared_ptr<SymbolTable>* s)
175         : fSymbolTable(s) {
176         SkDEBUGCODE(fPrevious = fSymbolTable->get();)
177         SymbolTable::Push(fSymbolTable);
178     }
179 
~AutoSymbolTable()180     ~AutoSymbolTable() {
181         SymbolTable::Pop(fSymbolTable);
182         SkASSERT(fPrevious == fSymbolTable->get());
183     }
184 
185     std::shared_ptr<SymbolTable>* fSymbolTable;
186     SkDEBUGCODE(SymbolTable* fPrevious;)
187 };
188 
189 }  // namespace SkSL
190 
191 #endif
192