mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-29 14:06:12 +00:00
[flang] Expression analysis checkpoint
Original-commit: flang-compiler/f18@f740cab641 Reviewed-on: https://github.com/flang-compiler/f18/pull/183 Tree-same-pre-rewrite: false
This commit is contained in:
parent
21fbc5fcfe
commit
2e68aff3fd
@ -19,6 +19,7 @@ add_library(FortranEvaluate
|
|||||||
integer.cc
|
integer.cc
|
||||||
logical.cc
|
logical.cc
|
||||||
real.cc
|
real.cc
|
||||||
|
tools.cc
|
||||||
type.cc
|
type.cc
|
||||||
variable.cc
|
variable.cc
|
||||||
)
|
)
|
||||||
|
@ -485,14 +485,14 @@ auto RealExpr<KIND>::Min::FoldScalar(FoldingContext &context, const Scalar &a,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<int KIND>
|
template<int KIND>
|
||||||
auto RealExpr<KIND>::RealPart::FoldScalar(
|
auto RealExpr<KIND>::RealPart::FoldScalar(FoldingContext &context,
|
||||||
FoldingContext &context, const CplxScalar &z) -> std::optional<Scalar> {
|
const SameKindComplexScalar &z) -> std::optional<Scalar> {
|
||||||
return {z.REAL()};
|
return {z.REAL()};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<int KIND>
|
template<int KIND>
|
||||||
auto RealExpr<KIND>::AIMAG::FoldScalar(
|
auto RealExpr<KIND>::AIMAG::FoldScalar(FoldingContext &context,
|
||||||
FoldingContext &context, const CplxScalar &z) -> std::optional<Scalar> {
|
const SameKindComplexScalar &z) -> std::optional<Scalar> {
|
||||||
return {z.AIMAG()};
|
return {z.AIMAG()};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -578,7 +578,8 @@ auto ComplexExpr<KIND>::IntPower::FoldScalar(FoldingContext &context,
|
|||||||
|
|
||||||
template<int KIND>
|
template<int KIND>
|
||||||
auto ComplexExpr<KIND>::CMPLX::FoldScalar(FoldingContext &context,
|
auto ComplexExpr<KIND>::CMPLX::FoldScalar(FoldingContext &context,
|
||||||
const PartScalar &a, const PartScalar &b) -> std::optional<Scalar> {
|
const SameKindRealScalar &a, const SameKindRealScalar &b)
|
||||||
|
-> std::optional<Scalar> {
|
||||||
return {Scalar{a, b}};
|
return {Scalar{a, b}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,18 +277,19 @@ public:
|
|||||||
static std::optional<Scalar> FoldScalar(
|
static std::optional<Scalar> FoldScalar(
|
||||||
FoldingContext &, const Scalar &, const Scalar &);
|
FoldingContext &, const Scalar &, const Scalar &);
|
||||||
};
|
};
|
||||||
using Cplx = Type<TypeCategory::Complex, KIND>;
|
using SameKindComplex = Type<TypeCategory::Complex, KIND>;
|
||||||
using CplxScalar = typename Cplx::Value;
|
using SameKindComplexScalar = typename SameKindComplex::Value;
|
||||||
template<typename CRTP> using CplxUn = Unary<CRTP, Result, Cplx>;
|
template<typename CRTP>
|
||||||
struct RealPart : public CplxUn<RealPart> {
|
using SameKindComplexUn = Unary<CRTP, Result, SameKindComplex>;
|
||||||
using CplxUn<RealPart>::CplxUn;
|
struct RealPart : public SameKindComplexUn<RealPart> {
|
||||||
|
using SameKindComplexUn<RealPart>::SameKindComplexUn;
|
||||||
static std::optional<Scalar> FoldScalar(
|
static std::optional<Scalar> FoldScalar(
|
||||||
FoldingContext &, const CplxScalar &);
|
FoldingContext &, const SameKindComplexScalar &);
|
||||||
};
|
};
|
||||||
struct AIMAG : public CplxUn<AIMAG> {
|
struct AIMAG : public SameKindComplexUn<AIMAG> {
|
||||||
using CplxUn<AIMAG>::CplxUn;
|
using SameKindComplexUn<AIMAG>::SameKindComplexUn;
|
||||||
static std::optional<Scalar> FoldScalar(
|
static std::optional<Scalar> FoldScalar(
|
||||||
FoldingContext &, const CplxScalar &);
|
FoldingContext &, const SameKindComplexScalar &);
|
||||||
};
|
};
|
||||||
|
|
||||||
CLASS_BOILERPLATE(Expr)
|
CLASS_BOILERPLATE(Expr)
|
||||||
@ -373,12 +374,12 @@ public:
|
|||||||
static std::optional<Scalar> FoldScalar(FoldingContext &, const Scalar &,
|
static std::optional<Scalar> FoldScalar(FoldingContext &, const Scalar &,
|
||||||
const ScalarConstant<TypeCategory::Integer> &);
|
const ScalarConstant<TypeCategory::Integer> &);
|
||||||
};
|
};
|
||||||
using Part = Type<TypeCategory::Real, KIND>;
|
using SameKindReal = Type<TypeCategory::Real, KIND>;
|
||||||
using PartScalar = typename Part::Value;
|
using SameKindRealScalar = typename SameKindReal::Value;
|
||||||
struct CMPLX : public Binary<CMPLX, Result, Part> {
|
struct CMPLX : public Binary<CMPLX, Result, SameKindReal> {
|
||||||
using Binary<CMPLX, Result, Part>::Binary;
|
using Binary<CMPLX, Result, SameKindReal>::Binary;
|
||||||
static std::optional<Scalar> FoldScalar(
|
static std::optional<Scalar> FoldScalar(FoldingContext &,
|
||||||
FoldingContext &, const PartScalar &, const PartScalar &);
|
const SameKindRealScalar &, const SameKindRealScalar &);
|
||||||
};
|
};
|
||||||
|
|
||||||
CLASS_BOILERPLATE(Expr)
|
CLASS_BOILERPLATE(Expr)
|
||||||
@ -608,15 +609,19 @@ struct GenericExpr {
|
|||||||
using Scalar = GenericScalar;
|
using Scalar = GenericScalar;
|
||||||
using FoldableTrait = std::true_type;
|
using FoldableTrait = std::true_type;
|
||||||
CLASS_BOILERPLATE(GenericExpr)
|
CLASS_BOILERPLATE(GenericExpr)
|
||||||
template<TypeCategory CAT, int KIND>
|
|
||||||
GenericExpr(const Expr<Type<CAT, KIND>> &x) : u{Expr<AnyKindType<CAT>>{x}} {}
|
|
||||||
template<TypeCategory CAT, int KIND>
|
|
||||||
GenericExpr(Expr<Type<CAT, KIND>> &&x)
|
|
||||||
: u{Expr<AnyKindType<CAT>>{std::move(x)}} {}
|
|
||||||
template<typename A> GenericExpr(const A &x) : u{x} {}
|
template<typename A> GenericExpr(const A &x) : u{x} {}
|
||||||
template<typename A>
|
template<typename A>
|
||||||
GenericExpr(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
|
GenericExpr(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
|
||||||
: u{std::move(x)} {}
|
: u{std::move(x)} {}
|
||||||
|
|
||||||
|
template<TypeCategory CAT, int KIND>
|
||||||
|
GenericExpr(const Expr<Type<CAT, KIND>> &x) : u{Expr<AnyKindType<CAT>>{x}} {}
|
||||||
|
|
||||||
|
template<TypeCategory CAT, int KIND>
|
||||||
|
GenericExpr(Expr<Type<CAT, KIND>> &&x)
|
||||||
|
: u{Expr<AnyKindType<CAT>>{std::move(x)}} {}
|
||||||
|
|
||||||
std::optional<Scalar> ScalarValue() const;
|
std::optional<Scalar> ScalarValue() const;
|
||||||
std::optional<Scalar> Fold(FoldingContext &);
|
std::optional<Scalar> Fold(FoldingContext &);
|
||||||
int Rank() const { return 1; } // TODO
|
int Rank() const { return 1; } // TODO
|
||||||
|
@ -419,10 +419,18 @@ ValueWithRealFlags<Real<W, P, IM>> Real<W, P, IM>::Read(
|
|||||||
}
|
}
|
||||||
exponent += expoVal;
|
exponent += expoVal;
|
||||||
}
|
}
|
||||||
Real tenPower{IntPower(ten, Integer<64>{exponent}, rounding)
|
if (exponent == 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
Real tenPower{IntPower(ten, Integer<64>{std::abs(exponent)}, rounding)
|
||||||
.AccumulateFlags(result.flags)};
|
.AccumulateFlags(result.flags)};
|
||||||
result.value =
|
if (exponent > 0) {
|
||||||
result.value.Multiply(tenPower, rounding).AccumulateFlags(result.flags);
|
result.value =
|
||||||
|
result.value.Multiply(tenPower, rounding).AccumulateFlags(result.flags);
|
||||||
|
} else {
|
||||||
|
result.value =
|
||||||
|
result.value.Divide(tenPower, rounding).AccumulateFlags(result.flags);
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
89
flang/lib/evaluate/tools.cc
Normal file
89
flang/lib/evaluate/tools.cc
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "tools.h"
|
||||||
|
#include "../parser/message.h"
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
using namespace Fortran::parser::literals;
|
||||||
|
|
||||||
|
namespace Fortran::evaluate {
|
||||||
|
|
||||||
|
AnyKindRealExpr ConvertToTypeOf(
|
||||||
|
const AnyKindRealExpr &to, const AnyKindIntegerExpr &from) {
|
||||||
|
return std::visit(
|
||||||
|
[&](const auto &rk) { return AnyKindRealExpr{decltype(rk){to}}; }, to.u);
|
||||||
|
}
|
||||||
|
|
||||||
|
AnyKindRealExpr ConvertToTypeOf(
|
||||||
|
const AnyKindRealExpr &to, const AnyKindRealExpr &from) {
|
||||||
|
return std::visit(
|
||||||
|
[&](const auto &rk) { return AnyKindRealExpr{decltype(rk){to}}; }, to.u);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ConvertToSameRealKind(AnyKindRealExpr &x, AnyKindRealExpr &y) {
|
||||||
|
std::visit(
|
||||||
|
[&](auto &xk, auto &yk) {
|
||||||
|
using xt = typename std::decay<decltype(xk)>::type;
|
||||||
|
using yt = typename std::decay<decltype(yk)>::type;
|
||||||
|
constexpr int kindDiff{xt::Result::kind - yt::Result::kind};
|
||||||
|
if constexpr (kindDiff < 0) {
|
||||||
|
x.u = yt{xk};
|
||||||
|
} else if constexpr (kindDiff > 0) {
|
||||||
|
y.u = xt{yk};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
x.u, y.u);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::pair<AnyKindRealExpr, AnyKindRealExpr>> ConvertRealOperands(
|
||||||
|
parser::ContextualMessages &messages, GenericExpr &&x, GenericExpr &&y) {
|
||||||
|
return std::visit(
|
||||||
|
common::visitors{
|
||||||
|
[&](AnyKindIntegerExpr &&ix, AnyKindIntegerExpr &&iy) {
|
||||||
|
// Can happen in a CMPLX() constructor. Per F'2018, both integer
|
||||||
|
// operands are converted to default REAL.
|
||||||
|
return std::optional{std::make_pair(
|
||||||
|
AnyKindRealExpr{Expr<DefaultReal>{std::move(ix)}},
|
||||||
|
AnyKindRealExpr{Expr<DefaultReal>{std::move(iy)}})};
|
||||||
|
},
|
||||||
|
[&](AnyKindIntegerExpr &&ix, AnyKindRealExpr &&ry) {
|
||||||
|
auto rx{ConvertToTypeOf(ry, std::move(ix))};
|
||||||
|
return std::optional{std::make_pair(std::move(rx), std::move(ry))};
|
||||||
|
},
|
||||||
|
[&](AnyKindRealExpr &&rx, AnyKindIntegerExpr &&iy) {
|
||||||
|
auto ry{ConvertToTypeOf(rx, std::move(iy))};
|
||||||
|
return std::optional{std::make_pair(std::move(rx), std::move(ry))};
|
||||||
|
},
|
||||||
|
[&](AnyKindRealExpr &&rx, AnyKindRealExpr &&ry) {
|
||||||
|
ConvertToSameRealKind(rx, ry);
|
||||||
|
return std::optional{std::make_pair(std::move(rx), std::move(ry))};
|
||||||
|
},
|
||||||
|
[&](const auto &, const auto &)
|
||||||
|
-> std::optional<std::pair<AnyKindRealExpr, AnyKindRealExpr>> {
|
||||||
|
messages.Say("operands must be INTEGER or REAL"_err_en_US);
|
||||||
|
return std::nullopt;
|
||||||
|
}},
|
||||||
|
std::move(x.u), std::move(y.u));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::pair<AnyKindRealExpr, AnyKindRealExpr>> ConvertRealOperands(
|
||||||
|
parser::ContextualMessages &messages, std::optional<GenericExpr> &&x,
|
||||||
|
std::optional<GenericExpr> &&y) {
|
||||||
|
if (x.has_value() && y.has_value()) {
|
||||||
|
return ConvertRealOperands(messages, std::move(*x), std::move(*y));
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
} // namespace Fortran::evaluate
|
41
flang/lib/evaluate/tools.h
Normal file
41
flang/lib/evaluate/tools.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef FORTRAN_EVALUATE_TOOLS_H_
|
||||||
|
#define FORTRAN_EVALUATE_TOOLS_H_
|
||||||
|
|
||||||
|
#include "expression.h"
|
||||||
|
#include "../parser/message.h"
|
||||||
|
#include <optional>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace Fortran::evaluate {
|
||||||
|
|
||||||
|
// Convert the second argument to the same type and kind of the first.
|
||||||
|
AnyKindRealExpr ConvertToTypeOf(
|
||||||
|
const AnyKindRealExpr &to, const AnyKindIntegerExpr &from);
|
||||||
|
AnyKindRealExpr ConvertToTypeOf(
|
||||||
|
const AnyKindRealExpr &to, const AnyKindRealExpr &from);
|
||||||
|
|
||||||
|
// Ensure that both operands of an intrinsic REAL operation or CMPLX()
|
||||||
|
// are INTEGER or REAL, and convert them as necessary to the same REAL type.
|
||||||
|
std::optional<std::pair<AnyKindRealExpr, AnyKindRealExpr>> ConvertRealOperands(
|
||||||
|
parser::ContextualMessages &, GenericExpr &&, GenericExpr &&);
|
||||||
|
|
||||||
|
std::optional<std::pair<AnyKindRealExpr, AnyKindRealExpr>> ConvertRealOperands(
|
||||||
|
parser::ContextualMessages &, std::optional<GenericExpr> &&x,
|
||||||
|
std::optional<GenericExpr> &&y);
|
||||||
|
|
||||||
|
} // namespace Fortran::evaluate
|
||||||
|
#endif // FORTRAN_EVALUATE_TOOLS_H_
|
@ -13,8 +13,10 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "expression.h"
|
#include "expression.h"
|
||||||
|
#include "symbol.h"
|
||||||
#include "../common/idioms.h"
|
#include "../common/idioms.h"
|
||||||
#include "../evaluate/common.h"
|
#include "../evaluate/common.h"
|
||||||
|
#include "../evaluate/tools.h"
|
||||||
|
|
||||||
using namespace Fortran::parser::literals;
|
using namespace Fortran::parser::literals;
|
||||||
|
|
||||||
@ -83,16 +85,16 @@ Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Integer<A> &tree) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
static std::optional<evaluate::AnyKindCharacterExpr> AnalyzeLiteral(
|
||||||
Result AnalyzeHelper(
|
|
||||||
ExpressionAnalyzer &ea, const parser::CharLiteralConstant &x) {
|
ExpressionAnalyzer &ea, const parser::CharLiteralConstant &x) {
|
||||||
auto kind{ea.Analyze(std::get<std::optional<parser::KindParam>>(x.t),
|
auto kind{ea.Analyze(std::get<std::optional<parser::KindParam>>(x.t),
|
||||||
ExpressionAnalyzer::KindParam{1})};
|
ExpressionAnalyzer::KindParam{1})};
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
#define CASE(k) \
|
#define CASE(k) \
|
||||||
case k: \
|
case k: \
|
||||||
return {evaluate::GenericExpr{evaluate::AnyKindCharacterExpr{ \
|
return {evaluate::AnyKindCharacterExpr{ \
|
||||||
evaluate::CharacterExpr<k>{std::get<std::string>(x.t)}}}};
|
evaluate::CharacterExpr<k>{std::get<std::string>(x.t)}}};
|
||||||
|
FOR_EACH_CHARACTER_KIND(CASE, )
|
||||||
#undef CASE
|
#undef CASE
|
||||||
default:
|
default:
|
||||||
ea.context().messages.Say("unimplemented CHARACTER kind (%ju)"_err_en_US,
|
ea.context().messages.Say("unimplemented CHARACTER kind (%ju)"_err_en_US,
|
||||||
@ -101,6 +103,15 @@ Result AnalyzeHelper(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: move this functor to common? abstract to more of an fmap?
|
||||||
|
template<typename A, typename B>
|
||||||
|
std::optional<A> WrapOptional(std::optional<B> &&x) {
|
||||||
|
if (x.has_value()) {
|
||||||
|
return {A{std::move(*x)}};
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
Result AnalyzeHelper(
|
Result AnalyzeHelper(
|
||||||
ExpressionAnalyzer &ea, const parser::CharLiteralConstantSubstring &x) {
|
ExpressionAnalyzer &ea, const parser::CharLiteralConstantSubstring &x) {
|
||||||
@ -109,7 +120,8 @@ Result AnalyzeHelper(
|
|||||||
const std::optional<parser::ScalarIntExpr> &ubTree{std::get<1>(range.t)};
|
const std::optional<parser::ScalarIntExpr> &ubTree{std::get<1>(range.t)};
|
||||||
if (!lbTree.has_value() && !ubTree.has_value()) {
|
if (!lbTree.has_value() && !ubTree.has_value()) {
|
||||||
// "..."(:)
|
// "..."(:)
|
||||||
return AnalyzeHelper(ea, std::get<parser::CharLiteralConstant>(x.t));
|
return WrapOptional<evaluate::GenericExpr>(
|
||||||
|
AnalyzeLiteral(ea, std::get<parser::CharLiteralConstant>(x.t)));
|
||||||
}
|
}
|
||||||
// TODO: ensure that any kind parameter is 1
|
// TODO: ensure that any kind parameter is 1
|
||||||
std::string str{std::get<parser::CharLiteralConstant>(x.t).GetString()};
|
std::string str{std::get<parser::CharLiteralConstant>(x.t).GetString()};
|
||||||
@ -141,22 +153,21 @@ Result AnalyzeHelper(
|
|||||||
evaluate::CopyableIndirection<evaluate::Substring> ind{std::move(substring)};
|
evaluate::CopyableIndirection<evaluate::Substring> ind{std::move(substring)};
|
||||||
evaluate::CharacterExpr<1> chExpr{std::move(ind)};
|
evaluate::CharacterExpr<1> chExpr{std::move(ind)};
|
||||||
chExpr.Fold(ea.context());
|
chExpr.Fold(ea.context());
|
||||||
evaluate::AnyKindCharacterExpr akcExpr{std::move(chExpr)};
|
return {
|
||||||
evaluate::GenericExpr gExpr{std::move(akcExpr)};
|
evaluate::GenericExpr{evaluate::AnyKindCharacterExpr{std::move(chExpr)}}};
|
||||||
return {gExpr};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
// Common handling of parser::IntLiteralConstant and SignedIntLiteralConstant
|
||||||
Result AnalyzeHelper(
|
template<typename PARSED>
|
||||||
ExpressionAnalyzer &ea, const parser::IntLiteralConstant &x) {
|
std::optional<evaluate::AnyKindIntegerExpr> IntLiteralConstant(
|
||||||
|
ExpressionAnalyzer &ea, const PARSED &x) {
|
||||||
auto kind{ea.Analyze(std::get<std::optional<parser::KindParam>>(x.t),
|
auto kind{ea.Analyze(std::get<std::optional<parser::KindParam>>(x.t),
|
||||||
ea.defaultIntegerKind())};
|
ea.defaultIntegerKind())};
|
||||||
std::uint64_t value{std::get<std::uint64_t>(x.t)};
|
auto value{std::get<0>(x.t)}; // std::[u]int64_t
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
#define CASE(k) \
|
#define CASE(k) \
|
||||||
case k: \
|
case k: \
|
||||||
return {evaluate::GenericExpr{ \
|
return {evaluate::AnyKindIntegerExpr{evaluate::IntegerExpr<k>{value}}};
|
||||||
evaluate::AnyKindIntegerExpr{evaluate::IntegerExpr<k>{value}}}};
|
|
||||||
FOR_EACH_INTEGER_KIND(CASE, )
|
FOR_EACH_INTEGER_KIND(CASE, )
|
||||||
#undef CASE
|
#undef CASE
|
||||||
default:
|
default:
|
||||||
@ -166,8 +177,17 @@ Result AnalyzeHelper(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
static std::optional<evaluate::AnyKindIntegerExpr> AnalyzeLiteral(
|
||||||
Result AnalyzeHelper(
|
ExpressionAnalyzer &ea, const parser::IntLiteralConstant &x) {
|
||||||
|
return IntLiteralConstant(ea, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::optional<evaluate::AnyKindIntegerExpr> AnalyzeLiteral(
|
||||||
|
ExpressionAnalyzer &ea, const parser::SignedIntLiteralConstant &x) {
|
||||||
|
return IntLiteralConstant(ea, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::optional<evaluate::BOZLiteralConstant> AnalyzeLiteral(
|
||||||
ExpressionAnalyzer &ea, const parser::BOZLiteralConstant &x) {
|
ExpressionAnalyzer &ea, const parser::BOZLiteralConstant &x) {
|
||||||
const char *p{x.v.data()};
|
const char *p{x.v.data()};
|
||||||
std::uint64_t base{16};
|
std::uint64_t base{16};
|
||||||
@ -189,11 +209,11 @@ Result AnalyzeHelper(
|
|||||||
ea.context().messages.Say("BOZ literal %s too large"_err_en_US, x.v.data());
|
ea.context().messages.Say("BOZ literal %s too large"_err_en_US, x.v.data());
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
return {evaluate::GenericExpr{value.value}};
|
return {value.value};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<int KIND>
|
template<int KIND>
|
||||||
Result ReadRealLiteral(
|
std::optional<evaluate::AnyKindRealExpr> ReadRealLiteral(
|
||||||
parser::CharBlock source, evaluate::FoldingContext &context) {
|
parser::CharBlock source, evaluate::FoldingContext &context) {
|
||||||
using valueType = typename evaluate::RealExpr<KIND>::Scalar;
|
using valueType = typename evaluate::RealExpr<KIND>::Scalar;
|
||||||
const char *p{source.begin()};
|
const char *p{source.begin()};
|
||||||
@ -205,12 +225,10 @@ Result ReadRealLiteral(
|
|||||||
if (context.flushDenormalsToZero) {
|
if (context.flushDenormalsToZero) {
|
||||||
value = value.FlushDenormalToZero();
|
value = value.FlushDenormalToZero();
|
||||||
}
|
}
|
||||||
return {evaluate::GenericExpr{
|
return {evaluate::AnyKindRealExpr{evaluate::RealExpr<KIND>{value}}};
|
||||||
evaluate::AnyKindRealExpr{evaluate::RealExpr<KIND>{value}}}};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
static std::optional<evaluate::AnyKindRealExpr> AnalyzeLiteral(
|
||||||
Result AnalyzeHelper(
|
|
||||||
ExpressionAnalyzer &ea, const parser::RealLiteralConstant &x) {
|
ExpressionAnalyzer &ea, const parser::RealLiteralConstant &x) {
|
||||||
// Use a local message context around the real literal.
|
// Use a local message context around the real literal.
|
||||||
parser::ContextualMessages ctxMsgs{x.real.source, ea.context().messages};
|
parser::ContextualMessages ctxMsgs{x.real.source, ea.context().messages};
|
||||||
@ -244,28 +262,84 @@ Result AnalyzeHelper(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::optional<evaluate::AnyKindRealExpr> AnalyzeLiteral(
|
||||||
|
ExpressionAnalyzer &ea, const parser::SignedRealLiteralConstant &x) {
|
||||||
|
auto result{AnalyzeLiteral(ea, std::get<parser::RealLiteralConstant>(x.t))};
|
||||||
|
if (result.has_value()) {
|
||||||
|
if (auto sign{std::get<std::optional<parser::Sign>>(x.t)}) {
|
||||||
|
if (sign == parser::Sign::Negative) {
|
||||||
|
std::visit(
|
||||||
|
[](auto &rk) {
|
||||||
|
using t = typename std::decay<decltype(rk)>::type;
|
||||||
|
rk = typename t::Negate{rk};
|
||||||
|
},
|
||||||
|
result->u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::NamedConstant &n) {
|
||||||
|
CHECK(n.v.symbol != nullptr);
|
||||||
|
auto *details{n.v.symbol->detailsIf<ObjectEntityDetails>()};
|
||||||
|
if (details == nullptr || !n.v.symbol->attrs().test(Attr::PARAMETER)) {
|
||||||
|
ea.context().messages.Say(
|
||||||
|
"name (%s) is not a defined constant"_err_en_US, n.v.ToString().data());
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return std::nullopt; // TODO parameters and enumerators
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::ComplexPart &x) {
|
||||||
|
return std::visit(common::visitors{[&](const parser::NamedConstant &n) {
|
||||||
|
return AnalyzeHelper(ea, n);
|
||||||
|
},
|
||||||
|
[&](const auto &literal) {
|
||||||
|
return WrapOptional<evaluate::GenericExpr>(
|
||||||
|
AnalyzeLiteral(ea, literal));
|
||||||
|
}},
|
||||||
|
x.u);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::optional<evaluate::AnyKindComplexExpr> BuildComplex(
|
||||||
|
ExpressionAnalyzer &ea, Result &&re, Result &&im) {
|
||||||
|
// TODO pmk: what follows should be abstracted, it will appear many more times
|
||||||
|
auto cvtd{evaluate::ConvertRealOperands(
|
||||||
|
ea.context().messages, std::move(re), std::move(im))};
|
||||||
|
if (cvtd.has_value()) {
|
||||||
|
auto cmplx{std::visit(
|
||||||
|
[](auto &&rx, auto &&ix) -> evaluate::AnyKindComplexExpr {
|
||||||
|
using realExpr = typename std::decay<decltype(rx)>::type;
|
||||||
|
using zExpr = evaluate::Expr<typename realExpr::SameKindComplex>;
|
||||||
|
return {zExpr{typename zExpr::CMPLX{std::move(rx), std::move(ix)}}};
|
||||||
|
},
|
||||||
|
std::move(cvtd->first.u), std::move(cvtd->second.u))};
|
||||||
|
return {cmplx};
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
// Per F'2018 R718, if both components are INTEGER, they are both converted
|
// Per F'2018 R718, if both components are INTEGER, they are both converted
|
||||||
// to default REAL and the result is default COMPLEX. Otherwise, the
|
// to default REAL and the result is default COMPLEX. Otherwise, the
|
||||||
// kind of the result is the kind of largest REAL component, and the other
|
// kind of the result is the kind of largest REAL component, and the other
|
||||||
// component is converted if necessary its type.
|
// component is converted if necessary its type.
|
||||||
template<>
|
static std::optional<evaluate::AnyKindComplexExpr> AnalyzeLiteral(
|
||||||
Result AnalyzeHelper(
|
|
||||||
ExpressionAnalyzer &ea, const parser::ComplexLiteralConstant &z) {
|
ExpressionAnalyzer &ea, const parser::ComplexLiteralConstant &z) {
|
||||||
#if 0 // TODO pmk next
|
const parser::ComplexPart &re{std::get<0>(z.t)}, &im{std::get<1>(z.t)};
|
||||||
parser::ComplexPart re{std::get<0>(z.t)}, im{std::get<1>(z.t)};
|
Result reEx{AnalyzeHelper(ea, re)}, imEx{AnalyzeHelper(ea, im)};
|
||||||
#endif
|
return BuildComplex(ea, std::move(reEx), std::move(imEx));
|
||||||
return std::nullopt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
static std::optional<evaluate::AnyKindCharacterExpr> AnalyzeLiteral(
|
||||||
Result AnalyzeHelper(
|
|
||||||
ExpressionAnalyzer &ea, const parser::HollerithLiteralConstant &x) {
|
ExpressionAnalyzer &ea, const parser::HollerithLiteralConstant &x) {
|
||||||
evaluate::Expr<evaluate::DefaultCharacter> expr{x.v};
|
evaluate::Expr<evaluate::DefaultCharacter> expr{x.v};
|
||||||
return {evaluate::GenericExpr{evaluate::AnyKindCharacterExpr{expr}}};
|
return {evaluate::AnyKindCharacterExpr{expr}};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
static std::optional<evaluate::AnyKindLogicalExpr> AnalyzeLiteral(
|
||||||
Result AnalyzeHelper(
|
|
||||||
ExpressionAnalyzer &ea, const parser::LogicalLiteralConstant &x) {
|
ExpressionAnalyzer &ea, const parser::LogicalLiteralConstant &x) {
|
||||||
auto kind{ea.Analyze(std::get<std::optional<parser::KindParam>>(x.t),
|
auto kind{ea.Analyze(std::get<std::optional<parser::KindParam>>(x.t),
|
||||||
ea.defaultLogicalKind())};
|
ea.defaultLogicalKind())};
|
||||||
@ -273,8 +347,7 @@ Result AnalyzeHelper(
|
|||||||
switch (kind) {
|
switch (kind) {
|
||||||
#define CASE(k) \
|
#define CASE(k) \
|
||||||
case k: \
|
case k: \
|
||||||
return {evaluate::GenericExpr{ \
|
return {evaluate::AnyKindLogicalExpr{evaluate::LogicalExpr<k>{value}}};
|
||||||
evaluate::AnyKindLogicalExpr{evaluate::LogicalExpr<k>{value}}}};
|
|
||||||
FOR_EACH_LOGICAL_KIND(CASE, )
|
FOR_EACH_LOGICAL_KIND(CASE, )
|
||||||
#undef CASE
|
#undef CASE
|
||||||
default:
|
default:
|
||||||
@ -286,7 +359,11 @@ Result AnalyzeHelper(
|
|||||||
|
|
||||||
template<>
|
template<>
|
||||||
Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::LiteralConstant &x) {
|
Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::LiteralConstant &x) {
|
||||||
return std::visit([&](const auto &c) { return AnalyzeHelper(ea, c); }, x.u);
|
return std::visit(
|
||||||
|
[&](const auto &c) {
|
||||||
|
return WrapOptional<evaluate::GenericExpr>(AnalyzeLiteral(ea, c));
|
||||||
|
},
|
||||||
|
x.u);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Name &n) {
|
template<> Result AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Name &n) {
|
||||||
@ -473,8 +550,10 @@ Result AnalyzeHelper(
|
|||||||
template<>
|
template<>
|
||||||
Result AnalyzeHelper(
|
Result AnalyzeHelper(
|
||||||
ExpressionAnalyzer &ea, const parser::Expr::ComplexConstructor &x) {
|
ExpressionAnalyzer &ea, const parser::Expr::ComplexConstructor &x) {
|
||||||
// TODO
|
Result reEx{ea.Analyze(*std::get<0>(x.t))};
|
||||||
return std::nullopt;
|
Result imEx{ea.Analyze(*std::get<1>(x.t))};
|
||||||
|
return WrapOptional<evaluate::GenericExpr>(
|
||||||
|
BuildComplex(ea, std::move(reEx), std::move(imEx)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result ExpressionAnalyzer::Analyze(const parser::Expr &x) {
|
Result ExpressionAnalyzer::Analyze(const parser::Expr &x) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user