blob: dae1a6b6910344580276f752213daac31dabc44b [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
8 :copyright: 2008 by Armin Ronacher.
9 :license: BSD, see LICENSE for more details.
10"""
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020011from jinja2 import nodes
12from jinja2.exceptions import TemplateSyntaxError
Armin Ronacher07bc6842008-03-31 14:18:49 +020013
14
Armin Ronachere791c2a2008-04-07 18:39:54 +020015_statement_keywords = frozenset(['for', 'if', 'block', 'extends', 'print',
Armin Ronacher0611e492008-04-25 23:44:14 +020016 'macro', 'include', 'from', 'import'])
Armin Ronacher115de2e2008-05-01 22:20:05 +020017_compare_operators = frozenset(['eq', 'ne', 'lt', 'lteq', 'gt', 'gteq'])
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020018
Armin Ronacher07bc6842008-03-31 14:18:49 +020019
20class Parser(object):
Armin Ronacher023b5e92008-05-08 11:03:10 +020021 """This is the central parsing class Jinja2 uses. It's passed to
22 extensions and can be used to parse expressions or statements.
Armin Ronacher07bc6842008-03-31 14:18:49 +020023 """
24
25 def __init__(self, environment, source, filename=None):
26 self.environment = environment
Armin Ronacher07bc6842008-03-31 14:18:49 +020027 if isinstance(filename, unicode):
28 filename = filename.encode('utf-8')
Armin Ronacherbf7c4ad2008-04-12 12:02:36 +020029 self.source = unicode(source)
Armin Ronacher07bc6842008-03-31 14:18:49 +020030 self.filename = filename
31 self.closed = False
Armin Ronacher023b5e92008-05-08 11:03:10 +020032 self.stream = environment.lexer.tokenize(self.source, filename)
Armin Ronacher05530932008-04-20 13:27:49 +020033 self.extensions = {}
Armin Ronacher023b5e92008-05-08 11:03:10 +020034 for extension in environment.extensions.itervalues():
Armin Ronacher05530932008-04-20 13:27:49 +020035 for tag in extension.tags:
36 self.extensions[tag] = extension.parse
Armin Ronacher023b5e92008-05-08 11:03:10 +020037 self._last_identifier = 0
Armin Ronacher115de2e2008-05-01 22:20:05 +020038
39 def is_tuple_end(self):
40 """Are we at the end of a tuple?"""
Armin Ronacher023b5e92008-05-08 11:03:10 +020041 return self.stream.current.type in ('variable_end', 'block_end',
42 'rparen') or \
43 self.stream.current.test('name:in')
44
Armin Ronacher762079c2008-05-08 23:57:56 +020045 def skip_colon(self):
Armin Ronacher023b5e92008-05-08 11:03:10 +020046 """If there is a colon, skip it and return `True`, else `False`."""
47 if self.stream.current.type is 'colon':
48 self.stream.next()
49 return True
50 return False
51
Armin Ronacher762079c2008-05-08 23:57:56 +020052 def skip_comma(self):
53 """If there is a comma, skip it and return `True`, else `False`."""
54 if self.stream.current.type is 'comma':
55 self.stream.next()
56 return True
57 return False
58
Armin Ronacher023b5e92008-05-08 11:03:10 +020059 def free_identifier(self, lineno=None):
60 """Return a new free identifier as :class:`~jinja2.nodes.InternalName`."""
61 self._last_identifier += 1
62 rv = object.__new__(nodes.InternalName)
63 nodes.Node.__init__(rv, 'fi%d' % self._last_identifier, lineno=lineno)
64 return rv
Armin Ronacher115de2e2008-05-01 22:20:05 +020065
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020066 def parse_statement(self):
67 """Parse a single statement."""
68 token_type = self.stream.current.type
Armin Ronacher115de2e2008-05-01 22:20:05 +020069 if self.stream.current.type is 'name':
70 if self.stream.current.value in _statement_keywords:
71 return getattr(self, 'parse_' + self.stream.current.value)()
72 elif self.stream.current.value == 'call':
73 return self.parse_call_block()
74 elif self.stream.current.value == 'filter':
75 return self.parse_filter_block()
76 else:
77 ext = self.extensions.get(self.stream.current.value)
78 if ext is not None:
79 return ext(self)
Armin Ronacher157531b2008-04-28 16:14:03 +020080 lineno = self.stream.current.lineno
Armin Ronacher8efc5222008-04-08 14:47:40 +020081 expr = self.parse_tuple()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020082 if self.stream.current.type == 'assign':
Armin Ronachere791c2a2008-04-07 18:39:54 +020083 result = self.parse_assign(expr)
84 else:
85 result = nodes.ExprStmt(expr, lineno=lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +020086 return result
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020087
88 def parse_assign(self, target):
89 """Parse an assign statement."""
90 lineno = self.stream.expect('assign').lineno
91 if not target.can_assign():
92 raise TemplateSyntaxError("can't assign to '%s'" %
Armin Ronacher4f7d2d52008-04-22 10:40:26 +020093 target.__class__.__name__.lower(),
94 target.lineno, self.filename)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020095 expr = self.parse_tuple()
Armin Ronachere791c2a2008-04-07 18:39:54 +020096 target.set_ctx('store')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020097 return nodes.Assign(target, expr, lineno=lineno)
98
99 def parse_statements(self, end_tokens, drop_needle=False):
Armin Ronacherf59bac22008-04-20 13:11:43 +0200100 """Parse multiple statements into a list until one of the end tokens
101 is reached. This is used to parse the body of statements as it also
Armin Ronacher023b5e92008-05-08 11:03:10 +0200102 parses template data if appropriate. The parser checks first if the
103 current token is a colon and skips it if there is one. Then it checks
104 for the block end and parses until if one of the `end_tokens` is
105 reached. Per default the active token in the stream at the end of
106 the call is the matched end token. If this is not wanted `drop_needle`
107 can be set to `True` and the end token is removed.
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200108 """
109 # the first token may be a colon for python compatibility
Armin Ronacher762079c2008-05-08 23:57:56 +0200110 self.skip_colon()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200111
Armin Ronacher2b60fe52008-04-21 08:23:59 +0200112 # in the future it would be possible to add whole code sections
113 # by adding some sort of end of statement token and parsing those here.
114 self.stream.expect('block_end')
115 result = self.subparse(end_tokens)
116
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200117 if drop_needle:
118 self.stream.next()
119 return result
120
121 def parse_for(self):
122 """Parse a for loop."""
Armin Ronacher115de2e2008-05-01 22:20:05 +0200123 lineno = self.stream.expect('name:for').lineno
Armin Ronacher09c002e2008-05-10 22:21:30 +0200124 target = self.parse_assign_target()
Armin Ronacher115de2e2008-05-01 22:20:05 +0200125 self.stream.expect('name:in')
Armin Ronacher09c002e2008-05-10 22:21:30 +0200126 iter = self.parse_tuple(with_condexpr=False)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200127 test = None
Armin Ronacherc0725642008-05-04 22:43:19 +0200128 if self.stream.current.test('name:if'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200129 self.stream.next()
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200130 test = self.parse_expression()
Armin Ronacher115de2e2008-05-01 22:20:05 +0200131 body = self.parse_statements(('name:endfor', 'name:else'))
132 if self.stream.next().value == 'endfor':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200133 else_ = []
134 else:
Armin Ronacher115de2e2008-05-01 22:20:05 +0200135 else_ = self.parse_statements(('name:endfor',), drop_needle=True)
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200136 return nodes.For(target, iter, body, else_, test, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200137
138 def parse_if(self):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200139 """Parse an if construct."""
Armin Ronacher115de2e2008-05-01 22:20:05 +0200140 node = result = nodes.If(lineno=self.stream.expect('name:if').lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200141 while 1:
Armin Ronacher09c002e2008-05-10 22:21:30 +0200142 node.test = self.parse_tuple(with_condexpr=False)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200143 node.body = self.parse_statements(('name:elif', 'name:else',
144 'name:endif'))
145 token = self.stream.next()
146 if token.test('name:elif'):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200147 new_node = nodes.If(lineno=self.stream.current.lineno)
148 node.else_ = [new_node]
149 node = new_node
150 continue
Armin Ronacher115de2e2008-05-01 22:20:05 +0200151 elif token.test('name:else'):
152 node.else_ = self.parse_statements(('name:endif',),
Armin Ronachere791c2a2008-04-07 18:39:54 +0200153 drop_needle=True)
154 else:
155 node.else_ = []
156 break
157 return result
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200158
159 def parse_block(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200160 node = nodes.Block(lineno=self.stream.next().lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200161 node.name = self.stream.expect('name').value
Armin Ronacher115de2e2008-05-01 22:20:05 +0200162 node.body = self.parse_statements(('name:endblock',), drop_needle=True)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200163 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200164
165 def parse_extends(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200166 node = nodes.Extends(lineno=self.stream.next().lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200167 node.template = self.parse_expression()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200168 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200169
Armin Ronacherea847c52008-05-02 20:04:32 +0200170 def parse_import_context(self, node, default):
Armin Ronachercda43df2008-05-03 17:10:05 +0200171 if self.stream.current.test_any('name:with', 'name:without') and \
Armin Ronacherea847c52008-05-02 20:04:32 +0200172 self.stream.look().test('name:context'):
173 node.with_context = self.stream.next().value == 'with'
174 self.stream.skip()
175 else:
176 node.with_context = default
177 return node
178
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200179 def parse_include(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200180 node = nodes.Include(lineno=self.stream.next().lineno)
Armin Ronacher0611e492008-04-25 23:44:14 +0200181 node.template = self.parse_expression()
Armin Ronacherea847c52008-05-02 20:04:32 +0200182 return self.parse_import_context(node, True)
Armin Ronacher0611e492008-04-25 23:44:14 +0200183
184 def parse_import(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200185 node = nodes.Import(lineno=self.stream.next().lineno)
Armin Ronacher0611e492008-04-25 23:44:14 +0200186 node.template = self.parse_expression()
187 self.stream.expect('name:as')
Armin Ronacher09c002e2008-05-10 22:21:30 +0200188 node.target = self.parse_assign_target(name_only=True).name
Armin Ronacherea847c52008-05-02 20:04:32 +0200189 return self.parse_import_context(node, False)
Armin Ronacher0611e492008-04-25 23:44:14 +0200190
191 def parse_from(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200192 node = nodes.FromImport(lineno=self.stream.next().lineno)
Armin Ronacher0611e492008-04-25 23:44:14 +0200193 node.template = self.parse_expression()
Armin Ronacher115de2e2008-05-01 22:20:05 +0200194 self.stream.expect('name:import')
Armin Ronacher0611e492008-04-25 23:44:14 +0200195 node.names = []
Armin Ronacherea847c52008-05-02 20:04:32 +0200196
197 def parse_context():
198 if self.stream.current.value in ('with', 'without') and \
199 self.stream.look().test('name:context'):
200 node.with_context = self.stream.next().value == 'with'
201 self.stream.skip()
202 return True
203 return False
204
Armin Ronacher0611e492008-04-25 23:44:14 +0200205 while 1:
206 if node.names:
207 self.stream.expect('comma')
208 if self.stream.current.type is 'name':
Armin Ronacherea847c52008-05-02 20:04:32 +0200209 if parse_context():
210 break
Armin Ronacher09c002e2008-05-10 22:21:30 +0200211 target = self.parse_assign_target(name_only=True)
212 if target.name.startswith('__'):
Armin Ronacher0611e492008-04-25 23:44:14 +0200213 raise TemplateAssertionError('names starting with two '
214 'underscores can not be '
215 'imported', target.lineno,
216 self.filename)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200217 if self.stream.current.test('name:as'):
218 self.stream.next()
Armin Ronacher09c002e2008-05-10 22:21:30 +0200219 alias = self.parse_assign_target(name_only=True)
220 node.names.append((target.name, alias.name))
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200221 else:
222 node.names.append(target.name)
Armin Ronacherea847c52008-05-02 20:04:32 +0200223 if parse_context() or self.stream.current.type is not 'comma':
Armin Ronacher0611e492008-04-25 23:44:14 +0200224 break
225 else:
226 break
Armin Ronacherea847c52008-05-02 20:04:32 +0200227 if not hasattr(node, 'with_context'):
228 node.with_context = False
229 if self.stream.current.type is 'comma':
230 self.stream.next()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200231 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200232
Armin Ronacher71082072008-04-12 14:19:36 +0200233 def parse_signature(self, node):
234 node.args = args = []
235 node.defaults = defaults = []
236 self.stream.expect('lparen')
237 while self.stream.current.type is not 'rparen':
238 if args:
239 self.stream.expect('comma')
Armin Ronacher09c002e2008-05-10 22:21:30 +0200240 arg = self.parse_assign_target(name_only=True)
Armin Ronacher71082072008-04-12 14:19:36 +0200241 if self.stream.current.type is 'assign':
242 self.stream.next()
243 defaults.append(self.parse_expression())
244 args.append(arg)
245 self.stream.expect('rparen')
246
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200247 def parse_call_block(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200248 node = nodes.CallBlock(lineno=self.stream.next().lineno)
Armin Ronacher71082072008-04-12 14:19:36 +0200249 if self.stream.current.type is 'lparen':
250 self.parse_signature(node)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200251 else:
252 node.args = []
253 node.defaults = []
Armin Ronacher71082072008-04-12 14:19:36 +0200254
Armin Ronacher8edbe492008-04-10 20:43:43 +0200255 node.call = self.parse_expression()
256 if not isinstance(node.call, nodes.Call):
257 raise TemplateSyntaxError('expected call', node.lineno,
258 self.filename)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200259 node.body = self.parse_statements(('name:endcall',), drop_needle=True)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200260 return node
261
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200262 def parse_filter_block(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200263 node = nodes.FilterBlock(lineno=self.stream.next().lineno)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200264 node.filter = self.parse_filter(None, start_inline=True)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200265 node.body = self.parse_statements(('name:endfilter',),
266 drop_needle=True)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200267 return node
268
Armin Ronachere791c2a2008-04-07 18:39:54 +0200269 def parse_macro(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200270 node = nodes.Macro(lineno=self.stream.next().lineno)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200271 node.name = self.parse_assign_target(name_only=True).name
Armin Ronacher71082072008-04-12 14:19:36 +0200272 self.parse_signature(node)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200273 node.body = self.parse_statements(('name:endmacro',),
274 drop_needle=True)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200275 return node
276
277 def parse_print(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200278 node = nodes.Output(lineno=self.stream.next().lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200279 node.nodes = []
Armin Ronacher023b5e92008-05-08 11:03:10 +0200280 while self.stream.current.type is not 'block_end':
Armin Ronachere791c2a2008-04-07 18:39:54 +0200281 if node.nodes:
282 self.stream.expect('comma')
283 node.nodes.append(self.parse_expression())
Armin Ronachere791c2a2008-04-07 18:39:54 +0200284 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200285
Armin Ronacher09c002e2008-05-10 22:21:30 +0200286 def parse_assign_target(self, with_tuple=True, name_only=False):
287 """Parse an assignment target. As Jinja2 allows assignments to
288 tuples, this function can parse all allowed assignment targets. Per
289 default assignments to tuples are parsed, that can be disable however
290 by setting `with_tuple` to `False`. If only assignments to names are
291 wanted `name_only` can be set to `True`.
292 """
293 if name_only:
294 token = self.stream.expect('name')
295 target = nodes.Name(token.value, 'store', lineno=token.lineno)
296 else:
297 if with_tuple:
298 target = self.parse_tuple(simplified=True)
299 else:
300 target = self.parse_primary(with_postfix=False)
301 target.set_ctx('store')
302 if not target.can_assign():
303 raise TemplateSyntaxError('can\'t assign to %r' %
304 target.__class__.__name__.lower(),
305 target.lineno, self.filename)
306 return target
307
308 def parse_expression(self, with_condexpr=True):
Armin Ronacher023b5e92008-05-08 11:03:10 +0200309 """Parse an expression. Per default all expressions are parsed, if
Armin Ronacher09c002e2008-05-10 22:21:30 +0200310 the optional `with_condexpr` parameter is set to `False` conditional
Armin Ronacher023b5e92008-05-08 11:03:10 +0200311 expressions are not parsed.
312 """
Armin Ronacher09c002e2008-05-10 22:21:30 +0200313 if with_condexpr:
314 return self.parse_condexpr()
315 return self.parse_or()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200316
317 def parse_condexpr(self):
318 lineno = self.stream.current.lineno
319 expr1 = self.parse_or()
Armin Ronacher115de2e2008-05-01 22:20:05 +0200320 while self.stream.current.test('name:if'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200321 self.stream.next()
322 expr2 = self.parse_or()
Armin Ronacher115de2e2008-05-01 22:20:05 +0200323 self.stream.expect('name:else')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200324 expr3 = self.parse_condexpr()
325 expr1 = nodes.CondExpr(expr2, expr1, expr3, lineno=lineno)
326 lineno = self.stream.current.lineno
327 return expr1
328
329 def parse_or(self):
330 lineno = self.stream.current.lineno
331 left = self.parse_and()
Armin Ronacher115de2e2008-05-01 22:20:05 +0200332 while self.stream.current.test('name:or'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200333 self.stream.next()
334 right = self.parse_and()
335 left = nodes.Or(left, right, lineno=lineno)
336 lineno = self.stream.current.lineno
337 return left
338
339 def parse_and(self):
340 lineno = self.stream.current.lineno
341 left = self.parse_compare()
Armin Ronacher115de2e2008-05-01 22:20:05 +0200342 while self.stream.current.test('name:and'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200343 self.stream.next()
344 right = self.parse_compare()
345 left = nodes.And(left, right, lineno=lineno)
346 lineno = self.stream.current.lineno
347 return left
348
349 def parse_compare(self):
350 lineno = self.stream.current.lineno
351 expr = self.parse_add()
352 ops = []
353 while 1:
354 token_type = self.stream.current.type
355 if token_type in _compare_operators:
356 self.stream.next()
357 ops.append(nodes.Operand(token_type, self.parse_add()))
Armin Ronacher115de2e2008-05-01 22:20:05 +0200358 elif self.stream.current.test('name:in'):
359 self.stream.next()
360 ops.append(nodes.Operand('in', self.parse_add()))
361 elif self.stream.current.test('name:not') and \
362 self.stream.look().test('name:in'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200363 self.stream.skip(2)
364 ops.append(nodes.Operand('notin', self.parse_add()))
365 else:
366 break
367 lineno = self.stream.current.lineno
368 if not ops:
369 return expr
370 return nodes.Compare(expr, ops, lineno=lineno)
371
372 def parse_add(self):
373 lineno = self.stream.current.lineno
374 left = self.parse_sub()
375 while self.stream.current.type is 'add':
376 self.stream.next()
377 right = self.parse_sub()
378 left = nodes.Add(left, right, lineno=lineno)
379 lineno = self.stream.current.lineno
380 return left
381
382 def parse_sub(self):
383 lineno = self.stream.current.lineno
384 left = self.parse_concat()
385 while self.stream.current.type is 'sub':
386 self.stream.next()
387 right = self.parse_concat()
388 left = nodes.Sub(left, right, lineno=lineno)
389 lineno = self.stream.current.lineno
390 return left
391
392 def parse_concat(self):
393 lineno = self.stream.current.lineno
394 args = [self.parse_mul()]
395 while self.stream.current.type is 'tilde':
396 self.stream.next()
397 args.append(self.parse_mul())
398 if len(args) == 1:
399 return args[0]
400 return nodes.Concat(args, lineno=lineno)
401
402 def parse_mul(self):
403 lineno = self.stream.current.lineno
404 left = self.parse_div()
405 while self.stream.current.type is 'mul':
406 self.stream.next()
407 right = self.parse_div()
408 left = nodes.Mul(left, right, lineno=lineno)
409 lineno = self.stream.current.lineno
410 return left
411
412 def parse_div(self):
413 lineno = self.stream.current.lineno
414 left = self.parse_floordiv()
415 while self.stream.current.type is 'div':
416 self.stream.next()
417 right = self.parse_floordiv()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200418 left = nodes.Div(left, right, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200419 lineno = self.stream.current.lineno
420 return left
421
422 def parse_floordiv(self):
423 lineno = self.stream.current.lineno
424 left = self.parse_mod()
425 while self.stream.current.type is 'floordiv':
426 self.stream.next()
427 right = self.parse_mod()
428 left = nodes.FloorDiv(left, right, lineno=lineno)
429 lineno = self.stream.current.lineno
430 return left
431
432 def parse_mod(self):
433 lineno = self.stream.current.lineno
434 left = self.parse_pow()
435 while self.stream.current.type is 'mod':
436 self.stream.next()
437 right = self.parse_pow()
438 left = nodes.Mod(left, right, lineno=lineno)
439 lineno = self.stream.current.lineno
440 return left
441
442 def parse_pow(self):
443 lineno = self.stream.current.lineno
444 left = self.parse_unary()
445 while self.stream.current.type is 'pow':
446 self.stream.next()
447 right = self.parse_unary()
448 left = nodes.Pow(left, right, lineno=lineno)
449 lineno = self.stream.current.lineno
450 return left
451
452 def parse_unary(self):
453 token_type = self.stream.current.type
454 lineno = self.stream.current.lineno
Armin Ronacher115de2e2008-05-01 22:20:05 +0200455 if token_type is 'name' and self.stream.current.value == 'not':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200456 self.stream.next()
457 node = self.parse_unary()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200458 return nodes.Not(node, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200459 if token_type is 'sub':
460 self.stream.next()
461 node = self.parse_unary()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200462 return nodes.Neg(node, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200463 if token_type is 'add':
464 self.stream.next()
465 node = self.parse_unary()
466 return nodes.Pos(node, lineno=lineno)
467 return self.parse_primary()
468
Armin Ronacher09c002e2008-05-10 22:21:30 +0200469 def parse_primary(self, with_postfix=True):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200470 token = self.stream.current
471 if token.type is 'name':
472 if token.value in ('true', 'false'):
473 node = nodes.Const(token.value == 'true', lineno=token.lineno)
474 elif token.value == 'none':
475 node = nodes.Const(None, lineno=token.lineno)
476 else:
477 node = nodes.Name(token.value, 'load', lineno=token.lineno)
478 self.stream.next()
479 elif token.type in ('integer', 'float', 'string'):
480 self.stream.next()
481 node = nodes.Const(token.value, lineno=token.lineno)
482 elif token.type is 'lparen':
483 self.stream.next()
484 node = self.parse_tuple()
485 self.stream.expect('rparen')
486 elif token.type is 'lbracket':
487 node = self.parse_list()
488 elif token.type is 'lbrace':
489 node = self.parse_dict()
490 else:
491 raise TemplateSyntaxError("unexpected token '%s'" %
492 (token,), token.lineno,
493 self.filename)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200494 if with_postfix:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200495 node = self.parse_postfix(node)
496 return node
497
Armin Ronacher09c002e2008-05-10 22:21:30 +0200498 def parse_tuple(self, simplified=False, with_condexpr=True):
Armin Ronacher023b5e92008-05-08 11:03:10 +0200499 """Works like `parse_expression` but if multiple expressions are
500 delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created.
501 This method could also return a regular expression instead of a tuple
502 if no commas where found.
503
504 The default parsing mode is a full tuple. If `simplified` is `True`
505 only names and literals are parsed. The `no_condexpr` parameter is
506 forwarded to :meth:`parse_expression`.
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200507 """
508 lineno = self.stream.current.lineno
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200509 if simplified:
Armin Ronacher09c002e2008-05-10 22:21:30 +0200510 parse = lambda: self.parse_primary(with_postfix=False)
511 elif with_condexpr:
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200512 parse = self.parse_expression
Armin Ronacher09c002e2008-05-10 22:21:30 +0200513 else:
514 parse = lambda: self.parse_expression(with_condexpr=False)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200515 args = []
516 is_tuple = False
517 while 1:
518 if args:
519 self.stream.expect('comma')
Armin Ronacher115de2e2008-05-01 22:20:05 +0200520 if self.is_tuple_end():
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200521 break
522 args.append(parse())
Armin Ronacherb5124e62008-04-25 00:36:14 +0200523 if self.stream.current.type is 'comma':
524 is_tuple = True
525 else:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200526 break
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200527 lineno = self.stream.current.lineno
528 if not is_tuple and args:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200529 return args[0]
530 return nodes.Tuple(args, 'load', lineno=lineno)
531
532 def parse_list(self):
533 token = self.stream.expect('lbracket')
534 items = []
535 while self.stream.current.type is not 'rbracket':
536 if items:
537 self.stream.expect('comma')
538 if self.stream.current.type == 'rbracket':
539 break
540 items.append(self.parse_expression())
541 self.stream.expect('rbracket')
542 return nodes.List(items, lineno=token.lineno)
543
544 def parse_dict(self):
545 token = self.stream.expect('lbrace')
546 items = []
547 while self.stream.current.type is not 'rbrace':
548 if items:
549 self.stream.expect('comma')
550 if self.stream.current.type == 'rbrace':
551 break
552 key = self.parse_expression()
553 self.stream.expect('colon')
554 value = self.parse_expression()
555 items.append(nodes.Pair(key, value, lineno=key.lineno))
556 self.stream.expect('rbrace')
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200557 return nodes.Dict(items, lineno=token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200558
559 def parse_postfix(self, node):
560 while 1:
561 token_type = self.stream.current.type
562 if token_type is 'dot' or token_type is 'lbracket':
563 node = self.parse_subscript(node)
564 elif token_type is 'lparen':
565 node = self.parse_call(node)
566 elif token_type is 'pipe':
567 node = self.parse_filter(node)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200568 elif token_type is 'name' and self.stream.current.value == 'is':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200569 node = self.parse_test(node)
570 else:
571 break
572 return node
573
574 def parse_subscript(self, node):
575 token = self.stream.next()
576 if token.type is 'dot':
Armin Ronachere791c2a2008-04-07 18:39:54 +0200577 attr_token = self.stream.current
578 if attr_token.type not in ('name', 'integer'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200579 raise TemplateSyntaxError('expected name or number',
Armin Ronachere791c2a2008-04-07 18:39:54 +0200580 attr_token.lineno, self.filename)
581 arg = nodes.Const(attr_token.value, lineno=attr_token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200582 self.stream.next()
583 elif token.type is 'lbracket':
584 args = []
585 while self.stream.current.type is not 'rbracket':
586 if args:
587 self.stream.expect('comma')
588 args.append(self.parse_subscribed())
589 self.stream.expect('rbracket')
590 if len(args) == 1:
591 arg = args[0]
592 else:
Benjamin Wieganda3152742008-04-28 18:07:52 +0200593 arg = nodes.Tuple(args, self.lineno, self.filename)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200594 else:
595 raise TemplateSyntaxError('expected subscript expression',
596 self.lineno, self.filename)
597 return nodes.Subscript(node, arg, 'load', lineno=token.lineno)
598
599 def parse_subscribed(self):
600 lineno = self.stream.current.lineno
601
602 if self.stream.current.type is 'colon':
603 self.stream.next()
604 args = [None]
605 else:
606 node = self.parse_expression()
607 if self.stream.current.type is not 'colon':
608 return node
609 self.stream.next()
610 args = [node]
611
612 if self.stream.current.type is 'colon':
613 args.append(None)
614 elif self.stream.current.type not in ('rbracket', 'comma'):
615 args.append(self.parse_expression())
616 else:
617 args.append(None)
618
619 if self.stream.current.type is 'colon':
620 self.stream.next()
621 if self.stream.current.type not in ('rbracket', 'comma'):
622 args.append(self.parse_expression())
623 else:
624 args.append(None)
625 else:
626 args.append(None)
627
628 return nodes.Slice(lineno=lineno, *args)
629
630 def parse_call(self, node):
631 token = self.stream.expect('lparen')
632 args = []
633 kwargs = []
634 dyn_args = dyn_kwargs = None
635 require_comma = False
636
637 def ensure(expr):
638 if not expr:
639 raise TemplateSyntaxError('invalid syntax for function '
640 'call expression', token.lineno,
641 self.filename)
642
643 while self.stream.current.type is not 'rparen':
644 if require_comma:
645 self.stream.expect('comma')
646 # support for trailing comma
647 if self.stream.current.type is 'rparen':
648 break
649 if self.stream.current.type is 'mul':
650 ensure(dyn_args is None and dyn_kwargs is None)
651 self.stream.next()
652 dyn_args = self.parse_expression()
653 elif self.stream.current.type is 'pow':
654 ensure(dyn_kwargs is None)
655 self.stream.next()
656 dyn_kwargs = self.parse_expression()
657 else:
658 ensure(dyn_args is None and dyn_kwargs is None)
659 if self.stream.current.type is 'name' and \
660 self.stream.look().type is 'assign':
661 key = self.stream.current.value
662 self.stream.skip(2)
Armin Ronacher0611e492008-04-25 23:44:14 +0200663 value = self.parse_expression()
664 kwargs.append(nodes.Keyword(key, value,
665 lineno=value.lineno))
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200666 else:
667 ensure(not kwargs)
668 args.append(self.parse_expression())
669
670 require_comma = True
671 self.stream.expect('rparen')
672
673 if node is None:
674 return args, kwargs, dyn_args, dyn_kwargs
675 return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs,
676 lineno=token.lineno)
677
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200678 def parse_filter(self, node, start_inline=False):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200679 lineno = self.stream.current.type
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200680 while self.stream.current.type == 'pipe' or start_inline:
681 if not start_inline:
682 self.stream.next()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200683 token = self.stream.expect('name')
684 if self.stream.current.type is 'lparen':
685 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
686 else:
687 args = []
688 kwargs = []
689 dyn_args = dyn_kwargs = None
Armin Ronacherd55ab532008-04-09 16:13:39 +0200690 node = nodes.Filter(node, token.value, args, kwargs, dyn_args,
691 dyn_kwargs, lineno=token.lineno)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200692 start_inline = False
Armin Ronacherd55ab532008-04-09 16:13:39 +0200693 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200694
695 def parse_test(self, node):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200696 token = self.stream.next()
697 if self.stream.current.test('name:not'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200698 self.stream.next()
699 negated = True
700 else:
701 negated = False
702 name = self.stream.expect('name').value
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200703 dyn_args = dyn_kwargs = None
704 kwargs = []
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200705 if self.stream.current.type is 'lparen':
706 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
707 elif self.stream.current.type in ('name', 'string', 'integer',
708 'float', 'lparen', 'lbracket',
Armin Ronacher115de2e2008-05-01 22:20:05 +0200709 'lbrace'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200710 args = [self.parse_expression()]
711 else:
712 args = []
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200713 node = nodes.Test(node, name, args, kwargs, dyn_args,
714 dyn_kwargs, lineno=token.lineno)
715 if negated:
Armin Ronacher9a822052008-04-17 18:44:07 +0200716 node = nodes.Not(node, lineno=token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200717 return node
718
719 def subparse(self, end_tokens=None):
720 body = []
721 data_buffer = []
722 add_data = data_buffer.append
723
724 def flush_data():
725 if data_buffer:
726 lineno = data_buffer[0].lineno
727 body.append(nodes.Output(data_buffer[:], lineno=lineno))
728 del data_buffer[:]
729
730 while self.stream:
731 token = self.stream.current
732 if token.type is 'data':
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200733 if token.value:
734 add_data(nodes.Const(token.value, lineno=token.lineno))
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200735 self.stream.next()
736 elif token.type is 'variable_begin':
737 self.stream.next()
Armin Ronacher09c002e2008-05-10 22:21:30 +0200738 add_data(self.parse_tuple(with_condexpr=True))
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200739 self.stream.expect('variable_end')
740 elif token.type is 'block_begin':
741 flush_data()
742 self.stream.next()
743 if end_tokens is not None and \
Armin Ronachercda43df2008-05-03 17:10:05 +0200744 self.stream.current.test_any(*end_tokens):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200745 return body
Armin Ronacher023b5e92008-05-08 11:03:10 +0200746 rv = self.parse_statement()
747 if isinstance(rv, list):
748 body.extend(rv)
749 else:
750 body.append(rv)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200751 self.stream.expect('block_end')
752 else:
753 raise AssertionError('internal parsing error')
754
755 flush_data()
756 return body
757
758 def parse(self):
759 """Parse the whole template into a `Template` node."""
Armin Ronacherd55ab532008-04-09 16:13:39 +0200760 result = nodes.Template(self.subparse(), lineno=1)
761 result.set_environment(self.environment)
762 return result