forked from OSchip/llvm-project
[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:
parent
9a503392b4
commit
e4f12b087c
|
@ -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_
|
||||
|
|
|
@ -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 {};
|
||||
},
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue