blob: ea7391fe26967fbf37377cddaff23904dc309982 [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
Armin Ronachera78d2762008-05-15 23:18:07 +020012from jinja2.exceptions import TemplateSyntaxError, TemplateAssertionError
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 Ronacher0a2ac692008-05-13 01:03:08 +020016 'macro', 'include', 'from', 'import',
17 'set'])
Armin Ronacher115de2e2008-05-01 22:20:05 +020018_compare_operators = frozenset(['eq', 'ne', 'lt', 'lteq', 'gt', 'gteq'])
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020019
Armin Ronacher07bc6842008-03-31 14:18:49 +020020
21class Parser(object):
Armin Ronacher023b5e92008-05-08 11:03:10 +020022 """This is the central parsing class Jinja2 uses. It's passed to
23 extensions and can be used to parse expressions or statements.
Armin Ronacher07bc6842008-03-31 14:18:49 +020024 """
25
Armin Ronacher7f15ef82008-05-16 09:11:39 +020026 def __init__(self, environment, source, name=None, filename=None):
Armin Ronacher07bc6842008-03-31 14:18:49 +020027 self.environment = environment
Armin Ronacher9ad96e72008-06-13 22:44:01 +020028 self.stream = environment._tokenize(source, name, filename)
Armin Ronacher7f15ef82008-05-16 09:11:39 +020029 self.name = name
Armin Ronacher07bc6842008-03-31 14:18:49 +020030 self.filename = filename
31 self.closed = False
Armin Ronacher05530932008-04-20 13:27:49 +020032 self.extensions = {}
Armin Ronacher023b5e92008-05-08 11:03:10 +020033 for extension in environment.extensions.itervalues():
Armin Ronacher05530932008-04-20 13:27:49 +020034 for tag in extension.tags:
35 self.extensions[tag] = extension.parse
Armin Ronacher023b5e92008-05-08 11:03:10 +020036 self._last_identifier = 0
Armin Ronacher115de2e2008-05-01 22:20:05 +020037
Armin Ronacher7f15ef82008-05-16 09:11:39 +020038 def fail(self, msg, lineno=None, exc=TemplateSyntaxError):
39 """Convenience method that raises `exc` with the message, passed
40 line number or last line number as well as the current name and
41 filename.
42 """
43 if lineno is None:
44 lineno = self.stream.current.lineno
Armin Ronacher61a5a242008-05-26 12:07:44 +020045 raise exc(msg, lineno, self.name, self.filename)
Armin Ronacher7f15ef82008-05-16 09:11:39 +020046
Armin Ronacherfdf95302008-05-11 22:20:51 +020047 def is_tuple_end(self, extra_end_rules=None):
Armin Ronacher115de2e2008-05-01 22:20:05 +020048 """Are we at the end of a tuple?"""
Armin Ronacherfdf95302008-05-11 22:20:51 +020049 if self.stream.current.type in ('variable_end', 'block_end', 'rparen'):
Armin Ronacher023b5e92008-05-08 11:03:10 +020050 return True
Armin Ronacherfdf95302008-05-11 22:20:51 +020051 elif extra_end_rules is not None:
52 return self.stream.current.test_any(extra_end_rules)
Armin Ronacher762079c2008-05-08 23:57:56 +020053 return False
54
Armin Ronacher023b5e92008-05-08 11:03:10 +020055 def free_identifier(self, lineno=None):
56 """Return a new free identifier as :class:`~jinja2.nodes.InternalName`."""
57 self._last_identifier += 1
58 rv = object.__new__(nodes.InternalName)
59 nodes.Node.__init__(rv, 'fi%d' % self._last_identifier, lineno=lineno)
60 return rv
Armin Ronacher115de2e2008-05-01 22:20:05 +020061
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020062 def parse_statement(self):
63 """Parse a single statement."""
Armin Ronacher0a2ac692008-05-13 01:03:08 +020064 token = self.stream.current
65 if token.type is not 'name':
Armin Ronacher7f15ef82008-05-16 09:11:39 +020066 self.fail('tag name expected', token.lineno)
Armin Ronacher0a2ac692008-05-13 01:03:08 +020067 if token.value in _statement_keywords:
68 return getattr(self, 'parse_' + self.stream.current.value)()
69 if token.value == 'call':
70 return self.parse_call_block()
71 if token.value == 'filter':
72 return self.parse_filter_block()
73 ext = self.extensions.get(token.value)
74 if ext is not None:
75 return ext(self)
Armin Ronacher7f15ef82008-05-16 09:11:39 +020076 self.fail('unknown tag %r' % token.value, token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020077
78 def parse_statements(self, end_tokens, drop_needle=False):
Armin Ronacherf59bac22008-04-20 13:11:43 +020079 """Parse multiple statements into a list until one of the end tokens
80 is reached. This is used to parse the body of statements as it also
Armin Ronacher023b5e92008-05-08 11:03:10 +020081 parses template data if appropriate. The parser checks first if the
82 current token is a colon and skips it if there is one. Then it checks
83 for the block end and parses until if one of the `end_tokens` is
84 reached. Per default the active token in the stream at the end of
85 the call is the matched end token. If this is not wanted `drop_needle`
86 can be set to `True` and the end token is removed.
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020087 """
88 # the first token may be a colon for python compatibility
Armin Ronacherfdf95302008-05-11 22:20:51 +020089 self.stream.skip_if('colon')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020090
Armin Ronacher2b60fe52008-04-21 08:23:59 +020091 # in the future it would be possible to add whole code sections
92 # by adding some sort of end of statement token and parsing those here.
93 self.stream.expect('block_end')
94 result = self.subparse(end_tokens)
95
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020096 if drop_needle:
97 self.stream.next()
98 return result
99
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200100 def parse_set(self):
101 """Parse an assign statement."""
102 lineno = self.stream.next().lineno
103 target = self.parse_assign_target()
104 self.stream.expect('assign')
105 expr = self.parse_tuple()
106 return nodes.Assign(target, expr, lineno=lineno)
107
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200108 def parse_for(self):
109 """Parse a for loop."""
Armin Ronacher115de2e2008-05-01 22:20:05 +0200110 lineno = self.stream.expect('name:for').lineno
Armin Ronacherfdf95302008-05-11 22:20:51 +0200111 target = self.parse_assign_target(extra_end_rules=('name:in',))
Armin Ronacher115de2e2008-05-01 22:20:05 +0200112 self.stream.expect('name:in')
Armin Ronacherfdf95302008-05-11 22:20:51 +0200113 iter = self.parse_tuple(with_condexpr=False,
114 extra_end_rules=('name:recursive',))
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200115 test = None
Armin Ronacherfdf95302008-05-11 22:20:51 +0200116 if self.stream.skip_if('name:if'):
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200117 test = self.parse_expression()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200118 recursive = self.stream.skip_if('name:recursive')
Armin Ronacher115de2e2008-05-01 22:20:05 +0200119 body = self.parse_statements(('name:endfor', 'name:else'))
120 if self.stream.next().value == 'endfor':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200121 else_ = []
122 else:
Armin Ronacher115de2e2008-05-01 22:20:05 +0200123 else_ = self.parse_statements(('name:endfor',), drop_needle=True)
Armin Ronacherfdf95302008-05-11 22:20:51 +0200124 return nodes.For(target, iter, body, else_, test,
125 recursive, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200126
127 def parse_if(self):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200128 """Parse an if construct."""
Armin Ronacher115de2e2008-05-01 22:20:05 +0200129 node = result = nodes.If(lineno=self.stream.expect('name:if').lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200130 while 1:
Armin Ronacher09c002e2008-05-10 22:21:30 +0200131 node.test = self.parse_tuple(with_condexpr=False)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200132 node.body = self.parse_statements(('name:elif', 'name:else',
133 'name:endif'))
134 token = self.stream.next()
135 if token.test('name:elif'):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200136 new_node = nodes.If(lineno=self.stream.current.lineno)
137 node.else_ = [new_node]
138 node = new_node
139 continue
Armin Ronacher115de2e2008-05-01 22:20:05 +0200140 elif token.test('name:else'):
141 node.else_ = self.parse_statements(('name:endif',),
Armin Ronachere791c2a2008-04-07 18:39:54 +0200142 drop_needle=True)
143 else:
144 node.else_ = []
145 break
146 return result
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200147
148 def parse_block(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200149 node = nodes.Block(lineno=self.stream.next().lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200150 node.name = self.stream.expect('name').value
Armin Ronacher115de2e2008-05-01 22:20:05 +0200151 node.body = self.parse_statements(('name:endblock',), drop_needle=True)
Armin Ronacherfd310492008-05-25 00:16:51 +0200152 self.stream.skip_if('name:' + node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200153 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200154
155 def parse_extends(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200156 node = nodes.Extends(lineno=self.stream.next().lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200157 node.template = self.parse_expression()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200158 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200159
Armin Ronacherea847c52008-05-02 20:04:32 +0200160 def parse_import_context(self, node, default):
Armin Ronachercda43df2008-05-03 17:10:05 +0200161 if self.stream.current.test_any('name:with', 'name:without') and \
Armin Ronacherea847c52008-05-02 20:04:32 +0200162 self.stream.look().test('name:context'):
163 node.with_context = self.stream.next().value == 'with'
164 self.stream.skip()
165 else:
166 node.with_context = default
167 return node
168
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200169 def parse_include(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200170 node = nodes.Include(lineno=self.stream.next().lineno)
Armin Ronacher0611e492008-04-25 23:44:14 +0200171 node.template = self.parse_expression()
Armin Ronacherea847c52008-05-02 20:04:32 +0200172 return self.parse_import_context(node, True)
Armin Ronacher0611e492008-04-25 23:44:14 +0200173
174 def parse_import(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200175 node = nodes.Import(lineno=self.stream.next().lineno)
Armin Ronacher0611e492008-04-25 23:44:14 +0200176 node.template = self.parse_expression()
177 self.stream.expect('name:as')
Armin Ronacher09c002e2008-05-10 22:21:30 +0200178 node.target = self.parse_assign_target(name_only=True).name
Armin Ronacherea847c52008-05-02 20:04:32 +0200179 return self.parse_import_context(node, False)
Armin Ronacher0611e492008-04-25 23:44:14 +0200180
181 def parse_from(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200182 node = nodes.FromImport(lineno=self.stream.next().lineno)
Armin Ronacher0611e492008-04-25 23:44:14 +0200183 node.template = self.parse_expression()
Armin Ronacher115de2e2008-05-01 22:20:05 +0200184 self.stream.expect('name:import')
Armin Ronacher0611e492008-04-25 23:44:14 +0200185 node.names = []
Armin Ronacherea847c52008-05-02 20:04:32 +0200186
187 def parse_context():
188 if self.stream.current.value in ('with', 'without') and \
189 self.stream.look().test('name:context'):
190 node.with_context = self.stream.next().value == 'with'
191 self.stream.skip()
192 return True
193 return False
194
Armin Ronacher0611e492008-04-25 23:44:14 +0200195 while 1:
196 if node.names:
197 self.stream.expect('comma')
198 if self.stream.current.type is 'name':
Armin Ronacherea847c52008-05-02 20:04:32 +0200199 if parse_context():
200 break
Armin Ronacher09c002e2008-05-10 22:21:30 +0200201 target = self.parse_assign_target(name_only=True)
Armin Ronacher903d1682008-05-23 00:51:58 +0200202 if target.name.startswith('_'):
203 self.fail('names starting with an underline can not '
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200204 'be imported', target.lineno,
205 exc=TemplateAssertionError)
Armin Ronacherfdf95302008-05-11 22:20:51 +0200206 if self.stream.skip_if('name:as'):
Armin Ronacher09c002e2008-05-10 22:21:30 +0200207 alias = self.parse_assign_target(name_only=True)
208 node.names.append((target.name, alias.name))
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200209 else:
210 node.names.append(target.name)
Armin Ronacherea847c52008-05-02 20:04:32 +0200211 if parse_context() or self.stream.current.type is not 'comma':
Armin Ronacher0611e492008-04-25 23:44:14 +0200212 break
213 else:
214 break
Armin Ronacherea847c52008-05-02 20:04:32 +0200215 if not hasattr(node, 'with_context'):
216 node.with_context = False
Armin Ronacherfdf95302008-05-11 22:20:51 +0200217 self.stream.skip_if('comma')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200218 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200219
Armin Ronacher71082072008-04-12 14:19:36 +0200220 def parse_signature(self, node):
221 node.args = args = []
222 node.defaults = defaults = []
223 self.stream.expect('lparen')
224 while self.stream.current.type is not 'rparen':
225 if args:
226 self.stream.expect('comma')
Armin Ronacher09c002e2008-05-10 22:21:30 +0200227 arg = self.parse_assign_target(name_only=True)
Armin Ronachere9411b42008-05-15 16:22:07 +0200228 arg.set_ctx('param')
Armin Ronacherfdf95302008-05-11 22:20:51 +0200229 if self.stream.skip_if('assign'):
Armin Ronacher71082072008-04-12 14:19:36 +0200230 defaults.append(self.parse_expression())
231 args.append(arg)
232 self.stream.expect('rparen')
233
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200234 def parse_call_block(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200235 node = nodes.CallBlock(lineno=self.stream.next().lineno)
Armin Ronacher71082072008-04-12 14:19:36 +0200236 if self.stream.current.type is 'lparen':
237 self.parse_signature(node)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200238 else:
239 node.args = []
240 node.defaults = []
Armin Ronacher71082072008-04-12 14:19:36 +0200241
Armin Ronacher8edbe492008-04-10 20:43:43 +0200242 node.call = self.parse_expression()
243 if not isinstance(node.call, nodes.Call):
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200244 self.fail('expected call', node.lineno)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200245 node.body = self.parse_statements(('name:endcall',), drop_needle=True)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200246 return node
247
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200248 def parse_filter_block(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200249 node = nodes.FilterBlock(lineno=self.stream.next().lineno)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200250 node.filter = self.parse_filter(None, start_inline=True)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200251 node.body = self.parse_statements(('name:endfilter',),
252 drop_needle=True)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200253 return node
254
Armin Ronachere791c2a2008-04-07 18:39:54 +0200255 def parse_macro(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200256 node = nodes.Macro(lineno=self.stream.next().lineno)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200257 node.name = self.parse_assign_target(name_only=True).name
Armin Ronacher71082072008-04-12 14:19:36 +0200258 self.parse_signature(node)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200259 node.body = self.parse_statements(('name:endmacro',),
260 drop_needle=True)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200261 return node
262
263 def parse_print(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200264 node = nodes.Output(lineno=self.stream.next().lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200265 node.nodes = []
Armin Ronacher023b5e92008-05-08 11:03:10 +0200266 while self.stream.current.type is not 'block_end':
Armin Ronachere791c2a2008-04-07 18:39:54 +0200267 if node.nodes:
268 self.stream.expect('comma')
269 node.nodes.append(self.parse_expression())
Armin Ronachere791c2a2008-04-07 18:39:54 +0200270 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200271
Armin Ronacherfdf95302008-05-11 22:20:51 +0200272 def parse_assign_target(self, with_tuple=True, name_only=False,
273 extra_end_rules=None):
Armin Ronacher09c002e2008-05-10 22:21:30 +0200274 """Parse an assignment target. As Jinja2 allows assignments to
275 tuples, this function can parse all allowed assignment targets. Per
276 default assignments to tuples are parsed, that can be disable however
277 by setting `with_tuple` to `False`. If only assignments to names are
Armin Ronacherfdf95302008-05-11 22:20:51 +0200278 wanted `name_only` can be set to `True`. The `extra_end_rules`
279 parameter is forwarded to the tuple parsing function.
Armin Ronacher09c002e2008-05-10 22:21:30 +0200280 """
281 if name_only:
282 token = self.stream.expect('name')
283 target = nodes.Name(token.value, 'store', lineno=token.lineno)
284 else:
285 if with_tuple:
Armin Ronacherfdf95302008-05-11 22:20:51 +0200286 target = self.parse_tuple(simplified=True,
287 extra_end_rules=extra_end_rules)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200288 else:
289 target = self.parse_primary(with_postfix=False)
290 target.set_ctx('store')
291 if not target.can_assign():
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200292 self.fail('can\'t assign to %r' % target.__class__.
293 __name__.lower(), target.lineno)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200294 return target
295
296 def parse_expression(self, with_condexpr=True):
Armin Ronacher023b5e92008-05-08 11:03:10 +0200297 """Parse an expression. Per default all expressions are parsed, if
Armin Ronacher09c002e2008-05-10 22:21:30 +0200298 the optional `with_condexpr` parameter is set to `False` conditional
Armin Ronacher023b5e92008-05-08 11:03:10 +0200299 expressions are not parsed.
300 """
Armin Ronacher09c002e2008-05-10 22:21:30 +0200301 if with_condexpr:
302 return self.parse_condexpr()
303 return self.parse_or()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200304
305 def parse_condexpr(self):
306 lineno = self.stream.current.lineno
307 expr1 = self.parse_or()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200308 while self.stream.skip_if('name:if'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200309 expr2 = self.parse_or()
Armin Ronacher115de2e2008-05-01 22:20:05 +0200310 self.stream.expect('name:else')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200311 expr3 = self.parse_condexpr()
312 expr1 = nodes.CondExpr(expr2, expr1, expr3, lineno=lineno)
313 lineno = self.stream.current.lineno
314 return expr1
315
316 def parse_or(self):
317 lineno = self.stream.current.lineno
318 left = self.parse_and()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200319 while self.stream.skip_if('name:or'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200320 right = self.parse_and()
321 left = nodes.Or(left, right, lineno=lineno)
322 lineno = self.stream.current.lineno
323 return left
324
325 def parse_and(self):
326 lineno = self.stream.current.lineno
327 left = self.parse_compare()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200328 while self.stream.skip_if('name:and'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200329 right = self.parse_compare()
330 left = nodes.And(left, right, lineno=lineno)
331 lineno = self.stream.current.lineno
332 return left
333
334 def parse_compare(self):
335 lineno = self.stream.current.lineno
336 expr = self.parse_add()
337 ops = []
338 while 1:
339 token_type = self.stream.current.type
340 if token_type in _compare_operators:
341 self.stream.next()
342 ops.append(nodes.Operand(token_type, self.parse_add()))
Armin Ronacherfdf95302008-05-11 22:20:51 +0200343 elif self.stream.skip_if('name:in'):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200344 ops.append(nodes.Operand('in', self.parse_add()))
345 elif self.stream.current.test('name:not') and \
346 self.stream.look().test('name:in'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200347 self.stream.skip(2)
348 ops.append(nodes.Operand('notin', self.parse_add()))
349 else:
350 break
351 lineno = self.stream.current.lineno
352 if not ops:
353 return expr
354 return nodes.Compare(expr, ops, lineno=lineno)
355
356 def parse_add(self):
357 lineno = self.stream.current.lineno
358 left = self.parse_sub()
359 while self.stream.current.type is 'add':
360 self.stream.next()
361 right = self.parse_sub()
362 left = nodes.Add(left, right, lineno=lineno)
363 lineno = self.stream.current.lineno
364 return left
365
366 def parse_sub(self):
367 lineno = self.stream.current.lineno
368 left = self.parse_concat()
369 while self.stream.current.type is 'sub':
370 self.stream.next()
371 right = self.parse_concat()
372 left = nodes.Sub(left, right, lineno=lineno)
373 lineno = self.stream.current.lineno
374 return left
375
376 def parse_concat(self):
377 lineno = self.stream.current.lineno
378 args = [self.parse_mul()]
379 while self.stream.current.type is 'tilde':
380 self.stream.next()
381 args.append(self.parse_mul())
382 if len(args) == 1:
383 return args[0]
384 return nodes.Concat(args, lineno=lineno)
385
386 def parse_mul(self):
387 lineno = self.stream.current.lineno
388 left = self.parse_div()
389 while self.stream.current.type is 'mul':
390 self.stream.next()
391 right = self.parse_div()
392 left = nodes.Mul(left, right, lineno=lineno)
393 lineno = self.stream.current.lineno
394 return left
395
396 def parse_div(self):
397 lineno = self.stream.current.lineno
398 left = self.parse_floordiv()
399 while self.stream.current.type is 'div':
400 self.stream.next()
401 right = self.parse_floordiv()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200402 left = nodes.Div(left, right, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200403 lineno = self.stream.current.lineno
404 return left
405
406 def parse_floordiv(self):
407 lineno = self.stream.current.lineno
408 left = self.parse_mod()
409 while self.stream.current.type is 'floordiv':
410 self.stream.next()
411 right = self.parse_mod()
412 left = nodes.FloorDiv(left, right, lineno=lineno)
413 lineno = self.stream.current.lineno
414 return left
415
416 def parse_mod(self):
417 lineno = self.stream.current.lineno
418 left = self.parse_pow()
419 while self.stream.current.type is 'mod':
420 self.stream.next()
421 right = self.parse_pow()
422 left = nodes.Mod(left, right, lineno=lineno)
423 lineno = self.stream.current.lineno
424 return left
425
426 def parse_pow(self):
427 lineno = self.stream.current.lineno
428 left = self.parse_unary()
429 while self.stream.current.type is 'pow':
430 self.stream.next()
431 right = self.parse_unary()
432 left = nodes.Pow(left, right, lineno=lineno)
433 lineno = self.stream.current.lineno
434 return left
435
436 def parse_unary(self):
437 token_type = self.stream.current.type
438 lineno = self.stream.current.lineno
Armin Ronacher115de2e2008-05-01 22:20:05 +0200439 if token_type is 'name' and self.stream.current.value == 'not':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200440 self.stream.next()
441 node = self.parse_unary()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200442 return nodes.Not(node, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200443 if token_type is 'sub':
444 self.stream.next()
445 node = self.parse_unary()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200446 return nodes.Neg(node, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200447 if token_type is 'add':
448 self.stream.next()
449 node = self.parse_unary()
450 return nodes.Pos(node, lineno=lineno)
451 return self.parse_primary()
452
Armin Ronacher09c002e2008-05-10 22:21:30 +0200453 def parse_primary(self, with_postfix=True):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200454 token = self.stream.current
455 if token.type is 'name':
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200456 if token.value in ('true', 'false', 'True', 'False'):
457 node = nodes.Const(token.value in ('true', 'True'),
458 lineno=token.lineno)
459 elif token.value in ('none', 'None'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200460 node = nodes.Const(None, lineno=token.lineno)
461 else:
462 node = nodes.Name(token.value, 'load', lineno=token.lineno)
463 self.stream.next()
464 elif token.type in ('integer', 'float', 'string'):
465 self.stream.next()
466 node = nodes.Const(token.value, lineno=token.lineno)
467 elif token.type is 'lparen':
468 self.stream.next()
469 node = self.parse_tuple()
470 self.stream.expect('rparen')
471 elif token.type is 'lbracket':
472 node = self.parse_list()
473 elif token.type is 'lbrace':
474 node = self.parse_dict()
475 else:
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200476 self.fail("unexpected token '%s'" % (token,), token.lineno)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200477 if with_postfix:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200478 node = self.parse_postfix(node)
479 return node
480
Armin Ronacherfdf95302008-05-11 22:20:51 +0200481 def parse_tuple(self, simplified=False, with_condexpr=True,
482 extra_end_rules=None):
Armin Ronacher023b5e92008-05-08 11:03:10 +0200483 """Works like `parse_expression` but if multiple expressions are
484 delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created.
485 This method could also return a regular expression instead of a tuple
486 if no commas where found.
487
488 The default parsing mode is a full tuple. If `simplified` is `True`
489 only names and literals are parsed. The `no_condexpr` parameter is
490 forwarded to :meth:`parse_expression`.
Armin Ronacherfdf95302008-05-11 22:20:51 +0200491
492 Because tuples do not require delimiters and may end in a bogus comma
493 an extra hint is needed that marks the end of a tuple. For example
494 for loops support tuples between `for` and `in`. In that case the
495 `extra_end_rules` is set to ``['name:in']``.
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200496 """
497 lineno = self.stream.current.lineno
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200498 if simplified:
Armin Ronacher09c002e2008-05-10 22:21:30 +0200499 parse = lambda: self.parse_primary(with_postfix=False)
500 elif with_condexpr:
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200501 parse = self.parse_expression
Armin Ronacher09c002e2008-05-10 22:21:30 +0200502 else:
503 parse = lambda: self.parse_expression(with_condexpr=False)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200504 args = []
505 is_tuple = False
506 while 1:
507 if args:
508 self.stream.expect('comma')
Armin Ronacherfdf95302008-05-11 22:20:51 +0200509 if self.is_tuple_end(extra_end_rules):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200510 break
511 args.append(parse())
Armin Ronacherb5124e62008-04-25 00:36:14 +0200512 if self.stream.current.type is 'comma':
513 is_tuple = True
514 else:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200515 break
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200516 lineno = self.stream.current.lineno
517 if not is_tuple and args:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200518 return args[0]
519 return nodes.Tuple(args, 'load', lineno=lineno)
520
521 def parse_list(self):
522 token = self.stream.expect('lbracket')
523 items = []
524 while self.stream.current.type is not 'rbracket':
525 if items:
526 self.stream.expect('comma')
527 if self.stream.current.type == 'rbracket':
528 break
529 items.append(self.parse_expression())
530 self.stream.expect('rbracket')
531 return nodes.List(items, lineno=token.lineno)
532
533 def parse_dict(self):
534 token = self.stream.expect('lbrace')
535 items = []
536 while self.stream.current.type is not 'rbrace':
537 if items:
538 self.stream.expect('comma')
539 if self.stream.current.type == 'rbrace':
540 break
541 key = self.parse_expression()
542 self.stream.expect('colon')
543 value = self.parse_expression()
544 items.append(nodes.Pair(key, value, lineno=key.lineno))
545 self.stream.expect('rbrace')
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200546 return nodes.Dict(items, lineno=token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200547
548 def parse_postfix(self, node):
549 while 1:
550 token_type = self.stream.current.type
551 if token_type is 'dot' or token_type is 'lbracket':
552 node = self.parse_subscript(node)
553 elif token_type is 'lparen':
554 node = self.parse_call(node)
555 elif token_type is 'pipe':
556 node = self.parse_filter(node)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200557 elif token_type is 'name' and self.stream.current.value == 'is':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200558 node = self.parse_test(node)
559 else:
560 break
561 return node
562
563 def parse_subscript(self, node):
564 token = self.stream.next()
565 if token.type is 'dot':
Armin Ronachere791c2a2008-04-07 18:39:54 +0200566 attr_token = self.stream.current
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200567 self.stream.next()
568 if attr_token.type is 'name':
569 return nodes.Getattr(node, attr_token.value, 'load',
570 lineno=token.lineno)
571 elif attr_token.type is not 'integer':
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200572 self.fail('expected name or number', attr_token.lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200573 arg = nodes.Const(attr_token.value, lineno=attr_token.lineno)
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200574 return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
575 if token.type is 'lbracket':
576 priority_on_attribute = False
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200577 args = []
578 while self.stream.current.type is not 'rbracket':
579 if args:
580 self.stream.expect('comma')
581 args.append(self.parse_subscribed())
582 self.stream.expect('rbracket')
583 if len(args) == 1:
584 arg = args[0]
585 else:
Benjamin Wieganda3152742008-04-28 18:07:52 +0200586 arg = nodes.Tuple(args, self.lineno, self.filename)
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200587 return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
588 self.fail('expected subscript expression', self.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200589
590 def parse_subscribed(self):
591 lineno = self.stream.current.lineno
592
593 if self.stream.current.type is 'colon':
594 self.stream.next()
595 args = [None]
596 else:
597 node = self.parse_expression()
598 if self.stream.current.type is not 'colon':
599 return node
600 self.stream.next()
601 args = [node]
602
603 if self.stream.current.type is 'colon':
604 args.append(None)
605 elif self.stream.current.type not in ('rbracket', 'comma'):
606 args.append(self.parse_expression())
607 else:
608 args.append(None)
609
610 if self.stream.current.type is 'colon':
611 self.stream.next()
612 if self.stream.current.type not in ('rbracket', 'comma'):
613 args.append(self.parse_expression())
614 else:
615 args.append(None)
616 else:
617 args.append(None)
618
619 return nodes.Slice(lineno=lineno, *args)
620
621 def parse_call(self, node):
622 token = self.stream.expect('lparen')
623 args = []
624 kwargs = []
625 dyn_args = dyn_kwargs = None
626 require_comma = False
627
628 def ensure(expr):
629 if not expr:
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200630 self.fail('invalid syntax for function call expression',
631 token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200632
633 while self.stream.current.type is not 'rparen':
634 if require_comma:
635 self.stream.expect('comma')
636 # support for trailing comma
637 if self.stream.current.type is 'rparen':
638 break
639 if self.stream.current.type is 'mul':
640 ensure(dyn_args is None and dyn_kwargs is None)
641 self.stream.next()
642 dyn_args = self.parse_expression()
643 elif self.stream.current.type is 'pow':
644 ensure(dyn_kwargs is None)
645 self.stream.next()
646 dyn_kwargs = self.parse_expression()
647 else:
648 ensure(dyn_args is None and dyn_kwargs is None)
649 if self.stream.current.type is 'name' and \
650 self.stream.look().type is 'assign':
651 key = self.stream.current.value
652 self.stream.skip(2)
Armin Ronacher0611e492008-04-25 23:44:14 +0200653 value = self.parse_expression()
654 kwargs.append(nodes.Keyword(key, value,
655 lineno=value.lineno))
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200656 else:
657 ensure(not kwargs)
658 args.append(self.parse_expression())
659
660 require_comma = True
661 self.stream.expect('rparen')
662
663 if node is None:
664 return args, kwargs, dyn_args, dyn_kwargs
665 return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs,
666 lineno=token.lineno)
667
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200668 def parse_filter(self, node, start_inline=False):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200669 while self.stream.current.type == 'pipe' or start_inline:
670 if not start_inline:
671 self.stream.next()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200672 token = self.stream.expect('name')
Armin Ronacherb9e78752008-05-10 23:36:28 +0200673 name = token.value
674 while self.stream.current.type is 'dot':
675 self.stream.next()
676 name += '.' + self.stream.expect('name').value
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200677 if self.stream.current.type is 'lparen':
678 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
679 else:
680 args = []
681 kwargs = []
682 dyn_args = dyn_kwargs = None
Armin Ronacherb9e78752008-05-10 23:36:28 +0200683 node = nodes.Filter(node, name, args, kwargs, dyn_args,
Armin Ronacherd55ab532008-04-09 16:13:39 +0200684 dyn_kwargs, lineno=token.lineno)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200685 start_inline = False
Armin Ronacherd55ab532008-04-09 16:13:39 +0200686 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200687
688 def parse_test(self, node):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200689 token = self.stream.next()
690 if self.stream.current.test('name:not'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200691 self.stream.next()
692 negated = True
693 else:
694 negated = False
695 name = self.stream.expect('name').value
Armin Ronacherb9e78752008-05-10 23:36:28 +0200696 while self.stream.current.type is 'dot':
697 self.stream.next()
698 name += '.' + self.stream.expect('name').value
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200699 dyn_args = dyn_kwargs = None
700 kwargs = []
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200701 if self.stream.current.type is 'lparen':
702 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
703 elif self.stream.current.type in ('name', 'string', 'integer',
704 'float', 'lparen', 'lbracket',
Armin Ronachere3290ea2008-06-12 10:30:01 +0200705 'lbrace') and not \
706 self.stream.current.test_any('name:else', 'name:or',
707 'name:and'):
708 if self.stream.current.test('name:is'):
709 self.fail('You cannot chain multiple tests with is')
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:
Armin Ronacher5411ce72008-05-25 11:36:22 +0200734 add_data(nodes.TemplateData(token.value,
735 lineno=token.lineno))
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200736 self.stream.next()
737 elif token.type is 'variable_begin':
738 self.stream.next()
Armin Ronacher09c002e2008-05-10 22:21:30 +0200739 add_data(self.parse_tuple(with_condexpr=True))
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200740 self.stream.expect('variable_end')
741 elif token.type is 'block_begin':
742 flush_data()
743 self.stream.next()
744 if end_tokens is not None and \
Armin Ronachercda43df2008-05-03 17:10:05 +0200745 self.stream.current.test_any(*end_tokens):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200746 return body
Armin Ronacher023b5e92008-05-08 11:03:10 +0200747 rv = self.parse_statement()
748 if isinstance(rv, list):
749 body.extend(rv)
750 else:
751 body.append(rv)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200752 self.stream.expect('block_end')
753 else:
754 raise AssertionError('internal parsing error')
755
756 flush_data()
757 return body
758
759 def parse(self):
760 """Parse the whole template into a `Template` node."""
Armin Ronacherd55ab532008-04-09 16:13:39 +0200761 result = nodes.Template(self.subparse(), lineno=1)
762 result.set_environment(self.environment)
763 return result