blob: dc19006beb922ea4dcba54554dffa50d13792083 [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/SkSLContext.h"
#include "src/sksl/ir/SkSLType.h"
#include "src/sksl/ir/SkSLUnresolvedFunction.h"
namespace SkSL {
std::vector<const FunctionDeclaration*> SymbolTable::GetFunctions(const Symbol& s) {
switch (s.kind()) {
case Symbol::Kind::kFunctionDeclaration:
return { &s.as<FunctionDeclaration>() };
case Symbol::Kind::kUnresolvedFunction:
return s.as<UnresolvedFunction>().functions();
default:
return std::vector<const FunctionDeclaration*>();
}
}
const Symbol* SymbolTable::operator[](std::string_view name) {
return this->lookup(fBuiltin ? nullptr : this, MakeSymbolKey(name));
}
const Symbol* SymbolTable::lookup(SymbolTable* writableSymbolTable, const SymbolKey& key) {
// Symbol-table lookup can cause new UnresolvedFunction nodes to be created; however, we don't
// want these to end up in built-in root symbol tables (where they will outlive the Program
// associated with those UnresolvedFunction nodes). `writableSymbolTable` tracks the closest
// symbol table to the root which is not a built-in.
if (!fBuiltin) {
writableSymbolTable = this;
}
const Symbol** symbolPPtr = fSymbols.find(key);
if (!symbolPPtr) {
if (fParent) {
return fParent->lookup(writableSymbolTable, key);
}
return nullptr;
}
const Symbol* symbol = *symbolPPtr;
if (fParent) {
auto functions = GetFunctions(*symbol);
if (functions.size() > 0) {
bool modified = false;
const Symbol* previous = fParent->lookup(writableSymbolTable, key);
if (previous) {
auto previousFunctions = GetFunctions(*previous);
for (const FunctionDeclaration* prev : previousFunctions) {
bool found = false;
for (const FunctionDeclaration* current : functions) {
if (current->matches(*prev)) {
found = true;
break;
}
}
if (!found) {
functions.push_back(prev);
modified = true;
}
}
if (modified) {
SkASSERT(functions.size() > 1);
return writableSymbolTable
? writableSymbolTable->takeOwnershipOfSymbol(
std::make_unique<UnresolvedFunction>(functions))
: nullptr;
}
}
}
}
return 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(const Symbol* symbol) {
const std::string_view& name = symbol->name();
const Symbol*& refInSymbolTable = fSymbols[MakeSymbolKey(name)];
if (refInSymbolTable == nullptr) {
refInSymbolTable = symbol;
return;
}
if (!symbol->is<FunctionDeclaration>()) {
fContext.fErrors->error(symbol->fLine, "symbol '" + std::string(name) +
"' was already defined");
return;
}
std::vector<const FunctionDeclaration*> functions;
if (refInSymbolTable->is<FunctionDeclaration>()) {
functions = {&refInSymbolTable->as<FunctionDeclaration>(),
&symbol->as<FunctionDeclaration>()};
refInSymbolTable = this->takeOwnershipOfSymbol(
std::make_unique<UnresolvedFunction>(std::move(functions)));
} else if (refInSymbolTable->is<UnresolvedFunction>()) {
functions = refInSymbolTable->as<UnresolvedFunction>().functions();
functions.push_back(&symbol->as<FunctionDeclaration>());
refInSymbolTable = this->takeOwnershipOfSymbol(
std::make_unique<UnresolvedFunction>(std::move(functions)));
}
}
const Type* SymbolTable::addArrayDimension(const Type* type, int arraySize) {
if (arraySize != 0) {
const std::string* arrayName = this->takeOwnershipOfString(type->getArrayName(arraySize));
type = this->takeOwnershipOfSymbol(Type::MakeArrayType(*arrayName, *type, arraySize));
}
return type;
}
} // namespace SkSL