blob: 96ba0a0085a9bfb5c4b4adccfe465b319219d060 [file] [log] [blame]
Armin Ronacher07bc6842008-03-31 14:18:49 +02001# -*- coding: utf-8 -*-
2"""
3 jinja2.parser
4 ~~~~~~~~~~~~~
5
6 Implements the template parser.
7
8 :copyright: 2008 by Armin Ronacher.
9 :license: BSD, see LICENSE for more details.
10"""
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020011from jinja2 import nodes
12from jinja2.exceptions import TemplateSyntaxError
Armin Ronacher07bc6842008-03-31 14:18:49 +020013
14
15__all__ = ['Parser']
16
Armin Ronachere791c2a2008-04-07 18:39:54 +020017_statement_keywords = frozenset(['for', 'if', 'block', 'extends', 'print',
18 'macro', 'include'])
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020019_compare_operators = frozenset(['eq', 'ne', 'lt', 'lteq', 'gt', 'gteq', 'in'])
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020020_statement_end_tokens = set(['elif', 'else', 'endblock', 'endfilter',
Armin Ronachere791c2a2008-04-07 18:39:54 +020021 'endfor', 'endif', 'endmacro', 'variable_end',
22 'in', 'recursive', 'endcall', 'block_end'])
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020023
Armin Ronacher07bc6842008-03-31 14:18:49 +020024
25class Parser(object):
26 """
27 The template parser class.
28
29 Transforms sourcecode into an abstract syntax tree.
30 """
31
32 def __init__(self, environment, source, filename=None):
33 self.environment = environment
34 if isinstance(source, str):
35 source = source.decode(environment.template_charset, 'ignore')
36 if isinstance(filename, unicode):
37 filename = filename.encode('utf-8')
38 self.source = source
39 self.filename = filename
40 self.closed = False
Armin Ronacher07bc6842008-03-31 14:18:49 +020041 self.no_variable_block = self.environment.lexer.no_variable_block
42 self.stream = environment.lexer.tokenize(source, filename)
43
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020044 def end_statement(self):
45 """Make sure that the statement ends properly."""
46 if self.stream.current.type is 'semicolon':
47 self.stream.next()
48 elif self.stream.current.type not in _statement_end_tokens:
49 raise TemplateSyntaxError('ambigous end of statement',
50 self.stream.current.lineno,
51 self.filename)
52
53 def parse_statement(self):
54 """Parse a single statement."""
55 token_type = self.stream.current.type
56 if token_type in _statement_keywords:
57 return getattr(self, 'parse_' + token_type)()
58 elif token_type is 'call':
59 self.stream.next()
60 return self.parse_call_block()
Armin Ronachere791c2a2008-04-07 18:39:54 +020061 lineno = self.stream.current
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020062 expr = self.parse_expression()
63 if self.stream.current.type == 'assign':
Armin Ronachere791c2a2008-04-07 18:39:54 +020064 result = self.parse_assign(expr)
65 else:
66 result = nodes.ExprStmt(expr, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020067 self.end_statement()
Armin Ronachere791c2a2008-04-07 18:39:54 +020068 return result
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020069
70 def parse_assign(self, target):
71 """Parse an assign statement."""
72 lineno = self.stream.expect('assign').lineno
73 if not target.can_assign():
74 raise TemplateSyntaxError("can't assign to '%s'" %
75 target, target.lineno,
76 self.filename)
77 expr = self.parse_tuple()
78 self.end_statement()
Armin Ronachere791c2a2008-04-07 18:39:54 +020079 target.set_ctx('store')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020080 return nodes.Assign(target, expr, lineno=lineno)
81
82 def parse_statements(self, end_tokens, drop_needle=False):
83 """
84 Parse multiple statements into a list until one of the end tokens
85 is reached. This is used to parse the body of statements as it
86 also parses template data if appropriate.
87 """
88 # the first token may be a colon for python compatibility
89 if self.stream.current.type is 'colon':
90 self.stream.next()
91
92 if self.stream.current.type is 'block_end':
93 self.stream.next()
94 result = self.subparse(end_tokens)
95 else:
96 result = []
97 while self.stream.current.type not in end_tokens:
Armin Ronachere791c2a2008-04-07 18:39:54 +020098 if self.stream.current.type is 'block_end':
99 self.stream.next()
100 result.extend(self.subparse(end_tokens))
101 break
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200102 result.append(self.parse_statement())
103 if drop_needle:
104 self.stream.next()
105 return result
106
107 def parse_for(self):
108 """Parse a for loop."""
109 lineno = self.stream.expect('for').lineno
110 target = self.parse_tuple(simplified=True)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200111 if not target.can_assign():
112 raise TemplateSyntaxError("can't assign to '%s'" %
113 target, target.lineno,
114 self.filename)
115 target.set_ctx('store')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200116 self.stream.expect('in')
117 iter = self.parse_tuple()
118 if self.stream.current.type is 'recursive':
119 self.stream.next()
120 recursive = True
121 else:
122 recursive = False
123 body = self.parse_statements(('endfor', 'else'))
Armin Ronachere791c2a2008-04-07 18:39:54 +0200124 if self.stream.next().type is 'endfor':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200125 else_ = []
126 else:
127 else_ = self.parse_statements(('endfor',), drop_needle=True)
128 return nodes.For(target, iter, body, else_, False, lineno=lineno)
129
130 def parse_if(self):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200131 """Parse an if construct."""
132 node = result = nodes.If(lineno=self.stream.expect('if').lineno)
133 while 1:
134 # TODO: exclude conditional expressions here
135 node.test = self.parse_tuple()
136 node.body = self.parse_statements(('elif', 'else', 'endif'))
137 token_type = self.stream.next().type
138 if token_type is 'elif':
139 new_node = nodes.If(lineno=self.stream.current.lineno)
140 node.else_ = [new_node]
141 node = new_node
142 continue
143 elif token_type is 'else':
144 node.else_ = self.parse_statements(('endif',),
145 drop_needle=True)
146 else:
147 node.else_ = []
148 break
149 return result
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200150
151 def parse_block(self):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200152 node = nodes.Block(lineno=self.stream.expect('block').lineno)
153 node.name = self.stream.expect('name').value
154 node.body = self.parse_statements(('endblock',), drop_needle=True)
155 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200156
157 def parse_extends(self):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200158 node = nodes.Extends(lineno=self.stream.expect('extends').lineno)
159 node.template = self.parse_expression()
160 self.end_statement()
161 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200162
163 def parse_include(self):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200164 node = nodes.Include(lineno=self.stream.expect('include').lineno)
165 expr = self.parse_expression()
166 if self.stream.current.type is 'assign':
167 self.stream.next()
168 if not expr.can_assign():
169 raise TemplateSyntaxError('can\'t assign imported template '
170 'to this expression.', expr.lineno,
171 self.filename)
172 expr.set_ctx('store')
173 node.target = expr
174 node.template = self.parse_expression()
175 else:
176 node.target = None
177 node.template = expr
178 self.end_statement()
179 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200180
181 def parse_call_block(self):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200182 node = nodes.CallBlock(lineno=self.stream.expect('call').lineno)
183 node.call = self.parse_call()
184 node.body = self.parse_statements(('endcall',), drop_needle=True)
185 return node
186
187 def parse_macro(self):
188 node = nodes.Macro(lineno=self.stream.expect('macro').lineno)
189 node.name = self.stream.expect('name').value
190 self.stream.expect('lparen')
191 node.args = args = []
192 node.defaults = defaults = []
193 while self.stream.current.type is not 'rparen':
194 if args:
195 self.stream.expect('comma')
196 token = self.stream.expect('name')
197 arg = nodes.Name(token.value, 'param', lineno=token.lineno)
198 if not arg.can_assign():
199 raise TemplateSyntaxError("can't assign to '%s'" %
200 arg.name, arg.lineno,
201 self.filename)
202 if self.stream.current.type is 'assign':
203 self.stream.next()
204 defaults.append(self.parse_expression())
205 self.stream.expect('rparen')
206 node.body = self.parse_statements(('endmacro',), drop_needle=True)
207 return node
208
209 def parse_print(self):
210 node = nodes.Output(lineno=self.stream.expect('print').lineno)
211 node.nodes = []
212 while self.stream.current.type not in _statement_end_tokens:
213 if node.nodes:
214 self.stream.expect('comma')
215 node.nodes.append(self.parse_expression())
216 self.end_statement()
217 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200218
219 def parse_expression(self):
220 """Parse an expression."""
221 return self.parse_condexpr()
222
223 def parse_condexpr(self):
224 lineno = self.stream.current.lineno
225 expr1 = self.parse_or()
226 while self.stream.current.type is 'if':
227 self.stream.next()
228 expr2 = self.parse_or()
229 self.stream.expect('else')
230 expr3 = self.parse_condexpr()
231 expr1 = nodes.CondExpr(expr2, expr1, expr3, lineno=lineno)
232 lineno = self.stream.current.lineno
233 return expr1
234
235 def parse_or(self):
236 lineno = self.stream.current.lineno
237 left = self.parse_and()
238 while self.stream.current.type is 'or':
239 self.stream.next()
240 right = self.parse_and()
241 left = nodes.Or(left, right, lineno=lineno)
242 lineno = self.stream.current.lineno
243 return left
244
245 def parse_and(self):
246 lineno = self.stream.current.lineno
247 left = self.parse_compare()
248 while self.stream.current.type is 'and':
249 self.stream.next()
250 right = self.parse_compare()
251 left = nodes.And(left, right, lineno=lineno)
252 lineno = self.stream.current.lineno
253 return left
254
255 def parse_compare(self):
256 lineno = self.stream.current.lineno
257 expr = self.parse_add()
258 ops = []
259 while 1:
260 token_type = self.stream.current.type
261 if token_type in _compare_operators:
262 self.stream.next()
263 ops.append(nodes.Operand(token_type, self.parse_add()))
264 elif token_type is 'not' and self.stream.look().type is 'in':
265 self.stream.skip(2)
266 ops.append(nodes.Operand('notin', self.parse_add()))
267 else:
268 break
269 lineno = self.stream.current.lineno
270 if not ops:
271 return expr
272 return nodes.Compare(expr, ops, lineno=lineno)
273
274 def parse_add(self):
275 lineno = self.stream.current.lineno
276 left = self.parse_sub()
277 while self.stream.current.type is 'add':
278 self.stream.next()
279 right = self.parse_sub()
280 left = nodes.Add(left, right, lineno=lineno)
281 lineno = self.stream.current.lineno
282 return left
283
284 def parse_sub(self):
285 lineno = self.stream.current.lineno
286 left = self.parse_concat()
287 while self.stream.current.type is 'sub':
288 self.stream.next()
289 right = self.parse_concat()
290 left = nodes.Sub(left, right, lineno=lineno)
291 lineno = self.stream.current.lineno
292 return left
293
294 def parse_concat(self):
295 lineno = self.stream.current.lineno
296 args = [self.parse_mul()]
297 while self.stream.current.type is 'tilde':
298 self.stream.next()
299 args.append(self.parse_mul())
300 if len(args) == 1:
301 return args[0]
302 return nodes.Concat(args, lineno=lineno)
303
304 def parse_mul(self):
305 lineno = self.stream.current.lineno
306 left = self.parse_div()
307 while self.stream.current.type is 'mul':
308 self.stream.next()
309 right = self.parse_div()
310 left = nodes.Mul(left, right, lineno=lineno)
311 lineno = self.stream.current.lineno
312 return left
313
314 def parse_div(self):
315 lineno = self.stream.current.lineno
316 left = self.parse_floordiv()
317 while self.stream.current.type is 'div':
318 self.stream.next()
319 right = self.parse_floordiv()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200320 left = nodes.Div(left, right, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200321 lineno = self.stream.current.lineno
322 return left
323
324 def parse_floordiv(self):
325 lineno = self.stream.current.lineno
326 left = self.parse_mod()
327 while self.stream.current.type is 'floordiv':
328 self.stream.next()
329 right = self.parse_mod()
330 left = nodes.FloorDiv(left, right, lineno=lineno)
331 lineno = self.stream.current.lineno
332 return left
333
334 def parse_mod(self):
335 lineno = self.stream.current.lineno
336 left = self.parse_pow()
337 while self.stream.current.type is 'mod':
338 self.stream.next()
339 right = self.parse_pow()
340 left = nodes.Mod(left, right, lineno=lineno)
341 lineno = self.stream.current.lineno
342 return left
343
344 def parse_pow(self):
345 lineno = self.stream.current.lineno
346 left = self.parse_unary()
347 while self.stream.current.type is 'pow':
348 self.stream.next()
349 right = self.parse_unary()
350 left = nodes.Pow(left, right, lineno=lineno)
351 lineno = self.stream.current.lineno
352 return left
353
354 def parse_unary(self):
355 token_type = self.stream.current.type
356 lineno = self.stream.current.lineno
357 if token_type is 'not':
358 self.stream.next()
359 node = self.parse_unary()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200360 return nodes.Not(node, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200361 if token_type is 'sub':
362 self.stream.next()
363 node = self.parse_unary()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200364 return nodes.Neg(node, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200365 if token_type is 'add':
366 self.stream.next()
367 node = self.parse_unary()
368 return nodes.Pos(node, lineno=lineno)
369 return self.parse_primary()
370
371 def parse_primary(self, parse_postfix=True):
372 token = self.stream.current
373 if token.type is 'name':
374 if token.value in ('true', 'false'):
375 node = nodes.Const(token.value == 'true', lineno=token.lineno)
376 elif token.value == 'none':
377 node = nodes.Const(None, lineno=token.lineno)
378 else:
379 node = nodes.Name(token.value, 'load', lineno=token.lineno)
380 self.stream.next()
381 elif token.type in ('integer', 'float', 'string'):
382 self.stream.next()
383 node = nodes.Const(token.value, lineno=token.lineno)
384 elif token.type is 'lparen':
385 self.stream.next()
386 node = self.parse_tuple()
387 self.stream.expect('rparen')
388 elif token.type is 'lbracket':
389 node = self.parse_list()
390 elif token.type is 'lbrace':
391 node = self.parse_dict()
392 else:
393 raise TemplateSyntaxError("unexpected token '%s'" %
394 (token,), token.lineno,
395 self.filename)
396 if parse_postfix:
397 node = self.parse_postfix(node)
398 return node
399
400 def parse_tuple(self, enforce=False, simplified=False):
401 """
402 Parse multiple expressions into a tuple. This can also return
403 just one expression which is not a tuple. If you want to enforce
404 a tuple, pass it enforce=True (currently unused).
405 """
406 lineno = self.stream.current.lineno
407 parse = simplified and self.parse_primary or self.parse_expression
408 args = []
409 is_tuple = False
410 while 1:
411 if args:
412 self.stream.expect('comma')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200413 if self.stream.current.type in _statement_end_tokens:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200414 break
415 args.append(parse())
416 if self.stream.current.type is not 'comma':
417 break
418 is_tuple = True
419 lineno = self.stream.current.lineno
420 if not is_tuple and args:
421 if enforce:
422 raise TemplateSyntaxError('tuple expected', lineno,
423 self.filename)
424 return args[0]
425 return nodes.Tuple(args, 'load', lineno=lineno)
426
427 def parse_list(self):
428 token = self.stream.expect('lbracket')
429 items = []
430 while self.stream.current.type is not 'rbracket':
431 if items:
432 self.stream.expect('comma')
433 if self.stream.current.type == 'rbracket':
434 break
435 items.append(self.parse_expression())
436 self.stream.expect('rbracket')
437 return nodes.List(items, lineno=token.lineno)
438
439 def parse_dict(self):
440 token = self.stream.expect('lbrace')
441 items = []
442 while self.stream.current.type is not 'rbrace':
443 if items:
444 self.stream.expect('comma')
445 if self.stream.current.type == 'rbrace':
446 break
447 key = self.parse_expression()
448 self.stream.expect('colon')
449 value = self.parse_expression()
450 items.append(nodes.Pair(key, value, lineno=key.lineno))
451 self.stream.expect('rbrace')
452 return nodes.Dict(items, token.lineno, self.filename)
453
454 def parse_postfix(self, node):
455 while 1:
456 token_type = self.stream.current.type
457 if token_type is 'dot' or token_type is 'lbracket':
458 node = self.parse_subscript(node)
459 elif token_type is 'lparen':
460 node = self.parse_call(node)
461 elif token_type is 'pipe':
462 node = self.parse_filter(node)
463 elif token_type is 'is':
464 node = self.parse_test(node)
465 else:
466 break
467 return node
468
469 def parse_subscript(self, node):
470 token = self.stream.next()
471 if token.type is 'dot':
Armin Ronachere791c2a2008-04-07 18:39:54 +0200472 attr_token = self.stream.current
473 if attr_token.type not in ('name', 'integer'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200474 raise TemplateSyntaxError('expected name or number',
Armin Ronachere791c2a2008-04-07 18:39:54 +0200475 attr_token.lineno, self.filename)
476 arg = nodes.Const(attr_token.value, lineno=attr_token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200477 self.stream.next()
478 elif token.type is 'lbracket':
479 args = []
480 while self.stream.current.type is not 'rbracket':
481 if args:
482 self.stream.expect('comma')
483 args.append(self.parse_subscribed())
484 self.stream.expect('rbracket')
485 if len(args) == 1:
486 arg = args[0]
487 else:
488 arg = nodes.Tuple(args, lineno, self.filename)
489 else:
490 raise TemplateSyntaxError('expected subscript expression',
491 self.lineno, self.filename)
492 return nodes.Subscript(node, arg, 'load', lineno=token.lineno)
493
494 def parse_subscribed(self):
495 lineno = self.stream.current.lineno
496
497 if self.stream.current.type is 'colon':
498 self.stream.next()
499 args = [None]
500 else:
501 node = self.parse_expression()
502 if self.stream.current.type is not 'colon':
503 return node
504 self.stream.next()
505 args = [node]
506
507 if self.stream.current.type is 'colon':
508 args.append(None)
509 elif self.stream.current.type not in ('rbracket', 'comma'):
510 args.append(self.parse_expression())
511 else:
512 args.append(None)
513
514 if self.stream.current.type is 'colon':
515 self.stream.next()
516 if self.stream.current.type not in ('rbracket', 'comma'):
517 args.append(self.parse_expression())
518 else:
519 args.append(None)
520 else:
521 args.append(None)
522
523 return nodes.Slice(lineno=lineno, *args)
524
525 def parse_call(self, node):
526 token = self.stream.expect('lparen')
527 args = []
528 kwargs = []
529 dyn_args = dyn_kwargs = None
530 require_comma = False
531
532 def ensure(expr):
533 if not expr:
534 raise TemplateSyntaxError('invalid syntax for function '
535 'call expression', token.lineno,
536 self.filename)
537
538 while self.stream.current.type is not 'rparen':
539 if require_comma:
540 self.stream.expect('comma')
541 # support for trailing comma
542 if self.stream.current.type is 'rparen':
543 break
544 if self.stream.current.type is 'mul':
545 ensure(dyn_args is None and dyn_kwargs is None)
546 self.stream.next()
547 dyn_args = self.parse_expression()
548 elif self.stream.current.type is 'pow':
549 ensure(dyn_kwargs is None)
550 self.stream.next()
551 dyn_kwargs = self.parse_expression()
552 else:
553 ensure(dyn_args is None and dyn_kwargs is None)
554 if self.stream.current.type is 'name' and \
555 self.stream.look().type is 'assign':
556 key = self.stream.current.value
557 self.stream.skip(2)
558 kwargs.append(nodes.Pair(key, self.parse_expression(),
559 lineno=key.lineno))
560 else:
561 ensure(not kwargs)
562 args.append(self.parse_expression())
563
564 require_comma = True
565 self.stream.expect('rparen')
566
567 if node is None:
568 return args, kwargs, dyn_args, dyn_kwargs
569 return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs,
570 lineno=token.lineno)
571
572 def parse_filter(self, node):
573 lineno = self.stream.current.type
574 filters = []
575 while self.stream.current.type == 'pipe':
576 self.stream.next()
577 token = self.stream.expect('name')
578 if self.stream.current.type is 'lparen':
579 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
580 else:
581 args = []
582 kwargs = []
583 dyn_args = dyn_kwargs = None
584 filters.append(nodes.FilterCall(token.value, args, kwargs,
585 dyn_args, dyn_kwargs,
586 lineno=token.lineno))
587 return nodes.Filter(node, filters)
588
589 def parse_test(self, node):
590 token = self.stream.expect('is')
591 if self.stream.current.type is 'not':
592 self.stream.next()
593 negated = True
594 else:
595 negated = False
596 name = self.stream.expect('name').value
597 if self.stream.current.type is 'lparen':
598 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
599 elif self.stream.current.type in ('name', 'string', 'integer',
600 'float', 'lparen', 'lbracket',
601 'lbrace', 'regex'):
602 args = [self.parse_expression()]
603 else:
604 args = []
605 kwargs = []
606 dyn_args = dyn_kwargs = None
607 node = nodes.Test(node, name, args, kwargs, dyn_args,
608 dyn_kwargs, lineno=token.lineno)
609 if negated:
610 node = nodes.NotExpression(node, lineno=token.lineno)
611 return node
612
613 def subparse(self, end_tokens=None):
614 body = []
615 data_buffer = []
616 add_data = data_buffer.append
617
618 def flush_data():
619 if data_buffer:
620 lineno = data_buffer[0].lineno
621 body.append(nodes.Output(data_buffer[:], lineno=lineno))
622 del data_buffer[:]
623
624 while self.stream:
625 token = self.stream.current
626 if token.type is 'data':
627 add_data(nodes.Const(token.value, lineno=token.lineno))
628 self.stream.next()
629 elif token.type is 'variable_begin':
630 self.stream.next()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200631 want_comma = False
632 while not self.stream.current.type in _statement_end_tokens:
633 if want_comma:
634 self.stream.expect('comma')
635 add_data(self.parse_expression())
636 want_comma = True
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200637 self.stream.expect('variable_end')
638 elif token.type is 'block_begin':
639 flush_data()
640 self.stream.next()
641 if end_tokens is not None and \
642 self.stream.current.type in end_tokens:
643 return body
644 while self.stream.current.type is not 'block_end':
645 body.append(self.parse_statement())
646 self.stream.expect('block_end')
647 else:
648 raise AssertionError('internal parsing error')
649
650 flush_data()
651 return body
652
653 def parse(self):
654 """Parse the whole template into a `Template` node."""
655 return nodes.Template(self.subparse(), lineno=1)