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