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/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 [](std::string_view name)27 const Symbol* SymbolTable::operator[](std::string_view 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 return symbol;
79 }
80
takeOwnershipOfString(std::string str)81 const std::string* SymbolTable::takeOwnershipOfString(std::string str) {
82 fOwnedStrings.push_front(std::move(str));
83 // Because fOwnedStrings is a linked list, pointers to elements are stable.
84 return &fOwnedStrings.front();
85 }
86
addWithoutOwnership(const Symbol * symbol)87 void SymbolTable::addWithoutOwnership(const Symbol* symbol) {
88 const std::string_view& name = symbol->name();
89
90 const Symbol*& refInSymbolTable = fSymbols[MakeSymbolKey(name)];
91 if (refInSymbolTable == nullptr) {
92 refInSymbolTable = symbol;
93 return;
94 }
95
96 if (!symbol->is<FunctionDeclaration>()) {
97 fContext.fErrors->error(symbol->fLine, "symbol '" + std::string(name) +
98 "' was already defined");
99 return;
100 }
101
102 std::vector<const FunctionDeclaration*> functions;
103 if (refInSymbolTable->is<FunctionDeclaration>()) {
104 functions = {&refInSymbolTable->as<FunctionDeclaration>(),
105 &symbol->as<FunctionDeclaration>()};
106
107 refInSymbolTable = this->takeOwnershipOfSymbol(
108 std::make_unique<UnresolvedFunction>(std::move(functions)));
109 } else if (refInSymbolTable->is<UnresolvedFunction>()) {
110 functions = refInSymbolTable->as<UnresolvedFunction>().functions();
111 functions.push_back(&symbol->as<FunctionDeclaration>());
112
113 refInSymbolTable = this->takeOwnershipOfSymbol(
114 std::make_unique<UnresolvedFunction>(std::move(functions)));
115 }
116 }
117
addArrayDimension(const Type * type,int arraySize)118 const Type* SymbolTable::addArrayDimension(const Type* type, int arraySize) {
119 if (arraySize != 0) {
120 const std::string* arrayName = this->takeOwnershipOfString(type->getArrayName(arraySize));
121 type = this->takeOwnershipOfSymbol(Type::MakeArrayType(*arrayName, *type, arraySize));
122 }
123 return type;
124 }
125
126 } // namespace SkSL
127