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 #include "src/sksl/ir/SkSLSymbolTable.h"
9
10 #include "src/sksl/SkSLContext.h"
11 #include "src/sksl/ir/SkSLSymbolAlias.h"
12 #include "src/sksl/ir/SkSLType.h"
13 #include "src/sksl/ir/SkSLUnresolvedFunction.h"
14
15 namespace SkSL {
16
GetFunctions(const Symbol & s)17 std::vector<const FunctionDeclaration*> SymbolTable::GetFunctions(const Symbol& s) {
18 switch (s.kind()) {
19 case Symbol::Kind::kFunctionDeclaration:
20 return { &s.as<FunctionDeclaration>() };
21 case Symbol::Kind::kUnresolvedFunction:
22 return s.as<UnresolvedFunction>().functions();
23 default:
24 return std::vector<const FunctionDeclaration*>();
25 }
26 }
27
operator [](skstd::string_view name)28 const Symbol* SymbolTable::operator[](skstd::string_view name) {
29 return this->lookup(fBuiltin ? nullptr : this, MakeSymbolKey(name));
30 }
31
lookup(SymbolTable * writableSymbolTable,const SymbolKey & key)32 const Symbol* SymbolTable::lookup(SymbolTable* writableSymbolTable, const SymbolKey& key) {
33 // Symbol-table lookup can cause new UnresolvedFunction nodes to be created; however, we don't
34 // want these to end up in built-in root symbol tables (where they will outlive the Program
35 // associated with those UnresolvedFunction nodes). `writableSymbolTable` tracks the closest
36 // symbol table to the root which is not a built-in.
37 if (!fBuiltin) {
38 writableSymbolTable = this;
39 }
40 const Symbol** symbolPPtr = fSymbols.find(key);
41 if (!symbolPPtr) {
42 if (fParent) {
43 return fParent->lookup(writableSymbolTable, key);
44 }
45 return nullptr;
46 }
47
48 const Symbol* symbol = *symbolPPtr;
49 if (fParent) {
50 auto functions = GetFunctions(*symbol);
51 if (functions.size() > 0) {
52 bool modified = false;
53 const Symbol* previous = fParent->lookup(writableSymbolTable, key);
54 if (previous) {
55 auto previousFunctions = GetFunctions(*previous);
56 for (const FunctionDeclaration* prev : previousFunctions) {
57 bool found = false;
58 for (const FunctionDeclaration* current : functions) {
59 if (current->matches(*prev)) {
60 found = true;
61 break;
62 }
63 }
64 if (!found) {
65 functions.push_back(prev);
66 modified = true;
67 }
68 }
69 if (modified) {
70 SkASSERT(functions.size() > 1);
71 return writableSymbolTable
72 ? writableSymbolTable->takeOwnershipOfSymbol(
73 std::make_unique<UnresolvedFunction>(functions))
74 : nullptr;
75 }
76 }
77 }
78 }
79 while (symbol && symbol->is<SymbolAlias>()) {
80 symbol = symbol->as<SymbolAlias>().origSymbol();
81 }
82 return symbol;
83 }
84
takeOwnershipOfString(String str)85 const String* SymbolTable::takeOwnershipOfString(String str) {
86 fOwnedStrings.push_front(std::move(str));
87 // Because fOwnedStrings is a linked list, pointers to elements are stable.
88 return &fOwnedStrings.front();
89 }
90
addAlias(skstd::string_view name,const Symbol * symbol)91 void SymbolTable::addAlias(skstd::string_view name, const Symbol* symbol) {
92 this->add(std::make_unique<SymbolAlias>(symbol->fLine, name, symbol));
93 }
94
addWithoutOwnership(const Symbol * symbol)95 void SymbolTable::addWithoutOwnership(const Symbol* symbol) {
96 const skstd::string_view& name = symbol->name();
97
98 const Symbol*& refInSymbolTable = fSymbols[MakeSymbolKey(name)];
99 if (refInSymbolTable == nullptr) {
100 refInSymbolTable = symbol;
101 return;
102 }
103
104 if (!symbol->is<FunctionDeclaration>()) {
105 fContext.fErrors->error(symbol->fLine, "symbol '" + name + "' was already defined");
106 return;
107 }
108
109 std::vector<const FunctionDeclaration*> functions;
110 if (refInSymbolTable->is<FunctionDeclaration>()) {
111 functions = {&refInSymbolTable->as<FunctionDeclaration>(),
112 &symbol->as<FunctionDeclaration>()};
113
114 refInSymbolTable = this->takeOwnershipOfSymbol(
115 std::make_unique<UnresolvedFunction>(std::move(functions)));
116 } else if (refInSymbolTable->is<UnresolvedFunction>()) {
117 functions = refInSymbolTable->as<UnresolvedFunction>().functions();
118 functions.push_back(&symbol->as<FunctionDeclaration>());
119
120 refInSymbolTable = this->takeOwnershipOfSymbol(
121 std::make_unique<UnresolvedFunction>(std::move(functions)));
122 }
123 }
124
addArrayDimension(const Type * type,int arraySize)125 const Type* SymbolTable::addArrayDimension(const Type* type, int arraySize) {
126 if (arraySize != 0) {
127 const String* arrayName = this->takeOwnershipOfString(type->getArrayName(arraySize));
128 type = this->takeOwnershipOfSymbol(Type::MakeArrayType(*arrayName, *type, arraySize));
129 }
130 return type;
131 }
132
133 } // namespace SkSL
134