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