1645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez# -*- coding: utf-8 -*- 2645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez""" 3645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez jinja2.parser 4645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez ~~~~~~~~~~~~~ 5645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 6645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez Implements the template parser. 7645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 8645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez :copyright: (c) 2010 by the Jinja Team. 9645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez :license: BSD, see LICENSE for more details. 10645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez""" 11645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezfrom jinja2 import nodes 12645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezfrom jinja2.exceptions import TemplateSyntaxError, TemplateAssertionError 13645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezfrom jinja2.lexer import describe_token, describe_token_expr 14645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezfrom jinja2._compat import next, imap 15645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 16645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 17645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#: statements that callinto 18645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez_statement_keywords = frozenset(['for', 'if', 'block', 'extends', 'print', 19645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 'macro', 'include', 'from', 'import', 20645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 'set']) 21645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez_compare_operators = frozenset(['eq', 'ne', 'lt', 'lteq', 'gt', 'gteq']) 22645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 23645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 24645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezclass Parser(object): 25645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """This is the central parsing class Jinja2 uses. It's passed to 26645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez extensions and can be used to parse expressions or statements. 27645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """ 28645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 29645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def __init__(self, environment, source, name=None, filename=None, 30645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez state=None): 31645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.environment = environment 32645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream = environment._tokenize(source, name, filename, state) 33645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.name = name 34645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.filename = filename 35645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.closed = False 36645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.extensions = {} 37645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez for extension in environment.iter_extensions(): 38645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez for tag in extension.tags: 39645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.extensions[tag] = extension.parse 40645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self._last_identifier = 0 41645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self._tag_stack = [] 42645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self._end_token_stack = [] 43645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 44645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def fail(self, msg, lineno=None, exc=TemplateSyntaxError): 45645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """Convenience method that raises `exc` with the message, passed 46645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez line number or last line number as well as the current name and 47645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez filename. 48645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """ 49645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if lineno is None: 50645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 51645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez raise exc(msg, lineno, self.name, self.filename) 52645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 53645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def _fail_ut_eof(self, name, end_token_stack, lineno): 54645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez expected = [] 55645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez for exprs in end_token_stack: 56645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez expected.extend(imap(describe_token_expr, exprs)) 57645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if end_token_stack: 58645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez currently_looking = ' or '.join( 59645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez "'%s'" % describe_token_expr(expr) 60645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez for expr in end_token_stack[-1]) 61645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 62645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez currently_looking = None 63645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 64645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if name is None: 65645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez message = ['Unexpected end of template.'] 66645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 67645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez message = ['Encountered unknown tag \'%s\'.' % name] 68645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 69645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if currently_looking: 70645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if name is not None and name in expected: 71645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez message.append('You probably made a nesting mistake. Jinja ' 72645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 'is expecting this tag, but currently looking ' 73645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 'for %s.' % currently_looking) 74645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 75645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez message.append('Jinja was looking for the following tags: ' 76645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez '%s.' % currently_looking) 77645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 78645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self._tag_stack: 79645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez message.append('The innermost block that needs to be ' 80645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 'closed is \'%s\'.' % self._tag_stack[-1]) 81645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 82645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.fail(' '.join(message), lineno) 83645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 84645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def fail_unknown_tag(self, name, lineno=None): 85645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """Called if the parser encounters an unknown tag. Tries to fail 86645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez with a human readable error message that could help to identify 87645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez the problem. 88645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """ 89645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return self._fail_ut_eof(name, self._end_token_stack, lineno) 90645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 91645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def fail_eof(self, end_tokens=None, lineno=None): 92645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """Like fail_unknown_tag but for end of template situations.""" 93645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez stack = list(self._end_token_stack) 94645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if end_tokens is not None: 95645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez stack.append(end_tokens) 96645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return self._fail_ut_eof(None, stack, lineno) 97645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 98645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def is_tuple_end(self, extra_end_rules=None): 99645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """Are we at the end of a tuple?""" 100645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.current.type in ('variable_end', 'block_end', 'rparen'): 101645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return True 102645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez elif extra_end_rules is not None: 103645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return self.stream.current.test_any(extra_end_rules) 104645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return False 105645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 106645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def free_identifier(self, lineno=None): 107645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """Return a new free identifier as :class:`~jinja2.nodes.InternalName`.""" 108645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self._last_identifier += 1 109645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez rv = object.__new__(nodes.InternalName) 110645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez nodes.Node.__init__(rv, 'fi%d' % self._last_identifier, lineno=lineno) 111645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return rv 112645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 113645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_statement(self): 114645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """Parse a single statement.""" 115645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez token = self.stream.current 116645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if token.type != 'name': 117645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.fail('tag name expected', token.lineno) 118645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self._tag_stack.append(token.value) 119645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez pop_tag = True 120645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez try: 121645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if token.value in _statement_keywords: 122645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return getattr(self, 'parse_' + self.stream.current.value)() 123645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if token.value == 'call': 124645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return self.parse_call_block() 125645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if token.value == 'filter': 126645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return self.parse_filter_block() 127645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez ext = self.extensions.get(token.value) 128645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if ext is not None: 129645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return ext(self) 130645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 131645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # did not work out, remove the token we pushed by accident 132645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # from the stack so that the unknown tag fail function can 133645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # produce a proper error message. 134645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self._tag_stack.pop() 135645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez pop_tag = False 136645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.fail_unknown_tag(token.value, token.lineno) 137645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez finally: 138645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if pop_tag: 139645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self._tag_stack.pop() 140645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 141645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_statements(self, end_tokens, drop_needle=False): 142645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """Parse multiple statements into a list until one of the end tokens 143645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez is reached. This is used to parse the body of statements as it also 144645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez parses template data if appropriate. The parser checks first if the 145645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez current token is a colon and skips it if there is one. Then it checks 146645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez for the block end and parses until if one of the `end_tokens` is 147645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez reached. Per default the active token in the stream at the end of 148645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez the call is the matched end token. If this is not wanted `drop_needle` 149645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez can be set to `True` and the end token is removed. 150645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """ 151645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # the first token may be a colon for python compatibility 152645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.skip_if('colon') 153645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 154645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # in the future it would be possible to add whole code sections 155645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # by adding some sort of end of statement token and parsing those here. 156645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.expect('block_end') 157645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez result = self.subparse(end_tokens) 158645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 159645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # we reached the end of the template too early, the subparser 160645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # does not check for this, so we do that now 161645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.current.type == 'eof': 162645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.fail_eof(end_tokens) 163645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 164645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if drop_needle: 165645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 166645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return result 167645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 168645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_set(self): 169645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """Parse an assign statement.""" 170645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = next(self.stream).lineno 171645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez target = self.parse_assign_target() 172645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.expect('assign') 173645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez expr = self.parse_tuple() 174645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return nodes.Assign(target, expr, lineno=lineno) 175645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 176645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_for(self): 177645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """Parse a for loop.""" 178645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.expect('name:for').lineno 179645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez target = self.parse_assign_target(extra_end_rules=('name:in',)) 180645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.expect('name:in') 181645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez iter = self.parse_tuple(with_condexpr=False, 182645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez extra_end_rules=('name:recursive',)) 183645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez test = None 184645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.skip_if('name:if'): 185645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez test = self.parse_expression() 186645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez recursive = self.stream.skip_if('name:recursive') 187645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez body = self.parse_statements(('name:endfor', 'name:else')) 188645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if next(self.stream).value == 'endfor': 189645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else_ = [] 190645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 191645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else_ = self.parse_statements(('name:endfor',), drop_needle=True) 192645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return nodes.For(target, iter, body, else_, test, 193645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez recursive, lineno=lineno) 194645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 195645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_if(self): 196645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """Parse an if construct.""" 197645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = result = nodes.If(lineno=self.stream.expect('name:if').lineno) 198645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while 1: 199645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.test = self.parse_tuple(with_condexpr=False) 200645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.body = self.parse_statements(('name:elif', 'name:else', 201645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 'name:endif')) 202645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez token = next(self.stream) 203645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if token.test('name:elif'): 204645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez new_node = nodes.If(lineno=self.stream.current.lineno) 205645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.else_ = [new_node] 206645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = new_node 207645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez continue 208645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez elif token.test('name:else'): 209645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.else_ = self.parse_statements(('name:endif',), 210645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez drop_needle=True) 211645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 212645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.else_ = [] 213645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez break 214645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return result 215645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 216645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_block(self): 217645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = nodes.Block(lineno=next(self.stream).lineno) 218645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.name = self.stream.expect('name').value 219645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.scoped = self.stream.skip_if('name:scoped') 220645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 221645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # common problem people encounter when switching from django 222645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # to jinja. we do not support hyphens in block names, so let's 223645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # raise a nicer error message in that case. 224645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.current.type == 'sub': 225645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.fail('Block names in Jinja have to be valid Python ' 226645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 'identifiers and may not contain hyphens, use an ' 227645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 'underscore instead.') 228645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 229645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.body = self.parse_statements(('name:endblock',), drop_needle=True) 230645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.skip_if('name:' + node.name) 231645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return node 232645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 233645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_extends(self): 234645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = nodes.Extends(lineno=next(self.stream).lineno) 235645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.template = self.parse_expression() 236645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return node 237645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 238645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_import_context(self, node, default): 239645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.current.test_any('name:with', 'name:without') and \ 240645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.look().test('name:context'): 241645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.with_context = next(self.stream).value == 'with' 242645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.skip() 243645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 244645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.with_context = default 245645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return node 246645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 247645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_include(self): 248645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = nodes.Include(lineno=next(self.stream).lineno) 249645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.template = self.parse_expression() 250645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.current.test('name:ignore') and \ 251645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.look().test('name:missing'): 252645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.ignore_missing = True 253645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.skip(2) 254645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 255645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.ignore_missing = False 256645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return self.parse_import_context(node, True) 257645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 258645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_import(self): 259645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = nodes.Import(lineno=next(self.stream).lineno) 260645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.template = self.parse_expression() 261645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.expect('name:as') 262645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.target = self.parse_assign_target(name_only=True).name 263645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return self.parse_import_context(node, False) 264645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 265645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_from(self): 266645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = nodes.FromImport(lineno=next(self.stream).lineno) 267645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.template = self.parse_expression() 268645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.expect('name:import') 269645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.names = [] 270645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 271645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_context(): 272645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.current.value in ('with', 'without') and \ 273645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.look().test('name:context'): 274645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.with_context = next(self.stream).value == 'with' 275645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.skip() 276645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return True 277645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return False 278645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 279645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while 1: 280645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if node.names: 281645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.expect('comma') 282645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.current.type == 'name': 283645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if parse_context(): 284645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez break 285645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez target = self.parse_assign_target(name_only=True) 286645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if target.name.startswith('_'): 287645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.fail('names starting with an underline can not ' 288645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 'be imported', target.lineno, 289645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez exc=TemplateAssertionError) 290645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.skip_if('name:as'): 291645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez alias = self.parse_assign_target(name_only=True) 292645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.names.append((target.name, alias.name)) 293645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 294645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.names.append(target.name) 295645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if parse_context() or self.stream.current.type != 'comma': 296645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez break 297645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 298645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez break 299645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if not hasattr(node, 'with_context'): 300645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.with_context = False 301645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.skip_if('comma') 302645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return node 303645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 304645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_signature(self, node): 305645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.args = args = [] 306645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.defaults = defaults = [] 307645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.expect('lparen') 308645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while self.stream.current.type != 'rparen': 309645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if args: 310645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.expect('comma') 311645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez arg = self.parse_assign_target(name_only=True) 312645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez arg.set_ctx('param') 313645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.skip_if('assign'): 314645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez defaults.append(self.parse_expression()) 315645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez args.append(arg) 316645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.expect('rparen') 317645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 318645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_call_block(self): 319645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = nodes.CallBlock(lineno=next(self.stream).lineno) 320645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.current.type == 'lparen': 321645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.parse_signature(node) 322645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 323645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.args = [] 324645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.defaults = [] 325645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 326645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.call = self.parse_expression() 327645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if not isinstance(node.call, nodes.Call): 328645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.fail('expected call', node.lineno) 329645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.body = self.parse_statements(('name:endcall',), drop_needle=True) 330645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return node 331645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 332645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_filter_block(self): 333645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = nodes.FilterBlock(lineno=next(self.stream).lineno) 334645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.filter = self.parse_filter(None, start_inline=True) 335645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.body = self.parse_statements(('name:endfilter',), 336645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez drop_needle=True) 337645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return node 338645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 339645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_macro(self): 340645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = nodes.Macro(lineno=next(self.stream).lineno) 341645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.name = self.parse_assign_target(name_only=True).name 342645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.parse_signature(node) 343645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.body = self.parse_statements(('name:endmacro',), 344645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez drop_needle=True) 345645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return node 346645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 347645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_print(self): 348645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = nodes.Output(lineno=next(self.stream).lineno) 349645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.nodes = [] 350645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while self.stream.current.type != 'block_end': 351645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if node.nodes: 352645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.expect('comma') 353645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node.nodes.append(self.parse_expression()) 354645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return node 355645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 356645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_assign_target(self, with_tuple=True, name_only=False, 357645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez extra_end_rules=None): 358645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """Parse an assignment target. As Jinja2 allows assignments to 359645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez tuples, this function can parse all allowed assignment targets. Per 360645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez default assignments to tuples are parsed, that can be disable however 361645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez by setting `with_tuple` to `False`. If only assignments to names are 362645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez wanted `name_only` can be set to `True`. The `extra_end_rules` 363645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez parameter is forwarded to the tuple parsing function. 364645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """ 365645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if name_only: 366645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez token = self.stream.expect('name') 367645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez target = nodes.Name(token.value, 'store', lineno=token.lineno) 368645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 369645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if with_tuple: 370645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez target = self.parse_tuple(simplified=True, 371645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez extra_end_rules=extra_end_rules) 372645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 373645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez target = self.parse_primary() 374645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez target.set_ctx('store') 375645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if not target.can_assign(): 376645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.fail('can\'t assign to %r' % target.__class__. 377645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez __name__.lower(), target.lineno) 378645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return target 379645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 380645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_expression(self, with_condexpr=True): 381645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """Parse an expression. Per default all expressions are parsed, if 382645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez the optional `with_condexpr` parameter is set to `False` conditional 383645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez expressions are not parsed. 384645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """ 385645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if with_condexpr: 386645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return self.parse_condexpr() 387645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return self.parse_or() 388645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 389645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_condexpr(self): 390645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 391645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez expr1 = self.parse_or() 392645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while self.stream.skip_if('name:if'): 393645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez expr2 = self.parse_or() 394645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.skip_if('name:else'): 395645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez expr3 = self.parse_condexpr() 396645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 397645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez expr3 = None 398645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez expr1 = nodes.CondExpr(expr2, expr1, expr3, lineno=lineno) 399645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 400645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return expr1 401645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 402645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_or(self): 403645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 404645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez left = self.parse_and() 405645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while self.stream.skip_if('name:or'): 406645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez right = self.parse_and() 407645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez left = nodes.Or(left, right, lineno=lineno) 408645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 409645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return left 410645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 411645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_and(self): 412645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 413645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez left = self.parse_not() 414645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while self.stream.skip_if('name:and'): 415645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez right = self.parse_not() 416645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez left = nodes.And(left, right, lineno=lineno) 417645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 418645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return left 419645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 420645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_not(self): 421645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.current.test('name:not'): 422645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = next(self.stream).lineno 423645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return nodes.Not(self.parse_not(), lineno=lineno) 424645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return self.parse_compare() 425645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 426645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_compare(self): 427645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 428645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez expr = self.parse_add() 429645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez ops = [] 430645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while 1: 431645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez token_type = self.stream.current.type 432645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if token_type in _compare_operators: 433645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 434645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez ops.append(nodes.Operand(token_type, self.parse_add())) 435645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez elif self.stream.skip_if('name:in'): 436645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez ops.append(nodes.Operand('in', self.parse_add())) 437645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez elif self.stream.current.test('name:not') and \ 438645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.look().test('name:in'): 439645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.skip(2) 440645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez ops.append(nodes.Operand('notin', self.parse_add())) 441645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 442645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez break 443645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 444645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if not ops: 445645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return expr 446645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return nodes.Compare(expr, ops, lineno=lineno) 447645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 448645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_add(self): 449645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 450645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez left = self.parse_sub() 451645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while self.stream.current.type == 'add': 452645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 453645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez right = self.parse_sub() 454645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez left = nodes.Add(left, right, lineno=lineno) 455645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 456645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return left 457645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 458645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_sub(self): 459645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 460645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez left = self.parse_concat() 461645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while self.stream.current.type == 'sub': 462645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 463645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez right = self.parse_concat() 464645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez left = nodes.Sub(left, right, lineno=lineno) 465645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 466645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return left 467645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 468645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_concat(self): 469645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 470645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez args = [self.parse_mul()] 471645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while self.stream.current.type == 'tilde': 472645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 473645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez args.append(self.parse_mul()) 474645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if len(args) == 1: 475645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return args[0] 476645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return nodes.Concat(args, lineno=lineno) 477645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 478645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_mul(self): 479645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 480645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez left = self.parse_div() 481645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while self.stream.current.type == 'mul': 482645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 483645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez right = self.parse_div() 484645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez left = nodes.Mul(left, right, lineno=lineno) 485645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 486645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return left 487645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 488645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_div(self): 489645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 490645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez left = self.parse_floordiv() 491645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while self.stream.current.type == 'div': 492645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 493645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez right = self.parse_floordiv() 494645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez left = nodes.Div(left, right, lineno=lineno) 495645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 496645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return left 497645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 498645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_floordiv(self): 499645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 500645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez left = self.parse_mod() 501645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while self.stream.current.type == 'floordiv': 502645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 503645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez right = self.parse_mod() 504645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez left = nodes.FloorDiv(left, right, lineno=lineno) 505645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 506645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return left 507645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 508645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_mod(self): 509645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 510645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez left = self.parse_pow() 511645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while self.stream.current.type == 'mod': 512645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 513645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez right = self.parse_pow() 514645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez left = nodes.Mod(left, right, lineno=lineno) 515645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 516645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return left 517645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 518645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_pow(self): 519645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 520645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez left = self.parse_unary() 521645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while self.stream.current.type == 'pow': 522645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 523645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez right = self.parse_unary() 524645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez left = nodes.Pow(left, right, lineno=lineno) 525645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 526645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return left 527645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 528645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_unary(self, with_filter=True): 529645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez token_type = self.stream.current.type 530645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 531645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if token_type == 'sub': 532645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 533645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = nodes.Neg(self.parse_unary(False), lineno=lineno) 534645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez elif token_type == 'add': 535645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 536645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = nodes.Pos(self.parse_unary(False), lineno=lineno) 537645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 538645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = self.parse_primary() 539645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = self.parse_postfix(node) 540645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if with_filter: 541645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = self.parse_filter_expr(node) 542645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return node 543645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 544645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_primary(self): 545645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez token = self.stream.current 546645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if token.type == 'name': 547645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if token.value in ('true', 'false', 'True', 'False'): 548645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = nodes.Const(token.value in ('true', 'True'), 549645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno=token.lineno) 550645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez elif token.value in ('none', 'None'): 551645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = nodes.Const(None, lineno=token.lineno) 552645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 553645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = nodes.Name(token.value, 'load', lineno=token.lineno) 554645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 555645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez elif token.type == 'string': 556645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 557645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez buf = [token.value] 558645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = token.lineno 559645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while self.stream.current.type == 'string': 560645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez buf.append(self.stream.current.value) 561645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 562645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = nodes.Const(''.join(buf), lineno=lineno) 563645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez elif token.type in ('integer', 'float'): 564645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 565645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = nodes.Const(token.value, lineno=token.lineno) 566645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez elif token.type == 'lparen': 567645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 568645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = self.parse_tuple(explicit_parentheses=True) 569645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.expect('rparen') 570645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez elif token.type == 'lbracket': 571645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = self.parse_list() 572645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez elif token.type == 'lbrace': 573645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = self.parse_dict() 574645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 575645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.fail("unexpected '%s'" % describe_token(token), token.lineno) 576645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return node 577645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 578645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_tuple(self, simplified=False, with_condexpr=True, 579645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez extra_end_rules=None, explicit_parentheses=False): 580645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """Works like `parse_expression` but if multiple expressions are 581645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created. 582645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez This method could also return a regular expression instead of a tuple 583645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if no commas where found. 584645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 585645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez The default parsing mode is a full tuple. If `simplified` is `True` 586645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez only names and literals are parsed. The `no_condexpr` parameter is 587645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez forwarded to :meth:`parse_expression`. 588645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 589645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez Because tuples do not require delimiters and may end in a bogus comma 590645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez an extra hint is needed that marks the end of a tuple. For example 591645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez for loops support tuples between `for` and `in`. In that case the 592645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez `extra_end_rules` is set to ``['name:in']``. 593645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 594645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez `explicit_parentheses` is true if the parsing was triggered by an 595645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez expression in parentheses. This is used to figure out if an empty 596645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez tuple is a valid expression or not. 597645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """ 598645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 599645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if simplified: 600645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez parse = self.parse_primary 601645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez elif with_condexpr: 602645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez parse = self.parse_expression 603645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 604645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez parse = lambda: self.parse_expression(with_condexpr=False) 605645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez args = [] 606645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez is_tuple = False 607645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while 1: 608645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if args: 609645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.expect('comma') 610645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.is_tuple_end(extra_end_rules): 611645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez break 612645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez args.append(parse()) 613645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.current.type == 'comma': 614645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez is_tuple = True 615645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 616645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez break 617645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 618645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 619645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if not is_tuple: 620645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if args: 621645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return args[0] 622645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 623645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # if we don't have explicit parentheses, an empty tuple is 624645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # not a valid expression. This would mean nothing (literally 625645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # nothing) in the spot of an expression would be an empty 626645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # tuple. 627645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if not explicit_parentheses: 628645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.fail('Expected an expression, got \'%s\'' % 629645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez describe_token(self.stream.current)) 630645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 631645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return nodes.Tuple(args, 'load', lineno=lineno) 632645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 633645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_list(self): 634645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez token = self.stream.expect('lbracket') 635645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez items = [] 636645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while self.stream.current.type != 'rbracket': 637645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if items: 638645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.expect('comma') 639645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.current.type == 'rbracket': 640645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez break 641645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez items.append(self.parse_expression()) 642645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.expect('rbracket') 643645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return nodes.List(items, lineno=token.lineno) 644645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 645645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_dict(self): 646645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez token = self.stream.expect('lbrace') 647645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez items = [] 648645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while self.stream.current.type != 'rbrace': 649645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if items: 650645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.expect('comma') 651645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.current.type == 'rbrace': 652645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez break 653645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez key = self.parse_expression() 654645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.expect('colon') 655645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez value = self.parse_expression() 656645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez items.append(nodes.Pair(key, value, lineno=key.lineno)) 657645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.expect('rbrace') 658645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return nodes.Dict(items, lineno=token.lineno) 659645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 660645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_postfix(self, node): 661645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while 1: 662645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez token_type = self.stream.current.type 663645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if token_type == 'dot' or token_type == 'lbracket': 664645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = self.parse_subscript(node) 665645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # calls are valid both after postfix expressions (getattr 666645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # and getitem) as well as filters and tests 667645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez elif token_type == 'lparen': 668645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = self.parse_call(node) 669645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 670645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez break 671645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return node 672645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 673645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_filter_expr(self, node): 674645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while 1: 675645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez token_type = self.stream.current.type 676645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if token_type == 'pipe': 677645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = self.parse_filter(node) 678645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez elif token_type == 'name' and self.stream.current.value == 'is': 679645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = self.parse_test(node) 680645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # calls are valid both after postfix expressions (getattr 681645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # and getitem) as well as filters and tests 682645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez elif token_type == 'lparen': 683645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = self.parse_call(node) 684645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 685645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez break 686645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return node 687645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 688645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_subscript(self, node): 689645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez token = next(self.stream) 690645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if token.type == 'dot': 691645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez attr_token = self.stream.current 692645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 693645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if attr_token.type == 'name': 694645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return nodes.Getattr(node, attr_token.value, 'load', 695645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno=token.lineno) 696645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez elif attr_token.type != 'integer': 697645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.fail('expected name or number', attr_token.lineno) 698645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez arg = nodes.Const(attr_token.value, lineno=attr_token.lineno) 699645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return nodes.Getitem(node, arg, 'load', lineno=token.lineno) 700645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if token.type == 'lbracket': 701645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez args = [] 702645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while self.stream.current.type != 'rbracket': 703645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if args: 704645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.expect('comma') 705645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez args.append(self.parse_subscribed()) 706645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.expect('rbracket') 707645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if len(args) == 1: 708645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez arg = args[0] 709645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 710645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez arg = nodes.Tuple(args, 'load', lineno=token.lineno) 711645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return nodes.Getitem(node, arg, 'load', lineno=token.lineno) 712645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.fail('expected subscript expression', self.lineno) 713645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 714645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_subscribed(self): 715645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = self.stream.current.lineno 716645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 717645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.current.type == 'colon': 718645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 719645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez args = [None] 720645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 721645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = self.parse_expression() 722645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.current.type != 'colon': 723645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return node 724645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 725645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez args = [node] 726645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 727645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.current.type == 'colon': 728645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez args.append(None) 729645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez elif self.stream.current.type not in ('rbracket', 'comma'): 730645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez args.append(self.parse_expression()) 731645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 732645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez args.append(None) 733645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 734645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.current.type == 'colon': 735645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 736645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.current.type not in ('rbracket', 'comma'): 737645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez args.append(self.parse_expression()) 738645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 739645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez args.append(None) 740645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 741645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez args.append(None) 742645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 743645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return nodes.Slice(lineno=lineno, *args) 744645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 745645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_call(self, node): 746645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez token = self.stream.expect('lparen') 747645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez args = [] 748645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez kwargs = [] 749645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez dyn_args = dyn_kwargs = None 750645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez require_comma = False 751645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 752645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def ensure(expr): 753645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if not expr: 754645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.fail('invalid syntax for function call expression', 755645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez token.lineno) 756645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 757645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while self.stream.current.type != 'rparen': 758645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if require_comma: 759645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.expect('comma') 760645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez # support for trailing comma 761645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.current.type == 'rparen': 762645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez break 763645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.current.type == 'mul': 764645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez ensure(dyn_args is None and dyn_kwargs is None) 765645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 766645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez dyn_args = self.parse_expression() 767645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez elif self.stream.current.type == 'pow': 768645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez ensure(dyn_kwargs is None) 769645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 770645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez dyn_kwargs = self.parse_expression() 771645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 772645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez ensure(dyn_args is None and dyn_kwargs is None) 773645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.current.type == 'name' and \ 774645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.look().type == 'assign': 775645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez key = self.stream.current.value 776645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.skip(2) 777645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez value = self.parse_expression() 778645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez kwargs.append(nodes.Keyword(key, value, 779645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno=value.lineno)) 780645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 781645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez ensure(not kwargs) 782645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez args.append(self.parse_expression()) 783645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 784645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez require_comma = True 785645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.expect('rparen') 786645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 787645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if node is None: 788645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return args, kwargs, dyn_args, dyn_kwargs 789645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs, 790645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno=token.lineno) 791645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 792645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_filter(self, node, start_inline=False): 793645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while self.stream.current.type == 'pipe' or start_inline: 794645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if not start_inline: 795645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 796645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez token = self.stream.expect('name') 797645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez name = token.value 798645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while self.stream.current.type == 'dot': 799645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 800645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez name += '.' + self.stream.expect('name').value 801645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.current.type == 'lparen': 802645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None) 803645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 804645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez args = [] 805645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez kwargs = [] 806645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez dyn_args = dyn_kwargs = None 807645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = nodes.Filter(node, name, args, kwargs, dyn_args, 808645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez dyn_kwargs, lineno=token.lineno) 809645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez start_inline = False 810645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return node 811645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 812645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse_test(self, node): 813645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez token = next(self.stream) 814645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.current.test('name:not'): 815645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 816645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez negated = True 817645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 818645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez negated = False 819645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez name = self.stream.expect('name').value 820645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while self.stream.current.type == 'dot': 821645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 822645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez name += '.' + self.stream.expect('name').value 823645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez dyn_args = dyn_kwargs = None 824645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez kwargs = [] 825645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.current.type == 'lparen': 826645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None) 827645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez elif self.stream.current.type in ('name', 'string', 'integer', 828645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 'float', 'lparen', 'lbracket', 829645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 'lbrace') and not \ 830645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.current.test_any('name:else', 'name:or', 831645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 'name:and'): 832645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if self.stream.current.test('name:is'): 833645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.fail('You cannot chain multiple tests with is') 834645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez args = [self.parse_expression()] 835645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 836645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez args = [] 837645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = nodes.Test(node, name, args, kwargs, dyn_args, 838645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez dyn_kwargs, lineno=token.lineno) 839645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if negated: 840645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez node = nodes.Not(node, lineno=token.lineno) 841645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return node 842645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 843645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def subparse(self, end_tokens=None): 844645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez body = [] 845645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez data_buffer = [] 846645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez add_data = data_buffer.append 847645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 848645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if end_tokens is not None: 849645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self._end_token_stack.append(end_tokens) 850645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 851645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def flush_data(): 852645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if data_buffer: 853645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno = data_buffer[0].lineno 854645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez body.append(nodes.Output(data_buffer[:], lineno=lineno)) 855645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez del data_buffer[:] 856645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 857645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez try: 858645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez while self.stream: 859645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez token = self.stream.current 860645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if token.type == 'data': 861645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if token.value: 862645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez add_data(nodes.TemplateData(token.value, 863645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez lineno=token.lineno)) 864645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 865645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez elif token.type == 'variable_begin': 866645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 867645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez add_data(self.parse_tuple(with_condexpr=True)) 868645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.expect('variable_end') 869645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez elif token.type == 'block_begin': 870645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez flush_data() 871645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez next(self.stream) 872645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if end_tokens is not None and \ 873645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.current.test_any(*end_tokens): 874645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return body 875645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez rv = self.parse_statement() 876645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if isinstance(rv, list): 877645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez body.extend(rv) 878645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 879645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez body.append(rv) 880645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self.stream.expect('block_end') 881645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez else: 882645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez raise AssertionError('internal parsing error') 883645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 884645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez flush_data() 885645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez finally: 886645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez if end_tokens is not None: 887645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez self._end_token_stack.pop() 888645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 889645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return body 890645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez 891645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez def parse(self): 892645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez """Parse the whole template into a `Template` node.""" 893645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez result = nodes.Template(self.subparse(), lineno=1) 894645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez result.set_environment(self.environment) 895645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez return result 896