blob: 1f5e12a721c71af9fd2b00e719ec04f89cf783b4 [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 Ronacher023b5e92008-05-08 11:03:10 +020037 for extension in environment.extensions.itervalues():
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:
373 target = self.parse_primary(with_postfix=False)
374 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
528 def parse_unary(self):
529 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 Ronacher82b3f3d2008-03-31 20:01:08 +0200533 node = self.parse_unary()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200534 return nodes.Neg(node, lineno=lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100535 if token_type == 'add':
Armin Ronacherbd357722009-08-05 20:25:06 +0200536 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200537 node = self.parse_unary()
538 return nodes.Pos(node, lineno=lineno)
539 return self.parse_primary()
540
Armin Ronacher09c002e2008-05-10 22:21:30 +0200541 def parse_primary(self, with_postfix=True):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200542 token = self.stream.current
Ali Afshar272ca2a2009-01-05 12:14:14 +0100543 if token.type == 'name':
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200544 if token.value in ('true', 'false', 'True', 'False'):
545 node = nodes.Const(token.value in ('true', 'True'),
546 lineno=token.lineno)
547 elif token.value in ('none', 'None'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200548 node = nodes.Const(None, lineno=token.lineno)
549 else:
550 node = nodes.Name(token.value, 'load', lineno=token.lineno)
Armin Ronacherbd357722009-08-05 20:25:06 +0200551 next(self.stream)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100552 elif token.type == 'string':
Armin Ronacherbd357722009-08-05 20:25:06 +0200553 next(self.stream)
Armin Ronacher4778bda2008-06-22 12:48:37 +0200554 buf = [token.value]
555 lineno = token.lineno
Ali Afshar272ca2a2009-01-05 12:14:14 +0100556 while self.stream.current.type == 'string':
Armin Ronacher4778bda2008-06-22 12:48:37 +0200557 buf.append(self.stream.current.value)
Armin Ronacherbd357722009-08-05 20:25:06 +0200558 next(self.stream)
Armin Ronacher4778bda2008-06-22 12:48:37 +0200559 node = nodes.Const(''.join(buf), lineno=lineno)
560 elif token.type in ('integer', 'float'):
Armin Ronacherbd357722009-08-05 20:25:06 +0200561 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200562 node = nodes.Const(token.value, lineno=token.lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100563 elif token.type == 'lparen':
Armin Ronacherbd357722009-08-05 20:25:06 +0200564 next(self.stream)
Armin Ronachere614e882010-02-06 15:04:46 +0100565 node = self.parse_tuple(explicit_parentheses=True)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200566 self.stream.expect('rparen')
Ali Afshar272ca2a2009-01-05 12:14:14 +0100567 elif token.type == 'lbracket':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200568 node = self.parse_list()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100569 elif token.type == 'lbrace':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200570 node = self.parse_dict()
571 else:
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100572 self.fail("unexpected '%s'" % describe_token(token), token.lineno)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200573 if with_postfix:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200574 node = self.parse_postfix(node)
575 return node
576
Armin Ronacherfdf95302008-05-11 22:20:51 +0200577 def parse_tuple(self, simplified=False, with_condexpr=True,
Armin Ronachere614e882010-02-06 15:04:46 +0100578 extra_end_rules=None, explicit_parentheses=False):
Armin Ronacher023b5e92008-05-08 11:03:10 +0200579 """Works like `parse_expression` but if multiple expressions are
580 delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created.
581 This method could also return a regular expression instead of a tuple
582 if no commas where found.
583
584 The default parsing mode is a full tuple. If `simplified` is `True`
585 only names and literals are parsed. The `no_condexpr` parameter is
586 forwarded to :meth:`parse_expression`.
Armin Ronacherfdf95302008-05-11 22:20:51 +0200587
588 Because tuples do not require delimiters and may end in a bogus comma
589 an extra hint is needed that marks the end of a tuple. For example
590 for loops support tuples between `for` and `in`. In that case the
591 `extra_end_rules` is set to ``['name:in']``.
Armin Ronachere614e882010-02-06 15:04:46 +0100592
593 `explicit_parentheses` is true if the parsing was triggered by an
594 expression in parentheses. This is used to figure out if an empty
595 tuple is a valid expression or not.
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200596 """
597 lineno = self.stream.current.lineno
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200598 if simplified:
Armin Ronacher09c002e2008-05-10 22:21:30 +0200599 parse = lambda: self.parse_primary(with_postfix=False)
600 elif with_condexpr:
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200601 parse = self.parse_expression
Armin Ronacher09c002e2008-05-10 22:21:30 +0200602 else:
603 parse = lambda: self.parse_expression(with_condexpr=False)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200604 args = []
605 is_tuple = False
606 while 1:
607 if args:
608 self.stream.expect('comma')
Armin Ronacherfdf95302008-05-11 22:20:51 +0200609 if self.is_tuple_end(extra_end_rules):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200610 break
611 args.append(parse())
Ali Afshar272ca2a2009-01-05 12:14:14 +0100612 if self.stream.current.type == 'comma':
Armin Ronacherb5124e62008-04-25 00:36:14 +0200613 is_tuple = True
614 else:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200615 break
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200616 lineno = self.stream.current.lineno
Armin Ronachere614e882010-02-06 15:04:46 +0100617
618 if not is_tuple:
619 if args:
620 return args[0]
621
622 # if we don't have explicit parentheses, an empty tuple is
623 # not a valid expression. This would mean nothing (literally
624 # nothing) in the spot of an expression would be an empty
625 # tuple.
626 if not explicit_parentheses:
627 self.fail('Expected an expression, got \'%s\'' %
628 describe_token(self.stream.current))
629
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200630 return nodes.Tuple(args, 'load', lineno=lineno)
631
632 def parse_list(self):
633 token = self.stream.expect('lbracket')
634 items = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100635 while self.stream.current.type != 'rbracket':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200636 if items:
637 self.stream.expect('comma')
638 if self.stream.current.type == 'rbracket':
639 break
640 items.append(self.parse_expression())
641 self.stream.expect('rbracket')
642 return nodes.List(items, lineno=token.lineno)
643
644 def parse_dict(self):
645 token = self.stream.expect('lbrace')
646 items = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100647 while self.stream.current.type != 'rbrace':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200648 if items:
649 self.stream.expect('comma')
650 if self.stream.current.type == 'rbrace':
651 break
652 key = self.parse_expression()
653 self.stream.expect('colon')
654 value = self.parse_expression()
655 items.append(nodes.Pair(key, value, lineno=key.lineno))
656 self.stream.expect('rbrace')
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200657 return nodes.Dict(items, lineno=token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200658
659 def parse_postfix(self, node):
660 while 1:
661 token_type = self.stream.current.type
Ali Afshar272ca2a2009-01-05 12:14:14 +0100662 if token_type == 'dot' or token_type == 'lbracket':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200663 node = self.parse_subscript(node)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100664 elif token_type == 'lparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200665 node = self.parse_call(node)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100666 elif token_type == 'pipe':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200667 node = self.parse_filter(node)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100668 elif token_type == 'name' and self.stream.current.value == 'is':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200669 node = self.parse_test(node)
670 else:
671 break
672 return node
673
674 def parse_subscript(self, node):
Armin Ronacherbd357722009-08-05 20:25:06 +0200675 token = next(self.stream)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100676 if token.type == 'dot':
Armin Ronachere791c2a2008-04-07 18:39:54 +0200677 attr_token = self.stream.current
Armin Ronacherbd357722009-08-05 20:25:06 +0200678 next(self.stream)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100679 if attr_token.type == 'name':
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200680 return nodes.Getattr(node, attr_token.value, 'load',
681 lineno=token.lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100682 elif attr_token.type != 'integer':
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200683 self.fail('expected name or number', attr_token.lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200684 arg = nodes.Const(attr_token.value, lineno=attr_token.lineno)
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200685 return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100686 if token.type == 'lbracket':
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200687 priority_on_attribute = False
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200688 args = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100689 while self.stream.current.type != 'rbracket':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200690 if args:
691 self.stream.expect('comma')
692 args.append(self.parse_subscribed())
693 self.stream.expect('rbracket')
694 if len(args) == 1:
695 arg = args[0]
696 else:
Armin Ronacheree2d3c42009-02-05 23:13:15 +0100697 arg = nodes.Tuple(args, 'load', lineno=token.lineno)
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200698 return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
699 self.fail('expected subscript expression', self.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200700
701 def parse_subscribed(self):
702 lineno = self.stream.current.lineno
703
Ali Afshar272ca2a2009-01-05 12:14:14 +0100704 if self.stream.current.type == 'colon':
Armin Ronacherbd357722009-08-05 20:25:06 +0200705 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200706 args = [None]
707 else:
708 node = self.parse_expression()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100709 if self.stream.current.type != 'colon':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200710 return node
Armin Ronacherbd357722009-08-05 20:25:06 +0200711 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200712 args = [node]
713
Ali Afshar272ca2a2009-01-05 12:14:14 +0100714 if self.stream.current.type == 'colon':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200715 args.append(None)
716 elif self.stream.current.type not in ('rbracket', 'comma'):
717 args.append(self.parse_expression())
718 else:
719 args.append(None)
720
Ali Afshar272ca2a2009-01-05 12:14:14 +0100721 if self.stream.current.type == 'colon':
Armin Ronacherbd357722009-08-05 20:25:06 +0200722 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200723 if self.stream.current.type not in ('rbracket', 'comma'):
724 args.append(self.parse_expression())
725 else:
726 args.append(None)
727 else:
728 args.append(None)
729
730 return nodes.Slice(lineno=lineno, *args)
731
732 def parse_call(self, node):
733 token = self.stream.expect('lparen')
734 args = []
735 kwargs = []
736 dyn_args = dyn_kwargs = None
737 require_comma = False
738
739 def ensure(expr):
740 if not expr:
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200741 self.fail('invalid syntax for function call expression',
742 token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200743
Ali Afshar272ca2a2009-01-05 12:14:14 +0100744 while self.stream.current.type != 'rparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200745 if require_comma:
746 self.stream.expect('comma')
747 # support for trailing comma
Ali Afshar272ca2a2009-01-05 12:14:14 +0100748 if self.stream.current.type == 'rparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200749 break
Ali Afshar272ca2a2009-01-05 12:14:14 +0100750 if self.stream.current.type == 'mul':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200751 ensure(dyn_args is None and dyn_kwargs is None)
Armin Ronacherbd357722009-08-05 20:25:06 +0200752 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200753 dyn_args = self.parse_expression()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100754 elif self.stream.current.type == 'pow':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200755 ensure(dyn_kwargs is None)
Armin Ronacherbd357722009-08-05 20:25:06 +0200756 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200757 dyn_kwargs = self.parse_expression()
758 else:
759 ensure(dyn_args is None and dyn_kwargs is None)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100760 if self.stream.current.type == 'name' and \
761 self.stream.look().type == 'assign':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200762 key = self.stream.current.value
763 self.stream.skip(2)
Armin Ronacher0611e492008-04-25 23:44:14 +0200764 value = self.parse_expression()
765 kwargs.append(nodes.Keyword(key, value,
766 lineno=value.lineno))
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200767 else:
768 ensure(not kwargs)
769 args.append(self.parse_expression())
770
771 require_comma = True
772 self.stream.expect('rparen')
773
774 if node is None:
775 return args, kwargs, dyn_args, dyn_kwargs
776 return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs,
777 lineno=token.lineno)
778
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200779 def parse_filter(self, node, start_inline=False):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200780 while self.stream.current.type == 'pipe' or start_inline:
781 if not start_inline:
Armin Ronacherbd357722009-08-05 20:25:06 +0200782 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200783 token = self.stream.expect('name')
Armin Ronacherb9e78752008-05-10 23:36:28 +0200784 name = token.value
Ali Afshar272ca2a2009-01-05 12:14:14 +0100785 while self.stream.current.type == 'dot':
Armin Ronacherbd357722009-08-05 20:25:06 +0200786 next(self.stream)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200787 name += '.' + self.stream.expect('name').value
Ali Afshar272ca2a2009-01-05 12:14:14 +0100788 if self.stream.current.type == 'lparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200789 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
790 else:
791 args = []
792 kwargs = []
793 dyn_args = dyn_kwargs = None
Armin Ronacherb9e78752008-05-10 23:36:28 +0200794 node = nodes.Filter(node, name, args, kwargs, dyn_args,
Armin Ronacherd55ab532008-04-09 16:13:39 +0200795 dyn_kwargs, lineno=token.lineno)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200796 start_inline = False
Armin Ronacherd55ab532008-04-09 16:13:39 +0200797 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200798
799 def parse_test(self, node):
Armin Ronacherbd357722009-08-05 20:25:06 +0200800 token = next(self.stream)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200801 if self.stream.current.test('name:not'):
Armin Ronacherbd357722009-08-05 20:25:06 +0200802 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200803 negated = True
804 else:
805 negated = False
806 name = self.stream.expect('name').value
Ali Afshar272ca2a2009-01-05 12:14:14 +0100807 while self.stream.current.type == 'dot':
Armin Ronacherbd357722009-08-05 20:25:06 +0200808 next(self.stream)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200809 name += '.' + self.stream.expect('name').value
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200810 dyn_args = dyn_kwargs = None
811 kwargs = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100812 if self.stream.current.type == 'lparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200813 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
814 elif self.stream.current.type in ('name', 'string', 'integer',
815 'float', 'lparen', 'lbracket',
Armin Ronachere3290ea2008-06-12 10:30:01 +0200816 'lbrace') and not \
817 self.stream.current.test_any('name:else', 'name:or',
818 'name:and'):
819 if self.stream.current.test('name:is'):
820 self.fail('You cannot chain multiple tests with is')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200821 args = [self.parse_expression()]
822 else:
823 args = []
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200824 node = nodes.Test(node, name, args, kwargs, dyn_args,
825 dyn_kwargs, lineno=token.lineno)
826 if negated:
Armin Ronacher9a822052008-04-17 18:44:07 +0200827 node = nodes.Not(node, lineno=token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200828 return node
829
830 def subparse(self, end_tokens=None):
831 body = []
832 data_buffer = []
833 add_data = data_buffer.append
834
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100835 if end_tokens is not None:
836 self._end_token_stack.append(end_tokens)
837
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200838 def flush_data():
839 if data_buffer:
840 lineno = data_buffer[0].lineno
841 body.append(nodes.Output(data_buffer[:], lineno=lineno))
842 del data_buffer[:]
843
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100844 try:
845 while self.stream:
846 token = self.stream.current
847 if token.type == 'data':
848 if token.value:
849 add_data(nodes.TemplateData(token.value,
850 lineno=token.lineno))
851 next(self.stream)
852 elif token.type == 'variable_begin':
853 next(self.stream)
854 add_data(self.parse_tuple(with_condexpr=True))
855 self.stream.expect('variable_end')
856 elif token.type == 'block_begin':
857 flush_data()
858 next(self.stream)
859 if end_tokens is not None and \
860 self.stream.current.test_any(*end_tokens):
861 return body
862 rv = self.parse_statement()
863 if isinstance(rv, list):
864 body.extend(rv)
865 else:
866 body.append(rv)
867 self.stream.expect('block_end')
Armin Ronacher023b5e92008-05-08 11:03:10 +0200868 else:
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100869 raise AssertionError('internal parsing error')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200870
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100871 flush_data()
872 finally:
873 if end_tokens is not None:
874 self._end_token_stack.pop()
875
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200876 return body
877
878 def parse(self):
879 """Parse the whole template into a `Template` node."""
Armin Ronacherd55ab532008-04-09 16:13:39 +0200880 result = nodes.Template(self.subparse(), lineno=1)
881 result.set_environment(self.environment)
882 return result