/* * 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(); } 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()) { // This is a function declaration, so we need to rename the entire overload set. for (FunctionDeclaration* fn = &symbol->as(); 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()) { // If we have a function with the same name... Symbol* existingSymbol = this->lookup(key); if (existingSymbol && existingSymbol->is()) { // ... add the existing function as the next overload in the chain. FunctionDeclaration* existingDecl = &existingSymbol->as(); symbol->as().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(); } // 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