blob: 520e88fa9ae554664877d41df7f3eaa6fc97767a [file] [log] [blame]
Armin Ronacher07bc6842008-03-31 14:18:49 +02001# -*- coding: utf-8 -*-
2"""
3 jinja2.parser
4 ~~~~~~~~~~~~~
5
6 Implements the template parser.
7
Armin Ronacher55494e42010-01-22 09:41:48 +01008 :copyright: (c) 2010 by the Jinja Team.
Armin Ronacher07bc6842008-03-31 14:18:49 +02009 :license: BSD, see LICENSE for more details.
10"""
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020011from jinja2 import nodes
Armin Ronachera78d2762008-05-15 23:18:07 +020012from jinja2.exceptions import TemplateSyntaxError, TemplateAssertionError
Armin Ronacher5dcb7242010-02-06 14:01:26 +010013from jinja2.lexer import describe_token, describe_token_expr
Thomas Waldmann7d295622013-05-18 00:06:22 +020014import six
15from six.moves import map, zip
Armin Ronacher07bc6842008-03-31 14:18:49 +020016
17
Armin Ronacher5dcb7242010-02-06 14:01:26 +010018#: statements that callinto
Armin Ronachere791c2a2008-04-07 18:39:54 +020019_statement_keywords = frozenset(['for', 'if', 'block', 'extends', 'print',
Armin Ronacher0a2ac692008-05-13 01:03:08 +020020 'macro', 'include', 'from', 'import',
21 'set'])
Armin Ronacher115de2e2008-05-01 22:20:05 +020022_compare_operators = frozenset(['eq', 'ne', 'lt', 'lteq', 'gt', 'gteq'])
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020023
Armin Ronacher07bc6842008-03-31 14:18:49 +020024
25class Parser(object):
Armin Ronacher023b5e92008-05-08 11:03:10 +020026 """This is the central parsing class Jinja2 uses. It's passed to
27 extensions and can be used to parse expressions or statements.
Armin Ronacher07bc6842008-03-31 14:18:49 +020028 """
29
Armin Ronacherba6e25a2008-11-02 15:58:14 +010030 def __init__(self, environment, source, name=None, filename=None,
31 state=None):
Armin Ronacher07bc6842008-03-31 14:18:49 +020032 self.environment = environment
Armin Ronacherba6e25a2008-11-02 15:58:14 +010033 self.stream = environment._tokenize(source, name, filename, state)
Armin Ronacher7f15ef82008-05-16 09:11:39 +020034 self.name = name
Armin Ronacher07bc6842008-03-31 14:18:49 +020035 self.filename = filename
36 self.closed = False
Armin Ronacher05530932008-04-20 13:27:49 +020037 self.extensions = {}
Armin Ronacher5b3f4dc2010-04-12 14:04:14 +020038 for extension in environment.iter_extensions():
Armin Ronacher05530932008-04-20 13:27:49 +020039 for tag in extension.tags:
40 self.extensions[tag] = extension.parse
Armin Ronacher023b5e92008-05-08 11:03:10 +020041 self._last_identifier = 0
Armin Ronacher5dcb7242010-02-06 14:01:26 +010042 self._tag_stack = []
43 self._end_token_stack = []
Armin Ronacher115de2e2008-05-01 22:20:05 +020044
Armin Ronacher7f15ef82008-05-16 09:11:39 +020045 def fail(self, msg, lineno=None, exc=TemplateSyntaxError):
46 """Convenience method that raises `exc` with the message, passed
47 line number or last line number as well as the current name and
48 filename.
49 """
50 if lineno is None:
51 lineno = self.stream.current.lineno
Armin Ronacher61a5a242008-05-26 12:07:44 +020052 raise exc(msg, lineno, self.name, self.filename)
Armin Ronacher7f15ef82008-05-16 09:11:39 +020053
Armin Ronacher5dcb7242010-02-06 14:01:26 +010054 def _fail_ut_eof(self, name, end_token_stack, lineno):
55 expected = []
56 for exprs in end_token_stack:
57 expected.extend(map(describe_token_expr, exprs))
Armin Ronacher28decdb2010-02-11 14:27:23 +010058 if end_token_stack:
59 currently_looking = ' or '.join(
60 "'%s'" % describe_token_expr(expr)
61 for expr in end_token_stack[-1])
62 else:
63 currently_looking = None
Armin Ronacher5dcb7242010-02-06 14:01:26 +010064
65 if name is None:
66 message = ['Unexpected end of template.']
67 else:
68 message = ['Encountered unknown tag \'%s\'.' % name]
69
Armin Ronacher28decdb2010-02-11 14:27:23 +010070 if currently_looking:
71 if name is not None and name in expected:
72 message.append('You probably made a nesting mistake. Jinja '
73 'is expecting this tag, but currently looking '
74 'for %s.' % currently_looking)
75 else:
76 message.append('Jinja was looking for the following tags: '
77 '%s.' % currently_looking)
Armin Ronacher5dcb7242010-02-06 14:01:26 +010078
79 if self._tag_stack:
80 message.append('The innermost block that needs to be '
81 'closed is \'%s\'.' % self._tag_stack[-1])
82
83 self.fail(' '.join(message), lineno)
84
85 def fail_unknown_tag(self, name, lineno=None):
86 """Called if the parser encounters an unknown tag. Tries to fail
87 with a human readable error message that could help to identify
88 the problem.
89 """
90 return self._fail_ut_eof(name, self._end_token_stack, lineno)
91
92 def fail_eof(self, end_tokens=None, lineno=None):
93 """Like fail_unknown_tag but for end of template situations."""
94 stack = list(self._end_token_stack)
95 if end_tokens is not None:
96 stack.append(end_tokens)
97 return self._fail_ut_eof(None, stack, lineno)
98
Armin Ronacherfdf95302008-05-11 22:20:51 +020099 def is_tuple_end(self, extra_end_rules=None):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200100 """Are we at the end of a tuple?"""
Armin Ronacherfdf95302008-05-11 22:20:51 +0200101 if self.stream.current.type in ('variable_end', 'block_end', 'rparen'):
Armin Ronacher023b5e92008-05-08 11:03:10 +0200102 return True
Armin Ronacherfdf95302008-05-11 22:20:51 +0200103 elif extra_end_rules is not None:
104 return self.stream.current.test_any(extra_end_rules)
Armin Ronacher762079c2008-05-08 23:57:56 +0200105 return False
106
Armin Ronacher023b5e92008-05-08 11:03:10 +0200107 def free_identifier(self, lineno=None):
108 """Return a new free identifier as :class:`~jinja2.nodes.InternalName`."""
109 self._last_identifier += 1
110 rv = object.__new__(nodes.InternalName)
111 nodes.Node.__init__(rv, 'fi%d' % self._last_identifier, lineno=lineno)
112 return rv
Armin Ronacher115de2e2008-05-01 22:20:05 +0200113
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200114 def parse_statement(self):
115 """Parse a single statement."""
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200116 token = self.stream.current
Ali Afshar272ca2a2009-01-05 12:14:14 +0100117 if token.type != 'name':
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200118 self.fail('tag name expected', token.lineno)
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100119 self._tag_stack.append(token.value)
120 pop_tag = True
121 try:
122 if token.value in _statement_keywords:
123 return getattr(self, 'parse_' + self.stream.current.value)()
124 if token.value == 'call':
125 return self.parse_call_block()
126 if token.value == 'filter':
127 return self.parse_filter_block()
128 ext = self.extensions.get(token.value)
129 if ext is not None:
130 return ext(self)
131
132 # did not work out, remove the token we pushed by accident
133 # from the stack so that the unknown tag fail function can
134 # produce a proper error message.
135 self._tag_stack.pop()
136 pop_tag = False
137 self.fail_unknown_tag(token.value, token.lineno)
138 finally:
139 if pop_tag:
140 self._tag_stack.pop()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200141
142 def parse_statements(self, end_tokens, drop_needle=False):
Armin Ronacherf59bac22008-04-20 13:11:43 +0200143 """Parse multiple statements into a list until one of the end tokens
144 is reached. This is used to parse the body of statements as it also
Armin Ronacher023b5e92008-05-08 11:03:10 +0200145 parses template data if appropriate. The parser checks first if the
146 current token is a colon and skips it if there is one. Then it checks
147 for the block end and parses until if one of the `end_tokens` is
148 reached. Per default the active token in the stream at the end of
149 the call is the matched end token. If this is not wanted `drop_needle`
150 can be set to `True` and the end token is removed.
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200151 """
152 # the first token may be a colon for python compatibility
Armin Ronacherfdf95302008-05-11 22:20:51 +0200153 self.stream.skip_if('colon')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200154
Armin Ronacher2b60fe52008-04-21 08:23:59 +0200155 # in the future it would be possible to add whole code sections
156 # by adding some sort of end of statement token and parsing those here.
157 self.stream.expect('block_end')
158 result = self.subparse(end_tokens)
159
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100160 # we reached the end of the template too early, the subparser
161 # does not check for this, so we do that now
162 if self.stream.current.type == 'eof':
163 self.fail_eof(end_tokens)
164
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200165 if drop_needle:
Thomas Waldmann7d295622013-05-18 00:06:22 +0200166 six.advance_iterator(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200167 return result
168
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200169 def parse_set(self):
170 """Parse an assign statement."""
Thomas Waldmann7d295622013-05-18 00:06:22 +0200171 lineno = six.advance_iterator(self.stream).lineno
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200172 target = self.parse_assign_target()
173 self.stream.expect('assign')
174 expr = self.parse_tuple()
175 return nodes.Assign(target, expr, lineno=lineno)
176
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200177 def parse_for(self):
178 """Parse a for loop."""
Armin Ronacher115de2e2008-05-01 22:20:05 +0200179 lineno = self.stream.expect('name:for').lineno
Armin Ronacherfdf95302008-05-11 22:20:51 +0200180 target = self.parse_assign_target(extra_end_rules=('name:in',))
Armin Ronacher115de2e2008-05-01 22:20:05 +0200181 self.stream.expect('name:in')
Armin Ronacherfdf95302008-05-11 22:20:51 +0200182 iter = self.parse_tuple(with_condexpr=False,
183 extra_end_rules=('name:recursive',))
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200184 test = None
Armin Ronacherfdf95302008-05-11 22:20:51 +0200185 if self.stream.skip_if('name:if'):
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200186 test = self.parse_expression()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200187 recursive = self.stream.skip_if('name:recursive')
Armin Ronacher115de2e2008-05-01 22:20:05 +0200188 body = self.parse_statements(('name:endfor', 'name:else'))
Thomas Waldmann7d295622013-05-18 00:06:22 +0200189 if six.advance_iterator(self.stream).value == 'endfor':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200190 else_ = []
191 else:
Armin Ronacher115de2e2008-05-01 22:20:05 +0200192 else_ = self.parse_statements(('name:endfor',), drop_needle=True)
Armin Ronacherfdf95302008-05-11 22:20:51 +0200193 return nodes.For(target, iter, body, else_, test,
194 recursive, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200195
196 def parse_if(self):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200197 """Parse an if construct."""
Armin Ronacher115de2e2008-05-01 22:20:05 +0200198 node = result = nodes.If(lineno=self.stream.expect('name:if').lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200199 while 1:
Armin Ronacher09c002e2008-05-10 22:21:30 +0200200 node.test = self.parse_tuple(with_condexpr=False)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200201 node.body = self.parse_statements(('name:elif', 'name:else',
202 'name:endif'))
Thomas Waldmann7d295622013-05-18 00:06:22 +0200203 token = six.advance_iterator(self.stream)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200204 if token.test('name:elif'):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200205 new_node = nodes.If(lineno=self.stream.current.lineno)
206 node.else_ = [new_node]
207 node = new_node
208 continue
Armin Ronacher115de2e2008-05-01 22:20:05 +0200209 elif token.test('name:else'):
210 node.else_ = self.parse_statements(('name:endif',),
Armin Ronachere791c2a2008-04-07 18:39:54 +0200211 drop_needle=True)
212 else:
213 node.else_ = []
214 break
215 return result
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200216
217 def parse_block(self):
Thomas Waldmann7d295622013-05-18 00:06:22 +0200218 node = nodes.Block(lineno=six.advance_iterator(self.stream).lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200219 node.name = self.stream.expect('name').value
Armin Ronacher74a0cd92009-02-19 15:56:53 +0100220 node.scoped = self.stream.skip_if('name:scoped')
Armin Ronacher92622e92010-02-07 01:27:47 +0100221
222 # common problem people encounter when switching from django
223 # to jinja. we do not support hyphens in block names, so let's
224 # raise a nicer error message in that case.
225 if self.stream.current.type == 'sub':
226 self.fail('Block names in Jinja have to be valid Python '
Dmitry Jemerov5c5d0612011-09-26 19:04:29 +0200227 'identifiers and may not contain hyphens, use an '
Armin Ronacher92622e92010-02-07 01:27:47 +0100228 'underscore instead.')
229
Armin Ronacher115de2e2008-05-01 22:20:05 +0200230 node.body = self.parse_statements(('name:endblock',), drop_needle=True)
Armin Ronacherfd310492008-05-25 00:16:51 +0200231 self.stream.skip_if('name:' + node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200232 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200233
234 def parse_extends(self):
Thomas Waldmann7d295622013-05-18 00:06:22 +0200235 node = nodes.Extends(lineno=six.advance_iterator(self.stream).lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200236 node.template = self.parse_expression()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200237 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200238
Armin Ronacherea847c52008-05-02 20:04:32 +0200239 def parse_import_context(self, node, default):
Armin Ronachercda43df2008-05-03 17:10:05 +0200240 if self.stream.current.test_any('name:with', 'name:without') and \
Armin Ronacherea847c52008-05-02 20:04:32 +0200241 self.stream.look().test('name:context'):
Thomas Waldmann7d295622013-05-18 00:06:22 +0200242 node.with_context = six.advance_iterator(self.stream).value == 'with'
Armin Ronacherea847c52008-05-02 20:04:32 +0200243 self.stream.skip()
244 else:
245 node.with_context = default
246 return node
247
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200248 def parse_include(self):
Thomas Waldmann7d295622013-05-18 00:06:22 +0200249 node = nodes.Include(lineno=six.advance_iterator(self.stream).lineno)
Armin Ronacher0611e492008-04-25 23:44:14 +0200250 node.template = self.parse_expression()
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100251 if self.stream.current.test('name:ignore') and \
252 self.stream.look().test('name:missing'):
253 node.ignore_missing = True
254 self.stream.skip(2)
255 else:
256 node.ignore_missing = False
Armin Ronacherea847c52008-05-02 20:04:32 +0200257 return self.parse_import_context(node, True)
Armin Ronacher0611e492008-04-25 23:44:14 +0200258
259 def parse_import(self):
Thomas Waldmann7d295622013-05-18 00:06:22 +0200260 node = nodes.Import(lineno=six.advance_iterator(self.stream).lineno)
Armin Ronacher0611e492008-04-25 23:44:14 +0200261 node.template = self.parse_expression()
262 self.stream.expect('name:as')
Armin Ronacher09c002e2008-05-10 22:21:30 +0200263 node.target = self.parse_assign_target(name_only=True).name
Armin Ronacherea847c52008-05-02 20:04:32 +0200264 return self.parse_import_context(node, False)
Armin Ronacher0611e492008-04-25 23:44:14 +0200265
266 def parse_from(self):
Thomas Waldmann7d295622013-05-18 00:06:22 +0200267 node = nodes.FromImport(lineno=six.advance_iterator(self.stream).lineno)
Armin Ronacher0611e492008-04-25 23:44:14 +0200268 node.template = self.parse_expression()
Armin Ronacher115de2e2008-05-01 22:20:05 +0200269 self.stream.expect('name:import')
Armin Ronacher0611e492008-04-25 23:44:14 +0200270 node.names = []
Armin Ronacherea847c52008-05-02 20:04:32 +0200271
272 def parse_context():
273 if self.stream.current.value in ('with', 'without') and \
274 self.stream.look().test('name:context'):
Thomas Waldmann7d295622013-05-18 00:06:22 +0200275 node.with_context = six.advance_iterator(self.stream).value == 'with'
Armin Ronacherea847c52008-05-02 20:04:32 +0200276 self.stream.skip()
277 return True
278 return False
279
Armin Ronacher0611e492008-04-25 23:44:14 +0200280 while 1:
281 if node.names:
282 self.stream.expect('comma')
Ali Afshar272ca2a2009-01-05 12:14:14 +0100283 if self.stream.current.type == 'name':
Armin Ronacherea847c52008-05-02 20:04:32 +0200284 if parse_context():
285 break
Armin Ronacher09c002e2008-05-10 22:21:30 +0200286 target = self.parse_assign_target(name_only=True)
Armin Ronacher903d1682008-05-23 00:51:58 +0200287 if target.name.startswith('_'):
288 self.fail('names starting with an underline can not '
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200289 'be imported', target.lineno,
290 exc=TemplateAssertionError)
Armin Ronacherfdf95302008-05-11 22:20:51 +0200291 if self.stream.skip_if('name:as'):
Armin Ronacher09c002e2008-05-10 22:21:30 +0200292 alias = self.parse_assign_target(name_only=True)
293 node.names.append((target.name, alias.name))
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200294 else:
295 node.names.append(target.name)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100296 if parse_context() or self.stream.current.type != 'comma':
Armin Ronacher0611e492008-04-25 23:44:14 +0200297 break
298 else:
299 break
Armin Ronacherea847c52008-05-02 20:04:32 +0200300 if not hasattr(node, 'with_context'):
301 node.with_context = False
Armin Ronacherfdf95302008-05-11 22:20:51 +0200302 self.stream.skip_if('comma')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200303 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200304
Armin Ronacher71082072008-04-12 14:19:36 +0200305 def parse_signature(self, node):
306 node.args = args = []
307 node.defaults = defaults = []
308 self.stream.expect('lparen')
Ali Afshar272ca2a2009-01-05 12:14:14 +0100309 while self.stream.current.type != 'rparen':
Armin Ronacher71082072008-04-12 14:19:36 +0200310 if args:
311 self.stream.expect('comma')
Armin Ronacher09c002e2008-05-10 22:21:30 +0200312 arg = self.parse_assign_target(name_only=True)
Armin Ronachere9411b42008-05-15 16:22:07 +0200313 arg.set_ctx('param')
Armin Ronacherfdf95302008-05-11 22:20:51 +0200314 if self.stream.skip_if('assign'):
Armin Ronacher71082072008-04-12 14:19:36 +0200315 defaults.append(self.parse_expression())
316 args.append(arg)
317 self.stream.expect('rparen')
318
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200319 def parse_call_block(self):
Thomas Waldmann7d295622013-05-18 00:06:22 +0200320 node = nodes.CallBlock(lineno=six.advance_iterator(self.stream).lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100321 if self.stream.current.type == 'lparen':
Armin Ronacher71082072008-04-12 14:19:36 +0200322 self.parse_signature(node)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200323 else:
324 node.args = []
325 node.defaults = []
Armin Ronacher71082072008-04-12 14:19:36 +0200326
Armin Ronacher8edbe492008-04-10 20:43:43 +0200327 node.call = self.parse_expression()
328 if not isinstance(node.call, nodes.Call):
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200329 self.fail('expected call', node.lineno)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200330 node.body = self.parse_statements(('name:endcall',), drop_needle=True)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200331 return node
332
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200333 def parse_filter_block(self):
Thomas Waldmann7d295622013-05-18 00:06:22 +0200334 node = nodes.FilterBlock(lineno=six.advance_iterator(self.stream).lineno)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200335 node.filter = self.parse_filter(None, start_inline=True)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200336 node.body = self.parse_statements(('name:endfilter',),
337 drop_needle=True)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200338 return node
339
Armin Ronachere791c2a2008-04-07 18:39:54 +0200340 def parse_macro(self):
Thomas Waldmann7d295622013-05-18 00:06:22 +0200341 node = nodes.Macro(lineno=six.advance_iterator(self.stream).lineno)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200342 node.name = self.parse_assign_target(name_only=True).name
Armin Ronacher71082072008-04-12 14:19:36 +0200343 self.parse_signature(node)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200344 node.body = self.parse_statements(('name:endmacro',),
345 drop_needle=True)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200346 return node
347
348 def parse_print(self):
Thomas Waldmann7d295622013-05-18 00:06:22 +0200349 node = nodes.Output(lineno=six.advance_iterator(self.stream).lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200350 node.nodes = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100351 while self.stream.current.type != 'block_end':
Armin Ronachere791c2a2008-04-07 18:39:54 +0200352 if node.nodes:
353 self.stream.expect('comma')
354 node.nodes.append(self.parse_expression())
Armin Ronachere791c2a2008-04-07 18:39:54 +0200355 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200356
Armin Ronacherfdf95302008-05-11 22:20:51 +0200357 def parse_assign_target(self, with_tuple=True, name_only=False,
358 extra_end_rules=None):
Armin Ronacher09c002e2008-05-10 22:21:30 +0200359 """Parse an assignment target. As Jinja2 allows assignments to
360 tuples, this function can parse all allowed assignment targets. Per
361 default assignments to tuples are parsed, that can be disable however
362 by setting `with_tuple` to `False`. If only assignments to names are
Armin Ronacherfdf95302008-05-11 22:20:51 +0200363 wanted `name_only` can be set to `True`. The `extra_end_rules`
364 parameter is forwarded to the tuple parsing function.
Armin Ronacher09c002e2008-05-10 22:21:30 +0200365 """
366 if name_only:
367 token = self.stream.expect('name')
368 target = nodes.Name(token.value, 'store', lineno=token.lineno)
369 else:
370 if with_tuple:
Armin Ronacherfdf95302008-05-11 22:20:51 +0200371 target = self.parse_tuple(simplified=True,
372 extra_end_rules=extra_end_rules)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200373 else:
Armin Ronacher2ee64bc2010-08-17 12:36:38 +0200374 target = self.parse_primary()
Armin Ronacher09c002e2008-05-10 22:21:30 +0200375 target.set_ctx('store')
376 if not target.can_assign():
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200377 self.fail('can\'t assign to %r' % target.__class__.
378 __name__.lower(), target.lineno)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200379 return target
380
381 def parse_expression(self, with_condexpr=True):
Armin Ronacher023b5e92008-05-08 11:03:10 +0200382 """Parse an expression. Per default all expressions are parsed, if
Armin Ronacher09c002e2008-05-10 22:21:30 +0200383 the optional `with_condexpr` parameter is set to `False` conditional
Armin Ronacher023b5e92008-05-08 11:03:10 +0200384 expressions are not parsed.
385 """
Armin Ronacher09c002e2008-05-10 22:21:30 +0200386 if with_condexpr:
387 return self.parse_condexpr()
388 return self.parse_or()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200389
390 def parse_condexpr(self):
391 lineno = self.stream.current.lineno
392 expr1 = self.parse_or()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200393 while self.stream.skip_if('name:if'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200394 expr2 = self.parse_or()
Armin Ronacher547d0b62008-07-04 16:35:10 +0200395 if self.stream.skip_if('name:else'):
396 expr3 = self.parse_condexpr()
397 else:
398 expr3 = None
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200399 expr1 = nodes.CondExpr(expr2, expr1, expr3, lineno=lineno)
400 lineno = self.stream.current.lineno
401 return expr1
402
403 def parse_or(self):
404 lineno = self.stream.current.lineno
405 left = self.parse_and()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200406 while self.stream.skip_if('name:or'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200407 right = self.parse_and()
408 left = nodes.Or(left, right, lineno=lineno)
409 lineno = self.stream.current.lineno
410 return left
411
412 def parse_and(self):
413 lineno = self.stream.current.lineno
Armin Ronacherd89f0f32009-02-04 18:57:27 +0100414 left = self.parse_not()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200415 while self.stream.skip_if('name:and'):
Armin Ronacherd89f0f32009-02-04 18:57:27 +0100416 right = self.parse_not()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200417 left = nodes.And(left, right, lineno=lineno)
418 lineno = self.stream.current.lineno
419 return left
420
Armin Ronacherd89f0f32009-02-04 18:57:27 +0100421 def parse_not(self):
422 if self.stream.current.test('name:not'):
Thomas Waldmann7d295622013-05-18 00:06:22 +0200423 lineno = six.advance_iterator(self.stream).lineno
Armin Ronacherd89f0f32009-02-04 18:57:27 +0100424 return nodes.Not(self.parse_not(), lineno=lineno)
425 return self.parse_compare()
426
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200427 def parse_compare(self):
428 lineno = self.stream.current.lineno
429 expr = self.parse_add()
430 ops = []
431 while 1:
432 token_type = self.stream.current.type
433 if token_type in _compare_operators:
Thomas Waldmann7d295622013-05-18 00:06:22 +0200434 six.advance_iterator(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200435 ops.append(nodes.Operand(token_type, self.parse_add()))
Armin Ronacherfdf95302008-05-11 22:20:51 +0200436 elif self.stream.skip_if('name:in'):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200437 ops.append(nodes.Operand('in', self.parse_add()))
438 elif self.stream.current.test('name:not') and \
439 self.stream.look().test('name:in'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200440 self.stream.skip(2)
441 ops.append(nodes.Operand('notin', self.parse_add()))
442 else:
443 break
444 lineno = self.stream.current.lineno
445 if not ops:
446 return expr
447 return nodes.Compare(expr, ops, lineno=lineno)
448
449 def parse_add(self):
450 lineno = self.stream.current.lineno
451 left = self.parse_sub()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100452 while self.stream.current.type == 'add':
Thomas Waldmann7d295622013-05-18 00:06:22 +0200453 six.advance_iterator(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200454 right = self.parse_sub()
455 left = nodes.Add(left, right, lineno=lineno)
456 lineno = self.stream.current.lineno
457 return left
458
459 def parse_sub(self):
460 lineno = self.stream.current.lineno
461 left = self.parse_concat()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100462 while self.stream.current.type == 'sub':
Thomas Waldmann7d295622013-05-18 00:06:22 +0200463 six.advance_iterator(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200464 right = self.parse_concat()
465 left = nodes.Sub(left, right, lineno=lineno)
466 lineno = self.stream.current.lineno
467 return left
468
469 def parse_concat(self):
470 lineno = self.stream.current.lineno
471 args = [self.parse_mul()]
Ali Afshar272ca2a2009-01-05 12:14:14 +0100472 while self.stream.current.type == 'tilde':
Thomas Waldmann7d295622013-05-18 00:06:22 +0200473 six.advance_iterator(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200474 args.append(self.parse_mul())
475 if len(args) == 1:
476 return args[0]
477 return nodes.Concat(args, lineno=lineno)
478
479 def parse_mul(self):
480 lineno = self.stream.current.lineno
481 left = self.parse_div()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100482 while self.stream.current.type == 'mul':
Thomas Waldmann7d295622013-05-18 00:06:22 +0200483 six.advance_iterator(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200484 right = self.parse_div()
485 left = nodes.Mul(left, right, lineno=lineno)
486 lineno = self.stream.current.lineno
487 return left
488
489 def parse_div(self):
490 lineno = self.stream.current.lineno
491 left = self.parse_floordiv()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100492 while self.stream.current.type == 'div':
Thomas Waldmann7d295622013-05-18 00:06:22 +0200493 six.advance_iterator(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200494 right = self.parse_floordiv()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200495 left = nodes.Div(left, right, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200496 lineno = self.stream.current.lineno
497 return left
498
499 def parse_floordiv(self):
500 lineno = self.stream.current.lineno
501 left = self.parse_mod()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100502 while self.stream.current.type == 'floordiv':
Thomas Waldmann7d295622013-05-18 00:06:22 +0200503 six.advance_iterator(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200504 right = self.parse_mod()
505 left = nodes.FloorDiv(left, right, lineno=lineno)
506 lineno = self.stream.current.lineno
507 return left
508
509 def parse_mod(self):
510 lineno = self.stream.current.lineno
511 left = self.parse_pow()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100512 while self.stream.current.type == 'mod':
Thomas Waldmann7d295622013-05-18 00:06:22 +0200513 six.advance_iterator(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200514 right = self.parse_pow()
515 left = nodes.Mod(left, right, lineno=lineno)
516 lineno = self.stream.current.lineno
517 return left
518
519 def parse_pow(self):
520 lineno = self.stream.current.lineno
521 left = self.parse_unary()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100522 while self.stream.current.type == 'pow':
Thomas Waldmann7d295622013-05-18 00:06:22 +0200523 six.advance_iterator(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200524 right = self.parse_unary()
525 left = nodes.Pow(left, right, lineno=lineno)
526 lineno = self.stream.current.lineno
527 return left
528
Armin Ronacher613912d2010-10-17 15:53:59 +0200529 def parse_unary(self, with_filter=True):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200530 token_type = self.stream.current.type
531 lineno = self.stream.current.lineno
Ali Afshar272ca2a2009-01-05 12:14:14 +0100532 if token_type == 'sub':
Thomas Waldmann7d295622013-05-18 00:06:22 +0200533 six.advance_iterator(self.stream)
Armin Ronacher2ee64bc2010-08-17 12:36:38 +0200534 node = nodes.Neg(self.parse_unary(False), lineno=lineno)
535 elif token_type == 'add':
Thomas Waldmann7d295622013-05-18 00:06:22 +0200536 six.advance_iterator(self.stream)
Armin Ronacher2ee64bc2010-08-17 12:36:38 +0200537 node = nodes.Pos(self.parse_unary(False), lineno=lineno)
538 else:
539 node = self.parse_primary()
Armin Ronacher613912d2010-10-17 15:53:59 +0200540 node = self.parse_postfix(node)
541 if with_filter:
542 node = self.parse_filter_expr(node)
Armin Ronacher2ee64bc2010-08-17 12:36:38 +0200543 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200544
Armin Ronacher2ee64bc2010-08-17 12:36:38 +0200545 def parse_primary(self):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200546 token = self.stream.current
Ali Afshar272ca2a2009-01-05 12:14:14 +0100547 if token.type == 'name':
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200548 if token.value in ('true', 'false', 'True', 'False'):
549 node = nodes.Const(token.value in ('true', 'True'),
550 lineno=token.lineno)
551 elif token.value in ('none', 'None'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200552 node = nodes.Const(None, lineno=token.lineno)
553 else:
554 node = nodes.Name(token.value, 'load', lineno=token.lineno)
Thomas Waldmann7d295622013-05-18 00:06:22 +0200555 six.advance_iterator(self.stream)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100556 elif token.type == 'string':
Thomas Waldmann7d295622013-05-18 00:06:22 +0200557 six.advance_iterator(self.stream)
Armin Ronacher4778bda2008-06-22 12:48:37 +0200558 buf = [token.value]
559 lineno = token.lineno
Ali Afshar272ca2a2009-01-05 12:14:14 +0100560 while self.stream.current.type == 'string':
Armin Ronacher4778bda2008-06-22 12:48:37 +0200561 buf.append(self.stream.current.value)
Thomas Waldmann7d295622013-05-18 00:06:22 +0200562 six.advance_iterator(self.stream)
Armin Ronacher4778bda2008-06-22 12:48:37 +0200563 node = nodes.Const(''.join(buf), lineno=lineno)
564 elif token.type in ('integer', 'float'):
Thomas Waldmann7d295622013-05-18 00:06:22 +0200565 six.advance_iterator(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200566 node = nodes.Const(token.value, lineno=token.lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100567 elif token.type == 'lparen':
Thomas Waldmann7d295622013-05-18 00:06:22 +0200568 six.advance_iterator(self.stream)
Armin Ronachere614e882010-02-06 15:04:46 +0100569 node = self.parse_tuple(explicit_parentheses=True)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200570 self.stream.expect('rparen')
Ali Afshar272ca2a2009-01-05 12:14:14 +0100571 elif token.type == 'lbracket':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200572 node = self.parse_list()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100573 elif token.type == 'lbrace':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200574 node = self.parse_dict()
575 else:
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100576 self.fail("unexpected '%s'" % describe_token(token), token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200577 return node
578
Armin Ronacherfdf95302008-05-11 22:20:51 +0200579 def parse_tuple(self, simplified=False, with_condexpr=True,
Armin Ronachere614e882010-02-06 15:04:46 +0100580 extra_end_rules=None, explicit_parentheses=False):
Armin Ronacher023b5e92008-05-08 11:03:10 +0200581 """Works like `parse_expression` but if multiple expressions are
582 delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created.
583 This method could also return a regular expression instead of a tuple
584 if no commas where found.
585
586 The default parsing mode is a full tuple. If `simplified` is `True`
587 only names and literals are parsed. The `no_condexpr` parameter is
588 forwarded to :meth:`parse_expression`.
Armin Ronacherfdf95302008-05-11 22:20:51 +0200589
590 Because tuples do not require delimiters and may end in a bogus comma
591 an extra hint is needed that marks the end of a tuple. For example
592 for loops support tuples between `for` and `in`. In that case the
593 `extra_end_rules` is set to ``['name:in']``.
Armin Ronachere614e882010-02-06 15:04:46 +0100594
595 `explicit_parentheses` is true if the parsing was triggered by an
596 expression in parentheses. This is used to figure out if an empty
597 tuple is a valid expression or not.
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200598 """
599 lineno = self.stream.current.lineno
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200600 if simplified:
Armin Ronacher2ee64bc2010-08-17 12:36:38 +0200601 parse = self.parse_primary
Armin Ronacher09c002e2008-05-10 22:21:30 +0200602 elif with_condexpr:
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200603 parse = self.parse_expression
Armin Ronacher09c002e2008-05-10 22:21:30 +0200604 else:
605 parse = lambda: self.parse_expression(with_condexpr=False)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200606 args = []
607 is_tuple = False
608 while 1:
609 if args:
610 self.stream.expect('comma')
Armin Ronacherfdf95302008-05-11 22:20:51 +0200611 if self.is_tuple_end(extra_end_rules):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200612 break
613 args.append(parse())
Ali Afshar272ca2a2009-01-05 12:14:14 +0100614 if self.stream.current.type == 'comma':
Armin Ronacherb5124e62008-04-25 00:36:14 +0200615 is_tuple = True
616 else:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200617 break
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200618 lineno = self.stream.current.lineno
Armin Ronachere614e882010-02-06 15:04:46 +0100619
620 if not is_tuple:
621 if args:
622 return args[0]
623
624 # if we don't have explicit parentheses, an empty tuple is
625 # not a valid expression. This would mean nothing (literally
626 # nothing) in the spot of an expression would be an empty
627 # tuple.
628 if not explicit_parentheses:
629 self.fail('Expected an expression, got \'%s\'' %
630 describe_token(self.stream.current))
631
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200632 return nodes.Tuple(args, 'load', lineno=lineno)
633
634 def parse_list(self):
635 token = self.stream.expect('lbracket')
636 items = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100637 while self.stream.current.type != 'rbracket':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200638 if items:
639 self.stream.expect('comma')
640 if self.stream.current.type == 'rbracket':
641 break
642 items.append(self.parse_expression())
643 self.stream.expect('rbracket')
644 return nodes.List(items, lineno=token.lineno)
645
646 def parse_dict(self):
647 token = self.stream.expect('lbrace')
648 items = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100649 while self.stream.current.type != 'rbrace':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200650 if items:
651 self.stream.expect('comma')
652 if self.stream.current.type == 'rbrace':
653 break
654 key = self.parse_expression()
655 self.stream.expect('colon')
656 value = self.parse_expression()
657 items.append(nodes.Pair(key, value, lineno=key.lineno))
658 self.stream.expect('rbrace')
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200659 return nodes.Dict(items, lineno=token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200660
661 def parse_postfix(self, node):
662 while 1:
663 token_type = self.stream.current.type
Ali Afshar272ca2a2009-01-05 12:14:14 +0100664 if token_type == 'dot' or token_type == 'lbracket':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200665 node = self.parse_subscript(node)
Armin Ronacher613912d2010-10-17 15:53:59 +0200666 # calls are valid both after postfix expressions (getattr
667 # and getitem) as well as filters and tests
Ali Afshar272ca2a2009-01-05 12:14:14 +0100668 elif token_type == 'lparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200669 node = self.parse_call(node)
Armin Ronacher613912d2010-10-17 15:53:59 +0200670 else:
671 break
672 return node
673
674 def parse_filter_expr(self, node):
675 while 1:
676 token_type = self.stream.current.type
677 if token_type == 'pipe':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200678 node = self.parse_filter(node)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100679 elif token_type == 'name' and self.stream.current.value == 'is':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200680 node = self.parse_test(node)
Armin Ronacher613912d2010-10-17 15:53:59 +0200681 # calls are valid both after postfix expressions (getattr
682 # and getitem) as well as filters and tests
683 elif token_type == 'lparen':
684 node = self.parse_call(node)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200685 else:
686 break
687 return node
688
689 def parse_subscript(self, node):
Thomas Waldmann7d295622013-05-18 00:06:22 +0200690 token = six.advance_iterator(self.stream)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100691 if token.type == 'dot':
Armin Ronachere791c2a2008-04-07 18:39:54 +0200692 attr_token = self.stream.current
Thomas Waldmann7d295622013-05-18 00:06:22 +0200693 six.advance_iterator(self.stream)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100694 if attr_token.type == 'name':
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200695 return nodes.Getattr(node, attr_token.value, 'load',
696 lineno=token.lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100697 elif attr_token.type != 'integer':
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200698 self.fail('expected name or number', attr_token.lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200699 arg = nodes.Const(attr_token.value, lineno=attr_token.lineno)
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200700 return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100701 if token.type == 'lbracket':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200702 args = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100703 while self.stream.current.type != 'rbracket':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200704 if args:
705 self.stream.expect('comma')
706 args.append(self.parse_subscribed())
707 self.stream.expect('rbracket')
708 if len(args) == 1:
709 arg = args[0]
710 else:
Armin Ronacheree2d3c42009-02-05 23:13:15 +0100711 arg = nodes.Tuple(args, 'load', lineno=token.lineno)
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200712 return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
713 self.fail('expected subscript expression', self.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200714
715 def parse_subscribed(self):
716 lineno = self.stream.current.lineno
717
Ali Afshar272ca2a2009-01-05 12:14:14 +0100718 if self.stream.current.type == 'colon':
Thomas Waldmann7d295622013-05-18 00:06:22 +0200719 six.advance_iterator(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200720 args = [None]
721 else:
722 node = self.parse_expression()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100723 if self.stream.current.type != 'colon':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200724 return node
Thomas Waldmann7d295622013-05-18 00:06:22 +0200725 six.advance_iterator(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200726 args = [node]
727
Ali Afshar272ca2a2009-01-05 12:14:14 +0100728 if self.stream.current.type == 'colon':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200729 args.append(None)
730 elif self.stream.current.type not in ('rbracket', 'comma'):
731 args.append(self.parse_expression())
732 else:
733 args.append(None)
734
Ali Afshar272ca2a2009-01-05 12:14:14 +0100735 if self.stream.current.type == 'colon':
Thomas Waldmann7d295622013-05-18 00:06:22 +0200736 six.advance_iterator(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200737 if self.stream.current.type not in ('rbracket', 'comma'):
738 args.append(self.parse_expression())
739 else:
740 args.append(None)
741 else:
742 args.append(None)
743
744 return nodes.Slice(lineno=lineno, *args)
745
746 def parse_call(self, node):
747 token = self.stream.expect('lparen')
748 args = []
749 kwargs = []
750 dyn_args = dyn_kwargs = None
751 require_comma = False
752
753 def ensure(expr):
754 if not expr:
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200755 self.fail('invalid syntax for function call expression',
756 token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200757
Ali Afshar272ca2a2009-01-05 12:14:14 +0100758 while self.stream.current.type != 'rparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200759 if require_comma:
760 self.stream.expect('comma')
761 # support for trailing comma
Ali Afshar272ca2a2009-01-05 12:14:14 +0100762 if self.stream.current.type == 'rparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200763 break
Ali Afshar272ca2a2009-01-05 12:14:14 +0100764 if self.stream.current.type == 'mul':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200765 ensure(dyn_args is None and dyn_kwargs is None)
Thomas Waldmann7d295622013-05-18 00:06:22 +0200766 six.advance_iterator(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200767 dyn_args = self.parse_expression()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100768 elif self.stream.current.type == 'pow':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200769 ensure(dyn_kwargs is None)
Thomas Waldmann7d295622013-05-18 00:06:22 +0200770 six.advance_iterator(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200771 dyn_kwargs = self.parse_expression()
772 else:
773 ensure(dyn_args is None and dyn_kwargs is None)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100774 if self.stream.current.type == 'name' and \
775 self.stream.look().type == 'assign':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200776 key = self.stream.current.value
777 self.stream.skip(2)
Armin Ronacher0611e492008-04-25 23:44:14 +0200778 value = self.parse_expression()
779 kwargs.append(nodes.Keyword(key, value,
780 lineno=value.lineno))
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200781 else:
782 ensure(not kwargs)
783 args.append(self.parse_expression())
784
785 require_comma = True
786 self.stream.expect('rparen')
787
788 if node is None:
789 return args, kwargs, dyn_args, dyn_kwargs
790 return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs,
791 lineno=token.lineno)
792
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200793 def parse_filter(self, node, start_inline=False):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200794 while self.stream.current.type == 'pipe' or start_inline:
795 if not start_inline:
Thomas Waldmann7d295622013-05-18 00:06:22 +0200796 six.advance_iterator(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200797 token = self.stream.expect('name')
Armin Ronacherb9e78752008-05-10 23:36:28 +0200798 name = token.value
Ali Afshar272ca2a2009-01-05 12:14:14 +0100799 while self.stream.current.type == 'dot':
Thomas Waldmann7d295622013-05-18 00:06:22 +0200800 six.advance_iterator(self.stream)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200801 name += '.' + self.stream.expect('name').value
Ali Afshar272ca2a2009-01-05 12:14:14 +0100802 if self.stream.current.type == 'lparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200803 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
804 else:
805 args = []
806 kwargs = []
807 dyn_args = dyn_kwargs = None
Armin Ronacherb9e78752008-05-10 23:36:28 +0200808 node = nodes.Filter(node, name, args, kwargs, dyn_args,
Armin Ronacherd55ab532008-04-09 16:13:39 +0200809 dyn_kwargs, lineno=token.lineno)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200810 start_inline = False
Armin Ronacherd55ab532008-04-09 16:13:39 +0200811 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200812
813 def parse_test(self, node):
Thomas Waldmann7d295622013-05-18 00:06:22 +0200814 token = six.advance_iterator(self.stream)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200815 if self.stream.current.test('name:not'):
Thomas Waldmann7d295622013-05-18 00:06:22 +0200816 six.advance_iterator(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200817 negated = True
818 else:
819 negated = False
820 name = self.stream.expect('name').value
Ali Afshar272ca2a2009-01-05 12:14:14 +0100821 while self.stream.current.type == 'dot':
Thomas Waldmann7d295622013-05-18 00:06:22 +0200822 six.advance_iterator(self.stream)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200823 name += '.' + self.stream.expect('name').value
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200824 dyn_args = dyn_kwargs = None
825 kwargs = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100826 if self.stream.current.type == 'lparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200827 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
828 elif self.stream.current.type in ('name', 'string', 'integer',
829 'float', 'lparen', 'lbracket',
Armin Ronachere3290ea2008-06-12 10:30:01 +0200830 'lbrace') and not \
831 self.stream.current.test_any('name:else', 'name:or',
832 'name:and'):
833 if self.stream.current.test('name:is'):
834 self.fail('You cannot chain multiple tests with is')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200835 args = [self.parse_expression()]
836 else:
837 args = []
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200838 node = nodes.Test(node, name, args, kwargs, dyn_args,
839 dyn_kwargs, lineno=token.lineno)
840 if negated:
Armin Ronacher9a822052008-04-17 18:44:07 +0200841 node = nodes.Not(node, lineno=token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200842 return node
843
844 def subparse(self, end_tokens=None):
845 body = []
846 data_buffer = []
847 add_data = data_buffer.append
848
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100849 if end_tokens is not None:
850 self._end_token_stack.append(end_tokens)
851
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200852 def flush_data():
853 if data_buffer:
854 lineno = data_buffer[0].lineno
855 body.append(nodes.Output(data_buffer[:], lineno=lineno))
856 del data_buffer[:]
857
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100858 try:
859 while self.stream:
860 token = self.stream.current
861 if token.type == 'data':
862 if token.value:
863 add_data(nodes.TemplateData(token.value,
864 lineno=token.lineno))
Thomas Waldmann7d295622013-05-18 00:06:22 +0200865 six.advance_iterator(self.stream)
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100866 elif token.type == 'variable_begin':
Thomas Waldmann7d295622013-05-18 00:06:22 +0200867 six.advance_iterator(self.stream)
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100868 add_data(self.parse_tuple(with_condexpr=True))
869 self.stream.expect('variable_end')
870 elif token.type == 'block_begin':
871 flush_data()
Thomas Waldmann7d295622013-05-18 00:06:22 +0200872 six.advance_iterator(self.stream)
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100873 if end_tokens is not None and \
874 self.stream.current.test_any(*end_tokens):
875 return body
876 rv = self.parse_statement()
877 if isinstance(rv, list):
878 body.extend(rv)
879 else:
880 body.append(rv)
881 self.stream.expect('block_end')
Armin Ronacher023b5e92008-05-08 11:03:10 +0200882 else:
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100883 raise AssertionError('internal parsing error')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200884
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100885 flush_data()
886 finally:
887 if end_tokens is not None:
888 self._end_token_stack.pop()
889
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200890 return body
891
892 def parse(self):
893 """Parse the whole template into a `Template` node."""
Armin Ronacherd55ab532008-04-09 16:13:39 +0200894 result = nodes.Template(self.subparse(), lineno=1)
895 result.set_environment(self.environment)
896 return result