2018-06-20 20:55:10 +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-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-07 00:12:33 +02:00
|
|
|
#include "../parser/characters.h"
|
2018-07-24 21:58:29 +02:00
|
|
|
#include "../parser/message.h"
|
2018-06-20 20:55:10 +02:00
|
|
|
#include <ostream>
|
|
|
|
#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-08-18 00:38:37 +02:00
|
|
|
// Dump
|
|
|
|
|
|
|
|
template<typename D, typename R, typename... O>
|
|
|
|
std::ostream &Operation<D, R, O...>::Dump(std::ostream &o) const {
|
2018-09-07 19:33:32 +02:00
|
|
|
left().Dump(derived().Prefix(o));
|
|
|
|
if constexpr (operands > 1) {
|
|
|
|
right().Dump(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>
|
|
|
|
std::ostream &Convert<TO, FROMCAT>::Dump(std::ostream &o) const {
|
|
|
|
static_assert(TO::category == TypeCategory::Integer ||
|
|
|
|
TO::category == TypeCategory::Real ||
|
|
|
|
TO::category == TypeCategory::Logical || !"Convert<> to bad category!");
|
|
|
|
if constexpr (TO::category == TypeCategory::Integer) {
|
|
|
|
o << "INT";
|
|
|
|
} else if constexpr (TO::category == TypeCategory::Real) {
|
|
|
|
o << "REAL";
|
|
|
|
} else if constexpr (TO::category == TypeCategory::Logical) {
|
|
|
|
o << "LOGICAL";
|
|
|
|
}
|
|
|
|
return this->left().Dump(o << '(') << ",KIND=" << TO::kind << ')';
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename A> std::ostream &Relational<A>::Infix(std::ostream &o) const {
|
|
|
|
return o << '.' << EnumToString(opr) << '.';
|
2018-08-18 00:38:37 +02:00
|
|
|
}
|
|
|
|
|
2018-08-29 00:15:18 +02:00
|
|
|
std::ostream &Relational<SomeType>::Dump(std::ostream &o) const {
|
|
|
|
std::visit([&](const auto &rel) { rel.Dump(o); }, u);
|
|
|
|
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-09-07 19:33:32 +02: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-08-29 00:15:18 +02:00
|
|
|
template<typename T> std::ostream &Constant<T>::Dump(std::ostream &o) const {
|
|
|
|
if constexpr (T::category == TypeCategory::Integer) {
|
2018-09-08 01:54:33 +02:00
|
|
|
return o << value.SignedDecimal() << '_' << T::kind;
|
2018-08-29 00:15:18 +02:00
|
|
|
} else if constexpr (T::category == TypeCategory::Real ||
|
|
|
|
T::category == TypeCategory::Complex) {
|
2018-09-08 01:54:33 +02:00
|
|
|
return o << value.DumpHexadecimal() << '_' << T::kind;
|
2018-08-29 00:15:18 +02:00
|
|
|
} else if constexpr (T::category == TypeCategory::Character) {
|
2018-09-08 01:54:33 +02:00
|
|
|
if constexpr (T::kind == 1) {
|
|
|
|
return o << T::kind << '_' << parser::QuoteCharacterLiteral(value);
|
|
|
|
} else {
|
|
|
|
return o << T::kind
|
|
|
|
<< "_'(wide character dumping unimplemented)'"; // TODO
|
|
|
|
}
|
2018-08-29 00:15:18 +02:00
|
|
|
} else if constexpr (T::category == TypeCategory::Logical) {
|
|
|
|
if (value.IsTrue()) {
|
|
|
|
o << ".TRUE.";
|
|
|
|
} else {
|
|
|
|
o << ".FALSE.";
|
|
|
|
}
|
|
|
|
return o << '_' << Result::kind;
|
|
|
|
} else {
|
|
|
|
return value.u.Dump(o);
|
|
|
|
}
|
2018-07-19 18:53:42 +02:00
|
|
|
}
|
|
|
|
|
2018-10-30 23:24:35 +01:00
|
|
|
template<typename T>
|
|
|
|
std::ostream &Emit(std::ostream &o, const CopyableIndirection<Expr<T>> &expr) {
|
|
|
|
return expr->Dump(o);
|
|
|
|
}
|
|
|
|
template<typename T>
|
|
|
|
std::ostream &Emit(std::ostream &, const ArrayConstructorValues<T> &);
|
|
|
|
|
|
|
|
template<typename ITEM, typename INT>
|
|
|
|
std::ostream &Emit(std::ostream &o, const ImpliedDo<ITEM, INT> &implDo) {
|
|
|
|
o << '(';
|
|
|
|
Emit(o, *implDo.values);
|
|
|
|
o << ',' << INT::Dump() << "::";
|
|
|
|
o << implDo.controlVariableName.ToString();
|
|
|
|
o << '=';
|
|
|
|
implDo.lower->Dump(o) << ',';
|
|
|
|
implDo.upper->Dump(o) << ',';
|
|
|
|
implDo.stride->Dump(o) << ')';
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
std::ostream &Emit(std::ostream &o, const ArrayConstructorValues<T> &values) {
|
|
|
|
const char *sep{""};
|
|
|
|
for (const auto &value : values.values) {
|
|
|
|
o << sep;
|
|
|
|
std::visit([&](const auto &x) { Emit(o, x); }, value.u);
|
|
|
|
sep = ",";
|
|
|
|
}
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
std::ostream &ArrayConstructor<T>::Dump(std::ostream &o) const {
|
|
|
|
o << '[' << Result::Dump() << "::";
|
|
|
|
Emit(o, *this);
|
|
|
|
return o << ']';
|
|
|
|
}
|
|
|
|
|
2018-08-29 00:15:18 +02:00
|
|
|
template<typename RESULT>
|
|
|
|
std::ostream &ExpressionBase<RESULT>::Dump(std::ostream &o) const {
|
2018-09-20 21:34:29 +02:00
|
|
|
std::visit(common::visitors{[&](const BOZLiteralConstant &x) {
|
|
|
|
o << "Z'" << x.Hexadecimal() << "'";
|
|
|
|
},
|
|
|
|
[&](const CopyableIndirection<Substring> &s) { s->Dump(o); },
|
|
|
|
[&](const auto &x) { x.Dump(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-08-29 00:15:18 +02:00
|
|
|
common::visitors{[](const Constant<Result> &c) {
|
2018-10-10 22:54:25 +02:00
|
|
|
return AsExpr(
|
|
|
|
Constant<SubscriptInteger>{c.value.size()});
|
2018-08-18 00:38:37 +02:00
|
|
|
},
|
2018-09-17 20:31:38 +02:00
|
|
|
[](const Parentheses<Result> &x) { return x.left().LEN(); },
|
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-09-20 21:34:29 +02:00
|
|
|
[](const FunctionRef<Result> &fr) { return fr.LEN(); }},
|
2018-07-20 21:19:09 +02:00
|
|
|
u);
|
2018-07-19 18:53:42 +02:00
|
|
|
}
|
|
|
|
|
2018-09-07 19:33:32 +02:00
|
|
|
Expr<SomeType>::~Expr() {}
|
|
|
|
|
2018-10-09 00:35:19 +02:00
|
|
|
template<typename A>
|
|
|
|
std::optional<DynamicType> ExpressionBase<A>::GetType() const {
|
2018-10-09 21:07:29 +02:00
|
|
|
if constexpr (Result::isSpecificIntrinsicType) {
|
|
|
|
return Result::GetType();
|
2018-10-09 00:35:19 +02:00
|
|
|
} else {
|
|
|
|
return std::visit(
|
|
|
|
[](const auto &x) -> std::optional<DynamicType> {
|
2018-10-15 21:17:30 +02:00
|
|
|
if constexpr (!std::is_same_v<std::decay_t<decltype(x)>,
|
2018-10-09 00:35:19 +02:00
|
|
|
BOZLiteralConstant>) {
|
|
|
|
return x.GetType();
|
|
|
|
}
|
2018-10-15 21:17:30 +02:00
|
|
|
return std::nullopt; // typeless -> 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);
|
|
|
|
}
|
|
|
|
|
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)
|
2018-10-25 14:55:23 +02:00
|
|
|
}
|
2018-09-07 19:33:32 +02:00
|
|
|
|
|
|
|
// For reclamation of analyzed expressions to which owning pointers have
|
|
|
|
// been embedded in the parse tree. This destructor appears here, where
|
|
|
|
// definitions for all the necessary types are available, to obviate a
|
|
|
|
// need to include lib/evaluate/*.h headers in the parser proper.
|
|
|
|
namespace Fortran::common {
|
|
|
|
template<> OwningPointer<evaluate::GenericExprWrapper>::~OwningPointer() {
|
|
|
|
delete p_;
|
|
|
|
p_ = nullptr;
|
|
|
|
}
|
|
|
|
template class OwningPointer<evaluate::GenericExprWrapper>;
|
2018-10-25 14:55:23 +02:00
|
|
|
}
|