111db2642SZachary Turner //===- FormatVariadic.cpp - Format string parsing and analysis ----*-C++-*-===// 211db2642SZachary Turner // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 611db2642SZachary Turner //===----------------------------------------------------------------------===// 711db2642SZachary Turner 811db2642SZachary Turner #include "llvm/Support/FormatVariadic.h" 9eb812efaSJoerg Sonnenberger #include <cassert> 1011db2642SZachary Turner 1111db2642SZachary Turner using namespace llvm; 1211db2642SZachary Turner 1311db2642SZachary Turner static Optional<AlignStyle> translateLocChar(char C) { 1411db2642SZachary Turner switch (C) { 1511db2642SZachary Turner case '-': 1611db2642SZachary Turner return AlignStyle::Left; 1711db2642SZachary Turner case '=': 1811db2642SZachary Turner return AlignStyle::Center; 1911db2642SZachary Turner case '+': 2011db2642SZachary Turner return AlignStyle::Right; 2111db2642SZachary Turner default: 2211db2642SZachary Turner return None; 2311db2642SZachary Turner } 2411db2642SZachary Turner LLVM_BUILTIN_UNREACHABLE; 2511db2642SZachary Turner } 2611db2642SZachary Turner 2711db2642SZachary Turner bool formatv_object_base::consumeFieldLayout(StringRef &Spec, AlignStyle &Where, 2811db2642SZachary Turner size_t &Align, char &Pad) { 2911db2642SZachary Turner Where = AlignStyle::Right; 3011db2642SZachary Turner Align = 0; 3111db2642SZachary Turner Pad = ' '; 3211db2642SZachary Turner if (Spec.empty()) 3311db2642SZachary Turner return true; 3411db2642SZachary Turner 3511db2642SZachary Turner if (Spec.size() > 1) { 3611db2642SZachary Turner // A maximum of 2 characters at the beginning can be used for something 3711db2642SZachary Turner // other 3811db2642SZachary Turner // than the width. 3911db2642SZachary Turner // If Spec[1] is a loc char, then Spec[0] is a pad char and Spec[2:...] 4011db2642SZachary Turner // contains the width. 4111db2642SZachary Turner // Otherwise, if Spec[0] is a loc char, then Spec[1:...] contains the width. 4211db2642SZachary Turner // Otherwise, Spec[0:...] contains the width. 4311db2642SZachary Turner if (auto Loc = translateLocChar(Spec[1])) { 4411db2642SZachary Turner Pad = Spec[0]; 4511db2642SZachary Turner Where = *Loc; 4611db2642SZachary Turner Spec = Spec.drop_front(2); 4711db2642SZachary Turner } else if (auto Loc = translateLocChar(Spec[0])) { 4811db2642SZachary Turner Where = *Loc; 4911db2642SZachary Turner Spec = Spec.drop_front(1); 5011db2642SZachary Turner } 5111db2642SZachary Turner } 5211db2642SZachary Turner 5311db2642SZachary Turner bool Failed = Spec.consumeInteger(0, Align); 5411db2642SZachary Turner return !Failed; 5511db2642SZachary Turner } 5611db2642SZachary Turner 5711db2642SZachary Turner Optional<ReplacementItem> 5811db2642SZachary Turner formatv_object_base::parseReplacementItem(StringRef Spec) { 5911db2642SZachary Turner StringRef RepString = Spec.trim("{}"); 6011db2642SZachary Turner 6111db2642SZachary Turner // If the replacement sequence does not start with a non-negative integer, 6211db2642SZachary Turner // this is an error. 6311db2642SZachary Turner char Pad = ' '; 6411db2642SZachary Turner std::size_t Align = 0; 6511db2642SZachary Turner AlignStyle Where = AlignStyle::Right; 6611db2642SZachary Turner StringRef Options; 6711db2642SZachary Turner size_t Index = 0; 6811db2642SZachary Turner RepString = RepString.trim(); 6911db2642SZachary Turner if (RepString.consumeInteger(0, Index)) { 7011db2642SZachary Turner assert(false && "Invalid replacement sequence index!"); 7111db2642SZachary Turner return ReplacementItem{}; 7211db2642SZachary Turner } 7311db2642SZachary Turner RepString = RepString.trim(); 7411db2642SZachary Turner if (!RepString.empty() && RepString.front() == ',') { 7511db2642SZachary Turner RepString = RepString.drop_front(); 7611db2642SZachary Turner if (!consumeFieldLayout(RepString, Where, Align, Pad)) 7711db2642SZachary Turner assert(false && "Invalid replacement field layout specification!"); 7811db2642SZachary Turner } 7911db2642SZachary Turner RepString = RepString.trim(); 8011db2642SZachary Turner if (!RepString.empty() && RepString.front() == ':') { 8111db2642SZachary Turner Options = RepString.drop_front().trim(); 8211db2642SZachary Turner RepString = StringRef(); 8311db2642SZachary Turner } 8411db2642SZachary Turner RepString = RepString.trim(); 8511db2642SZachary Turner if (!RepString.empty()) { 8611db2642SZachary Turner assert(false && "Unexpected characters found in replacement string!"); 8711db2642SZachary Turner } 8811db2642SZachary Turner 8911db2642SZachary Turner return ReplacementItem{Spec, Index, Align, Where, Pad, Options}; 9011db2642SZachary Turner } 9111db2642SZachary Turner 9211db2642SZachary Turner std::pair<ReplacementItem, StringRef> 9311db2642SZachary Turner formatv_object_base::splitLiteralAndReplacement(StringRef Fmt) { 9411db2642SZachary Turner std::size_t From = 0; 9511db2642SZachary Turner while (From < Fmt.size() && From != StringRef::npos) { 9611db2642SZachary Turner std::size_t BO = Fmt.find_first_of('{', From); 9711db2642SZachary Turner // Everything up until the first brace is a literal. 9811db2642SZachary Turner if (BO != 0) 9911db2642SZachary Turner return std::make_pair(ReplacementItem{Fmt.substr(0, BO)}, Fmt.substr(BO)); 10011db2642SZachary Turner 10111db2642SZachary Turner StringRef Braces = 10211db2642SZachary Turner Fmt.drop_front(BO).take_while([](char C) { return C == '{'; }); 10311db2642SZachary Turner // If there is more than one brace, then some of them are escaped. Treat 10411db2642SZachary Turner // these as replacements. 10511db2642SZachary Turner if (Braces.size() > 1) { 10611db2642SZachary Turner size_t NumEscapedBraces = Braces.size() / 2; 10711db2642SZachary Turner StringRef Middle = Fmt.substr(BO, NumEscapedBraces); 10811db2642SZachary Turner StringRef Right = Fmt.drop_front(BO + NumEscapedBraces * 2); 10911db2642SZachary Turner return std::make_pair(ReplacementItem{Middle}, Right); 11011db2642SZachary Turner } 11111db2642SZachary Turner // An unterminated open brace is undefined. We treat the rest of the string 11211db2642SZachary Turner // as a literal replacement, but we assert to indicate that this is 11311db2642SZachary Turner // undefined and that we consider it an error. 11411db2642SZachary Turner std::size_t BC = Fmt.find_first_of('}', BO); 11511db2642SZachary Turner if (BC == StringRef::npos) { 11611db2642SZachary Turner assert( 11711db2642SZachary Turner false && 11811db2642SZachary Turner "Unterminated brace sequence. Escape with {{ for a literal brace."); 11911db2642SZachary Turner return std::make_pair(ReplacementItem{Fmt}, StringRef()); 12011db2642SZachary Turner } 12111db2642SZachary Turner 12211db2642SZachary Turner // Even if there is a closing brace, if there is another open brace before 12311db2642SZachary Turner // this closing brace, treat this portion as literal, and try again with the 12411db2642SZachary Turner // next one. 12511db2642SZachary Turner std::size_t BO2 = Fmt.find_first_of('{', BO + 1); 12611db2642SZachary Turner if (BO2 < BC) 12711db2642SZachary Turner return std::make_pair(ReplacementItem{Fmt.substr(0, BO2)}, 12811db2642SZachary Turner Fmt.substr(BO2)); 12911db2642SZachary Turner 13011db2642SZachary Turner StringRef Spec = Fmt.slice(BO + 1, BC); 13111db2642SZachary Turner StringRef Right = Fmt.substr(BC + 1); 13211db2642SZachary Turner 13311db2642SZachary Turner auto RI = parseReplacementItem(Spec); 13411db2642SZachary Turner if (RI.hasValue()) 13511db2642SZachary Turner return std::make_pair(*RI, Right); 13611db2642SZachary Turner 13711db2642SZachary Turner // If there was an error parsing the replacement item, treat it as an 13811db2642SZachary Turner // invalid replacement spec, and just continue. 13911db2642SZachary Turner From = BC + 1; 14011db2642SZachary Turner } 14111db2642SZachary Turner return std::make_pair(ReplacementItem{Fmt}, StringRef()); 14211db2642SZachary Turner } 14311db2642SZachary Turner 144*5ef2cb3dSBenjamin Kramer SmallVector<ReplacementItem, 2> 14511db2642SZachary Turner formatv_object_base::parseFormatString(StringRef Fmt) { 146*5ef2cb3dSBenjamin Kramer SmallVector<ReplacementItem, 2> Replacements; 14711db2642SZachary Turner ReplacementItem I; 14811db2642SZachary Turner while (!Fmt.empty()) { 14911db2642SZachary Turner std::tie(I, Fmt) = splitLiteralAndReplacement(Fmt); 15011db2642SZachary Turner if (I.Type != ReplacementType::Empty) 15111db2642SZachary Turner Replacements.push_back(I); 15211db2642SZachary Turner } 15311db2642SZachary Turner return Replacements; 15411db2642SZachary Turner } 155a87b70d1SRichard Trieu 156a87b70d1SRichard Trieu void detail::format_adapter::anchor() { } 157