• 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 #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