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) |