xref: /aosp_15_r20/external/libchrome/third_party/jinja2/parser.py (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker# -*- coding: utf-8 -*-
2*635a8641SAndroid Build Coastguard Worker"""
3*635a8641SAndroid Build Coastguard Worker    jinja2.parser
4*635a8641SAndroid Build Coastguard Worker    ~~~~~~~~~~~~~
5*635a8641SAndroid Build Coastguard Worker
6*635a8641SAndroid Build Coastguard Worker    Implements the template parser.
7*635a8641SAndroid Build Coastguard Worker
8*635a8641SAndroid Build Coastguard Worker    :copyright: (c) 2017 by the Jinja Team.
9*635a8641SAndroid Build Coastguard Worker    :license: BSD, see LICENSE for more details.
10*635a8641SAndroid Build Coastguard Worker"""
11*635a8641SAndroid Build Coastguard Workerfrom jinja2 import nodes
12*635a8641SAndroid Build Coastguard Workerfrom jinja2.exceptions import TemplateSyntaxError, TemplateAssertionError
13*635a8641SAndroid Build Coastguard Workerfrom jinja2.lexer import describe_token, describe_token_expr
14*635a8641SAndroid Build Coastguard Workerfrom jinja2._compat import imap
15*635a8641SAndroid Build Coastguard Worker
16*635a8641SAndroid Build Coastguard Worker
17*635a8641SAndroid Build Coastguard Worker_statement_keywords = frozenset(['for', 'if', 'block', 'extends', 'print',
18*635a8641SAndroid Build Coastguard Worker                                 'macro', 'include', 'from', 'import',
19*635a8641SAndroid Build Coastguard Worker                                 'set', 'with', 'autoescape'])
20*635a8641SAndroid Build Coastguard Worker_compare_operators = frozenset(['eq', 'ne', 'lt', 'lteq', 'gt', 'gteq'])
21*635a8641SAndroid Build Coastguard Worker
22*635a8641SAndroid Build Coastguard Worker_math_nodes = {
23*635a8641SAndroid Build Coastguard Worker    'add': nodes.Add,
24*635a8641SAndroid Build Coastguard Worker    'sub': nodes.Sub,
25*635a8641SAndroid Build Coastguard Worker    'mul': nodes.Mul,
26*635a8641SAndroid Build Coastguard Worker    'div': nodes.Div,
27*635a8641SAndroid Build Coastguard Worker    'floordiv': nodes.FloorDiv,
28*635a8641SAndroid Build Coastguard Worker    'mod': nodes.Mod,
29*635a8641SAndroid Build Coastguard Worker}
30*635a8641SAndroid Build Coastguard Worker
31*635a8641SAndroid Build Coastguard Worker
32*635a8641SAndroid Build Coastguard Workerclass Parser(object):
33*635a8641SAndroid Build Coastguard Worker    """This is the central parsing class Jinja2 uses.  It's passed to
34*635a8641SAndroid Build Coastguard Worker    extensions and can be used to parse expressions or statements.
35*635a8641SAndroid Build Coastguard Worker    """
36*635a8641SAndroid Build Coastguard Worker
37*635a8641SAndroid Build Coastguard Worker    def __init__(self, environment, source, name=None, filename=None,
38*635a8641SAndroid Build Coastguard Worker                 state=None):
39*635a8641SAndroid Build Coastguard Worker        self.environment = environment
40*635a8641SAndroid Build Coastguard Worker        self.stream = environment._tokenize(source, name, filename, state)
41*635a8641SAndroid Build Coastguard Worker        self.name = name
42*635a8641SAndroid Build Coastguard Worker        self.filename = filename
43*635a8641SAndroid Build Coastguard Worker        self.closed = False
44*635a8641SAndroid Build Coastguard Worker        self.extensions = {}
45*635a8641SAndroid Build Coastguard Worker        for extension in environment.iter_extensions():
46*635a8641SAndroid Build Coastguard Worker            for tag in extension.tags:
47*635a8641SAndroid Build Coastguard Worker                self.extensions[tag] = extension.parse
48*635a8641SAndroid Build Coastguard Worker        self._last_identifier = 0
49*635a8641SAndroid Build Coastguard Worker        self._tag_stack = []
50*635a8641SAndroid Build Coastguard Worker        self._end_token_stack = []
51*635a8641SAndroid Build Coastguard Worker
52*635a8641SAndroid Build Coastguard Worker    def fail(self, msg, lineno=None, exc=TemplateSyntaxError):
53*635a8641SAndroid Build Coastguard Worker        """Convenience method that raises `exc` with the message, passed
54*635a8641SAndroid Build Coastguard Worker        line number or last line number as well as the current name and
55*635a8641SAndroid Build Coastguard Worker        filename.
56*635a8641SAndroid Build Coastguard Worker        """
57*635a8641SAndroid Build Coastguard Worker        if lineno is None:
58*635a8641SAndroid Build Coastguard Worker            lineno = self.stream.current.lineno
59*635a8641SAndroid Build Coastguard Worker        raise exc(msg, lineno, self.name, self.filename)
60*635a8641SAndroid Build Coastguard Worker
61*635a8641SAndroid Build Coastguard Worker    def _fail_ut_eof(self, name, end_token_stack, lineno):
62*635a8641SAndroid Build Coastguard Worker        expected = []
63*635a8641SAndroid Build Coastguard Worker        for exprs in end_token_stack:
64*635a8641SAndroid Build Coastguard Worker            expected.extend(imap(describe_token_expr, exprs))
65*635a8641SAndroid Build Coastguard Worker        if end_token_stack:
66*635a8641SAndroid Build Coastguard Worker            currently_looking = ' or '.join(
67*635a8641SAndroid Build Coastguard Worker                "'%s'" % describe_token_expr(expr)
68*635a8641SAndroid Build Coastguard Worker                for expr in end_token_stack[-1])
69*635a8641SAndroid Build Coastguard Worker        else:
70*635a8641SAndroid Build Coastguard Worker            currently_looking = None
71*635a8641SAndroid Build Coastguard Worker
72*635a8641SAndroid Build Coastguard Worker        if name is None:
73*635a8641SAndroid Build Coastguard Worker            message = ['Unexpected end of template.']
74*635a8641SAndroid Build Coastguard Worker        else:
75*635a8641SAndroid Build Coastguard Worker            message = ['Encountered unknown tag \'%s\'.' % name]
76*635a8641SAndroid Build Coastguard Worker
77*635a8641SAndroid Build Coastguard Worker        if currently_looking:
78*635a8641SAndroid Build Coastguard Worker            if name is not None and name in expected:
79*635a8641SAndroid Build Coastguard Worker                message.append('You probably made a nesting mistake. Jinja '
80*635a8641SAndroid Build Coastguard Worker                               'is expecting this tag, but currently looking '
81*635a8641SAndroid Build Coastguard Worker                               'for %s.' % currently_looking)
82*635a8641SAndroid Build Coastguard Worker            else:
83*635a8641SAndroid Build Coastguard Worker                message.append('Jinja was looking for the following tags: '
84*635a8641SAndroid Build Coastguard Worker                               '%s.' % currently_looking)
85*635a8641SAndroid Build Coastguard Worker
86*635a8641SAndroid Build Coastguard Worker        if self._tag_stack:
87*635a8641SAndroid Build Coastguard Worker            message.append('The innermost block that needs to be '
88*635a8641SAndroid Build Coastguard Worker                           'closed is \'%s\'.' % self._tag_stack[-1])
89*635a8641SAndroid Build Coastguard Worker
90*635a8641SAndroid Build Coastguard Worker        self.fail(' '.join(message), lineno)
91*635a8641SAndroid Build Coastguard Worker
92*635a8641SAndroid Build Coastguard Worker    def fail_unknown_tag(self, name, lineno=None):
93*635a8641SAndroid Build Coastguard Worker        """Called if the parser encounters an unknown tag.  Tries to fail
94*635a8641SAndroid Build Coastguard Worker        with a human readable error message that could help to identify
95*635a8641SAndroid Build Coastguard Worker        the problem.
96*635a8641SAndroid Build Coastguard Worker        """
97*635a8641SAndroid Build Coastguard Worker        return self._fail_ut_eof(name, self._end_token_stack, lineno)
98*635a8641SAndroid Build Coastguard Worker
99*635a8641SAndroid Build Coastguard Worker    def fail_eof(self, end_tokens=None, lineno=None):
100*635a8641SAndroid Build Coastguard Worker        """Like fail_unknown_tag but for end of template situations."""
101*635a8641SAndroid Build Coastguard Worker        stack = list(self._end_token_stack)
102*635a8641SAndroid Build Coastguard Worker        if end_tokens is not None:
103*635a8641SAndroid Build Coastguard Worker            stack.append(end_tokens)
104*635a8641SAndroid Build Coastguard Worker        return self._fail_ut_eof(None, stack, lineno)
105*635a8641SAndroid Build Coastguard Worker
106*635a8641SAndroid Build Coastguard Worker    def is_tuple_end(self, extra_end_rules=None):
107*635a8641SAndroid Build Coastguard Worker        """Are we at the end of a tuple?"""
108*635a8641SAndroid Build Coastguard Worker        if self.stream.current.type in ('variable_end', 'block_end', 'rparen'):
109*635a8641SAndroid Build Coastguard Worker            return True
110*635a8641SAndroid Build Coastguard Worker        elif extra_end_rules is not None:
111*635a8641SAndroid Build Coastguard Worker            return self.stream.current.test_any(extra_end_rules)
112*635a8641SAndroid Build Coastguard Worker        return False
113*635a8641SAndroid Build Coastguard Worker
114*635a8641SAndroid Build Coastguard Worker    def free_identifier(self, lineno=None):
115*635a8641SAndroid Build Coastguard Worker        """Return a new free identifier as :class:`~jinja2.nodes.InternalName`."""
116*635a8641SAndroid Build Coastguard Worker        self._last_identifier += 1
117*635a8641SAndroid Build Coastguard Worker        rv = object.__new__(nodes.InternalName)
118*635a8641SAndroid Build Coastguard Worker        nodes.Node.__init__(rv, 'fi%d' % self._last_identifier, lineno=lineno)
119*635a8641SAndroid Build Coastguard Worker        return rv
120*635a8641SAndroid Build Coastguard Worker
121*635a8641SAndroid Build Coastguard Worker    def parse_statement(self):
122*635a8641SAndroid Build Coastguard Worker        """Parse a single statement."""
123*635a8641SAndroid Build Coastguard Worker        token = self.stream.current
124*635a8641SAndroid Build Coastguard Worker        if token.type != 'name':
125*635a8641SAndroid Build Coastguard Worker            self.fail('tag name expected', token.lineno)
126*635a8641SAndroid Build Coastguard Worker        self._tag_stack.append(token.value)
127*635a8641SAndroid Build Coastguard Worker        pop_tag = True
128*635a8641SAndroid Build Coastguard Worker        try:
129*635a8641SAndroid Build Coastguard Worker            if token.value in _statement_keywords:
130*635a8641SAndroid Build Coastguard Worker                return getattr(self, 'parse_' + self.stream.current.value)()
131*635a8641SAndroid Build Coastguard Worker            if token.value == 'call':
132*635a8641SAndroid Build Coastguard Worker                return self.parse_call_block()
133*635a8641SAndroid Build Coastguard Worker            if token.value == 'filter':
134*635a8641SAndroid Build Coastguard Worker                return self.parse_filter_block()
135*635a8641SAndroid Build Coastguard Worker            ext = self.extensions.get(token.value)
136*635a8641SAndroid Build Coastguard Worker            if ext is not None:
137*635a8641SAndroid Build Coastguard Worker                return ext(self)
138*635a8641SAndroid Build Coastguard Worker
139*635a8641SAndroid Build Coastguard Worker            # did not work out, remove the token we pushed by accident
140*635a8641SAndroid Build Coastguard Worker            # from the stack so that the unknown tag fail function can
141*635a8641SAndroid Build Coastguard Worker            # produce a proper error message.
142*635a8641SAndroid Build Coastguard Worker            self._tag_stack.pop()
143*635a8641SAndroid Build Coastguard Worker            pop_tag = False
144*635a8641SAndroid Build Coastguard Worker            self.fail_unknown_tag(token.value, token.lineno)
145*635a8641SAndroid Build Coastguard Worker        finally:
146*635a8641SAndroid Build Coastguard Worker            if pop_tag:
147*635a8641SAndroid Build Coastguard Worker                self._tag_stack.pop()
148*635a8641SAndroid Build Coastguard Worker
149*635a8641SAndroid Build Coastguard Worker    def parse_statements(self, end_tokens, drop_needle=False):
150*635a8641SAndroid Build Coastguard Worker        """Parse multiple statements into a list until one of the end tokens
151*635a8641SAndroid Build Coastguard Worker        is reached.  This is used to parse the body of statements as it also
152*635a8641SAndroid Build Coastguard Worker        parses template data if appropriate.  The parser checks first if the
153*635a8641SAndroid Build Coastguard Worker        current token is a colon and skips it if there is one.  Then it checks
154*635a8641SAndroid Build Coastguard Worker        for the block end and parses until if one of the `end_tokens` is
155*635a8641SAndroid Build Coastguard Worker        reached.  Per default the active token in the stream at the end of
156*635a8641SAndroid Build Coastguard Worker        the call is the matched end token.  If this is not wanted `drop_needle`
157*635a8641SAndroid Build Coastguard Worker        can be set to `True` and the end token is removed.
158*635a8641SAndroid Build Coastguard Worker        """
159*635a8641SAndroid Build Coastguard Worker        # the first token may be a colon for python compatibility
160*635a8641SAndroid Build Coastguard Worker        self.stream.skip_if('colon')
161*635a8641SAndroid Build Coastguard Worker
162*635a8641SAndroid Build Coastguard Worker        # in the future it would be possible to add whole code sections
163*635a8641SAndroid Build Coastguard Worker        # by adding some sort of end of statement token and parsing those here.
164*635a8641SAndroid Build Coastguard Worker        self.stream.expect('block_end')
165*635a8641SAndroid Build Coastguard Worker        result = self.subparse(end_tokens)
166*635a8641SAndroid Build Coastguard Worker
167*635a8641SAndroid Build Coastguard Worker        # we reached the end of the template too early, the subparser
168*635a8641SAndroid Build Coastguard Worker        # does not check for this, so we do that now
169*635a8641SAndroid Build Coastguard Worker        if self.stream.current.type == 'eof':
170*635a8641SAndroid Build Coastguard Worker            self.fail_eof(end_tokens)
171*635a8641SAndroid Build Coastguard Worker
172*635a8641SAndroid Build Coastguard Worker        if drop_needle:
173*635a8641SAndroid Build Coastguard Worker            next(self.stream)
174*635a8641SAndroid Build Coastguard Worker        return result
175*635a8641SAndroid Build Coastguard Worker
176*635a8641SAndroid Build Coastguard Worker    def parse_set(self):
177*635a8641SAndroid Build Coastguard Worker        """Parse an assign statement."""
178*635a8641SAndroid Build Coastguard Worker        lineno = next(self.stream).lineno
179*635a8641SAndroid Build Coastguard Worker        target = self.parse_assign_target(with_namespace=True)
180*635a8641SAndroid Build Coastguard Worker        if self.stream.skip_if('assign'):
181*635a8641SAndroid Build Coastguard Worker            expr = self.parse_tuple()
182*635a8641SAndroid Build Coastguard Worker            return nodes.Assign(target, expr, lineno=lineno)
183*635a8641SAndroid Build Coastguard Worker        filter_node = self.parse_filter(None)
184*635a8641SAndroid Build Coastguard Worker        body = self.parse_statements(('name:endset',),
185*635a8641SAndroid Build Coastguard Worker                                     drop_needle=True)
186*635a8641SAndroid Build Coastguard Worker        return nodes.AssignBlock(target, filter_node, body, lineno=lineno)
187*635a8641SAndroid Build Coastguard Worker
188*635a8641SAndroid Build Coastguard Worker    def parse_for(self):
189*635a8641SAndroid Build Coastguard Worker        """Parse a for loop."""
190*635a8641SAndroid Build Coastguard Worker        lineno = self.stream.expect('name:for').lineno
191*635a8641SAndroid Build Coastguard Worker        target = self.parse_assign_target(extra_end_rules=('name:in',))
192*635a8641SAndroid Build Coastguard Worker        self.stream.expect('name:in')
193*635a8641SAndroid Build Coastguard Worker        iter = self.parse_tuple(with_condexpr=False,
194*635a8641SAndroid Build Coastguard Worker                                extra_end_rules=('name:recursive',))
195*635a8641SAndroid Build Coastguard Worker        test = None
196*635a8641SAndroid Build Coastguard Worker        if self.stream.skip_if('name:if'):
197*635a8641SAndroid Build Coastguard Worker            test = self.parse_expression()
198*635a8641SAndroid Build Coastguard Worker        recursive = self.stream.skip_if('name:recursive')
199*635a8641SAndroid Build Coastguard Worker        body = self.parse_statements(('name:endfor', 'name:else'))
200*635a8641SAndroid Build Coastguard Worker        if next(self.stream).value == 'endfor':
201*635a8641SAndroid Build Coastguard Worker            else_ = []
202*635a8641SAndroid Build Coastguard Worker        else:
203*635a8641SAndroid Build Coastguard Worker            else_ = self.parse_statements(('name:endfor',), drop_needle=True)
204*635a8641SAndroid Build Coastguard Worker        return nodes.For(target, iter, body, else_, test,
205*635a8641SAndroid Build Coastguard Worker                         recursive, lineno=lineno)
206*635a8641SAndroid Build Coastguard Worker
207*635a8641SAndroid Build Coastguard Worker    def parse_if(self):
208*635a8641SAndroid Build Coastguard Worker        """Parse an if construct."""
209*635a8641SAndroid Build Coastguard Worker        node = result = nodes.If(lineno=self.stream.expect('name:if').lineno)
210*635a8641SAndroid Build Coastguard Worker        while 1:
211*635a8641SAndroid Build Coastguard Worker            node.test = self.parse_tuple(with_condexpr=False)
212*635a8641SAndroid Build Coastguard Worker            node.body = self.parse_statements(('name:elif', 'name:else',
213*635a8641SAndroid Build Coastguard Worker                                               'name:endif'))
214*635a8641SAndroid Build Coastguard Worker            node.elif_ = []
215*635a8641SAndroid Build Coastguard Worker            node.else_ = []
216*635a8641SAndroid Build Coastguard Worker            token = next(self.stream)
217*635a8641SAndroid Build Coastguard Worker            if token.test('name:elif'):
218*635a8641SAndroid Build Coastguard Worker                node = nodes.If(lineno=self.stream.current.lineno)
219*635a8641SAndroid Build Coastguard Worker                result.elif_.append(node)
220*635a8641SAndroid Build Coastguard Worker                continue
221*635a8641SAndroid Build Coastguard Worker            elif token.test('name:else'):
222*635a8641SAndroid Build Coastguard Worker                result.else_ = self.parse_statements(('name:endif',),
223*635a8641SAndroid Build Coastguard Worker                                                     drop_needle=True)
224*635a8641SAndroid Build Coastguard Worker            break
225*635a8641SAndroid Build Coastguard Worker        return result
226*635a8641SAndroid Build Coastguard Worker
227*635a8641SAndroid Build Coastguard Worker    def parse_with(self):
228*635a8641SAndroid Build Coastguard Worker        node = nodes.With(lineno=next(self.stream).lineno)
229*635a8641SAndroid Build Coastguard Worker        targets = []
230*635a8641SAndroid Build Coastguard Worker        values = []
231*635a8641SAndroid Build Coastguard Worker        while self.stream.current.type != 'block_end':
232*635a8641SAndroid Build Coastguard Worker            lineno = self.stream.current.lineno
233*635a8641SAndroid Build Coastguard Worker            if targets:
234*635a8641SAndroid Build Coastguard Worker                self.stream.expect('comma')
235*635a8641SAndroid Build Coastguard Worker            target = self.parse_assign_target()
236*635a8641SAndroid Build Coastguard Worker            target.set_ctx('param')
237*635a8641SAndroid Build Coastguard Worker            targets.append(target)
238*635a8641SAndroid Build Coastguard Worker            self.stream.expect('assign')
239*635a8641SAndroid Build Coastguard Worker            values.append(self.parse_expression())
240*635a8641SAndroid Build Coastguard Worker        node.targets = targets
241*635a8641SAndroid Build Coastguard Worker        node.values = values
242*635a8641SAndroid Build Coastguard Worker        node.body = self.parse_statements(('name:endwith',),
243*635a8641SAndroid Build Coastguard Worker                                          drop_needle=True)
244*635a8641SAndroid Build Coastguard Worker        return node
245*635a8641SAndroid Build Coastguard Worker
246*635a8641SAndroid Build Coastguard Worker    def parse_autoescape(self):
247*635a8641SAndroid Build Coastguard Worker        node = nodes.ScopedEvalContextModifier(lineno=next(self.stream).lineno)
248*635a8641SAndroid Build Coastguard Worker        node.options = [
249*635a8641SAndroid Build Coastguard Worker            nodes.Keyword('autoescape', self.parse_expression())
250*635a8641SAndroid Build Coastguard Worker        ]
251*635a8641SAndroid Build Coastguard Worker        node.body = self.parse_statements(('name:endautoescape',),
252*635a8641SAndroid Build Coastguard Worker                                            drop_needle=True)
253*635a8641SAndroid Build Coastguard Worker        return nodes.Scope([node])
254*635a8641SAndroid Build Coastguard Worker
255*635a8641SAndroid Build Coastguard Worker    def parse_block(self):
256*635a8641SAndroid Build Coastguard Worker        node = nodes.Block(lineno=next(self.stream).lineno)
257*635a8641SAndroid Build Coastguard Worker        node.name = self.stream.expect('name').value
258*635a8641SAndroid Build Coastguard Worker        node.scoped = self.stream.skip_if('name:scoped')
259*635a8641SAndroid Build Coastguard Worker
260*635a8641SAndroid Build Coastguard Worker        # common problem people encounter when switching from django
261*635a8641SAndroid Build Coastguard Worker        # to jinja.  we do not support hyphens in block names, so let's
262*635a8641SAndroid Build Coastguard Worker        # raise a nicer error message in that case.
263*635a8641SAndroid Build Coastguard Worker        if self.stream.current.type == 'sub':
264*635a8641SAndroid Build Coastguard Worker            self.fail('Block names in Jinja have to be valid Python '
265*635a8641SAndroid Build Coastguard Worker                      'identifiers and may not contain hyphens, use an '
266*635a8641SAndroid Build Coastguard Worker                      'underscore instead.')
267*635a8641SAndroid Build Coastguard Worker
268*635a8641SAndroid Build Coastguard Worker        node.body = self.parse_statements(('name:endblock',), drop_needle=True)
269*635a8641SAndroid Build Coastguard Worker        self.stream.skip_if('name:' + node.name)
270*635a8641SAndroid Build Coastguard Worker        return node
271*635a8641SAndroid Build Coastguard Worker
272*635a8641SAndroid Build Coastguard Worker    def parse_extends(self):
273*635a8641SAndroid Build Coastguard Worker        node = nodes.Extends(lineno=next(self.stream).lineno)
274*635a8641SAndroid Build Coastguard Worker        node.template = self.parse_expression()
275*635a8641SAndroid Build Coastguard Worker        return node
276*635a8641SAndroid Build Coastguard Worker
277*635a8641SAndroid Build Coastguard Worker    def parse_import_context(self, node, default):
278*635a8641SAndroid Build Coastguard Worker        if self.stream.current.test_any('name:with', 'name:without') and \
279*635a8641SAndroid Build Coastguard Worker           self.stream.look().test('name:context'):
280*635a8641SAndroid Build Coastguard Worker            node.with_context = next(self.stream).value == 'with'
281*635a8641SAndroid Build Coastguard Worker            self.stream.skip()
282*635a8641SAndroid Build Coastguard Worker        else:
283*635a8641SAndroid Build Coastguard Worker            node.with_context = default
284*635a8641SAndroid Build Coastguard Worker        return node
285*635a8641SAndroid Build Coastguard Worker
286*635a8641SAndroid Build Coastguard Worker    def parse_include(self):
287*635a8641SAndroid Build Coastguard Worker        node = nodes.Include(lineno=next(self.stream).lineno)
288*635a8641SAndroid Build Coastguard Worker        node.template = self.parse_expression()
289*635a8641SAndroid Build Coastguard Worker        if self.stream.current.test('name:ignore') and \
290*635a8641SAndroid Build Coastguard Worker           self.stream.look().test('name:missing'):
291*635a8641SAndroid Build Coastguard Worker            node.ignore_missing = True
292*635a8641SAndroid Build Coastguard Worker            self.stream.skip(2)
293*635a8641SAndroid Build Coastguard Worker        else:
294*635a8641SAndroid Build Coastguard Worker            node.ignore_missing = False
295*635a8641SAndroid Build Coastguard Worker        return self.parse_import_context(node, True)
296*635a8641SAndroid Build Coastguard Worker
297*635a8641SAndroid Build Coastguard Worker    def parse_import(self):
298*635a8641SAndroid Build Coastguard Worker        node = nodes.Import(lineno=next(self.stream).lineno)
299*635a8641SAndroid Build Coastguard Worker        node.template = self.parse_expression()
300*635a8641SAndroid Build Coastguard Worker        self.stream.expect('name:as')
301*635a8641SAndroid Build Coastguard Worker        node.target = self.parse_assign_target(name_only=True).name
302*635a8641SAndroid Build Coastguard Worker        return self.parse_import_context(node, False)
303*635a8641SAndroid Build Coastguard Worker
304*635a8641SAndroid Build Coastguard Worker    def parse_from(self):
305*635a8641SAndroid Build Coastguard Worker        node = nodes.FromImport(lineno=next(self.stream).lineno)
306*635a8641SAndroid Build Coastguard Worker        node.template = self.parse_expression()
307*635a8641SAndroid Build Coastguard Worker        self.stream.expect('name:import')
308*635a8641SAndroid Build Coastguard Worker        node.names = []
309*635a8641SAndroid Build Coastguard Worker
310*635a8641SAndroid Build Coastguard Worker        def parse_context():
311*635a8641SAndroid Build Coastguard Worker            if self.stream.current.value in ('with', 'without') and \
312*635a8641SAndroid Build Coastguard Worker               self.stream.look().test('name:context'):
313*635a8641SAndroid Build Coastguard Worker                node.with_context = next(self.stream).value == 'with'
314*635a8641SAndroid Build Coastguard Worker                self.stream.skip()
315*635a8641SAndroid Build Coastguard Worker                return True
316*635a8641SAndroid Build Coastguard Worker            return False
317*635a8641SAndroid Build Coastguard Worker
318*635a8641SAndroid Build Coastguard Worker        while 1:
319*635a8641SAndroid Build Coastguard Worker            if node.names:
320*635a8641SAndroid Build Coastguard Worker                self.stream.expect('comma')
321*635a8641SAndroid Build Coastguard Worker            if self.stream.current.type == 'name':
322*635a8641SAndroid Build Coastguard Worker                if parse_context():
323*635a8641SAndroid Build Coastguard Worker                    break
324*635a8641SAndroid Build Coastguard Worker                target = self.parse_assign_target(name_only=True)
325*635a8641SAndroid Build Coastguard Worker                if target.name.startswith('_'):
326*635a8641SAndroid Build Coastguard Worker                    self.fail('names starting with an underline can not '
327*635a8641SAndroid Build Coastguard Worker                              'be imported', target.lineno,
328*635a8641SAndroid Build Coastguard Worker                              exc=TemplateAssertionError)
329*635a8641SAndroid Build Coastguard Worker                if self.stream.skip_if('name:as'):
330*635a8641SAndroid Build Coastguard Worker                    alias = self.parse_assign_target(name_only=True)
331*635a8641SAndroid Build Coastguard Worker                    node.names.append((target.name, alias.name))
332*635a8641SAndroid Build Coastguard Worker                else:
333*635a8641SAndroid Build Coastguard Worker                    node.names.append(target.name)
334*635a8641SAndroid Build Coastguard Worker                if parse_context() or self.stream.current.type != 'comma':
335*635a8641SAndroid Build Coastguard Worker                    break
336*635a8641SAndroid Build Coastguard Worker            else:
337*635a8641SAndroid Build Coastguard Worker                self.stream.expect('name')
338*635a8641SAndroid Build Coastguard Worker        if not hasattr(node, 'with_context'):
339*635a8641SAndroid Build Coastguard Worker            node.with_context = False
340*635a8641SAndroid Build Coastguard Worker        return node
341*635a8641SAndroid Build Coastguard Worker
342*635a8641SAndroid Build Coastguard Worker    def parse_signature(self, node):
343*635a8641SAndroid Build Coastguard Worker        node.args = args = []
344*635a8641SAndroid Build Coastguard Worker        node.defaults = defaults = []
345*635a8641SAndroid Build Coastguard Worker        self.stream.expect('lparen')
346*635a8641SAndroid Build Coastguard Worker        while self.stream.current.type != 'rparen':
347*635a8641SAndroid Build Coastguard Worker            if args:
348*635a8641SAndroid Build Coastguard Worker                self.stream.expect('comma')
349*635a8641SAndroid Build Coastguard Worker            arg = self.parse_assign_target(name_only=True)
350*635a8641SAndroid Build Coastguard Worker            arg.set_ctx('param')
351*635a8641SAndroid Build Coastguard Worker            if self.stream.skip_if('assign'):
352*635a8641SAndroid Build Coastguard Worker                defaults.append(self.parse_expression())
353*635a8641SAndroid Build Coastguard Worker            elif defaults:
354*635a8641SAndroid Build Coastguard Worker                self.fail('non-default argument follows default argument')
355*635a8641SAndroid Build Coastguard Worker            args.append(arg)
356*635a8641SAndroid Build Coastguard Worker        self.stream.expect('rparen')
357*635a8641SAndroid Build Coastguard Worker
358*635a8641SAndroid Build Coastguard Worker    def parse_call_block(self):
359*635a8641SAndroid Build Coastguard Worker        node = nodes.CallBlock(lineno=next(self.stream).lineno)
360*635a8641SAndroid Build Coastguard Worker        if self.stream.current.type == 'lparen':
361*635a8641SAndroid Build Coastguard Worker            self.parse_signature(node)
362*635a8641SAndroid Build Coastguard Worker        else:
363*635a8641SAndroid Build Coastguard Worker            node.args = []
364*635a8641SAndroid Build Coastguard Worker            node.defaults = []
365*635a8641SAndroid Build Coastguard Worker
366*635a8641SAndroid Build Coastguard Worker        node.call = self.parse_expression()
367*635a8641SAndroid Build Coastguard Worker        if not isinstance(node.call, nodes.Call):
368*635a8641SAndroid Build Coastguard Worker            self.fail('expected call', node.lineno)
369*635a8641SAndroid Build Coastguard Worker        node.body = self.parse_statements(('name:endcall',), drop_needle=True)
370*635a8641SAndroid Build Coastguard Worker        return node
371*635a8641SAndroid Build Coastguard Worker
372*635a8641SAndroid Build Coastguard Worker    def parse_filter_block(self):
373*635a8641SAndroid Build Coastguard Worker        node = nodes.FilterBlock(lineno=next(self.stream).lineno)
374*635a8641SAndroid Build Coastguard Worker        node.filter = self.parse_filter(None, start_inline=True)
375*635a8641SAndroid Build Coastguard Worker        node.body = self.parse_statements(('name:endfilter',),
376*635a8641SAndroid Build Coastguard Worker                                          drop_needle=True)
377*635a8641SAndroid Build Coastguard Worker        return node
378*635a8641SAndroid Build Coastguard Worker
379*635a8641SAndroid Build Coastguard Worker    def parse_macro(self):
380*635a8641SAndroid Build Coastguard Worker        node = nodes.Macro(lineno=next(self.stream).lineno)
381*635a8641SAndroid Build Coastguard Worker        node.name = self.parse_assign_target(name_only=True).name
382*635a8641SAndroid Build Coastguard Worker        self.parse_signature(node)
383*635a8641SAndroid Build Coastguard Worker        node.body = self.parse_statements(('name:endmacro',),
384*635a8641SAndroid Build Coastguard Worker                                          drop_needle=True)
385*635a8641SAndroid Build Coastguard Worker        return node
386*635a8641SAndroid Build Coastguard Worker
387*635a8641SAndroid Build Coastguard Worker    def parse_print(self):
388*635a8641SAndroid Build Coastguard Worker        node = nodes.Output(lineno=next(self.stream).lineno)
389*635a8641SAndroid Build Coastguard Worker        node.nodes = []
390*635a8641SAndroid Build Coastguard Worker        while self.stream.current.type != 'block_end':
391*635a8641SAndroid Build Coastguard Worker            if node.nodes:
392*635a8641SAndroid Build Coastguard Worker                self.stream.expect('comma')
393*635a8641SAndroid Build Coastguard Worker            node.nodes.append(self.parse_expression())
394*635a8641SAndroid Build Coastguard Worker        return node
395*635a8641SAndroid Build Coastguard Worker
396*635a8641SAndroid Build Coastguard Worker    def parse_assign_target(self, with_tuple=True, name_only=False,
397*635a8641SAndroid Build Coastguard Worker                            extra_end_rules=None, with_namespace=False):
398*635a8641SAndroid Build Coastguard Worker        """Parse an assignment target.  As Jinja2 allows assignments to
399*635a8641SAndroid Build Coastguard Worker        tuples, this function can parse all allowed assignment targets.  Per
400*635a8641SAndroid Build Coastguard Worker        default assignments to tuples are parsed, that can be disable however
401*635a8641SAndroid Build Coastguard Worker        by setting `with_tuple` to `False`.  If only assignments to names are
402*635a8641SAndroid Build Coastguard Worker        wanted `name_only` can be set to `True`.  The `extra_end_rules`
403*635a8641SAndroid Build Coastguard Worker        parameter is forwarded to the tuple parsing function.  If
404*635a8641SAndroid Build Coastguard Worker        `with_namespace` is enabled, a namespace assignment may be parsed.
405*635a8641SAndroid Build Coastguard Worker        """
406*635a8641SAndroid Build Coastguard Worker        if with_namespace and self.stream.look().type == 'dot':
407*635a8641SAndroid Build Coastguard Worker            token = self.stream.expect('name')
408*635a8641SAndroid Build Coastguard Worker            next(self.stream)  # dot
409*635a8641SAndroid Build Coastguard Worker            attr = self.stream.expect('name')
410*635a8641SAndroid Build Coastguard Worker            target = nodes.NSRef(token.value, attr.value, lineno=token.lineno)
411*635a8641SAndroid Build Coastguard Worker        elif name_only:
412*635a8641SAndroid Build Coastguard Worker            token = self.stream.expect('name')
413*635a8641SAndroid Build Coastguard Worker            target = nodes.Name(token.value, 'store', lineno=token.lineno)
414*635a8641SAndroid Build Coastguard Worker        else:
415*635a8641SAndroid Build Coastguard Worker            if with_tuple:
416*635a8641SAndroid Build Coastguard Worker                target = self.parse_tuple(simplified=True,
417*635a8641SAndroid Build Coastguard Worker                                          extra_end_rules=extra_end_rules)
418*635a8641SAndroid Build Coastguard Worker            else:
419*635a8641SAndroid Build Coastguard Worker                target = self.parse_primary()
420*635a8641SAndroid Build Coastguard Worker            target.set_ctx('store')
421*635a8641SAndroid Build Coastguard Worker        if not target.can_assign():
422*635a8641SAndroid Build Coastguard Worker            self.fail('can\'t assign to %r' % target.__class__.
423*635a8641SAndroid Build Coastguard Worker                      __name__.lower(), target.lineno)
424*635a8641SAndroid Build Coastguard Worker        return target
425*635a8641SAndroid Build Coastguard Worker
426*635a8641SAndroid Build Coastguard Worker    def parse_expression(self, with_condexpr=True):
427*635a8641SAndroid Build Coastguard Worker        """Parse an expression.  Per default all expressions are parsed, if
428*635a8641SAndroid Build Coastguard Worker        the optional `with_condexpr` parameter is set to `False` conditional
429*635a8641SAndroid Build Coastguard Worker        expressions are not parsed.
430*635a8641SAndroid Build Coastguard Worker        """
431*635a8641SAndroid Build Coastguard Worker        if with_condexpr:
432*635a8641SAndroid Build Coastguard Worker            return self.parse_condexpr()
433*635a8641SAndroid Build Coastguard Worker        return self.parse_or()
434*635a8641SAndroid Build Coastguard Worker
435*635a8641SAndroid Build Coastguard Worker    def parse_condexpr(self):
436*635a8641SAndroid Build Coastguard Worker        lineno = self.stream.current.lineno
437*635a8641SAndroid Build Coastguard Worker        expr1 = self.parse_or()
438*635a8641SAndroid Build Coastguard Worker        while self.stream.skip_if('name:if'):
439*635a8641SAndroid Build Coastguard Worker            expr2 = self.parse_or()
440*635a8641SAndroid Build Coastguard Worker            if self.stream.skip_if('name:else'):
441*635a8641SAndroid Build Coastguard Worker                expr3 = self.parse_condexpr()
442*635a8641SAndroid Build Coastguard Worker            else:
443*635a8641SAndroid Build Coastguard Worker                expr3 = None
444*635a8641SAndroid Build Coastguard Worker            expr1 = nodes.CondExpr(expr2, expr1, expr3, lineno=lineno)
445*635a8641SAndroid Build Coastguard Worker            lineno = self.stream.current.lineno
446*635a8641SAndroid Build Coastguard Worker        return expr1
447*635a8641SAndroid Build Coastguard Worker
448*635a8641SAndroid Build Coastguard Worker    def parse_or(self):
449*635a8641SAndroid Build Coastguard Worker        lineno = self.stream.current.lineno
450*635a8641SAndroid Build Coastguard Worker        left = self.parse_and()
451*635a8641SAndroid Build Coastguard Worker        while self.stream.skip_if('name:or'):
452*635a8641SAndroid Build Coastguard Worker            right = self.parse_and()
453*635a8641SAndroid Build Coastguard Worker            left = nodes.Or(left, right, lineno=lineno)
454*635a8641SAndroid Build Coastguard Worker            lineno = self.stream.current.lineno
455*635a8641SAndroid Build Coastguard Worker        return left
456*635a8641SAndroid Build Coastguard Worker
457*635a8641SAndroid Build Coastguard Worker    def parse_and(self):
458*635a8641SAndroid Build Coastguard Worker        lineno = self.stream.current.lineno
459*635a8641SAndroid Build Coastguard Worker        left = self.parse_not()
460*635a8641SAndroid Build Coastguard Worker        while self.stream.skip_if('name:and'):
461*635a8641SAndroid Build Coastguard Worker            right = self.parse_not()
462*635a8641SAndroid Build Coastguard Worker            left = nodes.And(left, right, lineno=lineno)
463*635a8641SAndroid Build Coastguard Worker            lineno = self.stream.current.lineno
464*635a8641SAndroid Build Coastguard Worker        return left
465*635a8641SAndroid Build Coastguard Worker
466*635a8641SAndroid Build Coastguard Worker    def parse_not(self):
467*635a8641SAndroid Build Coastguard Worker        if self.stream.current.test('name:not'):
468*635a8641SAndroid Build Coastguard Worker            lineno = next(self.stream).lineno
469*635a8641SAndroid Build Coastguard Worker            return nodes.Not(self.parse_not(), lineno=lineno)
470*635a8641SAndroid Build Coastguard Worker        return self.parse_compare()
471*635a8641SAndroid Build Coastguard Worker
472*635a8641SAndroid Build Coastguard Worker    def parse_compare(self):
473*635a8641SAndroid Build Coastguard Worker        lineno = self.stream.current.lineno
474*635a8641SAndroid Build Coastguard Worker        expr = self.parse_math1()
475*635a8641SAndroid Build Coastguard Worker        ops = []
476*635a8641SAndroid Build Coastguard Worker        while 1:
477*635a8641SAndroid Build Coastguard Worker            token_type = self.stream.current.type
478*635a8641SAndroid Build Coastguard Worker            if token_type in _compare_operators:
479*635a8641SAndroid Build Coastguard Worker                next(self.stream)
480*635a8641SAndroid Build Coastguard Worker                ops.append(nodes.Operand(token_type, self.parse_math1()))
481*635a8641SAndroid Build Coastguard Worker            elif self.stream.skip_if('name:in'):
482*635a8641SAndroid Build Coastguard Worker                ops.append(nodes.Operand('in', self.parse_math1()))
483*635a8641SAndroid Build Coastguard Worker            elif (self.stream.current.test('name:not') and
484*635a8641SAndroid Build Coastguard Worker                  self.stream.look().test('name:in')):
485*635a8641SAndroid Build Coastguard Worker                self.stream.skip(2)
486*635a8641SAndroid Build Coastguard Worker                ops.append(nodes.Operand('notin', self.parse_math1()))
487*635a8641SAndroid Build Coastguard Worker            else:
488*635a8641SAndroid Build Coastguard Worker                break
489*635a8641SAndroid Build Coastguard Worker            lineno = self.stream.current.lineno
490*635a8641SAndroid Build Coastguard Worker        if not ops:
491*635a8641SAndroid Build Coastguard Worker            return expr
492*635a8641SAndroid Build Coastguard Worker        return nodes.Compare(expr, ops, lineno=lineno)
493*635a8641SAndroid Build Coastguard Worker
494*635a8641SAndroid Build Coastguard Worker    def parse_math1(self):
495*635a8641SAndroid Build Coastguard Worker        lineno = self.stream.current.lineno
496*635a8641SAndroid Build Coastguard Worker        left = self.parse_concat()
497*635a8641SAndroid Build Coastguard Worker        while self.stream.current.type in ('add', 'sub'):
498*635a8641SAndroid Build Coastguard Worker            cls = _math_nodes[self.stream.current.type]
499*635a8641SAndroid Build Coastguard Worker            next(self.stream)
500*635a8641SAndroid Build Coastguard Worker            right = self.parse_concat()
501*635a8641SAndroid Build Coastguard Worker            left = cls(left, right, lineno=lineno)
502*635a8641SAndroid Build Coastguard Worker            lineno = self.stream.current.lineno
503*635a8641SAndroid Build Coastguard Worker        return left
504*635a8641SAndroid Build Coastguard Worker
505*635a8641SAndroid Build Coastguard Worker    def parse_concat(self):
506*635a8641SAndroid Build Coastguard Worker        lineno = self.stream.current.lineno
507*635a8641SAndroid Build Coastguard Worker        args = [self.parse_math2()]
508*635a8641SAndroid Build Coastguard Worker        while self.stream.current.type == 'tilde':
509*635a8641SAndroid Build Coastguard Worker            next(self.stream)
510*635a8641SAndroid Build Coastguard Worker            args.append(self.parse_math2())
511*635a8641SAndroid Build Coastguard Worker        if len(args) == 1:
512*635a8641SAndroid Build Coastguard Worker            return args[0]
513*635a8641SAndroid Build Coastguard Worker        return nodes.Concat(args, lineno=lineno)
514*635a8641SAndroid Build Coastguard Worker
515*635a8641SAndroid Build Coastguard Worker    def parse_math2(self):
516*635a8641SAndroid Build Coastguard Worker        lineno = self.stream.current.lineno
517*635a8641SAndroid Build Coastguard Worker        left = self.parse_pow()
518*635a8641SAndroid Build Coastguard Worker        while self.stream.current.type in ('mul', 'div', 'floordiv', 'mod'):
519*635a8641SAndroid Build Coastguard Worker            cls = _math_nodes[self.stream.current.type]
520*635a8641SAndroid Build Coastguard Worker            next(self.stream)
521*635a8641SAndroid Build Coastguard Worker            right = self.parse_pow()
522*635a8641SAndroid Build Coastguard Worker            left = cls(left, right, lineno=lineno)
523*635a8641SAndroid Build Coastguard Worker            lineno = self.stream.current.lineno
524*635a8641SAndroid Build Coastguard Worker        return left
525*635a8641SAndroid Build Coastguard Worker
526*635a8641SAndroid Build Coastguard Worker    def parse_pow(self):
527*635a8641SAndroid Build Coastguard Worker        lineno = self.stream.current.lineno
528*635a8641SAndroid Build Coastguard Worker        left = self.parse_unary()
529*635a8641SAndroid Build Coastguard Worker        while self.stream.current.type == 'pow':
530*635a8641SAndroid Build Coastguard Worker            next(self.stream)
531*635a8641SAndroid Build Coastguard Worker            right = self.parse_unary()
532*635a8641SAndroid Build Coastguard Worker            left = nodes.Pow(left, right, lineno=lineno)
533*635a8641SAndroid Build Coastguard Worker            lineno = self.stream.current.lineno
534*635a8641SAndroid Build Coastguard Worker        return left
535*635a8641SAndroid Build Coastguard Worker
536*635a8641SAndroid Build Coastguard Worker    def parse_unary(self, with_filter=True):
537*635a8641SAndroid Build Coastguard Worker        token_type = self.stream.current.type
538*635a8641SAndroid Build Coastguard Worker        lineno = self.stream.current.lineno
539*635a8641SAndroid Build Coastguard Worker        if token_type == 'sub':
540*635a8641SAndroid Build Coastguard Worker            next(self.stream)
541*635a8641SAndroid Build Coastguard Worker            node = nodes.Neg(self.parse_unary(False), lineno=lineno)
542*635a8641SAndroid Build Coastguard Worker        elif token_type == 'add':
543*635a8641SAndroid Build Coastguard Worker            next(self.stream)
544*635a8641SAndroid Build Coastguard Worker            node = nodes.Pos(self.parse_unary(False), lineno=lineno)
545*635a8641SAndroid Build Coastguard Worker        else:
546*635a8641SAndroid Build Coastguard Worker            node = self.parse_primary()
547*635a8641SAndroid Build Coastguard Worker        node = self.parse_postfix(node)
548*635a8641SAndroid Build Coastguard Worker        if with_filter:
549*635a8641SAndroid Build Coastguard Worker            node = self.parse_filter_expr(node)
550*635a8641SAndroid Build Coastguard Worker        return node
551*635a8641SAndroid Build Coastguard Worker
552*635a8641SAndroid Build Coastguard Worker    def parse_primary(self):
553*635a8641SAndroid Build Coastguard Worker        token = self.stream.current
554*635a8641SAndroid Build Coastguard Worker        if token.type == 'name':
555*635a8641SAndroid Build Coastguard Worker            if token.value in ('true', 'false', 'True', 'False'):
556*635a8641SAndroid Build Coastguard Worker                node = nodes.Const(token.value in ('true', 'True'),
557*635a8641SAndroid Build Coastguard Worker                                   lineno=token.lineno)
558*635a8641SAndroid Build Coastguard Worker            elif token.value in ('none', 'None'):
559*635a8641SAndroid Build Coastguard Worker                node = nodes.Const(None, lineno=token.lineno)
560*635a8641SAndroid Build Coastguard Worker            else:
561*635a8641SAndroid Build Coastguard Worker                node = nodes.Name(token.value, 'load', lineno=token.lineno)
562*635a8641SAndroid Build Coastguard Worker            next(self.stream)
563*635a8641SAndroid Build Coastguard Worker        elif token.type == 'string':
564*635a8641SAndroid Build Coastguard Worker            next(self.stream)
565*635a8641SAndroid Build Coastguard Worker            buf = [token.value]
566*635a8641SAndroid Build Coastguard Worker            lineno = token.lineno
567*635a8641SAndroid Build Coastguard Worker            while self.stream.current.type == 'string':
568*635a8641SAndroid Build Coastguard Worker                buf.append(self.stream.current.value)
569*635a8641SAndroid Build Coastguard Worker                next(self.stream)
570*635a8641SAndroid Build Coastguard Worker            node = nodes.Const(''.join(buf), lineno=lineno)
571*635a8641SAndroid Build Coastguard Worker        elif token.type in ('integer', 'float'):
572*635a8641SAndroid Build Coastguard Worker            next(self.stream)
573*635a8641SAndroid Build Coastguard Worker            node = nodes.Const(token.value, lineno=token.lineno)
574*635a8641SAndroid Build Coastguard Worker        elif token.type == 'lparen':
575*635a8641SAndroid Build Coastguard Worker            next(self.stream)
576*635a8641SAndroid Build Coastguard Worker            node = self.parse_tuple(explicit_parentheses=True)
577*635a8641SAndroid Build Coastguard Worker            self.stream.expect('rparen')
578*635a8641SAndroid Build Coastguard Worker        elif token.type == 'lbracket':
579*635a8641SAndroid Build Coastguard Worker            node = self.parse_list()
580*635a8641SAndroid Build Coastguard Worker        elif token.type == 'lbrace':
581*635a8641SAndroid Build Coastguard Worker            node = self.parse_dict()
582*635a8641SAndroid Build Coastguard Worker        else:
583*635a8641SAndroid Build Coastguard Worker            self.fail("unexpected '%s'" % describe_token(token), token.lineno)
584*635a8641SAndroid Build Coastguard Worker        return node
585*635a8641SAndroid Build Coastguard Worker
586*635a8641SAndroid Build Coastguard Worker    def parse_tuple(self, simplified=False, with_condexpr=True,
587*635a8641SAndroid Build Coastguard Worker                    extra_end_rules=None, explicit_parentheses=False):
588*635a8641SAndroid Build Coastguard Worker        """Works like `parse_expression` but if multiple expressions are
589*635a8641SAndroid Build Coastguard Worker        delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created.
590*635a8641SAndroid Build Coastguard Worker        This method could also return a regular expression instead of a tuple
591*635a8641SAndroid Build Coastguard Worker        if no commas where found.
592*635a8641SAndroid Build Coastguard Worker
593*635a8641SAndroid Build Coastguard Worker        The default parsing mode is a full tuple.  If `simplified` is `True`
594*635a8641SAndroid Build Coastguard Worker        only names and literals are parsed.  The `no_condexpr` parameter is
595*635a8641SAndroid Build Coastguard Worker        forwarded to :meth:`parse_expression`.
596*635a8641SAndroid Build Coastguard Worker
597*635a8641SAndroid Build Coastguard Worker        Because tuples do not require delimiters and may end in a bogus comma
598*635a8641SAndroid Build Coastguard Worker        an extra hint is needed that marks the end of a tuple.  For example
599*635a8641SAndroid Build Coastguard Worker        for loops support tuples between `for` and `in`.  In that case the
600*635a8641SAndroid Build Coastguard Worker        `extra_end_rules` is set to ``['name:in']``.
601*635a8641SAndroid Build Coastguard Worker
602*635a8641SAndroid Build Coastguard Worker        `explicit_parentheses` is true if the parsing was triggered by an
603*635a8641SAndroid Build Coastguard Worker        expression in parentheses.  This is used to figure out if an empty
604*635a8641SAndroid Build Coastguard Worker        tuple is a valid expression or not.
605*635a8641SAndroid Build Coastguard Worker        """
606*635a8641SAndroid Build Coastguard Worker        lineno = self.stream.current.lineno
607*635a8641SAndroid Build Coastguard Worker        if simplified:
608*635a8641SAndroid Build Coastguard Worker            parse = self.parse_primary
609*635a8641SAndroid Build Coastguard Worker        elif with_condexpr:
610*635a8641SAndroid Build Coastguard Worker            parse = self.parse_expression
611*635a8641SAndroid Build Coastguard Worker        else:
612*635a8641SAndroid Build Coastguard Worker            parse = lambda: self.parse_expression(with_condexpr=False)
613*635a8641SAndroid Build Coastguard Worker        args = []
614*635a8641SAndroid Build Coastguard Worker        is_tuple = False
615*635a8641SAndroid Build Coastguard Worker        while 1:
616*635a8641SAndroid Build Coastguard Worker            if args:
617*635a8641SAndroid Build Coastguard Worker                self.stream.expect('comma')
618*635a8641SAndroid Build Coastguard Worker            if self.is_tuple_end(extra_end_rules):
619*635a8641SAndroid Build Coastguard Worker                break
620*635a8641SAndroid Build Coastguard Worker            args.append(parse())
621*635a8641SAndroid Build Coastguard Worker            if self.stream.current.type == 'comma':
622*635a8641SAndroid Build Coastguard Worker                is_tuple = True
623*635a8641SAndroid Build Coastguard Worker            else:
624*635a8641SAndroid Build Coastguard Worker                break
625*635a8641SAndroid Build Coastguard Worker            lineno = self.stream.current.lineno
626*635a8641SAndroid Build Coastguard Worker
627*635a8641SAndroid Build Coastguard Worker        if not is_tuple:
628*635a8641SAndroid Build Coastguard Worker            if args:
629*635a8641SAndroid Build Coastguard Worker                return args[0]
630*635a8641SAndroid Build Coastguard Worker
631*635a8641SAndroid Build Coastguard Worker            # if we don't have explicit parentheses, an empty tuple is
632*635a8641SAndroid Build Coastguard Worker            # not a valid expression.  This would mean nothing (literally
633*635a8641SAndroid Build Coastguard Worker            # nothing) in the spot of an expression would be an empty
634*635a8641SAndroid Build Coastguard Worker            # tuple.
635*635a8641SAndroid Build Coastguard Worker            if not explicit_parentheses:
636*635a8641SAndroid Build Coastguard Worker                self.fail('Expected an expression, got \'%s\'' %
637*635a8641SAndroid Build Coastguard Worker                          describe_token(self.stream.current))
638*635a8641SAndroid Build Coastguard Worker
639*635a8641SAndroid Build Coastguard Worker        return nodes.Tuple(args, 'load', lineno=lineno)
640*635a8641SAndroid Build Coastguard Worker
641*635a8641SAndroid Build Coastguard Worker    def parse_list(self):
642*635a8641SAndroid Build Coastguard Worker        token = self.stream.expect('lbracket')
643*635a8641SAndroid Build Coastguard Worker        items = []
644*635a8641SAndroid Build Coastguard Worker        while self.stream.current.type != 'rbracket':
645*635a8641SAndroid Build Coastguard Worker            if items:
646*635a8641SAndroid Build Coastguard Worker                self.stream.expect('comma')
647*635a8641SAndroid Build Coastguard Worker            if self.stream.current.type == 'rbracket':
648*635a8641SAndroid Build Coastguard Worker                break
649*635a8641SAndroid Build Coastguard Worker            items.append(self.parse_expression())
650*635a8641SAndroid Build Coastguard Worker        self.stream.expect('rbracket')
651*635a8641SAndroid Build Coastguard Worker        return nodes.List(items, lineno=token.lineno)
652*635a8641SAndroid Build Coastguard Worker
653*635a8641SAndroid Build Coastguard Worker    def parse_dict(self):
654*635a8641SAndroid Build Coastguard Worker        token = self.stream.expect('lbrace')
655*635a8641SAndroid Build Coastguard Worker        items = []
656*635a8641SAndroid Build Coastguard Worker        while self.stream.current.type != 'rbrace':
657*635a8641SAndroid Build Coastguard Worker            if items:
658*635a8641SAndroid Build Coastguard Worker                self.stream.expect('comma')
659*635a8641SAndroid Build Coastguard Worker            if self.stream.current.type == 'rbrace':
660*635a8641SAndroid Build Coastguard Worker                break
661*635a8641SAndroid Build Coastguard Worker            key = self.parse_expression()
662*635a8641SAndroid Build Coastguard Worker            self.stream.expect('colon')
663*635a8641SAndroid Build Coastguard Worker            value = self.parse_expression()
664*635a8641SAndroid Build Coastguard Worker            items.append(nodes.Pair(key, value, lineno=key.lineno))
665*635a8641SAndroid Build Coastguard Worker        self.stream.expect('rbrace')
666*635a8641SAndroid Build Coastguard Worker        return nodes.Dict(items, lineno=token.lineno)
667*635a8641SAndroid Build Coastguard Worker
668*635a8641SAndroid Build Coastguard Worker    def parse_postfix(self, node):
669*635a8641SAndroid Build Coastguard Worker        while 1:
670*635a8641SAndroid Build Coastguard Worker            token_type = self.stream.current.type
671*635a8641SAndroid Build Coastguard Worker            if token_type == 'dot' or token_type == 'lbracket':
672*635a8641SAndroid Build Coastguard Worker                node = self.parse_subscript(node)
673*635a8641SAndroid Build Coastguard Worker            # calls are valid both after postfix expressions (getattr
674*635a8641SAndroid Build Coastguard Worker            # and getitem) as well as filters and tests
675*635a8641SAndroid Build Coastguard Worker            elif token_type == 'lparen':
676*635a8641SAndroid Build Coastguard Worker                node = self.parse_call(node)
677*635a8641SAndroid Build Coastguard Worker            else:
678*635a8641SAndroid Build Coastguard Worker                break
679*635a8641SAndroid Build Coastguard Worker        return node
680*635a8641SAndroid Build Coastguard Worker
681*635a8641SAndroid Build Coastguard Worker    def parse_filter_expr(self, node):
682*635a8641SAndroid Build Coastguard Worker        while 1:
683*635a8641SAndroid Build Coastguard Worker            token_type = self.stream.current.type
684*635a8641SAndroid Build Coastguard Worker            if token_type == 'pipe':
685*635a8641SAndroid Build Coastguard Worker                node = self.parse_filter(node)
686*635a8641SAndroid Build Coastguard Worker            elif token_type == 'name' and self.stream.current.value == 'is':
687*635a8641SAndroid Build Coastguard Worker                node = self.parse_test(node)
688*635a8641SAndroid Build Coastguard Worker            # calls are valid both after postfix expressions (getattr
689*635a8641SAndroid Build Coastguard Worker            # and getitem) as well as filters and tests
690*635a8641SAndroid Build Coastguard Worker            elif token_type == 'lparen':
691*635a8641SAndroid Build Coastguard Worker                node = self.parse_call(node)
692*635a8641SAndroid Build Coastguard Worker            else:
693*635a8641SAndroid Build Coastguard Worker                break
694*635a8641SAndroid Build Coastguard Worker        return node
695*635a8641SAndroid Build Coastguard Worker
696*635a8641SAndroid Build Coastguard Worker    def parse_subscript(self, node):
697*635a8641SAndroid Build Coastguard Worker        token = next(self.stream)
698*635a8641SAndroid Build Coastguard Worker        if token.type == 'dot':
699*635a8641SAndroid Build Coastguard Worker            attr_token = self.stream.current
700*635a8641SAndroid Build Coastguard Worker            next(self.stream)
701*635a8641SAndroid Build Coastguard Worker            if attr_token.type == 'name':
702*635a8641SAndroid Build Coastguard Worker                return nodes.Getattr(node, attr_token.value, 'load',
703*635a8641SAndroid Build Coastguard Worker                                     lineno=token.lineno)
704*635a8641SAndroid Build Coastguard Worker            elif attr_token.type != 'integer':
705*635a8641SAndroid Build Coastguard Worker                self.fail('expected name or number', attr_token.lineno)
706*635a8641SAndroid Build Coastguard Worker            arg = nodes.Const(attr_token.value, lineno=attr_token.lineno)
707*635a8641SAndroid Build Coastguard Worker            return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
708*635a8641SAndroid Build Coastguard Worker        if token.type == 'lbracket':
709*635a8641SAndroid Build Coastguard Worker            args = []
710*635a8641SAndroid Build Coastguard Worker            while self.stream.current.type != 'rbracket':
711*635a8641SAndroid Build Coastguard Worker                if args:
712*635a8641SAndroid Build Coastguard Worker                    self.stream.expect('comma')
713*635a8641SAndroid Build Coastguard Worker                args.append(self.parse_subscribed())
714*635a8641SAndroid Build Coastguard Worker            self.stream.expect('rbracket')
715*635a8641SAndroid Build Coastguard Worker            if len(args) == 1:
716*635a8641SAndroid Build Coastguard Worker                arg = args[0]
717*635a8641SAndroid Build Coastguard Worker            else:
718*635a8641SAndroid Build Coastguard Worker                arg = nodes.Tuple(args, 'load', lineno=token.lineno)
719*635a8641SAndroid Build Coastguard Worker            return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
720*635a8641SAndroid Build Coastguard Worker        self.fail('expected subscript expression', self.lineno)
721*635a8641SAndroid Build Coastguard Worker
722*635a8641SAndroid Build Coastguard Worker    def parse_subscribed(self):
723*635a8641SAndroid Build Coastguard Worker        lineno = self.stream.current.lineno
724*635a8641SAndroid Build Coastguard Worker
725*635a8641SAndroid Build Coastguard Worker        if self.stream.current.type == 'colon':
726*635a8641SAndroid Build Coastguard Worker            next(self.stream)
727*635a8641SAndroid Build Coastguard Worker            args = [None]
728*635a8641SAndroid Build Coastguard Worker        else:
729*635a8641SAndroid Build Coastguard Worker            node = self.parse_expression()
730*635a8641SAndroid Build Coastguard Worker            if self.stream.current.type != 'colon':
731*635a8641SAndroid Build Coastguard Worker                return node
732*635a8641SAndroid Build Coastguard Worker            next(self.stream)
733*635a8641SAndroid Build Coastguard Worker            args = [node]
734*635a8641SAndroid Build Coastguard Worker
735*635a8641SAndroid Build Coastguard Worker        if self.stream.current.type == 'colon':
736*635a8641SAndroid Build Coastguard Worker            args.append(None)
737*635a8641SAndroid Build Coastguard Worker        elif self.stream.current.type not in ('rbracket', 'comma'):
738*635a8641SAndroid Build Coastguard Worker            args.append(self.parse_expression())
739*635a8641SAndroid Build Coastguard Worker        else:
740*635a8641SAndroid Build Coastguard Worker            args.append(None)
741*635a8641SAndroid Build Coastguard Worker
742*635a8641SAndroid Build Coastguard Worker        if self.stream.current.type == 'colon':
743*635a8641SAndroid Build Coastguard Worker            next(self.stream)
744*635a8641SAndroid Build Coastguard Worker            if self.stream.current.type not in ('rbracket', 'comma'):
745*635a8641SAndroid Build Coastguard Worker                args.append(self.parse_expression())
746*635a8641SAndroid Build Coastguard Worker            else:
747*635a8641SAndroid Build Coastguard Worker                args.append(None)
748*635a8641SAndroid Build Coastguard Worker        else:
749*635a8641SAndroid Build Coastguard Worker            args.append(None)
750*635a8641SAndroid Build Coastguard Worker
751*635a8641SAndroid Build Coastguard Worker        return nodes.Slice(lineno=lineno, *args)
752*635a8641SAndroid Build Coastguard Worker
753*635a8641SAndroid Build Coastguard Worker    def parse_call(self, node):
754*635a8641SAndroid Build Coastguard Worker        token = self.stream.expect('lparen')
755*635a8641SAndroid Build Coastguard Worker        args = []
756*635a8641SAndroid Build Coastguard Worker        kwargs = []
757*635a8641SAndroid Build Coastguard Worker        dyn_args = dyn_kwargs = None
758*635a8641SAndroid Build Coastguard Worker        require_comma = False
759*635a8641SAndroid Build Coastguard Worker
760*635a8641SAndroid Build Coastguard Worker        def ensure(expr):
761*635a8641SAndroid Build Coastguard Worker            if not expr:
762*635a8641SAndroid Build Coastguard Worker                self.fail('invalid syntax for function call expression',
763*635a8641SAndroid Build Coastguard Worker                          token.lineno)
764*635a8641SAndroid Build Coastguard Worker
765*635a8641SAndroid Build Coastguard Worker        while self.stream.current.type != 'rparen':
766*635a8641SAndroid Build Coastguard Worker            if require_comma:
767*635a8641SAndroid Build Coastguard Worker                self.stream.expect('comma')
768*635a8641SAndroid Build Coastguard Worker                # support for trailing comma
769*635a8641SAndroid Build Coastguard Worker                if self.stream.current.type == 'rparen':
770*635a8641SAndroid Build Coastguard Worker                    break
771*635a8641SAndroid Build Coastguard Worker            if self.stream.current.type == 'mul':
772*635a8641SAndroid Build Coastguard Worker                ensure(dyn_args is None and dyn_kwargs is None)
773*635a8641SAndroid Build Coastguard Worker                next(self.stream)
774*635a8641SAndroid Build Coastguard Worker                dyn_args = self.parse_expression()
775*635a8641SAndroid Build Coastguard Worker            elif self.stream.current.type == 'pow':
776*635a8641SAndroid Build Coastguard Worker                ensure(dyn_kwargs is None)
777*635a8641SAndroid Build Coastguard Worker                next(self.stream)
778*635a8641SAndroid Build Coastguard Worker                dyn_kwargs = self.parse_expression()
779*635a8641SAndroid Build Coastguard Worker            else:
780*635a8641SAndroid Build Coastguard Worker                ensure(dyn_args is None and dyn_kwargs is None)
781*635a8641SAndroid Build Coastguard Worker                if self.stream.current.type == 'name' and \
782*635a8641SAndroid Build Coastguard Worker                   self.stream.look().type == 'assign':
783*635a8641SAndroid Build Coastguard Worker                    key = self.stream.current.value
784*635a8641SAndroid Build Coastguard Worker                    self.stream.skip(2)
785*635a8641SAndroid Build Coastguard Worker                    value = self.parse_expression()
786*635a8641SAndroid Build Coastguard Worker                    kwargs.append(nodes.Keyword(key, value,
787*635a8641SAndroid Build Coastguard Worker                                                lineno=value.lineno))
788*635a8641SAndroid Build Coastguard Worker                else:
789*635a8641SAndroid Build Coastguard Worker                    ensure(not kwargs)
790*635a8641SAndroid Build Coastguard Worker                    args.append(self.parse_expression())
791*635a8641SAndroid Build Coastguard Worker
792*635a8641SAndroid Build Coastguard Worker            require_comma = True
793*635a8641SAndroid Build Coastguard Worker        self.stream.expect('rparen')
794*635a8641SAndroid Build Coastguard Worker
795*635a8641SAndroid Build Coastguard Worker        if node is None:
796*635a8641SAndroid Build Coastguard Worker            return args, kwargs, dyn_args, dyn_kwargs
797*635a8641SAndroid Build Coastguard Worker        return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs,
798*635a8641SAndroid Build Coastguard Worker                          lineno=token.lineno)
799*635a8641SAndroid Build Coastguard Worker
800*635a8641SAndroid Build Coastguard Worker    def parse_filter(self, node, start_inline=False):
801*635a8641SAndroid Build Coastguard Worker        while self.stream.current.type == 'pipe' or start_inline:
802*635a8641SAndroid Build Coastguard Worker            if not start_inline:
803*635a8641SAndroid Build Coastguard Worker                next(self.stream)
804*635a8641SAndroid Build Coastguard Worker            token = self.stream.expect('name')
805*635a8641SAndroid Build Coastguard Worker            name = token.value
806*635a8641SAndroid Build Coastguard Worker            while self.stream.current.type == 'dot':
807*635a8641SAndroid Build Coastguard Worker                next(self.stream)
808*635a8641SAndroid Build Coastguard Worker                name += '.' + self.stream.expect('name').value
809*635a8641SAndroid Build Coastguard Worker            if self.stream.current.type == 'lparen':
810*635a8641SAndroid Build Coastguard Worker                args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
811*635a8641SAndroid Build Coastguard Worker            else:
812*635a8641SAndroid Build Coastguard Worker                args = []
813*635a8641SAndroid Build Coastguard Worker                kwargs = []
814*635a8641SAndroid Build Coastguard Worker                dyn_args = dyn_kwargs = None
815*635a8641SAndroid Build Coastguard Worker            node = nodes.Filter(node, name, args, kwargs, dyn_args,
816*635a8641SAndroid Build Coastguard Worker                                dyn_kwargs, lineno=token.lineno)
817*635a8641SAndroid Build Coastguard Worker            start_inline = False
818*635a8641SAndroid Build Coastguard Worker        return node
819*635a8641SAndroid Build Coastguard Worker
820*635a8641SAndroid Build Coastguard Worker    def parse_test(self, node):
821*635a8641SAndroid Build Coastguard Worker        token = next(self.stream)
822*635a8641SAndroid Build Coastguard Worker        if self.stream.current.test('name:not'):
823*635a8641SAndroid Build Coastguard Worker            next(self.stream)
824*635a8641SAndroid Build Coastguard Worker            negated = True
825*635a8641SAndroid Build Coastguard Worker        else:
826*635a8641SAndroid Build Coastguard Worker            negated = False
827*635a8641SAndroid Build Coastguard Worker        name = self.stream.expect('name').value
828*635a8641SAndroid Build Coastguard Worker        while self.stream.current.type == 'dot':
829*635a8641SAndroid Build Coastguard Worker            next(self.stream)
830*635a8641SAndroid Build Coastguard Worker            name += '.' + self.stream.expect('name').value
831*635a8641SAndroid Build Coastguard Worker        dyn_args = dyn_kwargs = None
832*635a8641SAndroid Build Coastguard Worker        kwargs = []
833*635a8641SAndroid Build Coastguard Worker        if self.stream.current.type == 'lparen':
834*635a8641SAndroid Build Coastguard Worker            args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
835*635a8641SAndroid Build Coastguard Worker        elif (self.stream.current.type in ('name', 'string', 'integer',
836*635a8641SAndroid Build Coastguard Worker                                           'float', 'lparen', 'lbracket',
837*635a8641SAndroid Build Coastguard Worker                                           'lbrace') and not
838*635a8641SAndroid Build Coastguard Worker              self.stream.current.test_any('name:else', 'name:or',
839*635a8641SAndroid Build Coastguard Worker                                           'name:and')):
840*635a8641SAndroid Build Coastguard Worker            if self.stream.current.test('name:is'):
841*635a8641SAndroid Build Coastguard Worker                self.fail('You cannot chain multiple tests with is')
842*635a8641SAndroid Build Coastguard Worker            args = [self.parse_primary()]
843*635a8641SAndroid Build Coastguard Worker        else:
844*635a8641SAndroid Build Coastguard Worker            args = []
845*635a8641SAndroid Build Coastguard Worker        node = nodes.Test(node, name, args, kwargs, dyn_args,
846*635a8641SAndroid Build Coastguard Worker                          dyn_kwargs, lineno=token.lineno)
847*635a8641SAndroid Build Coastguard Worker        if negated:
848*635a8641SAndroid Build Coastguard Worker            node = nodes.Not(node, lineno=token.lineno)
849*635a8641SAndroid Build Coastguard Worker        return node
850*635a8641SAndroid Build Coastguard Worker
851*635a8641SAndroid Build Coastguard Worker    def subparse(self, end_tokens=None):
852*635a8641SAndroid Build Coastguard Worker        body = []
853*635a8641SAndroid Build Coastguard Worker        data_buffer = []
854*635a8641SAndroid Build Coastguard Worker        add_data = data_buffer.append
855*635a8641SAndroid Build Coastguard Worker
856*635a8641SAndroid Build Coastguard Worker        if end_tokens is not None:
857*635a8641SAndroid Build Coastguard Worker            self._end_token_stack.append(end_tokens)
858*635a8641SAndroid Build Coastguard Worker
859*635a8641SAndroid Build Coastguard Worker        def flush_data():
860*635a8641SAndroid Build Coastguard Worker            if data_buffer:
861*635a8641SAndroid Build Coastguard Worker                lineno = data_buffer[0].lineno
862*635a8641SAndroid Build Coastguard Worker                body.append(nodes.Output(data_buffer[:], lineno=lineno))
863*635a8641SAndroid Build Coastguard Worker                del data_buffer[:]
864*635a8641SAndroid Build Coastguard Worker
865*635a8641SAndroid Build Coastguard Worker        try:
866*635a8641SAndroid Build Coastguard Worker            while self.stream:
867*635a8641SAndroid Build Coastguard Worker                token = self.stream.current
868*635a8641SAndroid Build Coastguard Worker                if token.type == 'data':
869*635a8641SAndroid Build Coastguard Worker                    if token.value:
870*635a8641SAndroid Build Coastguard Worker                        add_data(nodes.TemplateData(token.value,
871*635a8641SAndroid Build Coastguard Worker                                                    lineno=token.lineno))
872*635a8641SAndroid Build Coastguard Worker                    next(self.stream)
873*635a8641SAndroid Build Coastguard Worker                elif token.type == 'variable_begin':
874*635a8641SAndroid Build Coastguard Worker                    next(self.stream)
875*635a8641SAndroid Build Coastguard Worker                    add_data(self.parse_tuple(with_condexpr=True))
876*635a8641SAndroid Build Coastguard Worker                    self.stream.expect('variable_end')
877*635a8641SAndroid Build Coastguard Worker                elif token.type == 'block_begin':
878*635a8641SAndroid Build Coastguard Worker                    flush_data()
879*635a8641SAndroid Build Coastguard Worker                    next(self.stream)
880*635a8641SAndroid Build Coastguard Worker                    if end_tokens is not None and \
881*635a8641SAndroid Build Coastguard Worker                       self.stream.current.test_any(*end_tokens):
882*635a8641SAndroid Build Coastguard Worker                        return body
883*635a8641SAndroid Build Coastguard Worker                    rv = self.parse_statement()
884*635a8641SAndroid Build Coastguard Worker                    if isinstance(rv, list):
885*635a8641SAndroid Build Coastguard Worker                        body.extend(rv)
886*635a8641SAndroid Build Coastguard Worker                    else:
887*635a8641SAndroid Build Coastguard Worker                        body.append(rv)
888*635a8641SAndroid Build Coastguard Worker                    self.stream.expect('block_end')
889*635a8641SAndroid Build Coastguard Worker                else:
890*635a8641SAndroid Build Coastguard Worker                    raise AssertionError('internal parsing error')
891*635a8641SAndroid Build Coastguard Worker
892*635a8641SAndroid Build Coastguard Worker            flush_data()
893*635a8641SAndroid Build Coastguard Worker        finally:
894*635a8641SAndroid Build Coastguard Worker            if end_tokens is not None:
895*635a8641SAndroid Build Coastguard Worker                self._end_token_stack.pop()
896*635a8641SAndroid Build Coastguard Worker
897*635a8641SAndroid Build Coastguard Worker        return body
898*635a8641SAndroid Build Coastguard Worker
899*635a8641SAndroid Build Coastguard Worker    def parse(self):
900*635a8641SAndroid Build Coastguard Worker        """Parse the whole template into a `Template` node."""
901*635a8641SAndroid Build Coastguard Worker        result = nodes.Template(self.subparse(), lineno=1)
902*635a8641SAndroid Build Coastguard Worker        result.set_environment(self.environment)
903*635a8641SAndroid Build Coastguard Worker        return result
904