Nimish Mishra fe2d053c45 Added OpenMP 5.0 specification based semantic checks for CRITICAL construct name resolution
As reported in https://bugs.llvm.org/show_bug.cgi?id=48145, name resolution for omp critical construct was failing. This patch adds functionality to help that name resolution as well as implementation to catch name mismatches.

The following semantic restrictions are therefore handled here:

- If a name is specified on a critical directive, the same name must also be specified on the end critical directive

- If no name appears on the critical directive, no name can appear on the end critical directive

- If a name appears on either the start critical directive or the end critical directive

Reviewed By: kiranchandramohan

Differential Revision: https://reviews.llvm.org/D110502
2021-10-12 22:18:24 +05:30

2733 lines
92 KiB
C++

//===-- lib/Parser/unparse.cpp --------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Generates Fortran from the content of a parse tree, using the
// traversal templates in parse-tree-visitor.h.
#include "flang/Parser/unparse.h"
#include "flang/Common/Fortran.h"
#include "flang/Common/idioms.h"
#include "flang/Common/indirection.h"
#include "flang/Parser/characters.h"
#include "flang/Parser/parse-tree-visitor.h"
#include "flang/Parser/parse-tree.h"
#include "flang/Parser/tools.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cinttypes>
#include <cstddef>
#include <set>
namespace Fortran::parser {
class UnparseVisitor {
public:
UnparseVisitor(llvm::raw_ostream &out, int indentationAmount,
Encoding encoding, bool capitalize, bool backslashEscapes,
preStatementType *preStatement, AnalyzedObjectsAsFortran *asFortran)
: out_{out}, indentationAmount_{indentationAmount}, encoding_{encoding},
capitalizeKeywords_{capitalize}, backslashEscapes_{backslashEscapes},
preStatement_{preStatement}, asFortran_{asFortran} {}
// In nearly all cases, this code avoids defining Boolean-valued Pre()
// callbacks for the parse tree walking framework in favor of two void
// functions, Before() and Unparse(), which imply true and false return
// values for Pre() respectively.
template <typename T> void Before(const T &) {}
template <typename T> double Unparse(const T &); // not void, never used
template <typename T> bool Pre(const T &x) {
if constexpr (std::is_void_v<decltype(Unparse(x))>) {
// There is a local definition of Unparse() for this type. It
// overrides the parse tree walker's default Walk() over the descendents.
Before(x);
Unparse(x);
Post(x);
return false; // Walk() does not visit descendents
} else if constexpr (HasTypedExpr<T>::value) {
// Format the expression representation from semantics
if (asFortran_ && x.typedExpr) {
asFortran_->expr(out_, *x.typedExpr);
return false;
} else {
return true;
}
} else {
Before(x);
return true; // there's no Unparse() defined here, Walk() the descendents
}
}
template <typename T> void Post(const T &) {}
// Emit simple types as-is.
void Unparse(const std::string &x) { Put(x); }
void Unparse(int x) { Put(std::to_string(x)); }
void Unparse(unsigned int x) { Put(std::to_string(x)); }
void Unparse(long x) { Put(std::to_string(x)); }
void Unparse(unsigned long x) { Put(std::to_string(x)); }
void Unparse(long long x) { Put(std::to_string(x)); }
void Unparse(unsigned long long x) { Put(std::to_string(x)); }
void Unparse(char x) { Put(x); }
// Statement labels and ends of lines
template <typename T> void Before(const Statement<T> &x) {
if (preStatement_) {
(*preStatement_)(x.source, out_, indent_);
}
Walk(x.label, " ");
}
template <typename T> void Post(const Statement<T> &) { Put('\n'); }
// The special-case formatting functions for these productions are
// ordered to correspond roughly to their order of appearance in
// the Fortran 2018 standard (and parse-tree.h).
void Unparse(const Program &x) { // R501
Walk("", x.v, "\n"); // put blank lines between ProgramUnits
}
void Unparse(const Name &x) { // R603
Put(x.ToString());
}
void Unparse(const DefinedOperator::IntrinsicOperator &x) { // R608
switch (x) {
case DefinedOperator::IntrinsicOperator::Power:
Put("**");
break;
case DefinedOperator::IntrinsicOperator::Multiply:
Put('*');
break;
case DefinedOperator::IntrinsicOperator::Divide:
Put('/');
break;
case DefinedOperator::IntrinsicOperator::Add:
Put('+');
break;
case DefinedOperator::IntrinsicOperator::Subtract:
Put('-');
break;
case DefinedOperator::IntrinsicOperator::Concat:
Put("//");
break;
case DefinedOperator::IntrinsicOperator::LT:
Put('<');
break;
case DefinedOperator::IntrinsicOperator::LE:
Put("<=");
break;
case DefinedOperator::IntrinsicOperator::EQ:
Put("==");
break;
case DefinedOperator::IntrinsicOperator::NE:
Put("/=");
break;
case DefinedOperator::IntrinsicOperator::GE:
Put(">=");
break;
case DefinedOperator::IntrinsicOperator::GT:
Put('>');
break;
default:
Put('.'), Word(DefinedOperator::EnumToString(x)), Put('.');
}
}
void Post(const Star &) { Put('*'); } // R701 &c.
void Post(const TypeParamValue::Deferred &) { Put(':'); } // R701
void Unparse(const DeclarationTypeSpec::Type &x) { // R703
Word("TYPE("), Walk(x.derived), Put(')');
}
void Unparse(const DeclarationTypeSpec::Class &x) {
Word("CLASS("), Walk(x.derived), Put(')');
}
void Post(const DeclarationTypeSpec::ClassStar &) { Word("CLASS(*)"); }
void Post(const DeclarationTypeSpec::TypeStar &) { Word("TYPE(*)"); }
void Unparse(const DeclarationTypeSpec::Record &x) {
Word("RECORD/"), Walk(x.v), Put('/');
}
void Before(const IntrinsicTypeSpec::Real &) { // R704
Word("REAL");
}
void Before(const IntrinsicTypeSpec::Complex &) { Word("COMPLEX"); }
void Post(const IntrinsicTypeSpec::DoublePrecision &) {
Word("DOUBLE PRECISION");
}
void Before(const IntrinsicTypeSpec::Character &) { Word("CHARACTER"); }
void Before(const IntrinsicTypeSpec::Logical &) { Word("LOGICAL"); }
void Post(const IntrinsicTypeSpec::DoubleComplex &) {
Word("DOUBLE COMPLEX");
}
void Before(const IntegerTypeSpec &) { // R705
Word("INTEGER");
}
void Unparse(const KindSelector &x) { // R706
std::visit(
common::visitors{
[&](const ScalarIntConstantExpr &y) {
Put('('), Word("KIND="), Walk(y), Put(')');
},
[&](const KindSelector::StarSize &y) { Put('*'), Walk(y.v); },
},
x.u);
}
void Unparse(const SignedIntLiteralConstant &x) { // R707
Put(std::get<CharBlock>(x.t).ToString());
Walk("_", std::get<std::optional<KindParam>>(x.t));
}
void Unparse(const IntLiteralConstant &x) { // R708
Put(std::get<CharBlock>(x.t).ToString());
Walk("_", std::get<std::optional<KindParam>>(x.t));
}
void Unparse(const Sign &x) { // R712
Put(x == Sign::Negative ? '-' : '+');
}
void Unparse(const RealLiteralConstant &x) { // R714, R715
Put(x.real.source.ToString()), Walk("_", x.kind);
}
void Unparse(const ComplexLiteralConstant &x) { // R718 - R720
Put('('), Walk(x.t, ","), Put(')');
}
void Unparse(const CharSelector::LengthAndKind &x) { // R721
Put('('), Word("KIND="), Walk(x.kind);
Walk(", LEN=", x.length), Put(')');
}
void Unparse(const LengthSelector &x) { // R722
std::visit(common::visitors{
[&](const TypeParamValue &y) {
Put('('), Word("LEN="), Walk(y), Put(')');
},
[&](const CharLength &y) { Put('*'), Walk(y); },
},
x.u);
}
void Unparse(const CharLength &x) { // R723
std::visit(
common::visitors{
[&](const TypeParamValue &y) { Put('('), Walk(y), Put(')'); },
[&](const std::int64_t &y) { Walk(y); },
},
x.u);
}
void Unparse(const CharLiteralConstant &x) { // R724
const auto &str{std::get<std::string>(x.t)};
if (const auto &k{std::get<std::optional<KindParam>>(x.t)}) {
Walk(*k), Put('_');
}
PutNormalized(str);
}
void Unparse(const HollerithLiteralConstant &x) {
auto ucs{DecodeString<std::u32string, Encoding::UTF_8>(x.v, false)};
Unparse(ucs.size());
Put('H');
for (char32_t ch : ucs) {
EncodedCharacter encoded{EncodeCharacter(encoding_, ch)};
for (int j{0}; j < encoded.bytes; ++j) {
Put(encoded.buffer[j]);
}
}
}
void Unparse(const LogicalLiteralConstant &x) { // R725
Put(std::get<bool>(x.t) ? ".TRUE." : ".FALSE.");
Walk("_", std::get<std::optional<KindParam>>(x.t));
}
void Unparse(const DerivedTypeStmt &x) { // R727
Word("TYPE"), Walk(", ", std::get<std::list<TypeAttrSpec>>(x.t), ", ");
Put(" :: "), Walk(std::get<Name>(x.t));
Walk("(", std::get<std::list<Name>>(x.t), ", ", ")");
Indent();
}
void Unparse(const Abstract &) { // R728, &c.
Word("ABSTRACT");
}
void Post(const TypeAttrSpec::BindC &) { Word("BIND(C)"); }
void Unparse(const TypeAttrSpec::Extends &x) {
Word("EXTENDS("), Walk(x.v), Put(')');
}
void Unparse(const EndTypeStmt &x) { // R730
Outdent(), Word("END TYPE"), Walk(" ", x.v);
}
void Unparse(const SequenceStmt &) { // R731
Word("SEQUENCE");
}
void Unparse(const TypeParamDefStmt &x) { // R732
Walk(std::get<IntegerTypeSpec>(x.t));
Put(", "), Walk(std::get<common::TypeParamAttr>(x.t));
Put(" :: "), Walk(std::get<std::list<TypeParamDecl>>(x.t), ", ");
}
void Unparse(const TypeParamDecl &x) { // R733
Walk(std::get<Name>(x.t));
Walk("=", std::get<std::optional<ScalarIntConstantExpr>>(x.t));
}
void Unparse(const DataComponentDefStmt &x) { // R737
const auto &dts{std::get<DeclarationTypeSpec>(x.t)};
const auto &attrs{std::get<std::list<ComponentAttrSpec>>(x.t)};
const auto &decls{std::get<std::list<ComponentDecl>>(x.t)};
Walk(dts), Walk(", ", attrs, ", ");
if (!attrs.empty() ||
(!std::holds_alternative<DeclarationTypeSpec::Record>(dts.u) &&
std::none_of(
decls.begin(), decls.end(), [](const ComponentDecl &d) {
const auto &init{
std::get<std::optional<Initialization>>(d.t)};
return init &&
std::holds_alternative<
std::list<common::Indirection<DataStmtValue>>>(
init->u);
}))) {
Put(" ::");
}
Put(' '), Walk(decls, ", ");
}
void Unparse(const Allocatable &) { // R738
Word("ALLOCATABLE");
}
void Unparse(const Pointer &) { Word("POINTER"); }
void Unparse(const Contiguous &) { Word("CONTIGUOUS"); }
void Before(const ComponentAttrSpec &x) {
std::visit(common::visitors{
[&](const CoarraySpec &) { Word("CODIMENSION["); },
[&](const ComponentArraySpec &) { Word("DIMENSION("); },
[](const auto &) {},
},
x.u);
}
void Post(const ComponentAttrSpec &x) {
std::visit(common::visitors{
[&](const CoarraySpec &) { Put(']'); },
[&](const ComponentArraySpec &) { Put(')'); },
[](const auto &) {},
},
x.u);
}
void Unparse(const ComponentDecl &x) { // R739
Walk(std::get<ObjectName>(x.t));
Walk("(", std::get<std::optional<ComponentArraySpec>>(x.t), ")");
Walk("[", std::get<std::optional<CoarraySpec>>(x.t), "]");
Walk("*", std::get<std::optional<CharLength>>(x.t));
Walk(std::get<std::optional<Initialization>>(x.t));
}
void Unparse(const ComponentArraySpec &x) { // R740
std::visit(common::visitors{
[&](const std::list<ExplicitShapeSpec> &y) { Walk(y, ","); },
[&](const DeferredShapeSpecList &y) { Walk(y); },
},
x.u);
}
void Unparse(const ProcComponentDefStmt &x) { // R741
Word("PROCEDURE(");
Walk(std::get<std::optional<ProcInterface>>(x.t)), Put(')');
Walk(", ", std::get<std::list<ProcComponentAttrSpec>>(x.t), ", ");
Put(" :: "), Walk(std::get<std::list<ProcDecl>>(x.t), ", ");
}
void Unparse(const NoPass &) { // R742
Word("NOPASS");
}
void Unparse(const Pass &x) { Word("PASS"), Walk("(", x.v, ")"); }
void Unparse(const Initialization &x) { // R743 & R805
std::visit(common::visitors{
[&](const ConstantExpr &y) { Put(" = "), Walk(y); },
[&](const NullInit &y) { Put(" => "), Walk(y); },
[&](const InitialDataTarget &y) { Put(" => "), Walk(y); },
[&](const std::list<common::Indirection<DataStmtValue>> &y) {
Walk("/", y, ", ", "/");
},
},
x.u);
}
void Unparse(const PrivateStmt &) { // R745
Word("PRIVATE");
}
void Unparse(const TypeBoundProcedureStmt::WithoutInterface &x) { // R749
Word("PROCEDURE"), Walk(", ", x.attributes, ", ");
Put(" :: "), Walk(x.declarations, ", ");
}
void Unparse(const TypeBoundProcedureStmt::WithInterface &x) {
Word("PROCEDURE("), Walk(x.interfaceName), Put("), ");
Walk(x.attributes);
Put(" :: "), Walk(x.bindingNames, ", ");
}
void Unparse(const TypeBoundProcDecl &x) { // R750
Walk(std::get<Name>(x.t));
Walk(" => ", std::get<std::optional<Name>>(x.t));
}
void Unparse(const TypeBoundGenericStmt &x) { // R751
Word("GENERIC"), Walk(", ", std::get<std::optional<AccessSpec>>(x.t));
Put(" :: "), Walk(std::get<common::Indirection<GenericSpec>>(x.t));
Put(" => "), Walk(std::get<std::list<Name>>(x.t), ", ");
}
void Post(const BindAttr::Deferred &) { Word("DEFERRED"); } // R752
void Post(const BindAttr::Non_Overridable &) { Word("NON_OVERRIDABLE"); }
void Unparse(const FinalProcedureStmt &x) { // R753
Word("FINAL :: "), Walk(x.v, ", ");
}
void Unparse(const DerivedTypeSpec &x) { // R754
Walk(std::get<Name>(x.t));
Walk("(", std::get<std::list<TypeParamSpec>>(x.t), ",", ")");
}
void Unparse(const TypeParamSpec &x) { // R755
Walk(std::get<std::optional<Keyword>>(x.t), "=");
Walk(std::get<TypeParamValue>(x.t));
}
void Unparse(const StructureConstructor &x) { // R756
Walk(std::get<DerivedTypeSpec>(x.t));
Put('('), Walk(std::get<std::list<ComponentSpec>>(x.t), ", "), Put(')');
}
void Unparse(const ComponentSpec &x) { // R757
Walk(std::get<std::optional<Keyword>>(x.t), "=");
Walk(std::get<ComponentDataSource>(x.t));
}
void Unparse(const EnumDefStmt &) { // R760
Word("ENUM, BIND(C)"), Indent();
}
void Unparse(const EnumeratorDefStmt &x) { // R761
Word("ENUMERATOR :: "), Walk(x.v, ", ");
}
void Unparse(const Enumerator &x) { // R762
Walk(std::get<NamedConstant>(x.t));
Walk(" = ", std::get<std::optional<ScalarIntConstantExpr>>(x.t));
}
void Post(const EndEnumStmt &) { // R763
Outdent(), Word("END ENUM");
}
void Unparse(const BOZLiteralConstant &x) { // R764 - R767
Put(x.v);
}
void Unparse(const AcValue::Triplet &x) { // R773
Walk(std::get<0>(x.t)), Put(':'), Walk(std::get<1>(x.t));
Walk(":", std::get<std::optional<ScalarIntExpr>>(x.t));
}
void Unparse(const ArrayConstructor &x) { // R769
Put('['), Walk(x.v), Put(']');
}
void Unparse(const AcSpec &x) { // R770
Walk(x.type, "::"), Walk(x.values, ", ");
}
template <typename A, typename B> void Unparse(const LoopBounds<A, B> &x) {
Walk(x.name), Put('='), Walk(x.lower), Put(','), Walk(x.upper);
Walk(",", x.step);
}
void Unparse(const AcImpliedDo &x) { // R774
Put('('), Walk(std::get<std::list<AcValue>>(x.t), ", ");
Put(", "), Walk(std::get<AcImpliedDoControl>(x.t)), Put(')');
}
void Unparse(const AcImpliedDoControl &x) { // R775
Walk(std::get<std::optional<IntegerTypeSpec>>(x.t), "::");
Walk(std::get<AcImpliedDoControl::Bounds>(x.t));
}
void Unparse(const TypeDeclarationStmt &x) { // R801
const auto &dts{std::get<DeclarationTypeSpec>(x.t)};
const auto &attrs{std::get<std::list<AttrSpec>>(x.t)};
const auto &decls{std::get<std::list<EntityDecl>>(x.t)};
Walk(dts), Walk(", ", attrs, ", ");
static const auto isInitializerOldStyle{[](const Initialization &i) {
return std::holds_alternative<
std::list<common::Indirection<DataStmtValue>>>(i.u);
}};
static const auto hasAssignmentInitializer{[](const EntityDecl &d) {
// Does a declaration have a new-style =x initializer?
const auto &init{std::get<std::optional<Initialization>>(d.t)};
return init && !isInitializerOldStyle(*init);
}};
static const auto hasSlashDelimitedInitializer{[](const EntityDecl &d) {
// Does a declaration have an old-style /x/ initializer?
const auto &init{std::get<std::optional<Initialization>>(d.t)};
return init && isInitializerOldStyle(*init);
}};
const auto useDoubledColons{[&]() {
bool isRecord{std::holds_alternative<DeclarationTypeSpec::Record>(dts.u)};
if (!attrs.empty()) {
// Attributes after the type require :: before the entities.
CHECK(!isRecord);
return true;
}
if (std::any_of(decls.begin(), decls.end(), hasAssignmentInitializer)) {
// Always use :: with new style standard initializers (=x),
// since the standard requires them to appear (even in free form,
// where mandatory spaces already disambiguate INTEGER J=666).
CHECK(!isRecord);
return true;
}
if (isRecord) {
// Never put :: in a legacy extension RECORD// statement.
return false;
}
// The :: is optional for this declaration. Avoid usage that can
// crash the pgf90 compiler.
if (std::any_of(
decls.begin(), decls.end(), hasSlashDelimitedInitializer)) {
// Don't use :: when a declaration uses legacy DATA-statement-like
// /x/ initialization.
return false;
}
// Don't use :: with intrinsic types. Otherwise, use it.
return !std::holds_alternative<IntrinsicTypeSpec>(dts.u);
}};
if (useDoubledColons()) {
Put(" ::");
}
Put(' '), Walk(std::get<std::list<EntityDecl>>(x.t), ", ");
}
void Before(const AttrSpec &x) { // R802
std::visit(common::visitors{
[&](const CoarraySpec &) { Word("CODIMENSION["); },
[&](const ArraySpec &) { Word("DIMENSION("); },
[](const auto &) {},
},
x.u);
}
void Post(const AttrSpec &x) {
std::visit(common::visitors{
[&](const CoarraySpec &) { Put(']'); },
[&](const ArraySpec &) { Put(')'); },
[](const auto &) {},
},
x.u);
}
void Unparse(const EntityDecl &x) { // R803
Walk(std::get<ObjectName>(x.t));
Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")");
Walk("[", std::get<std::optional<CoarraySpec>>(x.t), "]");
Walk("*", std::get<std::optional<CharLength>>(x.t));
Walk(std::get<std::optional<Initialization>>(x.t));
}
void Unparse(const NullInit &) { // R806
Word("NULL()");
}
void Unparse(const LanguageBindingSpec &x) { // R808 & R1528
Word("BIND(C"), Walk(", NAME=", x.v), Put(')');
}
void Unparse(const CoarraySpec &x) { // R809
std::visit(common::visitors{
[&](const DeferredCoshapeSpecList &y) { Walk(y); },
[&](const ExplicitCoshapeSpec &y) { Walk(y); },
},
x.u);
}
void Unparse(const DeferredCoshapeSpecList &x) { // R810
for (auto j{x.v}; j > 0; --j) {
Put(':');
if (j > 1) {
Put(',');
}
}
}
void Unparse(const ExplicitCoshapeSpec &x) { // R811
Walk(std::get<std::list<ExplicitShapeSpec>>(x.t), ",", ",");
Walk(std::get<std::optional<SpecificationExpr>>(x.t), ":"), Put('*');
}
void Unparse(const ExplicitShapeSpec &x) { // R812 - R813 & R816 - R818
Walk(std::get<std::optional<SpecificationExpr>>(x.t), ":");
Walk(std::get<SpecificationExpr>(x.t));
}
void Unparse(const ArraySpec &x) { // R815
std::visit(common::visitors{
[&](const std::list<ExplicitShapeSpec> &y) { Walk(y, ","); },
[&](const std::list<AssumedShapeSpec> &y) { Walk(y, ","); },
[&](const DeferredShapeSpecList &y) { Walk(y); },
[&](const AssumedSizeSpec &y) { Walk(y); },
[&](const ImpliedShapeSpec &y) { Walk(y); },
[&](const AssumedRankSpec &y) { Walk(y); },
},
x.u);
}
void Post(const AssumedShapeSpec &) { Put(':'); } // R819
void Unparse(const DeferredShapeSpecList &x) { // R820
for (auto j{x.v}; j > 0; --j) {
Put(':');
if (j > 1) {
Put(',');
}
}
}
void Unparse(const AssumedImpliedSpec &x) { // R821
Walk(x.v, ":");
Put('*');
}
void Unparse(const AssumedSizeSpec &x) { // R822
Walk(std::get<std::list<ExplicitShapeSpec>>(x.t), ",", ",");
Walk(std::get<AssumedImpliedSpec>(x.t));
}
void Unparse(const ImpliedShapeSpec &x) { // R823
Walk(x.v, ",");
}
void Post(const AssumedRankSpec &) { Put(".."); } // R825
void Post(const Asynchronous &) { Word("ASYNCHRONOUS"); }
void Post(const External &) { Word("EXTERNAL"); }
void Post(const Intrinsic &) { Word("INTRINSIC"); }
void Post(const Optional &) { Word("OPTIONAL"); }
void Post(const Parameter &) { Word("PARAMETER"); }
void Post(const Protected &) { Word("PROTECTED"); }
void Post(const Save &) { Word("SAVE"); }
void Post(const Target &) { Word("TARGET"); }
void Post(const Value &) { Word("VALUE"); }
void Post(const Volatile &) { Word("VOLATILE"); }
void Unparse(const IntentSpec &x) { // R826
Word("INTENT("), Walk(x.v), Put(")");
}
void Unparse(const AccessStmt &x) { // R827
Walk(std::get<AccessSpec>(x.t));
Walk(" :: ", std::get<std::list<AccessId>>(x.t), ", ");
}
void Unparse(const AllocatableStmt &x) { // R829
Word("ALLOCATABLE :: "), Walk(x.v, ", ");
}
void Unparse(const ObjectDecl &x) { // R830 & R860
Walk(std::get<ObjectName>(x.t));
Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")");
Walk("[", std::get<std::optional<CoarraySpec>>(x.t), "]");
}
void Unparse(const AsynchronousStmt &x) { // R831
Word("ASYNCHRONOUS :: "), Walk(x.v, ", ");
}
void Unparse(const BindStmt &x) { // R832
Walk(x.t, " :: ");
}
void Unparse(const BindEntity &x) { // R833
bool isCommon{std::get<BindEntity::Kind>(x.t) == BindEntity::Kind::Common};
const char *slash{isCommon ? "/" : ""};
Put(slash), Walk(std::get<Name>(x.t)), Put(slash);
}
void Unparse(const CodimensionStmt &x) { // R834
Word("CODIMENSION :: "), Walk(x.v, ", ");
}
void Unparse(const CodimensionDecl &x) { // R835
Walk(std::get<Name>(x.t));
Put('['), Walk(std::get<CoarraySpec>(x.t)), Put(']');
}
void Unparse(const ContiguousStmt &x) { // R836
Word("CONTIGUOUS :: "), Walk(x.v, ", ");
}
void Unparse(const DataStmt &x) { // R837
Word("DATA "), Walk(x.v, ", ");
}
void Unparse(const DataStmtSet &x) { // R838
Walk(std::get<std::list<DataStmtObject>>(x.t), ", ");
Put('/'), Walk(std::get<std::list<DataStmtValue>>(x.t), ", "), Put('/');
}
void Unparse(const DataImpliedDo &x) { // R840, R842
Put('('), Walk(std::get<std::list<DataIDoObject>>(x.t), ", "), Put(',');
Walk(std::get<std::optional<IntegerTypeSpec>>(x.t), "::");
Walk(std::get<DataImpliedDo::Bounds>(x.t)), Put(')');
}
void Unparse(const DataStmtValue &x) { // R843
Walk(std::get<std::optional<DataStmtRepeat>>(x.t), "*");
Walk(std::get<DataStmtConstant>(x.t));
}
void Unparse(const DimensionStmt &x) { // R848
Word("DIMENSION :: "), Walk(x.v, ", ");
}
void Unparse(const DimensionStmt::Declaration &x) {
Walk(std::get<Name>(x.t));
Put('('), Walk(std::get<ArraySpec>(x.t)), Put(')');
}
void Unparse(const IntentStmt &x) { // R849
Walk(x.t, " :: ");
}
void Unparse(const OptionalStmt &x) { // R850
Word("OPTIONAL :: "), Walk(x.v, ", ");
}
void Unparse(const ParameterStmt &x) { // R851
Word("PARAMETER("), Walk(x.v, ", "), Put(')');
}
void Unparse(const NamedConstantDef &x) { // R852
Walk(x.t, "=");
}
void Unparse(const PointerStmt &x) { // R853
Word("POINTER :: "), Walk(x.v, ", ");
}
void Unparse(const PointerDecl &x) { // R854
Walk(std::get<Name>(x.t));
Walk("(", std::get<std::optional<DeferredShapeSpecList>>(x.t), ")");
}
void Unparse(const ProtectedStmt &x) { // R855
Word("PROTECTED :: "), Walk(x.v, ", ");
}
void Unparse(const SaveStmt &x) { // R856
Word("SAVE"), Walk(" :: ", x.v, ", ");
}
void Unparse(const SavedEntity &x) { // R857, R858
bool isCommon{
std::get<SavedEntity::Kind>(x.t) == SavedEntity::Kind::Common};
const char *slash{isCommon ? "/" : ""};
Put(slash), Walk(std::get<Name>(x.t)), Put(slash);
}
void Unparse(const TargetStmt &x) { // R859
Word("TARGET :: "), Walk(x.v, ", ");
}
void Unparse(const ValueStmt &x) { // R861
Word("VALUE :: "), Walk(x.v, ", ");
}
void Unparse(const VolatileStmt &x) { // R862
Word("VOLATILE :: "), Walk(x.v, ", ");
}
void Unparse(const ImplicitStmt &x) { // R863
Word("IMPLICIT ");
std::visit(common::visitors{
[&](const std::list<ImplicitSpec> &y) { Walk(y, ", "); },
[&](const std::list<ImplicitStmt::ImplicitNoneNameSpec> &y) {
Word("NONE"), Walk(" (", y, ", ", ")");
},
},
x.u);
}
void Unparse(const ImplicitSpec &x) { // R864
Walk(std::get<DeclarationTypeSpec>(x.t));
Put('('), Walk(std::get<std::list<LetterSpec>>(x.t), ", "), Put(')');
}
void Unparse(const LetterSpec &x) { // R865
Put(*std::get<const char *>(x.t));
auto second{std::get<std::optional<const char *>>(x.t)};
if (second) {
Put('-'), Put(**second);
}
}
void Unparse(const ImportStmt &x) { // R867
Word("IMPORT");
switch (x.kind) {
case common::ImportKind::Default:
Walk(" :: ", x.names, ", ");
break;
case common::ImportKind::Only:
Put(", "), Word("ONLY: ");
Walk(x.names, ", ");
break;
case common::ImportKind::None:
Word(", NONE");
break;
case common::ImportKind::All:
Word(", ALL");
break;
}
}
void Unparse(const NamelistStmt &x) { // R868
Word("NAMELIST"), Walk(x.v, ", ");
}
void Unparse(const NamelistStmt::Group &x) {
Put('/'), Walk(std::get<Name>(x.t)), Put('/');
Walk(std::get<std::list<Name>>(x.t), ", ");
}
void Unparse(const EquivalenceStmt &x) { // R870, R871
Word("EQUIVALENCE");
const char *separator{" "};
for (const std::list<EquivalenceObject> &y : x.v) {
Put(separator), Put('('), Walk(y), Put(')');
separator = ", ";
}
}
void Unparse(const CommonStmt &x) { // R873
Word("COMMON ");
Walk(x.blocks);
}
void Unparse(const CommonBlockObject &x) { // R874
Walk(std::get<Name>(x.t));
Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")");
}
void Unparse(const CommonStmt::Block &x) {
Word("/"), Walk(std::get<std::optional<Name>>(x.t)), Word("/");
Walk(std::get<std::list<CommonBlockObject>>(x.t));
}
void Unparse(const Substring &x) { // R908, R909
Walk(std::get<DataRef>(x.t));
Put('('), Walk(std::get<SubstringRange>(x.t)), Put(')');
}
void Unparse(const CharLiteralConstantSubstring &x) {
Walk(std::get<CharLiteralConstant>(x.t));
Put('('), Walk(std::get<SubstringRange>(x.t)), Put(')');
}
void Unparse(const SubstringRange &x) { // R910
Walk(x.t, ":");
}
void Unparse(const PartRef &x) { // R912
Walk(x.name);
Walk("(", x.subscripts, ",", ")");
Walk(x.imageSelector);
}
void Unparse(const StructureComponent &x) { // R913
Walk(x.base);
if (structureComponents_.find(x.component.source) !=
structureComponents_.end()) {
Put('.');
} else {
Put('%');
}
Walk(x.component);
}
void Unparse(const ArrayElement &x) { // R917
Walk(x.base);
Put('('), Walk(x.subscripts, ","), Put(')');
}
void Unparse(const SubscriptTriplet &x) { // R921
Walk(std::get<0>(x.t)), Put(':'), Walk(std::get<1>(x.t));
Walk(":", std::get<2>(x.t));
}
void Unparse(const ImageSelector &x) { // R924
Put('['), Walk(std::get<std::list<Cosubscript>>(x.t), ",");
Walk(",", std::get<std::list<ImageSelectorSpec>>(x.t), ","), Put(']');
}
void Before(const ImageSelectorSpec::Stat &) { // R926
Word("STAT=");
}
void Before(const ImageSelectorSpec::Team_Number &) { Word("TEAM_NUMBER="); }
void Before(const ImageSelectorSpec &x) {
if (std::holds_alternative<TeamValue>(x.u)) {
Word("TEAM=");
}
}
void Unparse(const AllocateStmt &x) { // R927
Word("ALLOCATE(");
Walk(std::get<std::optional<TypeSpec>>(x.t), "::");
Walk(std::get<std::list<Allocation>>(x.t), ", ");
Walk(", ", std::get<std::list<AllocOpt>>(x.t), ", "), Put(')');
}
void Before(const AllocOpt &x) { // R928, R931
std::visit(common::visitors{
[&](const AllocOpt::Mold &) { Word("MOLD="); },
[&](const AllocOpt::Source &) { Word("SOURCE="); },
[](const StatOrErrmsg &) {},
},
x.u);
}
void Unparse(const Allocation &x) { // R932
Walk(std::get<AllocateObject>(x.t));
Walk("(", std::get<std::list<AllocateShapeSpec>>(x.t), ",", ")");
Walk("[", std::get<std::optional<AllocateCoarraySpec>>(x.t), "]");
}
void Unparse(const AllocateShapeSpec &x) { // R934 & R938
Walk(std::get<std::optional<BoundExpr>>(x.t), ":");
Walk(std::get<BoundExpr>(x.t));
}
void Unparse(const AllocateCoarraySpec &x) { // R937
Walk(std::get<std::list<AllocateCoshapeSpec>>(x.t), ",", ",");
Walk(std::get<std::optional<BoundExpr>>(x.t), ":"), Put('*');
}
void Unparse(const NullifyStmt &x) { // R939
Word("NULLIFY("), Walk(x.v, ", "), Put(')');
}
void Unparse(const DeallocateStmt &x) { // R941
Word("DEALLOCATE(");
Walk(std::get<std::list<AllocateObject>>(x.t), ", ");
Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')');
}
void Before(const StatOrErrmsg &x) { // R942 & R1165
std::visit(common::visitors{
[&](const StatVariable &) { Word("STAT="); },
[&](const MsgVariable &) { Word("ERRMSG="); },
},
x.u);
}
// R1001 - R1022
void Unparse(const Expr::Parentheses &x) { Put('('), Walk(x.v), Put(')'); }
void Before(const Expr::UnaryPlus &) { Put("+"); }
void Before(const Expr::Negate &) { Put("-"); }
void Before(const Expr::NOT &) { Word(".NOT."); }
void Unparse(const Expr::PercentLoc &x) {
Word("%LOC("), Walk(x.v), Put(')');
}
void Unparse(const Expr::Power &x) { Walk(x.t, "**"); }
void Unparse(const Expr::Multiply &x) { Walk(x.t, "*"); }
void Unparse(const Expr::Divide &x) { Walk(x.t, "/"); }
void Unparse(const Expr::Add &x) { Walk(x.t, "+"); }
void Unparse(const Expr::Subtract &x) { Walk(x.t, "-"); }
void Unparse(const Expr::Concat &x) { Walk(x.t, "//"); }
void Unparse(const Expr::LT &x) { Walk(x.t, "<"); }
void Unparse(const Expr::LE &x) { Walk(x.t, "<="); }
void Unparse(const Expr::EQ &x) { Walk(x.t, "=="); }
void Unparse(const Expr::NE &x) { Walk(x.t, "/="); }
void Unparse(const Expr::GE &x) { Walk(x.t, ">="); }
void Unparse(const Expr::GT &x) { Walk(x.t, ">"); }
void Unparse(const Expr::AND &x) { Walk(x.t, ".AND."); }
void Unparse(const Expr::OR &x) { Walk(x.t, ".OR."); }
void Unparse(const Expr::EQV &x) { Walk(x.t, ".EQV."); }
void Unparse(const Expr::NEQV &x) { Walk(x.t, ".NEQV."); }
void Unparse(const Expr::ComplexConstructor &x) {
Put('('), Walk(x.t, ","), Put(')');
}
void Unparse(const Expr::DefinedBinary &x) {
Walk(std::get<1>(x.t)); // left
Walk(std::get<DefinedOpName>(x.t));
Walk(std::get<2>(x.t)); // right
}
void Unparse(const DefinedOpName &x) { // R1003, R1023, R1414, & R1415
Walk(x.v);
}
void Unparse(const AssignmentStmt &x) { // R1032
if (asFortran_ && x.typedAssignment.get()) {
Put(' ');
asFortran_->assignment(out_, *x.typedAssignment);
Put('\n');
} else {
Walk(x.t, " = ");
}
}
void Unparse(const PointerAssignmentStmt &x) { // R1033, R1034, R1038
if (asFortran_ && x.typedAssignment.get()) {
Put(' ');
asFortran_->assignment(out_, *x.typedAssignment);
Put('\n');
} else {
Walk(std::get<DataRef>(x.t));
std::visit(
common::visitors{
[&](const std::list<BoundsRemapping> &y) {
Put('('), Walk(y), Put(')');
},
[&](const std::list<BoundsSpec> &y) { Walk("(", y, ", ", ")"); },
},
std::get<PointerAssignmentStmt::Bounds>(x.t).u);
Put(" => "), Walk(std::get<Expr>(x.t));
}
}
void Post(const BoundsSpec &) { // R1035
Put(':');
}
void Unparse(const BoundsRemapping &x) { // R1036
Walk(x.t, ":");
}
void Unparse(const WhereStmt &x) { // R1041, R1045, R1046
Word("WHERE ("), Walk(x.t, ") ");
}
void Unparse(const WhereConstructStmt &x) { // R1043
Walk(std::get<std::optional<Name>>(x.t), ": ");
Word("WHERE ("), Walk(std::get<LogicalExpr>(x.t)), Put(')');
Indent();
}
void Unparse(const MaskedElsewhereStmt &x) { // R1047
Outdent();
Word("ELSEWHERE ("), Walk(std::get<LogicalExpr>(x.t)), Put(')');
Walk(" ", std::get<std::optional<Name>>(x.t));
Indent();
}
void Unparse(const ElsewhereStmt &x) { // R1048
Outdent(), Word("ELSEWHERE"), Walk(" ", x.v), Indent();
}
void Unparse(const EndWhereStmt &x) { // R1049
Outdent(), Word("END WHERE"), Walk(" ", x.v);
}
void Unparse(const ForallConstructStmt &x) { // R1051
Walk(std::get<std::optional<Name>>(x.t), ": ");
Word("FORALL"), Walk(std::get<common::Indirection<ConcurrentHeader>>(x.t));
Indent();
}
void Unparse(const EndForallStmt &x) { // R1054
Outdent(), Word("END FORALL"), Walk(" ", x.v);
}
void Before(const ForallStmt &) { // R1055
Word("FORALL");
}
void Unparse(const AssociateStmt &x) { // R1103
Walk(std::get<std::optional<Name>>(x.t), ": ");
Word("ASSOCIATE (");
Walk(std::get<std::list<Association>>(x.t), ", "), Put(')'), Indent();
}
void Unparse(const Association &x) { // R1104
Walk(x.t, " => ");
}
void Unparse(const EndAssociateStmt &x) { // R1106
Outdent(), Word("END ASSOCIATE"), Walk(" ", x.v);
}
void Unparse(const BlockStmt &x) { // R1108
Walk(x.v, ": "), Word("BLOCK"), Indent();
}
void Unparse(const EndBlockStmt &x) { // R1110
Outdent(), Word("END BLOCK"), Walk(" ", x.v);
}
void Unparse(const ChangeTeamStmt &x) { // R1112
Walk(std::get<std::optional<Name>>(x.t), ": ");
Word("CHANGE TEAM ("), Walk(std::get<TeamValue>(x.t));
Walk(", ", std::get<std::list<CoarrayAssociation>>(x.t), ", ");
Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')');
Indent();
}
void Unparse(const CoarrayAssociation &x) { // R1113
Walk(x.t, " => ");
}
void Unparse(const EndChangeTeamStmt &x) { // R1114
Outdent(), Word("END TEAM (");
Walk(std::get<std::list<StatOrErrmsg>>(x.t), ", ");
Put(')'), Walk(" ", std::get<std::optional<Name>>(x.t));
}
void Unparse(const CriticalStmt &x) { // R1117
Walk(std::get<std::optional<Name>>(x.t), ": ");
Word("CRITICAL ("), Walk(std::get<std::list<StatOrErrmsg>>(x.t), ", ");
Put(')'), Indent();
}
void Unparse(const EndCriticalStmt &x) { // R1118
Outdent(), Word("END CRITICAL"), Walk(" ", x.v);
}
void Unparse(const DoConstruct &x) { // R1119, R1120
Walk(std::get<Statement<NonLabelDoStmt>>(x.t));
Indent(), Walk(std::get<Block>(x.t), ""), Outdent();
Walk(std::get<Statement<EndDoStmt>>(x.t));
}
void Unparse(const LabelDoStmt &x) { // R1121
Walk(std::get<std::optional<Name>>(x.t), ": ");
Word("DO "), Walk(std::get<Label>(x.t));
Walk(" ", std::get<std::optional<LoopControl>>(x.t));
}
void Unparse(const NonLabelDoStmt &x) { // R1122
Walk(std::get<std::optional<Name>>(x.t), ": ");
Word("DO "), Walk(std::get<std::optional<LoopControl>>(x.t));
}
void Unparse(const LoopControl &x) { // R1123
std::visit(common::visitors{
[&](const ScalarLogicalExpr &y) {
Word("WHILE ("), Walk(y), Put(')');
},
[&](const auto &y) { Walk(y); },
},
x.u);
}
void Unparse(const ConcurrentHeader &x) { // R1125
Put('('), Walk(std::get<std::optional<IntegerTypeSpec>>(x.t), "::");
Walk(std::get<std::list<ConcurrentControl>>(x.t), ", ");
Walk(", ", std::get<std::optional<ScalarLogicalExpr>>(x.t)), Put(')');
}
void Unparse(const ConcurrentControl &x) { // R1126 - R1128
Walk(std::get<Name>(x.t)), Put('='), Walk(std::get<1>(x.t));
Put(':'), Walk(std::get<2>(x.t));
Walk(":", std::get<std::optional<ScalarIntExpr>>(x.t));
}
void Before(const LoopControl::Concurrent &) { // R1129
Word("CONCURRENT");
}
void Unparse(const LocalitySpec::Local &x) {
Word("LOCAL("), Walk(x.v, ", "), Put(')');
}
void Unparse(const LocalitySpec::LocalInit &x) {
Word("LOCAL_INIT("), Walk(x.v, ", "), Put(')');
}
void Unparse(const LocalitySpec::Shared &x) {
Word("SHARED("), Walk(x.v, ", "), Put(')');
}
void Post(const LocalitySpec::DefaultNone &) { Word("DEFAULT(NONE)"); }
void Unparse(const EndDoStmt &x) { // R1132
Word("END DO"), Walk(" ", x.v);
}
void Unparse(const CycleStmt &x) { // R1133
Word("CYCLE"), Walk(" ", x.v);
}
void Unparse(const IfThenStmt &x) { // R1135
Walk(std::get<std::optional<Name>>(x.t), ": ");
Word("IF ("), Walk(std::get<ScalarLogicalExpr>(x.t));
Put(") "), Word("THEN"), Indent();
}
void Unparse(const ElseIfStmt &x) { // R1136
Outdent(), Word("ELSE IF (");
Walk(std::get<ScalarLogicalExpr>(x.t)), Put(") "), Word("THEN");
Walk(" ", std::get<std::optional<Name>>(x.t)), Indent();
}
void Unparse(const ElseStmt &x) { // R1137
Outdent(), Word("ELSE"), Walk(" ", x.v), Indent();
}
void Unparse(const EndIfStmt &x) { // R1138
Outdent(), Word("END IF"), Walk(" ", x.v);
}
void Unparse(const IfStmt &x) { // R1139
Word("IF ("), Walk(x.t, ") ");
}
void Unparse(const SelectCaseStmt &x) { // R1141, R1144
Walk(std::get<std::optional<Name>>(x.t), ": ");
Word("SELECT CASE (");
Walk(std::get<Scalar<Expr>>(x.t)), Put(')'), Indent();
}
void Unparse(const CaseStmt &x) { // R1142
Outdent(), Word("CASE "), Walk(std::get<CaseSelector>(x.t));
Walk(" ", std::get<std::optional<Name>>(x.t)), Indent();
}
void Unparse(const EndSelectStmt &x) { // R1143 & R1151 & R1155
Outdent(), Word("END SELECT"), Walk(" ", x.v);
}
void Unparse(const CaseSelector &x) { // R1145
std::visit(common::visitors{
[&](const std::list<CaseValueRange> &y) {
Put('('), Walk(y), Put(')');
},
[&](const Default &) { Word("DEFAULT"); },
},
x.u);
}
void Unparse(const CaseValueRange::Range &x) { // R1146
Walk(x.lower), Put(':'), Walk(x.upper);
}
void Unparse(const SelectRankStmt &x) { // R1149
Walk(std::get<0>(x.t), ": ");
Word("SELECT RANK ("), Walk(std::get<1>(x.t), " => ");
Walk(std::get<Selector>(x.t)), Put(')'), Indent();
}
void Unparse(const SelectRankCaseStmt &x) { // R1150
Outdent(), Word("RANK ");
std::visit(common::visitors{
[&](const ScalarIntConstantExpr &y) {
Put('('), Walk(y), Put(')');
},
[&](const Star &) { Put("(*)"); },
[&](const Default &) { Word("DEFAULT"); },
},
std::get<SelectRankCaseStmt::Rank>(x.t).u);
Walk(" ", std::get<std::optional<Name>>(x.t)), Indent();
}
void Unparse(const SelectTypeStmt &x) { // R1153
Walk(std::get<0>(x.t), ": ");
Word("SELECT TYPE ("), Walk(std::get<1>(x.t), " => ");
Walk(std::get<Selector>(x.t)), Put(')'), Indent();
}
void Unparse(const TypeGuardStmt &x) { // R1154
Outdent(), Walk(std::get<TypeGuardStmt::Guard>(x.t));
Walk(" ", std::get<std::optional<Name>>(x.t)), Indent();
}
void Unparse(const TypeGuardStmt::Guard &x) {
std::visit(
common::visitors{
[&](const TypeSpec &y) { Word("TYPE IS ("), Walk(y), Put(')'); },
[&](const DerivedTypeSpec &y) {
Word("CLASS IS ("), Walk(y), Put(')');
},
[&](const Default &) { Word("CLASS DEFAULT"); },
},
x.u);
}
void Unparse(const ExitStmt &x) { // R1156
Word("EXIT"), Walk(" ", x.v);
}
void Before(const GotoStmt &) { // R1157
Word("GO TO ");
}
void Unparse(const ComputedGotoStmt &x) { // R1158
Word("GO TO ("), Walk(x.t, "), ");
}
void Unparse(const ContinueStmt &) { // R1159
Word("CONTINUE");
}
void Unparse(const StopStmt &x) { // R1160, R1161
if (std::get<StopStmt::Kind>(x.t) == StopStmt::Kind::ErrorStop) {
Word("ERROR ");
}
Word("STOP"), Walk(" ", std::get<std::optional<StopCode>>(x.t));
Walk(", QUIET=", std::get<std::optional<ScalarLogicalExpr>>(x.t));
}
void Unparse(const FailImageStmt &) { // R1163
Word("FAIL IMAGE");
}
void Unparse(const SyncAllStmt &x) { // R1164
Word("SYNC ALL ("), Walk(x.v, ", "), Put(')');
}
void Unparse(const SyncImagesStmt &x) { // R1166
Word("SYNC IMAGES (");
Walk(std::get<SyncImagesStmt::ImageSet>(x.t));
Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')');
}
void Unparse(const SyncMemoryStmt &x) { // R1168
Word("SYNC MEMORY ("), Walk(x.v, ", "), Put(')');
}
void Unparse(const SyncTeamStmt &x) { // R1169
Word("SYNC TEAM ("), Walk(std::get<TeamValue>(x.t));
Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')');
}
void Unparse(const EventPostStmt &x) { // R1170
Word("EVENT POST ("), Walk(std::get<EventVariable>(x.t));
Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')');
}
void Before(const EventWaitStmt::EventWaitSpec &x) { // R1173, R1174
std::visit(common::visitors{
[&](const ScalarIntExpr &) { Word("UNTIL_COUNT="); },
[](const StatOrErrmsg &) {},
},
x.u);
}
void Unparse(const EventWaitStmt &x) { // R1170
Word("EVENT WAIT ("), Walk(std::get<EventVariable>(x.t));
Walk(", ", std::get<std::list<EventWaitStmt::EventWaitSpec>>(x.t), ", ");
Put(')');
}
void Unparse(const FormTeamStmt &x) { // R1175, R1177
Word("FORM TEAM ("), Walk(std::get<ScalarIntExpr>(x.t));
Put(','), Walk(std::get<TeamVariable>(x.t));
Walk(", ", std::get<std::list<FormTeamStmt::FormTeamSpec>>(x.t), ", ");
Put(')');
}
void Before(const FormTeamStmt::FormTeamSpec &x) { // R1176, R1178
std::visit(common::visitors{
[&](const ScalarIntExpr &) { Word("NEW_INDEX="); },
[](const StatOrErrmsg &) {},
},
x.u);
}
void Unparse(const LockStmt &x) { // R1179
Word("LOCK ("), Walk(std::get<LockVariable>(x.t));
Walk(", ", std::get<std::list<LockStmt::LockStat>>(x.t), ", ");
Put(')');
}
void Before(const LockStmt::LockStat &x) { // R1180
std::visit(
common::visitors{
[&](const ScalarLogicalVariable &) { Word("ACQUIRED_LOCK="); },
[](const StatOrErrmsg &) {},
},
x.u);
}
void Unparse(const UnlockStmt &x) { // R1181
Word("UNLOCK ("), Walk(std::get<LockVariable>(x.t));
Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", ");
Put(')');
}
void Unparse(const OpenStmt &x) { // R1204
Word("OPEN ("), Walk(x.v, ", "), Put(')');
}
bool Pre(const ConnectSpec &x) { // R1205
return std::visit(common::visitors{
[&](const FileUnitNumber &) {
Word("UNIT=");
return true;
},
[&](const FileNameExpr &) {
Word("FILE=");
return true;
},
[&](const ConnectSpec::CharExpr &y) {
Walk(y.t, "=");
return false;
},
[&](const MsgVariable &) {
Word("IOMSG=");
return true;
},
[&](const StatVariable &) {
Word("IOSTAT=");
return true;
},
[&](const ConnectSpec::Recl &) {
Word("RECL=");
return true;
},
[&](const ConnectSpec::Newunit &) {
Word("NEWUNIT=");
return true;
},
[&](const ErrLabel &) {
Word("ERR=");
return true;
},
[&](const StatusExpr &) {
Word("STATUS=");
return true;
},
},
x.u);
}
void Unparse(const CloseStmt &x) { // R1208
Word("CLOSE ("), Walk(x.v, ", "), Put(')');
}
void Before(const CloseStmt::CloseSpec &x) { // R1209
std::visit(common::visitors{
[&](const FileUnitNumber &) { Word("UNIT="); },
[&](const StatVariable &) { Word("IOSTAT="); },
[&](const MsgVariable &) { Word("IOMSG="); },
[&](const ErrLabel &) { Word("ERR="); },
[&](const StatusExpr &) { Word("STATUS="); },
},
x.u);
}
void Unparse(const ReadStmt &x) { // R1210
Word("READ ");
if (x.iounit) {
Put('('), Walk(x.iounit);
if (x.format) {
Put(", "), Walk(x.format);
}
Walk(", ", x.controls, ", ");
Put(')');
} else if (x.format) {
Walk(x.format);
if (!x.items.empty()) {
Put(", ");
}
} else {
Put('('), Walk(x.controls, ", "), Put(')');
}
Walk(" ", x.items, ", ");
}
void Unparse(const WriteStmt &x) { // R1211
Word("WRITE (");
if (x.iounit) {
Walk(x.iounit);
if (x.format) {
Put(", "), Walk(x.format);
}
Walk(", ", x.controls, ", ");
} else {
Walk(x.controls, ", ");
}
Put(')'), Walk(" ", x.items, ", ");
}
void Unparse(const PrintStmt &x) { // R1212
Word("PRINT "), Walk(std::get<Format>(x.t));
Walk(", ", std::get<std::list<OutputItem>>(x.t), ", ");
}
bool Pre(const IoControlSpec &x) { // R1213
return std::visit(common::visitors{
[&](const IoUnit &) {
Word("UNIT=");
return true;
},
[&](const Format &) {
Word("FMT=");
return true;
},
[&](const Name &) {
Word("NML=");
return true;
},
[&](const IoControlSpec::CharExpr &y) {
Walk(y.t, "=");
return false;
},
[&](const IoControlSpec::Asynchronous &) {
Word("ASYNCHRONOUS=");
return true;
},
[&](const EndLabel &) {
Word("END=");
return true;
},
[&](const EorLabel &) {
Word("EOR=");
return true;
},
[&](const ErrLabel &) {
Word("ERR=");
return true;
},
[&](const IdVariable &) {
Word("ID=");
return true;
},
[&](const MsgVariable &) {
Word("IOMSG=");
return true;
},
[&](const StatVariable &) {
Word("IOSTAT=");
return true;
},
[&](const IoControlSpec::Pos &) {
Word("POS=");
return true;
},
[&](const IoControlSpec::Rec &) {
Word("REC=");
return true;
},
[&](const IoControlSpec::Size &) {
Word("SIZE=");
return true;
},
},
x.u);
}
void Unparse(const InputImpliedDo &x) { // R1218
Put('('), Walk(std::get<std::list<InputItem>>(x.t), ", "), Put(", ");
Walk(std::get<IoImpliedDoControl>(x.t)), Put(')');
}
void Unparse(const OutputImpliedDo &x) { // R1219
Put('('), Walk(std::get<std::list<OutputItem>>(x.t), ", "), Put(", ");
Walk(std::get<IoImpliedDoControl>(x.t)), Put(')');
}
void Unparse(const WaitStmt &x) { // R1222
Word("WAIT ("), Walk(x.v, ", "), Put(')');
}
void Before(const WaitSpec &x) { // R1223
std::visit(common::visitors{
[&](const FileUnitNumber &) { Word("UNIT="); },
[&](const EndLabel &) { Word("END="); },
[&](const EorLabel &) { Word("EOR="); },
[&](const ErrLabel &) { Word("ERR="); },
[&](const IdExpr &) { Word("ID="); },
[&](const MsgVariable &) { Word("IOMSG="); },
[&](const StatVariable &) { Word("IOSTAT="); },
},
x.u);
}
void Unparse(const BackspaceStmt &x) { // R1224
Word("BACKSPACE ("), Walk(x.v, ", "), Put(')');
}
void Unparse(const EndfileStmt &x) { // R1225
Word("ENDFILE ("), Walk(x.v, ", "), Put(')');
}
void Unparse(const RewindStmt &x) { // R1226
Word("REWIND ("), Walk(x.v, ", "), Put(')');
}
void Before(const PositionOrFlushSpec &x) { // R1227 & R1229
std::visit(common::visitors{
[&](const FileUnitNumber &) { Word("UNIT="); },
[&](const MsgVariable &) { Word("IOMSG="); },
[&](const StatVariable &) { Word("IOSTAT="); },
[&](const ErrLabel &) { Word("ERR="); },
},
x.u);
}
void Unparse(const FlushStmt &x) { // R1228
Word("FLUSH ("), Walk(x.v, ", "), Put(')');
}
void Unparse(const InquireStmt &x) { // R1230
Word("INQUIRE (");
std::visit(
common::visitors{
[&](const InquireStmt::Iolength &y) {
Word("IOLENGTH="), Walk(y.t, ") ");
},
[&](const std::list<InquireSpec> &y) { Walk(y, ", "), Put(')'); },
},
x.u);
}
bool Pre(const InquireSpec &x) { // R1231
return std::visit(common::visitors{
[&](const FileUnitNumber &) {
Word("UNIT=");
return true;
},
[&](const FileNameExpr &) {
Word("FILE=");
return true;
},
[&](const InquireSpec::CharVar &y) {
Walk(y.t, "=");
return false;
},
[&](const InquireSpec::IntVar &y) {
Walk(y.t, "=");
return false;
},
[&](const InquireSpec::LogVar &y) {
Walk(y.t, "=");
return false;
},
[&](const IdExpr &) {
Word("ID=");
return true;
},
[&](const ErrLabel &) {
Word("ERR=");
return true;
},
},
x.u);
}
void Before(const FormatStmt &) { // R1301
Word("FORMAT");
}
void Unparse(const format::FormatSpecification &x) { // R1302, R1303, R1305
Put('('), Walk("", x.items, ",", x.unlimitedItems.empty() ? "" : ",");
Walk("*(", x.unlimitedItems, ",", ")"), Put(')');
}
void Unparse(const format::FormatItem &x) { // R1304, R1306, R1321
if (x.repeatCount) {
Walk(*x.repeatCount);
}
std::visit(common::visitors{
[&](const std::string &y) { PutNormalized(y); },
[&](const std::list<format::FormatItem> &y) {
Walk("(", y, ",", ")");
},
[&](const auto &y) { Walk(y); },
},
x.u);
}
void Unparse(
const format::IntrinsicTypeDataEditDesc &x) { // R1307(1/2) - R1311
switch (x.kind) {
#define FMT(x) \
case format::IntrinsicTypeDataEditDesc::Kind::x: \
Put(#x); \
break
FMT(I);
FMT(B);
FMT(O);
FMT(Z);
FMT(F);
FMT(E);
FMT(EN);
FMT(ES);
FMT(EX);
FMT(G);
FMT(L);
FMT(A);
FMT(D);
#undef FMT
}
Walk(x.width), Walk(".", x.digits), Walk("E", x.exponentWidth);
}
void Unparse(const format::DerivedTypeDataEditDesc &x) { // R1307(2/2), R1312
Word("DT");
if (!x.type.empty()) {
Put('"'), Put(x.type), Put('"');
}
Walk("(", x.parameters, ",", ")");
}
void Unparse(const format::ControlEditDesc &x) { // R1313, R1315-R1320
switch (x.kind) {
case format::ControlEditDesc::Kind::T:
Word("T");
Walk(x.count);
break;
case format::ControlEditDesc::Kind::TL:
Word("TL");
Walk(x.count);
break;
case format::ControlEditDesc::Kind::TR:
Word("TR");
Walk(x.count);
break;
case format::ControlEditDesc::Kind::X:
if (x.count != 1) {
Walk(x.count);
}
Word("X");
break;
case format::ControlEditDesc::Kind::Slash:
if (x.count != 1) {
Walk(x.count);
}
Put('/');
break;
case format::ControlEditDesc::Kind::Colon:
Put(':');
break;
case format::ControlEditDesc::Kind::P:
Walk(x.count);
Word("P");
break;
#define FMT(x) \
case format::ControlEditDesc::Kind::x: \
Put(#x); \
break
FMT(SS);
FMT(SP);
FMT(S);
FMT(BN);
FMT(BZ);
FMT(RU);
FMT(RD);
FMT(RZ);
FMT(RN);
FMT(RC);
FMT(RP);
FMT(DC);
FMT(DP);
#undef FMT
case format::ControlEditDesc::Kind::Dollar:
Put('$');
break;
case format::ControlEditDesc::Kind::Backslash:
Put('\\');
break;
}
}
void Before(const MainProgram &x) { // R1401
if (!std::get<std::optional<Statement<ProgramStmt>>>(x.t)) {
Indent();
}
}
void Before(const ProgramStmt &) { // R1402
Word("PROGRAM "), Indent();
}
void Unparse(const EndProgramStmt &x) { // R1403
EndSubprogram("PROGRAM", x.v);
}
void Before(const ModuleStmt &) { // R1405
Word("MODULE "), Indent();
}
void Unparse(const EndModuleStmt &x) { // R1406
EndSubprogram("MODULE", x.v);
}
void Unparse(const UseStmt &x) { // R1409
Word("USE"), Walk(", ", x.nature), Put(" :: "), Walk(x.moduleName);
std::visit(common::visitors{
[&](const std::list<Rename> &y) { Walk(", ", y, ", "); },
[&](const std::list<Only> &y) { Walk(", ONLY: ", y, ", "); },
},
x.u);
}
void Unparse(const Rename &x) { // R1411
std::visit(common::visitors{
[&](const Rename::Names &y) { Walk(y.t, " => "); },
[&](const Rename::Operators &y) {
Word("OPERATOR("), Walk(y.t, ") => OPERATOR("), Put(")");
},
},
x.u);
}
void Unparse(const SubmoduleStmt &x) { // R1417
Word("SUBMODULE ("), WalkTupleElements(x.t, ")"), Indent();
}
void Unparse(const ParentIdentifier &x) { // R1418
Walk(std::get<Name>(x.t)), Walk(":", std::get<std::optional<Name>>(x.t));
}
void Unparse(const EndSubmoduleStmt &x) { // R1419
EndSubprogram("SUBMODULE", x.v);
}
void Unparse(const BlockDataStmt &x) { // R1421
Word("BLOCK DATA"), Walk(" ", x.v), Indent();
}
void Unparse(const EndBlockDataStmt &x) { // R1422
EndSubprogram("BLOCK DATA", x.v);
}
void Unparse(const InterfaceStmt &x) { // R1503
std::visit(common::visitors{
[&](const std::optional<GenericSpec> &y) {
Word("INTERFACE"), Walk(" ", y);
},
[&](const Abstract &) { Word("ABSTRACT INTERFACE"); },
},
x.u);
Indent();
}
void Unparse(const EndInterfaceStmt &x) { // R1504
Outdent(), Word("END INTERFACE"), Walk(" ", x.v);
}
void Unparse(const ProcedureStmt &x) { // R1506
if (std::get<ProcedureStmt::Kind>(x.t) ==
ProcedureStmt::Kind::ModuleProcedure) {
Word("MODULE ");
}
Word("PROCEDURE :: ");
Walk(std::get<std::list<Name>>(x.t), ", ");
}
void Before(const GenericSpec &x) { // R1508, R1509
std::visit(
common::visitors{
[&](const DefinedOperator &) { Word("OPERATOR("); },
[&](const GenericSpec::Assignment &) { Word("ASSIGNMENT(=)"); },
[&](const GenericSpec::ReadFormatted &) {
Word("READ(FORMATTED)");
},
[&](const GenericSpec::ReadUnformatted &) {
Word("READ(UNFORMATTED)");
},
[&](const GenericSpec::WriteFormatted &) {
Word("WRITE(FORMATTED)");
},
[&](const GenericSpec::WriteUnformatted &) {
Word("WRITE(UNFORMATTED)");
},
[](const auto &) {},
},
x.u);
}
void Post(const GenericSpec &x) {
std::visit(common::visitors{
[&](const DefinedOperator &) { Put(')'); },
[](const auto &) {},
},
x.u);
}
void Unparse(const GenericStmt &x) { // R1510
Word("GENERIC"), Walk(", ", std::get<std::optional<AccessSpec>>(x.t));
Put(" :: "), Walk(std::get<GenericSpec>(x.t)), Put(" => ");
Walk(std::get<std::list<Name>>(x.t), ", ");
}
void Unparse(const ExternalStmt &x) { // R1511
Word("EXTERNAL :: "), Walk(x.v, ", ");
}
void Unparse(const ProcedureDeclarationStmt &x) { // R1512
Word("PROCEDURE("), Walk(std::get<std::optional<ProcInterface>>(x.t));
Put(')'), Walk(", ", std::get<std::list<ProcAttrSpec>>(x.t), ", ");
Put(" :: "), Walk(std::get<std::list<ProcDecl>>(x.t), ", ");
}
void Unparse(const ProcDecl &x) { // R1515
Walk(std::get<Name>(x.t));
Walk(" => ", std::get<std::optional<ProcPointerInit>>(x.t));
}
void Unparse(const IntrinsicStmt &x) { // R1519
Word("INTRINSIC :: "), Walk(x.v, ", ");
}
void Unparse(const FunctionReference &x) { // R1520
Walk(std::get<ProcedureDesignator>(x.v.t));
Put('('), Walk(std::get<std::list<ActualArgSpec>>(x.v.t), ", "), Put(')');
}
void Unparse(const CallStmt &x) { // R1521
if (asFortran_ && x.typedCall.get()) {
Put(' ');
asFortran_->call(out_, *x.typedCall);
Put('\n');
} else {
const auto &pd{std::get<ProcedureDesignator>(x.v.t)};
const auto &args{std::get<std::list<ActualArgSpec>>(x.v.t)};
Word("CALL "), Walk(pd);
if (args.empty()) {
if (std::holds_alternative<ProcComponentRef>(pd.u)) {
Put("()"); // pgf90 crashes on CALL to tbp without parentheses
}
} else {
Walk("(", args, ", ", ")");
}
}
}
void Unparse(const ActualArgSpec &x) { // R1523
Walk(std::get<std::optional<Keyword>>(x.t), "=");
Walk(std::get<ActualArg>(x.t));
}
void Unparse(const ActualArg::PercentRef &x) { // R1524
Word("%REF("), Walk(x.v), Put(')');
}
void Unparse(const ActualArg::PercentVal &x) {
Word("%VAL("), Walk(x.v), Put(')');
}
void Before(const AltReturnSpec &) { // R1525
Put('*');
}
void Post(const PrefixSpec::Elemental) { Word("ELEMENTAL"); } // R1527
void Post(const PrefixSpec::Impure) { Word("IMPURE"); }
void Post(const PrefixSpec::Module) { Word("MODULE"); }
void Post(const PrefixSpec::Non_Recursive) { Word("NON_RECURSIVE"); }
void Post(const PrefixSpec::Pure) { Word("PURE"); }
void Post(const PrefixSpec::Recursive) { Word("RECURSIVE"); }
void Unparse(const FunctionStmt &x) { // R1530
Walk("", std::get<std::list<PrefixSpec>>(x.t), " ", " ");
Word("FUNCTION "), Walk(std::get<Name>(x.t)), Put("(");
Walk(std::get<std::list<Name>>(x.t), ", "), Put(')');
Walk(" ", std::get<std::optional<Suffix>>(x.t)), Indent();
}
void Unparse(const Suffix &x) { // R1532
if (x.resultName) {
Word("RESULT("), Walk(x.resultName), Put(')');
Walk(" ", x.binding);
} else {
Walk(x.binding);
}
}
void Unparse(const EndFunctionStmt &x) { // R1533
EndSubprogram("FUNCTION", x.v);
}
void Unparse(const SubroutineStmt &x) { // R1535
Walk("", std::get<std::list<PrefixSpec>>(x.t), " ", " ");
Word("SUBROUTINE "), Walk(std::get<Name>(x.t));
const auto &args{std::get<std::list<DummyArg>>(x.t)};
const auto &bind{std::get<std::optional<LanguageBindingSpec>>(x.t)};
if (args.empty()) {
Walk(" () ", bind);
} else {
Walk(" (", args, ", ", ")");
Walk(" ", bind);
}
Indent();
}
void Unparse(const EndSubroutineStmt &x) { // R1537
EndSubprogram("SUBROUTINE", x.v);
}
void Before(const MpSubprogramStmt &) { // R1539
Word("MODULE PROCEDURE "), Indent();
}
void Unparse(const EndMpSubprogramStmt &x) { // R1540
EndSubprogram("PROCEDURE", x.v);
}
void Unparse(const EntryStmt &x) { // R1541
Word("ENTRY "), Walk(std::get<Name>(x.t)), Put("(");
Walk(std::get<std::list<DummyArg>>(x.t), ", "), Put(")");
Walk(" ", std::get<std::optional<Suffix>>(x.t));
}
void Unparse(const ReturnStmt &x) { // R1542
Word("RETURN"), Walk(" ", x.v);
}
void Unparse(const ContainsStmt &) { // R1543
Outdent();
Word("CONTAINS");
Indent();
}
void Unparse(const StmtFunctionStmt &x) { // R1544
Walk(std::get<Name>(x.t)), Put('(');
Walk(std::get<std::list<Name>>(x.t), ", "), Put(") = ");
Walk(std::get<Scalar<Expr>>(x.t));
}
// Directives, extensions, and deprecated constructs
void Unparse(const CompilerDirective &x) {
std::visit(
common::visitors{
[&](const std::list<CompilerDirective::IgnoreTKR> &tkr) {
Word("!DIR$ IGNORE_TKR"); // emitted even if tkr list is empty
Walk(" ", tkr, ", ");
},
[&](const std::list<CompilerDirective::NameValue> &names) {
Walk("!DIR$ ", names, " ");
},
},
x.u);
Put('\n');
}
void Unparse(const CompilerDirective::IgnoreTKR &x) {
const auto &list{std::get<std::list<const char *>>(x.t)};
if (!list.empty()) {
Put("(");
for (const char *tkr : list) {
Put(*tkr);
}
Put(") ");
}
Walk(std::get<Name>(x.t));
}
void Unparse(const CompilerDirective::NameValue &x) {
Walk(std::get<Name>(x.t));
Walk("=", std::get<std::optional<std::uint64_t>>(x.t));
}
// OpenACC Directives & Clauses
void Unparse(const AccAtomicCapture &x) {
BeginOpenACC();
Word("!$ACC CAPTURE");
Put("\n");
EndOpenACC();
Walk(std::get<AccAtomicCapture::Stmt1>(x.t));
Put("\n");
Walk(std::get<AccAtomicCapture::Stmt2>(x.t));
BeginOpenACC();
Word("!$ACC END ATOMIC\n");
EndOpenACC();
}
void Unparse(const AccAtomicRead &x) {
BeginOpenACC();
Word("!$ACC ATOMIC READ");
Put("\n");
EndOpenACC();
Walk(std::get<Statement<AssignmentStmt>>(x.t));
BeginOpenACC();
Walk(std::get<std::optional<AccEndAtomic>>(x.t), "!$ACC END ATOMIC\n");
EndOpenACC();
}
void Unparse(const AccAtomicWrite &x) {
BeginOpenACC();
Word("!$ACC ATOMIC WRITE");
Put("\n");
EndOpenACC();
Walk(std::get<Statement<AssignmentStmt>>(x.t));
BeginOpenACC();
Walk(std::get<std::optional<AccEndAtomic>>(x.t), "!$ACC END ATOMIC\n");
EndOpenACC();
}
void Unparse(const AccAtomicUpdate &x) {
BeginOpenACC();
Word("!$ACC ATOMIC UPDATE");
Put("\n");
EndOpenACC();
Walk(std::get<Statement<AssignmentStmt>>(x.t));
BeginOpenACC();
Walk(std::get<std::optional<AccEndAtomic>>(x.t), "!$ACC END ATOMIC\n");
EndOpenACC();
}
void Unparse(const llvm::acc::Directive &x) {
Word(llvm::acc::getOpenACCDirectiveName(x).str());
}
#define GEN_FLANG_CLAUSE_UNPARSE
#include "llvm/Frontend/OpenACC/ACC.inc"
void Unparse(const AccObjectListWithModifier &x) {
Walk(std::get<std::optional<AccDataModifier>>(x.t), ":");
Walk(std::get<AccObjectList>(x.t));
}
void Unparse(const AccDataModifier::Modifier &x) {
Word(AccDataModifier::EnumToString(x));
}
void Unparse(const AccBindClause &x) {
std::visit(common::visitors{
[&](const Name &y) { Put('('), Walk(y), Put(')'); },
[&](const ScalarDefaultCharExpr &y) {
Put('('), Walk(y), Put(')');
},
},
x.u);
}
void Unparse(const AccDefaultClause &x) {
switch (x.v) {
case llvm::acc::DefaultValue::ACC_Default_none:
Put("NONE");
break;
case llvm::acc::DefaultValue::ACC_Default_present:
Put("PRESENT");
break;
}
}
void Unparse(const AccClauseList &x) { Walk(" ", x.v, " "); }
void Unparse(const AccGangArgument &x) {
Walk("NUM:", std::get<std::optional<ScalarIntExpr>>(x.t));
Walk(", STATIC:", std::get<std::optional<AccSizeExpr>>(x.t));
}
void Unparse(const OpenACCBlockConstruct &x) {
BeginOpenACC();
Word("!$ACC ");
Walk(std::get<AccBeginBlockDirective>(x.t));
Put("\n");
EndOpenACC();
Walk(std::get<Block>(x.t), "");
BeginOpenACC();
Word("!$ACC END ");
Walk(std::get<AccEndBlockDirective>(x.t));
Put("\n");
EndOpenACC();
}
void Unparse(const OpenACCLoopConstruct &x) {
BeginOpenACC();
Word("!$ACC ");
Walk(std::get<AccBeginLoopDirective>(x.t));
Put("\n");
EndOpenACC();
Walk(std::get<std::optional<DoConstruct>>(x.t));
}
void Unparse(const AccBeginLoopDirective &x) {
Walk(std::get<AccLoopDirective>(x.t));
Walk(std::get<AccClauseList>(x.t));
}
void Unparse(const OpenACCStandaloneConstruct &x) {
BeginOpenACC();
Word("!$ACC ");
Walk(std::get<AccStandaloneDirective>(x.t));
Walk(std::get<AccClauseList>(x.t));
Put("\n");
EndOpenACC();
}
void Unparse(const OpenACCStandaloneDeclarativeConstruct &x) {
BeginOpenACC();
Word("!$ACC ");
Walk(std::get<AccDeclarativeDirective>(x.t));
Walk(std::get<AccClauseList>(x.t));
Put("\n");
EndOpenACC();
}
void Unparse(const OpenACCCombinedConstruct &x) {
BeginOpenACC();
Word("!$ACC ");
Walk(std::get<AccBeginCombinedDirective>(x.t));
Put("\n");
EndOpenACC();
Walk(std::get<std::optional<DoConstruct>>(x.t));
BeginOpenACC();
Walk("!$ACC END ", std::get<std::optional<AccEndCombinedDirective>>(x.t),
"\n");
EndOpenACC();
}
void Unparse(const OpenACCRoutineConstruct &x) {
BeginOpenACC();
Word("!$ACC ROUTINE");
Walk("(", std::get<std::optional<Name>>(x.t), ")");
Walk(std::get<AccClauseList>(x.t));
Put("\n");
EndOpenACC();
}
void Unparse(const AccObject &x) {
std::visit(common::visitors{
[&](const Designator &y) { Walk(y); },
[&](const Name &y) { Put("/"), Walk(y), Put("/"); },
},
x.u);
}
void Unparse(const AccObjectList &x) { Walk(x.v, ","); }
void Unparse(const AccReductionOperator::Operator &x) {
Word(AccReductionOperator::EnumToString(x));
}
void Unparse(const AccObjectListWithReduction &x) {
Walk(std::get<AccReductionOperator>(x.t));
Put(":");
Walk(std::get<AccObjectList>(x.t));
}
void Unparse(const OpenACCCacheConstruct &x) {
BeginOpenACC();
Word("!$ACC ");
Word("CACHE(");
Walk(std::get<AccObjectListWithModifier>(x.t));
Put(")");
Put("\n");
EndOpenACC();
}
void Unparse(const AccWaitArgument &x) {
Walk("DEVNUM:", std::get<std::optional<ScalarIntExpr>>(x.t), ":");
Walk(std::get<std::list<ScalarIntExpr>>(x.t), ",");
}
void Unparse(const OpenACCWaitConstruct &x) {
BeginOpenACC();
Word("!$ACC ");
Word("WAIT(");
Walk(std::get<std::optional<AccWaitArgument>>(x.t));
Walk(std::get<AccClauseList>(x.t));
Put(")");
Put("\n");
EndOpenACC();
}
// OpenMP Clauses & Directives
void Unparse(const OmpObject &x) {
std::visit(common::visitors{
[&](const Designator &y) { Walk(y); },
[&](const Name &y) { Put("/"), Walk(y), Put("/"); },
},
x.u);
}
void Unparse(const OmpMapType::Always &) { Word("ALWAYS,"); }
void Unparse(const OmpMapClause &x) {
Walk(std::get<std::optional<OmpMapType>>(x.t), ":");
Walk(std::get<OmpObjectList>(x.t));
}
void Unparse(const OmpScheduleModifier &x) {
Walk(std::get<OmpScheduleModifier::Modifier1>(x.t));
Walk(",", std::get<std::optional<OmpScheduleModifier::Modifier2>>(x.t));
}
void Unparse(const OmpScheduleClause &x) {
Walk(std::get<std::optional<OmpScheduleModifier>>(x.t), ":");
Walk(std::get<OmpScheduleClause::ScheduleType>(x.t));
Walk(",", std::get<std::optional<ScalarIntExpr>>(x.t));
}
void Unparse(const OmpAlignedClause &x) {
Walk(std::get<std::list<Name>>(x.t), ",");
Walk(std::get<std::optional<ScalarIntConstantExpr>>(x.t));
}
void Unparse(const OmpIfClause &x) {
Walk(std::get<std::optional<OmpIfClause::DirectiveNameModifier>>(x.t), ":");
Walk(std::get<ScalarLogicalExpr>(x.t));
}
void Unparse(const OmpLinearClause::WithoutModifier &x) {
Walk(x.names, ", ");
Walk(":", x.step);
}
void Unparse(const OmpLinearClause::WithModifier &x) {
Walk(x.modifier), Put("("), Walk(x.names, ","), Put(")");
Walk(":", x.step);
}
void Unparse(const OmpReductionClause &x) {
Walk(std::get<OmpReductionOperator>(x.t));
Put(":");
Walk(std::get<OmpObjectList>(x.t));
}
void Unparse(const OmpAllocateClause &x) {
Walk(std::get<std::optional<OmpAllocateClause::Allocator>>(x.t));
Put(":");
Walk(std::get<OmpObjectList>(x.t));
}
void Unparse(const OmpDependSinkVecLength &x) {
Walk(std::get<DefinedOperator>(x.t));
Walk(std::get<ScalarIntConstantExpr>(x.t));
}
void Unparse(const OmpDependSinkVec &x) {
Walk(std::get<Name>(x.t));
Walk(std::get<std::optional<OmpDependSinkVecLength>>(x.t));
}
void Unparse(const OmpDependClause::InOut &x) {
Put("(");
Walk(std::get<OmpDependenceType>(x.t));
Put(":");
Walk(std::get<std::list<Designator>>(x.t), ",");
Put(")");
}
bool Pre(const OmpDependClause &x) {
return std::visit(common::visitors{
[&](const OmpDependClause::Source &) {
Word("SOURCE");
return false;
},
[&](const OmpDependClause::Sink &y) {
Word("SINK:");
Walk(y.v);
Put(")");
return false;
},
[&](const OmpDependClause::InOut &) { return true; },
},
x.u);
}
void Unparse(const OmpDefaultmapClause &x) {
Walk(std::get<OmpDefaultmapClause::ImplicitBehavior>(x.t));
Walk(":",
std::get<std::optional<OmpDefaultmapClause::VariableCategory>>(x.t));
}
#define GEN_FLANG_CLAUSE_UNPARSE
#include "llvm/Frontend/OpenMP/OMP.inc"
void Unparse(const OmpLoopDirective &x) {
switch (x.v) {
case llvm::omp::Directive::OMPD_distribute:
Word("DISTRIBUTE ");
break;
case llvm::omp::Directive::OMPD_distribute_parallel_do:
Word("DISTRIBUTE PARALLEL DO ");
break;
case llvm::omp::Directive::OMPD_distribute_parallel_do_simd:
Word("DISTRIBUTE PARALLEL DO SIMD ");
break;
case llvm::omp::Directive::OMPD_distribute_simd:
Word("DISTRIBUTE SIMD ");
break;
case llvm::omp::Directive::OMPD_do:
Word("DO ");
break;
case llvm::omp::Directive::OMPD_do_simd:
Word("DO SIMD ");
break;
case llvm::omp::Directive::OMPD_parallel_do:
Word("PARALLEL DO ");
break;
case llvm::omp::Directive::OMPD_parallel_do_simd:
Word("PARALLEL DO SIMD ");
break;
case llvm::omp::Directive::OMPD_simd:
Word("SIMD ");
break;
case llvm::omp::Directive::OMPD_target_parallel_do:
Word("TARGET PARALLEL DO ");
break;
case llvm::omp::Directive::OMPD_target_parallel_do_simd:
Word("TARGET PARALLEL DO SIMD ");
break;
case llvm::omp::Directive::OMPD_target_teams_distribute:
Word("TARGET TEAMS DISTRIBUTE ");
break;
case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do:
Word("TARGET TEAMS DISTRIBUTE PARALLEL DO ");
break;
case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do_simd:
Word("TARGET TEAMS DISTRIBUTE PARALLEL DO SIMD ");
break;
case llvm::omp::Directive::OMPD_target_teams_distribute_simd:
Word("TARGET TEAMS DISTRIBUTE SIMD ");
break;
case llvm::omp::Directive::OMPD_target_simd:
Word("TARGET SIMD ");
break;
case llvm::omp::Directive::OMPD_taskloop:
Word("TASKLOOP ");
break;
case llvm::omp::Directive::OMPD_taskloop_simd:
Word("TASKLOOP SIMD ");
break;
case llvm::omp::Directive::OMPD_teams_distribute:
Word("TEAMS DISTRIBUTE ");
break;
case llvm::omp::Directive::OMPD_teams_distribute_parallel_do:
Word("TEAMS DISTRIBUTE PARALLEL DO ");
break;
case llvm::omp::Directive::OMPD_teams_distribute_parallel_do_simd:
Word("TEAMS DISTRIBUTE PARALLEL DO SIMD ");
break;
case llvm::omp::Directive::OMPD_teams_distribute_simd:
Word("TEAMS DISTRIBUTE SIMD ");
break;
default:
break;
}
}
void Unparse(const OmpObjectList &x) { Walk(x.v, ","); }
void Unparse(const OmpSimpleStandaloneDirective &x) {
switch (x.v) {
case llvm::omp::Directive::OMPD_barrier:
Word("BARRIER ");
break;
case llvm::omp::Directive::OMPD_taskwait:
Word("TASKWAIT ");
break;
case llvm::omp::Directive::OMPD_taskyield:
Word("TASKYIELD ");
break;
case llvm::omp::Directive::OMPD_target_enter_data:
Word("TARGET ENTER DATA ");
break;
case llvm::omp::Directive::OMPD_target_exit_data:
Word("TARGET EXIT DATA ");
break;
case llvm::omp::Directive::OMPD_target_update:
Word("TARGET UPDATE ");
break;
case llvm::omp::Directive::OMPD_ordered:
Word("ORDERED ");
break;
default:
// Nothing to be done
break;
}
}
void Unparse(const OmpBlockDirective &x) {
switch (x.v) {
case llvm::omp::Directive::OMPD_master:
Word("MASTER");
break;
case llvm::omp::Directive::OMPD_ordered:
Word("ORDERED ");
break;
case llvm::omp::Directive::OMPD_parallel_workshare:
Word("PARALLEL WORKSHARE ");
break;
case llvm::omp::Directive::OMPD_parallel:
Word("PARALLEL ");
break;
case llvm::omp::Directive::OMPD_single:
Word("SINGLE ");
break;
case llvm::omp::Directive::OMPD_target_data:
Word("TARGET DATA ");
break;
case llvm::omp::Directive::OMPD_target_parallel:
Word("TARGET PARALLEL ");
break;
case llvm::omp::Directive::OMPD_target_teams:
Word("TARGET TEAMS ");
break;
case llvm::omp::Directive::OMPD_target:
Word("TARGET ");
break;
case llvm::omp::Directive::OMPD_taskgroup:
Word("TASKGROUP ");
break;
case llvm::omp::Directive::OMPD_task:
Word("TASK ");
break;
case llvm::omp::Directive::OMPD_teams:
Word("TEAMS ");
break;
case llvm::omp::Directive::OMPD_workshare:
Word("WORKSHARE ");
break;
default:
// Nothing to be done
break;
}
}
void Unparse(const OmpAtomicClauseList &x) { Walk(" ", x.v, " "); }
void Unparse(const OmpAtomic &x) {
BeginOpenMP();
Word("!$OMP ATOMIC");
Walk(std::get<OmpAtomicClauseList>(x.t));
Put("\n");
EndOpenMP();
Walk(std::get<Statement<AssignmentStmt>>(x.t));
BeginOpenMP();
Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n");
EndOpenMP();
}
void Unparse(const OmpAtomicCapture &x) {
BeginOpenMP();
Word("!$OMP ATOMIC");
Walk(std::get<0>(x.t));
Word(" CAPTURE");
Walk(std::get<2>(x.t));
Put("\n");
EndOpenMP();
Walk(std::get<OmpAtomicCapture::Stmt1>(x.t));
Put("\n");
Walk(std::get<OmpAtomicCapture::Stmt2>(x.t));
BeginOpenMP();
Word("!$OMP END ATOMIC\n");
EndOpenMP();
}
void Unparse(const OmpAtomicRead &x) {
BeginOpenMP();
Word("!$OMP ATOMIC");
Walk(std::get<0>(x.t));
Word(" READ");
Walk(std::get<2>(x.t));
Put("\n");
EndOpenMP();
Walk(std::get<Statement<AssignmentStmt>>(x.t));
BeginOpenMP();
Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n");
EndOpenMP();
}
void Unparse(const OmpAtomicUpdate &x) {
BeginOpenMP();
Word("!$OMP ATOMIC");
Walk(std::get<0>(x.t));
Word(" UPDATE");
Walk(std::get<2>(x.t));
Put("\n");
EndOpenMP();
Walk(std::get<Statement<AssignmentStmt>>(x.t));
BeginOpenMP();
Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n");
EndOpenMP();
}
void Unparse(const OmpAtomicWrite &x) {
BeginOpenMP();
Word("!$OMP ATOMIC");
Walk(std::get<0>(x.t));
Word(" WRITE");
Walk(std::get<2>(x.t));
Put("\n");
EndOpenMP();
Walk(std::get<Statement<AssignmentStmt>>(x.t));
BeginOpenMP();
Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n");
EndOpenMP();
}
void Unparse(const OpenMPExecutableAllocate &x) {
BeginOpenMP();
Word("!$OMP ALLOCATE");
Walk(" (", std::get<std::optional<OmpObjectList>>(x.t), ")");
Walk(std::get<OmpClauseList>(x.t));
Put("\n");
EndOpenMP();
Walk(std::get<Statement<AllocateStmt>>(x.t));
}
void Unparse(const OpenMPDeclarativeAllocate &x) {
BeginOpenMP();
Word("!$OMP ALLOCATE");
Put(" (");
Walk(std::get<OmpObjectList>(x.t));
Put(")");
Walk(std::get<OmpClauseList>(x.t));
Put("\n");
EndOpenMP();
}
void Unparse(const OmpCriticalDirective &x) {
BeginOpenMP();
Word("!$OMP CRITICAL");
Walk(" (", std::get<std::optional<Name>>(x.t), ")");
Walk(std::get<OmpClauseList>(x.t));
Put("\n");
EndOpenMP();
}
void Unparse(const OmpEndCriticalDirective &x) {
BeginOpenMP();
Word("!$OMP END CRITICAL");
Walk(" (", std::get<std::optional<Name>>(x.t), ")");
Put("\n");
EndOpenMP();
}
void Unparse(const OpenMPCriticalConstruct &x) {
Walk(std::get<OmpCriticalDirective>(x.t));
Walk(std::get<Block>(x.t), "");
Walk(std::get<OmpEndCriticalDirective>(x.t));
}
void Unparse(const OmpDeclareTargetWithList &x) {
Put("("), Walk(x.v), Put(")");
}
void Unparse(const OmpReductionInitializerClause &x) {
Word(" INITIALIZER(OMP_PRIV = ");
Walk(x.v);
Put(")");
}
void Unparse(const OmpReductionCombiner::FunctionCombiner &x) {
const auto &pd = std::get<ProcedureDesignator>(x.v.t);
const auto &args = std::get<std::list<ActualArgSpec>>(x.v.t);
Walk(pd);
if (args.empty()) {
if (std::holds_alternative<ProcComponentRef>(pd.u)) {
Put("()");
}
} else {
Walk("(", args, ", ", ")");
}
}
void Unparse(const OpenMPDeclareReductionConstruct &x) {
Put("(");
Walk(std::get<OmpReductionOperator>(x.t)), Put(" : ");
Walk(std::get<std::list<DeclarationTypeSpec>>(x.t), ","), Put(" : ");
Walk(std::get<OmpReductionCombiner>(x.t));
Put(")");
Walk(std::get<std::optional<OmpReductionInitializerClause>>(x.t));
}
bool Pre(const OpenMPDeclarativeConstruct &x) {
BeginOpenMP();
Word("!$OMP ");
return std::visit(common::visitors{
[&](const OpenMPDeclarativeAllocate &z) {
Word("ALLOCATE (");
Walk(std::get<OmpObjectList>(z.t));
Put(")");
Walk(std::get<OmpClauseList>(z.t));
Put("\n");
EndOpenMP();
return false;
},
[&](const OpenMPDeclareReductionConstruct &) {
Word("DECLARE REDUCTION ");
return true;
},
[&](const OpenMPDeclareSimdConstruct &y) {
Word("DECLARE SIMD ");
Walk("(", std::get<std::optional<Name>>(y.t), ")");
Walk(std::get<OmpClauseList>(y.t));
Put("\n");
EndOpenMP();
return false;
},
[&](const OpenMPDeclareTargetConstruct &) {
Word("DECLARE TARGET ");
return true;
},
[&](const OpenMPThreadprivate &) {
Word("THREADPRIVATE (");
return true;
},
},
x.u);
}
void Post(const OpenMPDeclarativeConstruct &) {
Put("\n");
EndOpenMP();
}
void Post(const OpenMPThreadprivate &) {
Put(")\n");
EndOpenMP();
}
void Unparse(const OmpSectionsDirective &x) {
switch (x.v) {
case llvm::omp::Directive::OMPD_sections:
Word("SECTIONS ");
break;
case llvm::omp::Directive::OMPD_parallel_sections:
Word("PARALLEL SECTIONS ");
break;
default:
break;
}
}
void Unparse(const OmpSectionBlocks &x) {
for (const auto &y : x.v) {
BeginOpenMP();
Word("!$OMP SECTION");
Put("\n");
EndOpenMP();
Walk(y, ""); // y is Block
}
}
void Unparse(const OpenMPSectionsConstruct &x) {
BeginOpenMP();
Word("!$OMP ");
Walk(std::get<OmpBeginSectionsDirective>(x.t));
Put("\n");
EndOpenMP();
Walk(std::get<OmpSectionBlocks>(x.t));
BeginOpenMP();
Word("!$OMP END ");
Walk(std::get<OmpEndSectionsDirective>(x.t));
Put("\n");
EndOpenMP();
}
void Unparse(const OpenMPCancellationPointConstruct &x) {
BeginOpenMP();
Word("!$OMP CANCELLATION POINT ");
Walk(std::get<OmpCancelType>(x.t));
Put("\n");
EndOpenMP();
}
void Unparse(const OpenMPCancelConstruct &x) {
BeginOpenMP();
Word("!$OMP CANCEL ");
Walk(std::get<OmpCancelType>(x.t));
Walk(std::get<std::optional<OpenMPCancelConstruct::If>>(x.t));
Put("\n");
EndOpenMP();
}
void Unparse(const OmpMemoryOrderClause &x) { Walk(x.v); }
void Unparse(const OmpAtomicClause &x) {
std::visit(common::visitors{
[&](const OmpMemoryOrderClause &y) { Walk(y); },
[&](const OmpClause &z) { Walk(z); },
},
x.u);
}
void Unparse(const OpenMPFlushConstruct &x) {
BeginOpenMP();
Word("!$OMP FLUSH ");
Walk(std::get<std::optional<std::list<OmpMemoryOrderClause>>>(x.t));
Walk(" (", std::get<std::optional<OmpObjectList>>(x.t), ")");
Put("\n");
EndOpenMP();
}
void Unparse(const OmpEndLoopDirective &x) {
BeginOpenMP();
Word("!$OMP END ");
Walk(std::get<OmpLoopDirective>(x.t));
Walk(std::get<OmpClauseList>(x.t));
Put("\n");
EndOpenMP();
}
void Unparse(const OmpClauseList &x) { Walk(" ", x.v, " "); }
void Unparse(const OpenMPSimpleStandaloneConstruct &x) {
BeginOpenMP();
Word("!$OMP ");
Walk(std::get<OmpSimpleStandaloneDirective>(x.t));
Walk(std::get<OmpClauseList>(x.t));
Put("\n");
EndOpenMP();
}
void Unparse(const OpenMPBlockConstruct &x) {
BeginOpenMP();
Word("!$OMP ");
Walk(std::get<OmpBeginBlockDirective>(x.t));
Put("\n");
EndOpenMP();
Walk(std::get<Block>(x.t), "");
BeginOpenMP();
Word("!$OMP END ");
Walk(std::get<OmpEndBlockDirective>(x.t));
Put("\n");
EndOpenMP();
}
void Unparse(const OpenMPLoopConstruct &x) {
BeginOpenMP();
Word("!$OMP ");
Walk(std::get<OmpBeginLoopDirective>(x.t));
Put("\n");
EndOpenMP();
Walk(std::get<std::optional<DoConstruct>>(x.t));
Walk(std::get<std::optional<OmpEndLoopDirective>>(x.t));
}
void Unparse(const BasedPointer &x) {
Put('('), Walk(std::get<0>(x.t)), Put(","), Walk(std::get<1>(x.t));
Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")"), Put(')');
}
void Unparse(const BasedPointerStmt &x) { Walk("POINTER ", x.v, ","); }
void Post(const StructureField &x) {
if (const auto *def{std::get_if<Statement<DataComponentDefStmt>>(&x.u)}) {
for (const auto &decl :
std::get<std::list<ComponentDecl>>(def->statement.t)) {
structureComponents_.insert(std::get<Name>(decl.t).source);
}
}
}
void Unparse(const StructureStmt &x) {
Word("STRUCTURE ");
if (std::get<bool>(x.t)) { // slashes around name
Put('/'), Walk(std::get<Name>(x.t)), Put('/');
Walk(" ", std::get<std::list<EntityDecl>>(x.t), ", ");
} else {
CHECK(std::get<std::list<EntityDecl>>(x.t).empty());
Walk(std::get<Name>(x.t));
}
Indent();
}
void Post(const Union::UnionStmt &) { Word("UNION"), Indent(); }
void Post(const Union::EndUnionStmt &) { Outdent(), Word("END UNION"); }
void Post(const Map::MapStmt &) { Word("MAP"), Indent(); }
void Post(const Map::EndMapStmt &) { Outdent(), Word("END MAP"); }
void Post(const StructureDef::EndStructureStmt &) {
Outdent(), Word("END STRUCTURE");
}
void Unparse(const OldParameterStmt &x) {
Word("PARAMETER "), Walk(x.v, ", ");
}
void Unparse(const ArithmeticIfStmt &x) {
Word("IF ("), Walk(std::get<Expr>(x.t)), Put(") ");
Walk(std::get<1>(x.t)), Put(", ");
Walk(std::get<2>(x.t)), Put(", ");
Walk(std::get<3>(x.t));
}
void Unparse(const AssignStmt &x) {
Word("ASSIGN "), Walk(std::get<Label>(x.t));
Word(" TO "), Walk(std::get<Name>(x.t));
}
void Unparse(const AssignedGotoStmt &x) {
Word("GO TO "), Walk(std::get<Name>(x.t));
Walk(", (", std::get<std::list<Label>>(x.t), ", ", ")");
}
void Unparse(const PauseStmt &x) { Word("PAUSE"), Walk(" ", x.v); }
#define WALK_NESTED_ENUM(CLASS, ENUM) \
void Unparse(const CLASS::ENUM &x) { Word(CLASS::EnumToString(x)); }
WALK_NESTED_ENUM(AccessSpec, Kind) // R807
WALK_NESTED_ENUM(common, TypeParamAttr) // R734
WALK_NESTED_ENUM(IntentSpec, Intent) // R826
WALK_NESTED_ENUM(ImplicitStmt, ImplicitNoneNameSpec) // R866
WALK_NESTED_ENUM(ConnectSpec::CharExpr, Kind) // R1205
WALK_NESTED_ENUM(IoControlSpec::CharExpr, Kind)
WALK_NESTED_ENUM(InquireSpec::CharVar, Kind)
WALK_NESTED_ENUM(InquireSpec::IntVar, Kind)
WALK_NESTED_ENUM(InquireSpec::LogVar, Kind)
WALK_NESTED_ENUM(ProcedureStmt, Kind) // R1506
WALK_NESTED_ENUM(UseStmt, ModuleNature) // R1410
WALK_NESTED_ENUM(OmpProcBindClause, Type) // OMP PROC_BIND
WALK_NESTED_ENUM(OmpDefaultClause, Type) // OMP DEFAULT
WALK_NESTED_ENUM(OmpDefaultmapClause, ImplicitBehavior) // OMP DEFAULTMAP
WALK_NESTED_ENUM(OmpDefaultmapClause, VariableCategory) // OMP DEFAULTMAP
WALK_NESTED_ENUM(OmpScheduleModifierType, ModType) // OMP schedule-modifier
WALK_NESTED_ENUM(OmpLinearModifier, Type) // OMP linear-modifier
WALK_NESTED_ENUM(OmpDependenceType, Type) // OMP dependence-type
WALK_NESTED_ENUM(OmpMapType, Type) // OMP map-type
WALK_NESTED_ENUM(OmpScheduleClause, ScheduleType) // OMP schedule-type
WALK_NESTED_ENUM(OmpIfClause, DirectiveNameModifier) // OMP directive-modifier
WALK_NESTED_ENUM(OmpCancelType, Type) // OMP cancel-type
#undef WALK_NESTED_ENUM
void Done() const { CHECK(indent_ == 0); }
private:
void Put(char);
void Put(const char *);
void Put(const std::string &);
void PutNormalized(const std::string &);
void PutKeywordLetter(char);
void Word(const char *);
void Word(const std::string &);
void Indent() { indent_ += indentationAmount_; }
void Outdent() {
CHECK(indent_ >= indentationAmount_);
indent_ -= indentationAmount_;
}
void BeginOpenMP() { openmpDirective_ = true; }
void EndOpenMP() { openmpDirective_ = false; }
void BeginOpenACC() { openaccDirective_ = true; }
void EndOpenACC() { openaccDirective_ = false; }
// Call back to the traversal framework.
template <typename T> void Walk(const T &x) {
Fortran::parser::Walk(x, *this);
}
// Traverse a std::optional<> value. Emit a prefix and/or a suffix string
// only when it contains a value.
template <typename A>
void Walk(
const char *prefix, const std::optional<A> &x, const char *suffix = "") {
if (x) {
Word(prefix), Walk(*x), Word(suffix);
}
}
template <typename A>
void Walk(const std::optional<A> &x, const char *suffix = "") {
return Walk("", x, suffix);
}
// Traverse a std::list<>. Separate the elements with an optional string.
// Emit a prefix and/or a suffix string only when the list is not empty.
template <typename A>
void Walk(const char *prefix, const std::list<A> &list,
const char *comma = ", ", const char *suffix = "") {
if (!list.empty()) {
const char *str{prefix};
for (const auto &x : list) {
Word(str), Walk(x);
str = comma;
}
Word(suffix);
}
}
template <typename A>
void Walk(const std::list<A> &list, const char *comma = ", ",
const char *suffix = "") {
return Walk("", list, comma, suffix);
}
// Traverse a std::tuple<>, with an optional separator.
template <std::size_t J = 0, typename T>
void WalkTupleElements(const T &tuple, const char *separator) {
if (J > 0 && J < std::tuple_size_v<T>) {
Word(separator); // this usage dodges "unused parameter" warning
}
if constexpr (J < std::tuple_size_v<T>) {
Walk(std::get<J>(tuple));
WalkTupleElements<J + 1>(tuple, separator);
}
}
template <typename... A>
void Walk(const std::tuple<A...> &tuple, const char *separator = "") {
WalkTupleElements(tuple, separator);
}
void EndSubprogram(const char *kind, const std::optional<Name> &name) {
Outdent(), Word("END "), Word(kind), Walk(" ", name);
structureComponents_.clear();
}
llvm::raw_ostream &out_;
int indent_{0};
const int indentationAmount_{1};
int column_{1};
const int maxColumns_{80};
std::set<CharBlock> structureComponents_;
Encoding encoding_{Encoding::UTF_8};
bool capitalizeKeywords_{true};
bool openaccDirective_{false};
bool openmpDirective_{false};
bool backslashEscapes_{false};
preStatementType *preStatement_{nullptr};
AnalyzedObjectsAsFortran *asFortran_{nullptr};
};
void UnparseVisitor::Put(char ch) {
int sav = indent_;
if (openmpDirective_ || openaccDirective_) {
indent_ = 0;
}
if (column_ <= 1) {
if (ch == '\n') {
return;
}
for (int j{0}; j < indent_; ++j) {
out_ << ' ';
}
column_ = indent_ + 2;
} else if (ch == '\n') {
column_ = 1;
} else if (++column_ >= maxColumns_) {
out_ << "&\n";
for (int j{0}; j < indent_; ++j) {
out_ << ' ';
}
if (openmpDirective_) {
out_ << "!$OMP&";
column_ = 8;
} else if (openaccDirective_) {
out_ << "!$ACC&";
column_ = 8;
} else {
out_ << '&';
column_ = indent_ + 3;
}
}
out_ << ch;
if (openmpDirective_ || openaccDirective_) {
indent_ = sav;
}
}
void UnparseVisitor::Put(const char *str) {
for (; *str != '\0'; ++str) {
Put(*str);
}
}
void UnparseVisitor::Put(const std::string &str) {
for (char ch : str) {
Put(ch);
}
}
void UnparseVisitor::PutNormalized(const std::string &str) {
auto decoded{DecodeString<std::string, Encoding::LATIN_1>(str, true)};
std::string encoded{EncodeString<Encoding::LATIN_1>(decoded)};
Put(QuoteCharacterLiteral(encoded, backslashEscapes_));
}
void UnparseVisitor::PutKeywordLetter(char ch) {
if (capitalizeKeywords_) {
Put(ToUpperCaseLetter(ch));
} else {
Put(ToLowerCaseLetter(ch));
}
}
void UnparseVisitor::Word(const char *str) {
for (; *str != '\0'; ++str) {
PutKeywordLetter(*str);
}
}
void UnparseVisitor::Word(const std::string &str) { Word(str.c_str()); }
void Unparse(llvm::raw_ostream &out, const Program &program, Encoding encoding,
bool capitalizeKeywords, bool backslashEscapes,
preStatementType *preStatement, AnalyzedObjectsAsFortran *asFortran) {
UnparseVisitor visitor{out, 1, encoding, capitalizeKeywords, backslashEscapes,
preStatement, asFortran};
Walk(program, visitor);
visitor.Done();
}
} // namespace Fortran::parser