github.com/johnnyeven/libtools@v0.0.0-20191126065708-61829c1adf46/third_party/mlir/lib/TableGen/Format.cpp (about) 1 //===- Format.cpp - Utilities for String Format ---------------------------===// 2 // 3 // Copyright 2019 The MLIR Authors. 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 // ============================================================================= 17 // 18 // This file defines utilities for formatting strings. They are specially 19 // tailored to the needs of TableGen'ing op definitions and rewrite rules, 20 // so they are not expected to be used as widely applicable utilities. 21 // 22 //===----------------------------------------------------------------------===// 23 24 #include "mlir/TableGen/Format.h" 25 #include <cctype> 26 27 using namespace mlir; 28 using namespace mlir::tblgen; 29 30 // Marker to indicate an error happened when replacing a placeholder. 31 const char *const kMarkerForNoSubst = "<no-subst-found>"; 32 33 FmtContext &tblgen::FmtContext::addSubst(StringRef placeholder, Twine subst) { 34 customSubstMap[placeholder] = subst.str(); 35 return *this; 36 } 37 38 FmtContext &tblgen::FmtContext::withBuilder(Twine subst) { 39 builtinSubstMap[PHKind::Builder] = subst.str(); 40 return *this; 41 } 42 43 FmtContext &tblgen::FmtContext::withOp(Twine subst) { 44 builtinSubstMap[PHKind::Op] = subst.str(); 45 return *this; 46 } 47 48 FmtContext &tblgen::FmtContext::withSelf(Twine subst) { 49 builtinSubstMap[PHKind::Self] = subst.str(); 50 return *this; 51 } 52 53 Optional<StringRef> 54 tblgen::FmtContext::getSubstFor(FmtContext::PHKind placeholder) const { 55 if (placeholder == FmtContext::PHKind::None || 56 placeholder == FmtContext::PHKind::Custom) 57 return {}; 58 auto it = builtinSubstMap.find(placeholder); 59 if (it == builtinSubstMap.end()) 60 return {}; 61 return StringRef(it->second); 62 } 63 64 Optional<StringRef> 65 tblgen::FmtContext::getSubstFor(StringRef placeholder) const { 66 auto it = customSubstMap.find(placeholder); 67 if (it == customSubstMap.end()) 68 return {}; 69 return StringRef(it->second); 70 } 71 72 FmtContext::PHKind tblgen::FmtContext::getPlaceHolderKind(StringRef str) { 73 return llvm::StringSwitch<FmtContext::PHKind>(str) 74 .Case("_builder", FmtContext::PHKind::Builder) 75 .Case("_op", FmtContext::PHKind::Op) 76 .Case("_self", FmtContext::PHKind::Self) 77 .Case("", FmtContext::PHKind::None) 78 .Default(FmtContext::PHKind::Custom); 79 } 80 81 std::pair<FmtReplacement, StringRef> 82 tblgen::FmtObjectBase::splitFmtSegment(StringRef fmt) { 83 size_t begin = fmt.find_first_of('$'); 84 if (begin == StringRef::npos) { 85 // No placeholders: the whole format string should be returned as a 86 // literal string. 87 return {FmtReplacement{fmt}, StringRef()}; 88 } 89 if (begin != 0) { 90 // The first placeholder is not at the beginning: we can split the format 91 // string into a literal string and the rest. 92 return {FmtReplacement{fmt.substr(0, begin)}, fmt.substr(begin)}; 93 } 94 95 // The first placeholder is at the beginning 96 97 if (fmt.size() == 1) { 98 // The whole format string just contains '$': treat as literal. 99 return {FmtReplacement{fmt}, StringRef()}; 100 } 101 102 // Allow escaping dollar with '$$' 103 if (fmt[1] == '$') { 104 return {FmtReplacement{fmt.substr(0, 1)}, fmt.substr(2)}; 105 } 106 107 // First try to see if it's a positional placeholder, and then handle special 108 // placeholders. 109 110 size_t end = fmt.find_if_not([](char c) { return std::isdigit(c); }, 1); 111 if (end != 1) { 112 // We have a positional placeholder. Parse the index. 113 size_t index = 0; 114 if (fmt.substr(1, end - 1).consumeInteger(0, index)) { 115 llvm_unreachable("invalid replacement sequence index"); 116 } 117 118 if (end == StringRef::npos) { 119 // All the remaining characters are part of the positional placeholder. 120 return {FmtReplacement{fmt, index}, StringRef()}; 121 } 122 return {FmtReplacement{fmt.substr(0, end), index}, fmt.substr(end)}; 123 } 124 125 end = fmt.find_if_not([](char c) { return std::isalnum(c) || c == '_'; }, 1); 126 auto placeholder = FmtContext::getPlaceHolderKind(fmt.substr(1, end - 1)); 127 if (end == StringRef::npos) { 128 // All the remaining characters are part of the special placeholder. 129 return {FmtReplacement{fmt, placeholder}, StringRef()}; 130 } 131 return {FmtReplacement{fmt.substr(0, end), placeholder}, fmt.substr(end)}; 132 } 133 134 std::vector<FmtReplacement> FmtObjectBase::parseFormatString(StringRef fmt) { 135 std::vector<FmtReplacement> replacements; 136 FmtReplacement repl; 137 while (!fmt.empty()) { 138 std::tie(repl, fmt) = splitFmtSegment(fmt); 139 if (repl.type != FmtReplacement::Type::Empty) 140 replacements.push_back(repl); 141 } 142 return replacements; 143 } 144 145 void FmtObjectBase::format(raw_ostream &s) const { 146 for (auto &repl : replacements) { 147 if (repl.type == FmtReplacement::Type::Empty) 148 continue; 149 150 if (repl.type == FmtReplacement::Type::Literal) { 151 s << repl.spec; 152 continue; 153 } 154 155 if (repl.type == FmtReplacement::Type::SpecialPH) { 156 if (repl.placeholder == FmtContext::PHKind::None) { 157 s << repl.spec; 158 } else if (!context) { 159 // We need the context to replace special placeholders. 160 s << repl.spec << kMarkerForNoSubst; 161 } else { 162 Optional<StringRef> subst; 163 if (repl.placeholder == FmtContext::PHKind::Custom) { 164 // Skip the leading '$' sign for the custom placeholder 165 subst = context->getSubstFor(repl.spec.substr(1)); 166 } else { 167 subst = context->getSubstFor(repl.placeholder); 168 } 169 if (subst) 170 s << *subst; 171 else 172 s << repl.spec << kMarkerForNoSubst; 173 } 174 continue; 175 } 176 177 assert(repl.type == FmtReplacement::Type::PositionalPH); 178 179 if (repl.index >= adapters.size()) { 180 s << repl.spec << kMarkerForNoSubst; 181 continue; 182 } 183 adapters[repl.index]->format(s, /*Options=*/""); 184 } 185 }