blob: d44229ad0f09a562bbf67de4a5daf5d5730456ab [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 Ronacherbd357722009-08-05 20:25:06 +020013from jinja2.utils import next
Armin Ronacher5dcb7242010-02-06 14:01:26 +010014from jinja2.lexer import describe_token, describe_token_expr
Armin Ronacher07bc6842008-03-31 14:18:49 +020015
16
Armin Ronacher5dcb7242010-02-06 14:01:26 +010017#: statements that callinto
Armin Ronachere791c2a2008-04-07 18:39:54 +020018_statement_keywords = frozenset(['for', 'if', 'block', 'extends', 'print',
Armin Ronacher0a2ac692008-05-13 01:03:08 +020019 'macro', 'include', 'from', 'import',
20 'set'])
Armin Ronacher115de2e2008-05-01 22:20:05 +020021_compare_operators = frozenset(['eq', 'ne', 'lt', 'lteq', 'gt', 'gteq'])
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020022
Armin Ronacher07bc6842008-03-31 14:18:49 +020023
24class Parser(object):
Armin Ronacher023b5e92008-05-08 11:03:10 +020025 """This is the central parsing class Jinja2 uses. It's passed to
26 extensions and can be used to parse expressions or statements.
Armin Ronacher07bc6842008-03-31 14:18:49 +020027 """
28
Armin Ronacherba6e25a2008-11-02 15:58:14 +010029 def __init__(self, environment, source, name=None, filename=None,
30 state=None):
Armin Ronacher07bc6842008-03-31 14:18:49 +020031 self.environment = environment
Armin Ronacherba6e25a2008-11-02 15:58:14 +010032 self.stream = environment._tokenize(source, name, filename, state)
Armin Ronacher7f15ef82008-05-16 09:11:39 +020033 self.name = name
Armin Ronacher07bc6842008-03-31 14:18:49 +020034 self.filename = filename
35 self.closed = False
Armin Ronacher05530932008-04-20 13:27:49 +020036 self.extensions = {}
Armin Ronacher5b3f4dc2010-04-12 14:04:14 +020037 for extension in environment.iter_extensions():
Armin Ronacher05530932008-04-20 13:27:49 +020038 for tag in extension.tags:
39 self.extensions[tag] = extension.parse
Armin Ronacher023b5e92008-05-08 11:03:10 +020040 self._last_identifier = 0
Armin Ronacher5dcb7242010-02-06 14:01:26 +010041 self._tag_stack = []
42 self._end_token_stack = []
Armin Ronacher115de2e2008-05-01 22:20:05 +020043
Armin Ronacher7f15ef82008-05-16 09:11:39 +020044 def fail(self, msg, lineno=None, exc=TemplateSyntaxError):
45 """Convenience method that raises `exc` with the message, passed
46 line number or last line number as well as the current name and
47 filename.
48 """
49 if lineno is None:
50 lineno = self.stream.current.lineno
Armin Ronacher61a5a242008-05-26 12:07:44 +020051 raise exc(msg, lineno, self.name, self.filename)
Armin Ronacher7f15ef82008-05-16 09:11:39 +020052
Armin Ronacher5dcb7242010-02-06 14:01:26 +010053 def _fail_ut_eof(self, name, end_token_stack, lineno):
54 expected = []
55 for exprs in end_token_stack:
56 expected.extend(map(describe_token_expr, exprs))
Armin Ronacher28decdb2010-02-11 14:27:23 +010057 if end_token_stack:
58 currently_looking = ' or '.join(
59 "'%s'" % describe_token_expr(expr)
60 for expr in end_token_stack[-1])
61 else:
62 currently_looking = None
Armin Ronacher5dcb7242010-02-06 14:01:26 +010063
64 if name is None:
65 message = ['Unexpected end of template.']
66 else:
67 message = ['Encountered unknown tag \'%s\'.' % name]
68
Armin Ronacher28decdb2010-02-11 14:27:23 +010069 if currently_looking:
70 if name is not None and name in expected:
71 message.append('You probably made a nesting mistake. Jinja '
72 'is expecting this tag, but currently looking '
73 'for %s.' % currently_looking)
74 else:
75 message.append('Jinja was looking for the following tags: '
76 '%s.' % currently_looking)
Armin Ronacher5dcb7242010-02-06 14:01:26 +010077
78 if self._tag_stack:
79 message.append('The innermost block that needs to be '
80 'closed is \'%s\'.' % self._tag_stack[-1])
81
82 self.fail(' '.join(message), lineno)
83
84 def fail_unknown_tag(self, name, lineno=None):
85 """Called if the parser encounters an unknown tag. Tries to fail
86 with a human readable error message that could help to identify
87 the problem.
88 """
89 return self._fail_ut_eof(name, self._end_token_stack, lineno)
90
91 def fail_eof(self, end_tokens=None, lineno=None):
92 """Like fail_unknown_tag but for end of template situations."""
93 stack = list(self._end_token_stack)
94 if end_tokens is not None:
95 stack.append(end_tokens)
96 return self._fail_ut_eof(None, stack, lineno)
97
Armin Ronacherfdf95302008-05-11 22:20:51 +020098 def is_tuple_end(self, extra_end_rules=None):
Armin Ronacher115de2e2008-05-01 22:20:05 +020099 """Are we at the end of a tuple?"""
Armin Ronacherfdf95302008-05-11 22:20:51 +0200100 if self.stream.current.type in ('variable_end', 'block_end', 'rparen'):
Armin Ronacher023b5e92008-05-08 11:03:10 +0200101 return True
Armin Ronacherfdf95302008-05-11 22:20:51 +0200102 elif extra_end_rules is not None:
103 return self.stream.current.test_any(extra_end_rules)
Armin Ronacher762079c2008-05-08 23:57:56 +0200104 return False
105
Armin Ronacher023b5e92008-05-08 11:03:10 +0200106 def free_identifier(self, lineno=None):
107 """Return a new free identifier as :class:`~jinja2.nodes.InternalName`."""
108 self._last_identifier += 1
109 rv = object.__new__(nodes.InternalName)
110 nodes.Node.__init__(rv, 'fi%d' % self._last_identifier, lineno=lineno)
111 return rv
Armin Ronacher115de2e2008-05-01 22:20:05 +0200112
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200113 def parse_statement(self):
114 """Parse a single statement."""
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200115 token = self.stream.current
Ali Afshar272ca2a2009-01-05 12:14:14 +0100116 if token.type != 'name':
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200117 self.fail('tag name expected', token.lineno)
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100118 self._tag_stack.append(token.value)
119 pop_tag = True
120 try:
121 if token.value in _statement_keywords:
122 return getattr(self, 'parse_' + self.stream.current.value)()
123 if token.value == 'call':
124 return self.parse_call_block()
125 if token.value == 'filter':
126 return self.parse_filter_block()
127 ext = self.extensions.get(token.value)
128 if ext is not None:
129 return ext(self)
130
131 # did not work out, remove the token we pushed by accident
132 # from the stack so that the unknown tag fail function can
133 # produce a proper error message.
134 self._tag_stack.pop()
135 pop_tag = False
136 self.fail_unknown_tag(token.value, token.lineno)
137 finally:
138 if pop_tag:
139 self._tag_stack.pop()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200140
141 def parse_statements(self, end_tokens, drop_needle=False):
Armin Ronacherf59bac22008-04-20 13:11:43 +0200142 """Parse multiple statements into a list until one of the end tokens
143 is reached. This is used to parse the body of statements as it also
Armin Ronacher023b5e92008-05-08 11:03:10 +0200144 parses template data if appropriate. The parser checks first if the
145 current token is a colon and skips it if there is one. Then it checks
146 for the block end and parses until if one of the `end_tokens` is
147 reached. Per default the active token in the stream at the end of
148 the call is the matched end token. If this is not wanted `drop_needle`
149 can be set to `True` and the end token is removed.
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200150 """
151 # the first token may be a colon for python compatibility
Armin Ronacherfdf95302008-05-11 22:20:51 +0200152 self.stream.skip_if('colon')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200153
Armin Ronacher2b60fe52008-04-21 08:23:59 +0200154 # in the future it would be possible to add whole code sections
155 # by adding some sort of end of statement token and parsing those here.
156 self.stream.expect('block_end')
157 result = self.subparse(end_tokens)
158
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100159 # we reached the end of the template too early, the subparser
160 # does not check for this, so we do that now
161 if self.stream.current.type == 'eof':
162 self.fail_eof(end_tokens)
163
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200164 if drop_needle:
Armin Ronacherbd357722009-08-05 20:25:06 +0200165 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200166 return result
167
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200168 def parse_set(self):
169 """Parse an assign statement."""
Armin Ronacherbd357722009-08-05 20:25:06 +0200170 lineno = next(self.stream).lineno
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200171 target = self.parse_assign_target()
172 self.stream.expect('assign')
173 expr = self.parse_tuple()
174 return nodes.Assign(target, expr, lineno=lineno)
175
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200176 def parse_for(self):
177 """Parse a for loop."""
Armin Ronacher115de2e2008-05-01 22:20:05 +0200178 lineno = self.stream.expect('name:for').lineno
Armin Ronacherfdf95302008-05-11 22:20:51 +0200179 target = self.parse_assign_target(extra_end_rules=('name:in',))
Armin Ronacher115de2e2008-05-01 22:20:05 +0200180 self.stream.expect('name:in')
Armin Ronacherfdf95302008-05-11 22:20:51 +0200181 iter = self.parse_tuple(with_condexpr=False,
182 extra_end_rules=('name:recursive',))
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200183 test = None
Armin Ronacherfdf95302008-05-11 22:20:51 +0200184 if self.stream.skip_if('name:if'):
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200185 test = self.parse_expression()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200186 recursive = self.stream.skip_if('name:recursive')
Armin Ronacher115de2e2008-05-01 22:20:05 +0200187 body = self.parse_statements(('name:endfor', 'name:else'))
Armin Ronacherbd357722009-08-05 20:25:06 +0200188 if next(self.stream).value == 'endfor':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200189 else_ = []
190 else:
Armin Ronacher115de2e2008-05-01 22:20:05 +0200191 else_ = self.parse_statements(('name:endfor',), drop_needle=True)
Armin Ronacherfdf95302008-05-11 22:20:51 +0200192 return nodes.For(target, iter, body, else_, test,
193 recursive, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200194
195 def parse_if(self):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200196 """Parse an if construct."""
Armin Ronacher115de2e2008-05-01 22:20:05 +0200197 node = result = nodes.If(lineno=self.stream.expect('name:if').lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200198 while 1:
Armin Ronacher09c002e2008-05-10 22:21:30 +0200199 node.test = self.parse_tuple(with_condexpr=False)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200200 node.body = self.parse_statements(('name:elif', 'name:else',
201 'name:endif'))
Armin Ronacherbd357722009-08-05 20:25:06 +0200202 token = next(self.stream)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200203 if token.test('name:elif'):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200204 new_node = nodes.If(lineno=self.stream.current.lineno)
205 node.else_ = [new_node]
206 node = new_node
207 continue
Armin Ronacher115de2e2008-05-01 22:20:05 +0200208 elif token.test('name:else'):
209 node.else_ = self.parse_statements(('name:endif',),
Armin Ronachere791c2a2008-04-07 18:39:54 +0200210 drop_needle=True)
211 else:
212 node.else_ = []
213 break
214 return result
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200215
216 def parse_block(self):
Armin Ronacherbd357722009-08-05 20:25:06 +0200217 node = nodes.Block(lineno=next(self.stream).lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200218 node.name = self.stream.expect('name').value
Armin Ronacher74a0cd92009-02-19 15:56:53 +0100219 node.scoped = self.stream.skip_if('name:scoped')
Armin Ronacher92622e92010-02-07 01:27:47 +0100220
221 # common problem people encounter when switching from django
222 # to jinja. we do not support hyphens in block names, so let's
223 # raise a nicer error message in that case.
224 if self.stream.current.type == 'sub':
225 self.fail('Block names in Jinja have to be valid Python '
226 'identifiers and may not contain hypens, use an '
227 'underscore instead.')
228
Armin Ronacher115de2e2008-05-01 22:20:05 +0200229 node.body = self.parse_statements(('name:endblock',), drop_needle=True)
Armin Ronacherfd310492008-05-25 00:16:51 +0200230 self.stream.skip_if('name:' + node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200231 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200232
233 def parse_extends(self):
Armin Ronacherbd357722009-08-05 20:25:06 +0200234 node = nodes.Extends(lineno=next(self.stream).lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200235 node.template = self.parse_expression()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200236 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200237
Armin Ronacherea847c52008-05-02 20:04:32 +0200238 def parse_import_context(self, node, default):
Armin Ronachercda43df2008-05-03 17:10:05 +0200239 if self.stream.current.test_any('name:with', 'name:without') and \
Armin Ronacherea847c52008-05-02 20:04:32 +0200240 self.stream.look().test('name:context'):
Armin Ronacherbd357722009-08-05 20:25:06 +0200241 node.with_context = next(self.stream).value == 'with'
Armin Ronacherea847c52008-05-02 20:04:32 +0200242 self.stream.skip()
243 else:
244 node.with_context = default
245 return node
246
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200247 def parse_include(self):
Armin Ronacherbd357722009-08-05 20:25:06 +0200248 node = nodes.Include(lineno=next(self.stream).lineno)
Armin Ronacher0611e492008-04-25 23:44:14 +0200249 node.template = self.parse_expression()
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100250 if self.stream.current.test('name:ignore') and \
251 self.stream.look().test('name:missing'):
252 node.ignore_missing = True
253 self.stream.skip(2)
254 else:
255 node.ignore_missing = False
Armin Ronacherea847c52008-05-02 20:04:32 +0200256 return self.parse_import_context(node, True)
Armin Ronacher0611e492008-04-25 23:44:14 +0200257
258 def parse_import(self):
Armin Ronacherbd357722009-08-05 20:25:06 +0200259 node = nodes.Import(lineno=next(self.stream).lineno)
Armin Ronacher0611e492008-04-25 23:44:14 +0200260 node.template = self.parse_expression()
261 self.stream.expect('name:as')
Armin Ronacher09c002e2008-05-10 22:21:30 +0200262 node.target = self.parse_assign_target(name_only=True).name
Armin Ronacherea847c52008-05-02 20:04:32 +0200263 return self.parse_import_context(node, False)
Armin Ronacher0611e492008-04-25 23:44:14 +0200264
265 def parse_from(self):
Armin Ronacherbd357722009-08-05 20:25:06 +0200266 node = nodes.FromImport(lineno=next(self.stream).lineno)
Armin Ronacher0611e492008-04-25 23:44:14 +0200267 node.template = self.parse_expression()
Armin Ronacher115de2e2008-05-01 22:20:05 +0200268 self.stream.expect('name:import')
Armin Ronacher0611e492008-04-25 23:44:14 +0200269 node.names = []
Armin Ronacherea847c52008-05-02 20:04:32 +0200270
271 def parse_context():
272 if self.stream.current.value in ('with', 'without') and \
273 self.stream.look().test('name:context'):
Armin Ronacherbd357722009-08-05 20:25:06 +0200274 node.with_context = next(self.stream).value == 'with'
Armin Ronacherea847c52008-05-02 20:04:32 +0200275 self.stream.skip()
276 return True
277 return False
278
Armin Ronacher0611e492008-04-25 23:44:14 +0200279 while 1:
280 if node.names:
281 self.stream.expect('comma')
Ali Afshar272ca2a2009-01-05 12:14:14 +0100282 if self.stream.current.type == 'name':
Armin Ronacherea847c52008-05-02 20:04:32 +0200283 if parse_context():
284 break
Armin Ronacher09c002e2008-05-10 22:21:30 +0200285 target = self.parse_assign_target(name_only=True)
Armin Ronacher903d1682008-05-23 00:51:58 +0200286 if target.name.startswith('_'):
287 self.fail('names starting with an underline can not '
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200288 'be imported', target.lineno,
289 exc=TemplateAssertionError)
Armin Ronacherfdf95302008-05-11 22:20:51 +0200290 if self.stream.skip_if('name:as'):
Armin Ronacher09c002e2008-05-10 22:21:30 +0200291 alias = self.parse_assign_target(name_only=True)
292 node.names.append((target.name, alias.name))
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200293 else:
294 node.names.append(target.name)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100295 if parse_context() or self.stream.current.type != 'comma':
Armin Ronacher0611e492008-04-25 23:44:14 +0200296 break
297 else:
298 break
Armin Ronacherea847c52008-05-02 20:04:32 +0200299 if not hasattr(node, 'with_context'):
300 node.with_context = False
Armin Ronacherfdf95302008-05-11 22:20:51 +0200301 self.stream.skip_if('comma')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200302 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200303
Armin Ronacher71082072008-04-12 14:19:36 +0200304 def parse_signature(self, node):
305 node.args = args = []
306 node.defaults = defaults = []
307 self.stream.expect('lparen')
Ali Afshar272ca2a2009-01-05 12:14:14 +0100308 while self.stream.current.type != 'rparen':
Armin Ronacher71082072008-04-12 14:19:36 +0200309 if args:
310 self.stream.expect('comma')
Armin Ronacher09c002e2008-05-10 22:21:30 +0200311 arg = self.parse_assign_target(name_only=True)
Armin Ronachere9411b42008-05-15 16:22:07 +0200312 arg.set_ctx('param')
Armin Ronacherfdf95302008-05-11 22:20:51 +0200313 if self.stream.skip_if('assign'):
Armin Ronacher71082072008-04-12 14:19:36 +0200314 defaults.append(self.parse_expression())
315 args.append(arg)
316 self.stream.expect('rparen')
317
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200318 def parse_call_block(self):
Armin Ronacherbd357722009-08-05 20:25:06 +0200319 node = nodes.CallBlock(lineno=next(self.stream).lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100320 if self.stream.current.type == 'lparen':
Armin Ronacher71082072008-04-12 14:19:36 +0200321 self.parse_signature(node)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200322 else:
323 node.args = []
324 node.defaults = []
Armin Ronacher71082072008-04-12 14:19:36 +0200325
Armin Ronacher8edbe492008-04-10 20:43:43 +0200326 node.call = self.parse_expression()
327 if not isinstance(node.call, nodes.Call):
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200328 self.fail('expected call', node.lineno)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200329 node.body = self.parse_statements(('name:endcall',), drop_needle=True)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200330 return node
331
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200332 def parse_filter_block(self):
Armin Ronacherbd357722009-08-05 20:25:06 +0200333 node = nodes.FilterBlock(lineno=next(self.stream).lineno)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200334 node.filter = self.parse_filter(None, start_inline=True)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200335 node.body = self.parse_statements(('name:endfilter',),
336 drop_needle=True)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200337 return node
338
Armin Ronachere791c2a2008-04-07 18:39:54 +0200339 def parse_macro(self):
Armin Ronacherbd357722009-08-05 20:25:06 +0200340 node = nodes.Macro(lineno=next(self.stream).lineno)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200341 node.name = self.parse_assign_target(name_only=True).name
Armin Ronacher71082072008-04-12 14:19:36 +0200342 self.parse_signature(node)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200343 node.body = self.parse_statements(('name:endmacro',),
344 drop_needle=True)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200345 return node
346
347 def parse_print(self):
Armin Ronacherbd357722009-08-05 20:25:06 +0200348 node = nodes.Output(lineno=next(self.stream).lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200349 node.nodes = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100350 while self.stream.current.type != 'block_end':
Armin Ronachere791c2a2008-04-07 18:39:54 +0200351 if node.nodes:
352 self.stream.expect('comma')
353 node.nodes.append(self.parse_expression())
Armin Ronachere791c2a2008-04-07 18:39:54 +0200354 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200355
Armin Ronacherfdf95302008-05-11 22:20:51 +0200356 def parse_assign_target(self, with_tuple=True, name_only=False,
357 extra_end_rules=None):
Armin Ronacher09c002e2008-05-10 22:21:30 +0200358 """Parse an assignment target. As Jinja2 allows assignments to
359 tuples, this function can parse all allowed assignment targets. Per
360 default assignments to tuples are parsed, that can be disable however
361 by setting `with_tuple` to `False`. If only assignments to names are
Armin Ronacherfdf95302008-05-11 22:20:51 +0200362 wanted `name_only` can be set to `True`. The `extra_end_rules`
363 parameter is forwarded to the tuple parsing function.
Armin Ronacher09c002e2008-05-10 22:21:30 +0200364 """
365 if name_only:
366 token = self.stream.expect('name')
367 target = nodes.Name(token.value, 'store', lineno=token.lineno)
368 else:
369 if with_tuple:
Armin Ronacherfdf95302008-05-11 22:20:51 +0200370 target = self.parse_tuple(simplified=True,
371 extra_end_rules=extra_end_rules)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200372 else:
Armin Ronacher2ee64bc2010-08-17 12:36:38 +0200373 target = self.parse_primary()
Armin Ronacher09c002e2008-05-10 22:21:30 +0200374 target.set_ctx('store')
375 if not target.can_assign():
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200376 self.fail('can\'t assign to %r' % target.__class__.
377 __name__.lower(), target.lineno)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200378 return target
379
380 def parse_expression(self, with_condexpr=True):
Armin Ronacher023b5e92008-05-08 11:03:10 +0200381 """Parse an expression. Per default all expressions are parsed, if
Armin Ronacher09c002e2008-05-10 22:21:30 +0200382 the optional `with_condexpr` parameter is set to `False` conditional
Armin Ronacher023b5e92008-05-08 11:03:10 +0200383 expressions are not parsed.
384 """
Armin Ronacher09c002e2008-05-10 22:21:30 +0200385 if with_condexpr:
386 return self.parse_condexpr()
387 return self.parse_or()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200388
389 def parse_condexpr(self):
390 lineno = self.stream.current.lineno
391 expr1 = self.parse_or()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200392 while self.stream.skip_if('name:if'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200393 expr2 = self.parse_or()
Armin Ronacher547d0b62008-07-04 16:35:10 +0200394 if self.stream.skip_if('name:else'):
395 expr3 = self.parse_condexpr()
396 else:
397 expr3 = None
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200398 expr1 = nodes.CondExpr(expr2, expr1, expr3, lineno=lineno)
399 lineno = self.stream.current.lineno
400 return expr1
401
402 def parse_or(self):
403 lineno = self.stream.current.lineno
404 left = self.parse_and()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200405 while self.stream.skip_if('name:or'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200406 right = self.parse_and()
407 left = nodes.Or(left, right, lineno=lineno)
408 lineno = self.stream.current.lineno
409 return left
410
411 def parse_and(self):
412 lineno = self.stream.current.lineno
Armin Ronacherd89f0f32009-02-04 18:57:27 +0100413 left = self.parse_not()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200414 while self.stream.skip_if('name:and'):
Armin Ronacherd89f0f32009-02-04 18:57:27 +0100415 right = self.parse_not()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200416 left = nodes.And(left, right, lineno=lineno)
417 lineno = self.stream.current.lineno
418 return left
419
Armin Ronacherd89f0f32009-02-04 18:57:27 +0100420 def parse_not(self):
421 if self.stream.current.test('name:not'):
Armin Ronacherbd357722009-08-05 20:25:06 +0200422 lineno = next(self.stream).lineno
Armin Ronacherd89f0f32009-02-04 18:57:27 +0100423 return nodes.Not(self.parse_not(), lineno=lineno)
424 return self.parse_compare()
425
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200426 def parse_compare(self):
427 lineno = self.stream.current.lineno
428 expr = self.parse_add()
429 ops = []
430 while 1:
431 token_type = self.stream.current.type
432 if token_type in _compare_operators:
Armin Ronacherbd357722009-08-05 20:25:06 +0200433 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200434 ops.append(nodes.Operand(token_type, self.parse_add()))
Armin Ronacherfdf95302008-05-11 22:20:51 +0200435 elif self.stream.skip_if('name:in'):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200436 ops.append(nodes.Operand('in', self.parse_add()))
437 elif self.stream.current.test('name:not') and \
438 self.stream.look().test('name:in'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200439 self.stream.skip(2)
440 ops.append(nodes.Operand('notin', self.parse_add()))
441 else:
442 break
443 lineno = self.stream.current.lineno
444 if not ops:
445 return expr
446 return nodes.Compare(expr, ops, lineno=lineno)
447
448 def parse_add(self):
449 lineno = self.stream.current.lineno
450 left = self.parse_sub()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100451 while self.stream.current.type == 'add':
Armin Ronacherbd357722009-08-05 20:25:06 +0200452 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200453 right = self.parse_sub()
454 left = nodes.Add(left, right, lineno=lineno)
455 lineno = self.stream.current.lineno
456 return left
457
458 def parse_sub(self):
459 lineno = self.stream.current.lineno
460 left = self.parse_concat()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100461 while self.stream.current.type == 'sub':
Armin Ronacherbd357722009-08-05 20:25:06 +0200462 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200463 right = self.parse_concat()
464 left = nodes.Sub(left, right, lineno=lineno)
465 lineno = self.stream.current.lineno
466 return left
467
468 def parse_concat(self):
469 lineno = self.stream.current.lineno
470 args = [self.parse_mul()]
Ali Afshar272ca2a2009-01-05 12:14:14 +0100471 while self.stream.current.type == 'tilde':
Armin Ronacherbd357722009-08-05 20:25:06 +0200472 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200473 args.append(self.parse_mul())
474 if len(args) == 1:
475 return args[0]
476 return nodes.Concat(args, lineno=lineno)
477
478 def parse_mul(self):
479 lineno = self.stream.current.lineno
480 left = self.parse_div()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100481 while self.stream.current.type == 'mul':
Armin Ronacherbd357722009-08-05 20:25:06 +0200482 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200483 right = self.parse_div()
484 left = nodes.Mul(left, right, lineno=lineno)
485 lineno = self.stream.current.lineno
486 return left
487
488 def parse_div(self):
489 lineno = self.stream.current.lineno
490 left = self.parse_floordiv()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100491 while self.stream.current.type == 'div':
Armin Ronacherbd357722009-08-05 20:25:06 +0200492 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200493 right = self.parse_floordiv()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200494 left = nodes.Div(left, right, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200495 lineno = self.stream.current.lineno
496 return left
497
498 def parse_floordiv(self):
499 lineno = self.stream.current.lineno
500 left = self.parse_mod()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100501 while self.stream.current.type == 'floordiv':
Armin Ronacherbd357722009-08-05 20:25:06 +0200502 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200503 right = self.parse_mod()
504 left = nodes.FloorDiv(left, right, lineno=lineno)
505 lineno = self.stream.current.lineno
506 return left
507
508 def parse_mod(self):
509 lineno = self.stream.current.lineno
510 left = self.parse_pow()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100511 while self.stream.current.type == 'mod':
Armin Ronacherbd357722009-08-05 20:25:06 +0200512 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200513 right = self.parse_pow()
514 left = nodes.Mod(left, right, lineno=lineno)
515 lineno = self.stream.current.lineno
516 return left
517
518 def parse_pow(self):
519 lineno = self.stream.current.lineno
520 left = self.parse_unary()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100521 while self.stream.current.type == 'pow':
Armin Ronacherbd357722009-08-05 20:25:06 +0200522 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200523 right = self.parse_unary()
524 left = nodes.Pow(left, right, lineno=lineno)
525 lineno = self.stream.current.lineno
526 return left
527
Armin Ronacher613912d2010-10-17 15:53:59 +0200528 def parse_unary(self, with_filter=True):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200529 token_type = self.stream.current.type
530 lineno = self.stream.current.lineno
Ali Afshar272ca2a2009-01-05 12:14:14 +0100531 if token_type == 'sub':
Armin Ronacherbd357722009-08-05 20:25:06 +0200532 next(self.stream)
Armin Ronacher2ee64bc2010-08-17 12:36:38 +0200533 node = nodes.Neg(self.parse_unary(False), lineno=lineno)
534 elif token_type == 'add':
Armin Ronacherbd357722009-08-05 20:25:06 +0200535 next(self.stream)
Armin Ronacher2ee64bc2010-08-17 12:36:38 +0200536 node = nodes.Pos(self.parse_unary(False), lineno=lineno)
537 else:
538 node = self.parse_primary()
Armin Ronacher613912d2010-10-17 15:53:59 +0200539 node = self.parse_postfix(node)
540 if with_filter:
541 node = self.parse_filter_expr(node)
Armin Ronacher2ee64bc2010-08-17 12:36:38 +0200542 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200543
Armin Ronacher2ee64bc2010-08-17 12:36:38 +0200544 def parse_primary(self):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200545 token = self.stream.current
Ali Afshar272ca2a2009-01-05 12:14:14 +0100546 if token.type == 'name':
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200547 if token.value in ('true', 'false', 'True', 'False'):
548 node = nodes.Const(token.value in ('true', 'True'),
549 lineno=token.lineno)
550 elif token.value in ('none', 'None'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200551 node = nodes.Const(None, lineno=token.lineno)
552 else:
553 node = nodes.Name(token.value, 'load', lineno=token.lineno)
Armin Ronacherbd357722009-08-05 20:25:06 +0200554 next(self.stream)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100555 elif token.type == 'string':
Armin Ronacherbd357722009-08-05 20:25:06 +0200556 next(self.stream)
Armin Ronacher4778bda2008-06-22 12:48:37 +0200557 buf = [token.value]
558 lineno = token.lineno
Ali Afshar272ca2a2009-01-05 12:14:14 +0100559 while self.stream.current.type == 'string':
Armin Ronacher4778bda2008-06-22 12:48:37 +0200560 buf.append(self.stream.current.value)
Armin Ronacherbd357722009-08-05 20:25:06 +0200561 next(self.stream)
Armin Ronacher4778bda2008-06-22 12:48:37 +0200562 node = nodes.Const(''.join(buf), lineno=lineno)
563 elif token.type in ('integer', 'float'):
Armin Ronacherbd357722009-08-05 20:25:06 +0200564 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200565 node = nodes.Const(token.value, lineno=token.lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100566 elif token.type == 'lparen':
Armin Ronacherbd357722009-08-05 20:25:06 +0200567 next(self.stream)
Armin Ronachere614e882010-02-06 15:04:46 +0100568 node = self.parse_tuple(explicit_parentheses=True)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200569 self.stream.expect('rparen')
Ali Afshar272ca2a2009-01-05 12:14:14 +0100570 elif token.type == 'lbracket':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200571 node = self.parse_list()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100572 elif token.type == 'lbrace':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200573 node = self.parse_dict()
574 else:
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100575 self.fail("unexpected '%s'" % describe_token(token), token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200576 return node
577
Armin Ronacherfdf95302008-05-11 22:20:51 +0200578 def parse_tuple(self, simplified=False, with_condexpr=True,
Armin Ronachere614e882010-02-06 15:04:46 +0100579 extra_end_rules=None, explicit_parentheses=False):
Armin Ronacher023b5e92008-05-08 11:03:10 +0200580 """Works like `parse_expression` but if multiple expressions are
581 delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created.
582 This method could also return a regular expression instead of a tuple
583 if no commas where found.
584
585 The default parsing mode is a full tuple. If `simplified` is `True`
586 only names and literals are parsed. The `no_condexpr` parameter is
587 forwarded to :meth:`parse_expression`.
Armin Ronacherfdf95302008-05-11 22:20:51 +0200588
589 Because tuples do not require delimiters and may end in a bogus comma
590 an extra hint is needed that marks the end of a tuple. For example
591 for loops support tuples between `for` and `in`. In that case the
592 `extra_end_rules` is set to ``['name:in']``.
Armin Ronachere614e882010-02-06 15:04:46 +0100593
594 `explicit_parentheses` is true if the parsing was triggered by an
595 expression in parentheses. This is used to figure out if an empty
596 tuple is a valid expression or not.
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200597 """
598 lineno = self.stream.current.lineno
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200599 if simplified:
Armin Ronacher2ee64bc2010-08-17 12:36:38 +0200600 parse = self.parse_primary
Armin Ronacher09c002e2008-05-10 22:21:30 +0200601 elif with_condexpr:
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200602 parse = self.parse_expression
Armin Ronacher09c002e2008-05-10 22:21:30 +0200603 else:
604 parse = lambda: self.parse_expression(with_condexpr=False)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200605 args = []
606 is_tuple = False
607 while 1:
608 if args:
609 self.stream.expect('comma')
Armin Ronacherfdf95302008-05-11 22:20:51 +0200610 if self.is_tuple_end(extra_end_rules):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200611 break
612 args.append(parse())
Ali Afshar272ca2a2009-01-05 12:14:14 +0100613 if self.stream.current.type == 'comma':
Armin Ronacherb5124e62008-04-25 00:36:14 +0200614 is_tuple = True
615 else:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200616 break
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200617 lineno = self.stream.current.lineno
Armin Ronachere614e882010-02-06 15:04:46 +0100618
619 if not is_tuple:
620 if args:
621 return args[0]
622
623 # if we don't have explicit parentheses, an empty tuple is
624 # not a valid expression. This would mean nothing (literally
625 # nothing) in the spot of an expression would be an empty
626 # tuple.
627 if not explicit_parentheses:
628 self.fail('Expected an expression, got \'%s\'' %
629 describe_token(self.stream.current))
630
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200631 return nodes.Tuple(args, 'load', lineno=lineno)
632
633 def parse_list(self):
634 token = self.stream.expect('lbracket')
635 items = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100636 while self.stream.current.type != 'rbracket':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200637 if items:
638 self.stream.expect('comma')
639 if self.stream.current.type == 'rbracket':
640 break
641 items.append(self.parse_expression())
642 self.stream.expect('rbracket')
643 return nodes.List(items, lineno=token.lineno)
644
645 def parse_dict(self):
646 token = self.stream.expect('lbrace')
647 items = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100648 while self.stream.current.type != 'rbrace':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200649 if items:
650 self.stream.expect('comma')
651 if self.stream.current.type == 'rbrace':
652 break
653 key = self.parse_expression()
654 self.stream.expect('colon')
655 value = self.parse_expression()
656 items.append(nodes.Pair(key, value, lineno=key.lineno))
657 self.stream.expect('rbrace')
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200658 return nodes.Dict(items, lineno=token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200659
660 def parse_postfix(self, node):
661 while 1:
662 token_type = self.stream.current.type
Ali Afshar272ca2a2009-01-05 12:14:14 +0100663 if token_type == 'dot' or token_type == 'lbracket':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200664 node = self.parse_subscript(node)
Armin Ronacher613912d2010-10-17 15:53:59 +0200665 # calls are valid both after postfix expressions (getattr
666 # and getitem) as well as filters and tests
Ali Afshar272ca2a2009-01-05 12:14:14 +0100667 elif token_type == 'lparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200668 node = self.parse_call(node)
Armin Ronacher613912d2010-10-17 15:53:59 +0200669 else:
670 break
671 return node
672
673 def parse_filter_expr(self, node):
674 while 1:
675 token_type = self.stream.current.type
676 if token_type == 'pipe':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200677 node = self.parse_filter(node)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100678 elif token_type == 'name' and self.stream.current.value == 'is':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200679 node = self.parse_test(node)
Armin Ronacher613912d2010-10-17 15:53:59 +0200680 # calls are valid both after postfix expressions (getattr
681 # and getitem) as well as filters and tests
682 elif token_type == 'lparen':
683 node = self.parse_call(node)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200684 else:
685 break
686 return node
687
688 def parse_subscript(self, node):
Armin Ronacherbd357722009-08-05 20:25:06 +0200689 token = next(self.stream)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100690 if token.type == 'dot':
Armin Ronachere791c2a2008-04-07 18:39:54 +0200691 attr_token = self.stream.current
Armin Ronacherbd357722009-08-05 20:25:06 +0200692 next(self.stream)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100693 if attr_token.type == 'name':
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200694 return nodes.Getattr(node, attr_token.value, 'load',
695 lineno=token.lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100696 elif attr_token.type != 'integer':
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200697 self.fail('expected name or number', attr_token.lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200698 arg = nodes.Const(attr_token.value, lineno=attr_token.lineno)
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200699 return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100700 if token.type == 'lbracket':
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200701 priority_on_attribute = False
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':
Armin Ronacherbd357722009-08-05 20:25:06 +0200719 next(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
Armin Ronacherbd357722009-08-05 20:25:06 +0200725 next(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':
Armin Ronacherbd357722009-08-05 20:25:06 +0200736 next(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)
Armin Ronacherbd357722009-08-05 20:25:06 +0200766 next(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)
Armin Ronacherbd357722009-08-05 20:25:06 +0200770 next(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:
Armin Ronacherbd357722009-08-05 20:25:06 +0200796 next(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':
Armin Ronacherbd357722009-08-05 20:25:06 +0200800 next(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):
Armin Ronacherbd357722009-08-05 20:25:06 +0200814 token = next(self.stream)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200815 if self.stream.current.test('name:not'):
Armin Ronacherbd357722009-08-05 20:25:06 +0200816 next(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':
Armin Ronacherbd357722009-08-05 20:25:06 +0200822 next(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))
865 next(self.stream)
866 elif token.type == 'variable_begin':
867 next(self.stream)
868 add_data(self.parse_tuple(with_condexpr=True))
869 self.stream.expect('variable_end')
870 elif token.type == 'block_begin':
871 flush_data()
872 next(self.stream)
873 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