19 "|": (5, None, ("|", 5)), |
19 "|": (5, None, ("|", 5)), |
20 "%": (6, None, ("%", 6)), |
20 "%": (6, None, ("%", 6)), |
21 ")": (0, None, None), |
21 ")": (0, None, None), |
22 "symbol": (0, ("symbol",), None), |
22 "symbol": (0, ("symbol",), None), |
23 "string": (0, ("string",), None), |
23 "string": (0, ("string",), None), |
|
24 "rawstring": (0, ("rawstring",), None), |
24 "end": (0, None, None), |
25 "end": (0, None, None), |
25 } |
26 } |
26 |
27 |
27 def tokenizer(data): |
28 def tokenizer(data): |
28 program, start, end = data |
29 program, start, end = data |
74 else: |
75 else: |
75 raise error.ParseError(_("syntax error"), pos) |
76 raise error.ParseError(_("syntax error"), pos) |
76 pos += 1 |
77 pos += 1 |
77 yield ('end', None, pos) |
78 yield ('end', None, pos) |
78 |
79 |
79 def compiletemplate(tmpl, context): |
80 def compiletemplate(tmpl, context, strtoken="string"): |
80 parsed = [] |
81 parsed = [] |
81 pos, stop = 0, len(tmpl) |
82 pos, stop = 0, len(tmpl) |
82 p = parser.parser(tokenizer, elements) |
83 p = parser.parser(tokenizer, elements) |
83 while pos < stop: |
84 while pos < stop: |
84 n = tmpl.find('{', pos) |
85 n = tmpl.find('{', pos) |
85 if n < 0: |
86 if n < 0: |
86 parsed.append(("string", tmpl[pos:].decode("string-escape"))) |
87 parsed.append((strtoken, tmpl[pos:])) |
87 break |
88 break |
88 if n > 0 and tmpl[n - 1] == '\\': |
89 if n > 0 and tmpl[n - 1] == '\\': |
89 # escaped |
90 # escaped |
90 parsed.append(("string", |
91 parsed.append((strtoken, (tmpl[pos:n - 1] + "{"))) |
91 (tmpl[pos:n - 1] + "{").decode("string-escape"))) |
|
92 pos = n + 1 |
92 pos = n + 1 |
93 continue |
93 continue |
94 if n > pos: |
94 if n > pos: |
95 parsed.append(("string", tmpl[pos:n].decode("string-escape"))) |
95 parsed.append((strtoken, tmpl[pos:n])) |
96 |
96 |
97 pd = [tmpl, n + 1, stop] |
97 pd = [tmpl, n + 1, stop] |
98 parseres, pos = p.parse(pd) |
98 parseres, pos = p.parse(pd) |
99 parsed.append(parseres) |
99 parsed.append(parseres) |
100 |
100 |
125 if f not in context._filters: |
125 if f not in context._filters: |
126 raise error.ParseError(_("unknown function '%s'") % f) |
126 raise error.ParseError(_("unknown function '%s'") % f) |
127 return context._filters[f] |
127 return context._filters[f] |
128 |
128 |
129 def gettemplate(exp, context): |
129 def gettemplate(exp, context): |
130 if exp[0] == 'string': |
130 if exp[0] == 'string' or exp[0] == 'rawstring': |
131 return compiletemplate(exp[1], context) |
131 return compiletemplate(exp[1], context, strtoken=exp[0]) |
132 if exp[0] == 'symbol': |
132 if exp[0] == 'symbol': |
133 return context._load(exp[1]) |
133 return context._load(exp[1]) |
134 raise error.ParseError(_("expected template specifier")) |
134 raise error.ParseError(_("expected template specifier")) |
135 |
135 |
136 def runstring(context, mapping, data): |
136 def runstring(context, mapping, data): |
|
137 return data.decode("string-escape") |
|
138 |
|
139 def runrawstring(context, mapping, data): |
137 return data |
140 return data |
138 |
141 |
139 def runsymbol(context, mapping, key): |
142 def runsymbol(context, mapping, key): |
140 v = mapping.get(key) |
143 v = mapping.get(key) |
141 if v is None: |
144 if v is None: |
232 try: |
235 try: |
233 width = int(stringify(args[1][0](context, mapping, args[1][1]))) |
236 width = int(stringify(args[1][0](context, mapping, args[1][1]))) |
234 except ValueError: |
237 except ValueError: |
235 raise error.ParseError(_("fill expects an integer width")) |
238 raise error.ParseError(_("fill expects an integer width")) |
236 try: |
239 try: |
237 initindent = stringify(args[2][0](context, mapping, args[2][1])) |
240 initindent = stringify(_evalifliteral(args[2], context, mapping)) |
238 initindent = stringify(runtemplate(context, mapping, |
241 hangindent = stringify(_evalifliteral(args[3], context, mapping)) |
239 compiletemplate(initindent, context))) |
|
240 hangindent = stringify(args[3][0](context, mapping, args[3][1])) |
|
241 hangindent = stringify(runtemplate(context, mapping, |
|
242 compiletemplate(hangindent, context))) |
|
243 except IndexError: |
242 except IndexError: |
244 pass |
243 pass |
245 |
244 |
246 return templatefilters.fill(text, width, initindent, hangindent) |
245 return templatefilters.fill(text, width, initindent, hangindent) |
247 |
246 |
283 key = args[1][0](context, mapping, args[1][1]) |
282 key = args[1][0](context, mapping, args[1][1]) |
284 yield dictarg.get(key) |
283 yield dictarg.get(key) |
285 |
284 |
286 def _evalifliteral(arg, context, mapping): |
285 def _evalifliteral(arg, context, mapping): |
287 t = stringify(arg[0](context, mapping, arg[1])) |
286 t = stringify(arg[0](context, mapping, arg[1])) |
288 if arg[0] == runstring: |
287 if arg[0] == runstring or arg[0] == runrawstring: |
289 yield runtemplate(context, mapping, compiletemplate(t, context)) |
288 yield runtemplate(context, mapping, |
|
289 compiletemplate(t, context, strtoken='rawstring')) |
290 else: |
290 else: |
291 yield t |
291 yield t |
292 |
292 |
293 def if_(context, mapping, args): |
293 def if_(context, mapping, args): |
294 if not (2 <= len(args) <= 3): |
294 if not (2 <= len(args) <= 3): |
445 |
445 |
446 def strip(context, mapping, args): |
446 def strip(context, mapping, args): |
447 if not (1 <= len(args) <= 2): |
447 if not (1 <= len(args) <= 2): |
448 raise error.ParseError(_("strip expects one or two arguments")) |
448 raise error.ParseError(_("strip expects one or two arguments")) |
449 |
449 |
450 text = args[0][0](context, mapping, args[0][1]) |
450 text = stringify(args[0][0](context, mapping, args[0][1])) |
451 if len(args) == 2: |
451 if len(args) == 2: |
452 chars = args[1][0](context, mapping, args[1][1]) |
452 chars = stringify(args[1][0](context, mapping, args[1][1])) |
453 return text.strip(chars) |
453 return text.strip(chars) |
454 return text.strip() |
454 return text.strip() |
455 |
455 |
456 def sub(context, mapping, args): |
456 def sub(context, mapping, args): |
457 if len(args) != 3: |
457 if len(args) != 3: |
458 # i18n: "sub" is a keyword |
458 # i18n: "sub" is a keyword |
459 raise error.ParseError(_("sub expects three arguments")) |
459 raise error.ParseError(_("sub expects three arguments")) |
460 |
460 |
461 pat = stringify(args[0][0](context, mapping, args[0][1])) |
461 pat = stringify(args[0][0](context, mapping, args[0][1])) |
462 rpl = stringify(args[1][0](context, mapping, args[1][1])) |
462 rpl = stringify(args[1][0](context, mapping, args[1][1])) |
463 src = stringify(args[2][0](context, mapping, args[2][1])) |
463 src = stringify(_evalifliteral(args[2], context, mapping)) |
464 src = stringify(runtemplate(context, mapping, |
|
465 compiletemplate(src, context))) |
|
466 yield re.sub(pat, rpl, src) |
464 yield re.sub(pat, rpl, src) |
467 |
465 |
468 methods = { |
466 methods = { |
469 "string": lambda e, c: (runstring, e[1]), |
467 "string": lambda e, c: (runstring, e[1]), |
|
468 "rawstring": lambda e, c: (runrawstring, e[1]), |
470 "symbol": lambda e, c: (runsymbol, e[1]), |
469 "symbol": lambda e, c: (runsymbol, e[1]), |
471 "group": lambda e, c: compileexp(e[1], c), |
470 "group": lambda e, c: compileexp(e[1], c), |
472 # ".": buildmember, |
471 # ".": buildmember, |
473 "|": buildfilter, |
472 "|": buildfilter, |
474 "%": buildmap, |
473 "%": buildmap, |