blob: 837e8d076b3bfb18b8eb308cceb60ab8da5d2b82 [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/ir/SkSLSymbolAlias.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[](StringFragment 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;
}
}
}
}
while (symbol && symbol->is<SymbolAlias>()) {
symbol = symbol->as<SymbolAlias>().origSymbol();
}
return symbol;
}
const String* SymbolTable::takeOwnershipOfString(std::unique_ptr<String> n) {
String* result = n.get();
fOwnedStrings.push_back(std::move(n));
return result;
}
void SymbolTable::addAlias(StringFragment name, const Symbol* symbol) {
this->add(std::make_unique<SymbolAlias>(symbol->fOffset, name, symbol));
}
void SymbolTable::addWithoutOwnership(const Symbol* symbol) {
const StringFragment& name = symbol->name();
const Symbol*& refInSymbolTable = fSymbols[MakeSymbolKey(name)];
if (refInSymbolTable == nullptr) {
refInSymbolTable = symbol;
return;
}
if (!symbol->is<FunctionDeclaration>()) {
fErrorReporter.error(symbol->fOffset, "symbol '" + 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) {
String baseName = type->name();
String arrayName = (arraySize != Type::kUnsizedArray)
? String::printf("%s[%d]", baseName.c_str(), arraySize)
: String::printf("%s[]", baseName.c_str());
type = this->takeOwnershipOfSymbol(Type::MakeArrayType(std::move(arrayName),
*type, arraySize));
}
return type;
}
} // namespace SkSL