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