2733 lines
		
	
	
		
			92 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			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 "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 {
 | 
						|
      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
 | 
						|
  bool Pre(const Expr &x) {
 | 
						|
    if (asFortran_ && x.typedExpr) {
 | 
						|
      // Format the expression representation from semantics
 | 
						|
      asFortran_->expr(out_, *x.typedExpr);
 | 
						|
      return false;
 | 
						|
    } else {
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  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<std::optional<OmpClause>>(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
 |