blob: 6c2998b37bb26d1e0533bf5759525aac0a10b50e [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.
#pragma once
#include <string>
#include <utility>
#include <vector>
#include "garnet/bin/zxdb/common/err.h"
#include "garnet/bin/zxdb/expr/expr_token.h"
namespace zxdb {
class Err;
// An identifier is a sequence of names. Currently this handles C++ and Rust,
// but could be enhanced in the future for other languages.
//
// This is used for variable names and function names. If you type a class
// name or a typedef, the parser will also parse it as an identifier. What
// the identifier actually means will depend on the context in which it's used.
//
// One component can consist of a name and a template part (note currently the
// parser doesn't support the template part, but this class does in expectation
// that parsing support will be added in the future).
//
// Component := [ "::" ] <Name> [ "<" <Template-Goop> ">" ]
//
// An identifier consists of one or more components. In C++, if the first
// component has a valid separator token, it's fully qualified ("::foo"), but
// it could be omitted for non-fully-qualified names. Subsequent components
// will always have separators.
//
// The identifier contains the token information for the original so that
// it can be used for syntax highlighting.
class Identifier {
public:
class Component {
public:
Component();
// Constructor for names without templates.
Component(ExprToken separator, ExprToken name)
: separator_(std::move(separator)), name_(std::move(name)) {}
// Constructor for names without templates for use by tests that hard-code
// values.
Component(bool has_separator, const std::string& name)
: name_(ExprToken::kName, name, 0) {
if (has_separator)
separator_ = ExprToken(ExprToken::kColonColon, "::", 0);
}
// Constructor for names with templates. The contents will be a
// vector of somewhat-normalized type string in between the <>.
Component(ExprToken separator, ExprToken name, ExprToken template_begin,
std::vector<std::string> template_contents,
ExprToken template_end)
: separator_(std::move(separator)),
name_(std::move(name)),
template_begin_(std::move(template_begin)),
template_contents_(std::move(template_contents)),
template_end_(std::move(template_end)) {}
bool has_separator() const {
return separator_.type() != ExprToken::kInvalid;
}
bool has_template() const {
return template_begin_.type() != ExprToken::kInvalid;
}
const ExprToken& separator() const { return separator_; }
void set_separator(ExprToken t) { separator_ = std::move(t); }
const ExprToken& name() const { return name_; }
// This will be kInvalid if there is no template on this component.
// The begin and end are the <> tokens, and the contents is the normalized
// string in between. Note that the contents may not exactly match the
// input string (some whitespace may be removed).
const ExprToken& template_begin() const { return template_begin_; }
const std::vector<std::string>& template_contents() const {
return template_contents_;
}
const ExprToken& template_end() const { return template_end_; }
private:
ExprToken separator_;
ExprToken name_;
ExprToken template_begin_;
std::vector<std::string> template_contents_;
ExprToken template_end_;
};
Identifier() = default;
// Makes a simple identifier with a standalone name.
explicit Identifier(ExprToken name);
// Makes an identifier from a single component.
explicit Identifier(Component comp);
// Attempts to parse the given string as an identifier. Returns either a
// set Err or the resulting Identifier when the Err is not set.
static std::pair<Err, Identifier> FromString(const std::string& input);
// Makes an identifier over a range of components.
template <class InputIterator>
Identifier(InputIterator first, InputIterator last)
: components_(first, last) {}
std::vector<Component>& components() { return components_; }
const std::vector<Component>& components() const { return components_; }
void AppendComponent(Component c);
void AppendComponent(ExprToken separator, ExprToken name);
void AppendComponent(ExprToken separator, ExprToken name,
ExprToken template_begin,
std::vector<std::string> template_contents,
ExprToken template_end);
// Returns a new identifier that's the scope of this one. The scope is
// everything but the last identifier.
//
// If there is only one component, the resulting identifier will either be
// empty (if the component has no separator, e.g. "Foo" becomes ""), or
// contain only a separator (if the component has a separator, e.g. "::Foo"
// becomes "::" and "::" becomes itself).
Identifier GetScope() const;
// Returns true if this identifier begins with "::" and as such can only be
// resolved in the global namespace.
bool InGlobalNamespace() const;
// Returns the full name with all components concatenated together.
std::string GetFullName() const;
// Returns a form for debugging where the parsing is more visible.
std::string GetDebugName() const;
// In many contexts (like function parameters and local variables) the name
// can't have any :: or template parameters and can have only one component.
// If this identifier satisfies this requirement, a pointer to the single
// string is returned. If there is zero or more than one component or any
// template specs, returns null.
//
// The returned pointer will be invalidated if the Identifier is mutated.
const std::string* GetSingleComponentName() const;
private:
// Backend for the name getters.
std::string GetName(bool include_debug) const;
std::vector<Component> components_;
};
} // namespace zxdb