| 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 |