@@ -23,6 +23,70 @@ namespace Fortran::parser {
2323constexpr auto startOmpLine = skipStuffBeforeStatement >> " !$OMP " _sptok;
2424constexpr auto endOmpLine = space >> endOfLine;
2525
26+ // Map modifiers come from two categories: map-type-modifier and map-type.
27+ // There can be zero or more map-type-modifiers, and zero or one map-type.
28+ // Syntax-wise they look like a single list, where the last element could
29+ // be a map-type, and all elements in that list are comma-separated[1].
30+ // Only if there was at least one modifier (of any kind) specified, the
31+ // list must end with ":".
32+ // [1] Any of the commas are optional, but that syntax has been deprecated,
33+ // and the parsing code is intended to identify that. There are complications
34+ // coming from the fact that the comma separating the two kinds of modifiers
35+ // is only allowed if there is at least one modifier of each kind.
36+ // The MapModifiers parser parses the modifier list as a whole, and returns
37+ // a tuple with the (optional) map-type-modifier list, and the (optional)
38+ // type modifier as its members.
39+ // The list is then parsed, first with a mandatory separator, and if that
40+ // fails, with an optional one. If the latter succeeds, a deprecation
41+ // message is printed.
42+ template <typename Separator> struct MapModifiers {
43+ constexpr MapModifiers (
44+ Separator sep, std::optional<MessageFixedText> msg = std::nullopt )
45+ : sep_(sep), msg_(msg) {}
46+ constexpr MapModifiers (const MapModifiers &) = default;
47+ constexpr MapModifiers (MapModifiers &&) = default;
48+
49+ using resultType =
50+ std::tuple<std::optional<std::list<OmpMapClause::TypeModifier>>,
51+ std::optional<OmpMapClause::Type>>;
52+
53+ std::optional<resultType> Parse (ParseState &state) const {
54+ auto pmod{Parser<OmpMapClause::TypeModifier>{}};
55+ auto ptype{Parser<OmpMapClause::Type>{}};
56+ auto startLoc{state.GetLocation ()};
57+
58+ auto &&[mods, type] = [&]() -> resultType {
59+ // The 'maybe' will return optional<optional<list>>, and the outer
60+ // optional will never be nullopt.
61+ if (auto mods{
62+ *maybe (attempt (nonemptySeparated (pmod, sep_))).Parse (state)}) {
63+ // mods = optional<list>, and the list is nonempty.
64+ return attempt (sep_).Parse (state)
65+ ? resultType (mods, *maybe (attempt (ptype)).Parse (state))
66+ : resultType (mods, std::nullopt );
67+ }
68+ return {std::nullopt , *maybe (attempt (ptype)).Parse (state)};
69+ }();
70+ auto endLoc{state.GetLocation ()};
71+
72+ // The above always "succeeds", i.e. even if the input is junk, it will
73+ // return a tuple with two nullopts. If any of the components is not a
74+ // nullopt, expect a ":".
75+ if ((mods.has_value () || type.has_value ()) &&
76+ !attempt (" :" _tok).Parse (state)) {
77+ return std::nullopt ;
78+ }
79+ if (msg_) {
80+ state.Say (CharBlock{startLoc, endLoc}, *msg_);
81+ }
82+ return resultType (mods, type);
83+ }
84+
85+ private:
86+ const Separator sep_;
87+ std::optional<MessageFixedText> msg_;
88+ };
89+
2690// OpenMP Clauses
2791// 2.15.3.1 DEFAULT (PRIVATE | FIRSTPRIVATE | SHARED | NONE)
2892TYPE_PARSER (construct<OmpDefaultClause>(
@@ -38,20 +102,39 @@ TYPE_PARSER(construct<OmpProcBindClause>(
38102 "PRIMARY" >> pure(OmpProcBindClause::Type::Primary) ||
39103 "SPREAD" >> pure(OmpProcBindClause::Type::Spread)))
40104
41- // 2.15.5.1 MAP ([ [ALWAYS[,]] map-type : ] variable-name-list)
42- // map-type -> TO | FROM | TOFROM | ALLOC | RELEASE | DELETE
43- TYPE_PARSER(construct<OmpMapType>(
44- maybe (" ALWAYS" >> construct<OmpMapType::Always>() / maybe(" ," _tok)),
45- (" TO" _id >> pure (OmpMapType::Type::To) ||
46- "FROM" >> pure(OmpMapType::Type::From) ||
47- "TOFROM" >> pure(OmpMapType::Type::Tofrom) ||
48- "ALLOC" >> pure(OmpMapType::Type::Alloc) ||
49- "RELEASE" >> pure(OmpMapType::Type::Release) ||
50- "DELETE" >> pure(OmpMapType::Type::Delete)) /
51- ":"))
52-
53- TYPE_PARSER(construct<OmpMapClause>(
54- maybe (Parser<OmpMapType>{}), Parser<OmpObjectList>{}))
105+ // 2.15.5.1 map ->
106+ // MAP ([ [map-type-modifiers [,] ] map-type : ] variable-name-list)
107+ // map-type-modifiers -> map-type-modifier [,] [...]
108+ // map-type-modifier -> ALWAYS | CLOSE | OMPX_HOLD | PRESENT
109+ // map-type -> ALLOC | DELETE | FROM | RELEASE | TO | TOFROM
110+ TYPE_PARSER(construct<OmpMapClause::TypeModifier>(
111+ " ALWAYS" >> pure (OmpMapClause::TypeModifier::Always) ||
112+ "CLOSE" >> pure(OmpMapClause::TypeModifier::Close) ||
113+ "OMPX_HOLD" >> pure(OmpMapClause::TypeModifier::OmpxHold) ||
114+ "PRESENT" >> pure(OmpMapClause::TypeModifier::Present)))
115+
116+ TYPE_PARSER(
117+ construct<OmpMapClause::Type>(" ALLOC" >> pure (OmpMapClause::Type::Alloc) ||
118+ "DELETE" >> pure(OmpMapClause::Type::Delete) ||
119+ "FROM" >> pure(OmpMapClause::Type::From) ||
120+ "RELEASE" >> pure(OmpMapClause::Type::Release) ||
121+ "TO"_id >> pure(OmpMapClause::Type::To) ||
122+ "TOFROM" >> pure(OmpMapClause::Type::Tofrom)))
123+
124+ static inline OmpMapClause makeMapClause(
125+ std::tuple<std::optional<std::list<OmpMapClause::TypeModifier>>,
126+ std::optional<OmpMapClause::Type>> &&mod,
127+ OmpObjectList &&obj) {
128+ return OmpMapClause{
129+ std::move (std::get<0 >(mod)), std::move (std::get<1 >(mod)), std::move (obj)};
130+ }
131+
132+ TYPE_PARSER (construct<OmpMapClause>(applyFunction<OmpMapClause>(makeMapClause,
133+ (MapModifiers(" ," _tok) ||
134+ MapModifiers(maybe(" ," _tok),
135+ "the specification of modifiers without comma separators for the "
136+ "'MAP' clause has been deprecated"_port_en_US)),
137+ Parser<OmpObjectList>{})))
55138
56139// [OpenMP 5.0]
57140// 2.19.7.2 defaultmap(implicit-behavior[:variable-category])
0 commit comments