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.lexer import describe_token, describe_token_expr | 13 from jinja2.lexer import describe_token, describe_token_expr |
14 from jinja2._compat import next, imap | 14 from jinja2._compat import imap |
15 | 15 |
16 | 16 |
17 #: statements that callinto | |
18 _statement_keywords = frozenset(['for', 'if', 'block', 'extends', 'print', | 17 _statement_keywords = frozenset(['for', 'if', 'block', 'extends', 'print', |
19 'macro', 'include', 'from', 'import', | 18 'macro', 'include', 'from', 'import', |
20 'set']) | 19 'set']) |
21 _compare_operators = frozenset(['eq', 'ne', 'lt', 'lteq', 'gt', 'gteq']) | 20 _compare_operators = frozenset(['eq', 'ne', 'lt', 'lteq', 'gt', 'gteq']) |
22 | 21 |
23 | 22 |
24 class Parser(object): | 23 class Parser(object): |
25 """This is the central parsing class Jinja2 uses. It's passed to | 24 """This is the central parsing class Jinja2 uses. It's passed to |
26 extensions and can be used to parse expressions or statements. | 25 extensions and can be used to parse expressions or statements. |
27 """ | 26 """ |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
162 self.fail_eof(end_tokens) | 161 self.fail_eof(end_tokens) |
163 | 162 |
164 if drop_needle: | 163 if drop_needle: |
165 next(self.stream) | 164 next(self.stream) |
166 return result | 165 return result |
167 | 166 |
168 def parse_set(self): | 167 def parse_set(self): |
169 """Parse an assign statement.""" | 168 """Parse an assign statement.""" |
170 lineno = next(self.stream).lineno | 169 lineno = next(self.stream).lineno |
171 target = self.parse_assign_target() | 170 target = self.parse_assign_target() |
172 self.stream.expect('assign') | 171 if self.stream.skip_if('assign'): |
173 expr = self.parse_tuple() | 172 expr = self.parse_tuple() |
174 return nodes.Assign(target, expr, lineno=lineno) | 173 return nodes.Assign(target, expr, lineno=lineno) |
| 174 body = self.parse_statements(('name:endset',), |
| 175 drop_needle=True) |
| 176 return nodes.AssignBlock(target, body, lineno=lineno) |
175 | 177 |
176 def parse_for(self): | 178 def parse_for(self): |
177 """Parse a for loop.""" | 179 """Parse a for loop.""" |
178 lineno = self.stream.expect('name:for').lineno | 180 lineno = self.stream.expect('name:for').lineno |
179 target = self.parse_assign_target(extra_end_rules=('name:in',)) | 181 target = self.parse_assign_target(extra_end_rules=('name:in',)) |
180 self.stream.expect('name:in') | 182 self.stream.expect('name:in') |
181 iter = self.parse_tuple(with_condexpr=False, | 183 iter = self.parse_tuple(with_condexpr=False, |
182 extra_end_rules=('name:recursive',)) | 184 extra_end_rules=('name:recursive',)) |
183 test = None | 185 test = None |
184 if self.stream.skip_if('name:if'): | 186 if self.stream.skip_if('name:if'): |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
305 node.args = args = [] | 307 node.args = args = [] |
306 node.defaults = defaults = [] | 308 node.defaults = defaults = [] |
307 self.stream.expect('lparen') | 309 self.stream.expect('lparen') |
308 while self.stream.current.type != 'rparen': | 310 while self.stream.current.type != 'rparen': |
309 if args: | 311 if args: |
310 self.stream.expect('comma') | 312 self.stream.expect('comma') |
311 arg = self.parse_assign_target(name_only=True) | 313 arg = self.parse_assign_target(name_only=True) |
312 arg.set_ctx('param') | 314 arg.set_ctx('param') |
313 if self.stream.skip_if('assign'): | 315 if self.stream.skip_if('assign'): |
314 defaults.append(self.parse_expression()) | 316 defaults.append(self.parse_expression()) |
| 317 elif defaults: |
| 318 self.fail('non-default argument follows default argument') |
315 args.append(arg) | 319 args.append(arg) |
316 self.stream.expect('rparen') | 320 self.stream.expect('rparen') |
317 | 321 |
318 def parse_call_block(self): | 322 def parse_call_block(self): |
319 node = nodes.CallBlock(lineno=next(self.stream).lineno) | 323 node = nodes.CallBlock(lineno=next(self.stream).lineno) |
320 if self.stream.current.type == 'lparen': | 324 if self.stream.current.type == 'lparen': |
321 self.parse_signature(node) | 325 self.parse_signature(node) |
322 else: | 326 else: |
323 node.args = [] | 327 node.args = [] |
324 node.defaults = [] | 328 node.defaults = [] |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
427 lineno = self.stream.current.lineno | 431 lineno = self.stream.current.lineno |
428 expr = self.parse_add() | 432 expr = self.parse_add() |
429 ops = [] | 433 ops = [] |
430 while 1: | 434 while 1: |
431 token_type = self.stream.current.type | 435 token_type = self.stream.current.type |
432 if token_type in _compare_operators: | 436 if token_type in _compare_operators: |
433 next(self.stream) | 437 next(self.stream) |
434 ops.append(nodes.Operand(token_type, self.parse_add())) | 438 ops.append(nodes.Operand(token_type, self.parse_add())) |
435 elif self.stream.skip_if('name:in'): | 439 elif self.stream.skip_if('name:in'): |
436 ops.append(nodes.Operand('in', self.parse_add())) | 440 ops.append(nodes.Operand('in', self.parse_add())) |
437 elif self.stream.current.test('name:not') and \ | 441 elif (self.stream.current.test('name:not') and |
438 self.stream.look().test('name:in'): | 442 self.stream.look().test('name:in')): |
439 self.stream.skip(2) | 443 self.stream.skip(2) |
440 ops.append(nodes.Operand('notin', self.parse_add())) | 444 ops.append(nodes.Operand('notin', self.parse_add())) |
441 else: | 445 else: |
442 break | 446 break |
443 lineno = self.stream.current.lineno | 447 lineno = self.stream.current.lineno |
444 if not ops: | 448 if not ops: |
445 return expr | 449 return expr |
446 return nodes.Compare(expr, ops, lineno=lineno) | 450 return nodes.Compare(expr, ops, lineno=lineno) |
447 | 451 |
448 def parse_add(self): | 452 def parse_add(self): |
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
764 ensure(dyn_args is None and dyn_kwargs is None) | 768 ensure(dyn_args is None and dyn_kwargs is None) |
765 next(self.stream) | 769 next(self.stream) |
766 dyn_args = self.parse_expression() | 770 dyn_args = self.parse_expression() |
767 elif self.stream.current.type == 'pow': | 771 elif self.stream.current.type == 'pow': |
768 ensure(dyn_kwargs is None) | 772 ensure(dyn_kwargs is None) |
769 next(self.stream) | 773 next(self.stream) |
770 dyn_kwargs = self.parse_expression() | 774 dyn_kwargs = self.parse_expression() |
771 else: | 775 else: |
772 ensure(dyn_args is None and dyn_kwargs is None) | 776 ensure(dyn_args is None and dyn_kwargs is None) |
773 if self.stream.current.type == 'name' and \ | 777 if self.stream.current.type == 'name' and \ |
774 self.stream.look().type == 'assign': | 778 self.stream.look().type == 'assign': |
775 key = self.stream.current.value | 779 key = self.stream.current.value |
776 self.stream.skip(2) | 780 self.stream.skip(2) |
777 value = self.parse_expression() | 781 value = self.parse_expression() |
778 kwargs.append(nodes.Keyword(key, value, | 782 kwargs.append(nodes.Keyword(key, value, |
779 lineno=value.lineno)) | 783 lineno=value.lineno)) |
780 else: | 784 else: |
781 ensure(not kwargs) | 785 ensure(not kwargs) |
782 args.append(self.parse_expression()) | 786 args.append(self.parse_expression()) |
783 | 787 |
784 require_comma = True | 788 require_comma = True |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
817 else: | 821 else: |
818 negated = False | 822 negated = False |
819 name = self.stream.expect('name').value | 823 name = self.stream.expect('name').value |
820 while self.stream.current.type == 'dot': | 824 while self.stream.current.type == 'dot': |
821 next(self.stream) | 825 next(self.stream) |
822 name += '.' + self.stream.expect('name').value | 826 name += '.' + self.stream.expect('name').value |
823 dyn_args = dyn_kwargs = None | 827 dyn_args = dyn_kwargs = None |
824 kwargs = [] | 828 kwargs = [] |
825 if self.stream.current.type == 'lparen': | 829 if self.stream.current.type == 'lparen': |
826 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None) | 830 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None) |
827 elif self.stream.current.type in ('name', 'string', 'integer', | 831 elif (self.stream.current.type in ('name', 'string', 'integer', |
828 'float', 'lparen', 'lbracket', | 832 'float', 'lparen', 'lbracket', |
829 'lbrace') and not \ | 833 'lbrace') and not |
830 self.stream.current.test_any('name:else', 'name:or', | 834 self.stream.current.test_any('name:else', 'name:or', |
831 'name:and'): | 835 'name:and')): |
832 if self.stream.current.test('name:is'): | 836 if self.stream.current.test('name:is'): |
833 self.fail('You cannot chain multiple tests with is') | 837 self.fail('You cannot chain multiple tests with is') |
834 args = [self.parse_expression()] | 838 args = [self.parse_expression()] |
835 else: | 839 else: |
836 args = [] | 840 args = [] |
837 node = nodes.Test(node, name, args, kwargs, dyn_args, | 841 node = nodes.Test(node, name, args, kwargs, dyn_args, |
838 dyn_kwargs, lineno=token.lineno) | 842 dyn_kwargs, lineno=token.lineno) |
839 if negated: | 843 if negated: |
840 node = nodes.Not(node, lineno=token.lineno) | 844 node = nodes.Not(node, lineno=token.lineno) |
841 return node | 845 return node |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
886 if end_tokens is not None: | 890 if end_tokens is not None: |
887 self._end_token_stack.pop() | 891 self._end_token_stack.pop() |
888 | 892 |
889 return body | 893 return body |
890 | 894 |
891 def parse(self): | 895 def parse(self): |
892 """Parse the whole template into a `Template` node.""" | 896 """Parse the whole template into a `Template` node.""" |
893 result = nodes.Template(self.subparse(), lineno=1) | 897 result = nodes.Template(self.subparse(), lineno=1) |
894 result.set_environment(self.environment) | 898 result.set_environment(self.environment) |
895 return result | 899 return result |
OLD | NEW |