OLD | NEW |
1 # -*- coding: utf-8 -*- | 1 # -*- coding: utf-8 -*- |
2 """ | 2 """ |
3 jinja2.parser | 3 jinja2.parser |
4 ~~~~~~~~~~~~~ | 4 ~~~~~~~~~~~~~ |
5 | 5 |
6 Implements the template parser. | 6 Implements the template parser. |
7 | 7 |
8 :copyright: (c) 2010 by the Jinja Team. | 8 :copyright: (c) 2010 by the Jinja Team. |
9 :license: BSD, see LICENSE for more details. | 9 :license: BSD, see LICENSE for more details. |
10 """ | 10 """ |
11 from jinja2 import nodes | 11 from jinja2 import nodes |
12 from jinja2.exceptions import TemplateSyntaxError, TemplateAssertionError | 12 from jinja2.exceptions import TemplateSyntaxError, TemplateAssertionError |
13 from jinja2.utils import next | |
14 from jinja2.lexer import describe_token, describe_token_expr | 13 from jinja2.lexer import describe_token, describe_token_expr |
| 14 from jinja2._compat import next, imap |
15 | 15 |
16 | 16 |
17 #: statements that callinto | 17 #: statements that callinto |
18 _statement_keywords = frozenset(['for', 'if', 'block', 'extends', 'print', | 18 _statement_keywords = frozenset(['for', 'if', 'block', 'extends', 'print', |
19 'macro', 'include', 'from', 'import', | 19 'macro', 'include', 'from', 'import', |
20 'set']) | 20 'set']) |
21 _compare_operators = frozenset(['eq', 'ne', 'lt', 'lteq', 'gt', 'gteq']) | 21 _compare_operators = frozenset(['eq', 'ne', 'lt', 'lteq', 'gt', 'gteq']) |
22 | 22 |
23 | 23 |
24 class Parser(object): | 24 class Parser(object): |
(...skipping 21 matching lines...) Expand all Loading... |
46 line number or last line number as well as the current name and | 46 line number or last line number as well as the current name and |
47 filename. | 47 filename. |
48 """ | 48 """ |
49 if lineno is None: | 49 if lineno is None: |
50 lineno = self.stream.current.lineno | 50 lineno = self.stream.current.lineno |
51 raise exc(msg, lineno, self.name, self.filename) | 51 raise exc(msg, lineno, self.name, self.filename) |
52 | 52 |
53 def _fail_ut_eof(self, name, end_token_stack, lineno): | 53 def _fail_ut_eof(self, name, end_token_stack, lineno): |
54 expected = [] | 54 expected = [] |
55 for exprs in end_token_stack: | 55 for exprs in end_token_stack: |
56 expected.extend(map(describe_token_expr, exprs)) | 56 expected.extend(imap(describe_token_expr, exprs)) |
57 if end_token_stack: | 57 if end_token_stack: |
58 currently_looking = ' or '.join( | 58 currently_looking = ' or '.join( |
59 "'%s'" % describe_token_expr(expr) | 59 "'%s'" % describe_token_expr(expr) |
60 for expr in end_token_stack[-1]) | 60 for expr in end_token_stack[-1]) |
61 else: | 61 else: |
62 currently_looking = None | 62 currently_looking = None |
63 | 63 |
64 if name is None: | 64 if name is None: |
65 message = ['Unexpected end of template.'] | 65 message = ['Unexpected end of template.'] |
66 else: | 66 else: |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
216 def parse_block(self): | 216 def parse_block(self): |
217 node = nodes.Block(lineno=next(self.stream).lineno) | 217 node = nodes.Block(lineno=next(self.stream).lineno) |
218 node.name = self.stream.expect('name').value | 218 node.name = self.stream.expect('name').value |
219 node.scoped = self.stream.skip_if('name:scoped') | 219 node.scoped = self.stream.skip_if('name:scoped') |
220 | 220 |
221 # common problem people encounter when switching from django | 221 # common problem people encounter when switching from django |
222 # to jinja. we do not support hyphens in block names, so let's | 222 # to jinja. we do not support hyphens in block names, so let's |
223 # raise a nicer error message in that case. | 223 # raise a nicer error message in that case. |
224 if self.stream.current.type == 'sub': | 224 if self.stream.current.type == 'sub': |
225 self.fail('Block names in Jinja have to be valid Python ' | 225 self.fail('Block names in Jinja have to be valid Python ' |
226 'identifiers and may not contain hypens, use an ' | 226 'identifiers and may not contain hyphens, use an ' |
227 'underscore instead.') | 227 'underscore instead.') |
228 | 228 |
229 node.body = self.parse_statements(('name:endblock',), drop_needle=True) | 229 node.body = self.parse_statements(('name:endblock',), drop_needle=True) |
230 self.stream.skip_if('name:' + node.name) | 230 self.stream.skip_if('name:' + node.name) |
231 return node | 231 return node |
232 | 232 |
233 def parse_extends(self): | 233 def parse_extends(self): |
234 node = nodes.Extends(lineno=next(self.stream).lineno) | 234 node = nodes.Extends(lineno=next(self.stream).lineno) |
235 node.template = self.parse_expression() | 235 node.template = self.parse_expression() |
236 return node | 236 return node |
(...skipping 454 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
691 attr_token = self.stream.current | 691 attr_token = self.stream.current |
692 next(self.stream) | 692 next(self.stream) |
693 if attr_token.type == 'name': | 693 if attr_token.type == 'name': |
694 return nodes.Getattr(node, attr_token.value, 'load', | 694 return nodes.Getattr(node, attr_token.value, 'load', |
695 lineno=token.lineno) | 695 lineno=token.lineno) |
696 elif attr_token.type != 'integer': | 696 elif attr_token.type != 'integer': |
697 self.fail('expected name or number', attr_token.lineno) | 697 self.fail('expected name or number', attr_token.lineno) |
698 arg = nodes.Const(attr_token.value, lineno=attr_token.lineno) | 698 arg = nodes.Const(attr_token.value, lineno=attr_token.lineno) |
699 return nodes.Getitem(node, arg, 'load', lineno=token.lineno) | 699 return nodes.Getitem(node, arg, 'load', lineno=token.lineno) |
700 if token.type == 'lbracket': | 700 if token.type == 'lbracket': |
701 priority_on_attribute = False | |
702 args = [] | 701 args = [] |
703 while self.stream.current.type != 'rbracket': | 702 while self.stream.current.type != 'rbracket': |
704 if args: | 703 if args: |
705 self.stream.expect('comma') | 704 self.stream.expect('comma') |
706 args.append(self.parse_subscribed()) | 705 args.append(self.parse_subscribed()) |
707 self.stream.expect('rbracket') | 706 self.stream.expect('rbracket') |
708 if len(args) == 1: | 707 if len(args) == 1: |
709 arg = args[0] | 708 arg = args[0] |
710 else: | 709 else: |
711 arg = nodes.Tuple(args, 'load', lineno=token.lineno) | 710 arg = nodes.Tuple(args, 'load', lineno=token.lineno) |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
887 if end_tokens is not None: | 886 if end_tokens is not None: |
888 self._end_token_stack.pop() | 887 self._end_token_stack.pop() |
889 | 888 |
890 return body | 889 return body |
891 | 890 |
892 def parse(self): | 891 def parse(self): |
893 """Parse the whole template into a `Template` node.""" | 892 """Parse the whole template into a `Template` node.""" |
894 result = nodes.Template(self.subparse(), lineno=1) | 893 result = nodes.Template(self.subparse(), lineno=1) |
895 result.set_environment(self.environment) | 894 result.set_environment(self.environment) |
896 return result | 895 return result |
OLD | NEW |