blob: e8771c956018e81775d5d50dfc079af7633586a2 [file] [log] [blame]
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/sksl/ir/SkSLSymbolTable.h"
#include "src/sksl/SkSLThreadContext.h"
#include "src/sksl/ir/SkSLFunctionDeclaration.h"
#include "src/sksl/ir/SkSLType.h"
namespace SkSL {
bool SymbolTable::isType(std::string_view name) const {
const Symbol* symbol = this->find(name);
return symbol && symbol->is<Type>();
}
bool SymbolTable::isBuiltinType(std::string_view name) const {
if (!this->isBuiltin()) {
return fParent && fParent->isBuiltinType(name);
}
return this->isType(name);
}
const Symbol* SymbolTable::findBuiltinSymbol(std::string_view name) const {
if (!this->isBuiltin()) {
return fParent ? fParent->findBuiltinSymbol(name) : nullptr;
}
return this->find(name);
}
Symbol* SymbolTable::lookup(const SymbolKey& key) const {
Symbol** symbolPPtr = fSymbols.find(key);
if (symbolPPtr) {
return *symbolPPtr;
}
// The symbol wasn't found; recurse into the parent symbol table.
return fParent ? fParent->lookup(key) : nullptr;
}
void SymbolTable::renameSymbol(Symbol* symbol, std::string_view newName) {
if (symbol->is<FunctionDeclaration>()) {
// This is a function declaration, so we need to rename the entire overload set.
for (FunctionDeclaration* fn = &symbol->as<FunctionDeclaration>(); fn != nullptr;
fn = fn->mutableNextOverload()) {
fn->setName(newName);
}
} else {
// Other types of symbols don't allow multiple symbols with the same name.
symbol->setName(newName);
}
this->addWithoutOwnership(symbol);
}
const std::string* SymbolTable::takeOwnershipOfString(std::string str) {
fOwnedStrings.push_front(std::move(str));
// Because fOwnedStrings is a linked list, pointers to elements are stable.
return &fOwnedStrings.front();
}
void SymbolTable::addWithoutOwnership(Symbol* symbol) {
auto key = MakeSymbolKey(symbol->name());
// If this is a function declaration, we need to keep the overload chain in sync.
if (symbol->is<FunctionDeclaration>()) {
// If we have a function with the same name...
Symbol* existingSymbol = this->lookup(key);
if (existingSymbol && existingSymbol->is<FunctionDeclaration>()) {
// ... add the existing function as the next overload in the chain.
FunctionDeclaration* existingDecl = &existingSymbol->as<FunctionDeclaration>();
symbol->as<FunctionDeclaration>().setNextOverload(existingDecl);
fSymbols[key] = symbol;
return;
}
}
if (fAtModuleBoundary && fParent && fParent->lookup(key)) {
// We are attempting to declare a symbol at global scope that already exists in a parent
// module. This is a duplicate symbol and should be rejected.
} else {
Symbol*& refInSymbolTable = fSymbols[key];
if (refInSymbolTable == nullptr) {
refInSymbolTable = symbol;
return;
}
}
ThreadContext::ReportError("symbol '" + std::string(symbol->name()) + "' was already defined",
symbol->fPosition);
}
void SymbolTable::injectWithoutOwnership(Symbol* symbol) {
auto key = MakeSymbolKey(symbol->name());
fSymbols[key] = symbol;
}
const Type* SymbolTable::addArrayDimension(const Type* type, int arraySize) {
if (arraySize == 0) {
return type;
}
// If this is a builtin type, we add it as high as possible in the symbol table tree (at the
// module boundary), to enable additional reuse of the array-type.
if (type->isInBuiltinTypes() && fParent && !fAtModuleBoundary) {
return fParent->addArrayDimension(type, arraySize);
}
// Reuse an existing array type with this name if one already exists in our symbol table.
std::string arrayName = type->getArrayName(arraySize);
if (const Symbol* existingType = this->find(arrayName)) {
return &existingType->as<Type>();
}
// Add a new array type to the symbol table.
const std::string* arrayNamePtr = this->takeOwnershipOfString(std::move(arrayName));
return this->add(Type::MakeArrayType(*arrayNamePtr, *type, arraySize));
}
} // namespace SkSL