// Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef FORTRAN_PARSER_PARSE_TREE_H_ #define FORTRAN_PARSER_PARSE_TREE_H_ // Defines the classes used to represent successful reductions of productions // in the Fortran grammar. The names and content of these definitions // adhere closely to the syntax specifications in the language standard (q.v.) // that are transcribed here and referenced via their requirement numbers. // The representations of some productions that may also be of use in the // run-time I/O support library have been isolated into a distinct header file // (viz., format-specification.h). #include "char-block.h" #include "characters.h" #include "format-specification.h" #include "message.h" #include "provenance.h" #include "../common/Fortran.h" #include "../common/idioms.h" #include "../common/indirection.h" #include #include #include #include #include #include #include #include #include // Parse tree node class types do not have default constructors. They // explicitly declare "T() {} = delete;" to make this clear. This restriction // prevents the introduction of what would be a viral requirement to include // std::monostate among most std::variant<> discriminated union members. // Parse tree node class types do not have copy constructors or copy assignment // operators. They are explicitly declared "= delete;" to make this clear, // although a C++ compiler wouldn't default them anyway due to the presence // of explicitly defaulted move constructors and move assignments. CLASS_TRAIT(EmptyTrait) CLASS_TRAIT(WrapperTrait) CLASS_TRAIT(UnionTrait) CLASS_TRAIT(TupleTrait) CLASS_TRAIT(ConstraintTrait) // Some parse tree nodes have fields in them to cache the results of a // successful semantic analysis later. Their types are forward declared // here. namespace Fortran::semantics { class Symbol; class DeclTypeSpec; class DerivedTypeSpec; } // Expressions in the parse tree have owning pointers that can be set to // type-checked generic expression representations by semantic analysis. namespace Fortran::evaluate { struct GenericExprWrapper; // forward definition, wraps Expr } // Most non-template classes in this file use these default definitions // for their move constructor and move assignment operator=, and disable // their copy constructor and copy assignment operator=. #define COPY_AND_ASSIGN_BOILERPLATE(classname) \ classname(classname &&) = default; \ classname &operator=(classname &&) = default; \ classname(const classname &) = delete; \ classname &operator=(const classname &) = delete // Almost all classes in this file have no default constructor. #define BOILERPLATE(classname) \ COPY_AND_ASSIGN_BOILERPLATE(classname); \ classname() = delete // Empty classes are often used below as alternatives in std::variant<> // discriminated unions. #define EMPTY_CLASS(classname) \ struct classname { \ classname() {} \ classname(const classname &) {} \ classname(classname &&) {} \ classname &operator=(const classname &) { return *this; }; \ classname &operator=(classname &&) { return *this; }; \ using EmptyTrait = std::true_type; \ } // Many classes below simply wrap a std::variant<> discriminated union, // which is conventionally named "u". #define UNION_CLASS_BOILERPLATE(classname) \ template> \ classname(A &&x) : u(std::move(x)) {} \ using UnionTrait = std::true_type; \ BOILERPLATE(classname) // Many other classes below simply wrap a std::tuple<> structure, which // is conventionally named "t". #define TUPLE_CLASS_BOILERPLATE(classname) \ template> \ classname(Ts &&... args) : t(std::move(args)...) {} \ using TupleTrait = std::true_type; \ BOILERPLATE(classname) // Many other classes below simply wrap a single data member, which is // conventionally named "v". #define WRAPPER_CLASS_BOILERPLATE(classname, type) \ BOILERPLATE(classname); \ classname(type &&x) : v(std::move(x)) {} \ using WrapperTrait = std::true_type; \ type v #define WRAPPER_CLASS(classname, type) \ struct classname { \ WRAPPER_CLASS_BOILERPLATE(classname, type); \ } namespace Fortran::parser { // These are the unavoidable recursively-defined productions of Fortran. // Some references to the representations of their parses require // indirection. The Indirect<> pointer wrapper class is used to // enforce ownership semantics and non-nullability. struct SpecificationPart; // R504 struct ExecutableConstruct; // R514 struct ActionStmt; // R515 struct AcImpliedDo; // R774 struct DataImpliedDo; // R840 struct Designator; // R901 struct Variable; // R902 struct Expr; // R1001 struct WhereConstruct; // R1042 struct ForallConstruct; // R1050 struct InputImpliedDo; // R1218 struct OutputImpliedDo; // R1218 struct FunctionReference; // R1520 struct FunctionSubprogram; // R1529 struct SubroutineSubprogram; // R1534 // These additional forward references are declared so that the order of // class definitions in this header file can remain reasonably consistent // with order of the the requirement productions in the grammar. struct DerivedTypeDef; // R726 struct EnumDef; // R759 struct TypeDeclarationStmt; // R801 struct AccessStmt; // R827 struct AllocatableStmt; // R829 struct AsynchronousStmt; // R831 struct BindStmt; // R832 struct CodimensionStmt; // R834 struct ContiguousStmt; // R836 struct DataStmt; // R837 struct DataStmtValue; // R843 struct DimensionStmt; // R848 struct IntentStmt; // R849 struct OptionalStmt; // R850 struct ParameterStmt; // R851 struct OldParameterStmt; struct PointerStmt; // R853 struct ProtectedStmt; // R855 struct SaveStmt; // R856 struct TargetStmt; // R859 struct ValueStmt; // R861 struct VolatileStmt; // R862 struct ImplicitStmt; // R863 struct ImportStmt; // R867 struct NamelistStmt; // R868 struct EquivalenceStmt; // R870 struct CommonStmt; // R873 struct Substring; // R908 struct CharLiteralConstantSubstring; struct DataRef; // R911 struct StructureComponent; // R913 struct CoindexedNamedObject; // R914 struct ArrayElement; // R917 struct AllocateStmt; // R927 struct NullifyStmt; // R939 struct DeallocateStmt; // R941 struct AssignmentStmt; // R1032 struct PointerAssignmentStmt; // R1033 struct WhereStmt; // R1041, R1045, R1046 struct ForallStmt; // R1055 struct AssociateConstruct; // R1102 struct BlockConstruct; // R1107 struct ChangeTeamConstruct; // R1111 struct CriticalConstruct; // R1116 struct DoConstruct; // R1119 struct LabelDoStmt; // R1121 struct ConcurrentHeader; // R1125 struct EndDoStmt; // R1132 struct CycleStmt; // R1133 struct IfConstruct; // R1134 struct IfStmt; // R1139 struct CaseConstruct; // R1140 struct SelectRankConstruct; // R1148 struct SelectTypeConstruct; // R1152 struct ExitStmt; // R1156 struct GotoStmt; // R1157 struct ComputedGotoStmt; // R1158 struct StopStmt; // R1160, R1161 struct SyncAllStmt; // R1164 struct SyncImagesStmt; // R1166 struct SyncMemoryStmt; // R1168 struct SyncTeamStmt; // R1169 struct EventPostStmt; // R1170, R1171 struct EventWaitStmt; // R1172, R1173, R1174 struct FormTeamStmt; // R1175, R1176, R1177 struct LockStmt; // R1178 struct UnlockStmt; // R1180 struct OpenStmt; // R1204 struct CloseStmt; // R1208 struct ReadStmt; // R1210 struct WriteStmt; // R1211 struct PrintStmt; // R1212 struct WaitStmt; // R1222 struct BackspaceStmt; // R1224 struct EndfileStmt; // R1225 struct RewindStmt; // R1226 struct FlushStmt; // R1228 struct InquireStmt; // R1230 struct FormatStmt; // R1301 struct MainProgram; // R1401 struct Module; // R1404 struct UseStmt; // R1409 struct Submodule; // R1416 struct BlockData; // R1420 struct InterfaceBlock; // R1501 struct GenericSpec; // R1508 struct GenericStmt; // R1510 struct ExternalStmt; // R1511 struct ProcedureDeclarationStmt; // R1512 struct IntrinsicStmt; // R1519 struct Call; // R1520 & R1521 struct CallStmt; // R1521 struct ProcedureDesignator; // R1522 struct ActualArg; // R1524 struct SeparateModuleSubprogram; // R1538 struct EntryStmt; // R1541 struct ReturnStmt; // R1542 struct StmtFunctionStmt; // R1544 // Directives, extensions, and deprecated statements struct CompilerDirective; struct BasedPointerStmt; struct StructureDef; struct ArithmeticIfStmt; struct AssignStmt; struct AssignedGotoStmt; struct PauseStmt; struct OpenMPConstruct; struct OpenMPDeclarativeConstruct; struct OmpBlockDirective; struct OpenMPEndLoopDirective; // Cooked character stream locations using Location = const char *; // Implicit definitions of the Standard // R403 scalar-xyz -> xyz // These template class wrappers correspond to the Standard's modifiers // scalar-xyz, constant-xzy, int-xzy, default-char-xyz, & logical-xyz. template struct Scalar { using ConstraintTrait = std::true_type; Scalar(Scalar &&that) = default; Scalar(A &&that) : thing(std::move(that)) {} Scalar &operator=(Scalar &&) = default; A thing; }; template struct Constant { using ConstraintTrait = std::true_type; Constant(Constant &&that) = default; Constant(A &&that) : thing(std::move(that)) {} Constant &operator=(Constant &&) = default; A thing; }; template struct Integer { using ConstraintTrait = std::true_type; Integer(Integer &&that) = default; Integer(A &&that) : thing(std::move(that)) {} Integer &operator=(Integer &&) = default; A thing; }; template struct Logical { using ConstraintTrait = std::true_type; Logical(Logical &&that) = default; Logical(A &&that) : thing(std::move(that)) {} Logical &operator=(Logical &&) = default; A thing; }; template struct DefaultChar { using ConstraintTrait = std::true_type; DefaultChar(DefaultChar &&that) = default; DefaultChar(A &&that) : thing(std::move(that)) {} DefaultChar &operator=(DefaultChar &&) = default; A thing; }; using LogicalExpr = Logical>; // R1024 using DefaultCharExpr = DefaultChar>; // R1025 using IntExpr = Integer>; // R1026 using ConstantExpr = Constant>; // R1029 using IntConstantExpr = Integer; // R1031 using ScalarLogicalExpr = Scalar; using ScalarIntExpr = Scalar; using ScalarIntConstantExpr = Scalar; using ScalarDefaultCharExpr = Scalar; // R1030 default-char-constant-expr is used in the Standard only as part of // scalar-default-char-constant-expr. using ScalarDefaultCharConstantExpr = Scalar>; // R611 label -> digit [digit]... using Label = std::uint64_t; // validated later, must be in [1..99999] // A wrapper for xzy-stmt productions that are statements, so that // source provenances and labels have a uniform representation. template struct UnlabeledStatement { explicit UnlabeledStatement(A &&s) : statement(std::move(s)) {} CharBlock source; A statement; }; template struct Statement : public UnlabeledStatement { Statement(std::optional &&lab, A &&s) : UnlabeledStatement{std::move(s)}, label(std::move(lab)) {} std::optional &&x) : nature(std::move(nat)), moduleName(std::move(n)), u(std::move(x)) {} std::optional nature; Name moduleName; std::variant, std::list> u; }; // R1514 proc-attr-spec -> // access-spec | proc-language-binding-spec | INTENT ( intent-spec ) | // OPTIONAL | POINTER | PROTECTED | SAVE struct ProcAttrSpec { UNION_CLASS_BOILERPLATE(ProcAttrSpec); std::variant u; }; // R1512 procedure-declaration-stmt -> // PROCEDURE ( [proc-interface] ) [[, proc-attr-spec]... ::] // proc-decl-list struct ProcedureDeclarationStmt { TUPLE_CLASS_BOILERPLATE(ProcedureDeclarationStmt); std::tuple, std::list, std::list> t; }; // R1527 prefix-spec -> // declaration-type-spec | ELEMENTAL | IMPURE | MODULE | // NON_RECURSIVE | PURE | RECURSIVE struct PrefixSpec { UNION_CLASS_BOILERPLATE(PrefixSpec); EMPTY_CLASS(Elemental); EMPTY_CLASS(Impure); EMPTY_CLASS(Module); EMPTY_CLASS(Non_Recursive); EMPTY_CLASS(Pure); EMPTY_CLASS(Recursive); std::variant u; }; // R1532 suffix -> // proc-language-binding-spec [RESULT ( result-name )] | // RESULT ( result-name ) [proc-language-binding-spec] struct Suffix { BOILERPLATE(Suffix); Suffix(LanguageBindingSpec &&lbs, std::optional &&rn) : binding(std::move(lbs)), resultName(std::move(rn)) {} Suffix(Name &&rn, std::optional &&lbs) : binding(std::move(lbs)), resultName(std::move(rn)) {} std::optional binding; std::optional resultName; }; // R1530 function-stmt -> // [prefix] FUNCTION function-name ( [dummy-arg-name-list] ) [suffix] // R1526 prefix -> prefix-spec [prefix-spec]... // R1531 dummy-arg-name -> name struct FunctionStmt { TUPLE_CLASS_BOILERPLATE(FunctionStmt); std::tuple, Name, std::list, std::optional> t; }; // R1533 end-function-stmt -> END [FUNCTION [function-name]] WRAPPER_CLASS(EndFunctionStmt, std::optional); // R1536 dummy-arg -> dummy-arg-name | * struct DummyArg { UNION_CLASS_BOILERPLATE(DummyArg); std::variant u; }; // R1535 subroutine-stmt -> // [prefix] SUBROUTINE subroutine-name [( [dummy-arg-list] ) // [proc-language-binding-spec]] struct SubroutineStmt { TUPLE_CLASS_BOILERPLATE(SubroutineStmt); std::tuple, Name, std::list, std::optional> t; }; // R1537 end-subroutine-stmt -> END [SUBROUTINE [subroutine-name]] WRAPPER_CLASS(EndSubroutineStmt, std::optional); // R1505 interface-body -> // function-stmt [specification-part] end-function-stmt | // subroutine-stmt [specification-part] end-subroutine-stmt struct InterfaceBody { UNION_CLASS_BOILERPLATE(InterfaceBody); struct Function { TUPLE_CLASS_BOILERPLATE(Function); std::tuple, common::Indirection, Statement> t; }; struct Subroutine { TUPLE_CLASS_BOILERPLATE(Subroutine); std::tuple, common::Indirection, Statement> t; }; std::variant u; }; // R1506 procedure-stmt -> [MODULE] PROCEDURE [::] specific-procedure-list struct ProcedureStmt { ENUM_CLASS(Kind, ModuleProcedure, Procedure) TUPLE_CLASS_BOILERPLATE(ProcedureStmt); std::tuple> t; }; // R1502 interface-specification -> interface-body | procedure-stmt struct InterfaceSpecification { UNION_CLASS_BOILERPLATE(InterfaceSpecification); std::variant> u; }; // R1504 end-interface-stmt -> END INTERFACE [generic-spec] WRAPPER_CLASS(EndInterfaceStmt, std::optional); // R1501 interface-block -> // interface-stmt [interface-specification]... end-interface-stmt struct InterfaceBlock { TUPLE_CLASS_BOILERPLATE(InterfaceBlock); std::tuple, std::list, Statement> t; }; // R1511 external-stmt -> EXTERNAL [::] external-name-list WRAPPER_CLASS(ExternalStmt, std::list); // R1519 intrinsic-stmt -> INTRINSIC [::] intrinsic-procedure-name-list WRAPPER_CLASS(IntrinsicStmt, std::list); // R1522 procedure-designator -> // procedure-name | proc-component-ref | data-ref % binding-name struct ProcedureDesignator { UNION_CLASS_BOILERPLATE(ProcedureDesignator); std::variant u; }; // R1525 alt-return-spec -> * label WRAPPER_CLASS(AltReturnSpec, Label); // R1524 actual-arg -> // expr | variable | procedure-name | proc-component-ref | // alt-return-spec struct ActualArg { WRAPPER_CLASS(PercentRef, Variable); // %REF(v) extension WRAPPER_CLASS(PercentVal, Expr); // %VAL(x) extension UNION_CLASS_BOILERPLATE(ActualArg); ActualArg(Expr &&x) : u{common::Indirection(std::move(x))} {} std::variant, AltReturnSpec, PercentRef, PercentVal> u; }; // R1523 actual-arg-spec -> [keyword =] actual-arg struct ActualArgSpec { TUPLE_CLASS_BOILERPLATE(ActualArgSpec); std::tuple, ActualArg> t; }; // R1520 function-reference -> procedure-designator ( [actual-arg-spec-list] ) struct Call { TUPLE_CLASS_BOILERPLATE(Call); CharBlock source; std::tuple> t; }; struct FunctionReference { WRAPPER_CLASS_BOILERPLATE(FunctionReference, Call); Designator ConvertToArrayElementRef(); StructureConstructor ConvertToStructureConstructor( const semantics::DerivedTypeSpec &); }; // R1521 call-stmt -> CALL procedure-designator [( [actual-arg-spec-list] )] WRAPPER_CLASS(CallStmt, Call); // R1529 function-subprogram -> // function-stmt [specification-part] [execution-part] // [internal-subprogram-part] end-function-stmt struct FunctionSubprogram { TUPLE_CLASS_BOILERPLATE(FunctionSubprogram); std::tuple, SpecificationPart, ExecutionPart, std::optional, Statement> t; }; // R1534 subroutine-subprogram -> // subroutine-stmt [specification-part] [execution-part] // [internal-subprogram-part] end-subroutine-stmt struct SubroutineSubprogram { TUPLE_CLASS_BOILERPLATE(SubroutineSubprogram); std::tuple, SpecificationPart, ExecutionPart, std::optional, Statement> t; }; // R1539 mp-subprogram-stmt -> MODULE PROCEDURE procedure-name WRAPPER_CLASS(MpSubprogramStmt, Name); // R1540 end-mp-subprogram-stmt -> END [PROCEDURE [procedure-name]] WRAPPER_CLASS(EndMpSubprogramStmt, std::optional); // R1538 separate-module-subprogram -> // mp-subprogram-stmt [specification-part] [execution-part] // [internal-subprogram-part] end-mp-subprogram-stmt struct SeparateModuleSubprogram { TUPLE_CLASS_BOILERPLATE(SeparateModuleSubprogram); std::tuple, SpecificationPart, ExecutionPart, std::optional, Statement> t; }; // R1541 entry-stmt -> ENTRY entry-name [( [dummy-arg-list] ) [suffix]] struct EntryStmt { TUPLE_CLASS_BOILERPLATE(EntryStmt); std::tuple, std::optional> t; }; // R1542 return-stmt -> RETURN [scalar-int-expr] WRAPPER_CLASS(ReturnStmt, std::optional); // R1544 stmt-function-stmt -> // function-name ( [dummy-arg-name-list] ) = scalar-expr struct StmtFunctionStmt { TUPLE_CLASS_BOILERPLATE(StmtFunctionStmt); std::tuple, Scalar> t; Statement ConvertToAssignment(); }; // Compiler directives // !DIR$ IGNORE_TKR [ [(tkr...)] name ]... // !DIR$ name... struct CompilerDirective { UNION_CLASS_BOILERPLATE(CompilerDirective); struct IgnoreTKR { TUPLE_CLASS_BOILERPLATE(IgnoreTKR); std::tuple, Name> t; }; CharBlock source; std::variant, std::list> u; }; // Legacy extensions struct BasedPointer { TUPLE_CLASS_BOILERPLATE(BasedPointer); std::tuple> t; }; WRAPPER_CLASS(BasedPointerStmt, std::list); struct Union; struct StructureDef; struct StructureField { UNION_CLASS_BOILERPLATE(StructureField); std::variant, common::Indirection, common::Indirection> u; }; struct Map { EMPTY_CLASS(MapStmt); EMPTY_CLASS(EndMapStmt); TUPLE_CLASS_BOILERPLATE(Map); std::tuple, std::list, Statement> t; }; struct Union { EMPTY_CLASS(UnionStmt); EMPTY_CLASS(EndUnionStmt); TUPLE_CLASS_BOILERPLATE(Union); std::tuple, std::list, Statement> t; }; struct StructureStmt { TUPLE_CLASS_BOILERPLATE(StructureStmt); std::tuple> t; }; struct StructureDef { EMPTY_CLASS(EndStructureStmt); TUPLE_CLASS_BOILERPLATE(StructureDef); std::tuple, std::list, Statement> t; }; // Old style PARAMETER statement without parentheses. // Types are determined entirely from the right-hand sides, not the names. WRAPPER_CLASS(OldParameterStmt, std::list); // Deprecations struct ArithmeticIfStmt { TUPLE_CLASS_BOILERPLATE(ArithmeticIfStmt); std::tuple t; }; struct AssignStmt { TUPLE_CLASS_BOILERPLATE(AssignStmt); std::tuple t; }; struct AssignedGotoStmt { TUPLE_CLASS_BOILERPLATE(AssignedGotoStmt); std::tuple> t; }; WRAPPER_CLASS(PauseStmt, std::optional); // PROC_BIND(CLOSE | MASTER | SPREAD) struct OmpProcBindClause { ENUM_CLASS(Type, Close, Master, Spread) WRAPPER_CLASS_BOILERPLATE(OmpProcBindClause, Type); }; // DEFAULT(PRIVATE | FIRSTPRIVATE | SHARED | NOND) struct OmpDefaultClause { ENUM_CLASS(Type, Private, Firstprivate, Shared, None) WRAPPER_CLASS_BOILERPLATE(OmpDefaultClause, Type); }; // variable-name | / common-block / | array-sections struct OmpObject { TUPLE_CLASS_BOILERPLATE(OmpObject); ENUM_CLASS(Kind, Object, Common) std::tuple t; }; WRAPPER_CLASS(OmpObjectList, std::list); // map-type ->(TO | FROM | TOFROM | ALLOC | RELEASE | DELETE) struct OmpMapType { TUPLE_CLASS_BOILERPLATE(OmpMapType); EMPTY_CLASS(Always); ENUM_CLASS(Type, To, From, Tofrom, Alloc, Release, Delete) std::tuple, Type> t; }; // MAP ( map-type : list) struct OmpMapClause { TUPLE_CLASS_BOILERPLATE(OmpMapClause); std::tuple, OmpObjectList> t; }; // schedule-modifier-type -> MONOTONIC | NONMONOTONIC | SIMD struct OmpScheduleModifierType { ENUM_CLASS(ModType, Monotonic, Nonmonotonic, Simd) WRAPPER_CLASS_BOILERPLATE(OmpScheduleModifierType, ModType); }; struct OmpScheduleModifier { TUPLE_CLASS_BOILERPLATE(OmpScheduleModifier); WRAPPER_CLASS(Modifier1, OmpScheduleModifierType); WRAPPER_CLASS(Modifier2, OmpScheduleModifierType); std::tuple> t; }; // SCHEDULE([schedule-modifier [,schedule-modifier]] schedule-type [, // chunksize]) struct OmpScheduleClause { TUPLE_CLASS_BOILERPLATE(OmpScheduleClause); ENUM_CLASS(ScheduleType, Static, Dynamic, Guided, Auto, Runtime) std::tuple, ScheduleType, std::optional> t; }; // IF(DirectiveNameModifier: scalar-logical-expr) struct OmpIfClause { TUPLE_CLASS_BOILERPLATE(OmpIfClause); ENUM_CLASS(DirectiveNameModifier, Parallel, Target, TargetEnterData, TargetExitData, TargetData, TargetUpdate, Taskloop, Task) std::tuple, ScalarLogicalExpr> t; }; // ALIGNED(list, scalar-int-constant-expr) struct OmpAlignedClause { TUPLE_CLASS_BOILERPLATE(OmpAlignedClause); std::tuple, std::optional> t; }; // linear-modifier -> REF | VAL | UVAL struct OmpLinearModifier { ENUM_CLASS(Type, Ref, Val, Uval) WRAPPER_CLASS_BOILERPLATE(OmpLinearModifier, Type); }; // LINEAR((linear-modifier(list) | (list)) [: linear-step]) struct OmpLinearClause { UNION_CLASS_BOILERPLATE(OmpLinearClause); struct WithModifier { BOILERPLATE(WithModifier); WithModifier(OmpLinearModifier &&m, std::list &&n, std::optional &&s) : modifier(std::move(m)), names(std::move(n)), step(std::move(s)) {} OmpLinearModifier modifier; std::list names; std::optional step; }; struct WithoutModifier { BOILERPLATE(WithoutModifier); WithoutModifier( std::list &&n, std::optional &&s) : names(std::move(n)), step(std::move(s)) {} std::list names; std::optional step; }; std::variant u; }; // reduction-identifier -> Add, Subtract, Multiply, .and., .or., .eqv., .neqv., // min, max, iand, ior, ieor struct OmpReductionOperator { UNION_CLASS_BOILERPLATE(OmpReductionOperator); std::variant, ProcedureDesignator> u; }; // REDUCTION(reduction-identifier: list) struct OmpReductionClause { TUPLE_CLASS_BOILERPLATE(OmpReductionClause); std::tuple> t; }; // depend-vec-length -> +/- non-negative-constant struct OmpDependSinkVecLength { TUPLE_CLASS_BOILERPLATE(OmpDependSinkVecLength); std::tuple, ScalarIntConstantExpr> t; }; // depend-vec -> iterator_variable [+/- depend-vec-length] struct OmpDependSinkVec { TUPLE_CLASS_BOILERPLATE(OmpDependSinkVec); std::tuple> t; }; struct OmpDependenceType { ENUM_CLASS(Type, In, Out, Inout, Source, Sink) WRAPPER_CLASS_BOILERPLATE(OmpDependenceType, Type); }; // DEPEND(SOURCE | SINK: vec | DEPEND((IN | OUT | INOUT) : list) struct OmpDependClause { UNION_CLASS_BOILERPLATE(OmpDependClause); EMPTY_CLASS(Source); WRAPPER_CLASS(Sink, std::list); struct InOut { TUPLE_CLASS_BOILERPLATE(InOut); std::tuple> t; }; std::variant u; }; // NOWAIT EMPTY_CLASS(OmpNowait); // OpenMP Clauses struct OmpClause { UNION_CLASS_BOILERPLATE(OmpClause); EMPTY_CLASS(Defaultmap); EMPTY_CLASS(Inbranch); EMPTY_CLASS(Mergeable); EMPTY_CLASS(Nogroup); EMPTY_CLASS(Notinbranch); EMPTY_CLASS(Untied); WRAPPER_CLASS(Collapse, ScalarIntConstantExpr); WRAPPER_CLASS(Copyin, OmpObjectList); WRAPPER_CLASS(Copyprivate, OmpObjectList); WRAPPER_CLASS(Device, ScalarIntExpr); WRAPPER_CLASS(DistSchedule, ScalarIntExpr); WRAPPER_CLASS(Final, ScalarIntExpr); WRAPPER_CLASS(Firstprivate, OmpObjectList); WRAPPER_CLASS(From, std::list); WRAPPER_CLASS(Grainsize, ScalarIntExpr); WRAPPER_CLASS(Lastprivate, OmpObjectList); WRAPPER_CLASS(NumTasks, ScalarIntExpr); WRAPPER_CLASS(NumTeams, ScalarIntExpr); WRAPPER_CLASS(NumThreads, ScalarIntExpr); WRAPPER_CLASS(Ordered, std::optional); WRAPPER_CLASS(Priority, ScalarIntExpr); WRAPPER_CLASS(Private, OmpObjectList); WRAPPER_CLASS(Safelen, ScalarIntConstantExpr); WRAPPER_CLASS(Shared, OmpObjectList); WRAPPER_CLASS(Simdlen, ScalarIntConstantExpr); WRAPPER_CLASS(ThreadLimit, ScalarIntExpr); WRAPPER_CLASS(To, std::list); WRAPPER_CLASS(Link, std::list); WRAPPER_CLASS(Uniform, std::list); WRAPPER_CLASS(UseDevicePtr, std::list); WRAPPER_CLASS(IsDevicePtr, std::list); std::variant u; }; WRAPPER_CLASS(OmpClauseList, std::list); // SECTIONS, PARALLEL SECTIONS WRAPPER_CLASS(OmpEndSections, std::optional); WRAPPER_CLASS(OmpEndParallelSections, std::optional); EMPTY_CLASS(OmpSection); struct OpenMPSectionsConstruct { TUPLE_CLASS_BOILERPLATE(OpenMPSectionsConstruct); std::tuple t; }; struct OpenMPParallelSectionsConstruct { TUPLE_CLASS_BOILERPLATE(OpenMPParallelSectionsConstruct); std::tuple t; }; // WORKSHARE EMPTY_CLASS(OmpEndWorkshare); struct OpenMPWorkshareConstruct { TUPLE_CLASS_BOILERPLATE(OpenMPWorkshareConstruct); std::tuple> t; }; // SINGLE WRAPPER_CLASS(OmpEndSingle, OmpClauseList); struct OpenMPSingleConstruct { TUPLE_CLASS_BOILERPLATE(OpenMPSingleConstruct); std::tuple t; }; // OpenMP directive enclosing block struct OmpBlockDirective { UNION_CLASS_BOILERPLATE(OmpBlockDirective); EMPTY_CLASS(Master); EMPTY_CLASS(Ordered); EMPTY_CLASS(ParallelWorkshare); EMPTY_CLASS(Parallel); EMPTY_CLASS(TargetData); EMPTY_CLASS(TargetParallel); EMPTY_CLASS(TargetTeams); EMPTY_CLASS(Target); EMPTY_CLASS(Taskgroup); EMPTY_CLASS(Task); EMPTY_CLASS(Teams); std::variant u; }; struct OmpDeclareTargetMapType { ENUM_CLASS(Type, Link, To) WRAPPER_CLASS_BOILERPLATE(OmpDeclareTargetMapType, Type); }; struct OpenMPDeclareTargetConstruct { UNION_CLASS_BOILERPLATE(OpenMPDeclareTargetConstruct); struct WithClause { BOILERPLATE(WithClause); WithClause(OmpDeclareTargetMapType &&m, OmpObjectList &&n) : maptype(std::move(m)), names(std::move(n)) {} OmpDeclareTargetMapType maptype; OmpObjectList names; }; struct WithExtendedList { BOILERPLATE(WithExtendedList); WithExtendedList(OmpObjectList &&n) : names(std::move(n)) {} OmpObjectList names; }; EMPTY_CLASS(Implicit); std::variant u; }; struct OmpReductionCombiner { UNION_CLASS_BOILERPLATE(OmpReductionCombiner); WRAPPER_CLASS(FunctionCombiner, Call); std::variant u; }; WRAPPER_CLASS(OmpReductionInitializerClause, common::Indirection); struct OpenMPDeclareReductionConstruct { TUPLE_CLASS_BOILERPLATE(OpenMPDeclareReductionConstruct); std::tuple, OmpReductionCombiner, std::optional> t; }; struct OpenMPDeclareSimdConstruct { TUPLE_CLASS_BOILERPLATE(OpenMPDeclareSimdConstruct); std::tuple, OmpClauseList> t; }; struct OpenMPDeclarativeConstruct { UNION_CLASS_BOILERPLATE(OpenMPDeclarativeConstruct); WRAPPER_CLASS(Threadprivate, OmpObjectList); std::variant u; }; // CRITICAL [Name] END CRITICAL [Name] WRAPPER_CLASS(OmpEndCritical, std::optional); struct OpenMPCriticalConstruct { TUPLE_CLASS_BOILERPLATE(OpenMPCriticalConstruct); WRAPPER_CLASS(Hint, ConstantExpr); std::tuple, std::optional, Block, OmpEndCritical> t; }; // END ATOMIC EMPTY_CLASS(OmpEndAtomic); // ATOMIC READ struct OmpAtomicRead { TUPLE_CLASS_BOILERPLATE(OmpAtomicRead); EMPTY_CLASS(SeqCst1); EMPTY_CLASS(SeqCst2); std::tuple, std::optional, Statement, std::optional> t; }; // ATOMIC WRITE struct OmpAtomicWrite { TUPLE_CLASS_BOILERPLATE(OmpAtomicWrite); EMPTY_CLASS(SeqCst1); EMPTY_CLASS(SeqCst2); std::tuple, std::optional, Statement, std::optional> t; }; // ATOMIC UPDATE struct OmpAtomicUpdate { TUPLE_CLASS_BOILERPLATE(OmpAtomicUpdate); EMPTY_CLASS(SeqCst1); EMPTY_CLASS(SeqCst2); std::tuple, std::optional, Statement, std::optional> t; }; // ATOMIC CAPTURE struct OmpAtomicCapture { TUPLE_CLASS_BOILERPLATE(OmpAtomicCapture); EMPTY_CLASS(SeqCst1); EMPTY_CLASS(SeqCst2); WRAPPER_CLASS(Stmt1, Statement); WRAPPER_CLASS(Stmt2, Statement); std::tuple, std::optional, Stmt1, Stmt2, OmpEndAtomic> t; }; // ATOMIC struct OmpAtomic { TUPLE_CLASS_BOILERPLATE(OmpAtomic); EMPTY_CLASS(SeqCst); std::tuple, Statement, std::optional> t; }; struct OpenMPAtomicConstruct { UNION_CLASS_BOILERPLATE(OpenMPAtomicConstruct); std::variant u; }; struct OmpLoopDirective { UNION_CLASS_BOILERPLATE(OmpLoopDirective); EMPTY_CLASS(DistributeParallelDoSimd); EMPTY_CLASS(DistributeParallelDo); EMPTY_CLASS(DistributeSimd); EMPTY_CLASS(Distribute); EMPTY_CLASS(ParallelDoSimd); EMPTY_CLASS(ParallelDo); EMPTY_CLASS(Do); EMPTY_CLASS(DoSimd); EMPTY_CLASS(Simd); EMPTY_CLASS(TargetParallelDoSimd); EMPTY_CLASS(TargetParallelDo); EMPTY_CLASS(TargetTeamsDistributeParallelDoSimd); EMPTY_CLASS(TargetTeamsDistributeParallelDo); EMPTY_CLASS(TargetTeamsDistributeSimd); EMPTY_CLASS(TargetTeamsDistribute); EMPTY_CLASS(TargetSimd); EMPTY_CLASS(TaskloopSimd); EMPTY_CLASS(Taskloop); EMPTY_CLASS(TeamsDistributeParallelDoSimd); EMPTY_CLASS(TeamsDistributeParallelDo); EMPTY_CLASS(TeamsDistributeSimd); EMPTY_CLASS(TeamsDistribute); std::variant u; }; // Cancel/Cancellation type struct OmpCancelType { ENUM_CLASS(Type, Parallel, Sections, Do, Taskgroup) WRAPPER_CLASS_BOILERPLATE(OmpCancelType, Type); }; // CANCELLATION POINT WRAPPER_CLASS(OpenMPCancellationPointConstruct, OmpCancelType); // CANCEL struct OpenMPCancelConstruct { TUPLE_CLASS_BOILERPLATE(OpenMPCancelConstruct); WRAPPER_CLASS(If, ScalarLogicalExpr); std::tuple> t; }; // FLUSH WRAPPER_CLASS(OpenMPFlushConstruct, std::optional); // Standalone constructs struct OmpStandaloneDirective { UNION_CLASS_BOILERPLATE(OmpStandaloneDirective); EMPTY_CLASS(TargetEnterData); EMPTY_CLASS(TargetExitData); EMPTY_CLASS(TargetUpdate); std::variant u; }; EMPTY_CLASS(OpenMPTaskyieldConstruct); EMPTY_CLASS(OpenMPTaskwaitConstruct); EMPTY_CLASS(OpenMPBarrierConstruct); WRAPPER_CLASS(OmpEndBlockDirective, common::Indirection); // DO / DO SIMD WRAPPER_CLASS(OmpEndDoSimd, std::optional); WRAPPER_CLASS(OmpEndDo, std::optional); struct OpenMPEndLoopDirective { UNION_CLASS_BOILERPLATE(OpenMPEndLoopDirective); std::variant, common::Indirection, common::Indirection> u; }; struct OpenMPBlockConstruct { TUPLE_CLASS_BOILERPLATE(OpenMPBlockConstruct); std::tuple t; }; struct OpenMPLoopConstruct { TUPLE_CLASS_BOILERPLATE(OpenMPLoopConstruct); std::tuple t; }; struct OpenMPStandaloneConstruct { TUPLE_CLASS_BOILERPLATE(OpenMPStandaloneConstruct); std::tuple t; }; struct OpenMPConstruct { UNION_CLASS_BOILERPLATE(OpenMPConstruct); std::variant, common::Indirection, common::Indirection, common::Indirection, common::Indirection, common::Indirection, common::Indirection, common::Indirection, common::Indirection, common::Indirection, common::Indirection, common::Indirection, common::Indirection, common::Indirection, common::Indirection, OmpSection> u; }; } #endif // FORTRAN_PARSER_PARSE_TREE_H_