blob: bc4925e4d445bbf2370310c122850f3aea3eae04 [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 Ronachere614e882010-02-06 15:04:46 +0100551 node = self.parse_tuple(explicit_parentheses=True)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200552 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,
Armin Ronachere614e882010-02-06 15:04:46 +0100564 extra_end_rules=None, explicit_parentheses=False):
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 Ronachere614e882010-02-06 15:04:46 +0100578
579 `explicit_parentheses` is true if the parsing was triggered by an
580 expression in parentheses. This is used to figure out if an empty
581 tuple is a valid expression or not.
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200582 """
583 lineno = self.stream.current.lineno
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200584 if simplified:
Armin Ronacher09c002e2008-05-10 22:21:30 +0200585 parse = lambda: self.parse_primary(with_postfix=False)
586 elif with_condexpr:
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200587 parse = self.parse_expression
Armin Ronacher09c002e2008-05-10 22:21:30 +0200588 else:
589 parse = lambda: self.parse_expression(with_condexpr=False)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200590 args = []
591 is_tuple = False
592 while 1:
593 if args:
594 self.stream.expect('comma')
Armin Ronacherfdf95302008-05-11 22:20:51 +0200595 if self.is_tuple_end(extra_end_rules):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200596 break
597 args.append(parse())
Ali Afshar272ca2a2009-01-05 12:14:14 +0100598 if self.stream.current.type == 'comma':
Armin Ronacherb5124e62008-04-25 00:36:14 +0200599 is_tuple = True
600 else:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200601 break
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200602 lineno = self.stream.current.lineno
Armin Ronachere614e882010-02-06 15:04:46 +0100603
604 if not is_tuple:
605 if args:
606 return args[0]
607
608 # if we don't have explicit parentheses, an empty tuple is
609 # not a valid expression. This would mean nothing (literally
610 # nothing) in the spot of an expression would be an empty
611 # tuple.
612 if not explicit_parentheses:
613 self.fail('Expected an expression, got \'%s\'' %
614 describe_token(self.stream.current))
615
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200616 return nodes.Tuple(args, 'load', lineno=lineno)
617
618 def parse_list(self):
619 token = self.stream.expect('lbracket')
620 items = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100621 while self.stream.current.type != 'rbracket':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200622 if items:
623 self.stream.expect('comma')
624 if self.stream.current.type == 'rbracket':
625 break
626 items.append(self.parse_expression())
627 self.stream.expect('rbracket')
628 return nodes.List(items, lineno=token.lineno)
629
630 def parse_dict(self):
631 token = self.stream.expect('lbrace')
632 items = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100633 while self.stream.current.type != 'rbrace':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200634 if items:
635 self.stream.expect('comma')
636 if self.stream.current.type == 'rbrace':
637 break
638 key = self.parse_expression()
639 self.stream.expect('colon')
640 value = self.parse_expression()
641 items.append(nodes.Pair(key, value, lineno=key.lineno))
642 self.stream.expect('rbrace')
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200643 return nodes.Dict(items, lineno=token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200644
645 def parse_postfix(self, node):
646 while 1:
647 token_type = self.stream.current.type
Ali Afshar272ca2a2009-01-05 12:14:14 +0100648 if token_type == 'dot' or token_type == 'lbracket':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200649 node = self.parse_subscript(node)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100650 elif token_type == 'lparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200651 node = self.parse_call(node)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100652 elif token_type == 'pipe':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200653 node = self.parse_filter(node)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100654 elif token_type == 'name' and self.stream.current.value == 'is':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200655 node = self.parse_test(node)
656 else:
657 break
658 return node
659
660 def parse_subscript(self, node):
Armin Ronacherbd357722009-08-05 20:25:06 +0200661 token = next(self.stream)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100662 if token.type == 'dot':
Armin Ronachere791c2a2008-04-07 18:39:54 +0200663 attr_token = self.stream.current
Armin Ronacherbd357722009-08-05 20:25:06 +0200664 next(self.stream)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100665 if attr_token.type == 'name':
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200666 return nodes.Getattr(node, attr_token.value, 'load',
667 lineno=token.lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100668 elif attr_token.type != 'integer':
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200669 self.fail('expected name or number', attr_token.lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200670 arg = nodes.Const(attr_token.value, lineno=attr_token.lineno)
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200671 return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100672 if token.type == 'lbracket':
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200673 priority_on_attribute = False
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200674 args = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100675 while self.stream.current.type != 'rbracket':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200676 if args:
677 self.stream.expect('comma')
678 args.append(self.parse_subscribed())
679 self.stream.expect('rbracket')
680 if len(args) == 1:
681 arg = args[0]
682 else:
Armin Ronacheree2d3c42009-02-05 23:13:15 +0100683 arg = nodes.Tuple(args, 'load', lineno=token.lineno)
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200684 return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
685 self.fail('expected subscript expression', self.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200686
687 def parse_subscribed(self):
688 lineno = self.stream.current.lineno
689
Ali Afshar272ca2a2009-01-05 12:14:14 +0100690 if self.stream.current.type == 'colon':
Armin Ronacherbd357722009-08-05 20:25:06 +0200691 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200692 args = [None]
693 else:
694 node = self.parse_expression()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100695 if self.stream.current.type != 'colon':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200696 return node
Armin Ronacherbd357722009-08-05 20:25:06 +0200697 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200698 args = [node]
699
Ali Afshar272ca2a2009-01-05 12:14:14 +0100700 if self.stream.current.type == 'colon':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200701 args.append(None)
702 elif self.stream.current.type not in ('rbracket', 'comma'):
703 args.append(self.parse_expression())
704 else:
705 args.append(None)
706
Ali Afshar272ca2a2009-01-05 12:14:14 +0100707 if self.stream.current.type == 'colon':
Armin Ronacherbd357722009-08-05 20:25:06 +0200708 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200709 if self.stream.current.type not in ('rbracket', 'comma'):
710 args.append(self.parse_expression())
711 else:
712 args.append(None)
713 else:
714 args.append(None)
715
716 return nodes.Slice(lineno=lineno, *args)
717
718 def parse_call(self, node):
719 token = self.stream.expect('lparen')
720 args = []
721 kwargs = []
722 dyn_args = dyn_kwargs = None
723 require_comma = False
724
725 def ensure(expr):
726 if not expr:
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200727 self.fail('invalid syntax for function call expression',
728 token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200729
Ali Afshar272ca2a2009-01-05 12:14:14 +0100730 while self.stream.current.type != 'rparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200731 if require_comma:
732 self.stream.expect('comma')
733 # support for trailing comma
Ali Afshar272ca2a2009-01-05 12:14:14 +0100734 if self.stream.current.type == 'rparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200735 break
Ali Afshar272ca2a2009-01-05 12:14:14 +0100736 if self.stream.current.type == 'mul':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200737 ensure(dyn_args is None and dyn_kwargs is None)
Armin Ronacherbd357722009-08-05 20:25:06 +0200738 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200739 dyn_args = self.parse_expression()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100740 elif self.stream.current.type == 'pow':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200741 ensure(dyn_kwargs is None)
Armin Ronacherbd357722009-08-05 20:25:06 +0200742 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200743 dyn_kwargs = self.parse_expression()
744 else:
745 ensure(dyn_args is None and dyn_kwargs is None)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100746 if self.stream.current.type == 'name' and \
747 self.stream.look().type == 'assign':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200748 key = self.stream.current.value
749 self.stream.skip(2)
Armin Ronacher0611e492008-04-25 23:44:14 +0200750 value = self.parse_expression()
751 kwargs.append(nodes.Keyword(key, value,
752 lineno=value.lineno))
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200753 else:
754 ensure(not kwargs)
755 args.append(self.parse_expression())
756
757 require_comma = True
758 self.stream.expect('rparen')
759
760 if node is None:
761 return args, kwargs, dyn_args, dyn_kwargs
762 return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs,
763 lineno=token.lineno)
764
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200765 def parse_filter(self, node, start_inline=False):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200766 while self.stream.current.type == 'pipe' or start_inline:
767 if not start_inline:
Armin Ronacherbd357722009-08-05 20:25:06 +0200768 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200769 token = self.stream.expect('name')
Armin Ronacherb9e78752008-05-10 23:36:28 +0200770 name = token.value
Ali Afshar272ca2a2009-01-05 12:14:14 +0100771 while self.stream.current.type == 'dot':
Armin Ronacherbd357722009-08-05 20:25:06 +0200772 next(self.stream)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200773 name += '.' + self.stream.expect('name').value
Ali Afshar272ca2a2009-01-05 12:14:14 +0100774 if self.stream.current.type == 'lparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200775 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
776 else:
777 args = []
778 kwargs = []
779 dyn_args = dyn_kwargs = None
Armin Ronacherb9e78752008-05-10 23:36:28 +0200780 node = nodes.Filter(node, name, args, kwargs, dyn_args,
Armin Ronacherd55ab532008-04-09 16:13:39 +0200781 dyn_kwargs, lineno=token.lineno)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200782 start_inline = False
Armin Ronacherd55ab532008-04-09 16:13:39 +0200783 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200784
785 def parse_test(self, node):
Armin Ronacherbd357722009-08-05 20:25:06 +0200786 token = next(self.stream)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200787 if self.stream.current.test('name:not'):
Armin Ronacherbd357722009-08-05 20:25:06 +0200788 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200789 negated = True
790 else:
791 negated = False
792 name = self.stream.expect('name').value
Ali Afshar272ca2a2009-01-05 12:14:14 +0100793 while self.stream.current.type == 'dot':
Armin Ronacherbd357722009-08-05 20:25:06 +0200794 next(self.stream)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200795 name += '.' + self.stream.expect('name').value
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200796 dyn_args = dyn_kwargs = None
797 kwargs = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100798 if self.stream.current.type == 'lparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200799 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
800 elif self.stream.current.type in ('name', 'string', 'integer',
801 'float', 'lparen', 'lbracket',
Armin Ronachere3290ea2008-06-12 10:30:01 +0200802 'lbrace') and not \
803 self.stream.current.test_any('name:else', 'name:or',
804 'name:and'):
805 if self.stream.current.test('name:is'):
806 self.fail('You cannot chain multiple tests with is')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200807 args = [self.parse_expression()]
808 else:
809 args = []
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200810 node = nodes.Test(node, name, args, kwargs, dyn_args,
811 dyn_kwargs, lineno=token.lineno)
812 if negated:
Armin Ronacher9a822052008-04-17 18:44:07 +0200813 node = nodes.Not(node, lineno=token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200814 return node
815
816 def subparse(self, end_tokens=None):
817 body = []
818 data_buffer = []
819 add_data = data_buffer.append
820
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100821 if end_tokens is not None:
822 self._end_token_stack.append(end_tokens)
823
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200824 def flush_data():
825 if data_buffer:
826 lineno = data_buffer[0].lineno
827 body.append(nodes.Output(data_buffer[:], lineno=lineno))
828 del data_buffer[:]
829
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100830 try:
831 while self.stream:
832 token = self.stream.current
833 if token.type == 'data':
834 if token.value:
835 add_data(nodes.TemplateData(token.value,
836 lineno=token.lineno))
837 next(self.stream)
838 elif token.type == 'variable_begin':
839 next(self.stream)
840 add_data(self.parse_tuple(with_condexpr=True))
841 self.stream.expect('variable_end')
842 elif token.type == 'block_begin':
843 flush_data()
844 next(self.stream)
845 if end_tokens is not None and \
846 self.stream.current.test_any(*end_tokens):
847 return body
848 rv = self.parse_statement()
849 if isinstance(rv, list):
850 body.extend(rv)
851 else:
852 body.append(rv)
853 self.stream.expect('block_end')
Armin Ronacher023b5e92008-05-08 11:03:10 +0200854 else:
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100855 raise AssertionError('internal parsing error')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200856
Armin Ronacher5dcb7242010-02-06 14:01:26 +0100857 flush_data()
858 finally:
859 if end_tokens is not None:
860 self._end_token_stack.pop()
861
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200862 return body
863
864 def parse(self):
865 """Parse the whole template into a `Template` node."""
Armin Ronacherd55ab532008-04-09 16:13:39 +0200866 result = nodes.Template(self.subparse(), lineno=1)
867 result.set_environment(self.environment)
868 return result