368 def runtemplate(context, mapping, template): |
368 def runtemplate(context, mapping, template): |
369 for func, data in template: |
369 for func, data in template: |
370 yield func(context, mapping, data) |
370 yield func(context, mapping, data) |
371 |
371 |
372 def buildfilter(exp, context): |
372 def buildfilter(exp, context): |
373 arg = compileexp(exp[1], context, methods) |
|
374 n = getsymbol(exp[2]) |
373 n = getsymbol(exp[2]) |
375 if n in context._filters: |
374 if n in context._filters: |
376 filt = context._filters[n] |
375 filt = context._filters[n] |
|
376 arg = compileexp(exp[1], context, methods) |
377 return (runfilter, (arg, filt)) |
377 return (runfilter, (arg, filt)) |
378 if n in funcs: |
378 if n in funcs: |
379 f = funcs[n] |
379 f = funcs[n] |
380 return (f, [arg]) |
380 args = _buildfuncargs(exp[1], context, methods, n, f._argspec) |
|
381 return (f, args) |
381 raise error.ParseError(_("unknown function '%s'") % n) |
382 raise error.ParseError(_("unknown function '%s'") % n) |
382 |
383 |
383 def runfilter(context, mapping, data): |
384 def runfilter(context, mapping, data): |
384 arg, filt = data |
385 arg, filt = data |
385 thing = evalfuncarg(context, mapping, arg) |
386 thing = evalfuncarg(context, mapping, arg) |
450 except ZeroDivisionError: |
451 except ZeroDivisionError: |
451 raise error.Abort(_('division by zero is not defined')) |
452 raise error.Abort(_('division by zero is not defined')) |
452 |
453 |
453 def buildfunc(exp, context): |
454 def buildfunc(exp, context): |
454 n = getsymbol(exp[1]) |
455 n = getsymbol(exp[1]) |
455 args = [compileexp(x, context, exprmethods) for x in getlist(exp[2])] |
|
456 if n in funcs: |
456 if n in funcs: |
457 f = funcs[n] |
457 f = funcs[n] |
|
458 args = _buildfuncargs(exp[2], context, exprmethods, n, f._argspec) |
458 return (f, args) |
459 return (f, args) |
459 if n in context._filters: |
460 if n in context._filters: |
|
461 args = _buildfuncargs(exp[2], context, exprmethods, n, argspec=None) |
460 if len(args) != 1: |
462 if len(args) != 1: |
461 raise error.ParseError(_("filter %s expects one argument") % n) |
463 raise error.ParseError(_("filter %s expects one argument") % n) |
462 f = context._filters[n] |
464 f = context._filters[n] |
463 return (runfilter, (args[0], f)) |
465 return (runfilter, (args[0], f)) |
464 raise error.ParseError(_("unknown function '%s'") % n) |
466 raise error.ParseError(_("unknown function '%s'") % n) |
|
467 |
|
468 def _buildfuncargs(exp, context, curmethods, funcname, argspec): |
|
469 """Compile parsed tree of function arguments into list or dict of |
|
470 (func, data) pairs""" |
|
471 def compiledict(xs): |
|
472 return dict((k, compileexp(x, context, curmethods)) |
|
473 for k, x in xs.iteritems()) |
|
474 def compilelist(xs): |
|
475 return [compileexp(x, context, curmethods) for x in xs] |
|
476 |
|
477 if not argspec: |
|
478 # filter or function with no argspec: return list of positional args |
|
479 return compilelist(getlist(exp)) |
|
480 |
|
481 # function with argspec: return dict of named args |
|
482 _poskeys, varkey, _keys = argspec = parser.splitargspec(argspec) |
|
483 treeargs = parser.buildargsdict(getlist(exp), funcname, argspec, |
|
484 keyvaluenode='keyvalue', keynode='symbol') |
|
485 compargs = {} |
|
486 if varkey: |
|
487 compargs[varkey] = compilelist(treeargs.pop(varkey)) |
|
488 compargs.update(compiledict(treeargs)) |
|
489 return compargs |
465 |
490 |
466 def buildkeyvaluepair(exp, content): |
491 def buildkeyvaluepair(exp, content): |
467 raise error.ParseError(_("can't use a key-value pair in this context")) |
492 raise error.ParseError(_("can't use a key-value pair in this context")) |
468 |
493 |
469 # dict of template built-in functions |
494 # dict of template built-in functions |
830 text = evalstring(context, mapping, args[0]) |
855 text = evalstring(context, mapping, args[0]) |
831 style = evalstring(context, mapping, args[1]) |
856 style = evalstring(context, mapping, args[1]) |
832 |
857 |
833 return minirst.format(text, style=style, keep=['verbose']) |
858 return minirst.format(text, style=style, keep=['verbose']) |
834 |
859 |
835 @templatefunc('separate(sep, args)') |
860 @templatefunc('separate(sep, args)', argspec='sep *args') |
836 def separate(context, mapping, args): |
861 def separate(context, mapping, args): |
837 """Add a separator between non-empty arguments.""" |
862 """Add a separator between non-empty arguments.""" |
838 if not args: |
863 if 'sep' not in args: |
839 # i18n: "separate" is a keyword |
864 # i18n: "separate" is a keyword |
840 raise error.ParseError(_("separate expects at least one argument")) |
865 raise error.ParseError(_("separate expects at least one argument")) |
841 |
866 |
842 sep = evalstring(context, mapping, args[0]) |
867 sep = evalstring(context, mapping, args['sep']) |
843 first = True |
868 first = True |
844 for arg in args[1:]: |
869 for arg in args['args']: |
845 argstr = evalstring(context, mapping, arg) |
870 argstr = evalstring(context, mapping, arg) |
846 if not argstr: |
871 if not argstr: |
847 continue |
872 continue |
848 if first: |
873 if first: |
849 first = False |
874 first = False |