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  }