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/SkSLThreadContext.h"
11 #include "src/sksl/ir/SkSLFunctionDeclaration.h"
12 #include "src/sksl/ir/SkSLType.h"
13
14 namespace SkSL {
15
isType(std::string_view name) const16 bool SymbolTable::isType(std::string_view name) const {
17 const Symbol* symbol = this->find(name);
18 return symbol && symbol->is<Type>();
19 }
20
isBuiltinType(std::string_view name) const21 bool SymbolTable::isBuiltinType(std::string_view name) const {
22 if (!this->isBuiltin()) {
23 return fParent && fParent->isBuiltinType(name);
24 }
25 return this->isType(name);
26 }
27
findBuiltinSymbol(std::string_view name) const28 const Symbol* SymbolTable::findBuiltinSymbol(std::string_view name) const {
29 if (!this->isBuiltin()) {
30 return fParent ? fParent->findBuiltinSymbol(name) : nullptr;
31 }
32 return this->find(name);
33 }
34
lookup(const SymbolKey & key) const35 Symbol* SymbolTable::lookup(const SymbolKey& key) const {
36 Symbol** symbolPPtr = fSymbols.find(key);
37 if (symbolPPtr) {
38 return *symbolPPtr;
39 }
40
41 // The symbol wasn't found; recurse into the parent symbol table.
42 return fParent ? fParent->lookup(key) : nullptr;
43 }
44
renameSymbol(Symbol * symbol,std::string_view newName)45 void SymbolTable::renameSymbol(Symbol* symbol, std::string_view newName) {
46 if (symbol->is<FunctionDeclaration>()) {
47 // This is a function declaration, so we need to rename the entire overload set.
48 for (FunctionDeclaration* fn = &symbol->as<FunctionDeclaration>(); fn != nullptr;
49 fn = fn->mutableNextOverload()) {
50 fn->setName(newName);
51 }
52 } else {
53 // Other types of symbols don't allow multiple symbols with the same name.
54 symbol->setName(newName);
55 }
56
57 this->addWithoutOwnership(symbol);
58 }
59
takeOwnershipOfString(std::string str)60 const std::string* SymbolTable::takeOwnershipOfString(std::string str) {
61 fOwnedStrings.push_front(std::move(str));
62 // Because fOwnedStrings is a linked list, pointers to elements are stable.
63 return &fOwnedStrings.front();
64 }
65
addWithoutOwnership(Symbol * symbol)66 void SymbolTable::addWithoutOwnership(Symbol* symbol) {
67 auto key = MakeSymbolKey(symbol->name());
68
69 // If this is a function declaration, we need to keep the overload chain in sync.
70 if (symbol->is<FunctionDeclaration>()) {
71 // If we have a function with the same name...
72 Symbol* existingSymbol = this->lookup(key);
73 if (existingSymbol && existingSymbol->is<FunctionDeclaration>()) {
74 // ... add the existing function as the next overload in the chain.
75 FunctionDeclaration* existingDecl = &existingSymbol->as<FunctionDeclaration>();
76 symbol->as<FunctionDeclaration>().setNextOverload(existingDecl);
77 fSymbols[key] = symbol;
78 return;
79 }
80 }
81
82 if (fAtModuleBoundary && fParent && fParent->lookup(key)) {
83 // We are attempting to declare a symbol at global scope that already exists in a parent
84 // module. This is a duplicate symbol and should be rejected.
85 } else {
86 Symbol*& refInSymbolTable = fSymbols[key];
87
88 if (refInSymbolTable == nullptr) {
89 refInSymbolTable = symbol;
90 return;
91 }
92 }
93
94 ThreadContext::ReportError("symbol '" + std::string(symbol->name()) + "' was already defined",
95 symbol->fPosition);
96 }
97
injectWithoutOwnership(Symbol * symbol)98 void SymbolTable::injectWithoutOwnership(Symbol* symbol) {
99 auto key = MakeSymbolKey(symbol->name());
100 fSymbols[key] = symbol;
101 }
102
addArrayDimension(const Type * type,int arraySize)103 const Type* SymbolTable::addArrayDimension(const Type* type, int arraySize) {
104 if (arraySize == 0) {
105 return type;
106 }
107 // If this is a builtin type, we add it as high as possible in the symbol table tree (at the
108 // module boundary), to enable additional reuse of the array-type.
109 if (type->isInBuiltinTypes() && fParent && !fAtModuleBoundary) {
110 return fParent->addArrayDimension(type, arraySize);
111 }
112 // Reuse an existing array type with this name if one already exists in our symbol table.
113 std::string arrayName = type->getArrayName(arraySize);
114 if (const Symbol* existingType = this->find(arrayName)) {
115 return &existingType->as<Type>();
116 }
117 // Add a new array type to the symbol table.
118 const std::string* arrayNamePtr = this->takeOwnershipOfString(std::move(arrayName));
119 return this->add(Type::MakeArrayType(*arrayNamePtr, *type, arraySize));
120 }
121
122 } // namespace SkSL
123