2018-07-14 01:55:11 +02:00
|
|
|
// 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 "expression.h"
|
2018-08-10 20:44:43 +02:00
|
|
|
#include "symbol.h"
|
2018-07-14 01:55:11 +02:00
|
|
|
#include "../common/idioms.h"
|
2018-08-08 20:29:05 +02:00
|
|
|
#include "../evaluate/common.h"
|
2018-08-10 20:44:43 +02:00
|
|
|
#include "../evaluate/tools.h"
|
2018-08-13 22:33:31 +02:00
|
|
|
#include <functional>
|
2018-07-14 01:55:11 +02:00
|
|
|
|
|
|
|
using namespace Fortran::parser::literals;
|
|
|
|
|
|
|
|
namespace Fortran::semantics {
|
|
|
|
|
2018-08-14 23:35:51 +02:00
|
|
|
using common::TypeCategory;
|
2018-08-15 00:11:53 +02:00
|
|
|
using evaluate::Expr;
|
2018-08-20 18:29:08 +02:00
|
|
|
using evaluate::SomeType;
|
2018-08-15 00:11:53 +02:00
|
|
|
using evaluate::Type;
|
2018-08-14 23:35:51 +02:00
|
|
|
|
2018-08-15 01:48:49 +02:00
|
|
|
using MaybeIntExpr = std::optional<Expr<evaluate::SomeInteger>>;
|
|
|
|
|
2018-08-07 21:34:09 +02:00
|
|
|
// AnalyzeHelper is a local template function that keeps the API
|
|
|
|
// member function ExpressionAnalyzer::Analyze from having to be a
|
|
|
|
// many-specialized template itself.
|
2018-08-13 22:33:31 +02:00
|
|
|
template<typename A> MaybeExpr AnalyzeHelper(ExpressionAnalyzer &, const A &);
|
2018-08-07 21:34:09 +02:00
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr &expr) {
|
2018-08-07 21:34:09 +02:00
|
|
|
return ea.Analyze(expr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Template wrappers are traversed with checking.
|
|
|
|
template<typename A>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(ExpressionAnalyzer &ea, const std::optional<A> &x) {
|
2018-08-07 21:34:09 +02:00
|
|
|
if (x.has_value()) {
|
|
|
|
return AnalyzeHelper(ea, *x);
|
|
|
|
} else {
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-19 18:53:42 +02:00
|
|
|
template<typename A>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(
|
|
|
|
ExpressionAnalyzer &ea, const common::Indirection<A> &p) {
|
2018-08-07 21:34:09 +02:00
|
|
|
return AnalyzeHelper(ea, *p);
|
2018-07-14 01:55:11 +02:00
|
|
|
}
|
|
|
|
|
2018-07-19 18:53:42 +02:00
|
|
|
template<typename A>
|
2018-08-15 01:48:49 +02:00
|
|
|
auto AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Scalar<A> &tree)
|
|
|
|
-> decltype(AnalyzeHelper(ea, tree.thing)) {
|
|
|
|
auto result{AnalyzeHelper(ea, tree.thing)};
|
2018-07-19 18:53:42 +02:00
|
|
|
if (result.has_value()) {
|
|
|
|
if (result->Rank() > 1) {
|
2018-07-24 21:58:29 +02:00
|
|
|
ea.context().messages.Say("must be scalar"_err_en_US);
|
2018-07-26 00:13:40 +02:00
|
|
|
return std::nullopt;
|
2018-07-19 18:53:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename A>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(
|
|
|
|
ExpressionAnalyzer &ea, const parser::Constant<A> &tree) {
|
|
|
|
MaybeExpr result{AnalyzeHelper(ea, tree.thing)};
|
2018-07-19 18:53:42 +02:00
|
|
|
if (result.has_value()) {
|
|
|
|
result->Fold(ea.context());
|
2018-07-19 22:30:17 +02:00
|
|
|
if (!result->ScalarValue().has_value()) {
|
2018-07-24 21:58:29 +02:00
|
|
|
ea.context().messages.Say("must be constant"_err_en_US);
|
2018-07-26 00:13:40 +02:00
|
|
|
return std::nullopt;
|
2018-07-19 18:53:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename A>
|
2018-08-15 01:48:49 +02:00
|
|
|
std::optional<Expr<evaluate::SomeInteger>> AnalyzeHelper(
|
2018-08-13 22:33:31 +02:00
|
|
|
ExpressionAnalyzer &ea, const parser::Integer<A> &tree) {
|
|
|
|
MaybeExpr result{AnalyzeHelper(ea, tree.thing)};
|
2018-08-15 01:48:49 +02:00
|
|
|
if (result.has_value()) {
|
|
|
|
if (auto *intexpr{std::get_if<Expr<evaluate::SomeInteger>>(&result->u)}) {
|
|
|
|
return {std::move(*intexpr)};
|
|
|
|
}
|
|
|
|
ea.context().messages.Say("expression must be integer"_err_en_US);
|
2018-07-19 18:53:42 +02:00
|
|
|
}
|
2018-08-15 01:48:49 +02:00
|
|
|
return std::nullopt;
|
2018-07-19 18:53:42 +02:00
|
|
|
}
|
|
|
|
|
2018-08-15 00:11:53 +02:00
|
|
|
static std::optional<Expr<evaluate::SomeCharacter>> AnalyzeLiteral(
|
2018-08-09 01:30:58 +02:00
|
|
|
ExpressionAnalyzer &ea, const parser::CharLiteralConstant &x) {
|
|
|
|
auto kind{ea.Analyze(std::get<std::optional<parser::KindParam>>(x.t),
|
|
|
|
ExpressionAnalyzer::KindParam{1})};
|
2018-08-22 22:36:45 +02:00
|
|
|
auto value{std::get<std::string>(x.t)};
|
|
|
|
using Ex = Expr<evaluate::SomeCharacter>;
|
|
|
|
std::optional<Ex> result{Ex::template ForceKind(kind, std::move(value))};
|
|
|
|
if (!result.has_value()) {
|
|
|
|
ea.context().messages.Say("unsupported CHARACTER(KIND=%ju)"_err_en_US,
|
2018-08-09 01:30:58 +02:00
|
|
|
static_cast<std::uintmax_t>(kind));
|
|
|
|
}
|
2018-08-22 22:36:45 +02:00
|
|
|
return result;
|
2018-08-09 01:30:58 +02:00
|
|
|
}
|
|
|
|
|
2018-08-13 22:33:31 +02:00
|
|
|
template<typename A> MaybeExpr PackageGeneric(std::optional<A> &&x) {
|
2018-08-20 18:29:08 +02:00
|
|
|
std::function<Expr<SomeType>(A &&)> f{
|
|
|
|
[](A &&y) { return Expr<SomeType>{std::move(y)}; }};
|
2018-08-13 22:33:31 +02:00
|
|
|
return common::MapOptional(f, std::move(x));
|
2018-08-10 20:44:43 +02:00
|
|
|
}
|
|
|
|
|
2018-07-19 19:12:25 +02:00
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(
|
2018-08-07 21:34:09 +02:00
|
|
|
ExpressionAnalyzer &ea, const parser::CharLiteralConstantSubstring &x) {
|
|
|
|
const auto &range{std::get<parser::SubstringRange>(x.t)};
|
2018-08-08 20:29:05 +02:00
|
|
|
const std::optional<parser::ScalarIntExpr> &lbTree{std::get<0>(range.t)};
|
|
|
|
const std::optional<parser::ScalarIntExpr> &ubTree{std::get<1>(range.t)};
|
|
|
|
if (!lbTree.has_value() && !ubTree.has_value()) {
|
2018-08-07 21:34:09 +02:00
|
|
|
// "..."(:)
|
2018-08-13 22:33:31 +02:00
|
|
|
return PackageGeneric(
|
2018-08-10 20:44:43 +02:00
|
|
|
AnalyzeLiteral(ea, std::get<parser::CharLiteralConstant>(x.t)));
|
2018-07-14 01:55:11 +02:00
|
|
|
}
|
2018-08-08 20:29:05 +02:00
|
|
|
// TODO: ensure that any kind parameter is 1
|
|
|
|
std::string str{std::get<parser::CharLiteralConstant>(x.t).GetString()};
|
2018-08-15 00:11:53 +02:00
|
|
|
std::optional<Expr<evaluate::SubscriptInteger>> lb, ub;
|
2018-08-08 20:29:05 +02:00
|
|
|
if (lbTree.has_value()) {
|
2018-08-15 01:48:49 +02:00
|
|
|
if (MaybeIntExpr lbExpr{AnalyzeHelper(ea, *lbTree)}) {
|
|
|
|
lb = Expr<evaluate::SubscriptInteger>{std::move(*lbExpr)};
|
2018-08-07 21:34:09 +02:00
|
|
|
}
|
|
|
|
}
|
2018-08-08 20:29:05 +02:00
|
|
|
if (ubTree.has_value()) {
|
2018-08-15 01:48:49 +02:00
|
|
|
if (MaybeIntExpr ubExpr{AnalyzeHelper(ea, *ubTree)}) {
|
|
|
|
ub = Expr<evaluate::SubscriptInteger>{std::move(*ubExpr)};
|
2018-08-08 20:29:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!lb.has_value() || !ub.has_value()) {
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
evaluate::Substring substring{std::move(str), std::move(lb), std::move(ub)};
|
|
|
|
evaluate::CopyableIndirection<evaluate::Substring> ind{std::move(substring)};
|
2018-08-15 00:11:53 +02:00
|
|
|
Expr<evaluate::DefaultCharacter> chExpr{std::move(ind)};
|
2018-08-08 20:29:05 +02:00
|
|
|
chExpr.Fold(ea.context());
|
2018-08-20 18:29:08 +02:00
|
|
|
return {Expr<SomeType>{Expr<evaluate::SomeCharacter>{std::move(chExpr)}}};
|
2018-07-19 18:53:42 +02:00
|
|
|
}
|
|
|
|
|
2018-08-10 20:44:43 +02:00
|
|
|
// Common handling of parser::IntLiteralConstant and SignedIntLiteralConstant
|
|
|
|
template<typename PARSED>
|
2018-08-15 00:11:53 +02:00
|
|
|
std::optional<Expr<evaluate::SomeInteger>> IntLiteralConstant(
|
2018-08-10 20:44:43 +02:00
|
|
|
ExpressionAnalyzer &ea, const PARSED &x) {
|
2018-07-19 18:53:42 +02:00
|
|
|
auto kind{ea.Analyze(std::get<std::optional<parser::KindParam>>(x.t),
|
2018-07-19 19:12:25 +02:00
|
|
|
ea.defaultIntegerKind())};
|
2018-08-22 22:36:45 +02:00
|
|
|
auto value{std::get<0>(x.t)}; // std::(u)int64_t
|
|
|
|
using Ex = Expr<evaluate::SomeInteger>;
|
|
|
|
std::optional<Ex> result{Ex::template ForceKind(kind, std::move(value))};
|
|
|
|
if (!result.has_value()) {
|
|
|
|
ea.context().messages.Say("unsupported INTEGER(KIND=%ju)"_err_en_US,
|
2018-08-08 20:29:05 +02:00
|
|
|
static_cast<std::uintmax_t>(kind));
|
2018-07-14 01:55:11 +02:00
|
|
|
}
|
2018-08-22 22:36:45 +02:00
|
|
|
return result;
|
2018-07-14 01:55:11 +02:00
|
|
|
}
|
|
|
|
|
2018-08-15 00:11:53 +02:00
|
|
|
static std::optional<Expr<evaluate::SomeInteger>> AnalyzeLiteral(
|
2018-08-10 20:44:43 +02:00
|
|
|
ExpressionAnalyzer &ea, const parser::IntLiteralConstant &x) {
|
|
|
|
return IntLiteralConstant(ea, x);
|
|
|
|
}
|
|
|
|
|
2018-08-15 00:11:53 +02:00
|
|
|
static std::optional<Expr<evaluate::SomeInteger>> AnalyzeLiteral(
|
2018-08-10 20:44:43 +02:00
|
|
|
ExpressionAnalyzer &ea, const parser::SignedIntLiteralConstant &x) {
|
|
|
|
return IntLiteralConstant(ea, x);
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::optional<evaluate::BOZLiteralConstant> AnalyzeLiteral(
|
2018-08-09 01:30:58 +02:00
|
|
|
ExpressionAnalyzer &ea, const parser::BOZLiteralConstant &x) {
|
|
|
|
const char *p{x.v.data()};
|
|
|
|
std::uint64_t base{16};
|
|
|
|
switch (*p++) {
|
|
|
|
case 'b': base = 2; break;
|
|
|
|
case 'o': base = 8; break;
|
|
|
|
case 'z': break;
|
|
|
|
case 'x': break;
|
|
|
|
default: CRASH_NO_CASE;
|
|
|
|
}
|
|
|
|
CHECK(*p == '"');
|
|
|
|
auto value{evaluate::BOZLiteralConstant::ReadUnsigned(++p, base)};
|
|
|
|
if (*p != '"') {
|
|
|
|
ea.context().messages.Say(
|
|
|
|
"invalid digit ('%c') in BOZ literal %s"_err_en_US, *p, x.v.data());
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
if (value.overflow) {
|
|
|
|
ea.context().messages.Say("BOZ literal %s too large"_err_en_US, x.v.data());
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
2018-08-10 20:44:43 +02:00
|
|
|
return {value.value};
|
2018-08-09 01:30:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template<int KIND>
|
2018-08-15 00:11:53 +02:00
|
|
|
std::optional<Expr<evaluate::SomeReal>> ReadRealLiteral(
|
2018-08-09 01:30:58 +02:00
|
|
|
parser::CharBlock source, evaluate::FoldingContext &context) {
|
|
|
|
const char *p{source.begin()};
|
2018-08-15 00:11:53 +02:00
|
|
|
using RealType = Type<TypeCategory::Real, KIND>;
|
2018-08-14 22:39:59 +02:00
|
|
|
auto valWithFlags{evaluate::Scalar<RealType>::Read(p, context.rounding)};
|
2018-08-09 01:30:58 +02:00
|
|
|
CHECK(p == source.end());
|
|
|
|
evaluate::RealFlagWarnings(
|
|
|
|
context, valWithFlags.flags, "conversion of REAL literal");
|
|
|
|
auto value{valWithFlags.value};
|
|
|
|
if (context.flushDenormalsToZero) {
|
|
|
|
value = value.FlushDenormalToZero();
|
|
|
|
}
|
2018-08-15 00:11:53 +02:00
|
|
|
return {evaluate::ToSomeKindExpr(Expr<RealType>{value})};
|
2018-08-09 01:30:58 +02:00
|
|
|
}
|
|
|
|
|
2018-08-22 22:36:45 +02:00
|
|
|
struct RealHelper {
|
|
|
|
RealHelper(parser::CharBlock lit, evaluate::FoldingContext &ctx)
|
|
|
|
: literal{lit}, context{ctx} {}
|
|
|
|
template<int K> void action() {
|
|
|
|
CHECK(!result.has_value());
|
|
|
|
result = ReadRealLiteral<K>(literal, context);
|
|
|
|
}
|
|
|
|
parser::CharBlock literal;
|
|
|
|
evaluate::FoldingContext &context;
|
|
|
|
std::optional<Expr<evaluate::SomeReal>> result;
|
|
|
|
};
|
|
|
|
|
2018-08-15 00:11:53 +02:00
|
|
|
static std::optional<Expr<evaluate::SomeReal>> AnalyzeLiteral(
|
2018-08-09 01:30:58 +02:00
|
|
|
ExpressionAnalyzer &ea, const parser::RealLiteralConstant &x) {
|
|
|
|
// Use a local message context around the real literal.
|
|
|
|
parser::ContextualMessages ctxMsgs{x.real.source, ea.context().messages};
|
2018-08-22 22:36:45 +02:00
|
|
|
evaluate::FoldingContext localFoldingContext{ctxMsgs, ea.context()};
|
2018-08-09 01:30:58 +02:00
|
|
|
// If a kind parameter appears, it takes precedence. In the absence of
|
|
|
|
// an explicit kind parameter, the exponent letter (e.g., 'e'/'d')
|
|
|
|
// determines the kind.
|
|
|
|
typename ExpressionAnalyzer::KindParam defaultKind{ea.defaultRealKind()};
|
|
|
|
const char *end{x.real.source.end()};
|
|
|
|
for (const char *p{x.real.source.begin()}; p < end; ++p) {
|
|
|
|
if (parser::IsLetter(*p)) {
|
|
|
|
switch (*p) {
|
|
|
|
case 'e': defaultKind = 4; break;
|
|
|
|
case 'd': defaultKind = 8; break;
|
|
|
|
case 'q': defaultKind = 16; break;
|
|
|
|
default: ctxMsgs.Say("unknown exponent letter '%c'"_err_en_US, *p);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
auto kind{ea.Analyze(x.kind, defaultKind)};
|
2018-08-22 22:36:45 +02:00
|
|
|
RealHelper helper{x.real.source, localFoldingContext};
|
|
|
|
Expr<evaluate::SomeReal>::template AtKind(helper, kind);
|
|
|
|
if (!helper.result.has_value()) {
|
|
|
|
ctxMsgs.Say("unsupported REAL(KIND=%ju)"_err_en_US,
|
2018-08-09 01:30:58 +02:00
|
|
|
static_cast<std::uintmax_t>(kind));
|
|
|
|
}
|
2018-08-22 22:36:45 +02:00
|
|
|
return helper.result;
|
2018-08-09 01:30:58 +02:00
|
|
|
}
|
|
|
|
|
2018-08-15 00:11:53 +02:00
|
|
|
static std::optional<Expr<evaluate::SomeReal>> AnalyzeLiteral(
|
2018-08-10 20:44:43 +02:00
|
|
|
ExpressionAnalyzer &ea, const parser::SignedRealLiteralConstant &x) {
|
2018-08-16 20:46:18 +02:00
|
|
|
if (auto result{
|
|
|
|
AnalyzeLiteral(ea, std::get<parser::RealLiteralConstant>(x.t))}) {
|
2018-08-10 20:44:43 +02:00
|
|
|
if (auto sign{std::get<std::optional<parser::Sign>>(x.t)}) {
|
|
|
|
if (sign == parser::Sign::Negative) {
|
2018-08-20 18:29:08 +02:00
|
|
|
return {-std::move(*result)};
|
2018-08-10 20:44:43 +02:00
|
|
|
}
|
|
|
|
}
|
2018-08-16 20:46:18 +02:00
|
|
|
return result;
|
2018-08-10 20:44:43 +02:00
|
|
|
}
|
2018-08-16 20:46:18 +02:00
|
|
|
return std::nullopt;
|
2018-08-10 20:44:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Name &n) {
|
|
|
|
CHECK(n.symbol != nullptr);
|
|
|
|
auto *details{n.symbol->detailsIf<ObjectEntityDetails>()};
|
|
|
|
if (details == nullptr || !n.symbol->attrs().test(Attr::PARAMETER)) {
|
2018-08-10 20:44:43 +02:00
|
|
|
ea.context().messages.Say(
|
2018-08-13 22:33:31 +02:00
|
|
|
"name (%s) is not a defined constant"_err_en_US, n.ToString().data());
|
2018-08-10 20:44:43 +02:00
|
|
|
return std::nullopt;
|
|
|
|
}
|
2018-08-13 22:33:31 +02:00
|
|
|
// TODO: enumerators, do they have the PARAMETER attribute?
|
2018-08-10 20:44:43 +02:00
|
|
|
return std::nullopt; // TODO parameters and enumerators
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(
|
|
|
|
ExpressionAnalyzer &ea, const parser::NamedConstant &n) {
|
|
|
|
return AnalyzeHelper(ea, n.v);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
|
|
|
MaybeExpr AnalyzeHelper(ExpressionAnalyzer &ea, const parser::ComplexPart &x) {
|
2018-08-10 20:44:43 +02:00
|
|
|
return std::visit(common::visitors{[&](const parser::NamedConstant &n) {
|
|
|
|
return AnalyzeHelper(ea, n);
|
|
|
|
},
|
|
|
|
[&](const auto &literal) {
|
2018-08-13 22:33:31 +02:00
|
|
|
return PackageGeneric(AnalyzeLiteral(ea, literal));
|
2018-08-10 20:44:43 +02:00
|
|
|
}},
|
|
|
|
x.u);
|
|
|
|
}
|
|
|
|
|
2018-08-09 01:30:58 +02:00
|
|
|
// Per F'2018 R718, if both components are INTEGER, they are both converted
|
|
|
|
// 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
|
|
|
|
// component is converted if necessary its type.
|
2018-08-15 00:11:53 +02:00
|
|
|
static std::optional<Expr<evaluate::SomeComplex>> AnalyzeLiteral(
|
2018-08-09 01:30:58 +02:00
|
|
|
ExpressionAnalyzer &ea, const parser::ComplexLiteralConstant &z) {
|
2018-08-10 20:44:43 +02:00
|
|
|
const parser::ComplexPart &re{std::get<0>(z.t)}, &im{std::get<1>(z.t)};
|
2018-08-13 22:33:31 +02:00
|
|
|
return ea.ConstructComplex(AnalyzeHelper(ea, re), AnalyzeHelper(ea, im));
|
2018-08-09 01:30:58 +02:00
|
|
|
}
|
|
|
|
|
2018-08-15 00:11:53 +02:00
|
|
|
static std::optional<Expr<evaluate::SomeCharacter>> AnalyzeLiteral(
|
2018-08-09 01:30:58 +02:00
|
|
|
ExpressionAnalyzer &ea, const parser::HollerithLiteralConstant &x) {
|
2018-08-15 00:11:53 +02:00
|
|
|
Expr<evaluate::DefaultCharacter> expr{x.v};
|
|
|
|
return {Expr<evaluate::SomeCharacter>{expr}};
|
2018-08-09 01:30:58 +02:00
|
|
|
}
|
|
|
|
|
2018-08-15 00:11:53 +02:00
|
|
|
static std::optional<Expr<evaluate::SomeLogical>> AnalyzeLiteral(
|
2018-08-09 01:30:58 +02:00
|
|
|
ExpressionAnalyzer &ea, const parser::LogicalLiteralConstant &x) {
|
|
|
|
auto kind{ea.Analyze(std::get<std::optional<parser::KindParam>>(x.t),
|
|
|
|
ea.defaultLogicalKind())};
|
|
|
|
bool value{std::get<bool>(x.t)};
|
2018-08-22 22:36:45 +02:00
|
|
|
using Ex = Expr<evaluate::SomeLogical>;
|
|
|
|
std::optional<Ex> result{Ex::template ForceKind(kind, std::move(value))};
|
|
|
|
if (!result.has_value()) {
|
|
|
|
ea.context().messages.Say("unsupported LOGICAL(KIND=%ju)"_err_en_US,
|
2018-08-09 01:30:58 +02:00
|
|
|
static_cast<std::uintmax_t>(kind));
|
|
|
|
}
|
2018-08-22 22:36:45 +02:00
|
|
|
return result;
|
2018-08-09 01:30:58 +02:00
|
|
|
}
|
|
|
|
|
2018-07-19 19:12:25 +02:00
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(
|
|
|
|
ExpressionAnalyzer &ea, const parser::LiteralConstant &x) {
|
2018-08-10 20:44:43 +02:00
|
|
|
return std::visit(
|
2018-08-13 22:33:31 +02:00
|
|
|
[&](const auto &c) { return PackageGeneric(AnalyzeLiteral(ea, c)); },
|
2018-08-10 20:44:43 +02:00
|
|
|
x.u);
|
2018-07-19 18:53:42 +02:00
|
|
|
}
|
|
|
|
|
2018-08-07 21:34:09 +02:00
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(
|
2018-08-07 21:34:09 +02:00
|
|
|
ExpressionAnalyzer &ea, const parser::ArrayConstructor &x) {
|
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(
|
2018-08-07 21:34:09 +02:00
|
|
|
ExpressionAnalyzer &ea, const parser::StructureConstructor &x) {
|
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(
|
2018-08-07 21:34:09 +02:00
|
|
|
ExpressionAnalyzer &ea, const parser::TypeParamInquiry &x) {
|
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(
|
2018-08-07 21:34:09 +02:00
|
|
|
ExpressionAnalyzer &ea, const parser::FunctionReference &x) {
|
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(
|
2018-08-07 21:34:09 +02:00
|
|
|
ExpressionAnalyzer &ea, const parser::Expr::Parentheses &x) {
|
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(
|
|
|
|
ExpressionAnalyzer &ea, const parser::Expr::UnaryPlus &x) {
|
2018-08-07 21:34:09 +02:00
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::Negate &x) {
|
2018-08-07 21:34:09 +02:00
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::NOT &x) {
|
2018-08-07 21:34:09 +02:00
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(
|
2018-08-07 21:34:09 +02:00
|
|
|
ExpressionAnalyzer &ea, const parser::Expr::PercentLoc &x) {
|
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(
|
2018-08-07 21:34:09 +02:00
|
|
|
ExpressionAnalyzer &ea, const parser::Expr::DefinedUnary &x) {
|
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::Power &x) {
|
2018-08-07 21:34:09 +02:00
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(
|
|
|
|
ExpressionAnalyzer &ea, const parser::Expr::Multiply &x) {
|
2018-08-07 21:34:09 +02:00
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::Divide &x) {
|
2018-08-07 21:34:09 +02:00
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::Add &x) {
|
2018-08-07 21:34:09 +02:00
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(
|
|
|
|
ExpressionAnalyzer &ea, const parser::Expr::Subtract &x) {
|
2018-08-07 21:34:09 +02:00
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::Concat &x) {
|
2018-08-07 21:34:09 +02:00
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::LT &x) {
|
2018-08-07 21:34:09 +02:00
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::LE &x) {
|
2018-08-07 21:34:09 +02:00
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::EQ &x) {
|
2018-08-07 21:34:09 +02:00
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::NE &x) {
|
2018-08-07 21:34:09 +02:00
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::GE &x) {
|
2018-08-07 21:34:09 +02:00
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::GT &x) {
|
2018-08-07 21:34:09 +02:00
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::AND &x) {
|
2018-08-07 21:34:09 +02:00
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::OR &x) {
|
2018-08-07 21:34:09 +02:00
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::EQV &x) {
|
2018-08-07 21:34:09 +02:00
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::NEQV &x) {
|
2018-08-07 21:34:09 +02:00
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(ExpressionAnalyzer &ea, const parser::Expr::XOR &x) {
|
2018-08-07 21:34:09 +02:00
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(
|
2018-08-07 21:34:09 +02:00
|
|
|
ExpressionAnalyzer &ea, const parser::Expr::DefinedBinary &x) {
|
|
|
|
// TODO
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr AnalyzeHelper(
|
2018-08-07 21:34:09 +02:00
|
|
|
ExpressionAnalyzer &ea, const parser::Expr::ComplexConstructor &x) {
|
2018-08-13 22:33:31 +02:00
|
|
|
return PackageGeneric(ea.ConstructComplex(
|
|
|
|
ea.Analyze(*std::get<0>(x.t)), ea.Analyze(*std::get<1>(x.t))));
|
2018-08-07 21:34:09 +02:00
|
|
|
}
|
|
|
|
|
2018-08-13 22:33:31 +02:00
|
|
|
MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr &x) {
|
2018-08-07 21:34:09 +02:00
|
|
|
return std::visit(common::visitors{[&](const parser::LiteralConstant &c) {
|
|
|
|
return AnalyzeHelper(*this, c);
|
|
|
|
},
|
|
|
|
// TODO: remaining cases
|
2018-08-13 22:33:31 +02:00
|
|
|
[&](const auto &) { return MaybeExpr{}; }},
|
2018-07-14 01:55:11 +02:00
|
|
|
x.u);
|
|
|
|
}
|
2018-08-07 21:34:09 +02:00
|
|
|
|
|
|
|
ExpressionAnalyzer::KindParam ExpressionAnalyzer::Analyze(
|
|
|
|
const std::optional<parser::KindParam> &kindParam, KindParam defaultKind,
|
|
|
|
KindParam kanjiKind) {
|
|
|
|
if (!kindParam.has_value()) {
|
|
|
|
return defaultKind;
|
|
|
|
}
|
|
|
|
return std::visit(
|
|
|
|
common::visitors{
|
|
|
|
[](std::uint64_t k) { return static_cast<KindParam>(k); },
|
|
|
|
[&](const parser::Scalar<
|
|
|
|
parser::Integer<parser::Constant<parser::Name>>> &n) {
|
2018-08-15 01:48:49 +02:00
|
|
|
if (MaybeIntExpr ie{AnalyzeHelper(*this, n)}) {
|
|
|
|
return *ie->ScalarValue()->ToInt64();
|
2018-08-07 21:34:09 +02:00
|
|
|
}
|
2018-08-15 01:48:49 +02:00
|
|
|
context_.messages.Say(
|
|
|
|
"KIND type parameter must be a scalar integer constant"_err_en_US);
|
2018-08-07 21:34:09 +02:00
|
|
|
return defaultKind;
|
|
|
|
},
|
|
|
|
[&](parser::KindParam::Kanji) {
|
|
|
|
if (kanjiKind >= 0) {
|
|
|
|
return kanjiKind;
|
|
|
|
}
|
2018-08-13 22:33:31 +02:00
|
|
|
context_.messages.Say("Kanji not allowed here"_err_en_US);
|
2018-08-07 21:34:09 +02:00
|
|
|
return defaultKind;
|
|
|
|
}},
|
|
|
|
kindParam->u);
|
|
|
|
}
|
|
|
|
|
2018-08-15 00:11:53 +02:00
|
|
|
std::optional<Expr<evaluate::SomeComplex>> ExpressionAnalyzer::ConstructComplex(
|
|
|
|
MaybeExpr &&real, MaybeExpr &&imaginary) {
|
2018-08-13 22:33:31 +02:00
|
|
|
// TODO: pmk abstract further, this will be a common pattern
|
2018-08-20 18:29:08 +02:00
|
|
|
auto partial{[&](Expr<SomeType> &&x, Expr<SomeType> &&y) {
|
2018-08-13 22:33:31 +02:00
|
|
|
return evaluate::ConvertRealOperands(
|
|
|
|
context_.messages, std::move(x), std::move(y));
|
|
|
|
}};
|
2018-08-14 22:39:59 +02:00
|
|
|
using fType =
|
2018-08-20 18:29:08 +02:00
|
|
|
evaluate::ConvertRealOperandsResult(Expr<SomeType> &&, Expr<SomeType> &&);
|
2018-08-13 22:33:31 +02:00
|
|
|
std::function<fType> f{partial};
|
|
|
|
auto converted{common::MapOptional(f, std::move(real), std::move(imaginary))};
|
|
|
|
if (auto joined{common::JoinOptionals(std::move(converted))}) {
|
|
|
|
return {std::visit(
|
2018-08-15 00:11:53 +02:00
|
|
|
[](auto &&rx, auto &&ix) -> Expr<evaluate::SomeComplex> {
|
2018-08-14 22:39:59 +02:00
|
|
|
using realType = evaluate::ResultType<decltype(rx)>;
|
2018-08-18 00:38:37 +02:00
|
|
|
constexpr int kind{realType::kind};
|
|
|
|
using zType = evaluate::Type<TypeCategory::Complex, kind>;
|
|
|
|
return {Expr<zType>{evaluate::ComplexConstructor<kind>{
|
|
|
|
std::move(rx), std::move(ix)}}};
|
2018-08-13 22:33:31 +02:00
|
|
|
},
|
2018-08-22 22:36:45 +02:00
|
|
|
std::move(joined->first.u.u), std::move(joined->second.u.u))};
|
2018-08-13 22:33:31 +02:00
|
|
|
}
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
2018-07-14 01:55:11 +02:00
|
|
|
} // namespace Fortran::semantics
|