blob: d365d4c0d18acdd8298a76fb5e59f40656e1c795 [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 Ronacher547d0b62008-07-04 16:35:10 +0200310 if self.stream.skip_if('name:else'):
311 expr3 = self.parse_condexpr()
312 else:
313 expr3 = None
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200314 expr1 = nodes.CondExpr(expr2, expr1, expr3, lineno=lineno)
315 lineno = self.stream.current.lineno
316 return expr1
317
318 def parse_or(self):
319 lineno = self.stream.current.lineno
320 left = self.parse_and()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200321 while self.stream.skip_if('name:or'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200322 right = self.parse_and()
323 left = nodes.Or(left, right, lineno=lineno)
324 lineno = self.stream.current.lineno
325 return left
326
327 def parse_and(self):
328 lineno = self.stream.current.lineno
329 left = self.parse_compare()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200330 while self.stream.skip_if('name:and'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200331 right = self.parse_compare()
332 left = nodes.And(left, right, lineno=lineno)
333 lineno = self.stream.current.lineno
334 return left
335
336 def parse_compare(self):
337 lineno = self.stream.current.lineno
338 expr = self.parse_add()
339 ops = []
340 while 1:
341 token_type = self.stream.current.type
342 if token_type in _compare_operators:
343 self.stream.next()
344 ops.append(nodes.Operand(token_type, self.parse_add()))
Armin Ronacherfdf95302008-05-11 22:20:51 +0200345 elif self.stream.skip_if('name:in'):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200346 ops.append(nodes.Operand('in', self.parse_add()))
347 elif self.stream.current.test('name:not') and \
348 self.stream.look().test('name:in'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200349 self.stream.skip(2)
350 ops.append(nodes.Operand('notin', self.parse_add()))
351 else:
352 break
353 lineno = self.stream.current.lineno
354 if not ops:
355 return expr
356 return nodes.Compare(expr, ops, lineno=lineno)
357
358 def parse_add(self):
359 lineno = self.stream.current.lineno
360 left = self.parse_sub()
361 while self.stream.current.type is 'add':
362 self.stream.next()
363 right = self.parse_sub()
364 left = nodes.Add(left, right, lineno=lineno)
365 lineno = self.stream.current.lineno
366 return left
367
368 def parse_sub(self):
369 lineno = self.stream.current.lineno
370 left = self.parse_concat()
371 while self.stream.current.type is 'sub':
372 self.stream.next()
373 right = self.parse_concat()
374 left = nodes.Sub(left, right, lineno=lineno)
375 lineno = self.stream.current.lineno
376 return left
377
378 def parse_concat(self):
379 lineno = self.stream.current.lineno
380 args = [self.parse_mul()]
381 while self.stream.current.type is 'tilde':
382 self.stream.next()
383 args.append(self.parse_mul())
384 if len(args) == 1:
385 return args[0]
386 return nodes.Concat(args, lineno=lineno)
387
388 def parse_mul(self):
389 lineno = self.stream.current.lineno
390 left = self.parse_div()
391 while self.stream.current.type is 'mul':
392 self.stream.next()
393 right = self.parse_div()
394 left = nodes.Mul(left, right, lineno=lineno)
395 lineno = self.stream.current.lineno
396 return left
397
398 def parse_div(self):
399 lineno = self.stream.current.lineno
400 left = self.parse_floordiv()
401 while self.stream.current.type is 'div':
402 self.stream.next()
403 right = self.parse_floordiv()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200404 left = nodes.Div(left, right, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200405 lineno = self.stream.current.lineno
406 return left
407
408 def parse_floordiv(self):
409 lineno = self.stream.current.lineno
410 left = self.parse_mod()
411 while self.stream.current.type is 'floordiv':
412 self.stream.next()
413 right = self.parse_mod()
414 left = nodes.FloorDiv(left, right, lineno=lineno)
415 lineno = self.stream.current.lineno
416 return left
417
418 def parse_mod(self):
419 lineno = self.stream.current.lineno
420 left = self.parse_pow()
421 while self.stream.current.type is 'mod':
422 self.stream.next()
423 right = self.parse_pow()
424 left = nodes.Mod(left, right, lineno=lineno)
425 lineno = self.stream.current.lineno
426 return left
427
428 def parse_pow(self):
429 lineno = self.stream.current.lineno
430 left = self.parse_unary()
431 while self.stream.current.type is 'pow':
432 self.stream.next()
433 right = self.parse_unary()
434 left = nodes.Pow(left, right, lineno=lineno)
435 lineno = self.stream.current.lineno
436 return left
437
438 def parse_unary(self):
439 token_type = self.stream.current.type
440 lineno = self.stream.current.lineno
Armin Ronacher115de2e2008-05-01 22:20:05 +0200441 if token_type is 'name' and self.stream.current.value == 'not':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200442 self.stream.next()
443 node = self.parse_unary()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200444 return nodes.Not(node, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200445 if token_type is 'sub':
446 self.stream.next()
447 node = self.parse_unary()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200448 return nodes.Neg(node, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200449 if token_type is 'add':
450 self.stream.next()
451 node = self.parse_unary()
452 return nodes.Pos(node, lineno=lineno)
453 return self.parse_primary()
454
Armin Ronacher09c002e2008-05-10 22:21:30 +0200455 def parse_primary(self, with_postfix=True):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200456 token = self.stream.current
457 if token.type is 'name':
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200458 if token.value in ('true', 'false', 'True', 'False'):
459 node = nodes.Const(token.value in ('true', 'True'),
460 lineno=token.lineno)
461 elif token.value in ('none', 'None'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200462 node = nodes.Const(None, lineno=token.lineno)
463 else:
464 node = nodes.Name(token.value, 'load', lineno=token.lineno)
465 self.stream.next()
Armin Ronacher4778bda2008-06-22 12:48:37 +0200466 elif token.type is 'string':
467 self.stream.next()
468 buf = [token.value]
469 lineno = token.lineno
470 while self.stream.current.type is 'string':
471 buf.append(self.stream.current.value)
472 self.stream.next()
473 node = nodes.Const(''.join(buf), lineno=lineno)
474 elif token.type in ('integer', 'float'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200475 self.stream.next()
476 node = nodes.Const(token.value, lineno=token.lineno)
477 elif token.type is 'lparen':
478 self.stream.next()
479 node = self.parse_tuple()
480 self.stream.expect('rparen')
481 elif token.type is 'lbracket':
482 node = self.parse_list()
483 elif token.type is 'lbrace':
484 node = self.parse_dict()
485 else:
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200486 self.fail("unexpected token '%s'" % (token,), token.lineno)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200487 if with_postfix:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200488 node = self.parse_postfix(node)
489 return node
490
Armin Ronacherfdf95302008-05-11 22:20:51 +0200491 def parse_tuple(self, simplified=False, with_condexpr=True,
492 extra_end_rules=None):
Armin Ronacher023b5e92008-05-08 11:03:10 +0200493 """Works like `parse_expression` but if multiple expressions are
494 delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created.
495 This method could also return a regular expression instead of a tuple
496 if no commas where found.
497
498 The default parsing mode is a full tuple. If `simplified` is `True`
499 only names and literals are parsed. The `no_condexpr` parameter is
500 forwarded to :meth:`parse_expression`.
Armin Ronacherfdf95302008-05-11 22:20:51 +0200501
502 Because tuples do not require delimiters and may end in a bogus comma
503 an extra hint is needed that marks the end of a tuple. For example
504 for loops support tuples between `for` and `in`. In that case the
505 `extra_end_rules` is set to ``['name:in']``.
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200506 """
507 lineno = self.stream.current.lineno
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200508 if simplified:
Armin Ronacher09c002e2008-05-10 22:21:30 +0200509 parse = lambda: self.parse_primary(with_postfix=False)
510 elif with_condexpr:
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200511 parse = self.parse_expression
Armin Ronacher09c002e2008-05-10 22:21:30 +0200512 else:
513 parse = lambda: self.parse_expression(with_condexpr=False)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200514 args = []
515 is_tuple = False
516 while 1:
517 if args:
518 self.stream.expect('comma')
Armin Ronacherfdf95302008-05-11 22:20:51 +0200519 if self.is_tuple_end(extra_end_rules):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200520 break
521 args.append(parse())
Armin Ronacherb5124e62008-04-25 00:36:14 +0200522 if self.stream.current.type is 'comma':
523 is_tuple = True
524 else:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200525 break
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200526 lineno = self.stream.current.lineno
527 if not is_tuple and args:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200528 return args[0]
529 return nodes.Tuple(args, 'load', lineno=lineno)
530
531 def parse_list(self):
532 token = self.stream.expect('lbracket')
533 items = []
534 while self.stream.current.type is not 'rbracket':
535 if items:
536 self.stream.expect('comma')
537 if self.stream.current.type == 'rbracket':
538 break
539 items.append(self.parse_expression())
540 self.stream.expect('rbracket')
541 return nodes.List(items, lineno=token.lineno)
542
543 def parse_dict(self):
544 token = self.stream.expect('lbrace')
545 items = []
546 while self.stream.current.type is not 'rbrace':
547 if items:
548 self.stream.expect('comma')
549 if self.stream.current.type == 'rbrace':
550 break
551 key = self.parse_expression()
552 self.stream.expect('colon')
553 value = self.parse_expression()
554 items.append(nodes.Pair(key, value, lineno=key.lineno))
555 self.stream.expect('rbrace')
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200556 return nodes.Dict(items, lineno=token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200557
558 def parse_postfix(self, node):
559 while 1:
560 token_type = self.stream.current.type
561 if token_type is 'dot' or token_type is 'lbracket':
562 node = self.parse_subscript(node)
563 elif token_type is 'lparen':
564 node = self.parse_call(node)
565 elif token_type is 'pipe':
566 node = self.parse_filter(node)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200567 elif token_type is 'name' and self.stream.current.value == 'is':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200568 node = self.parse_test(node)
569 else:
570 break
571 return node
572
573 def parse_subscript(self, node):
574 token = self.stream.next()
575 if token.type is 'dot':
Armin Ronachere791c2a2008-04-07 18:39:54 +0200576 attr_token = self.stream.current
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200577 self.stream.next()
578 if attr_token.type is 'name':
579 return nodes.Getattr(node, attr_token.value, 'load',
580 lineno=token.lineno)
581 elif attr_token.type is not 'integer':
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200582 self.fail('expected name or number', attr_token.lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200583 arg = nodes.Const(attr_token.value, lineno=attr_token.lineno)
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200584 return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
585 if token.type is 'lbracket':
586 priority_on_attribute = False
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200587 args = []
588 while self.stream.current.type is not 'rbracket':
589 if args:
590 self.stream.expect('comma')
591 args.append(self.parse_subscribed())
592 self.stream.expect('rbracket')
593 if len(args) == 1:
594 arg = args[0]
595 else:
Benjamin Wieganda3152742008-04-28 18:07:52 +0200596 arg = nodes.Tuple(args, self.lineno, self.filename)
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200597 return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
598 self.fail('expected subscript expression', self.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200599
600 def parse_subscribed(self):
601 lineno = self.stream.current.lineno
602
603 if self.stream.current.type is 'colon':
604 self.stream.next()
605 args = [None]
606 else:
607 node = self.parse_expression()
608 if self.stream.current.type is not 'colon':
609 return node
610 self.stream.next()
611 args = [node]
612
613 if self.stream.current.type is 'colon':
614 args.append(None)
615 elif self.stream.current.type not in ('rbracket', 'comma'):
616 args.append(self.parse_expression())
617 else:
618 args.append(None)
619
620 if self.stream.current.type is 'colon':
621 self.stream.next()
622 if self.stream.current.type not in ('rbracket', 'comma'):
623 args.append(self.parse_expression())
624 else:
625 args.append(None)
626 else:
627 args.append(None)
628
629 return nodes.Slice(lineno=lineno, *args)
630
631 def parse_call(self, node):
632 token = self.stream.expect('lparen')
633 args = []
634 kwargs = []
635 dyn_args = dyn_kwargs = None
636 require_comma = False
637
638 def ensure(expr):
639 if not expr:
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200640 self.fail('invalid syntax for function call expression',
641 token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200642
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 Ronacherfa865fb2008-04-12 22:11:53 +0200679 while self.stream.current.type == 'pipe' or start_inline:
680 if not start_inline:
681 self.stream.next()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200682 token = self.stream.expect('name')
Armin Ronacherb9e78752008-05-10 23:36:28 +0200683 name = token.value
684 while self.stream.current.type is 'dot':
685 self.stream.next()
686 name += '.' + self.stream.expect('name').value
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200687 if self.stream.current.type is 'lparen':
688 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
689 else:
690 args = []
691 kwargs = []
692 dyn_args = dyn_kwargs = None
Armin Ronacherb9e78752008-05-10 23:36:28 +0200693 node = nodes.Filter(node, name, args, kwargs, dyn_args,
Armin Ronacherd55ab532008-04-09 16:13:39 +0200694 dyn_kwargs, lineno=token.lineno)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200695 start_inline = False
Armin Ronacherd55ab532008-04-09 16:13:39 +0200696 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200697
698 def parse_test(self, node):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200699 token = self.stream.next()
700 if self.stream.current.test('name:not'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200701 self.stream.next()
702 negated = True
703 else:
704 negated = False
705 name = self.stream.expect('name').value
Armin Ronacherb9e78752008-05-10 23:36:28 +0200706 while self.stream.current.type is 'dot':
707 self.stream.next()
708 name += '.' + self.stream.expect('name').value
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200709 dyn_args = dyn_kwargs = None
710 kwargs = []
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200711 if self.stream.current.type is 'lparen':
712 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
713 elif self.stream.current.type in ('name', 'string', 'integer',
714 'float', 'lparen', 'lbracket',
Armin Ronachere3290ea2008-06-12 10:30:01 +0200715 'lbrace') and not \
716 self.stream.current.test_any('name:else', 'name:or',
717 'name:and'):
718 if self.stream.current.test('name:is'):
719 self.fail('You cannot chain multiple tests with is')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200720 args = [self.parse_expression()]
721 else:
722 args = []
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200723 node = nodes.Test(node, name, args, kwargs, dyn_args,
724 dyn_kwargs, lineno=token.lineno)
725 if negated:
Armin Ronacher9a822052008-04-17 18:44:07 +0200726 node = nodes.Not(node, lineno=token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200727 return node
728
729 def subparse(self, end_tokens=None):
730 body = []
731 data_buffer = []
732 add_data = data_buffer.append
733
734 def flush_data():
735 if data_buffer:
736 lineno = data_buffer[0].lineno
737 body.append(nodes.Output(data_buffer[:], lineno=lineno))
738 del data_buffer[:]
739
740 while self.stream:
741 token = self.stream.current
742 if token.type is 'data':
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200743 if token.value:
Armin Ronacher5411ce72008-05-25 11:36:22 +0200744 add_data(nodes.TemplateData(token.value,
745 lineno=token.lineno))
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200746 self.stream.next()
747 elif token.type is 'variable_begin':
748 self.stream.next()
Armin Ronacher09c002e2008-05-10 22:21:30 +0200749 add_data(self.parse_tuple(with_condexpr=True))
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200750 self.stream.expect('variable_end')
751 elif token.type is 'block_begin':
752 flush_data()
753 self.stream.next()
754 if end_tokens is not None and \
Armin Ronachercda43df2008-05-03 17:10:05 +0200755 self.stream.current.test_any(*end_tokens):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200756 return body
Armin Ronacher023b5e92008-05-08 11:03:10 +0200757 rv = self.parse_statement()
758 if isinstance(rv, list):
759 body.extend(rv)
760 else:
761 body.append(rv)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200762 self.stream.expect('block_end')
763 else:
764 raise AssertionError('internal parsing error')
765
766 flush_data()
767 return body
768
769 def parse(self):
770 """Parse the whole template into a `Template` node."""
Armin Ronacherd55ab532008-04-09 16:13:39 +0200771 result = nodes.Template(self.subparse(), lineno=1)
772 result.set_environment(self.environment)
773 return result