Mercurial > hg
comparison mercurial/templater.py @ 25785:f976b7dc5e7b
templater: unify "string" and "rawstring"
"rawstring" was introduced by 5ab28a2e9962, but it's no longer necessary
because c1975809a6b5 and fd5bc660c9f0 changed the way of processing string
literals.
This patch moves string decoding to the parsing phase as it was before:
('rawstring', s) -> ('string', s)
('string', s) -> ('string', s.decode('string-escape'))
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Sat, 20 Jun 2015 18:24:11 +0900 |
parents | 33e613687dab |
children | f8f7ae0f4d98 |
comparison
equal
deleted
inserted
replaced
25784:33e613687dab | 25785:f976b7dc5e7b |
---|---|
20 "|": (5, None, ("|", 5)), | 20 "|": (5, None, ("|", 5)), |
21 "%": (6, None, ("%", 6)), | 21 "%": (6, None, ("%", 6)), |
22 ")": (0, None, None), | 22 ")": (0, None, None), |
23 "integer": (0, ("integer",), None), | 23 "integer": (0, ("integer",), None), |
24 "symbol": (0, ("symbol",), None), | 24 "symbol": (0, ("symbol",), None), |
25 "rawstring": (0, ("rawstring",), None), | 25 "string": (0, ("string",), None), |
26 "template": (0, ("template",), None), | 26 "template": (0, ("template",), None), |
27 "end": (0, None, None), | 27 "end": (0, None, None), |
28 } | 28 } |
29 | 29 |
30 def tokenize(program, start, end): | 30 def tokenize(program, start, end): |
48 d = program[pos] | 48 d = program[pos] |
49 if d == '\\': # skip over escaped characters | 49 if d == '\\': # skip over escaped characters |
50 pos += 2 | 50 pos += 2 |
51 continue | 51 continue |
52 if d == c: | 52 if d == c: |
53 yield ('rawstring', program[s:pos], s) | 53 yield ('string', program[s:pos], s) |
54 break | 54 break |
55 pos += 1 | 55 pos += 1 |
56 else: | 56 else: |
57 raise error.ParseError(_("unterminated string"), s) | 57 raise error.ParseError(_("unterminated string"), s) |
58 elif c.isdigit() or c == '-': | 58 elif c.isdigit() or c == '-': |
81 # {f("\\\\ {g(\"\\\"\")}"} \\ {g("\"")} [r'\\', {g("\"")}] | 81 # {f("\\\\ {g(\"\\\"\")}"} \\ {g("\"")} [r'\\', {g("\"")}] |
82 # ~~~~~~~~ | 82 # ~~~~~~~~ |
83 # escaped quoted string | 83 # escaped quoted string |
84 if c == 'r': | 84 if c == 'r': |
85 pos += 1 | 85 pos += 1 |
86 token = 'rawstring' | 86 token = 'string' |
87 else: | 87 else: |
88 token = 'template' | 88 token = 'template' |
89 quote = program[pos:pos + 2] | 89 quote = program[pos:pos + 2] |
90 s = pos = pos + 2 | 90 s = pos = pos + 2 |
91 while pos < end: # find closing escaped quote | 91 while pos < end: # find closing escaped quote |
134 >>> _parsetemplate('foo"{bar}', 0, 9, quote='"') | 134 >>> _parsetemplate('foo"{bar}', 0, 9, quote='"') |
135 ([('string', 'foo')], 4) | 135 ([('string', 'foo')], 4) |
136 >>> _parsetemplate(r'foo\"bar"baz', 0, 12, quote='"') | 136 >>> _parsetemplate(r'foo\"bar"baz', 0, 12, quote='"') |
137 ([('string', 'foo"'), ('string', 'bar')], 9) | 137 ([('string', 'foo"'), ('string', 'bar')], 9) |
138 >>> _parsetemplate(r'foo\\"bar', 0, 10, quote='"') | 138 >>> _parsetemplate(r'foo\\"bar', 0, 10, quote='"') |
139 ([('string', 'foo\\\\')], 6) | 139 ([('string', 'foo\\')], 6) |
140 """ | 140 """ |
141 parsed = [] | 141 parsed = [] |
142 sepchars = '{' + quote | 142 sepchars = '{' + quote |
143 pos = start | 143 pos = start |
144 p = parser.parser(elements) | 144 p = parser.parser(elements) |
145 while pos < stop: | 145 while pos < stop: |
146 n = min((tmpl.find(c, pos, stop) for c in sepchars), | 146 n = min((tmpl.find(c, pos, stop) for c in sepchars), |
147 key=lambda n: (n < 0, n)) | 147 key=lambda n: (n < 0, n)) |
148 if n < 0: | 148 if n < 0: |
149 parsed.append(('string', tmpl[pos:stop])) | 149 parsed.append(('string', tmpl[pos:stop].decode('string-escape'))) |
150 pos = stop | 150 pos = stop |
151 break | 151 break |
152 c = tmpl[n] | 152 c = tmpl[n] |
153 bs = (n - pos) - len(tmpl[pos:n].rstrip('\\')) | 153 bs = (n - pos) - len(tmpl[pos:n].rstrip('\\')) |
154 if bs % 2 == 1: | 154 if bs % 2 == 1: |
155 # escaped (e.g. '\{', '\\\{', but not '\\{') | 155 # escaped (e.g. '\{', '\\\{', but not '\\{') |
156 parsed.append(('string', (tmpl[pos:n - 1] + c))) | 156 parsed.append(('string', |
157 tmpl[pos:n - 1].decode('string-escape') + c)) | |
157 pos = n + 1 | 158 pos = n + 1 |
158 continue | 159 continue |
159 if n > pos: | 160 if n > pos: |
160 parsed.append(('string', tmpl[pos:n])) | 161 parsed.append(('string', tmpl[pos:n].decode('string-escape'))) |
161 if c == quote: | 162 if c == quote: |
162 return parsed, n + 1 | 163 return parsed, n + 1 |
163 | 164 |
164 parseres, pos = p.parse(tokenize(tmpl, n + 1, stop)) | 165 parseres, pos = p.parse(tokenize(tmpl, n + 1, stop)) |
165 parsed.append(parseres) | 166 parsed.append(parseres) |
210 | 211 |
211 def runinteger(context, mapping, data): | 212 def runinteger(context, mapping, data): |
212 return int(data) | 213 return int(data) |
213 | 214 |
214 def runstring(context, mapping, data): | 215 def runstring(context, mapping, data): |
215 return data.decode("string-escape") | |
216 | |
217 def runrawstring(context, mapping, data): | |
218 return data | 216 return data |
219 | 217 |
220 def runsymbol(context, mapping, key): | 218 def runsymbol(context, mapping, key): |
221 v = mapping.get(key) | 219 v = mapping.get(key) |
222 if v is None: | 220 if v is None: |
657 | 655 |
658 # methods to interpret function arguments or inner expressions (e.g. {_(x)}) | 656 # methods to interpret function arguments or inner expressions (e.g. {_(x)}) |
659 exprmethods = { | 657 exprmethods = { |
660 "integer": lambda e, c: (runinteger, e[1]), | 658 "integer": lambda e, c: (runinteger, e[1]), |
661 "string": lambda e, c: (runstring, e[1]), | 659 "string": lambda e, c: (runstring, e[1]), |
662 "rawstring": lambda e, c: (runrawstring, e[1]), | |
663 "symbol": lambda e, c: (runsymbol, e[1]), | 660 "symbol": lambda e, c: (runsymbol, e[1]), |
664 "template": buildtemplate, | 661 "template": buildtemplate, |
665 "group": lambda e, c: compileexp(e[1], c, exprmethods), | 662 "group": lambda e, c: compileexp(e[1], c, exprmethods), |
666 # ".": buildmember, | 663 # ".": buildmember, |
667 "|": buildfilter, | 664 "|": buildfilter, |