Mercurial > hg
comparison mercurial/templater.py @ 28547:73d01cba5810
templater: expand list of parsed templates to template node
This patch eliminates a nested data structure other than the parsed tree.
('template', [(op, data), ..]) -> ('template', (op, data), ..)
New expanded tree can be processed by common parser functions. This change
will help implementing template aliases.
Because a (template ..) node should have at least one child node, an empty
template (template []) is mapped to (string ''). Also a trivial string
(template [(string ..)]) node is unwrapped to (string ..) at parsing phase,
instead of compiling phase.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Sat, 13 Feb 2016 23:20:47 +0900 |
parents | 1987ed32efca |
children | ed1d90f6e921 |
comparison
equal
deleted
inserted
replaced
28546:1987ed32efca | 28547:73d01cba5810 |
---|---|
175 | 175 |
176 if quote: | 176 if quote: |
177 raise error.ParseError(_("unterminated string"), start) | 177 raise error.ParseError(_("unterminated string"), start) |
178 return parsed, pos | 178 return parsed, pos |
179 | 179 |
180 def _unnesttemplatelist(tree): | |
181 """Expand list of templates to node tuple | |
182 | |
183 >>> def f(tree): | |
184 ... print prettyformat(_unnesttemplatelist(tree)) | |
185 >>> f(('template', [])) | |
186 ('string', '') | |
187 >>> f(('template', [('string', 'foo')])) | |
188 ('string', 'foo') | |
189 >>> f(('template', [('string', 'foo'), ('symbol', 'rev')])) | |
190 (template | |
191 ('string', 'foo') | |
192 ('symbol', 'rev')) | |
193 >>> f(('template', [('symbol', 'rev')])) # template(rev) -> str | |
194 (template | |
195 ('symbol', 'rev')) | |
196 >>> f(('template', [('template', [('string', 'foo')])])) | |
197 ('string', 'foo') | |
198 """ | |
199 if not isinstance(tree, tuple): | |
200 return tree | |
201 op = tree[0] | |
202 if op != 'template': | |
203 return (op,) + tuple(_unnesttemplatelist(x) for x in tree[1:]) | |
204 | |
205 assert len(tree) == 2 | |
206 xs = tuple(_unnesttemplatelist(x) for x in tree[1]) | |
207 if not xs: | |
208 return ('string', '') # empty template "" | |
209 elif len(xs) == 1 and xs[0][0] == 'string': | |
210 return xs[0] # fast path for string with no template fragment "x" | |
211 else: | |
212 return (op,) + xs | |
213 | |
180 def parse(tmpl): | 214 def parse(tmpl): |
181 """Parse template string into tree""" | 215 """Parse template string into tree""" |
182 parsed, pos = _parsetemplate(tmpl, 0, len(tmpl)) | 216 parsed, pos = _parsetemplate(tmpl, 0, len(tmpl)) |
183 assert pos == len(tmpl), 'unquoted template should be consumed' | 217 assert pos == len(tmpl), 'unquoted template should be consumed' |
184 return ('template', parsed) | 218 return _unnesttemplatelist(('template', parsed)) |
219 | |
220 def prettyformat(tree): | |
221 return parser.prettyformat(tree, ('integer', 'string', 'symbol')) | |
185 | 222 |
186 def compiletemplate(tmpl, context): | 223 def compiletemplate(tmpl, context): |
187 """Parse and compile template string to (func, data) pair""" | 224 """Parse and compile template string to (func, data) pair""" |
188 return compileexp(parse(tmpl), context, methods) | 225 return compileexp(parse(tmpl), context, methods) |
189 | 226 |
279 if callable(v): | 316 if callable(v): |
280 return v(**mapping) | 317 return v(**mapping) |
281 return v | 318 return v |
282 | 319 |
283 def buildtemplate(exp, context): | 320 def buildtemplate(exp, context): |
284 ctmpl = [compileexp(e, context, methods) for e in exp[1]] | 321 ctmpl = [compileexp(e, context, methods) for e in exp[1:]] |
285 if len(ctmpl) == 1: | |
286 return ctmpl[0] # fast path for string with no template fragment | |
287 return (runtemplate, ctmpl) | 322 return (runtemplate, ctmpl) |
288 | 323 |
289 def runtemplate(context, mapping, template): | 324 def runtemplate(context, mapping, template): |
290 for func, data in template: | 325 for func, data in template: |
291 yield func(context, mapping, data) | 326 yield func(context, mapping, data) |