|
19 | 19 | #include "llvm/ADT/StringExtras.h" |
20 | 20 | #include "llvm/ADT/TypeSwitch.h" |
21 | 21 | #include "llvm/Support/Casting.h" |
| 22 | +#include "llvm/Support/FormatVariadic.h" |
22 | 23 |
|
23 | 24 | using namespace mlir; |
24 | 25 | using namespace mlir::emitc; |
@@ -167,6 +168,63 @@ static LogicalResult verifyInitializationAttribute(Operation *op, |
167 | 168 | return success(); |
168 | 169 | } |
169 | 170 |
|
| 171 | +/// Parse a format string and return a list of its parts. |
| 172 | +/// A part is either a StringRef that has to be printed as-is, or |
| 173 | +/// a Placeholder which requires printing the next operand of the VerbatimOp. |
| 174 | +/// In the format string, all `{}` are replaced by Placeholders, except if the |
| 175 | +/// `{` is escaped by `{{` - then it doesn't start a placeholder. |
| 176 | +template <class ArgType> |
| 177 | +FailureOr<SmallVector<ReplacementItem>> |
| 178 | +parseFormatString(StringRef toParse, ArgType fmtArgs, |
| 179 | + std::optional<llvm::function_ref<mlir::InFlightDiagnostic()>> |
| 180 | + emitError = {}) { |
| 181 | + SmallVector<ReplacementItem> items; |
| 182 | + |
| 183 | + // If there are not operands, the format string is not interpreted. |
| 184 | + if (fmtArgs.empty()) { |
| 185 | + items.push_back(toParse); |
| 186 | + return items; |
| 187 | + } |
| 188 | + |
| 189 | + while (!toParse.empty()) { |
| 190 | + size_t idx = toParse.find('{'); |
| 191 | + if (idx == StringRef::npos) { |
| 192 | + // No '{' |
| 193 | + items.push_back(toParse); |
| 194 | + break; |
| 195 | + } |
| 196 | + if (idx > 0) { |
| 197 | + // Take all chars excluding the '{'. |
| 198 | + items.push_back(toParse.take_front(idx)); |
| 199 | + toParse = toParse.drop_front(idx); |
| 200 | + continue; |
| 201 | + } |
| 202 | + if (toParse.size() < 2) { |
| 203 | + return (*emitError)() |
| 204 | + << "expected '}' after unescaped '{' at end of string"; |
| 205 | + } |
| 206 | + // toParse contains at least two characters and starts with `{`. |
| 207 | + char nextChar = toParse[1]; |
| 208 | + if (nextChar == '{') { |
| 209 | + // Double '{{' -> '{' (escaping). |
| 210 | + items.push_back(toParse.take_front(1)); |
| 211 | + toParse = toParse.drop_front(2); |
| 212 | + continue; |
| 213 | + } |
| 214 | + if (nextChar == '}') { |
| 215 | + items.push_back(Placeholder{}); |
| 216 | + toParse = toParse.drop_front(2); |
| 217 | + continue; |
| 218 | + } |
| 219 | + |
| 220 | + if (emitError.has_value()) { |
| 221 | + return (*emitError)() << "expected '}' after unescaped '{'"; |
| 222 | + } |
| 223 | + return failure(); |
| 224 | + } |
| 225 | + return items; |
| 226 | +} |
| 227 | + |
170 | 228 | //===----------------------------------------------------------------------===// |
171 | 229 | // AddOp |
172 | 230 | //===----------------------------------------------------------------------===// |
@@ -909,6 +967,55 @@ LogicalResult emitc::SubscriptOp::verify() { |
909 | 967 | return success(); |
910 | 968 | } |
911 | 969 |
|
| 970 | +//===----------------------------------------------------------------------===// |
| 971 | +// VerbatimOp |
| 972 | +//===----------------------------------------------------------------------===// |
| 973 | + |
| 974 | +LogicalResult emitc::VerbatimOp::verify() { |
| 975 | + auto errorCallback = [&]() -> InFlightDiagnostic { |
| 976 | + return this->emitOpError(); |
| 977 | + }; |
| 978 | + FailureOr<SmallVector<ReplacementItem>> fmt = |
| 979 | + ::parseFormatString(getValue(), getFmtArgs(), errorCallback); |
| 980 | + if (failed(fmt)) |
| 981 | + return failure(); |
| 982 | + |
| 983 | + size_t numPlaceholders = llvm::count_if(*fmt, [](ReplacementItem &item) { |
| 984 | + return std::holds_alternative<Placeholder>(item); |
| 985 | + }); |
| 986 | + |
| 987 | + if (numPlaceholders != getFmtArgs().size()) { |
| 988 | + return emitOpError() |
| 989 | + << "requires operands for each placeholder in the format string"; |
| 990 | + } |
| 991 | + return success(); |
| 992 | +} |
| 993 | + |
| 994 | +static ParseResult parseVariadicTypeFmtArgs(AsmParser &p, |
| 995 | + SmallVector<Type> ¶ms) { |
| 996 | + Type type; |
| 997 | + if (p.parseType(type)) |
| 998 | + return failure(); |
| 999 | + |
| 1000 | + params.push_back(type); |
| 1001 | + while (succeeded(p.parseOptionalComma())) { |
| 1002 | + if (p.parseType(type)) |
| 1003 | + return failure(); |
| 1004 | + params.push_back(type); |
| 1005 | + } |
| 1006 | + |
| 1007 | + return success(); |
| 1008 | +} |
| 1009 | + |
| 1010 | +static void printVariadicTypeFmtArgs(AsmPrinter &p, ArrayRef<Type> params) { |
| 1011 | + llvm::interleaveComma(params, p, [&](Type type) { p.printType(type); }); |
| 1012 | +} |
| 1013 | + |
| 1014 | +FailureOr<SmallVector<ReplacementItem>> emitc::VerbatimOp::parseFormatString() { |
| 1015 | + // Error checking is done in verify. |
| 1016 | + return ::parseFormatString(getValue(), getFmtArgs()); |
| 1017 | +} |
| 1018 | + |
912 | 1019 | //===----------------------------------------------------------------------===// |
913 | 1020 | // EmitC Enums |
914 | 1021 | //===----------------------------------------------------------------------===// |
|
0 commit comments