blob: fa1290c35a074a9ece104f6d42537a9c47ec969e [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))
57 currently_looking = ' or '.join("'%s'" % describe_token_expr(expr)
58 for expr in end_token_stack[-1])
59
60 if name is None:
61 message = ['Unexpected end of template.']
62 else:
63 message = ['Encountered unknown tag \'%s\'.' % name]
64
65 if name is not None and name in expected:
66 message.append('You probably made a nesting mistake. Jinja '
67 'is expecting this tag, but currently looking '
68 'for %s.' % currently_looking)
69 else:
70 message.append('Jinja was looking for the following tags: '
71 '%s.' % currently_looking)
72
73 if self._tag_stack:
74 message.append('The innermost block that needs to be '
75 'closed is \'%s\'.' % self._tag_stack[-1])
76
77 self.fail(' '.join(message), lineno)
78
79 def fail_unknown_tag(self, name, lineno=None):
80 """Called if the parser encounters an unknown tag. Tries to fail
81 with a human readable error message that could help to identify
82 the problem.
83 """
84 return self._fail_ut_eof(name, self._end_token_stack, lineno)
85
86 def fail_eof(self, end_tokens=None, lineno=None):
87 """Like fail_unknown_tag but for end of template situations."""
88 stack = list(self._end_token_stack)
89 if end_tokens is not None:
90 stack.append(end_tokens)
91 return self._fail_ut_eof(None, stack, lineno)
92
Armin Ronacherfdf95302008-05-11 22:20:51 +020093 def is_tuple_end(self, extra_end_rules=None):
Armin Ronacher115de2e2008-05-01 22:20:05 +020094 """Are we at the end of a tuple?"""
Armin Ronacherfdf95302008-05-11 22:20:51 +020095 if self.stream.current.type in ('variable_end', 'block_end', 'rparen'):
Armin Ronacher023b5e92008-05-08 11:03:10 +020096 return True
Armin Ronacherfdf95302008-05-11 22:20:51 +020097 elif extra_end_rules is not None:
98 return self.stream.current.test_any(extra_end_rules)
Armin Ronacher762079c2008-05-08 23:57:56 +020099 return False
100
Armin Ronacher023b5e92008-05-08 11:03:10 +0200101 def free_identifier(self, lineno=None):
102 """Return a new free identifier as :class:`~jinja2.nodes.InternalName`."""
103 self._last_identifier += 1
104 rv = object.__new__(nodes.InternalName)
105 nodes.Node.__init__(rv, 'fi%d' % self._last_identifier, lineno=lineno)
106 return rv
Armin Ronacher115de2e2008-05-01 22:20:05 +0200107
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200108 def parse_statement(self):
109 """Parse a single statement."""
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200110 token = self.stream.current
Ali Afshar272ca2a2009-01-05 12:14:14 +0100111 if token.type != 'name':
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200112 self.fail('tag name expected', token.lineno)
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100113 self._tag_stack.append(token.value)
114 pop_tag = True
115 try:
116 if token.value in _statement_keywords:
117 return getattr(self, 'parse_' + self.stream.current.value)()
118 if token.value == 'call':
119 return self.parse_call_block()
120 if token.value == 'filter':
121 return self.parse_filter_block()
122 ext = self.extensions.get(token.value)
123 if ext is not None:
124 return ext(self)
125
126 # did not work out, remove the token we pushed by accident
127 # from the stack so that the unknown tag fail function can
128 # produce a proper error message.
129 self._tag_stack.pop()
130 pop_tag = False
131 self.fail_unknown_tag(token.value, token.lineno)
132 finally:
133 if pop_tag:
134 self._tag_stack.pop()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200135
136 def parse_statements(self, end_tokens, drop_needle=False):
Armin Ronacherf59bac22008-04-20 13:11:43 +0200137 """Parse multiple statements into a list until one of the end tokens
138 is reached. This is used to parse the body of statements as it also
Armin Ronacher023b5e92008-05-08 11:03:10 +0200139 parses template data if appropriate. The parser checks first if the
140 current token is a colon and skips it if there is one. Then it checks
141 for the block end and parses until if one of the `end_tokens` is
142 reached. Per default the active token in the stream at the end of
143 the call is the matched end token. If this is not wanted `drop_needle`
144 can be set to `True` and the end token is removed.
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200145 """
146 # the first token may be a colon for python compatibility
Armin Ronacherfdf95302008-05-11 22:20:51 +0200147 self.stream.skip_if('colon')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200148
Armin Ronacher2b60fe52008-04-21 08:23:59 +0200149 # in the future it would be possible to add whole code sections
150 # by adding some sort of end of statement token and parsing those here.
151 self.stream.expect('block_end')
152 result = self.subparse(end_tokens)
153
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100154 # we reached the end of the template too early, the subparser
155 # does not check for this, so we do that now
156 if self.stream.current.type == 'eof':
157 self.fail_eof(end_tokens)
158
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200159 if drop_needle:
Armin Ronacherbd357722009-08-05 20:25:06 +0200160 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200161 return result
162
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200163 def parse_set(self):
164 """Parse an assign statement."""
Armin Ronacherbd357722009-08-05 20:25:06 +0200165 lineno = next(self.stream).lineno
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200166 target = self.parse_assign_target()
167 self.stream.expect('assign')
168 expr = self.parse_tuple()
169 return nodes.Assign(target, expr, lineno=lineno)
170
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200171 def parse_for(self):
172 """Parse a for loop."""
Armin Ronacher115de2e2008-05-01 22:20:05 +0200173 lineno = self.stream.expect('name:for').lineno
Armin Ronacherfdf95302008-05-11 22:20:51 +0200174 target = self.parse_assign_target(extra_end_rules=('name:in',))
Armin Ronacher115de2e2008-05-01 22:20:05 +0200175 self.stream.expect('name:in')
Armin Ronacherfdf95302008-05-11 22:20:51 +0200176 iter = self.parse_tuple(with_condexpr=False,
177 extra_end_rules=('name:recursive',))
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200178 test = None
Armin Ronacherfdf95302008-05-11 22:20:51 +0200179 if self.stream.skip_if('name:if'):
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200180 test = self.parse_expression()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200181 recursive = self.stream.skip_if('name:recursive')
Armin Ronacher115de2e2008-05-01 22:20:05 +0200182 body = self.parse_statements(('name:endfor', 'name:else'))
Armin Ronacherbd357722009-08-05 20:25:06 +0200183 if next(self.stream).value == 'endfor':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200184 else_ = []
185 else:
Armin Ronacher115de2e2008-05-01 22:20:05 +0200186 else_ = self.parse_statements(('name:endfor',), drop_needle=True)
Armin Ronacherfdf95302008-05-11 22:20:51 +0200187 return nodes.For(target, iter, body, else_, test,
188 recursive, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200189
190 def parse_if(self):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200191 """Parse an if construct."""
Armin Ronacher115de2e2008-05-01 22:20:05 +0200192 node = result = nodes.If(lineno=self.stream.expect('name:if').lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200193 while 1:
Armin Ronacher09c002e2008-05-10 22:21:30 +0200194 node.test = self.parse_tuple(with_condexpr=False)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200195 node.body = self.parse_statements(('name:elif', 'name:else',
196 'name:endif'))
Armin Ronacherbd357722009-08-05 20:25:06 +0200197 token = next(self.stream)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200198 if token.test('name:elif'):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200199 new_node = nodes.If(lineno=self.stream.current.lineno)
200 node.else_ = [new_node]
201 node = new_node
202 continue
Armin Ronacher115de2e2008-05-01 22:20:05 +0200203 elif token.test('name:else'):
204 node.else_ = self.parse_statements(('name:endif',),
Armin Ronachere791c2a2008-04-07 18:39:54 +0200205 drop_needle=True)
206 else:
207 node.else_ = []
208 break
209 return result
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200210
211 def parse_block(self):
Armin Ronacherbd357722009-08-05 20:25:06 +0200212 node = nodes.Block(lineno=next(self.stream).lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200213 node.name = self.stream.expect('name').value
Armin Ronacher74a0cd92009-02-19 15:56:53 +0100214 node.scoped = self.stream.skip_if('name:scoped')
Armin Ronacher115de2e2008-05-01 22:20:05 +0200215 node.body = self.parse_statements(('name:endblock',), drop_needle=True)
Armin Ronacherfd310492008-05-25 00:16:51 +0200216 self.stream.skip_if('name:' + node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200217 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200218
219 def parse_extends(self):
Armin Ronacherbd357722009-08-05 20:25:06 +0200220 node = nodes.Extends(lineno=next(self.stream).lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200221 node.template = self.parse_expression()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200222 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200223
Armin Ronacherea847c52008-05-02 20:04:32 +0200224 def parse_import_context(self, node, default):
Armin Ronachercda43df2008-05-03 17:10:05 +0200225 if self.stream.current.test_any('name:with', 'name:without') and \
Armin Ronacherea847c52008-05-02 20:04:32 +0200226 self.stream.look().test('name:context'):
Armin Ronacherbd357722009-08-05 20:25:06 +0200227 node.with_context = next(self.stream).value == 'with'
Armin Ronacherea847c52008-05-02 20:04:32 +0200228 self.stream.skip()
229 else:
230 node.with_context = default
231 return node
232
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200233 def parse_include(self):
Armin Ronacherbd357722009-08-05 20:25:06 +0200234 node = nodes.Include(lineno=next(self.stream).lineno)
Armin Ronacher0611e492008-04-25 23:44:14 +0200235 node.template = self.parse_expression()
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100236 if self.stream.current.test('name:ignore') and \
237 self.stream.look().test('name:missing'):
238 node.ignore_missing = True
239 self.stream.skip(2)
240 else:
241 node.ignore_missing = False
Armin Ronacherea847c52008-05-02 20:04:32 +0200242 return self.parse_import_context(node, True)
Armin Ronacher0611e492008-04-25 23:44:14 +0200243
244 def parse_import(self):
Armin Ronacherbd357722009-08-05 20:25:06 +0200245 node = nodes.Import(lineno=next(self.stream).lineno)
Armin Ronacher0611e492008-04-25 23:44:14 +0200246 node.template = self.parse_expression()
247 self.stream.expect('name:as')
Armin Ronacher09c002e2008-05-10 22:21:30 +0200248 node.target = self.parse_assign_target(name_only=True).name
Armin Ronacherea847c52008-05-02 20:04:32 +0200249 return self.parse_import_context(node, False)
Armin Ronacher0611e492008-04-25 23:44:14 +0200250
251 def parse_from(self):
Armin Ronacherbd357722009-08-05 20:25:06 +0200252 node = nodes.FromImport(lineno=next(self.stream).lineno)
Armin Ronacher0611e492008-04-25 23:44:14 +0200253 node.template = self.parse_expression()
Armin Ronacher115de2e2008-05-01 22:20:05 +0200254 self.stream.expect('name:import')
Armin Ronacher0611e492008-04-25 23:44:14 +0200255 node.names = []
Armin Ronacherea847c52008-05-02 20:04:32 +0200256
257 def parse_context():
258 if self.stream.current.value in ('with', 'without') and \
259 self.stream.look().test('name:context'):
Armin Ronacherbd357722009-08-05 20:25:06 +0200260 node.with_context = next(self.stream).value == 'with'
Armin Ronacherea847c52008-05-02 20:04:32 +0200261 self.stream.skip()
262 return True
263 return False
264
Armin Ronacher0611e492008-04-25 23:44:14 +0200265 while 1:
266 if node.names:
267 self.stream.expect('comma')
Ali Afshar272ca2a2009-01-05 12:14:14 +0100268 if self.stream.current.type == 'name':
Armin Ronacherea847c52008-05-02 20:04:32 +0200269 if parse_context():
270 break
Armin Ronacher09c002e2008-05-10 22:21:30 +0200271 target = self.parse_assign_target(name_only=True)
Armin Ronacher903d1682008-05-23 00:51:58 +0200272 if target.name.startswith('_'):
273 self.fail('names starting with an underline can not '
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200274 'be imported', target.lineno,
275 exc=TemplateAssertionError)
Armin Ronacherfdf95302008-05-11 22:20:51 +0200276 if self.stream.skip_if('name:as'):
Armin Ronacher09c002e2008-05-10 22:21:30 +0200277 alias = self.parse_assign_target(name_only=True)
278 node.names.append((target.name, alias.name))
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200279 else:
280 node.names.append(target.name)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100281 if parse_context() or self.stream.current.type != 'comma':
Armin Ronacher0611e492008-04-25 23:44:14 +0200282 break
283 else:
284 break
Armin Ronacherea847c52008-05-02 20:04:32 +0200285 if not hasattr(node, 'with_context'):
286 node.with_context = False
Armin Ronacherfdf95302008-05-11 22:20:51 +0200287 self.stream.skip_if('comma')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200288 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200289
Armin Ronacher71082072008-04-12 14:19:36 +0200290 def parse_signature(self, node):
291 node.args = args = []
292 node.defaults = defaults = []
293 self.stream.expect('lparen')
Ali Afshar272ca2a2009-01-05 12:14:14 +0100294 while self.stream.current.type != 'rparen':
Armin Ronacher71082072008-04-12 14:19:36 +0200295 if args:
296 self.stream.expect('comma')
Armin Ronacher09c002e2008-05-10 22:21:30 +0200297 arg = self.parse_assign_target(name_only=True)
Armin Ronachere9411b42008-05-15 16:22:07 +0200298 arg.set_ctx('param')
Armin Ronacherfdf95302008-05-11 22:20:51 +0200299 if self.stream.skip_if('assign'):
Armin Ronacher71082072008-04-12 14:19:36 +0200300 defaults.append(self.parse_expression())
301 args.append(arg)
302 self.stream.expect('rparen')
303
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200304 def parse_call_block(self):
Armin Ronacherbd357722009-08-05 20:25:06 +0200305 node = nodes.CallBlock(lineno=next(self.stream).lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100306 if self.stream.current.type == 'lparen':
Armin Ronacher71082072008-04-12 14:19:36 +0200307 self.parse_signature(node)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200308 else:
309 node.args = []
310 node.defaults = []
Armin Ronacher71082072008-04-12 14:19:36 +0200311
Armin Ronacher8edbe492008-04-10 20:43:43 +0200312 node.call = self.parse_expression()
313 if not isinstance(node.call, nodes.Call):
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200314 self.fail('expected call', node.lineno)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200315 node.body = self.parse_statements(('name:endcall',), drop_needle=True)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200316 return node
317
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200318 def parse_filter_block(self):
Armin Ronacherbd357722009-08-05 20:25:06 +0200319 node = nodes.FilterBlock(lineno=next(self.stream).lineno)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200320 node.filter = self.parse_filter(None, start_inline=True)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200321 node.body = self.parse_statements(('name:endfilter',),
322 drop_needle=True)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200323 return node
324
Armin Ronachere791c2a2008-04-07 18:39:54 +0200325 def parse_macro(self):
Armin Ronacherbd357722009-08-05 20:25:06 +0200326 node = nodes.Macro(lineno=next(self.stream).lineno)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200327 node.name = self.parse_assign_target(name_only=True).name
Armin Ronacher71082072008-04-12 14:19:36 +0200328 self.parse_signature(node)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200329 node.body = self.parse_statements(('name:endmacro',),
330 drop_needle=True)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200331 return node
332
333 def parse_print(self):
Armin Ronacherbd357722009-08-05 20:25:06 +0200334 node = nodes.Output(lineno=next(self.stream).lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200335 node.nodes = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100336 while self.stream.current.type != 'block_end':
Armin Ronachere791c2a2008-04-07 18:39:54 +0200337 if node.nodes:
338 self.stream.expect('comma')
339 node.nodes.append(self.parse_expression())
Armin Ronachere791c2a2008-04-07 18:39:54 +0200340 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200341
Armin Ronacherfdf95302008-05-11 22:20:51 +0200342 def parse_assign_target(self, with_tuple=True, name_only=False,
343 extra_end_rules=None):
Armin Ronacher09c002e2008-05-10 22:21:30 +0200344 """Parse an assignment target. As Jinja2 allows assignments to
345 tuples, this function can parse all allowed assignment targets. Per
346 default assignments to tuples are parsed, that can be disable however
347 by setting `with_tuple` to `False`. If only assignments to names are
Armin Ronacherfdf95302008-05-11 22:20:51 +0200348 wanted `name_only` can be set to `True`. The `extra_end_rules`
349 parameter is forwarded to the tuple parsing function.
Armin Ronacher09c002e2008-05-10 22:21:30 +0200350 """
351 if name_only:
352 token = self.stream.expect('name')
353 target = nodes.Name(token.value, 'store', lineno=token.lineno)
354 else:
355 if with_tuple:
Armin Ronacherfdf95302008-05-11 22:20:51 +0200356 target = self.parse_tuple(simplified=True,
357 extra_end_rules=extra_end_rules)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200358 else:
359 target = self.parse_primary(with_postfix=False)
360 target.set_ctx('store')
361 if not target.can_assign():
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200362 self.fail('can\'t assign to %r' % target.__class__.
363 __name__.lower(), target.lineno)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200364 return target
365
366 def parse_expression(self, with_condexpr=True):
Armin Ronacher023b5e92008-05-08 11:03:10 +0200367 """Parse an expression. Per default all expressions are parsed, if
Armin Ronacher09c002e2008-05-10 22:21:30 +0200368 the optional `with_condexpr` parameter is set to `False` conditional
Armin Ronacher023b5e92008-05-08 11:03:10 +0200369 expressions are not parsed.
370 """
Armin Ronacher09c002e2008-05-10 22:21:30 +0200371 if with_condexpr:
372 return self.parse_condexpr()
373 return self.parse_or()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200374
375 def parse_condexpr(self):
376 lineno = self.stream.current.lineno
377 expr1 = self.parse_or()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200378 while self.stream.skip_if('name:if'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200379 expr2 = self.parse_or()
Armin Ronacher547d0b62008-07-04 16:35:10 +0200380 if self.stream.skip_if('name:else'):
381 expr3 = self.parse_condexpr()
382 else:
383 expr3 = None
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200384 expr1 = nodes.CondExpr(expr2, expr1, expr3, lineno=lineno)
385 lineno = self.stream.current.lineno
386 return expr1
387
388 def parse_or(self):
389 lineno = self.stream.current.lineno
390 left = self.parse_and()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200391 while self.stream.skip_if('name:or'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200392 right = self.parse_and()
393 left = nodes.Or(left, right, lineno=lineno)
394 lineno = self.stream.current.lineno
395 return left
396
397 def parse_and(self):
398 lineno = self.stream.current.lineno
Armin Ronacherd89f0f32009-02-04 18:57:27 +0100399 left = self.parse_not()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200400 while self.stream.skip_if('name:and'):
Armin Ronacherd89f0f32009-02-04 18:57:27 +0100401 right = self.parse_not()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200402 left = nodes.And(left, right, lineno=lineno)
403 lineno = self.stream.current.lineno
404 return left
405
Armin Ronacherd89f0f32009-02-04 18:57:27 +0100406 def parse_not(self):
407 if self.stream.current.test('name:not'):
Armin Ronacherbd357722009-08-05 20:25:06 +0200408 lineno = next(self.stream).lineno
Armin Ronacherd89f0f32009-02-04 18:57:27 +0100409 return nodes.Not(self.parse_not(), lineno=lineno)
410 return self.parse_compare()
411
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200412 def parse_compare(self):
413 lineno = self.stream.current.lineno
414 expr = self.parse_add()
415 ops = []
416 while 1:
417 token_type = self.stream.current.type
418 if token_type in _compare_operators:
Armin Ronacherbd357722009-08-05 20:25:06 +0200419 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200420 ops.append(nodes.Operand(token_type, self.parse_add()))
Armin Ronacherfdf95302008-05-11 22:20:51 +0200421 elif self.stream.skip_if('name:in'):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200422 ops.append(nodes.Operand('in', self.parse_add()))
423 elif self.stream.current.test('name:not') and \
424 self.stream.look().test('name:in'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200425 self.stream.skip(2)
426 ops.append(nodes.Operand('notin', self.parse_add()))
427 else:
428 break
429 lineno = self.stream.current.lineno
430 if not ops:
431 return expr
432 return nodes.Compare(expr, ops, lineno=lineno)
433
434 def parse_add(self):
435 lineno = self.stream.current.lineno
436 left = self.parse_sub()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100437 while self.stream.current.type == 'add':
Armin Ronacherbd357722009-08-05 20:25:06 +0200438 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200439 right = self.parse_sub()
440 left = nodes.Add(left, right, lineno=lineno)
441 lineno = self.stream.current.lineno
442 return left
443
444 def parse_sub(self):
445 lineno = self.stream.current.lineno
446 left = self.parse_concat()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100447 while self.stream.current.type == 'sub':
Armin Ronacherbd357722009-08-05 20:25:06 +0200448 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200449 right = self.parse_concat()
450 left = nodes.Sub(left, right, lineno=lineno)
451 lineno = self.stream.current.lineno
452 return left
453
454 def parse_concat(self):
455 lineno = self.stream.current.lineno
456 args = [self.parse_mul()]
Ali Afshar272ca2a2009-01-05 12:14:14 +0100457 while self.stream.current.type == 'tilde':
Armin Ronacherbd357722009-08-05 20:25:06 +0200458 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200459 args.append(self.parse_mul())
460 if len(args) == 1:
461 return args[0]
462 return nodes.Concat(args, lineno=lineno)
463
464 def parse_mul(self):
465 lineno = self.stream.current.lineno
466 left = self.parse_div()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100467 while self.stream.current.type == 'mul':
Armin Ronacherbd357722009-08-05 20:25:06 +0200468 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200469 right = self.parse_div()
470 left = nodes.Mul(left, right, lineno=lineno)
471 lineno = self.stream.current.lineno
472 return left
473
474 def parse_div(self):
475 lineno = self.stream.current.lineno
476 left = self.parse_floordiv()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100477 while self.stream.current.type == 'div':
Armin Ronacherbd357722009-08-05 20:25:06 +0200478 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200479 right = self.parse_floordiv()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200480 left = nodes.Div(left, right, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200481 lineno = self.stream.current.lineno
482 return left
483
484 def parse_floordiv(self):
485 lineno = self.stream.current.lineno
486 left = self.parse_mod()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100487 while self.stream.current.type == 'floordiv':
Armin Ronacherbd357722009-08-05 20:25:06 +0200488 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200489 right = self.parse_mod()
490 left = nodes.FloorDiv(left, right, lineno=lineno)
491 lineno = self.stream.current.lineno
492 return left
493
494 def parse_mod(self):
495 lineno = self.stream.current.lineno
496 left = self.parse_pow()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100497 while self.stream.current.type == 'mod':
Armin Ronacherbd357722009-08-05 20:25:06 +0200498 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200499 right = self.parse_pow()
500 left = nodes.Mod(left, right, lineno=lineno)
501 lineno = self.stream.current.lineno
502 return left
503
504 def parse_pow(self):
505 lineno = self.stream.current.lineno
506 left = self.parse_unary()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100507 while self.stream.current.type == 'pow':
Armin Ronacherbd357722009-08-05 20:25:06 +0200508 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200509 right = self.parse_unary()
510 left = nodes.Pow(left, right, lineno=lineno)
511 lineno = self.stream.current.lineno
512 return left
513
514 def parse_unary(self):
515 token_type = self.stream.current.type
516 lineno = self.stream.current.lineno
Ali Afshar272ca2a2009-01-05 12:14:14 +0100517 if token_type == 'sub':
Armin Ronacherbd357722009-08-05 20:25:06 +0200518 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200519 node = self.parse_unary()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200520 return nodes.Neg(node, lineno=lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100521 if token_type == 'add':
Armin Ronacherbd357722009-08-05 20:25:06 +0200522 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200523 node = self.parse_unary()
524 return nodes.Pos(node, lineno=lineno)
525 return self.parse_primary()
526
Armin Ronacher09c002e2008-05-10 22:21:30 +0200527 def parse_primary(self, with_postfix=True):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200528 token = self.stream.current
Ali Afshar272ca2a2009-01-05 12:14:14 +0100529 if token.type == 'name':
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200530 if token.value in ('true', 'false', 'True', 'False'):
531 node = nodes.Const(token.value in ('true', 'True'),
532 lineno=token.lineno)
533 elif token.value in ('none', 'None'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200534 node = nodes.Const(None, lineno=token.lineno)
535 else:
536 node = nodes.Name(token.value, 'load', lineno=token.lineno)
Armin Ronacherbd357722009-08-05 20:25:06 +0200537 next(self.stream)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100538 elif token.type == 'string':
Armin Ronacherbd357722009-08-05 20:25:06 +0200539 next(self.stream)
Armin Ronacher4778bda2008-06-22 12:48:37 +0200540 buf = [token.value]
541 lineno = token.lineno
Ali Afshar272ca2a2009-01-05 12:14:14 +0100542 while self.stream.current.type == 'string':
Armin Ronacher4778bda2008-06-22 12:48:37 +0200543 buf.append(self.stream.current.value)
Armin Ronacherbd357722009-08-05 20:25:06 +0200544 next(self.stream)
Armin Ronacher4778bda2008-06-22 12:48:37 +0200545 node = nodes.Const(''.join(buf), lineno=lineno)
546 elif token.type in ('integer', 'float'):
Armin Ronacherbd357722009-08-05 20:25:06 +0200547 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200548 node = nodes.Const(token.value, lineno=token.lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100549 elif token.type == 'lparen':
Armin Ronacherbd357722009-08-05 20:25:06 +0200550 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200551 node = self.parse_tuple()
552 self.stream.expect('rparen')
Ali Afshar272ca2a2009-01-05 12:14:14 +0100553 elif token.type == 'lbracket':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200554 node = self.parse_list()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100555 elif token.type == 'lbrace':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200556 node = self.parse_dict()
557 else:
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100558 self.fail("unexpected '%s'" % describe_token(token), token.lineno)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200559 if with_postfix:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200560 node = self.parse_postfix(node)
561 return node
562
Armin Ronacherfdf95302008-05-11 22:20:51 +0200563 def parse_tuple(self, simplified=False, with_condexpr=True,
564 extra_end_rules=None):
Armin Ronacher023b5e92008-05-08 11:03:10 +0200565 """Works like `parse_expression` but if multiple expressions are
566 delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created.
567 This method could also return a regular expression instead of a tuple
568 if no commas where found.
569
570 The default parsing mode is a full tuple. If `simplified` is `True`
571 only names and literals are parsed. The `no_condexpr` parameter is
572 forwarded to :meth:`parse_expression`.
Armin Ronacherfdf95302008-05-11 22:20:51 +0200573
574 Because tuples do not require delimiters and may end in a bogus comma
575 an extra hint is needed that marks the end of a tuple. For example
576 for loops support tuples between `for` and `in`. In that case the
577 `extra_end_rules` is set to ``['name:in']``.
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200578 """
579 lineno = self.stream.current.lineno
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200580 if simplified:
Armin Ronacher09c002e2008-05-10 22:21:30 +0200581 parse = lambda: self.parse_primary(with_postfix=False)
582 elif with_condexpr:
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200583 parse = self.parse_expression
Armin Ronacher09c002e2008-05-10 22:21:30 +0200584 else:
585 parse = lambda: self.parse_expression(with_condexpr=False)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200586 args = []
587 is_tuple = False
588 while 1:
589 if args:
590 self.stream.expect('comma')
Armin Ronacherfdf95302008-05-11 22:20:51 +0200591 if self.is_tuple_end(extra_end_rules):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200592 break
593 args.append(parse())
Ali Afshar272ca2a2009-01-05 12:14:14 +0100594 if self.stream.current.type == 'comma':
Armin Ronacherb5124e62008-04-25 00:36:14 +0200595 is_tuple = True
596 else:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200597 break
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200598 lineno = self.stream.current.lineno
599 if not is_tuple and args:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200600 return args[0]
601 return nodes.Tuple(args, 'load', lineno=lineno)
602
603 def parse_list(self):
604 token = self.stream.expect('lbracket')
605 items = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100606 while self.stream.current.type != 'rbracket':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200607 if items:
608 self.stream.expect('comma')
609 if self.stream.current.type == 'rbracket':
610 break
611 items.append(self.parse_expression())
612 self.stream.expect('rbracket')
613 return nodes.List(items, lineno=token.lineno)
614
615 def parse_dict(self):
616 token = self.stream.expect('lbrace')
617 items = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100618 while self.stream.current.type != 'rbrace':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200619 if items:
620 self.stream.expect('comma')
621 if self.stream.current.type == 'rbrace':
622 break
623 key = self.parse_expression()
624 self.stream.expect('colon')
625 value = self.parse_expression()
626 items.append(nodes.Pair(key, value, lineno=key.lineno))
627 self.stream.expect('rbrace')
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200628 return nodes.Dict(items, lineno=token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200629
630 def parse_postfix(self, node):
631 while 1:
632 token_type = self.stream.current.type
Ali Afshar272ca2a2009-01-05 12:14:14 +0100633 if token_type == 'dot' or token_type == 'lbracket':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200634 node = self.parse_subscript(node)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100635 elif token_type == 'lparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200636 node = self.parse_call(node)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100637 elif token_type == 'pipe':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200638 node = self.parse_filter(node)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100639 elif token_type == 'name' and self.stream.current.value == 'is':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200640 node = self.parse_test(node)
641 else:
642 break
643 return node
644
645 def parse_subscript(self, node):
Armin Ronacherbd357722009-08-05 20:25:06 +0200646 token = next(self.stream)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100647 if token.type == 'dot':
Armin Ronachere791c2a2008-04-07 18:39:54 +0200648 attr_token = self.stream.current
Armin Ronacherbd357722009-08-05 20:25:06 +0200649 next(self.stream)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100650 if attr_token.type == 'name':
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200651 return nodes.Getattr(node, attr_token.value, 'load',
652 lineno=token.lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100653 elif attr_token.type != 'integer':
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200654 self.fail('expected name or number', attr_token.lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200655 arg = nodes.Const(attr_token.value, lineno=attr_token.lineno)
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200656 return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100657 if token.type == 'lbracket':
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200658 priority_on_attribute = False
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200659 args = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100660 while self.stream.current.type != 'rbracket':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200661 if args:
662 self.stream.expect('comma')
663 args.append(self.parse_subscribed())
664 self.stream.expect('rbracket')
665 if len(args) == 1:
666 arg = args[0]
667 else:
Armin Ronacheree2d3c42009-02-05 23:13:15 +0100668 arg = nodes.Tuple(args, 'load', lineno=token.lineno)
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200669 return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
670 self.fail('expected subscript expression', self.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200671
672 def parse_subscribed(self):
673 lineno = self.stream.current.lineno
674
Ali Afshar272ca2a2009-01-05 12:14:14 +0100675 if self.stream.current.type == 'colon':
Armin Ronacherbd357722009-08-05 20:25:06 +0200676 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200677 args = [None]
678 else:
679 node = self.parse_expression()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100680 if self.stream.current.type != 'colon':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200681 return node
Armin Ronacherbd357722009-08-05 20:25:06 +0200682 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200683 args = [node]
684
Ali Afshar272ca2a2009-01-05 12:14:14 +0100685 if self.stream.current.type == 'colon':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200686 args.append(None)
687 elif self.stream.current.type not in ('rbracket', 'comma'):
688 args.append(self.parse_expression())
689 else:
690 args.append(None)
691
Ali Afshar272ca2a2009-01-05 12:14:14 +0100692 if self.stream.current.type == 'colon':
Armin Ronacherbd357722009-08-05 20:25:06 +0200693 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200694 if self.stream.current.type not in ('rbracket', 'comma'):
695 args.append(self.parse_expression())
696 else:
697 args.append(None)
698 else:
699 args.append(None)
700
701 return nodes.Slice(lineno=lineno, *args)
702
703 def parse_call(self, node):
704 token = self.stream.expect('lparen')
705 args = []
706 kwargs = []
707 dyn_args = dyn_kwargs = None
708 require_comma = False
709
710 def ensure(expr):
711 if not expr:
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200712 self.fail('invalid syntax for function call expression',
713 token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200714
Ali Afshar272ca2a2009-01-05 12:14:14 +0100715 while self.stream.current.type != 'rparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200716 if require_comma:
717 self.stream.expect('comma')
718 # support for trailing comma
Ali Afshar272ca2a2009-01-05 12:14:14 +0100719 if self.stream.current.type == 'rparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200720 break
Ali Afshar272ca2a2009-01-05 12:14:14 +0100721 if self.stream.current.type == 'mul':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200722 ensure(dyn_args is None and dyn_kwargs is None)
Armin Ronacherbd357722009-08-05 20:25:06 +0200723 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200724 dyn_args = self.parse_expression()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100725 elif self.stream.current.type == 'pow':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200726 ensure(dyn_kwargs is None)
Armin Ronacherbd357722009-08-05 20:25:06 +0200727 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200728 dyn_kwargs = self.parse_expression()
729 else:
730 ensure(dyn_args is None and dyn_kwargs is None)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100731 if self.stream.current.type == 'name' and \
732 self.stream.look().type == 'assign':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200733 key = self.stream.current.value
734 self.stream.skip(2)
Armin Ronacher0611e492008-04-25 23:44:14 +0200735 value = self.parse_expression()
736 kwargs.append(nodes.Keyword(key, value,
737 lineno=value.lineno))
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200738 else:
739 ensure(not kwargs)
740 args.append(self.parse_expression())
741
742 require_comma = True
743 self.stream.expect('rparen')
744
745 if node is None:
746 return args, kwargs, dyn_args, dyn_kwargs
747 return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs,
748 lineno=token.lineno)
749
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200750 def parse_filter(self, node, start_inline=False):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200751 while self.stream.current.type == 'pipe' or start_inline:
752 if not start_inline:
Armin Ronacherbd357722009-08-05 20:25:06 +0200753 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200754 token = self.stream.expect('name')
Armin Ronacherb9e78752008-05-10 23:36:28 +0200755 name = token.value
Ali Afshar272ca2a2009-01-05 12:14:14 +0100756 while self.stream.current.type == 'dot':
Armin Ronacherbd357722009-08-05 20:25:06 +0200757 next(self.stream)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200758 name += '.' + self.stream.expect('name').value
Ali Afshar272ca2a2009-01-05 12:14:14 +0100759 if self.stream.current.type == 'lparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200760 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
761 else:
762 args = []
763 kwargs = []
764 dyn_args = dyn_kwargs = None
Armin Ronacherb9e78752008-05-10 23:36:28 +0200765 node = nodes.Filter(node, name, args, kwargs, dyn_args,
Armin Ronacherd55ab532008-04-09 16:13:39 +0200766 dyn_kwargs, lineno=token.lineno)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200767 start_inline = False
Armin Ronacherd55ab532008-04-09 16:13:39 +0200768 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200769
770 def parse_test(self, node):
Armin Ronacherbd357722009-08-05 20:25:06 +0200771 token = next(self.stream)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200772 if self.stream.current.test('name:not'):
Armin Ronacherbd357722009-08-05 20:25:06 +0200773 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200774 negated = True
775 else:
776 negated = False
777 name = self.stream.expect('name').value
Ali Afshar272ca2a2009-01-05 12:14:14 +0100778 while self.stream.current.type == 'dot':
Armin Ronacherbd357722009-08-05 20:25:06 +0200779 next(self.stream)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200780 name += '.' + self.stream.expect('name').value
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200781 dyn_args = dyn_kwargs = None
782 kwargs = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100783 if self.stream.current.type == 'lparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200784 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
785 elif self.stream.current.type in ('name', 'string', 'integer',
786 'float', 'lparen', 'lbracket',
Armin Ronachere3290ea2008-06-12 10:30:01 +0200787 'lbrace') and not \
788 self.stream.current.test_any('name:else', 'name:or',
789 'name:and'):
790 if self.stream.current.test('name:is'):
791 self.fail('You cannot chain multiple tests with is')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200792 args = [self.parse_expression()]
793 else:
794 args = []
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200795 node = nodes.Test(node, name, args, kwargs, dyn_args,
796 dyn_kwargs, lineno=token.lineno)
797 if negated:
Armin Ronacher9a822052008-04-17 18:44:07 +0200798 node = nodes.Not(node, lineno=token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200799 return node
800
801 def subparse(self, end_tokens=None):
802 body = []
803 data_buffer = []
804 add_data = data_buffer.append
805
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100806 if end_tokens is not None:
807 self._end_token_stack.append(end_tokens)
808
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200809 def flush_data():
810 if data_buffer:
811 lineno = data_buffer[0].lineno
812 body.append(nodes.Output(data_buffer[:], lineno=lineno))
813 del data_buffer[:]
814
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100815 try:
816 while self.stream:
817 token = self.stream.current
818 if token.type == 'data':
819 if token.value:
820 add_data(nodes.TemplateData(token.value,
821 lineno=token.lineno))
822 next(self.stream)
823 elif token.type == 'variable_begin':
824 next(self.stream)
825 add_data(self.parse_tuple(with_condexpr=True))
826 self.stream.expect('variable_end')
827 elif token.type == 'block_begin':
828 flush_data()
829 next(self.stream)
830 if end_tokens is not None and \
831 self.stream.current.test_any(*end_tokens):
832 return body
833 rv = self.parse_statement()
834 if isinstance(rv, list):
835 body.extend(rv)
836 else:
837 body.append(rv)
838 self.stream.expect('block_end')
Armin Ronacher023b5e92008-05-08 11:03:10 +0200839 else:
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100840 raise AssertionError('internal parsing error')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200841
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100842 flush_data()
843 finally:
844 if end_tokens is not None:
845 self._end_token_stack.pop()
846
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200847 return body
848
849 def parse(self):
850 """Parse the whole template into a `Template` node."""
Armin Ronacherd55ab532008-04-09 16:13:39 +0200851 result = nodes.Template(self.subparse(), lineno=1)
852 result.set_environment(self.environment)
853 return result