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:
Adrien Leravat
2022-12-06 13:31:18 -08:00
committed by GitHub
parent 1d0bb85d0c
commit 0cb2c92c6c
6 changed files with 124 additions and 28 deletions
+43 -14
View File
@@ -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: {