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