xref: /aosp_15_r20/external/regex-re2/re2/tostring.cc (revision ccdc9c3e24c519bfa4832a66aa2e83a52c19f295)
1*ccdc9c3eSSadaf Ebrahimi // Copyright 2006 The RE2 Authors.  All Rights Reserved.
2*ccdc9c3eSSadaf Ebrahimi // Use of this source code is governed by a BSD-style
3*ccdc9c3eSSadaf Ebrahimi // license that can be found in the LICENSE file.
4*ccdc9c3eSSadaf Ebrahimi 
5*ccdc9c3eSSadaf Ebrahimi // Format a regular expression structure as a string.
6*ccdc9c3eSSadaf Ebrahimi // Tested by parse_test.cc
7*ccdc9c3eSSadaf Ebrahimi 
8*ccdc9c3eSSadaf Ebrahimi #include <string.h>
9*ccdc9c3eSSadaf Ebrahimi #include <string>
10*ccdc9c3eSSadaf Ebrahimi 
11*ccdc9c3eSSadaf Ebrahimi #include "util/util.h"
12*ccdc9c3eSSadaf Ebrahimi #include "util/logging.h"
13*ccdc9c3eSSadaf Ebrahimi #include "util/strutil.h"
14*ccdc9c3eSSadaf Ebrahimi #include "util/utf.h"
15*ccdc9c3eSSadaf Ebrahimi #include "re2/regexp.h"
16*ccdc9c3eSSadaf Ebrahimi #include "re2/walker-inl.h"
17*ccdc9c3eSSadaf Ebrahimi 
18*ccdc9c3eSSadaf Ebrahimi namespace re2 {
19*ccdc9c3eSSadaf Ebrahimi 
20*ccdc9c3eSSadaf Ebrahimi enum {
21*ccdc9c3eSSadaf Ebrahimi   PrecAtom,
22*ccdc9c3eSSadaf Ebrahimi   PrecUnary,
23*ccdc9c3eSSadaf Ebrahimi   PrecConcat,
24*ccdc9c3eSSadaf Ebrahimi   PrecAlternate,
25*ccdc9c3eSSadaf Ebrahimi   PrecEmpty,
26*ccdc9c3eSSadaf Ebrahimi   PrecParen,
27*ccdc9c3eSSadaf Ebrahimi   PrecToplevel,
28*ccdc9c3eSSadaf Ebrahimi };
29*ccdc9c3eSSadaf Ebrahimi 
30*ccdc9c3eSSadaf Ebrahimi // Helper function.  See description below.
31*ccdc9c3eSSadaf Ebrahimi static void AppendCCRange(string* t, Rune lo, Rune hi);
32*ccdc9c3eSSadaf Ebrahimi 
33*ccdc9c3eSSadaf Ebrahimi // Walker to generate string in s_.
34*ccdc9c3eSSadaf Ebrahimi // The arg pointers are actually integers giving the
35*ccdc9c3eSSadaf Ebrahimi // context precedence.
36*ccdc9c3eSSadaf Ebrahimi // The child_args are always NULL.
37*ccdc9c3eSSadaf Ebrahimi class ToStringWalker : public Regexp::Walker<int> {
38*ccdc9c3eSSadaf Ebrahimi  public:
ToStringWalker(string * t)39*ccdc9c3eSSadaf Ebrahimi   explicit ToStringWalker(string* t) : t_(t) {}
40*ccdc9c3eSSadaf Ebrahimi 
41*ccdc9c3eSSadaf Ebrahimi   virtual int PreVisit(Regexp* re, int parent_arg, bool* stop);
42*ccdc9c3eSSadaf Ebrahimi   virtual int PostVisit(Regexp* re, int parent_arg, int pre_arg,
43*ccdc9c3eSSadaf Ebrahimi                         int* child_args, int nchild_args);
ShortVisit(Regexp * re,int parent_arg)44*ccdc9c3eSSadaf Ebrahimi   virtual int ShortVisit(Regexp* re, int parent_arg) {
45*ccdc9c3eSSadaf Ebrahimi     return 0;
46*ccdc9c3eSSadaf Ebrahimi   }
47*ccdc9c3eSSadaf Ebrahimi 
48*ccdc9c3eSSadaf Ebrahimi  private:
49*ccdc9c3eSSadaf Ebrahimi   string* t_;  // The string the walker appends to.
50*ccdc9c3eSSadaf Ebrahimi 
51*ccdc9c3eSSadaf Ebrahimi   ToStringWalker(const ToStringWalker&) = delete;
52*ccdc9c3eSSadaf Ebrahimi   ToStringWalker& operator=(const ToStringWalker&) = delete;
53*ccdc9c3eSSadaf Ebrahimi };
54*ccdc9c3eSSadaf Ebrahimi 
ToString()55*ccdc9c3eSSadaf Ebrahimi string Regexp::ToString() {
56*ccdc9c3eSSadaf Ebrahimi   string t;
57*ccdc9c3eSSadaf Ebrahimi   ToStringWalker w(&t);
58*ccdc9c3eSSadaf Ebrahimi   w.WalkExponential(this, PrecToplevel, 100000);
59*ccdc9c3eSSadaf Ebrahimi   if (w.stopped_early())
60*ccdc9c3eSSadaf Ebrahimi     t += " [truncated]";
61*ccdc9c3eSSadaf Ebrahimi   return t;
62*ccdc9c3eSSadaf Ebrahimi }
63*ccdc9c3eSSadaf Ebrahimi 
64*ccdc9c3eSSadaf Ebrahimi #define ToString DontCallToString  // Avoid accidental recursion.
65*ccdc9c3eSSadaf Ebrahimi 
66*ccdc9c3eSSadaf Ebrahimi // Visits re before children are processed.
67*ccdc9c3eSSadaf Ebrahimi // Appends ( if needed and passes new precedence to children.
PreVisit(Regexp * re,int parent_arg,bool * stop)68*ccdc9c3eSSadaf Ebrahimi int ToStringWalker::PreVisit(Regexp* re, int parent_arg, bool* stop) {
69*ccdc9c3eSSadaf Ebrahimi   int prec = parent_arg;
70*ccdc9c3eSSadaf Ebrahimi   int nprec = PrecAtom;
71*ccdc9c3eSSadaf Ebrahimi 
72*ccdc9c3eSSadaf Ebrahimi   switch (re->op()) {
73*ccdc9c3eSSadaf Ebrahimi     case kRegexpNoMatch:
74*ccdc9c3eSSadaf Ebrahimi     case kRegexpEmptyMatch:
75*ccdc9c3eSSadaf Ebrahimi     case kRegexpLiteral:
76*ccdc9c3eSSadaf Ebrahimi     case kRegexpAnyChar:
77*ccdc9c3eSSadaf Ebrahimi     case kRegexpAnyByte:
78*ccdc9c3eSSadaf Ebrahimi     case kRegexpBeginLine:
79*ccdc9c3eSSadaf Ebrahimi     case kRegexpEndLine:
80*ccdc9c3eSSadaf Ebrahimi     case kRegexpBeginText:
81*ccdc9c3eSSadaf Ebrahimi     case kRegexpEndText:
82*ccdc9c3eSSadaf Ebrahimi     case kRegexpWordBoundary:
83*ccdc9c3eSSadaf Ebrahimi     case kRegexpNoWordBoundary:
84*ccdc9c3eSSadaf Ebrahimi     case kRegexpCharClass:
85*ccdc9c3eSSadaf Ebrahimi     case kRegexpHaveMatch:
86*ccdc9c3eSSadaf Ebrahimi       nprec = PrecAtom;
87*ccdc9c3eSSadaf Ebrahimi       break;
88*ccdc9c3eSSadaf Ebrahimi 
89*ccdc9c3eSSadaf Ebrahimi     case kRegexpConcat:
90*ccdc9c3eSSadaf Ebrahimi     case kRegexpLiteralString:
91*ccdc9c3eSSadaf Ebrahimi       if (prec < PrecConcat)
92*ccdc9c3eSSadaf Ebrahimi         t_->append("(?:");
93*ccdc9c3eSSadaf Ebrahimi       nprec = PrecConcat;
94*ccdc9c3eSSadaf Ebrahimi       break;
95*ccdc9c3eSSadaf Ebrahimi 
96*ccdc9c3eSSadaf Ebrahimi     case kRegexpAlternate:
97*ccdc9c3eSSadaf Ebrahimi       if (prec < PrecAlternate)
98*ccdc9c3eSSadaf Ebrahimi         t_->append("(?:");
99*ccdc9c3eSSadaf Ebrahimi       nprec = PrecAlternate;
100*ccdc9c3eSSadaf Ebrahimi       break;
101*ccdc9c3eSSadaf Ebrahimi 
102*ccdc9c3eSSadaf Ebrahimi     case kRegexpCapture:
103*ccdc9c3eSSadaf Ebrahimi       t_->append("(");
104*ccdc9c3eSSadaf Ebrahimi       if (re->cap() == 0)
105*ccdc9c3eSSadaf Ebrahimi         LOG(DFATAL) << "kRegexpCapture cap() == 0";
106*ccdc9c3eSSadaf Ebrahimi       if (re->name()) {
107*ccdc9c3eSSadaf Ebrahimi         t_->append("?P<");
108*ccdc9c3eSSadaf Ebrahimi         t_->append(*re->name());
109*ccdc9c3eSSadaf Ebrahimi         t_->append(">");
110*ccdc9c3eSSadaf Ebrahimi       }
111*ccdc9c3eSSadaf Ebrahimi       nprec = PrecParen;
112*ccdc9c3eSSadaf Ebrahimi       break;
113*ccdc9c3eSSadaf Ebrahimi 
114*ccdc9c3eSSadaf Ebrahimi     case kRegexpStar:
115*ccdc9c3eSSadaf Ebrahimi     case kRegexpPlus:
116*ccdc9c3eSSadaf Ebrahimi     case kRegexpQuest:
117*ccdc9c3eSSadaf Ebrahimi     case kRegexpRepeat:
118*ccdc9c3eSSadaf Ebrahimi       if (prec < PrecUnary)
119*ccdc9c3eSSadaf Ebrahimi         t_->append("(?:");
120*ccdc9c3eSSadaf Ebrahimi       // The subprecedence here is PrecAtom instead of PrecUnary
121*ccdc9c3eSSadaf Ebrahimi       // because PCRE treats two unary ops in a row as a parse error.
122*ccdc9c3eSSadaf Ebrahimi       nprec = PrecAtom;
123*ccdc9c3eSSadaf Ebrahimi       break;
124*ccdc9c3eSSadaf Ebrahimi   }
125*ccdc9c3eSSadaf Ebrahimi 
126*ccdc9c3eSSadaf Ebrahimi   return nprec;
127*ccdc9c3eSSadaf Ebrahimi }
128*ccdc9c3eSSadaf Ebrahimi 
AppendLiteral(string * t,Rune r,bool foldcase)129*ccdc9c3eSSadaf Ebrahimi static void AppendLiteral(string *t, Rune r, bool foldcase) {
130*ccdc9c3eSSadaf Ebrahimi   if (r != 0 && r < 0x80 && strchr("(){}[]*+?|.^$\\", r)) {
131*ccdc9c3eSSadaf Ebrahimi     t->append(1, '\\');
132*ccdc9c3eSSadaf Ebrahimi     t->append(1, static_cast<char>(r));
133*ccdc9c3eSSadaf Ebrahimi   } else if (foldcase && 'a' <= r && r <= 'z') {
134*ccdc9c3eSSadaf Ebrahimi     r -= 'a' - 'A';
135*ccdc9c3eSSadaf Ebrahimi     t->append(1, '[');
136*ccdc9c3eSSadaf Ebrahimi     t->append(1, static_cast<char>(r));
137*ccdc9c3eSSadaf Ebrahimi     t->append(1, static_cast<char>(r) + 'a' - 'A');
138*ccdc9c3eSSadaf Ebrahimi     t->append(1, ']');
139*ccdc9c3eSSadaf Ebrahimi   } else {
140*ccdc9c3eSSadaf Ebrahimi     AppendCCRange(t, r, r);
141*ccdc9c3eSSadaf Ebrahimi   }
142*ccdc9c3eSSadaf Ebrahimi }
143*ccdc9c3eSSadaf Ebrahimi 
144*ccdc9c3eSSadaf Ebrahimi // Visits re after children are processed.
145*ccdc9c3eSSadaf Ebrahimi // For childless regexps, all the work is done here.
146*ccdc9c3eSSadaf Ebrahimi // For regexps with children, append any unary suffixes or ).
PostVisit(Regexp * re,int parent_arg,int pre_arg,int * child_args,int nchild_args)147*ccdc9c3eSSadaf Ebrahimi int ToStringWalker::PostVisit(Regexp* re, int parent_arg, int pre_arg,
148*ccdc9c3eSSadaf Ebrahimi                               int* child_args, int nchild_args) {
149*ccdc9c3eSSadaf Ebrahimi   int prec = parent_arg;
150*ccdc9c3eSSadaf Ebrahimi   switch (re->op()) {
151*ccdc9c3eSSadaf Ebrahimi     case kRegexpNoMatch:
152*ccdc9c3eSSadaf Ebrahimi       // There's no simple symbol for "no match", but
153*ccdc9c3eSSadaf Ebrahimi       // [^0-Runemax] excludes everything.
154*ccdc9c3eSSadaf Ebrahimi       t_->append("[^\\x00-\\x{10ffff}]");
155*ccdc9c3eSSadaf Ebrahimi       break;
156*ccdc9c3eSSadaf Ebrahimi 
157*ccdc9c3eSSadaf Ebrahimi     case kRegexpEmptyMatch:
158*ccdc9c3eSSadaf Ebrahimi       // Append (?:) to make empty string visible,
159*ccdc9c3eSSadaf Ebrahimi       // unless this is already being parenthesized.
160*ccdc9c3eSSadaf Ebrahimi       if (prec < PrecEmpty)
161*ccdc9c3eSSadaf Ebrahimi         t_->append("(?:)");
162*ccdc9c3eSSadaf Ebrahimi       break;
163*ccdc9c3eSSadaf Ebrahimi 
164*ccdc9c3eSSadaf Ebrahimi     case kRegexpLiteral:
165*ccdc9c3eSSadaf Ebrahimi       AppendLiteral(t_, re->rune(),
166*ccdc9c3eSSadaf Ebrahimi                     (re->parse_flags() & Regexp::FoldCase) != 0);
167*ccdc9c3eSSadaf Ebrahimi       break;
168*ccdc9c3eSSadaf Ebrahimi 
169*ccdc9c3eSSadaf Ebrahimi     case kRegexpLiteralString:
170*ccdc9c3eSSadaf Ebrahimi       for (int i = 0; i < re->nrunes(); i++)
171*ccdc9c3eSSadaf Ebrahimi         AppendLiteral(t_, re->runes()[i],
172*ccdc9c3eSSadaf Ebrahimi                       (re->parse_flags() & Regexp::FoldCase) != 0);
173*ccdc9c3eSSadaf Ebrahimi       if (prec < PrecConcat)
174*ccdc9c3eSSadaf Ebrahimi         t_->append(")");
175*ccdc9c3eSSadaf Ebrahimi       break;
176*ccdc9c3eSSadaf Ebrahimi 
177*ccdc9c3eSSadaf Ebrahimi     case kRegexpConcat:
178*ccdc9c3eSSadaf Ebrahimi       if (prec < PrecConcat)
179*ccdc9c3eSSadaf Ebrahimi         t_->append(")");
180*ccdc9c3eSSadaf Ebrahimi       break;
181*ccdc9c3eSSadaf Ebrahimi 
182*ccdc9c3eSSadaf Ebrahimi     case kRegexpAlternate:
183*ccdc9c3eSSadaf Ebrahimi       // Clumsy but workable: the children all appended |
184*ccdc9c3eSSadaf Ebrahimi       // at the end of their strings, so just remove the last one.
185*ccdc9c3eSSadaf Ebrahimi       if ((*t_)[t_->size()-1] == '|')
186*ccdc9c3eSSadaf Ebrahimi         t_->erase(t_->size()-1);
187*ccdc9c3eSSadaf Ebrahimi       else
188*ccdc9c3eSSadaf Ebrahimi         LOG(DFATAL) << "Bad final char: " << t_;
189*ccdc9c3eSSadaf Ebrahimi       if (prec < PrecAlternate)
190*ccdc9c3eSSadaf Ebrahimi         t_->append(")");
191*ccdc9c3eSSadaf Ebrahimi       break;
192*ccdc9c3eSSadaf Ebrahimi 
193*ccdc9c3eSSadaf Ebrahimi     case kRegexpStar:
194*ccdc9c3eSSadaf Ebrahimi       t_->append("*");
195*ccdc9c3eSSadaf Ebrahimi       if (re->parse_flags() & Regexp::NonGreedy)
196*ccdc9c3eSSadaf Ebrahimi         t_->append("?");
197*ccdc9c3eSSadaf Ebrahimi       if (prec < PrecUnary)
198*ccdc9c3eSSadaf Ebrahimi         t_->append(")");
199*ccdc9c3eSSadaf Ebrahimi       break;
200*ccdc9c3eSSadaf Ebrahimi 
201*ccdc9c3eSSadaf Ebrahimi     case kRegexpPlus:
202*ccdc9c3eSSadaf Ebrahimi       t_->append("+");
203*ccdc9c3eSSadaf Ebrahimi       if (re->parse_flags() & Regexp::NonGreedy)
204*ccdc9c3eSSadaf Ebrahimi         t_->append("?");
205*ccdc9c3eSSadaf Ebrahimi       if (prec < PrecUnary)
206*ccdc9c3eSSadaf Ebrahimi         t_->append(")");
207*ccdc9c3eSSadaf Ebrahimi       break;
208*ccdc9c3eSSadaf Ebrahimi 
209*ccdc9c3eSSadaf Ebrahimi     case kRegexpQuest:
210*ccdc9c3eSSadaf Ebrahimi       t_->append("?");
211*ccdc9c3eSSadaf Ebrahimi       if (re->parse_flags() & Regexp::NonGreedy)
212*ccdc9c3eSSadaf Ebrahimi         t_->append("?");
213*ccdc9c3eSSadaf Ebrahimi       if (prec < PrecUnary)
214*ccdc9c3eSSadaf Ebrahimi         t_->append(")");
215*ccdc9c3eSSadaf Ebrahimi       break;
216*ccdc9c3eSSadaf Ebrahimi 
217*ccdc9c3eSSadaf Ebrahimi     case kRegexpRepeat:
218*ccdc9c3eSSadaf Ebrahimi       if (re->max() == -1)
219*ccdc9c3eSSadaf Ebrahimi         t_->append(StringPrintf("{%d,}", re->min()));
220*ccdc9c3eSSadaf Ebrahimi       else if (re->min() == re->max())
221*ccdc9c3eSSadaf Ebrahimi         t_->append(StringPrintf("{%d}", re->min()));
222*ccdc9c3eSSadaf Ebrahimi       else
223*ccdc9c3eSSadaf Ebrahimi         t_->append(StringPrintf("{%d,%d}", re->min(), re->max()));
224*ccdc9c3eSSadaf Ebrahimi       if (re->parse_flags() & Regexp::NonGreedy)
225*ccdc9c3eSSadaf Ebrahimi         t_->append("?");
226*ccdc9c3eSSadaf Ebrahimi       if (prec < PrecUnary)
227*ccdc9c3eSSadaf Ebrahimi         t_->append(")");
228*ccdc9c3eSSadaf Ebrahimi       break;
229*ccdc9c3eSSadaf Ebrahimi 
230*ccdc9c3eSSadaf Ebrahimi     case kRegexpAnyChar:
231*ccdc9c3eSSadaf Ebrahimi       t_->append(".");
232*ccdc9c3eSSadaf Ebrahimi       break;
233*ccdc9c3eSSadaf Ebrahimi 
234*ccdc9c3eSSadaf Ebrahimi     case kRegexpAnyByte:
235*ccdc9c3eSSadaf Ebrahimi       t_->append("\\C");
236*ccdc9c3eSSadaf Ebrahimi       break;
237*ccdc9c3eSSadaf Ebrahimi 
238*ccdc9c3eSSadaf Ebrahimi     case kRegexpBeginLine:
239*ccdc9c3eSSadaf Ebrahimi       t_->append("^");
240*ccdc9c3eSSadaf Ebrahimi       break;
241*ccdc9c3eSSadaf Ebrahimi 
242*ccdc9c3eSSadaf Ebrahimi     case kRegexpEndLine:
243*ccdc9c3eSSadaf Ebrahimi       t_->append("$");
244*ccdc9c3eSSadaf Ebrahimi       break;
245*ccdc9c3eSSadaf Ebrahimi 
246*ccdc9c3eSSadaf Ebrahimi     case kRegexpBeginText:
247*ccdc9c3eSSadaf Ebrahimi       t_->append("(?-m:^)");
248*ccdc9c3eSSadaf Ebrahimi       break;
249*ccdc9c3eSSadaf Ebrahimi 
250*ccdc9c3eSSadaf Ebrahimi     case kRegexpEndText:
251*ccdc9c3eSSadaf Ebrahimi       if (re->parse_flags() & Regexp::WasDollar)
252*ccdc9c3eSSadaf Ebrahimi         t_->append("(?-m:$)");
253*ccdc9c3eSSadaf Ebrahimi       else
254*ccdc9c3eSSadaf Ebrahimi         t_->append("\\z");
255*ccdc9c3eSSadaf Ebrahimi       break;
256*ccdc9c3eSSadaf Ebrahimi 
257*ccdc9c3eSSadaf Ebrahimi     case kRegexpWordBoundary:
258*ccdc9c3eSSadaf Ebrahimi       t_->append("\\b");
259*ccdc9c3eSSadaf Ebrahimi       break;
260*ccdc9c3eSSadaf Ebrahimi 
261*ccdc9c3eSSadaf Ebrahimi     case kRegexpNoWordBoundary:
262*ccdc9c3eSSadaf Ebrahimi       t_->append("\\B");
263*ccdc9c3eSSadaf Ebrahimi       break;
264*ccdc9c3eSSadaf Ebrahimi 
265*ccdc9c3eSSadaf Ebrahimi     case kRegexpCharClass: {
266*ccdc9c3eSSadaf Ebrahimi       if (re->cc()->size() == 0) {
267*ccdc9c3eSSadaf Ebrahimi         t_->append("[^\\x00-\\x{10ffff}]");
268*ccdc9c3eSSadaf Ebrahimi         break;
269*ccdc9c3eSSadaf Ebrahimi       }
270*ccdc9c3eSSadaf Ebrahimi       t_->append("[");
271*ccdc9c3eSSadaf Ebrahimi       // Heuristic: show class as negated if it contains the
272*ccdc9c3eSSadaf Ebrahimi       // non-character 0xFFFE.
273*ccdc9c3eSSadaf Ebrahimi       CharClass* cc = re->cc();
274*ccdc9c3eSSadaf Ebrahimi       if (cc->Contains(0xFFFE)) {
275*ccdc9c3eSSadaf Ebrahimi         cc = cc->Negate();
276*ccdc9c3eSSadaf Ebrahimi         t_->append("^");
277*ccdc9c3eSSadaf Ebrahimi       }
278*ccdc9c3eSSadaf Ebrahimi       for (CharClass::iterator i = cc->begin(); i != cc->end(); ++i)
279*ccdc9c3eSSadaf Ebrahimi         AppendCCRange(t_, i->lo, i->hi);
280*ccdc9c3eSSadaf Ebrahimi       if (cc != re->cc())
281*ccdc9c3eSSadaf Ebrahimi         cc->Delete();
282*ccdc9c3eSSadaf Ebrahimi       t_->append("]");
283*ccdc9c3eSSadaf Ebrahimi       break;
284*ccdc9c3eSSadaf Ebrahimi     }
285*ccdc9c3eSSadaf Ebrahimi 
286*ccdc9c3eSSadaf Ebrahimi     case kRegexpCapture:
287*ccdc9c3eSSadaf Ebrahimi       t_->append(")");
288*ccdc9c3eSSadaf Ebrahimi       break;
289*ccdc9c3eSSadaf Ebrahimi 
290*ccdc9c3eSSadaf Ebrahimi     case kRegexpHaveMatch:
291*ccdc9c3eSSadaf Ebrahimi       // There's no syntax accepted by the parser to generate
292*ccdc9c3eSSadaf Ebrahimi       // this node (it is generated by RE2::Set) so make something
293*ccdc9c3eSSadaf Ebrahimi       // up that is readable but won't compile.
294*ccdc9c3eSSadaf Ebrahimi       t_->append("(?HaveMatch:%d)", re->match_id());
295*ccdc9c3eSSadaf Ebrahimi       break;
296*ccdc9c3eSSadaf Ebrahimi   }
297*ccdc9c3eSSadaf Ebrahimi 
298*ccdc9c3eSSadaf Ebrahimi   // If the parent is an alternation, append the | for it.
299*ccdc9c3eSSadaf Ebrahimi   if (prec == PrecAlternate)
300*ccdc9c3eSSadaf Ebrahimi     t_->append("|");
301*ccdc9c3eSSadaf Ebrahimi 
302*ccdc9c3eSSadaf Ebrahimi   return 0;
303*ccdc9c3eSSadaf Ebrahimi }
304*ccdc9c3eSSadaf Ebrahimi 
305*ccdc9c3eSSadaf Ebrahimi // Appends a rune for use in a character class to the string t.
AppendCCChar(string * t,Rune r)306*ccdc9c3eSSadaf Ebrahimi static void AppendCCChar(string* t, Rune r) {
307*ccdc9c3eSSadaf Ebrahimi   if (0x20 <= r && r <= 0x7E) {
308*ccdc9c3eSSadaf Ebrahimi     if (strchr("[]^-\\", r))
309*ccdc9c3eSSadaf Ebrahimi       t->append("\\");
310*ccdc9c3eSSadaf Ebrahimi     t->append(1, static_cast<char>(r));
311*ccdc9c3eSSadaf Ebrahimi     return;
312*ccdc9c3eSSadaf Ebrahimi   }
313*ccdc9c3eSSadaf Ebrahimi   switch (r) {
314*ccdc9c3eSSadaf Ebrahimi     default:
315*ccdc9c3eSSadaf Ebrahimi       break;
316*ccdc9c3eSSadaf Ebrahimi 
317*ccdc9c3eSSadaf Ebrahimi     case '\r':
318*ccdc9c3eSSadaf Ebrahimi       t->append("\\r");
319*ccdc9c3eSSadaf Ebrahimi       return;
320*ccdc9c3eSSadaf Ebrahimi 
321*ccdc9c3eSSadaf Ebrahimi     case '\t':
322*ccdc9c3eSSadaf Ebrahimi       t->append("\\t");
323*ccdc9c3eSSadaf Ebrahimi       return;
324*ccdc9c3eSSadaf Ebrahimi 
325*ccdc9c3eSSadaf Ebrahimi     case '\n':
326*ccdc9c3eSSadaf Ebrahimi       t->append("\\n");
327*ccdc9c3eSSadaf Ebrahimi       return;
328*ccdc9c3eSSadaf Ebrahimi 
329*ccdc9c3eSSadaf Ebrahimi     case '\f':
330*ccdc9c3eSSadaf Ebrahimi       t->append("\\f");
331*ccdc9c3eSSadaf Ebrahimi       return;
332*ccdc9c3eSSadaf Ebrahimi   }
333*ccdc9c3eSSadaf Ebrahimi 
334*ccdc9c3eSSadaf Ebrahimi   if (r < 0x100) {
335*ccdc9c3eSSadaf Ebrahimi     StringAppendF(t, "\\x%02x", static_cast<int>(r));
336*ccdc9c3eSSadaf Ebrahimi     return;
337*ccdc9c3eSSadaf Ebrahimi   }
338*ccdc9c3eSSadaf Ebrahimi   StringAppendF(t, "\\x{%x}", static_cast<int>(r));
339*ccdc9c3eSSadaf Ebrahimi }
340*ccdc9c3eSSadaf Ebrahimi 
AppendCCRange(string * t,Rune lo,Rune hi)341*ccdc9c3eSSadaf Ebrahimi static void AppendCCRange(string* t, Rune lo, Rune hi) {
342*ccdc9c3eSSadaf Ebrahimi   if (lo > hi)
343*ccdc9c3eSSadaf Ebrahimi     return;
344*ccdc9c3eSSadaf Ebrahimi   AppendCCChar(t, lo);
345*ccdc9c3eSSadaf Ebrahimi   if (lo < hi) {
346*ccdc9c3eSSadaf Ebrahimi     t->append("-");
347*ccdc9c3eSSadaf Ebrahimi     AppendCCChar(t, hi);
348*ccdc9c3eSSadaf Ebrahimi   }
349*ccdc9c3eSSadaf Ebrahimi }
350*ccdc9c3eSSadaf Ebrahimi 
351*ccdc9c3eSSadaf Ebrahimi }  // namespace re2
352