mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-06 06:44:46 +01:00
Explorer: support index-based fields for FieldPath and Members (#2417)
Features * Support addressing positional members (i.e. tuple fields) using an index. * Addresses a couple of `TODO`s relative to positional members Changes: * Add a new `IndexedValue` mirroring `NamedValue` * Adds `FieldPath::index() -> int` * Adds a `Member` variant for `IndexedValue`
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
#include "explorer/common/arena.h"
|
||||
#include "explorer/common/error_builders.h"
|
||||
#include "explorer/interpreter/action.h"
|
||||
#include "explorer/interpreter/field_path.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
@@ -48,12 +49,32 @@ static auto FindClassField(Nonnull<const NominalClassValue*> object,
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
static auto GetMember(Nonnull<Arena*> arena, Nonnull<const Value*> v,
|
||||
const FieldPath::Component& field,
|
||||
SourceLocation source_loc, Nonnull<const Value*> me_value)
|
||||
static auto GetPositionalMember(Nonnull<const Value*> v,
|
||||
const FieldPath::Component& field,
|
||||
SourceLocation source_loc)
|
||||
-> ErrorOr<Nonnull<const Value*>> {
|
||||
std::string_view f = field.name();
|
||||
switch (v->kind()) {
|
||||
case Value::Kind::TupleValue: {
|
||||
const auto& tuple = cast<TupleValue>(*v);
|
||||
const auto index = field.member().index();
|
||||
if (index < 0 || index >= static_cast<int>(tuple.elements().size())) {
|
||||
return ProgramError(source_loc)
|
||||
<< "index " << index << " out of range for " << *v;
|
||||
}
|
||||
return tuple.elements()[index];
|
||||
}
|
||||
default:
|
||||
return ProgramError(source_loc)
|
||||
<< "Invalid positional argument for value " << *v;
|
||||
}
|
||||
}
|
||||
|
||||
static auto GetNamedMember(Nonnull<Arena*> arena, Nonnull<const Value*> v,
|
||||
const FieldPath::Component& field,
|
||||
SourceLocation source_loc,
|
||||
Nonnull<const Value*> me_value)
|
||||
-> ErrorOr<Nonnull<const Value*>> {
|
||||
const auto f = field.member().name();
|
||||
if (field.witness().has_value()) {
|
||||
const auto* witness = cast<Witness>(*field.witness());
|
||||
|
||||
@@ -152,6 +173,15 @@ static auto GetMember(Nonnull<Arena*> arena, Nonnull<const Value*> v,
|
||||
}
|
||||
}
|
||||
|
||||
static auto GetMember(Nonnull<Arena*> arena, Nonnull<const Value*> v,
|
||||
const FieldPath::Component& field,
|
||||
SourceLocation source_loc, Nonnull<const Value*> me_value)
|
||||
-> ErrorOr<Nonnull<const Value*>> {
|
||||
return field.member().HasPosition()
|
||||
? GetPositionalMember(v, field, source_loc)
|
||||
: GetNamedMember(arena, v, field, source_loc, me_value);
|
||||
}
|
||||
|
||||
auto Value::GetMember(Nonnull<Arena*> arena, const FieldPath& path,
|
||||
SourceLocation source_loc,
|
||||
Nonnull<const Value*> me_value) const
|
||||
@@ -178,11 +208,11 @@ static auto SetFieldImpl(
|
||||
std::vector<NamedValue> elements = cast<StructValue>(*value).elements();
|
||||
auto it =
|
||||
llvm::find_if(elements, [path_begin](const NamedValue& element) {
|
||||
return element.name == (*path_begin).name();
|
||||
return (*path_begin).IsNamed(element.name);
|
||||
});
|
||||
if (it == elements.end()) {
|
||||
return ProgramError(source_loc)
|
||||
<< "field " << (*path_begin).name() << " not in " << *value;
|
||||
<< "field " << *path_begin << " not in " << *value;
|
||||
}
|
||||
CARBON_ASSIGN_OR_RETURN(
|
||||
it->value, SetFieldImpl(arena, it->value, path_begin + 1, path_end,
|
||||
@@ -207,17 +237,16 @@ static auto SetFieldImpl(
|
||||
}
|
||||
// Failed to match, show full object content
|
||||
return ProgramError(source_loc)
|
||||
<< "field " << (*path_begin).name() << " not in " << *value;
|
||||
<< "field " << *path_begin << " not in " << *value;
|
||||
}
|
||||
case Value::Kind::TupleType:
|
||||
case Value::Kind::TupleValue: {
|
||||
std::vector<Nonnull<const Value*>> elements =
|
||||
cast<TupleValueBase>(*value).elements();
|
||||
// TODO(geoffromer): update FieldPath to hold integers as well as strings.
|
||||
int index = std::stoi(std::string((*path_begin).name()));
|
||||
if (index < 0 || static_cast<size_t>(index) >= elements.size()) {
|
||||
return ProgramError(source_loc) << "index " << (*path_begin).name()
|
||||
<< " out of range in " << *value;
|
||||
const auto index = (*path_begin).member().index();
|
||||
if (index < 0 || index >= static_cast<int>(elements.size())) {
|
||||
return ProgramError(source_loc)
|
||||
<< "index " << index << " out of range in " << *value;
|
||||
}
|
||||
CARBON_ASSIGN_OR_RETURN(
|
||||
elements[index], SetFieldImpl(arena, elements[index], path_begin + 1,
|
||||
@@ -541,7 +570,7 @@ void Value::Print(llvm::raw_ostream& out) const {
|
||||
if (member_name.interface().has_value()) {
|
||||
out << *member_name.interface().value();
|
||||
}
|
||||
out << "." << member_name.name();
|
||||
out << "." << member_name;
|
||||
if (member_name.base_type().has_value() &&
|
||||
member_name.interface().has_value()) {
|
||||
out << ")";
|
||||
@@ -587,7 +616,7 @@ void Value::Print(llvm::raw_ostream& out) const {
|
||||
<< cast<TypeOfParameterizedEntityName>(*this).name();
|
||||
break;
|
||||
case Value::Kind::TypeOfMemberName: {
|
||||
out << "member name " << cast<TypeOfMemberName>(*this).member().name();
|
||||
out << "member name " << cast<TypeOfMemberName>(*this).member();
|
||||
break;
|
||||
}
|
||||
case Value::Kind::StaticArrayType: {
|
||||
|
||||
Reference in New Issue
Block a user