blob: 437d03a654264df60db7542dac813f5e2106e88a [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_IDENTIFIER_BASE_H_
#define SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_IDENTIFIER_BASE_H_
#include <string>
#include <string_view>
#include <utility>
#include <vector>
namespace zxdb {
// Identifiers can be explicitly global qualified ("::foo" in C++) or without
// global qualification ("foo" or "Foo::Bar" in C++). Note that relative
// can still include class or namespace qualifications.
enum class IdentifierQualification { kGlobal, kRelative };
enum class SpecialIdentifier {
kNone = 0, // Not special.
// Used for "$(foo bar)" where there is no special name and the "$" is used to escape some
// contents. This is not stored in an Identifier since the "contents" in this case is just an
// identifier literal that can be stored normally. It is used by the parser to identify this case
// of special identifier.
kEscaped,
kAnon, // Anonymous namespace.
kMain, // Main function (uses DWARF-indicated "entrypoint" regardless of name).
kElf, // Symbol defined in the ELF format (simpler than the full DWARF symbols).
kPlt, // PLT identifier (a subset of ELF symbols).
kRegister,
kLast, // Not a type, marker for array size.
};
// The input and output strings should includes the "$" but no parens, so kMain -> "$main" and kPlt
// -> "$plt". SpecialIdentifierToString returns the empty string for kNone and "$" for kEscaped.
// StringToSpecialIdentifier return kNone if there's no match.
std::string_view SpecialIdentifierToString(SpecialIdentifier i);
SpecialIdentifier StringToSpecialIdentifier(std::string_view name);
// Returns true if the given special identifier has data associated with it, e.g. "$plt(foo)".
// Returns false if there are no parens required. Returns true for kNone since in that case it's
// only the data.
bool SpecialIdentifierHasData(SpecialIdentifier i);
extern const char kAnonIdentifierComponentName[];
// Base class for identifiers that have different types of components. Different languages might
// want to represent different aspects of an identifier. This class encapsulates the core
// hierarchical part of an identifier.
//
// Code in the symbols directory must use "Identifier" which contains opaque strings as components.
// The "expr" library adds a "ParsedIdentifier" which has more C++-aware parsing of template types.
// See those classes for more.
//
// The ComponentType must be copyable and moveable and implement:
// - Construction from simple name:
// ComponentType(const std::string&)
// - Conversion to a string:
// std::string GetName(bool include_debug)
// - Comparison:
// operator==
// operator!=
// operator<
//
// TODO(brettw) there is currently an annoying amount of duplicating between Identifier[Base] and
// ParsedIdentifier, and also a fair bit of converting back-and-forth. We should consider moving
// ParsedIdentifier to symbols and using that everywhere (renamed to Identifier), and having a
// "parse" callback function for the higher-level "expr" layer to inject its full parser into the
// lower-layer symbol directory.
template <class ComponentType>
class IdentifierBase {
public:
using Qualification = IdentifierQualification;
explicit IdentifierBase(Qualification qual = Qualification::kRelative) : qualification_(qual) {}
// Makes an identifier from a single component. Without the qualification means relative.
explicit IdentifierBase(ComponentType comp)
: qualification_(Qualification::kRelative), components_({std::move(comp)}) {}
IdentifierBase(Qualification qual, ComponentType comp)
: qualification_(qual), components_({std::move(comp)}) {}
// Construction of a relative identifier from a simple single-name string. This string is passed
// to the underlying component's constructor.
IdentifierBase(const std::string& name)
: qualification_(Qualification::kRelative), components_({ComponentType(name)}) {}
// Makes an identifier over a range of components.
template <class InputIterator>
IdentifierBase(Qualification qual, InputIterator first, InputIterator last)
: qualification_(qual), components_(first, last) {}
// Comparisons. "==" compares everything for exact equality, "EqualsIgnoringQualification"
// checks that everything is equal except the global/relative qualification flag.
bool EqualsIgnoringQualification(const IdentifierBase<ComponentType>& other) const {
return components_ == other.components_;
}
bool operator==(const IdentifierBase<ComponentType>& other) const {
return qualification_ == other.qualification_ && EqualsIgnoringQualification(other);
}
bool operator!=(const IdentifierBase<ComponentType>& other) const { return !operator==(other); }
// For map/set lookups.
bool operator<(const IdentifierBase<ComponentType>& other) const {
if (qualification_ == other.qualification_)
return components_ < other.components_;
return qualification_ == IdentifierQualification::kGlobal;
}
std::vector<ComponentType>& components() { return components_; }
const std::vector<ComponentType>& components() const { return components_; }
bool empty() const { return components_.empty() && qualification_ == Qualification::kRelative; }
// Appends a single component.
void AppendComponent(ComponentType c) { components_.push_back(std::move(c)); }
// Appends the components from the other identifier to this one.
void Append(IdentifierBase<ComponentType> other) {
for (auto& cur : other.components())
components_.push_back(std::move(cur));
}
Qualification qualification() const { return qualification_; }
void set_qualification(Qualification q) { qualification_ = q; }
// Returns a new identifier that's the scope of this one. The scope is everything but the last
// component. The qualification remains unchanged.
//
// If there is only one component, the resulting identifier will be empty (still leaving the
// qualification unchanged). Examples:
// "foo::bar<int>::baz" -> "foo::bar<int>"
// "::foo::bar::baz" -> "::foo::bar"
// "foo" -> ""
// "" -> ""
// "::foo" -> "::"
// "::" -> "::"
IdentifierBase<ComponentType> GetScope() const {
if (components_.size() <= 1)
return IdentifierBase<ComponentType>(qualification_);
return IdentifierBase<ComponentType>(qualification_, components_.begin(),
components_.end() - 1);
}
// Returns the full name with all components concatenated together, including or omitting the
// global qualifier (leading "::"), if any.
std::string GetFullName() const { return GetName(true, false); }
std::string GetFullNameNoQual() const { return GetName(false, false); }
// Returns a form for debugging where the parsing is more visible.
std::string GetDebugName() const { return GetName(true, true); }
// Returns the separator string for components. This is currently always "::" but is exposed here
// as a getter to avoid hardcoding it everywhere and to allow us to do language-specific
// separators in the future.
const char* GetSeparator() const { return "::"; }
private:
// Backend for the name getters.
//
// A leading "::" will be included for globally qualified identifiers only when
// include_global_qual is set.
std::string GetName(bool include_global_qual, bool include_debug) const {
std::string result;
if (include_global_qual && qualification_ == Qualification::kGlobal)
result += GetSeparator();
bool first = true;
for (const auto& c : components_) {
if (first) {
first = false;
} else {
if (include_debug)
result += "; ";
result += GetSeparator();
}
std::string component_name = c.GetName(include_debug);
if (component_name.empty())
result += kAnonIdentifierComponentName;
else
result += component_name;
}
return result;
}
Qualification qualification_ = Qualification::kRelative;
std::vector<ComponentType> components_;
};
} // namespace zxdb
#endif // SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_IDENTIFIER_BASE_H_