1*11db2642SZachary Turner //===- FormatVariadic.cpp - Format string parsing and analysis ----*-C++-*-===// 2*11db2642SZachary Turner // 3*11db2642SZachary Turner // The LLVM Compiler Infrastructure 4*11db2642SZachary Turner // 5*11db2642SZachary Turner // This file is distributed under the University of Illinois Open Source 6*11db2642SZachary Turner // License. See LICENSE.TXT for details. 7*11db2642SZachary Turner //===----------------------------------------------------------------------===// 8*11db2642SZachary Turner 9*11db2642SZachary Turner #include "llvm/Support/FormatVariadic.h" 10*11db2642SZachary Turner 11*11db2642SZachary Turner using namespace llvm; 12*11db2642SZachary Turner 13*11db2642SZachary Turner static Optional<AlignStyle> translateLocChar(char C) { 14*11db2642SZachary Turner switch (C) { 15*11db2642SZachary Turner case '-': 16*11db2642SZachary Turner return AlignStyle::Left; 17*11db2642SZachary Turner case '=': 18*11db2642SZachary Turner return AlignStyle::Center; 19*11db2642SZachary Turner case '+': 20*11db2642SZachary Turner return AlignStyle::Right; 21*11db2642SZachary Turner default: 22*11db2642SZachary Turner return None; 23*11db2642SZachary Turner } 24*11db2642SZachary Turner LLVM_BUILTIN_UNREACHABLE; 25*11db2642SZachary Turner } 26*11db2642SZachary Turner 27*11db2642SZachary Turner bool formatv_object_base::consumeFieldLayout(StringRef &Spec, AlignStyle &Where, 28*11db2642SZachary Turner size_t &Align, char &Pad) { 29*11db2642SZachary Turner Where = AlignStyle::Right; 30*11db2642SZachary Turner Align = 0; 31*11db2642SZachary Turner Pad = ' '; 32*11db2642SZachary Turner if (Spec.empty()) 33*11db2642SZachary Turner return true; 34*11db2642SZachary Turner 35*11db2642SZachary Turner if (Spec.size() > 1) { 36*11db2642SZachary Turner // A maximum of 2 characters at the beginning can be used for something 37*11db2642SZachary Turner // other 38*11db2642SZachary Turner // than the width. 39*11db2642SZachary Turner // If Spec[1] is a loc char, then Spec[0] is a pad char and Spec[2:...] 40*11db2642SZachary Turner // contains the width. 41*11db2642SZachary Turner // Otherwise, if Spec[0] is a loc char, then Spec[1:...] contains the width. 42*11db2642SZachary Turner // Otherwise, Spec[0:...] contains the width. 43*11db2642SZachary Turner if (auto Loc = translateLocChar(Spec[1])) { 44*11db2642SZachary Turner Pad = Spec[0]; 45*11db2642SZachary Turner Where = *Loc; 46*11db2642SZachary Turner Spec = Spec.drop_front(2); 47*11db2642SZachary Turner } else if (auto Loc = translateLocChar(Spec[0])) { 48*11db2642SZachary Turner Where = *Loc; 49*11db2642SZachary Turner Spec = Spec.drop_front(1); 50*11db2642SZachary Turner } 51*11db2642SZachary Turner } 52*11db2642SZachary Turner 53*11db2642SZachary Turner bool Failed = Spec.consumeInteger(0, Align); 54*11db2642SZachary Turner return !Failed; 55*11db2642SZachary Turner } 56*11db2642SZachary Turner 57*11db2642SZachary Turner Optional<ReplacementItem> 58*11db2642SZachary Turner formatv_object_base::parseReplacementItem(StringRef Spec) { 59*11db2642SZachary Turner StringRef RepString = Spec.trim("{}"); 60*11db2642SZachary Turner 61*11db2642SZachary Turner // If the replacement sequence does not start with a non-negative integer, 62*11db2642SZachary Turner // this is an error. 63*11db2642SZachary Turner char Pad = ' '; 64*11db2642SZachary Turner std::size_t Align = 0; 65*11db2642SZachary Turner AlignStyle Where = AlignStyle::Right; 66*11db2642SZachary Turner StringRef Options; 67*11db2642SZachary Turner size_t Index = 0; 68*11db2642SZachary Turner RepString = RepString.trim(); 69*11db2642SZachary Turner if (RepString.consumeInteger(0, Index)) { 70*11db2642SZachary Turner assert(false && "Invalid replacement sequence index!"); 71*11db2642SZachary Turner return ReplacementItem{}; 72*11db2642SZachary Turner } 73*11db2642SZachary Turner RepString = RepString.trim(); 74*11db2642SZachary Turner if (!RepString.empty() && RepString.front() == ',') { 75*11db2642SZachary Turner RepString = RepString.drop_front(); 76*11db2642SZachary Turner if (!consumeFieldLayout(RepString, Where, Align, Pad)) 77*11db2642SZachary Turner assert(false && "Invalid replacement field layout specification!"); 78*11db2642SZachary Turner } 79*11db2642SZachary Turner RepString = RepString.trim(); 80*11db2642SZachary Turner if (!RepString.empty() && RepString.front() == ':') { 81*11db2642SZachary Turner Options = RepString.drop_front().trim(); 82*11db2642SZachary Turner RepString = StringRef(); 83*11db2642SZachary Turner } 84*11db2642SZachary Turner RepString = RepString.trim(); 85*11db2642SZachary Turner if (!RepString.empty()) { 86*11db2642SZachary Turner assert(false && "Unexpected characters found in replacement string!"); 87*11db2642SZachary Turner } 88*11db2642SZachary Turner 89*11db2642SZachary Turner return ReplacementItem{Spec, Index, Align, Where, Pad, Options}; 90*11db2642SZachary Turner } 91*11db2642SZachary Turner 92*11db2642SZachary Turner std::pair<ReplacementItem, StringRef> 93*11db2642SZachary Turner formatv_object_base::splitLiteralAndReplacement(StringRef Fmt) { 94*11db2642SZachary Turner StringRef Rep; 95*11db2642SZachary Turner StringRef Remainder; 96*11db2642SZachary Turner std::size_t From = 0; 97*11db2642SZachary Turner while (From < Fmt.size() && From != StringRef::npos) { 98*11db2642SZachary Turner std::size_t BO = Fmt.find_first_of('{', From); 99*11db2642SZachary Turner // Everything up until the first brace is a literal. 100*11db2642SZachary Turner if (BO != 0) 101*11db2642SZachary Turner return std::make_pair(ReplacementItem{Fmt.substr(0, BO)}, Fmt.substr(BO)); 102*11db2642SZachary Turner 103*11db2642SZachary Turner StringRef Braces = 104*11db2642SZachary Turner Fmt.drop_front(BO).take_while([](char C) { return C == '{'; }); 105*11db2642SZachary Turner // If there is more than one brace, then some of them are escaped. Treat 106*11db2642SZachary Turner // these as replacements. 107*11db2642SZachary Turner if (Braces.size() > 1) { 108*11db2642SZachary Turner size_t NumEscapedBraces = Braces.size() / 2; 109*11db2642SZachary Turner StringRef Middle = Fmt.substr(BO, NumEscapedBraces); 110*11db2642SZachary Turner StringRef Right = Fmt.drop_front(BO + NumEscapedBraces * 2); 111*11db2642SZachary Turner return std::make_pair(ReplacementItem{Middle}, Right); 112*11db2642SZachary Turner } 113*11db2642SZachary Turner // An unterminated open brace is undefined. We treat the rest of the string 114*11db2642SZachary Turner // as a literal replacement, but we assert to indicate that this is 115*11db2642SZachary Turner // undefined and that we consider it an error. 116*11db2642SZachary Turner std::size_t BC = Fmt.find_first_of('}', BO); 117*11db2642SZachary Turner if (BC == StringRef::npos) { 118*11db2642SZachary Turner assert( 119*11db2642SZachary Turner false && 120*11db2642SZachary Turner "Unterminated brace sequence. Escape with {{ for a literal brace."); 121*11db2642SZachary Turner return std::make_pair(ReplacementItem{Fmt}, StringRef()); 122*11db2642SZachary Turner } 123*11db2642SZachary Turner 124*11db2642SZachary Turner // Even if there is a closing brace, if there is another open brace before 125*11db2642SZachary Turner // this closing brace, treat this portion as literal, and try again with the 126*11db2642SZachary Turner // next one. 127*11db2642SZachary Turner std::size_t BO2 = Fmt.find_first_of('{', BO + 1); 128*11db2642SZachary Turner if (BO2 < BC) 129*11db2642SZachary Turner return std::make_pair(ReplacementItem{Fmt.substr(0, BO2)}, 130*11db2642SZachary Turner Fmt.substr(BO2)); 131*11db2642SZachary Turner 132*11db2642SZachary Turner StringRef Spec = Fmt.slice(BO + 1, BC); 133*11db2642SZachary Turner StringRef Right = Fmt.substr(BC + 1); 134*11db2642SZachary Turner 135*11db2642SZachary Turner auto RI = parseReplacementItem(Spec); 136*11db2642SZachary Turner if (RI.hasValue()) 137*11db2642SZachary Turner return std::make_pair(*RI, Right); 138*11db2642SZachary Turner 139*11db2642SZachary Turner // If there was an error parsing the replacement item, treat it as an 140*11db2642SZachary Turner // invalid replacement spec, and just continue. 141*11db2642SZachary Turner From = BC + 1; 142*11db2642SZachary Turner } 143*11db2642SZachary Turner return std::make_pair(ReplacementItem{Fmt}, StringRef()); 144*11db2642SZachary Turner } 145*11db2642SZachary Turner 146*11db2642SZachary Turner std::vector<ReplacementItem> 147*11db2642SZachary Turner formatv_object_base::parseFormatString(StringRef Fmt) { 148*11db2642SZachary Turner std::vector<ReplacementItem> Replacements; 149*11db2642SZachary Turner ReplacementItem I; 150*11db2642SZachary Turner while (!Fmt.empty()) { 151*11db2642SZachary Turner std::tie(I, Fmt) = splitLiteralAndReplacement(Fmt); 152*11db2642SZachary Turner if (I.Type != ReplacementType::Empty) 153*11db2642SZachary Turner Replacements.push_back(I); 154*11db2642SZachary Turner } 155*11db2642SZachary Turner return Replacements; 156*11db2642SZachary Turner } 157