[flang] Be more clear that constants in expressions are scalars now.

Original-commit: flang-compiler/f18@3181b8d961
Reviewed-on: https://github.com/flang-compiler/f18/pull/144
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2018-07-19 13:30:17 -07:00
parent 9a503392b4
commit e4f12b087c
4 changed files with 152 additions and 162 deletions

View File

@ -128,5 +128,14 @@ template<typename A> struct ListItemCount {
static_cast<int>(e), #__VA_ARGS__); \
}
// If a variant holds a value of a particular type, return a copy in a
// std::optional<>.
template<typename A, typename VARIANT>
std::optional<A> GetIf(const VARIANT &u) {
if (const A *x{std::get_if<A>(&u)}) {
return {*x};
}
return {};
}
} // namespace Fortran::common
#endif // FORTRAN_COMMON_IDIOMS_H_

View File

@ -24,6 +24,7 @@ using namespace Fortran::parser::literals;
namespace Fortran::evaluate {
// Dumping
template<typename... A>
std::ostream &DumpExprWithType(std::ostream &o, const std::variant<A...> &u) {
std::visit(
@ -69,7 +70,7 @@ std::ostream &Binary<A, B, CONST>::Dump(
template<int KIND>
std::ostream &IntegerExpr<KIND>::Dump(std::ostream &o) const {
std::visit(
common::visitors{[&](const Constant &n) { o << n.SignedDecimal(); },
common::visitors{[&](const Scalar &n) { o << n.SignedDecimal(); },
[&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
[&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
[&](const Parentheses &p) { p.Dump(o, "("); },
@ -90,7 +91,7 @@ std::ostream &IntegerExpr<KIND>::Dump(std::ostream &o) const {
template<int KIND> std::ostream &RealExpr<KIND>::Dump(std::ostream &o) const {
std::visit(
common::visitors{[&](const Constant &n) { o << n.DumpHexadecimal(); },
common::visitors{[&](const Scalar &n) { o << n.DumpHexadecimal(); },
[&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
[&](const CopyableIndirection<ComplexPart> &d) { d->Dump(o); },
[&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
@ -116,7 +117,7 @@ template<int KIND> std::ostream &RealExpr<KIND>::Dump(std::ostream &o) const {
template<int KIND>
std::ostream &ComplexExpr<KIND>::Dump(std::ostream &o) const {
std::visit(
common::visitors{[&](const Constant &n) { o << n.DumpHexadecimal(); },
common::visitors{[&](const Scalar &n) { o << n.DumpHexadecimal(); },
[&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
[&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
[&](const Parentheses &p) { p.Dump(o, "("); },
@ -134,7 +135,7 @@ std::ostream &ComplexExpr<KIND>::Dump(std::ostream &o) const {
template<int KIND>
std::ostream &CharacterExpr<KIND>::Dump(std::ostream &o) const {
std::visit(common::visitors{[&](const Constant &s) {
std::visit(common::visitors{[&](const Scalar &s) {
o << parser::QuoteCharacterLiteral(s);
},
[&](const Concat &concat) { concat.Dump(o, "//"); },
@ -168,10 +169,11 @@ std::ostream &LogicalExpr::Dump(std::ostream &o) const {
return o;
}
// LEN()
template<int KIND> SubscriptIntegerExpr CharacterExpr<KIND>::LEN() const {
return std::visit(
common::visitors{
[](const Constant &c) { return SubscriptIntegerExpr{c.size()}; },
[](const Scalar &c) { return SubscriptIntegerExpr{c.size()}; },
[](const Concat &c) { return c.left().LEN() + c.right().LEN(); },
[](const Max &c) {
return SubscriptIntegerExpr{
@ -189,35 +191,37 @@ template<int KIND> SubscriptIntegerExpr CharacterExpr<KIND>::LEN() const {
u_);
}
template<typename A, typename CONST>
std::optional<CONST> Unary<A, CONST>::Fold(FoldingContext &context) {
// Rank
template<typename A, typename B, typename SCALAR>
int Binary<A, B, SCALAR>::Rank() const {
int lrank{left_.Rank()};
if (lrank > 0) {
return lrank;
}
return right_.Rank();
}
// Folding
template<typename A, typename SCALAR>
std::optional<SCALAR> Unary<A, SCALAR>::Fold(FoldingContext &context) {
operand_->Fold(context);
return {};
}
template<typename A, typename B, typename CONST>
std::optional<CONST> Binary<A, B, CONST>::Fold(FoldingContext &context) {
template<typename A, typename B, typename SCALAR>
std::optional<SCALAR> Binary<A, B, SCALAR>::Fold(FoldingContext &context) {
left_->Fold(context);
right_->Fold(context);
return {};
}
template<int KIND>
std::optional<typename IntegerExpr<KIND>::Constant>
IntegerExpr<KIND>::ConstantValue() const {
if (auto c{std::get_if<Constant>(&u_)}) {
return {*c};
}
return {};
}
template<int KIND>
std::optional<typename IntegerExpr<KIND>::Constant>
std::optional<typename IntegerExpr<KIND>::Scalar>
IntegerExpr<KIND>::ConvertInteger::Fold(FoldingContext &context) {
return std::visit(
[&](auto &x) -> std::optional<typename IntegerExpr<KIND>::Constant> {
[&](auto &x) -> std::optional<typename IntegerExpr<KIND>::Scalar> {
if (auto c{x.Fold(context)}) {
auto converted{Constant::ConvertSigned(*c)};
auto converted{Scalar::ConvertSigned(*c)};
if (converted.overflow && context.messages != nullptr) {
context.messages->Say(
context.at, "integer conversion overflowed"_en_US);
@ -226,14 +230,14 @@ IntegerExpr<KIND>::ConvertInteger::Fold(FoldingContext &context) {
}
// g++ 8.1.0 choked on the legal "return {};" that should be here,
// saying that it may be used uninitialized.
std::optional<typename IntegerExpr<KIND>::Constant> result;
std::optional<typename IntegerExpr<KIND>::Scalar> result;
return std::move(result);
},
this->operand().u);
}
template<int KIND>
std::optional<typename IntegerExpr<KIND>::Constant>
std::optional<typename IntegerExpr<KIND>::Scalar>
IntegerExpr<KIND>::Negate::Fold(FoldingContext &context) {
if (auto c{this->operand().Fold(context)}) {
auto negated{c->Negate()};
@ -246,7 +250,7 @@ IntegerExpr<KIND>::Negate::Fold(FoldingContext &context) {
}
template<int KIND>
std::optional<typename IntegerExpr<KIND>::Constant>
std::optional<typename IntegerExpr<KIND>::Scalar>
IntegerExpr<KIND>::Add::Fold(FoldingContext &context) {
auto lc{this->left().Fold(context)};
auto rc{this->right().Fold(context)};
@ -261,7 +265,7 @@ IntegerExpr<KIND>::Add::Fold(FoldingContext &context) {
}
template<int KIND>
std::optional<typename IntegerExpr<KIND>::Constant>
std::optional<typename IntegerExpr<KIND>::Scalar>
IntegerExpr<KIND>::Subtract::Fold(FoldingContext &context) {
auto lc{this->left().Fold(context)};
auto rc{this->right().Fold(context)};
@ -276,7 +280,7 @@ IntegerExpr<KIND>::Subtract::Fold(FoldingContext &context) {
}
template<int KIND>
std::optional<typename IntegerExpr<KIND>::Constant>
std::optional<typename IntegerExpr<KIND>::Scalar>
IntegerExpr<KIND>::Multiply::Fold(FoldingContext &context) {
auto lc{this->left().Fold(context)};
auto rc{this->right().Fold(context)};
@ -293,7 +297,7 @@ IntegerExpr<KIND>::Multiply::Fold(FoldingContext &context) {
}
template<int KIND>
std::optional<typename IntegerExpr<KIND>::Constant>
std::optional<typename IntegerExpr<KIND>::Scalar>
IntegerExpr<KIND>::Divide::Fold(FoldingContext &context) {
auto lc{this->left().Fold(context)};
auto rc{this->right().Fold(context)};
@ -312,12 +316,12 @@ IntegerExpr<KIND>::Divide::Fold(FoldingContext &context) {
}
template<int KIND>
std::optional<typename IntegerExpr<KIND>::Constant>
std::optional<typename IntegerExpr<KIND>::Scalar>
IntegerExpr<KIND>::Power::Fold(FoldingContext &context) {
auto lc{this->left().Fold(context)};
auto rc{this->right().Fold(context)};
if (lc && rc) {
typename Constant::PowerWithErrors power{lc->Power(*rc)};
typename Scalar::PowerWithErrors power{lc->Power(*rc)};
if (context.messages != nullptr) {
if (power.divisionByZero) {
context.messages->Say(context.at, "zero to negative power"_en_US);
@ -333,7 +337,7 @@ IntegerExpr<KIND>::Power::Fold(FoldingContext &context) {
}
template<int KIND>
std::optional<typename IntegerExpr<KIND>::Constant>
std::optional<typename IntegerExpr<KIND>::Scalar>
IntegerExpr<KIND>::Max::Fold(FoldingContext &context) {
auto lc{this->left().Fold(context)};
auto rc{this->right().Fold(context)};
@ -347,7 +351,7 @@ IntegerExpr<KIND>::Max::Fold(FoldingContext &context) {
}
template<int KIND>
std::optional<typename IntegerExpr<KIND>::Constant>
std::optional<typename IntegerExpr<KIND>::Scalar>
IntegerExpr<KIND>::Min::Fold(FoldingContext &context) {
auto lc{this->left().Fold(context)};
auto rc{this->right().Fold(context)};
@ -361,12 +365,12 @@ IntegerExpr<KIND>::Min::Fold(FoldingContext &context) {
}
template<int KIND>
std::optional<typename IntegerExpr<KIND>::Constant> IntegerExpr<KIND>::Fold(
std::optional<typename IntegerExpr<KIND>::Scalar> IntegerExpr<KIND>::Fold(
FoldingContext &context) {
return std::visit(
[&](auto &x) -> std::optional<Constant> {
[&](auto &x) -> std::optional<Scalar> {
using Ty = typename std::decay<decltype(x)>::type;
if constexpr (std::is_same_v<Ty, Constant>) {
if constexpr (std::is_same_v<Ty, Scalar>) {
return {x};
}
if constexpr (std::is_base_of_v<Un, Ty> || std::is_base_of_v<Bin, Ty>) {
@ -381,61 +385,27 @@ std::optional<typename IntegerExpr<KIND>::Constant> IntegerExpr<KIND>::Fold(
u_);
}
template<int KIND>
std::optional<typename RealExpr<KIND>::Constant>
RealExpr<KIND>::ConstantValue() const {
if (auto c{std::get_if<Constant>(&u_)}) {
return {*c};
}
return {};
}
template<int KIND> void RealExpr<KIND>::Fold(FoldingContext &context) {
// TODO
}
template<int KIND>
std::optional<typename ComplexExpr<KIND>::Constant>
ComplexExpr<KIND>::ConstantValue() const {
if (auto c{std::get_if<Constant>(&u_)}) {
return {*c};
}
return {};
}
template<int KIND> void ComplexExpr<KIND>::Fold(FoldingContext &context) {
// TODO
}
template<int KIND>
std::optional<typename CharacterExpr<KIND>::Constant>
CharacterExpr<KIND>::ConstantValue() const {
if (auto c{std::get_if<Constant>(&u_)}) {
return {*c};
}
return {};
}
template<int KIND> void CharacterExpr<KIND>::Fold(FoldingContext &context) {
// TODO
}
std::optional<bool> LogicalExpr::ConstantValue() const {
if (auto c{std::get_if<bool>(&u_)}) {
return {*c};
}
return {};
}
void LogicalExpr::Fold(FoldingContext &context) {
// TODO and comparisons too
}
std::optional<GenericConstant> GenericExpr::ConstantValue() const {
std::optional<GenericScalar> GenericExpr::ScalarValue() const {
return std::visit(
[](const auto &x) -> std::optional<GenericConstant> {
if (auto c{x.ConstantValue()}) {
return {GenericConstant{std::move(*c)}};
[](const auto &x) -> std::optional<GenericScalar> {
if (auto c{x.ScalarValue()}) {
return {GenericScalar{std::move(*c)}};
}
return {};
},
@ -443,11 +413,11 @@ std::optional<GenericConstant> GenericExpr::ConstantValue() const {
}
template<Category CAT>
std::optional<CategoryConstant<CAT>> CategoryExpr<CAT>::ConstantValue() const {
std::optional<CategoryScalar<CAT>> CategoryExpr<CAT>::ScalarValue() const {
return std::visit(
[](const auto &x) -> std::optional<CategoryConstant<CAT>> {
if (auto c{x.ConstantValue()}) {
return {CategoryConstant<CAT>{std::move(*c)}};
[](const auto &x) -> std::optional<CategoryScalar<CAT>> {
if (auto c{x.ScalarValue()}) {
return {CategoryScalar<CAT>{std::move(*c)}};
}
return {};
},

View File

@ -37,13 +37,14 @@ namespace Fortran::evaluate {
struct FoldingContext {
const parser::CharBlock &at;
parser::Messages *messages;
std::size_t element;
};
// Helper base classes for packaging subexpressions.
template<typename A, typename CONST = typename A::Constant> class Unary {
template<typename A, typename SCALAR = typename A::Scalar> class Unary {
public:
using Operand = A;
using Constant = CONST;
using Scalar = SCALAR;
CLASS_BOILERPLATE(Unary)
Unary(const A &a) : operand_{a} {}
Unary(A &&a) : operand_{std::move(a)} {}
@ -51,18 +52,19 @@ public:
const A &operand() const { return *operand_; }
A &operand() { return *operand_; }
std::ostream &Dump(std::ostream &, const char *opr) const;
std::optional<CONST> Fold(FoldingContext &); // folds operand, no result
std::optional<Scalar> Fold(FoldingContext &); // folds operand, no result
int Rank() const { return operand_.Rank(); }
private:
CopyableIndirection<A> operand_;
};
template<typename A, typename B = A, typename CONST = typename A::Constant>
template<typename A, typename B = A, typename SCALAR = typename A::Scalar>
class Binary {
public:
using Left = A;
using Right = B;
using Constant = CONST;
using Scalar = SCALAR;
CLASS_BOILERPLATE(Binary)
Binary(const A &a, const B &b) : left_{a}, right_{b} {}
Binary(A &&a, B &&b) : left_{std::move(a)}, right_{std::move(b)} {}
@ -74,7 +76,8 @@ public:
B &right() { return *right_; }
std::ostream &Dump(
std::ostream &, const char *opr, const char *before = "(") const;
std::optional<CONST> Fold(FoldingContext &); // folds operands, no result
int Rank() const;
std::optional<Scalar> Fold(FoldingContext &); // folds operands, no result
private:
CopyableIndirection<A> left_;
@ -84,61 +87,61 @@ private:
template<int KIND> class Expr<Category::Integer, KIND> {
public:
using Result = Type<Category::Integer, KIND>;
using Constant = typename Result::Value;
struct ConvertInteger : public Unary<GenericIntegerExpr, Constant> {
using Unary<GenericIntegerExpr, Constant>::Unary;
std::optional<Constant> Fold(FoldingContext &);
using Scalar = typename Result::Value;
struct ConvertInteger : public Unary<GenericIntegerExpr, Scalar> {
using Unary<GenericIntegerExpr, Scalar>::Unary;
std::optional<Scalar> Fold(FoldingContext &);
};
struct ConvertReal : public Unary<GenericRealExpr, Constant> {
using Unary<GenericRealExpr, Constant>::Unary;
struct ConvertReal : public Unary<GenericRealExpr, Scalar> {
using Unary<GenericRealExpr, Scalar>::Unary;
};
using Un = Unary<Expr, Constant>;
using Bin = Binary<Expr, Expr, Constant>;
using Un = Unary<Expr, Scalar>;
using Bin = Binary<Expr, Expr, Scalar>;
struct Parentheses : public Un {
using Un::Un;
std::optional<Constant> Fold(FoldingContext &c) {
std::optional<Scalar> Fold(FoldingContext &c) {
return this->operand().Fold(c);
}
};
struct Negate : public Un {
using Un::Un;
std::optional<Constant> Fold(FoldingContext &);
std::optional<Scalar> Fold(FoldingContext &);
};
struct Add : public Bin {
using Bin::Bin;
std::optional<Constant> Fold(FoldingContext &);
std::optional<Scalar> Fold(FoldingContext &);
};
struct Subtract : public Bin {
using Bin::Bin;
std::optional<Constant> Fold(FoldingContext &);
std::optional<Scalar> Fold(FoldingContext &);
};
struct Multiply : public Bin {
using Bin::Bin;
std::optional<Constant> Fold(FoldingContext &);
std::optional<Scalar> Fold(FoldingContext &);
};
struct Divide : public Bin {
using Bin::Bin;
std::optional<Constant> Fold(FoldingContext &);
std::optional<Scalar> Fold(FoldingContext &);
};
struct Power : public Bin {
using Bin::Bin;
std::optional<Constant> Fold(FoldingContext &);
std::optional<Scalar> Fold(FoldingContext &);
};
struct Max : public Bin {
using Bin::Bin;
std::optional<Constant> Fold(FoldingContext &);
std::optional<Scalar> Fold(FoldingContext &);
};
struct Min : public Bin {
using Bin::Bin;
std::optional<Constant> Fold(FoldingContext &);
std::optional<Scalar> Fold(FoldingContext &);
};
// TODO: R916 type-param-inquiry
CLASS_BOILERPLATE(Expr)
Expr(const Constant &x) : u_{x} {}
Expr(std::int64_t n) : u_{Constant{n}} {}
Expr(std::uint64_t n) : u_{Constant{n}} {}
Expr(int n) : u_{Constant{n}} {}
Expr(const Scalar &x) : u_{x} {}
Expr(std::int64_t n) : u_{Scalar{n}} {}
Expr(std::uint64_t n) : u_{Scalar{n}} {}
Expr(int n) : u_{Scalar{n}} {}
template<int K>
Expr(const IntegerExpr<K> &x) : u_{ConvertInteger{GenericIntegerExpr{x}}} {}
template<int K>
@ -156,11 +159,13 @@ public:
: u_(std::move(x)) {}
template<typename A> Expr(CopyableIndirection<A> &&x) : u_{std::move(x)} {}
std::optional<Constant> ConstantValue() const;
std::optional<Constant> Fold(FoldingContext &c);
std::optional<Scalar> ScalarValue() const {
return common::GetIf<Scalar>(u_);
}
std::optional<Scalar> Fold(FoldingContext &c);
private:
std::variant<Constant, CopyableIndirection<DataRef>,
std::variant<Scalar, CopyableIndirection<DataRef>,
CopyableIndirection<FunctionRef>, ConvertInteger, ConvertReal,
Parentheses, Negate, Add, Subtract, Multiply, Divide, Power, Max, Min>
u_;
@ -169,19 +174,19 @@ private:
template<int KIND> class Expr<Category::Real, KIND> {
public:
using Result = Type<Category::Real, KIND>;
using Constant = typename Result::Value;
using Scalar = typename Result::Value;
// N.B. Real->Complex and Complex->Real conversions are done with CMPLX
// and part access operations (resp.). Conversions between kinds of
// Complex are done via decomposition to Real and reconstruction.
struct ConvertInteger : public Unary<GenericIntegerExpr, Constant> {
using Unary<GenericIntegerExpr, Constant>::Unary;
std::optional<Constant> Fold(FoldingContext &);
struct ConvertInteger : public Unary<GenericIntegerExpr, Scalar> {
using Unary<GenericIntegerExpr, Scalar>::Unary;
std::optional<Scalar> Fold(FoldingContext &);
};
struct ConvertReal : public Unary<GenericRealExpr, Constant> {
using Unary<GenericRealExpr, Constant>::Unary;
struct ConvertReal : public Unary<GenericRealExpr, Scalar> {
using Unary<GenericRealExpr, Scalar>::Unary;
};
using Un = Unary<Expr, Constant>;
using Bin = Binary<Expr, Expr, Constant>;
using Un = Unary<Expr, Scalar>;
using Bin = Binary<Expr, Expr, Scalar>;
struct Parentheses : public Un {
using Un::Un;
};
@ -203,8 +208,8 @@ public:
struct Power : public Bin {
using Bin::Bin;
};
struct IntPower : public Binary<Expr, GenericIntegerExpr, Constant> {
using Binary<Expr, GenericIntegerExpr, Constant>::Binary;
struct IntPower : public Binary<Expr, GenericIntegerExpr, Scalar> {
using Binary<Expr, GenericIntegerExpr, Scalar>::Binary;
};
struct Max : public Bin {
using Bin::Bin;
@ -212,7 +217,7 @@ public:
struct Min : public Bin {
using Bin::Bin;
};
using CplxUn = Unary<ComplexExpr<KIND>, Constant>;
using CplxUn = Unary<ComplexExpr<KIND>, Scalar>;
struct RealPart : public CplxUn {
using CplxUn::CplxUn;
};
@ -221,7 +226,7 @@ public:
};
CLASS_BOILERPLATE(Expr)
Expr(const Constant &x) : u_{x} {}
Expr(const Scalar &x) : u_{x} {}
template<int K>
Expr(const IntegerExpr<K> &x) : u_{ConvertInteger{GenericIntegerExpr{x}}} {}
template<int K>
@ -236,11 +241,13 @@ public:
Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u_{std::move(x)} {}
template<typename A> Expr(CopyableIndirection<A> &&x) : u_{std::move(x)} {}
std::optional<Constant> ConstantValue() const;
std::optional<Scalar> ScalarValue() const {
return common::GetIf<Scalar>(u_);
}
void Fold(FoldingContext &c);
private:
std::variant<Constant, CopyableIndirection<DataRef>,
std::variant<Scalar, CopyableIndirection<DataRef>,
CopyableIndirection<ComplexPart>, CopyableIndirection<FunctionRef>,
ConvertInteger, ConvertReal, Parentheses, Negate, Add, Subtract, Multiply,
Divide, Power, IntPower, Max, Min, RealPart, AIMAG>
@ -250,9 +257,9 @@ private:
template<int KIND> class Expr<Category::Complex, KIND> {
public:
using Result = Type<Category::Complex, KIND>;
using Constant = typename Result::Value;
using Un = Unary<Expr, Constant>;
using Bin = Binary<Expr, Expr, Constant>;
using Scalar = typename Result::Value;
using Un = Unary<Expr, Scalar>;
using Bin = Binary<Expr, Expr, Scalar>;
struct Parentheses : public Un {
using Un::Un;
};
@ -274,25 +281,27 @@ public:
struct Power : public Bin {
using Bin::Bin;
};
struct IntPower : public Binary<Expr, GenericIntegerExpr, Constant> {
using Binary<Expr, GenericIntegerExpr, Constant>::Binary;
struct IntPower : public Binary<Expr, GenericIntegerExpr, Scalar> {
using Binary<Expr, GenericIntegerExpr, Scalar>::Binary;
};
struct CMPLX : public Binary<RealExpr<KIND>, RealExpr<KIND>, Constant> {
using Binary<RealExpr<KIND>, RealExpr<KIND>, Constant>::Binary;
struct CMPLX : public Binary<RealExpr<KIND>, RealExpr<KIND>, Scalar> {
using Binary<RealExpr<KIND>, RealExpr<KIND>, Scalar>::Binary;
};
CLASS_BOILERPLATE(Expr)
Expr(const Constant &x) : u_{x} {}
Expr(const Scalar &x) : u_{x} {}
template<typename A> Expr(const A &x) : u_{x} {}
template<typename A>
Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u_{std::move(x)} {}
template<typename A> Expr(CopyableIndirection<A> &&x) : u_{std::move(x)} {}
std::optional<Constant> ConstantValue() const;
std::optional<Scalar> ScalarValue() const {
return common::GetIf<Scalar>(u_);
}
void Fold(FoldingContext &c);
private:
std::variant<Constant, CopyableIndirection<DataRef>,
std::variant<Scalar, CopyableIndirection<DataRef>,
CopyableIndirection<FunctionRef>, Parentheses, Negate, Add, Subtract,
Multiply, Divide, Power, IntPower, CMPLX>
u_;
@ -301,8 +310,8 @@ private:
template<int KIND> class Expr<Category::Character, KIND> {
public:
using Result = Type<Category::Character, KIND>;
using Constant = typename Result::Value;
using Bin = Binary<Expr, Expr, Constant>;
using Scalar = typename Result::Value;
using Bin = Binary<Expr, Expr, Scalar>;
struct Concat : public Bin {
using Bin::Bin;
};
@ -314,19 +323,21 @@ public:
};
CLASS_BOILERPLATE(Expr)
Expr(const Constant &x) : u_{x} {}
Expr(Constant &&x) : u_{std::move(x)} {}
Expr(const Scalar &x) : u_{x} {}
Expr(Scalar &&x) : u_{std::move(x)} {}
template<typename A> Expr(const A &x) : u_{x} {}
template<typename A>
Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u_{std::move(x)} {}
template<typename A> Expr(CopyableIndirection<A> &&x) : u_{std::move(x)} {}
std::optional<Constant> ConstantValue() const;
std::optional<Scalar> ScalarValue() const {
return common::GetIf<Scalar>(u_);
}
void Fold(FoldingContext &c);
SubscriptIntegerExpr LEN() const;
private:
std::variant<Constant, CopyableIndirection<DataRef>,
std::variant<Scalar, CopyableIndirection<DataRef>,
CopyableIndirection<Substring>, CopyableIndirection<FunctionRef>, Concat,
Max, Min>
u_;
@ -379,7 +390,7 @@ template<Category CAT> struct CategoryComparison {
// No need to distinguish the various kinds of LOGICAL expression results.
template<> class Expr<Category::Logical, 1> {
public:
using Constant = bool;
using Scalar = bool;
struct Not : Unary<Expr, bool> {
using Unary<Expr, bool>::Unary;
};
@ -409,7 +420,7 @@ public:
Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u_{std::move(x)} {}
template<typename A> Expr(CopyableIndirection<A> &&x) : u_{std::move(x)} {}
std::optional<bool> ConstantValue() const;
std::optional<bool> ScalarValue() const { return common::GetIf<bool>(u_); }
void Fold(FoldingContext &c);
private:
@ -439,33 +450,33 @@ extern template class Expr<Category::Complex, 16>;
extern template class Expr<Category::Character, 1>;
extern template class Expr<Category::Logical, 1>;
// Holds a constant of any kind in an intrinsic type category.
template<Category CAT> struct CategoryConstant {
CLASS_BOILERPLATE(CategoryConstant)
template<int KIND> using KindConstant = typename Expr<CAT, KIND>::Constant;
template<typename A> CategoryConstant(const A &x) : u{x} {}
// Holds a scalar constant of any kind in an intrinsic type category.
template<Category CAT> struct CategoryScalar {
CLASS_BOILERPLATE(CategoryScalar)
template<int KIND> using KindScalar = typename Expr<CAT, KIND>::Scalar;
template<typename A> CategoryScalar(const A &x) : u{x} {}
template<typename A>
CategoryConstant(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
CategoryScalar(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
: u{std::move(x)} {}
typename KindsVariant<CAT, KindConstant>::type u;
typename KindsVariant<CAT, KindScalar>::type u;
};
// Holds a constant of any intrinsic category and size.
struct GenericConstant {
CLASS_BOILERPLATE(GenericConstant)
// Holds a scalar constant of any intrinsic category and size.
struct GenericScalar {
CLASS_BOILERPLATE(GenericScalar)
template<Category CAT, int KIND>
GenericConstant(const typename Expr<CAT, KIND>::Constant &x)
: u{CategoryConstant<CAT>{x}} {}
GenericScalar(const typename Expr<CAT, KIND>::Scalar &x)
: u{CategoryScalar<CAT>{x}} {}
template<Category CAT, int KIND>
GenericConstant(typename Expr<CAT, KIND>::Constant &&x)
: u{CategoryConstant<CAT>{std::move(x)}} {}
template<typename A> GenericConstant(const A &x) : u{x} {}
GenericScalar(typename Expr<CAT, KIND>::Scalar &&x)
: u{CategoryScalar<CAT>{std::move(x)}} {}
template<typename A> GenericScalar(const A &x) : u{x} {}
template<typename A>
GenericConstant(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
GenericScalar(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
: u{std::move(x)} {}
std::variant<CategoryConstant<Category::Integer>,
CategoryConstant<Category::Real>, CategoryConstant<Category::Complex>,
CategoryConstant<Category::Character>, bool>
std::variant<CategoryScalar<Category::Integer>,
CategoryScalar<Category::Real>, CategoryScalar<Category::Complex>,
CategoryScalar<Category::Character>, bool>
u;
};
@ -476,7 +487,7 @@ template<Category CAT> struct CategoryExpr {
template<int KIND> using KindExpr = Expr<CAT, KIND>;
template<int KIND> CategoryExpr(const KindExpr<KIND> &x) : u{x} {}
template<int KIND> CategoryExpr(KindExpr<KIND> &&x) : u{std::move(x)} {}
std::optional<CategoryConstant<CAT>> ConstantValue() const;
std::optional<CategoryScalar<CAT>> ScalarValue() const;
void Fold(FoldingContext &);
typename KindsVariant<CAT, KindExpr>::type u;
};
@ -493,7 +504,7 @@ struct GenericExpr {
template<typename A>
GenericExpr(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
: u{std::move(x)} {}
std::optional<GenericConstant> ConstantValue() const;
std::optional<GenericScalar> ScalarValue() const;
void Fold(FoldingContext &);
int Rank() const { return 1; } // TODO
std::variant<GenericIntegerExpr, GenericRealExpr, GenericComplexExpr,

View File

@ -44,7 +44,7 @@ std::optional<evaluate::GenericExpr> AnalyzeHelper(
std::optional<evaluate::GenericExpr> result{AnalyzeHelper(ea, tree.thing)};
if (result.has_value()) {
result->Fold(ea.context());
if (!result->ConstantValue().has_value()) {
if (!result->ScalarValue().has_value()) {
ea.Say("must be constant"_err_en_US);
return {};
}
@ -84,8 +84,8 @@ ExpressionAnalyzer::KindParam ExpressionAnalyzer::Analyze(
parser::Integer<parser::Constant<parser::Name>>> &n) {
if (std::optional<evaluate::GenericExpr> oge{
AnalyzeHelper(*this, n)}) {
if (std::optional<evaluate::GenericConstant> ogc{
oge->ConstantValue()}) {
if (std::optional<evaluate::GenericScalar> ogs{
oge->ScalarValue()}) {
// TODO pmk more here next
}
}