1 | //===- DialectImplementation.h ----------------------------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file contains utilities classes for implementing dialect attributes and |
10 | // types. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef MLIR_IR_DIALECTIMPLEMENTATION_H |
15 | #define MLIR_IR_DIALECTIMPLEMENTATION_H |
16 | |
17 | #include "mlir/IR/OpImplementation.h" |
18 | |
19 | namespace mlir { |
20 | |
21 | //===----------------------------------------------------------------------===// |
22 | // DialectAsmPrinter |
23 | //===----------------------------------------------------------------------===// |
24 | |
25 | /// This is a pure-virtual base class that exposes the asmprinter hooks |
26 | /// necessary to implement a custom printAttribute/printType() method on a |
27 | /// dialect. |
28 | class DialectAsmPrinter : public AsmPrinter { |
29 | public: |
30 | using AsmPrinter::AsmPrinter; |
31 | ~DialectAsmPrinter() override; |
32 | }; |
33 | |
34 | //===----------------------------------------------------------------------===// |
35 | // DialectAsmParser |
36 | //===----------------------------------------------------------------------===// |
37 | |
38 | /// The DialectAsmParser has methods for interacting with the asm parser when |
39 | /// parsing attributes and types. |
40 | class DialectAsmParser : public AsmParser { |
41 | public: |
42 | using AsmParser::AsmParser; |
43 | ~DialectAsmParser() override; |
44 | |
45 | /// Returns the full specification of the symbol being parsed. This allows for |
46 | /// using a separate parser if necessary. |
47 | virtual StringRef getFullSymbolSpec() const = 0; |
48 | }; |
49 | |
50 | //===----------------------------------------------------------------------===// |
51 | // Parse Fields |
52 | //===----------------------------------------------------------------------===// |
53 | |
54 | /// Provide a template class that can be specialized by users to dispatch to |
55 | /// parsers. Auto-generated parsers generate calls to `FieldParser<T>::parse`, |
56 | /// where `T` is the parameter storage type, to parse custom types. |
57 | template <typename T, typename = T> |
58 | struct FieldParser; |
59 | |
60 | /// Parse an attribute. |
61 | template <typename AttributeT> |
62 | struct FieldParser< |
63 | AttributeT, std::enable_if_t<std::is_base_of<Attribute, AttributeT>::value, |
64 | AttributeT>> { |
65 | static FailureOr<AttributeT> parse(AsmParser &parser) { |
66 | AttributeT value; |
67 | if (parser.parseCustomAttributeWithFallback(value)) |
68 | return failure(); |
69 | return value; |
70 | } |
71 | }; |
72 | |
73 | /// Parse an attribute. |
74 | template <typename TypeT> |
75 | struct FieldParser< |
76 | TypeT, std::enable_if_t<std::is_base_of<Type, TypeT>::value, TypeT>> { |
77 | static FailureOr<TypeT> parse(AsmParser &parser) { |
78 | TypeT value; |
79 | if (parser.parseCustomTypeWithFallback(value)) |
80 | return failure(); |
81 | return value; |
82 | } |
83 | }; |
84 | |
85 | /// Parse any integer. |
86 | template <typename IntT> |
87 | struct FieldParser<IntT, |
88 | std::enable_if_t<std::is_integral<IntT>::value, IntT>> { |
89 | static FailureOr<IntT> parse(AsmParser &parser) { |
90 | IntT value = 0; |
91 | if (parser.parseInteger(value)) |
92 | return failure(); |
93 | return value; |
94 | } |
95 | }; |
96 | |
97 | /// Parse a string. |
98 | template <> |
99 | struct FieldParser<std::string> { |
100 | static FailureOr<std::string> parse(AsmParser &parser) { |
101 | std::string value; |
102 | if (parser.parseString(string: &value)) |
103 | return failure(); |
104 | return value; |
105 | } |
106 | }; |
107 | |
108 | /// Parse an Optional attribute. |
109 | template <typename AttributeT> |
110 | struct FieldParser< |
111 | std::optional<AttributeT>, |
112 | std::enable_if_t<std::is_base_of<Attribute, AttributeT>::value, |
113 | std::optional<AttributeT>>> { |
114 | static FailureOr<std::optional<AttributeT>> parse(AsmParser &parser) { |
115 | AttributeT attr; |
116 | OptionalParseResult result = parser.parseOptionalAttribute(attr); |
117 | if (result.has_value()) { |
118 | if (succeeded(result: *result)) |
119 | return {std::optional<AttributeT>(attr)}; |
120 | return failure(); |
121 | } |
122 | return {std::nullopt}; |
123 | } |
124 | }; |
125 | |
126 | /// Parse an Optional integer. |
127 | template <typename IntT> |
128 | struct FieldParser< |
129 | std::optional<IntT>, |
130 | std::enable_if_t<std::is_integral<IntT>::value, std::optional<IntT>>> { |
131 | static FailureOr<std::optional<IntT>> parse(AsmParser &parser) { |
132 | IntT value; |
133 | OptionalParseResult result = parser.parseOptionalInteger(value); |
134 | if (result.has_value()) { |
135 | if (succeeded(result: *result)) |
136 | return {std::optional<IntT>(value)}; |
137 | return failure(); |
138 | } |
139 | return {std::nullopt}; |
140 | } |
141 | }; |
142 | |
143 | namespace detail { |
144 | template <typename T> |
145 | using has_push_back_t = decltype(std::declval<T>().push_back( |
146 | std::declval<typename T::value_type &&>())); |
147 | } // namespace detail |
148 | |
149 | /// Parse any container that supports back insertion as a list. |
150 | template <typename ContainerT> |
151 | struct FieldParser<ContainerT, |
152 | std::enable_if_t<llvm::is_detected<detail::has_push_back_t, |
153 | ContainerT>::value, |
154 | ContainerT>> { |
155 | using ElementT = typename ContainerT::value_type; |
156 | static FailureOr<ContainerT> parse(AsmParser &parser) { |
157 | ContainerT elements; |
158 | auto elementParser = [&]() { |
159 | auto element = FieldParser<ElementT>::parse(parser); |
160 | if (failed(element)) |
161 | return failure(); |
162 | elements.push_back(std::move(*element)); |
163 | return success(); |
164 | }; |
165 | if (parser.parseCommaSeparatedList(elementParser)) |
166 | return failure(); |
167 | return elements; |
168 | } |
169 | }; |
170 | |
171 | /// Parse an affine map. |
172 | template <> |
173 | struct FieldParser<AffineMap> { |
174 | static FailureOr<AffineMap> parse(AsmParser &parser) { |
175 | AffineMap map; |
176 | if (failed(result: parser.parseAffineMap(map))) |
177 | return failure(); |
178 | return map; |
179 | } |
180 | }; |
181 | |
182 | } // namespace mlir |
183 | |
184 | #endif // MLIR_IR_DIALECTIMPLEMENTATION_H |
185 | |