Files
carbon-lang/explorer/ast/element.h
T
2023-08-15 19:23:23 +00:00

193 lines
5.4 KiB
C++

// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef CARBON_EXPLORER_AST_ELEMENT_H_
#define CARBON_EXPLORER_AST_ELEMENT_H_
#include <optional>
#include <string>
#include <string_view>
#include "common/ostream.h"
#include "explorer/ast/ast_rtti.h"
#include "explorer/base/decompose.h"
#include "explorer/base/nonnull.h"
#include "llvm/ADT/PointerUnion.h"
namespace Carbon {
class Declaration;
class Value;
// A NamedValue represents a value with a name, such as a single struct field.
struct NamedValue : HashFromDecompose<NamedValue> {
NamedValue(std::string name, Nonnull<const Value*> value)
: name(std::move(name)), value(value) {}
template <typename F>
auto Decompose(F f) const {
return f(name, value);
}
// The field name.
std::string name;
// The field's value.
Nonnull<const Value*> value;
};
// A generic member of a type. This is can be a named, positional or other type
// of member.
//
// Arena's canonicalization support is enabled for Element and all derived
// types. As a result, all Elements must be immutable, and all their constructor
// arguments must be copyable, equality-comparable, and hashable. See
// Arena's documentation for details.
class Element {
protected:
explicit Element(ElementKind kind) : kind_(kind) {}
public:
using EnableCanonicalizedAllocation = void;
virtual ~Element() = default;
// Call `f` on this value, cast to its most-derived type. `R` specifies the
// expected return type of `f`.
template <typename R, typename F>
auto Visit(F f) const -> R;
// Prints the Member
virtual void Print(llvm::raw_ostream& out) const = 0;
// Return whether the member's name matches `name`.
virtual auto IsNamed(std::string_view name) const -> bool = 0;
// Returns the enumerator corresponding to the most-derived type of this
// object.
auto kind() const -> ElementKind { return kind_; }
// The declared type of the member, which might include type variables.
virtual auto type() const -> const Value& = 0;
private:
const ElementKind kind_;
};
// A named element of a type.
//
// This is either a declared member of a class, interface, or similar, or a
// member of a struct with no declaration.
class NamedElement : public Element {
public:
explicit NamedElement(Nonnull<const Declaration*> declaration);
explicit NamedElement(Nonnull<const NamedValue*> struct_member);
template <typename F>
auto Decompose(F f) const {
if (auto decl = declaration()) {
return f(*decl);
} else {
return f(*struct_member());
}
}
// Prints the element's name
void Print(llvm::raw_ostream& out) const override;
auto IsNamed(std::string_view name) const -> bool override;
static auto classof(const Element* member) -> bool {
return InheritsFromNamedElement(member->kind());
}
auto type() const -> const Value& override;
// The name of the member.
auto name() const -> std::string_view;
// A declaration of the member, if any exists.
auto declaration() const -> std::optional<Nonnull<const Declaration*>>;
// A name and type pair, if this is a struct member.
auto struct_member() const -> std::optional<Nonnull<const NamedValue*>>;
private:
const llvm::PointerUnion<Nonnull<const Declaration*>,
Nonnull<const NamedValue*>>
element_;
};
// A positional element of a type.
//
// This is a positional tuple element, or other index-based value.
class PositionalElement : public Element {
public:
explicit PositionalElement(int index, Nonnull<const Value*> type)
: Element(ElementKind::PositionalElement), index_(index), type_(type) {}
template <typename F>
auto Decompose(F f) const {
return f(index_, type_);
}
// Prints the element
void Print(llvm::raw_ostream& out) const override;
// Return whether the member's name matches `name`.
auto IsNamed(std::string_view name) const -> bool override;
static auto classof(const Element* member) -> bool {
return InheritsFromPositionalElement(member->kind());
}
auto index() const -> int { return index_; }
auto type() const -> const Value& override { return *type_; }
private:
const int index_;
const Nonnull<const Value*> type_;
};
// A base class object.
//
// This is the base class object of a class value.
class BaseElement : public Element {
public:
explicit BaseElement(Nonnull<const Value*> type)
: Element(ElementKind::BaseElement), type_(type) {}
template <typename F>
auto Decompose(F f) const {
return f(type_);
}
// Prints the Member
void Print(llvm::raw_ostream& out) const override;
// Return whether the member's name matches `name`.
auto IsNamed(std::string_view name) const -> bool override;
static auto classof(const Element* member) -> bool {
return InheritsFromBaseElement(member->kind());
}
auto type() const -> const Value& override { return *type_; }
private:
const Nonnull<const Value*> type_;
};
template <typename R, typename F>
auto Element::Visit(F f) const -> R {
switch (kind()) {
case ElementKind::NamedElement:
return f(static_cast<const NamedElement*>(this));
case ElementKind::PositionalElement:
return f(static_cast<const PositionalElement*>(this));
case ElementKind::BaseElement:
return f(static_cast<const BaseElement*>(this));
}
}
} // namespace Carbon
#endif // CARBON_EXPLORER_AST_ELEMENT_H_