• 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[](skstd::string_view name);
78 
79     /**
80      * Creates a new name for a symbol which already exists; does not take ownership of Symbol*.
81      */
82     void addAlias(skstd::string_view name, const Symbol* symbol);
83 
84     void addWithoutOwnership(const Symbol* symbol);
85 
86     template <typename T>
add(std::unique_ptr<T> symbol)87     const T* add(std::unique_ptr<T> symbol) {
88         const T* ptr = symbol.get();
89         this->addWithoutOwnership(ptr);
90         this->takeOwnershipOfSymbol(std::move(symbol));
91         return ptr;
92     }
93 
94     template <typename T>
takeOwnershipOfSymbol(std::unique_ptr<T> symbol)95     const T* takeOwnershipOfSymbol(std::unique_ptr<T> symbol) {
96         const T* ptr = symbol.get();
97         fOwnedSymbols.push_back(std::move(symbol));
98         return ptr;
99     }
100 
101     template <typename T>
takeOwnershipOfIRNode(std::unique_ptr<T> node)102     const T* takeOwnershipOfIRNode(std::unique_ptr<T> node) {
103         const T* ptr = node.get();
104         fOwnedNodes.push_back(std::move(node));
105         return ptr;
106     }
107 
108     /**
109      * Given type = `float` and arraySize = 5, creates the array type `float[5]` in the symbol
110      * table. The created array type is returned. If zero is passed, the base type is returned
111      * unchanged.
112      */
113     const Type* addArrayDimension(const Type* type, int arraySize);
114 
115     // Call fn for every symbol in the table.  You may not mutate anything.
116     template <typename Fn>
foreach(Fn && fn)117     void foreach(Fn&& fn) const {
118         fSymbols.foreach(
119                 [&fn](const SymbolKey& key, const Symbol* symbol) { fn(key.fName, symbol); });
120     }
121 
count()122     size_t count() {
123         return fSymbols.count();
124     }
125 
126     /** Returns true if this is a built-in SymbolTable. */
isBuiltin()127     bool isBuiltin() const {
128         return fBuiltin;
129     }
130 
131     /**
132      * Returns the built-in symbol table that this SymbolTable rests upon.
133      * If this symbol table is already a built-in, it will be returned as-is.
134      */
builtinParent()135     SkSL::SymbolTable* builtinParent() {
136         return this->isBuiltin() ? this : fParent->builtinParent();
137     }
138 
139     const String* takeOwnershipOfString(String n);
140 
141     std::shared_ptr<SymbolTable> fParent;
142 
143     std::vector<std::unique_ptr<const Symbol>> fOwnedSymbols;
144 
145 private:
146     struct SymbolKey {
147         skstd::string_view fName;
148         uint32_t       fHash;
149 
150         bool operator==(const SymbolKey& that) const { return fName == that.fName; }
151         bool operator!=(const SymbolKey& that) const { return fName != that.fName; }
152         struct Hash {
operatorSymbolKey::Hash153             uint32_t operator()(const SymbolKey& key) const { return key.fHash; }
154         };
155     };
156 
MakeSymbolKey(skstd::string_view name)157     static SymbolKey MakeSymbolKey(skstd::string_view name) {
158         return SymbolKey{name, SkOpts::hash_fn(name.data(), name.size(), 0)};
159     }
160 
161     const Symbol* lookup(SymbolTable* writableSymbolTable, const SymbolKey& key);
162 
163     static std::vector<const FunctionDeclaration*> GetFunctions(const Symbol& s);
164 
165     bool fBuiltin = false;
166     std::vector<std::unique_ptr<IRNode>> fOwnedNodes;
167     std::forward_list<String> fOwnedStrings;
168     SkTHashMap<SymbolKey, const Symbol*, SymbolKey::Hash> fSymbols;
169     const Context& fContext;
170 
171     friend class Dehydrator;
172 };
173 
174 /**
175  * While in scope, the passed-in symbol table is replaced with a child symbol table.
176  */
177 class AutoSymbolTable {
178 public:
AutoSymbolTable(std::shared_ptr<SymbolTable> * s)179     AutoSymbolTable(std::shared_ptr<SymbolTable>* s)
180         : fSymbolTable(s) {
181         SkDEBUGCODE(fPrevious = fSymbolTable->get();)
182         SymbolTable::Push(fSymbolTable);
183     }
184 
~AutoSymbolTable()185     ~AutoSymbolTable() {
186         SymbolTable::Pop(fSymbolTable);
187         SkASSERT(fPrevious == fSymbolTable->get());
188     }
189 
190     std::shared_ptr<SymbolTable>* fSymbolTable;
191     SkDEBUGCODE(SymbolTable* fPrevious;)
192 };
193 
194 }  // namespace SkSL
195 
196 #endif
197