bool SymbolTable::wouldShadowSymbolsFrom(const SymbolTable* other) const { // We are checking two hash maps for overlap; we always iterate over the smaller one to minimize // the total number of checks. const SymbolTable* self = this; if (self->count() > other->count()) {
std::swap(self, other);
}
bool foundShadow = false;
self->fSymbols.foreach([&](const SymbolKey& key, const Symbol* symbol) { if (foundShadow) { // We've already found a shadowed symbol; stop searching. return;
} if (other->fSymbols.find(key) != nullptr) {
foundShadow = true;
}
});
// The symbol wasn't found; recurse into the parent symbol table. return fParent ? fParent->lookup(key) : nullptr;
}
void SymbolTable::renameSymbol(const Context& context, 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(context, symbol);
}
std::unique_ptr<Symbol> SymbolTable::removeSymbol(const Symbol* symbol) { // Remove the symbol from our symbol lookup table. if (fSymbols.removeIfExists(MakeSymbolKey(symbol->name()))) { // Transfer ownership of the symbol if we own it. (This will leave a nullptr behind in the // `fOwnedSymbols` list, which should be harmless.) for (std::unique_ptr<Symbol>& owned : fOwnedSymbols) { if (symbol == owned.get()) { return std::move(owned);
}
}
}
// We don't own the symbol after all. return nullptr;
}
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::addWithoutOwnershipOrDie(Symbol* symbol) { if (!this->addWithoutOwnership(symbol)) {
SK_ABORT("symbol '%.*s' was already defined",
(int)symbol->name().size(), symbol->name().data());
}
}
bool SymbolTable::addWithoutOwnership(Symbol* symbol) { if (symbol->name().empty()) { // We have legitimate use cases of nameless symbols, such as anonymous function parameters. // If we find one here, we don't need to add its name to the symbol table. returntrue;
} 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; returntrue;
}
}
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. returnfalse;
}
std::swap(symbol, fSymbols[key]); return symbol == nullptr;
}
const Type* SymbolTable::addArrayDimension(const Context& context, const Type* type, int arraySize) { if (arraySize == 0) { return type;
} // If we are making an array of 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 (fParent && !fAtModuleBoundary && !context.fConfig->isBuiltinCode() && type->isBuiltin()) { return fParent->addArrayDimension(context, 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* existingSymbol = this->find(arrayName)) { // We would expect an existing symbol named `Type[123]` to match our `Type[123]`. However, // we might be compiling invalid code that contains duplicate symbols, and so we need to // verify that these two types actually match before reusing the existing type. const Type* existingType = &existingSymbol->as<Type>(); if (existingType->isArray() && type->matches(existingType->componentType())) { return existingType;
}
} // Add a new array type to the symbol table. const std::string* arrayNamePtr = this->takeOwnershipOfString(std::move(arrayName)); return this->add(context, Type::MakeArrayType(context, *arrayNamePtr, *type, arraySize));
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.