| //===- TemplatingUtils.h - Templater for text templates -----------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef MLIR_LIB_TARGET_IRDLTOCPP_TEMPLATINGUTILS_H |
| #define MLIR_LIB_TARGET_IRDLTOCPP_TEMPLATINGUTILS_H |
| |
| #include "llvm/ADT/SmallString.h" |
| #include "llvm/ADT/StringMap.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/Support/ErrorHandling.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include <variant> |
| #include <vector> |
| |
| namespace mlir::irdl::detail { |
| |
| /// A dictionary stores a mapping of template variable names to their assigned |
| /// string values. |
| using dictionary = llvm::StringMap<llvm::SmallString<8>>; |
| |
| /// Template Code as used by IRDL-to-Cpp. |
| /// |
| /// For efficiency, produces a bytecode representation of an input template. |
| /// - LiteralToken: A contiguous stream of characters to be printed |
| /// - ReplacementToken: A template variable that will be replaced |
| class Template { |
| public: |
| Template(llvm::StringRef str) { |
| bool processingReplacementToken = false; |
| while (!str.empty()) { |
| auto [token, remainder] = str.split("__"); |
| |
| if (processingReplacementToken) { |
| assert(!token.empty() && "replacement name cannot be empty"); |
| bytecode.emplace_back(ReplacementToken{token}); |
| } else { |
| if (!token.empty()) |
| bytecode.emplace_back(LiteralToken{token}); |
| } |
| |
| processingReplacementToken = !processingReplacementToken; |
| str = remainder; |
| } |
| } |
| |
| /// Render will apply a dictionary to the Template and send the rendered |
| /// result to the specified output stream. |
| void render(llvm::raw_ostream &out, const dictionary &replacements) const { |
| for (auto instruction : bytecode) { |
| if (auto *inst = std::get_if<LiteralToken>(&instruction)) { |
| out << inst->text; |
| continue; |
| } |
| |
| if (auto *inst = std::get_if<ReplacementToken>(&instruction)) { |
| auto replacement = replacements.find(inst->keyName); |
| #ifndef NDEBUG |
| if (replacement == replacements.end()) { |
| llvm::errs() << "Missing template key: " << inst->keyName << "\n"; |
| llvm_unreachable("Missing template key"); |
| } |
| #endif |
| out << replacement->second; |
| continue; |
| } |
| |
| llvm_unreachable("non-exhaustive bytecode visit"); |
| } |
| } |
| |
| private: |
| struct LiteralToken { |
| llvm::StringRef text; |
| }; |
| |
| struct ReplacementToken { |
| llvm::StringRef keyName; |
| }; |
| |
| std::vector<std::variant<LiteralToken, ReplacementToken>> bytecode; |
| }; |
| |
| } // namespace mlir::irdl::detail |
| |
| #endif // MLIR_LIB_TARGET_IRDLTOCPP_TEMPLATINGUTILS_H |