71 if not d.isdigit(): |
71 if not d.isdigit(): |
72 break |
72 break |
73 pos += 1 |
73 pos += 1 |
74 yield ('integer', program[s:pos], s) |
74 yield ('integer', program[s:pos], s) |
75 pos -= 1 |
75 pos -= 1 |
|
76 elif (c == '\\' and program[pos:pos + 2] in (r"\'", r'\"') |
|
77 or c == 'r' and program[pos:pos + 3] in (r"r\'", r'r\"')): |
|
78 # handle escaped quoted strings for compatibility with 2.9.2-3.4, |
|
79 # where some of nested templates were preprocessed as strings and |
|
80 # then compiled. therefore, \"...\" was allowed. (issue4733) |
|
81 # |
|
82 # processing flow of _evalifliteral() at 5ab28a2e9962: |
|
83 # outer template string -> stringify() -> compiletemplate() |
|
84 # ------------------------ ------------ ------------------ |
|
85 # {f("\\\\ {g(\"\\\"\")}"} \\ {g("\"")} [r'\\', {g("\"")}] |
|
86 # ~~~~~~~~ |
|
87 # escaped quoted string |
|
88 if c == 'r': |
|
89 pos += 1 |
|
90 token = 'rawstring' |
|
91 else: |
|
92 token = 'string' |
|
93 quote = program[pos:pos + 2] |
|
94 s = pos = pos + 2 |
|
95 while pos < end: # find closing escaped quote |
|
96 if program.startswith('\\\\\\', pos, end): |
|
97 pos += 4 # skip over double escaped characters |
|
98 continue |
|
99 if program.startswith(quote, pos, end): |
|
100 try: |
|
101 # interpret as if it were a part of an outer string |
|
102 data = program[s:pos].decode('string-escape') |
|
103 except ValueError: # unbalanced escapes |
|
104 raise error.ParseError(_("syntax error"), s) |
|
105 yield (token, data, s) |
|
106 pos += 1 |
|
107 break |
|
108 pos += 1 |
|
109 else: |
|
110 raise error.ParseError(_("unterminated string"), s) |
76 elif c.isalnum() or c in '_': |
111 elif c.isalnum() or c in '_': |
77 s = pos |
112 s = pos |
78 pos += 1 |
113 pos += 1 |
79 while pos < end: # find end of symbol |
114 while pos < end: # find end of symbol |
80 d = program[pos] |
115 d = program[pos] |