2019-01-28 23:38:17 +01:00
|
|
|
// Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
|
2018-06-20 20:55:10 +02:00
|
|
|
//
|
|
|
|
// 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-09 01:30:58 +02:00
|
|
|
#include "common.h"
|
2018-07-25 22:46:13 +02:00
|
|
|
#include "int-power.h"
|
2018-08-20 18:29:08 +02:00
|
|
|
#include "tools.h"
|
2018-07-07 00:12:33 +02:00
|
|
|
#include "variable.h"
|
2018-06-20 20:55:10 +02:00
|
|
|
#include "../common/idioms.h"
|
2018-07-24 21:58:29 +02:00
|
|
|
#include "../parser/message.h"
|
2018-06-20 20:55:10 +02:00
|
|
|
#include <ostream>
|
2019-01-23 01:30:32 +01:00
|
|
|
#include <sstream>
|
2018-06-20 20:55:10 +02:00
|
|
|
#include <string>
|
2018-06-21 01:50:27 +02:00
|
|
|
#include <type_traits>
|
2018-06-20 20:55:10 +02:00
|
|
|
|
2018-06-22 23:51:15 +02:00
|
|
|
using namespace Fortran::parser::literals;
|
|
|
|
|
2018-06-20 20:55:10 +02:00
|
|
|
namespace Fortran::evaluate {
|
|
|
|
|
2018-11-06 00:02:37 +01:00
|
|
|
// AsFortran() formatting
|
2018-08-18 00:38:37 +02:00
|
|
|
|
|
|
|
template<typename D, typename R, typename... O>
|
2018-11-06 00:02:37 +01:00
|
|
|
std::ostream &Operation<D, R, O...>::AsFortran(std::ostream &o) const {
|
|
|
|
left().AsFortran(derived().Prefix(o));
|
2018-09-07 19:33:32 +02:00
|
|
|
if constexpr (operands > 1) {
|
2018-11-06 00:02:37 +01:00
|
|
|
right().AsFortran(derived().Infix(o));
|
2018-08-18 00:38:37 +02:00
|
|
|
}
|
2018-09-07 19:33:32 +02:00
|
|
|
return derived().Suffix(o);
|
2018-08-18 00:38:37 +02:00
|
|
|
}
|
|
|
|
|
2018-09-07 19:33:32 +02:00
|
|
|
template<typename TO, TypeCategory FROMCAT>
|
2018-11-06 00:02:37 +01:00
|
|
|
std::ostream &Convert<TO, FROMCAT>::AsFortran(std::ostream &o) const {
|
2018-09-07 19:33:32 +02:00
|
|
|
static_assert(TO::category == TypeCategory::Integer ||
|
|
|
|
TO::category == TypeCategory::Real ||
|
2019-02-20 00:38:55 +01:00
|
|
|
TO::category == TypeCategory::Character ||
|
2018-09-07 19:33:32 +02:00
|
|
|
TO::category == TypeCategory::Logical || !"Convert<> to bad category!");
|
2019-02-20 00:38:55 +01:00
|
|
|
if constexpr (TO::category == TypeCategory::Character) {
|
|
|
|
this->left().AsFortran(o << "achar(iachar(") << ')';
|
|
|
|
} else if constexpr (TO::category == TypeCategory::Integer) {
|
|
|
|
this->left().AsFortran(o << "int(");
|
2018-09-07 19:33:32 +02:00
|
|
|
} else if constexpr (TO::category == TypeCategory::Real) {
|
2019-02-20 00:38:55 +01:00
|
|
|
this->left().AsFortran(o << "real(");
|
|
|
|
} else {
|
|
|
|
this->left().AsFortran(o << "logical(");
|
2018-09-07 19:33:32 +02:00
|
|
|
}
|
2019-02-20 00:38:55 +01:00
|
|
|
return o << ",kind=" << TO::kind << ')';
|
2018-09-07 19:33:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename A> std::ostream &Relational<A>::Infix(std::ostream &o) const {
|
2018-11-14 23:35:10 +01:00
|
|
|
switch (opr) {
|
|
|
|
case RelationalOperator::LT: o << '<'; break;
|
|
|
|
case RelationalOperator::LE: o << "<="; break;
|
|
|
|
case RelationalOperator::EQ: o << "=="; break;
|
|
|
|
case RelationalOperator::NE: o << "/="; break;
|
|
|
|
case RelationalOperator::GE: o << ">="; break;
|
|
|
|
case RelationalOperator::GT: o << '>'; break;
|
|
|
|
}
|
|
|
|
return o;
|
2018-08-18 00:38:37 +02:00
|
|
|
}
|
|
|
|
|
2018-11-06 00:02:37 +01:00
|
|
|
std::ostream &Relational<SomeType>::AsFortran(std::ostream &o) const {
|
|
|
|
std::visit([&](const auto &rel) { rel.AsFortran(o); }, u);
|
2018-08-29 00:15:18 +02:00
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
2018-09-07 19:33:32 +02:00
|
|
|
template<int KIND>
|
|
|
|
std::ostream &LogicalOperation<KIND>::Infix(std::ostream &o) const {
|
2018-08-18 00:38:37 +02:00
|
|
|
switch (logicalOperator) {
|
2018-11-14 23:35:10 +01:00
|
|
|
case LogicalOperator::And: o << ".and."; break;
|
|
|
|
case LogicalOperator::Or: o << ".or."; break;
|
|
|
|
case LogicalOperator::Eqv: o << ".eqv."; break;
|
|
|
|
case LogicalOperator::Neqv: o << ".neqv."; break;
|
2018-08-18 00:38:37 +02:00
|
|
|
}
|
2018-09-07 19:33:32 +02:00
|
|
|
return o;
|
2018-08-18 00:38:37 +02:00
|
|
|
}
|
|
|
|
|
2018-10-30 23:24:35 +01:00
|
|
|
template<typename T>
|
2019-03-20 19:38:45 +01:00
|
|
|
std::ostream &Emit(
|
|
|
|
std::ostream &o, const common::CopyableIndirection<Expr<T>> &expr) {
|
2019-03-05 21:28:08 +01:00
|
|
|
return expr.value().AsFortran(o);
|
2018-10-30 23:24:35 +01:00
|
|
|
}
|
2019-01-23 01:30:32 +01:00
|
|
|
|
2018-10-30 23:24:35 +01:00
|
|
|
template<typename T>
|
|
|
|
std::ostream &Emit(std::ostream &, const ArrayConstructorValues<T> &);
|
|
|
|
|
2019-01-23 01:30:32 +01:00
|
|
|
template<typename T>
|
|
|
|
std::ostream &Emit(std::ostream &o, const ImpliedDo<T> &implDo) {
|
2018-10-30 23:24:35 +01:00
|
|
|
o << '(';
|
2019-03-05 21:28:08 +01:00
|
|
|
Emit(o, implDo.values());
|
2019-01-31 18:58:40 +01:00
|
|
|
o << ',' << ImpliedDoIndex::Result::AsFortran()
|
2019-03-05 21:28:08 +01:00
|
|
|
<< "::" << implDo.name().ToString() << '=';
|
|
|
|
implDo.lower().AsFortran(o) << ',';
|
|
|
|
implDo.upper().AsFortran(o) << ',';
|
|
|
|
implDo.stride().AsFortran(o) << ')';
|
2018-10-30 23:24:35 +01:00
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
std::ostream &Emit(std::ostream &o, const ArrayConstructorValues<T> &values) {
|
|
|
|
const char *sep{""};
|
2019-02-09 01:35:02 +01:00
|
|
|
for (const auto &value : values.values()) {
|
2018-10-30 23:24:35 +01:00
|
|
|
o << sep;
|
|
|
|
std::visit([&](const auto &x) { Emit(o, x); }, value.u);
|
|
|
|
sep = ",";
|
|
|
|
}
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
2018-11-06 00:02:37 +01:00
|
|
|
std::ostream &ArrayConstructor<T>::AsFortran(std::ostream &o) const {
|
2019-01-23 01:30:32 +01:00
|
|
|
o << '[' << GetType().AsFortran() << "::";
|
2019-02-09 01:35:02 +01:00
|
|
|
Emit(o, *this);
|
2019-01-23 01:30:32 +01:00
|
|
|
return o << ']';
|
|
|
|
}
|
|
|
|
|
|
|
|
template<int KIND>
|
|
|
|
std::ostream &ArrayConstructor<Type<TypeCategory::Character, KIND>>::AsFortran(
|
|
|
|
std::ostream &o) const {
|
|
|
|
std::stringstream len;
|
2019-02-09 01:35:02 +01:00
|
|
|
LEN().AsFortran(len);
|
2019-01-23 01:30:32 +01:00
|
|
|
o << '[' << GetType().AsFortran(len.str()) << "::";
|
2019-02-09 01:35:02 +01:00
|
|
|
Emit(o, *this);
|
2018-10-30 23:24:35 +01:00
|
|
|
return o << ']';
|
|
|
|
}
|
|
|
|
|
2019-02-08 19:39:10 +01:00
|
|
|
std::ostream &ArrayConstructor<SomeDerived>::AsFortran(std::ostream &o) const {
|
|
|
|
o << '[' << GetType().AsFortran() << "::";
|
2019-02-09 01:35:02 +01:00
|
|
|
Emit(o, *this);
|
2019-02-08 19:39:10 +01:00
|
|
|
return o << ']';
|
|
|
|
}
|
|
|
|
|
2018-08-29 00:15:18 +02:00
|
|
|
template<typename RESULT>
|
2018-11-06 00:02:37 +01:00
|
|
|
std::ostream &ExpressionBase<RESULT>::AsFortran(std::ostream &o) const {
|
|
|
|
std::visit(
|
2018-11-29 18:27:34 +01:00
|
|
|
common::visitors{
|
|
|
|
[&](const BOZLiteralConstant &x) {
|
|
|
|
o << "z'" << x.Hexadecimal() << "'";
|
|
|
|
},
|
2019-02-20 02:06:28 +01:00
|
|
|
[&](const NullPointer &) { o << "NULL()"; },
|
2019-03-20 19:38:45 +01:00
|
|
|
[&](const common::CopyableIndirection<Substring> &s) {
|
2019-03-05 21:28:08 +01:00
|
|
|
s.value().AsFortran(o);
|
|
|
|
},
|
2019-01-23 01:30:32 +01:00
|
|
|
[&](const ImpliedDoIndex &i) { o << i.name.ToString(); },
|
2018-11-29 18:27:34 +01:00
|
|
|
[&](const auto &x) { x.AsFortran(o); },
|
|
|
|
},
|
2018-08-29 00:15:18 +02:00
|
|
|
derived().u);
|
2018-08-18 00:38:37 +02:00
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<int KIND>
|
|
|
|
Expr<SubscriptInteger> Expr<Type<TypeCategory::Character, KIND>>::LEN() const {
|
2018-07-19 19:12:25 +02:00
|
|
|
return std::visit(
|
2018-11-29 18:27:34 +01:00
|
|
|
common::visitors{
|
|
|
|
[](const Constant<Result> &c) {
|
2019-02-07 21:05:27 +01:00
|
|
|
return AsExpr(Constant<SubscriptInteger>{c.LEN()});
|
2018-11-29 18:27:34 +01:00
|
|
|
},
|
2018-10-31 00:25:10 +01:00
|
|
|
[](const ArrayConstructor<Result> &a) { return a.LEN(); },
|
2018-09-17 20:31:38 +02:00
|
|
|
[](const Parentheses<Result> &x) { return x.left().LEN(); },
|
2019-02-20 00:38:55 +01:00
|
|
|
[](const Convert<Result> &x) {
|
|
|
|
return std::visit(
|
|
|
|
[&](const auto &kx) { return kx.LEN(); }, x.left().u);
|
|
|
|
},
|
2018-08-18 00:38:37 +02:00
|
|
|
[](const Concat<KIND> &c) {
|
2018-09-17 20:31:38 +02:00
|
|
|
return c.left().LEN() + c.right().LEN();
|
2018-08-09 01:30:58 +02:00
|
|
|
},
|
2018-08-18 00:38:37 +02:00
|
|
|
[](const Extremum<Result> &c) {
|
2018-09-07 19:33:32 +02:00
|
|
|
return Expr<SubscriptInteger>{
|
|
|
|
Extremum<SubscriptInteger>{c.left().LEN(), c.right().LEN()}};
|
2018-08-18 00:38:37 +02:00
|
|
|
},
|
2018-09-15 00:48:40 +02:00
|
|
|
[](const Designator<Result> &dr) { return dr.LEN(); },
|
2018-11-29 18:27:34 +01:00
|
|
|
[](const FunctionRef<Result> &fr) { return fr.LEN(); },
|
2019-02-28 00:51:03 +01:00
|
|
|
[](const SetLength<KIND> &x) { return x.right(); },
|
2018-11-29 18:27:34 +01:00
|
|
|
},
|
2018-07-20 21:19:09 +02:00
|
|
|
u);
|
2018-07-19 18:53:42 +02:00
|
|
|
}
|
|
|
|
|
2019-03-20 19:38:45 +01:00
|
|
|
Expr<SomeType>::~Expr() = default;
|
2018-09-07 19:33:32 +02:00
|
|
|
|
2019-01-03 17:45:27 +01:00
|
|
|
#if defined(__APPLE__) && defined(__GNUC__)
|
2018-12-20 18:39:29 +01:00
|
|
|
template<typename A>
|
|
|
|
typename ExpressionBase<A>::Derived &ExpressionBase<A>::derived() {
|
|
|
|
return *static_cast<Derived *>(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename A>
|
|
|
|
const typename ExpressionBase<A>::Derived &ExpressionBase<A>::derived() const {
|
|
|
|
return *static_cast<const Derived *>(this);
|
|
|
|
}
|
2019-01-03 17:45:27 +01:00
|
|
|
#endif
|
2018-12-20 18:39:29 +01:00
|
|
|
|
2018-10-09 00:35:19 +02:00
|
|
|
template<typename A>
|
|
|
|
std::optional<DynamicType> ExpressionBase<A>::GetType() const {
|
2019-01-04 23:05:53 +01:00
|
|
|
if constexpr (IsLengthlessIntrinsicType<Result>) {
|
2018-10-09 21:07:29 +02:00
|
|
|
return Result::GetType();
|
2018-10-09 00:35:19 +02:00
|
|
|
} else {
|
|
|
|
return std::visit(
|
|
|
|
[](const auto &x) -> std::optional<DynamicType> {
|
2019-02-20 02:06:28 +01:00
|
|
|
using Ty = std::decay_t<decltype(x)>;
|
2019-03-05 02:02:48 +01:00
|
|
|
if constexpr (!std::is_same_v<Ty, BOZLiteralConstant> &&
|
|
|
|
!std::is_same_v<Ty, NullPointer>) {
|
2018-10-09 00:35:19 +02:00
|
|
|
return x.GetType();
|
|
|
|
}
|
2019-03-05 02:02:48 +01:00
|
|
|
return std::nullopt; // typeless really means "no type"
|
2018-10-09 00:35:19 +02:00
|
|
|
},
|
|
|
|
derived().u);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-18 18:34:59 +02:00
|
|
|
template<typename A> int ExpressionBase<A>::Rank() const {
|
|
|
|
return std::visit(
|
2018-10-01 23:36:31 +02:00
|
|
|
[](const auto &x) {
|
|
|
|
if constexpr (std::is_same_v<std::decay_t<decltype(x)>,
|
|
|
|
BOZLiteralConstant>) {
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
return x.Rank();
|
|
|
|
}
|
|
|
|
},
|
2018-09-18 18:34:59 +02:00
|
|
|
derived().u);
|
|
|
|
}
|
|
|
|
|
2019-01-04 23:05:53 +01:00
|
|
|
// Equality testing for classes without EVALUATE_UNION_CLASS_BOILERPLATE()
|
|
|
|
|
2019-01-23 01:30:32 +01:00
|
|
|
bool ImpliedDoIndex::operator==(const ImpliedDoIndex &that) const {
|
|
|
|
return name == that.name;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
bool ImpliedDo<T>::operator==(const ImpliedDo<T> &that) const {
|
2019-03-05 21:28:08 +01:00
|
|
|
return name_ == that.name_ && lower_ == that.lower_ &&
|
|
|
|
upper_ == that.upper_ && stride_ == that.stride_ &&
|
|
|
|
values_ == that.values_;
|
2019-01-04 23:05:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename R>
|
|
|
|
bool ArrayConstructorValues<R>::operator==(
|
|
|
|
const ArrayConstructorValues<R> &that) const {
|
2019-02-09 01:35:02 +01:00
|
|
|
return values_ == that.values_;
|
2019-01-23 01:30:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
template<int KIND>
|
|
|
|
bool ArrayConstructor<Type<TypeCategory::Character, KIND>>::operator==(
|
2019-02-09 01:35:02 +01:00
|
|
|
const ArrayConstructor &that) const {
|
|
|
|
return length_ == that.length_ &&
|
|
|
|
static_cast<const Base &>(*this) == static_cast<const Base &>(that);
|
2019-01-04 23:05:53 +01:00
|
|
|
}
|
|
|
|
|
2019-02-08 19:39:10 +01:00
|
|
|
bool ArrayConstructor<SomeDerived>::operator==(
|
2019-02-09 01:35:02 +01:00
|
|
|
const ArrayConstructor &that) const {
|
|
|
|
return derivedTypeSpec_ == that.derivedTypeSpec_ &&
|
|
|
|
static_cast<const Base &>(*this) == static_cast<const Base &>(that);
|
|
|
|
;
|
2019-02-08 19:39:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
StructureConstructor::StructureConstructor(
|
|
|
|
const semantics::DerivedTypeSpec &spec,
|
|
|
|
const StructureConstructorValues &values)
|
|
|
|
: derivedTypeSpec_{&spec}, values_{values} {}
|
|
|
|
StructureConstructor::StructureConstructor(
|
|
|
|
const semantics::DerivedTypeSpec &spec, StructureConstructorValues &&values)
|
|
|
|
: derivedTypeSpec_{&spec}, values_{std::move(values)} {}
|
|
|
|
|
|
|
|
bool StructureConstructor::operator==(const StructureConstructor &that) const {
|
|
|
|
return derivedTypeSpec_ == that.derivedTypeSpec_ && values_ == that.values_;
|
|
|
|
}
|
|
|
|
|
|
|
|
DynamicType StructureConstructor::GetType() const {
|
2019-02-27 00:59:25 +01:00
|
|
|
return DynamicType{*derivedTypeSpec_};
|
2019-02-08 19:39:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
StructureConstructor &StructureConstructor::Add(
|
|
|
|
const Symbol &symbol, Expr<SomeType> &&expr) {
|
|
|
|
values_.emplace(&symbol, std::move(expr));
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::ostream &StructureConstructor::AsFortran(std::ostream &o) const {
|
|
|
|
DerivedTypeSpecAsFortran(o, *derivedTypeSpec_);
|
|
|
|
if (values_.empty()) {
|
|
|
|
o << '(';
|
|
|
|
} else {
|
|
|
|
char ch{'('};
|
|
|
|
for (const auto &[symbol, value] : values_) {
|
2019-03-05 21:28:08 +01:00
|
|
|
value.value().AsFortran(o << ch << symbol->name().ToString() << '=');
|
2019-02-08 19:39:10 +01:00
|
|
|
ch = ',';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return o << ')';
|
|
|
|
}
|
|
|
|
|
|
|
|
std::ostream &DerivedTypeSpecAsFortran(
|
|
|
|
std::ostream &o, const semantics::DerivedTypeSpec &spec) {
|
2019-02-28 22:31:34 +01:00
|
|
|
o << spec.typeSymbol().name().ToString();
|
2019-02-08 19:39:10 +01:00
|
|
|
if (!spec.parameters().empty()) {
|
|
|
|
char ch{'('};
|
|
|
|
for (const auto &[name, value] : spec.parameters()) {
|
|
|
|
value.GetExplicit()->AsFortran(o << ch << name.ToString() << '=');
|
|
|
|
ch = ',';
|
|
|
|
}
|
|
|
|
o << ')';
|
|
|
|
}
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
2019-03-20 19:38:45 +01:00
|
|
|
GenericExprWrapper::~GenericExprWrapper() = default;
|
|
|
|
|
2019-01-04 23:05:53 +01:00
|
|
|
bool GenericExprWrapper::operator==(const GenericExprWrapper &that) const {
|
|
|
|
return v == that.v;
|
|
|
|
}
|
|
|
|
|
2019-03-20 19:38:45 +01:00
|
|
|
template<TypeCategory CAT> int Expr<SomeKind<CAT>>::GetKind() const {
|
|
|
|
return std::visit(
|
|
|
|
[](const auto &kx) { return std::decay_t<decltype(kx)>::Result::kind; },
|
|
|
|
u);
|
|
|
|
}
|
|
|
|
|
|
|
|
int Expr<SomeCharacter>::GetKind() const {
|
|
|
|
return std::visit(
|
|
|
|
[](const auto &kx) { return std::decay_t<decltype(kx)>::Result::kind; },
|
|
|
|
u);
|
|
|
|
}
|
|
|
|
|
|
|
|
Expr<SubscriptInteger> Expr<SomeCharacter>::LEN() const {
|
|
|
|
return std::visit([](const auto &kx) { return kx.LEN(); }, u);
|
|
|
|
}
|
|
|
|
|
2018-08-29 00:15:18 +02:00
|
|
|
// Template instantiations to resolve the "extern template" declarations
|
2018-09-12 20:20:30 +02:00
|
|
|
// that appear in expression.h.
|
2018-08-18 00:38:37 +02:00
|
|
|
|
2018-10-27 01:31:20 +02:00
|
|
|
FOR_EACH_INTRINSIC_KIND(template class Expr)
|
|
|
|
FOR_EACH_CATEGORY_TYPE(template class Expr)
|
|
|
|
FOR_EACH_INTEGER_KIND(template struct Relational)
|
|
|
|
FOR_EACH_REAL_KIND(template struct Relational)
|
|
|
|
FOR_EACH_CHARACTER_KIND(template struct Relational)
|
2018-08-29 00:15:18 +02:00
|
|
|
template struct Relational<SomeType>;
|
2018-10-30 20:44:09 +01:00
|
|
|
FOR_EACH_TYPE_AND_KIND(template class ExpressionBase)
|
2019-02-09 01:35:02 +01:00
|
|
|
FOR_EACH_INTRINSIC_KIND(template class ArrayConstructorValues)
|
|
|
|
FOR_EACH_INTRINSIC_KIND(template class ArrayConstructor)
|
2018-10-25 14:55:23 +02:00
|
|
|
}
|
2019-03-20 19:38:45 +01:00
|
|
|
DEFINE_DELETER(Fortran::evaluate::GenericExprWrapper)
|