blob: 86ee570aa7088c80fad919ab31d68dde8979acb9 [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 Ronacherbf7c4ad2008-04-12 12:02:36 +020028 self.source = unicode(source)
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 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
Armin Ronacher7f15ef82008-05-16 09:11:39 +020039 def fail(self, msg, lineno=None, exc=TemplateSyntaxError):
40 """Convenience method that raises `exc` with the message, passed
41 line number or last line number as well as the current name and
42 filename.
43 """
44 if lineno is None:
45 lineno = self.stream.current.lineno
46 raise TemplateSyntaxError(msg, lineno, self.name, self.filename)
47
Armin Ronacherfdf95302008-05-11 22:20:51 +020048 def is_tuple_end(self, extra_end_rules=None):
Armin Ronacher115de2e2008-05-01 22:20:05 +020049 """Are we at the end of a tuple?"""
Armin Ronacherfdf95302008-05-11 22:20:51 +020050 if self.stream.current.type in ('variable_end', 'block_end', 'rparen'):
Armin Ronacher023b5e92008-05-08 11:03:10 +020051 return True
Armin Ronacherfdf95302008-05-11 22:20:51 +020052 elif extra_end_rules is not None:
53 return self.stream.current.test_any(extra_end_rules)
Armin Ronacher762079c2008-05-08 23:57:56 +020054 return False
55
Armin Ronacher023b5e92008-05-08 11:03:10 +020056 def free_identifier(self, lineno=None):
57 """Return a new free identifier as :class:`~jinja2.nodes.InternalName`."""
58 self._last_identifier += 1
59 rv = object.__new__(nodes.InternalName)
60 nodes.Node.__init__(rv, 'fi%d' % self._last_identifier, lineno=lineno)
61 return rv
Armin Ronacher115de2e2008-05-01 22:20:05 +020062
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020063 def parse_statement(self):
64 """Parse a single statement."""
Armin Ronacher0a2ac692008-05-13 01:03:08 +020065 token = self.stream.current
66 if token.type is not 'name':
Armin Ronacher7f15ef82008-05-16 09:11:39 +020067 self.fail('tag name expected', token.lineno)
Armin Ronacher0a2ac692008-05-13 01:03:08 +020068 if token.value in _statement_keywords:
69 return getattr(self, 'parse_' + self.stream.current.value)()
70 if token.value == 'call':
71 return self.parse_call_block()
72 if token.value == 'filter':
73 return self.parse_filter_block()
74 ext = self.extensions.get(token.value)
75 if ext is not None:
76 return ext(self)
Armin Ronacher7f15ef82008-05-16 09:11:39 +020077 self.fail('unknown tag %r' % token.value, token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020078
79 def parse_statements(self, end_tokens, drop_needle=False):
Armin Ronacherf59bac22008-04-20 13:11:43 +020080 """Parse multiple statements into a list until one of the end tokens
81 is reached. This is used to parse the body of statements as it also
Armin Ronacher023b5e92008-05-08 11:03:10 +020082 parses template data if appropriate. The parser checks first if the
83 current token is a colon and skips it if there is one. Then it checks
84 for the block end and parses until if one of the `end_tokens` is
85 reached. Per default the active token in the stream at the end of
86 the call is the matched end token. If this is not wanted `drop_needle`
87 can be set to `True` and the end token is removed.
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020088 """
89 # the first token may be a colon for python compatibility
Armin Ronacherfdf95302008-05-11 22:20:51 +020090 self.stream.skip_if('colon')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020091
Armin Ronacher2b60fe52008-04-21 08:23:59 +020092 # in the future it would be possible to add whole code sections
93 # by adding some sort of end of statement token and parsing those here.
94 self.stream.expect('block_end')
95 result = self.subparse(end_tokens)
96
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020097 if drop_needle:
98 self.stream.next()
99 return result
100
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200101 def parse_set(self):
102 """Parse an assign statement."""
103 lineno = self.stream.next().lineno
104 target = self.parse_assign_target()
105 self.stream.expect('assign')
106 expr = self.parse_tuple()
107 return nodes.Assign(target, expr, lineno=lineno)
108
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200109 def parse_for(self):
110 """Parse a for loop."""
Armin Ronacher115de2e2008-05-01 22:20:05 +0200111 lineno = self.stream.expect('name:for').lineno
Armin Ronacherfdf95302008-05-11 22:20:51 +0200112 target = self.parse_assign_target(extra_end_rules=('name:in',))
Armin Ronacher115de2e2008-05-01 22:20:05 +0200113 self.stream.expect('name:in')
Armin Ronacherfdf95302008-05-11 22:20:51 +0200114 iter = self.parse_tuple(with_condexpr=False,
115 extra_end_rules=('name:recursive',))
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200116 test = None
Armin Ronacherfdf95302008-05-11 22:20:51 +0200117 if self.stream.skip_if('name:if'):
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200118 test = self.parse_expression()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200119 recursive = self.stream.skip_if('name:recursive')
Armin Ronacher115de2e2008-05-01 22:20:05 +0200120 body = self.parse_statements(('name:endfor', 'name:else'))
121 if self.stream.next().value == 'endfor':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200122 else_ = []
123 else:
Armin Ronacher115de2e2008-05-01 22:20:05 +0200124 else_ = self.parse_statements(('name:endfor',), drop_needle=True)
Armin Ronacherfdf95302008-05-11 22:20:51 +0200125 return nodes.For(target, iter, body, else_, test,
126 recursive, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200127
128 def parse_if(self):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200129 """Parse an if construct."""
Armin Ronacher115de2e2008-05-01 22:20:05 +0200130 node = result = nodes.If(lineno=self.stream.expect('name:if').lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200131 while 1:
Armin Ronacher09c002e2008-05-10 22:21:30 +0200132 node.test = self.parse_tuple(with_condexpr=False)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200133 node.body = self.parse_statements(('name:elif', 'name:else',
134 'name:endif'))
135 token = self.stream.next()
136 if token.test('name:elif'):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200137 new_node = nodes.If(lineno=self.stream.current.lineno)
138 node.else_ = [new_node]
139 node = new_node
140 continue
Armin Ronacher115de2e2008-05-01 22:20:05 +0200141 elif token.test('name:else'):
142 node.else_ = self.parse_statements(('name:endif',),
Armin Ronachere791c2a2008-04-07 18:39:54 +0200143 drop_needle=True)
144 else:
145 node.else_ = []
146 break
147 return result
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200148
149 def parse_block(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200150 node = nodes.Block(lineno=self.stream.next().lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200151 node.name = self.stream.expect('name').value
Armin Ronacher115de2e2008-05-01 22:20:05 +0200152 node.body = self.parse_statements(('name:endblock',), drop_needle=True)
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':
456 if token.value in ('true', 'false'):
457 node = nodes.Const(token.value == 'true', lineno=token.lineno)
458 elif token.value == 'none':
459 node = nodes.Const(None, lineno=token.lineno)
460 else:
461 node = nodes.Name(token.value, 'load', lineno=token.lineno)
462 self.stream.next()
463 elif token.type in ('integer', 'float', 'string'):
464 self.stream.next()
465 node = nodes.Const(token.value, lineno=token.lineno)
466 elif token.type is 'lparen':
467 self.stream.next()
468 node = self.parse_tuple()
469 self.stream.expect('rparen')
470 elif token.type is 'lbracket':
471 node = self.parse_list()
472 elif token.type is 'lbrace':
473 node = self.parse_dict()
474 else:
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200475 self.fail("unexpected token '%s'" % (token,), token.lineno)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200476 if with_postfix:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200477 node = self.parse_postfix(node)
478 return node
479
Armin Ronacherfdf95302008-05-11 22:20:51 +0200480 def parse_tuple(self, simplified=False, with_condexpr=True,
481 extra_end_rules=None):
Armin Ronacher023b5e92008-05-08 11:03:10 +0200482 """Works like `parse_expression` but if multiple expressions are
483 delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created.
484 This method could also return a regular expression instead of a tuple
485 if no commas where found.
486
487 The default parsing mode is a full tuple. If `simplified` is `True`
488 only names and literals are parsed. The `no_condexpr` parameter is
489 forwarded to :meth:`parse_expression`.
Armin Ronacherfdf95302008-05-11 22:20:51 +0200490
491 Because tuples do not require delimiters and may end in a bogus comma
492 an extra hint is needed that marks the end of a tuple. For example
493 for loops support tuples between `for` and `in`. In that case the
494 `extra_end_rules` is set to ``['name:in']``.
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200495 """
496 lineno = self.stream.current.lineno
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200497 if simplified:
Armin Ronacher09c002e2008-05-10 22:21:30 +0200498 parse = lambda: self.parse_primary(with_postfix=False)
499 elif with_condexpr:
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200500 parse = self.parse_expression
Armin Ronacher09c002e2008-05-10 22:21:30 +0200501 else:
502 parse = lambda: self.parse_expression(with_condexpr=False)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200503 args = []
504 is_tuple = False
505 while 1:
506 if args:
507 self.stream.expect('comma')
Armin Ronacherfdf95302008-05-11 22:20:51 +0200508 if self.is_tuple_end(extra_end_rules):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200509 break
510 args.append(parse())
Armin Ronacherb5124e62008-04-25 00:36:14 +0200511 if self.stream.current.type is 'comma':
512 is_tuple = True
513 else:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200514 break
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200515 lineno = self.stream.current.lineno
516 if not is_tuple and args:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200517 return args[0]
518 return nodes.Tuple(args, 'load', lineno=lineno)
519
520 def parse_list(self):
521 token = self.stream.expect('lbracket')
522 items = []
523 while self.stream.current.type is not 'rbracket':
524 if items:
525 self.stream.expect('comma')
526 if self.stream.current.type == 'rbracket':
527 break
528 items.append(self.parse_expression())
529 self.stream.expect('rbracket')
530 return nodes.List(items, lineno=token.lineno)
531
532 def parse_dict(self):
533 token = self.stream.expect('lbrace')
534 items = []
535 while self.stream.current.type is not 'rbrace':
536 if items:
537 self.stream.expect('comma')
538 if self.stream.current.type == 'rbrace':
539 break
540 key = self.parse_expression()
541 self.stream.expect('colon')
542 value = self.parse_expression()
543 items.append(nodes.Pair(key, value, lineno=key.lineno))
544 self.stream.expect('rbrace')
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200545 return nodes.Dict(items, lineno=token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200546
547 def parse_postfix(self, node):
548 while 1:
549 token_type = self.stream.current.type
550 if token_type is 'dot' or token_type is 'lbracket':
551 node = self.parse_subscript(node)
552 elif token_type is 'lparen':
553 node = self.parse_call(node)
554 elif token_type is 'pipe':
555 node = self.parse_filter(node)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200556 elif token_type is 'name' and self.stream.current.value == 'is':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200557 node = self.parse_test(node)
558 else:
559 break
560 return node
561
562 def parse_subscript(self, node):
563 token = self.stream.next()
564 if token.type is 'dot':
Armin Ronachere791c2a2008-04-07 18:39:54 +0200565 attr_token = self.stream.current
566 if attr_token.type not in ('name', 'integer'):
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200567 self.fail('expected name or number', attr_token.lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200568 arg = nodes.Const(attr_token.value, lineno=attr_token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200569 self.stream.next()
570 elif token.type is 'lbracket':
571 args = []
572 while self.stream.current.type is not 'rbracket':
573 if args:
574 self.stream.expect('comma')
575 args.append(self.parse_subscribed())
576 self.stream.expect('rbracket')
577 if len(args) == 1:
578 arg = args[0]
579 else:
Benjamin Wieganda3152742008-04-28 18:07:52 +0200580 arg = nodes.Tuple(args, self.lineno, self.filename)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200581 else:
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200582 self.fail('expected subscript expression', self.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200583 return nodes.Subscript(node, arg, 'load', lineno=token.lineno)
584
585 def parse_subscribed(self):
586 lineno = self.stream.current.lineno
587
588 if self.stream.current.type is 'colon':
589 self.stream.next()
590 args = [None]
591 else:
592 node = self.parse_expression()
593 if self.stream.current.type is not 'colon':
594 return node
595 self.stream.next()
596 args = [node]
597
598 if self.stream.current.type is 'colon':
599 args.append(None)
600 elif self.stream.current.type not in ('rbracket', 'comma'):
601 args.append(self.parse_expression())
602 else:
603 args.append(None)
604
605 if self.stream.current.type is 'colon':
606 self.stream.next()
607 if self.stream.current.type not in ('rbracket', 'comma'):
608 args.append(self.parse_expression())
609 else:
610 args.append(None)
611 else:
612 args.append(None)
613
614 return nodes.Slice(lineno=lineno, *args)
615
616 def parse_call(self, node):
617 token = self.stream.expect('lparen')
618 args = []
619 kwargs = []
620 dyn_args = dyn_kwargs = None
621 require_comma = False
622
623 def ensure(expr):
624 if not expr:
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200625 self.fail('invalid syntax for function call expression',
626 token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200627
628 while self.stream.current.type is not 'rparen':
629 if require_comma:
630 self.stream.expect('comma')
631 # support for trailing comma
632 if self.stream.current.type is 'rparen':
633 break
634 if self.stream.current.type is 'mul':
635 ensure(dyn_args is None and dyn_kwargs is None)
636 self.stream.next()
637 dyn_args = self.parse_expression()
638 elif self.stream.current.type is 'pow':
639 ensure(dyn_kwargs is None)
640 self.stream.next()
641 dyn_kwargs = self.parse_expression()
642 else:
643 ensure(dyn_args is None and dyn_kwargs is None)
644 if self.stream.current.type is 'name' and \
645 self.stream.look().type is 'assign':
646 key = self.stream.current.value
647 self.stream.skip(2)
Armin Ronacher0611e492008-04-25 23:44:14 +0200648 value = self.parse_expression()
649 kwargs.append(nodes.Keyword(key, value,
650 lineno=value.lineno))
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200651 else:
652 ensure(not kwargs)
653 args.append(self.parse_expression())
654
655 require_comma = True
656 self.stream.expect('rparen')
657
658 if node is None:
659 return args, kwargs, dyn_args, dyn_kwargs
660 return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs,
661 lineno=token.lineno)
662
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200663 def parse_filter(self, node, start_inline=False):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200664 while self.stream.current.type == 'pipe' or start_inline:
665 if not start_inline:
666 self.stream.next()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200667 token = self.stream.expect('name')
Armin Ronacherb9e78752008-05-10 23:36:28 +0200668 name = token.value
669 while self.stream.current.type is 'dot':
670 self.stream.next()
671 name += '.' + self.stream.expect('name').value
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200672 if self.stream.current.type is 'lparen':
673 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
674 else:
675 args = []
676 kwargs = []
677 dyn_args = dyn_kwargs = None
Armin Ronacherb9e78752008-05-10 23:36:28 +0200678 node = nodes.Filter(node, name, args, kwargs, dyn_args,
Armin Ronacherd55ab532008-04-09 16:13:39 +0200679 dyn_kwargs, lineno=token.lineno)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200680 start_inline = False
Armin Ronacherd55ab532008-04-09 16:13:39 +0200681 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200682
683 def parse_test(self, node):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200684 token = self.stream.next()
685 if self.stream.current.test('name:not'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200686 self.stream.next()
687 negated = True
688 else:
689 negated = False
690 name = self.stream.expect('name').value
Armin Ronacherb9e78752008-05-10 23:36:28 +0200691 while self.stream.current.type is 'dot':
692 self.stream.next()
693 name += '.' + self.stream.expect('name').value
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200694 dyn_args = dyn_kwargs = None
695 kwargs = []
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200696 if self.stream.current.type is 'lparen':
697 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
698 elif self.stream.current.type in ('name', 'string', 'integer',
699 'float', 'lparen', 'lbracket',
Armin Ronacher115de2e2008-05-01 22:20:05 +0200700 'lbrace'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200701 args = [self.parse_expression()]
702 else:
703 args = []
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200704 node = nodes.Test(node, name, args, kwargs, dyn_args,
705 dyn_kwargs, lineno=token.lineno)
706 if negated:
Armin Ronacher9a822052008-04-17 18:44:07 +0200707 node = nodes.Not(node, lineno=token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200708 return node
709
710 def subparse(self, end_tokens=None):
711 body = []
712 data_buffer = []
713 add_data = data_buffer.append
714
715 def flush_data():
716 if data_buffer:
717 lineno = data_buffer[0].lineno
718 body.append(nodes.Output(data_buffer[:], lineno=lineno))
719 del data_buffer[:]
720
721 while self.stream:
722 token = self.stream.current
723 if token.type is 'data':
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200724 if token.value:
725 add_data(nodes.Const(token.value, lineno=token.lineno))
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200726 self.stream.next()
727 elif token.type is 'variable_begin':
728 self.stream.next()
Armin Ronacher09c002e2008-05-10 22:21:30 +0200729 add_data(self.parse_tuple(with_condexpr=True))
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200730 self.stream.expect('variable_end')
731 elif token.type is 'block_begin':
732 flush_data()
733 self.stream.next()
734 if end_tokens is not None and \
Armin Ronachercda43df2008-05-03 17:10:05 +0200735 self.stream.current.test_any(*end_tokens):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200736 return body
Armin Ronacher023b5e92008-05-08 11:03:10 +0200737 rv = self.parse_statement()
738 if isinstance(rv, list):
739 body.extend(rv)
740 else:
741 body.append(rv)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200742 self.stream.expect('block_end')
743 else:
744 raise AssertionError('internal parsing error')
745
746 flush_data()
747 return body
748
749 def parse(self):
750 """Parse the whole template into a `Template` node."""
Armin Ronacherd55ab532008-04-09 16:13:39 +0200751 result = nodes.Template(self.subparse(), lineno=1)
752 result.set_environment(self.environment)
753 return result