return Fortran::common::EnumIndexToString( \
static_cast<int>(e), #__VA_ARGS__); \
}
+
+// Given a const reference to a value, return a copy of the value.
+
+template<typename A> A Clone(const A &x) { return x; }
}
#endif // FORTRAN_COMMON_IDIOMS_H_
#include "expression.h"
#include "type.h"
#include "../parser/characters.h"
+#include <algorithm>
namespace Fortran::evaluate {
template<typename RESULT, typename VALUE>
ConstantBase<RESULT, VALUE>::~ConstantBase() {}
+static void ShapeAsFortran(
+ std::ostream &o, const std::vector<std::int64_t> &shape) {
+ if (shape.size() > 1) {
+ o << ",shape=";
+ char ch{'['};
+ for (auto dim : shape) {
+ o << ch << dim;
+ ch = ',';
+ }
+ o << "])";
+ }
+}
+
template<typename RESULT, typename VALUE>
std::ostream &ConstantBase<RESULT, VALUE>::AsFortran(std::ostream &o) const {
if (Rank() > 1) {
if (Rank() > 0) {
o << ']';
}
- if (Rank() > 1) {
- o << ",shape=";
- char ch{'['};
- for (auto dim : shape_) {
- o << ch << dim;
- ch = ',';
- }
- o << "])";
- }
+ ShapeAsFortran(o, shape_);
return o;
}
-template<typename RESULT, typename VALUE>
-auto ConstantBase<RESULT, VALUE>::At(
- const std::vector<std::int64_t> &index) const -> Value {
- CHECK(index.size() == static_cast<std::size_t>(Rank()));
+static std::int64_t SubscriptsToOffset(const std::vector<std::int64_t> &index,
+ const std::vector<std::int64_t> &shape) {
+ CHECK(index.size() == shape.size());
std::int64_t stride{1}, offset{0};
int dim{0};
for (std::int64_t j : index) {
- std::int64_t bound{shape_[dim++]};
+ std::int64_t bound{shape[dim++]};
CHECK(j >= 1 && j <= bound);
offset += stride * (j - 1);
stride *= bound;
}
- return values_.at(offset);
+ return offset;
}
template<typename RESULT, typename VALUE>
-Constant<SubscriptInteger> ConstantBase<RESULT, VALUE>::SHAPE() const {
+auto ConstantBase<RESULT, VALUE>::At(
+ const std::vector<std::int64_t> &index) const -> ScalarValue {
+ return values_.at(SubscriptsToOffset(index, shape_));
+}
+
+static Constant<SubscriptInteger> ShapeAsConstant(
+ const std::vector<std::int64_t> &shape) {
using IntType = Scalar<SubscriptInteger>;
std::vector<IntType> result;
- for (std::int64_t dim : shape_) {
+ for (std::int64_t dim : shape) {
result.emplace_back(dim);
}
- return {std::move(result), std::vector<std::int64_t>{Rank()}};
+ return {std::move(result),
+ std::vector<std::int64_t>{static_cast<std::int64_t>(shape.size())}};
+}
+
+template<typename RESULT, typename VALUE>
+Constant<SubscriptInteger> ConstantBase<RESULT, VALUE>::SHAPE() const {
+ return ShapeAsConstant(shape_);
+}
+
+// Constant<Type<TypeCategory::Character, KIND> specializations
+
+template<int KIND>
+Constant<Type<TypeCategory::Character, KIND>>::Constant(const ScalarValue &str)
+ : values_{str}, length_{static_cast<std::int64_t>(values_.size())} {}
+
+template<int KIND>
+Constant<Type<TypeCategory::Character, KIND>>::Constant(ScalarValue &&str)
+ : values_{std::move(str)}, length_{
+ static_cast<std::int64_t>(values_.size())} {}
+
+template<int KIND>
+Constant<Type<TypeCategory::Character, KIND>>::Constant(std::int64_t len,
+ std::vector<ScalarValue> &&strings, std::vector<std::int64_t> &&dims)
+ : length_{len} {
+ values_.assign(strings.size() * length_,
+ static_cast<typename ScalarValue::value_type>(' '));
+ std::int64_t at{0};
+ for (const auto &str : strings) {
+ values_.replace(
+ at, std::min(length_, static_cast<std::int64_t>(str.size())), str);
+ at += length_;
+ }
+ CHECK(at == static_cast<std::int64_t>(values_.size()));
}
+template<int KIND> Constant<Type<TypeCategory::Character, KIND>>::~Constant() {}
+
+template<int KIND>
+auto Constant<Type<TypeCategory::Character, KIND>>::At(
+ const std::vector<std::int64_t> &index) const -> ScalarValue {
+ auto offset{SubscriptsToOffset(index, shape_)};
+ return values_.substr(offset, length_);
+}
+
+template<int KIND>
+Constant<SubscriptInteger>
+Constant<Type<TypeCategory::Character, KIND>>::SHAPE() const {
+ return ShapeAsConstant(shape_);
+}
+
+template<int KIND>
+std::ostream &Constant<Type<TypeCategory::Character, KIND>>::AsFortran(
+ std::ostream &o) const {
+ if (Rank() > 1) {
+ o << "reshape(";
+ }
+ if (Rank() > 0) {
+ o << '[' << GetType().AsFortran() << "::";
+ }
+ bool first{true};
+ auto total{static_cast<std::int64_t>(size())};
+ for (std::int64_t at{0}; at < total; at += length_) {
+ ScalarValue value{values_.substr(at, length_)};
+ if (first) {
+ first = false;
+ } else {
+ o << ',';
+ }
+ o << Result::kind << '_' << parser::QuoteCharacterLiteral(value);
+ }
+ if (Rank() > 0) {
+ o << ']';
+ }
+ ShapeAsFortran(o, shape_);
+ return o;
+}
+
+// Constant<SomeDerived> specialization
+
Constant<SomeDerived>::Constant(const StructureConstructor &x)
: Base{x.values()}, derivedTypeSpec_{&x.derivedTypeSpec()} {}
std::vector<StructureConstructor> &&x, std::vector<std::int64_t> &&s)
: Base{GetValues(std::move(x)), std::move(s)}, derivedTypeSpec_{&spec} {}
-FOR_EACH_INTRINSIC_KIND(template class ConstantBase)
+FOR_EACH_LENGTHLESS_INTRINSIC_KIND(template class ConstantBase)
template class ConstantBase<SomeDerived, StructureConstructorValues>;
FOR_EACH_INTRINSIC_KIND(template class Constant)
}
namespace Fortran::evaluate {
// Wraps a constant value in a class templated by its resolved type.
-// N.B. Generic constants are represented by generic expressions
-// (like Expr<SomeInteger> & Expr<SomeType>) wrapping the appropriate
-// instantiations of Constant.
+// This Constant<> template class should be instantiated only for
+// concrete intrinsic types and SomeDerived. There is no instance
+// Constant<Expr<SomeType>> since there is no way to constrain each
+// element of its array to hold the same type. To represent a generic
+// constants, use a generic expression like Expr<SomeInteger> &
+// Expr<SomeType>) to wrap the appropriate instantiation of Constant<>.
template<typename> class Constant;
-template<typename RESULT, typename VALUE = Scalar<RESULT>> class ConstantBase {
+// Constant<> is specialized for Character kinds and SomeDerived.
+// The non-Character intrinsic types, and SomeDerived, share enough
+// common behavior that they use this common base class.
+template<typename RESULT, typename SCALAR = Scalar<RESULT>> class ConstantBase {
+ static_assert(RESULT::category != TypeCategory::Character);
+
public:
using Result = RESULT;
- using Value = VALUE;
+ using ScalarValue = SCALAR;
template<typename A> ConstantBase(const A &x) : values_{x} {}
template<typename A>
ConstantBase(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
: values_{std::move(x)} {}
- ConstantBase(std::vector<Value> &&x, std::vector<std::int64_t> &&s)
- : values_(std::move(x)), shape_(std::move(s)) {}
+ ConstantBase(std::vector<ScalarValue> &&x, std::vector<std::int64_t> &&dims)
+ : values_(std::move(x)), shape_(std::move(dims)) {}
~ConstantBase();
int Rank() const { return static_cast<int>(shape_.size()); }
std::size_t size() const { return values_.size(); }
const std::vector<std::int64_t> &shape() const { return shape_; }
- Value operator*() const {
+ ScalarValue operator*() const {
CHECK(values_.size() == 1);
return values_.at(0);
}
// Apply 1-based subscripts
- Value At(const std::vector<std::int64_t> &) const;
+ ScalarValue At(const std::vector<std::int64_t> &) const;
Constant<SubscriptInteger> SHAPE() const;
std::ostream &AsFortran(std::ostream &) const;
protected:
- std::vector<Value> values_;
+ std::vector<ScalarValue> values_;
std::vector<std::int64_t> shape_;
private:
template<typename T> class Constant : public ConstantBase<T> {
public:
using Result = T;
- using ConstantBase<Result>::ConstantBase;
+ using ScalarValue = Scalar<Result>;
+ using ConstantBase<Result, ScalarValue>::ConstantBase;
CLASS_BOILERPLATE(Constant)
static constexpr DynamicType GetType() { return Result::GetType(); }
};
-template<int KIND>
-class Constant<Type<TypeCategory::Character, KIND>>
- : public ConstantBase<Type<TypeCategory::Character, KIND>> {
+template<int KIND> class Constant<Type<TypeCategory::Character, KIND>> {
public:
using Result = Type<TypeCategory::Character, KIND>;
- using ConstantBase<Result>::ConstantBase;
+ using ScalarValue = Scalar<Result>;
CLASS_BOILERPLATE(Constant)
- static constexpr DynamicType GetType() { return Result::GetType(); }
- std::int64_t LEN() const {
- if (this->values_.empty()) {
- return 0;
- } else {
- return static_cast<std::int64_t>(this->values_.front().size());
- }
+ explicit Constant(const ScalarValue &);
+ explicit Constant(ScalarValue &&);
+ Constant(
+ std::int64_t, std::vector<ScalarValue> &&, std::vector<std::int64_t> &&);
+ ~Constant();
+
+ int Rank() const { return static_cast<int>(shape_.size()); }
+ bool operator==(const Constant &that) const {
+ return shape_ == that.shape_ && values_ == that.values_;
+ }
+ bool empty() const { return values_.empty(); }
+ std::size_t size() const { return values_.size() / length_; }
+ const std::vector<std::int64_t> &shape() const { return shape_; }
+
+ std::int64_t LEN() const { return length_; }
+
+ ScalarValue operator*() const {
+ CHECK(static_cast<std::int64_t>(values_.size()) == length_);
+ return values_;
}
- // TODO pmk: make CHARACTER values contiguous (they're strings now)
+
+ // Apply 1-based subscripts
+ ScalarValue At(const std::vector<std::int64_t> &) const;
+
+ Constant<SubscriptInteger> SHAPE() const;
+ std::ostream &AsFortran(std::ostream &) const;
+ static constexpr DynamicType GetType() { return Result::GetType(); }
+
+private:
+ ScalarValue values_; // one contiguous string
+ std::int64_t length_;
+ std::vector<std::int64_t> shape_;
};
using StructureConstructorValues =
using Base = ConstantBase<Result, StructureConstructorValues>;
Constant(const StructureConstructor &);
Constant(StructureConstructor &&);
- Constant(const semantics::DerivedTypeSpec &, std::vector<Value> &&,
+ Constant(const semantics::DerivedTypeSpec &, std::vector<ScalarValue> &&,
std::vector<std::int64_t> &&);
Constant(const semantics::DerivedTypeSpec &,
std::vector<StructureConstructor> &&, std::vector<std::int64_t> &&);
const semantics::DerivedTypeSpec *derivedTypeSpec_;
};
-FOR_EACH_INTRINSIC_KIND(extern template class ConstantBase)
+FOR_EACH_LENGTHLESS_INTRINSIC_KIND(extern template class ConstantBase)
extern template class ConstantBase<SomeDerived, StructureConstructorValues>;
FOR_EACH_INTRINSIC_KIND(extern template class Constant)
}
Triplet FoldOperation(FoldingContext &context, Triplet &&triplet) {
return {Fold(context, triplet.lower()), Fold(context, triplet.upper()),
- Fold(context, Expr<SubscriptInteger>{triplet.stride()})};
+ Fold(context, common::Clone(triplet.stride()))};
}
Subscript FoldOperation(FoldingContext &context, Subscript &&subscript) {
if constexpr (std::is_same_v<T, SomeDerived>) {
return Expr<T>{Constant<T>{array.derivedTypeSpec(),
std::move(elements_), std::vector<std::int64_t>{n}}};
+ } else if constexpr (T::category == TypeCategory::Character) {
+ auto length{Fold(context_, common::Clone(array.LEN()))};
+ if (std::optional<std::int64_t> lengthValue{ToInt64(length)}) {
+ return Expr<T>{Constant<T>{*lengthValue, std::move(elements_),
+ std::vector<std::int64_t>{n}}};
+ }
} else {
return Expr<T>{
Constant<T>{std::move(elements_), std::vector<std::int64_t>{n}}};
}
- } else {
- return Expr<T>{std::move(array)};
}
+ return Expr<T>{std::move(array)};
}
private:
bool FoldArray(const CopyableIndirection<Expr<T>> &expr) {
- Expr<T> folded{Fold(context_, Expr<T>{*expr})};
+ Expr<T> folded{Fold(context_, common::Clone(*expr))};
if (auto *c{UnwrapExpr<Constant<T>>(folded)}) {
// Copy elements in Fortran array element order
std::vector<std::int64_t> shape{c->shape()};
template<typename TO> Expr<TO> ConvertToType(BOZLiteralConstant &&x) {
static_assert(IsSpecificIntrinsicType<TO>);
- using Value = typename Constant<TO>::Value;
+ using Value = typename Constant<TO>::ScalarValue;
if constexpr (TO::category == TypeCategory::Integer) {
return Expr<TO>{Constant<TO>{Value::ConvertUnsigned(std::move(x)).value}};
} else {
#define FOR_EACH_LOGICAL_KIND(PREFIX) \
EXPAND_FOR_EACH_LOGICAL_KIND(FOR_EACH_LOGICAL_KIND_HELP, PREFIX)
-#define FOR_EACH_INTRINSIC_KIND(PREFIX) \
+#define FOR_EACH_LENGTHLESS_INTRINSIC_KIND(PREFIX) \
FOR_EACH_INTEGER_KIND(PREFIX) \
FOR_EACH_REAL_KIND(PREFIX) \
FOR_EACH_COMPLEX_KIND(PREFIX) \
- FOR_EACH_CHARACTER_KIND(PREFIX) \
FOR_EACH_LOGICAL_KIND(PREFIX)
+#define FOR_EACH_INTRINSIC_KIND(PREFIX) \
+ FOR_EACH_LENGTHLESS_INTRINSIC_KIND(PREFIX) \
+ FOR_EACH_CHARACTER_KIND(PREFIX)
#define FOR_EACH_SPECIFIC_TYPE(PREFIX) \
FOR_EACH_INTRINSIC_KIND(PREFIX) \
PREFIX<SomeDerived>;
+
#define FOR_EACH_CATEGORY_TYPE(PREFIX) \
PREFIX<SomeInteger>; \
PREFIX<SomeReal>; \