2019-03-06 01:57:18 +01:00
|
|
|
// Copyright (c) 2019, 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_TRAVERSAL_H_
|
|
|
|
#define FORTRAN_EVALUATE_TRAVERSAL_H_
|
|
|
|
|
|
|
|
#include "expression.h"
|
2019-03-06 18:11:17 +01:00
|
|
|
#include <type_traits>
|
2019-03-06 01:57:18 +01:00
|
|
|
|
|
|
|
// Implements an expression traversal utility framework.
|
2019-03-06 20:52:25 +01:00
|
|
|
// See fold.cc to see how this framework is used to implement detection
|
|
|
|
// of constant expressions.
|
|
|
|
//
|
|
|
|
// To use, define one or more client visitation classes of the form:
|
|
|
|
// class MyVisitor : public virtual TraversalBase<RESULT> {
|
|
|
|
// explicit MyVisitor(ARGTYPE); // single-argument constructor
|
|
|
|
// void Handle(const T1 &); // callback for type T1 objects
|
|
|
|
// void Pre(const T2 &); // callback before visiting T2
|
|
|
|
// void Post(const T2 &); // callback after visiting T2
|
|
|
|
// ...
|
|
|
|
// };
|
|
|
|
// RESULT should have some default-constructible type.
|
|
|
|
// Then instantiate and construct a Traversal and its embedded MyVisitor via:
|
|
|
|
// Traversal<RESULT, MyVisitor, ...> t{value}; // value is ARGTYPE &&
|
|
|
|
// and call:
|
|
|
|
// RESULT result{t.Traverse(topLevelExpr)};
|
|
|
|
// Within the callback routines (Handle, Pre, Post), one may call
|
|
|
|
// void Stop(); // to end traversal
|
|
|
|
// void Return(...); // to emplace-construct the result and end traversal
|
|
|
|
// RESULT &result(); // to reference the result to define or update it
|
|
|
|
// For any given expression object type T for which a callback is defined
|
|
|
|
// in any visitor class, the callback must be distinct from all others.
|
|
|
|
// Further, if there is a Handle(const T &) callback, there cannot be a
|
|
|
|
// Pre() or a Post().
|
|
|
|
|
2019-03-06 01:57:18 +01:00
|
|
|
namespace Fortran::evaluate {
|
|
|
|
|
2019-03-06 18:11:17 +01:00
|
|
|
template<typename RESULT> class TraversalBase {
|
2019-03-06 01:57:18 +01:00
|
|
|
public:
|
|
|
|
using Result = RESULT;
|
2019-03-06 20:52:25 +01:00
|
|
|
|
|
|
|
Result &result() { return result_; }
|
|
|
|
|
|
|
|
// Note the odd return type; it distinguishes these default callbacks
|
|
|
|
// from any void-valued client callback.
|
2019-03-06 18:11:17 +01:00
|
|
|
template<typename A> std::nullptr_t Handle(const A &) { return nullptr; }
|
2019-03-06 20:52:25 +01:00
|
|
|
template<typename A> std::nullptr_t Pre(const A &) { return nullptr; }
|
|
|
|
template<typename A> std::nullptr_t Post(const A &) { return nullptr; }
|
|
|
|
|
|
|
|
void Stop() { done_ = true; }
|
|
|
|
void Return(RESULT &&x) {
|
|
|
|
result_ = std::move(x);
|
|
|
|
Stop();
|
2019-03-06 01:57:18 +01:00
|
|
|
}
|
2019-03-06 18:11:17 +01:00
|
|
|
|
2019-03-06 01:57:18 +01:00
|
|
|
protected:
|
2019-03-06 20:52:25 +01:00
|
|
|
bool done_{false};
|
|
|
|
Result result_;
|
2019-03-06 01:57:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
// Descend() is a helper function template for Traversal::Visit().
|
|
|
|
// Do not use directly.
|
|
|
|
namespace descend {
|
2019-03-06 18:11:17 +01:00
|
|
|
template<typename VISITOR, typename EXPR>
|
|
|
|
void Descend(VISITOR &, const EXPR &) {}
|
2019-03-06 01:57:18 +01:00
|
|
|
template<typename V, typename A> void Descend(V &visitor, const A *p) {
|
|
|
|
if (p != nullptr) {
|
|
|
|
visitor.Visit(*p);
|
|
|
|
}
|
|
|
|
}
|
2019-03-06 18:11:17 +01:00
|
|
|
template<typename V, typename A>
|
|
|
|
void Descend(V &visitor, const std::optional<A> *o) {
|
2019-03-06 01:57:18 +01:00
|
|
|
if (o.has_value()) {
|
|
|
|
visitor.Visit(*o);
|
|
|
|
}
|
|
|
|
}
|
2019-03-06 18:11:17 +01:00
|
|
|
template<typename V, typename A>
|
|
|
|
void Descend(V &visitor, const CopyableIndirection<A> &p) {
|
2019-03-06 01:57:18 +01:00
|
|
|
visitor.Visit(p.value());
|
|
|
|
}
|
2019-03-06 18:11:17 +01:00
|
|
|
template<typename V, typename... A>
|
|
|
|
void Descend(V &visitor, const std::variant<A...> &u) {
|
|
|
|
std::visit([&](const auto &x) { visitor.Visit(x); }, u);
|
2019-03-06 01:57:18 +01:00
|
|
|
}
|
2019-03-06 18:11:17 +01:00
|
|
|
template<typename V, typename A>
|
|
|
|
void Descend(V &visitor, const std::vector<A> &xs) {
|
2019-03-06 01:57:18 +01:00
|
|
|
for (const auto &x : xs) {
|
|
|
|
visitor.Visit(x);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
template<typename V, typename T> void Descend(V &visitor, const Expr<T> &expr) {
|
|
|
|
visitor.Visit(expr.u);
|
|
|
|
}
|
|
|
|
template<typename V, typename D, typename R, typename... O>
|
2019-03-06 18:11:17 +01:00
|
|
|
void Descend(V &visitor, const Operation<D, R, O...> &op) {
|
2019-03-06 01:57:18 +01:00
|
|
|
visitor.Visit(op.left());
|
|
|
|
if constexpr (op.operands > 1) {
|
|
|
|
visitor.Visit(op.right());
|
|
|
|
}
|
|
|
|
}
|
2019-03-06 18:11:17 +01:00
|
|
|
template<typename V, typename R>
|
|
|
|
void Descend(V &visitor, const ImpliedDo<R> &ido) {
|
2019-03-06 01:57:18 +01:00
|
|
|
visitor.Visit(ido.lower());
|
|
|
|
visitor.Visit(ido.upper());
|
|
|
|
visitor.Visit(ido.stride());
|
|
|
|
visitor.Visit(ido.values());
|
|
|
|
}
|
2019-03-06 18:11:17 +01:00
|
|
|
template<typename V, typename R>
|
|
|
|
void Descend(V &visitor, const ArrayConstructorValue<R> &av) {
|
2019-03-06 01:57:18 +01:00
|
|
|
visitor.Visit(av.u);
|
|
|
|
}
|
2019-03-06 18:11:17 +01:00
|
|
|
template<typename V, typename R>
|
|
|
|
void Descend(V &visitor, const ArrayConstructorValues<R> &avs) {
|
2019-03-06 01:57:18 +01:00
|
|
|
visitor.Visit(avs.values());
|
|
|
|
}
|
2019-03-06 18:11:17 +01:00
|
|
|
template<typename V, int KIND>
|
|
|
|
void Descend(V &visitor,
|
|
|
|
const ArrayConstructor<Type<TypeCategory::Character, KIND>> &ac) {
|
|
|
|
visitor.Visit(
|
|
|
|
static_cast<ArrayConstructorValues<Type<TypeCategory::Character, KIND>>>(
|
|
|
|
ac));
|
2019-03-06 01:57:18 +01:00
|
|
|
visitor.Visit(ac.LEN());
|
|
|
|
}
|
2019-03-06 18:11:17 +01:00
|
|
|
template<typename V>
|
|
|
|
void Descend(V &visitor, const semantics::ParamValue ¶m) {
|
2019-03-06 01:57:18 +01:00
|
|
|
visitor.Visit(param.GetExplicit());
|
|
|
|
}
|
2019-03-06 18:11:17 +01:00
|
|
|
template<typename V>
|
|
|
|
void Descend(V &visitor, const semantics::DerivedTypeSpec &derived) {
|
2019-03-06 01:57:18 +01:00
|
|
|
for (const auto &pair : derived.parameters()) {
|
|
|
|
visitor.Visit(pair.second);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
template<typename V> void Descend(V &visitor, const StructureConstructor &sc) {
|
|
|
|
visitor.Visit(sc.derivedTypeSpec());
|
|
|
|
for (const auto &pair : sc.values()) {
|
|
|
|
visitor.Visit(pair.second);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
template<typename V> void Descend(V &visitor, const BaseObject &object) {
|
|
|
|
visitor.Visit(object.u);
|
|
|
|
}
|
|
|
|
template<typename V> void Descend(V &visitor, const Component &component) {
|
|
|
|
visitor.Visit(component.base());
|
|
|
|
visitor.Visit(component.GetLastSymbol());
|
|
|
|
}
|
2019-03-06 18:11:17 +01:00
|
|
|
template<typename V, int KIND>
|
|
|
|
void Descend(V &visitor, const TypeParamInquiry<KIND> &inq) {
|
2019-03-06 01:57:18 +01:00
|
|
|
visitor.Visit(inq.base());
|
|
|
|
visitor.Visit(inq.parameter());
|
|
|
|
}
|
|
|
|
template<typename V> void Descend(V &visitor, const Triplet &triplet) {
|
|
|
|
visitor.Visit(triplet.lower());
|
|
|
|
visitor.Visit(triplet.upper());
|
|
|
|
visitor.Visit(triplet.stride());
|
|
|
|
}
|
|
|
|
template<typename V> void Descend(V &visitor, const Subscript &sscript) {
|
|
|
|
visitor.Visit(sscript.u);
|
|
|
|
}
|
|
|
|
template<typename V> void Descend(V &visitor, const ArrayRef &aref) {
|
|
|
|
visitor.Visit(aref.base());
|
|
|
|
visitor.Visit(aref.subscript());
|
|
|
|
}
|
|
|
|
template<typename V> void Descend(V &visitor, const CoarrayRef &caref) {
|
|
|
|
visitor.Visit(caref.base());
|
|
|
|
visitor.Visit(caref.subscript());
|
|
|
|
visitor.Visit(caref.cosubscript());
|
|
|
|
visitor.Visit(caref.stat());
|
|
|
|
visitor.Visit(caref.team());
|
|
|
|
}
|
|
|
|
template<typename V> void Descend(V &visitor, const DataRef &data) {
|
|
|
|
visitor.Visit(data.u);
|
|
|
|
}
|
|
|
|
template<typename V> void Descend(V &visitor, const ComplexPart &z) {
|
|
|
|
visitor.Visit(z.complex());
|
|
|
|
}
|
2019-03-06 18:11:17 +01:00
|
|
|
template<typename V, typename T>
|
|
|
|
void Descend(V &visitor, const Designator<T> &designator) {
|
2019-03-06 01:57:18 +01:00
|
|
|
visitor.Visit(designator.u);
|
|
|
|
}
|
2019-03-06 18:11:17 +01:00
|
|
|
template<typename V, typename T>
|
|
|
|
void Descend(V &visitor, const Variable<T> &var) {
|
2019-03-06 01:57:18 +01:00
|
|
|
visitor.Visit(var.u);
|
|
|
|
}
|
|
|
|
template<typename V> void Descend(V &visitor, const ActualArgument &arg) {
|
|
|
|
visitor.Visit(arg.value());
|
|
|
|
}
|
|
|
|
template<typename V> void Descend(V &visitor, const ProcedureDesignator &p) {
|
|
|
|
visitor.Visit(p.u);
|
|
|
|
}
|
|
|
|
template<typename V> void Descend(V &visitor, const ProcedureRef &call) {
|
|
|
|
visitor.Visit(call.proc());
|
|
|
|
visitor.Visit(call.arguments());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename RESULT, typename... A>
|
2019-03-06 02:11:05 +01:00
|
|
|
class Traversal : public virtual TraversalBase<RESULT>, public A... {
|
2019-03-06 01:57:18 +01:00
|
|
|
public:
|
|
|
|
using Result = RESULT;
|
2019-03-06 02:11:05 +01:00
|
|
|
using Base = TraversalBase<Result>;
|
|
|
|
using Base::Handle, Base::Pre, Base::Post;
|
2019-03-06 01:57:18 +01:00
|
|
|
using A::Handle..., A::Pre..., A::Post...;
|
2019-03-06 18:11:17 +01:00
|
|
|
|
2019-03-06 01:57:18 +01:00
|
|
|
private:
|
2019-03-06 20:52:25 +01:00
|
|
|
using TraversalBase<Result>::done_, TraversalBase<Result>::result_;
|
2019-03-06 18:11:17 +01:00
|
|
|
|
2019-03-06 01:57:18 +01:00
|
|
|
public:
|
|
|
|
template<typename... B> Traversal(B... x) : A{x}... {}
|
2019-03-06 20:52:25 +01:00
|
|
|
template<typename B> Result Traverse(const B &x) {
|
2019-03-06 01:57:18 +01:00
|
|
|
Visit(x);
|
|
|
|
return std::move(result_);
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: make private, make Descend instances friends
|
|
|
|
template<typename B> void Visit(const B &x) {
|
2019-03-06 20:52:25 +01:00
|
|
|
if (!done_) {
|
2019-03-06 18:11:17 +01:00
|
|
|
if constexpr (std::is_same_v<std::decay_t<decltype(Handle(x))>,
|
|
|
|
std::nullptr_t>) {
|
|
|
|
// No visitation class defines Handle(B), so try Pre()/Post().
|
2019-03-06 01:57:18 +01:00
|
|
|
Pre(x);
|
2019-03-06 20:52:25 +01:00
|
|
|
if (!done_) {
|
2019-03-06 01:57:18 +01:00
|
|
|
descend::Descend(*this, x);
|
2019-03-06 20:52:25 +01:00
|
|
|
if (!done_) {
|
2019-03-06 01:57:18 +01:00
|
|
|
Post(x);
|
|
|
|
}
|
|
|
|
}
|
2019-03-06 18:11:17 +01:00
|
|
|
} else {
|
2019-03-06 20:52:25 +01:00
|
|
|
static_assert(
|
|
|
|
std::is_same_v<std::decay_t<decltype(Pre(x))>, std::nullptr_t>);
|
|
|
|
static_assert(
|
|
|
|
std::is_same_v<std::decay_t<decltype(Post(x))>, std::nullptr_t>);
|
2019-03-06 18:11:17 +01:00
|
|
|
Handle(x);
|
2019-03-06 01:57:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
#endif // FORTRAN_EVALUATE_TRAVERSAL_H_
|