@@ -158,31 +158,23 @@ static TypeDeclarationStmt makeIterSpecDecl(std::list<ObjectName> &&names) {
158158static std::string nameToString(Name &&name) { return name.ToString(); }
159159
160160TYPE_PARSER(sourced(construct<OmpTraitPropertyName>( //
161- (space >> charLiteralConstantWithoutKind) ||
162- applyFunction(nameToString, Parser<Name>{}))))
161+ construct<OmpTraitPropertyName>(space >> charLiteralConstantWithoutKind) ||
162+ construct<OmpTraitPropertyName>(
163+ applyFunction(nameToString, Parser<Name>{})))))
163164
164165TYPE_PARSER(sourced(construct<OmpTraitScore>( //
165- "SCORE" >> parenthesized(scalarIntExpr))))
166+ "SCORE"_tok >> parenthesized(scalarIntExpr))))
166167
167- TYPE_PARSER(sourced(construct<OmpTraitPropertyExtension::ExtensionValue>(
168- // Parse nested extension first.
169- construct<OmpTraitPropertyExtension::ExtensionValue>(
170- indirect(Parser<OmpTraitPropertyExtension>{})) ||
171- construct<OmpTraitPropertyExtension::ExtensionValue>(
172- Parser<OmpTraitPropertyName>{}) ||
173- construct<OmpTraitPropertyExtension::ExtensionValue>(scalarExpr))))
174-
175- TYPE_PARSER(sourced(construct<OmpTraitPropertyExtension>( //
168+ TYPE_PARSER(sourced(construct<OmpTraitPropertyExtension::Complex>(
176169 Parser<OmpTraitPropertyName>{},
177170 parenthesized(nonemptySeparated(
178- Parser<OmpTraitPropertyExtension::ExtensionValue >{}, ","_tok)))))
171+ indirect( Parser<OmpTraitPropertyExtension>{}) , ","_tok)))))
179172
180- TYPE_PARSER(sourced(construct<OmpTraitProperty>(
181- // Try clause first, then extension before OmpTraitPropertyName.
182- construct<OmpTraitProperty>(indirect(Parser<OmpClause>{})) ||
183- construct<OmpTraitProperty>(Parser<OmpTraitPropertyExtension>{}) ||
184- construct<OmpTraitProperty>(Parser<OmpTraitPropertyName>{}) ||
185- construct<OmpTraitProperty>(scalarExpr))))
173+ TYPE_PARSER(sourced(construct<OmpTraitPropertyExtension>(
174+ construct<OmpTraitPropertyExtension>(
175+ Parser<OmpTraitPropertyExtension::Complex>{}) ||
176+ construct<OmpTraitPropertyExtension>(Parser<OmpTraitPropertyName>{}) ||
177+ construct<OmpTraitPropertyExtension>(scalarExpr))))
186178
187179TYPE_PARSER(construct<OmpTraitSelectorName::Value>(
188180 "ARCH" >> pure(OmpTraitSelectorName::Value::Arch) ||
@@ -201,15 +193,96 @@ TYPE_PARSER(construct<OmpTraitSelectorName::Value>(
201193TYPE_PARSER(sourced(construct<OmpTraitSelectorName>(
202194 // Parse predefined names first (because of SIMD).
203195 construct<OmpTraitSelectorName>(Parser<OmpTraitSelectorName::Value>{}) ||
204- construct<OmpTraitSelectorName>(OmpDirectiveNameParser{}))))
196+ construct<OmpTraitSelectorName>(OmpDirectiveNameParser{}) ||
197+ // identifier-or-string for extensions
198+ construct<OmpTraitSelectorName>(
199+ applyFunction(nameToString, Parser<Name>{})) ||
200+ construct<OmpTraitSelectorName>(space >> charLiteralConstantWithoutKind))))
201+
202+ // Parser for OmpTraitSelector::Properties
203+ template <typename... PropParser>
204+ static constexpr auto propertyListParser(PropParser... pp) {
205+ // Parse the property list "(score(expr): item1...)" in three steps:
206+ // 1. Parse the "("
207+ // 2. Parse the optional "score(expr):"
208+ // 3. Parse the "item1, ...)", together with the ")".
209+ // The reason for including the ")" in the 3rd step is to force parsing
210+ // the entire list in each of the alternative property parsers. Otherwise,
211+ // the name parser could stop after "foo" in "(foo, bar(1))", without
212+ // allowing the next parser to give the list a try.
213+
214+ using P = OmpTraitProperty;
215+ return maybe("(" >>
216+ construct<OmpTraitSelector::Properties>(
217+ maybe(Parser<OmpTraitScore>{} / ":"_tok),
218+ (attempt(nonemptySeparated(construct<P>(pp), ","_tok) / ")"_tok) ||
219+ ...)));
220+ }
221+
222+ // Parser for OmpTraitSelector
223+ struct TraitSelectorParser {
224+ using resultType = OmpTraitSelector;
225+
226+ constexpr TraitSelectorParser(Parser<OmpTraitSelectorName> p) : np(p) {}
227+
228+ std::optional<resultType> Parse(ParseState &state) const {
229+ auto name{attempt(np).Parse(state)};
230+ if (!name.has_value()) {
231+ return std::nullopt;
232+ }
233+
234+ // Default fallback parser for lists that cannot be parser using the
235+ // primary property parser.
236+ auto extParser{Parser<OmpTraitPropertyExtension>{}};
237+
238+ if (auto *v{std::get_if<OmpTraitSelectorName::Value>(&name->u)}) {
239+ switch (*v) {
240+ // name-list properties
241+ case OmpTraitSelectorName::Value::Arch: // [6.0:319:18]
242+ case OmpTraitSelectorName::Value::Extension: // [6.0:319:30]
243+ case OmpTraitSelectorName::Value::Isa: // [6.0:319:15]
244+ case OmpTraitSelectorName::Value::Kind: // [6.0:319:10]
245+ case OmpTraitSelectorName::Value::Uid: // [6.0:319:23](*)
246+ case OmpTraitSelectorName::Value::Vendor: { // [6.0:319:27]
247+ auto pp{propertyListParser(Parser<OmpTraitPropertyName>{}, extParser)};
248+ return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state)));
249+ }
250+ // clause-list
251+ case OmpTraitSelectorName::Value::Atomic_Default_Mem_Order:
252+ // [6.0:321:26-29](*)
253+ case OmpTraitSelectorName::Value::Requires: // [6.0:319:33]
254+ case OmpTraitSelectorName::Value::Simd: { // [6.0:318:31]
255+ auto pp{propertyListParser(indirect(Parser<OmpClause>{}), extParser)};
256+ return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state)));
257+ }
258+ // expr-list
259+ case OmpTraitSelectorName::Value::Condition: // [6.0:321:33](*)
260+ case OmpTraitSelectorName::Value::Device_Num: { // [6.0:321:23-24](*)
261+ auto pp{propertyListParser(scalarExpr, extParser)};
262+ return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state)));
263+ }
264+ // (*) The spec doesn't assign any list-type to these traits, but for
265+ // convenience they can be treated as if they were.
266+ } // switch
267+ } else {
268+ // The other alternatives are `llvm::omp::Directive`, and `std::string`.
269+ // The former doesn't take any properties[1], the latter is a name of an
270+ // extension[2].
271+ // [1] [6.0:319:1-2]
272+ // [2] [6.0:319:36-37]
273+ auto pp{propertyListParser(extParser)};
274+ return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state)));
275+ }
205276
206- TYPE_PARSER(construct<OmpTraitSelector::Properties>(
207- maybe(Parser<OmpTraitScore>{} / ":"_tok),
208- nonemptySeparated(Parser<OmpTraitProperty>{}, ","_tok)))
277+ llvm_unreachable("Unhandled trait name?");
278+ }
279+
280+ private:
281+ const Parser<OmpTraitSelectorName> np;
282+ };
209283
210- TYPE_PARSER(sourced(construct<OmpTraitSelector>( //
211- Parser<OmpTraitSelectorName>{}, //
212- maybe(parenthesized(Parser<OmpTraitSelector::Properties>{})))))
284+ TYPE_PARSER(construct<OmpTraitSelector>(
285+ TraitSelectorParser(Parser<OmpTraitSelectorName>{})))
213286
214287TYPE_PARSER(construct<OmpTraitSetSelectorName::Value>(
215288 "CONSTRUCT" >> pure(OmpTraitSetSelectorName::Value::Construct) ||
0 commit comments