xref: /aosp_15_r20/external/skia/src/sksl/ir/SkSLSymbolTable.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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/core/SkTypes.h"
12 #include "src/core/SkChecksum.h"
13 #include "src/core/SkTHash.h"
14 #include "src/sksl/ir/SkSLSymbol.h"
15 
16 #include <cstddef>
17 #include <cstdint>
18 #include <forward_list>
19 #include <memory>
20 #include <string>
21 #include <string_view>
22 #include <utility>
23 #include <vector>
24 
25 namespace SkSL {
26 
27 class Context;
28 class Expression;
29 class Position;
30 class Type;
31 
32 /**
33  * Maps identifiers to symbols.
34  */
35 class SymbolTable {
36 public:
SymbolTable(bool builtin)37     explicit SymbolTable(bool builtin)
38             : fBuiltin(builtin) {}
39 
SymbolTable(SymbolTable * parent,bool builtin)40     explicit SymbolTable(SymbolTable* parent, bool builtin)
41             : fParent(parent)
42             , fBuiltin(builtin) {}
43 
44     /**
45      * Creates a new, empty SymbolTable between this SymbolTable and its current parent.
46      * The new symbol table is returned, and is also accessible as `this->fParent`.
47      * The original parent is accessible as `this->fParent->fParent`.
48      */
49     std::unique_ptr<SymbolTable> insertNewParent();
50 
51     /**
52      * Looks up the requested symbol and returns a const pointer.
53      */
find(std::string_view name)54     const Symbol* find(std::string_view name) const {
55         return this->lookup(MakeSymbolKey(name));
56     }
57 
58     /**
59      * Looks up the requested symbol, only searching the built-in symbol tables. Always const.
60      */
61     const Symbol* findBuiltinSymbol(std::string_view name) const;
62 
63     /**
64      * Looks up the requested symbol and returns a mutable pointer. Use caution--mutating a symbol
65      * will have program-wide impact, and built-in symbol tables must never be mutated.
66      */
findMutable(std::string_view name)67     Symbol* findMutable(std::string_view name) const {
68         return this->lookup(MakeSymbolKey(name));
69     }
70 
71     /**
72      * Looks up the requested symbol and instantiates an Expression reference to it; will return a
73      * VariableReference, TypeReference, FunctionReference, FieldAccess, or nullptr.
74      */
75     std::unique_ptr<Expression> instantiateSymbolRef(const Context& context,
76                                                      std::string_view name,
77                                                      Position pos);
78 
79     /**
80      * Assigns a new name to the passed-in symbol. The old name will continue to exist in the symbol
81      * table and point to the symbol.
82      */
83     void renameSymbol(const Context& context, Symbol* symbol, std::string_view newName);
84 
85     /**
86      * Removes a symbol from the symbol table. If this symbol table had ownership of the symbol, the
87      * symbol is returned (and can be deleted or reinserted as desired); if not, null is returned.
88      * In either event, the name will no longer correspond to the symbol.
89      */
90     std::unique_ptr<Symbol> removeSymbol(const Symbol* symbol);
91 
92     /**
93      * Moves a symbol from this symbol table to another one. If this symbol table had ownership of
94      * the symbol, the ownership will be transferred as well. (If the symbol does not actually exist
95      * in this table at all, it will still be added to the other table.)
96      */
97     void moveSymbolTo(SymbolTable* otherTable, Symbol* sym, const Context& context);
98 
99     /**
100      * Returns true if the name refers to a type (user or built-in) in the current symbol table.
101      */
102     bool isType(std::string_view name) const;
103 
104     /**
105      * Returns true if the name refers to a builtin type.
106      */
107     bool isBuiltinType(std::string_view name) const;
108 
109     /**
110      * Adds a symbol to this symbol table, without conferring ownership. The caller is responsible
111      * for keeping the Symbol alive throughout the lifetime of the program/module.
112      */
113     void addWithoutOwnershipOrDie(Symbol* symbol);
114     void addWithoutOwnership(const Context& context, Symbol* symbol);
115 
116     /**
117      * Adds a symbol to this symbol table, conferring ownership. The symbol table will always be
118      * updated to reference the new symbol. If the symbol already exists, an error will be reported.
119      */
120     template <typename T>
add(const Context & context,std::unique_ptr<T> symbol)121     T* add(const Context& context, std::unique_ptr<T> symbol) {
122         T* ptr = symbol.get();
123         this->addWithoutOwnership(context, this->takeOwnershipOfSymbol(std::move(symbol)));
124         return ptr;
125     }
126 
127     /**
128      * Adds a symbol to this symbol table, conferring ownership. The symbol table will always be
129      * updated to reference the new symbol. If the symbol already exists, abort.
130      */
131     template <typename T>
addOrDie(std::unique_ptr<T> symbol)132     T* addOrDie(std::unique_ptr<T> symbol) {
133         T* ptr = symbol.get();
134         this->addWithoutOwnershipOrDie(this->takeOwnershipOfSymbol(std::move(symbol)));
135         return ptr;
136     }
137 
138     /**
139      * Forces a symbol into this symbol table, without conferring ownership. Replaces any existing
140      * symbol with the same name, if one exists.
141      */
142     void injectWithoutOwnership(Symbol* symbol);
143 
144     /**
145      * Forces a symbol into this symbol table, conferring ownership. Replaces any existing symbol
146      * with the same name, if one exists.
147      */
148     template <typename T>
inject(std::unique_ptr<T> symbol)149     T* inject(std::unique_ptr<T> symbol) {
150         T* ptr = symbol.get();
151         this->injectWithoutOwnership(this->takeOwnershipOfSymbol(std::move(symbol)));
152         return ptr;
153     }
154 
155     /**
156      * Confers ownership of a symbol without adding its name to the lookup table.
157      */
158     template <typename T>
takeOwnershipOfSymbol(std::unique_ptr<T> symbol)159     T* takeOwnershipOfSymbol(std::unique_ptr<T> symbol) {
160         T* ptr = symbol.get();
161         fOwnedSymbols.push_back(std::move(symbol));
162         return ptr;
163     }
164 
165     /**
166      * Given type = `float` and arraySize = 5, creates the array type `float[5]` in the symbol
167      * table. The created array type is returned. If zero is passed, the base type is returned
168      * unchanged.
169      */
170     const Type* addArrayDimension(const Context& context, const Type* type, int arraySize);
171 
172     // Call fn for every symbol in the table. You may not mutate anything.
173     template <typename Fn>
foreach(Fn && fn)174     void foreach(Fn&& fn) const {
175         fSymbols.foreach(
176                 [&fn](const SymbolKey& key, const Symbol* symbol) { fn(key.fName, symbol); });
177     }
178 
179     // Checks `this` directly against `other` to see if the two symbol tables have any names in
180     // common. Parent tables are not considered.
181     bool wouldShadowSymbolsFrom(const SymbolTable* other) const;
182 
count()183     size_t count() const {
184         return fSymbols.count();
185     }
186 
187     /** Returns true if this is a built-in SymbolTable. */
isBuiltin()188     bool isBuiltin() const {
189         return fBuiltin;
190     }
191 
192     const std::string* takeOwnershipOfString(std::string n);
193 
194     /**
195      * Indicates that this symbol table's parent is in a different module than this one.
196      */
markModuleBoundary()197     void markModuleBoundary() {
198         fAtModuleBoundary = true;
199     }
200 
201     SymbolTable* fParent = nullptr;
202 
203     std::vector<std::unique_ptr<Symbol>> fOwnedSymbols;
204 
205 private:
206     struct SymbolKey {
207         std::string_view fName;
208         uint32_t         fHash;
209 
210         bool operator==(const SymbolKey& that) const { return fName == that.fName; }
211         bool operator!=(const SymbolKey& that) const { return fName != that.fName; }
212         struct Hash {
operatorSymbolKey::Hash213             uint32_t operator()(const SymbolKey& key) const { return key.fHash; }
214         };
215     };
216 
MakeSymbolKey(std::string_view name)217     static SymbolKey MakeSymbolKey(std::string_view name) {
218         return SymbolKey{name, SkChecksum::Hash32(name.data(), name.size())};
219     }
220 
221     Symbol* lookup(const SymbolKey& key) const;
222     bool addWithoutOwnership(Symbol* symbol);
223 
224     bool fBuiltin = false;
225     bool fAtModuleBoundary = false;
226     std::forward_list<std::string> fOwnedStrings;
227     skia_private::THashMap<SymbolKey, Symbol*, SymbolKey::Hash> fSymbols;
228 };
229 
230 }  // namespace SkSL
231 
232 #endif
233