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