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