blob: 810e381e13df1bd7950ea20b6a377c86eeb3e78a [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 Ronacher61a5a242008-05-26 12:07:44 +020032 self.stream = environment.lexer.tokenize(self.source, name, 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
Armin Ronacher61a5a242008-05-26 12:07:44 +020046 raise exc(msg, lineno, self.name, self.filename)
Armin Ronacher7f15ef82008-05-16 09:11:39 +020047
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 Ronacherfd310492008-05-25 00:16:51 +0200153 self.stream.skip_if('name:' + node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200154 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200155
156 def parse_extends(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200157 node = nodes.Extends(lineno=self.stream.next().lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200158 node.template = self.parse_expression()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200159 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200160
Armin Ronacherea847c52008-05-02 20:04:32 +0200161 def parse_import_context(self, node, default):
Armin Ronachercda43df2008-05-03 17:10:05 +0200162 if self.stream.current.test_any('name:with', 'name:without') and \
Armin Ronacherea847c52008-05-02 20:04:32 +0200163 self.stream.look().test('name:context'):
164 node.with_context = self.stream.next().value == 'with'
165 self.stream.skip()
166 else:
167 node.with_context = default
168 return node
169
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200170 def parse_include(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200171 node = nodes.Include(lineno=self.stream.next().lineno)
Armin Ronacher0611e492008-04-25 23:44:14 +0200172 node.template = self.parse_expression()
Armin Ronacherea847c52008-05-02 20:04:32 +0200173 return self.parse_import_context(node, True)
Armin Ronacher0611e492008-04-25 23:44:14 +0200174
175 def parse_import(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200176 node = nodes.Import(lineno=self.stream.next().lineno)
Armin Ronacher0611e492008-04-25 23:44:14 +0200177 node.template = self.parse_expression()
178 self.stream.expect('name:as')
Armin Ronacher09c002e2008-05-10 22:21:30 +0200179 node.target = self.parse_assign_target(name_only=True).name
Armin Ronacherea847c52008-05-02 20:04:32 +0200180 return self.parse_import_context(node, False)
Armin Ronacher0611e492008-04-25 23:44:14 +0200181
182 def parse_from(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200183 node = nodes.FromImport(lineno=self.stream.next().lineno)
Armin Ronacher0611e492008-04-25 23:44:14 +0200184 node.template = self.parse_expression()
Armin Ronacher115de2e2008-05-01 22:20:05 +0200185 self.stream.expect('name:import')
Armin Ronacher0611e492008-04-25 23:44:14 +0200186 node.names = []
Armin Ronacherea847c52008-05-02 20:04:32 +0200187
188 def parse_context():
189 if self.stream.current.value in ('with', 'without') and \
190 self.stream.look().test('name:context'):
191 node.with_context = self.stream.next().value == 'with'
192 self.stream.skip()
193 return True
194 return False
195
Armin Ronacher0611e492008-04-25 23:44:14 +0200196 while 1:
197 if node.names:
198 self.stream.expect('comma')
199 if self.stream.current.type is 'name':
Armin Ronacherea847c52008-05-02 20:04:32 +0200200 if parse_context():
201 break
Armin Ronacher09c002e2008-05-10 22:21:30 +0200202 target = self.parse_assign_target(name_only=True)
Armin Ronacher903d1682008-05-23 00:51:58 +0200203 if target.name.startswith('_'):
204 self.fail('names starting with an underline can not '
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200205 'be imported', target.lineno,
206 exc=TemplateAssertionError)
Armin Ronacherfdf95302008-05-11 22:20:51 +0200207 if self.stream.skip_if('name:as'):
Armin Ronacher09c002e2008-05-10 22:21:30 +0200208 alias = self.parse_assign_target(name_only=True)
209 node.names.append((target.name, alias.name))
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200210 else:
211 node.names.append(target.name)
Armin Ronacherea847c52008-05-02 20:04:32 +0200212 if parse_context() or self.stream.current.type is not 'comma':
Armin Ronacher0611e492008-04-25 23:44:14 +0200213 break
214 else:
215 break
Armin Ronacherea847c52008-05-02 20:04:32 +0200216 if not hasattr(node, 'with_context'):
217 node.with_context = False
Armin Ronacherfdf95302008-05-11 22:20:51 +0200218 self.stream.skip_if('comma')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200219 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200220
Armin Ronacher71082072008-04-12 14:19:36 +0200221 def parse_signature(self, node):
222 node.args = args = []
223 node.defaults = defaults = []
224 self.stream.expect('lparen')
225 while self.stream.current.type is not 'rparen':
226 if args:
227 self.stream.expect('comma')
Armin Ronacher09c002e2008-05-10 22:21:30 +0200228 arg = self.parse_assign_target(name_only=True)
Armin Ronachere9411b42008-05-15 16:22:07 +0200229 arg.set_ctx('param')
Armin Ronacherfdf95302008-05-11 22:20:51 +0200230 if self.stream.skip_if('assign'):
Armin Ronacher71082072008-04-12 14:19:36 +0200231 defaults.append(self.parse_expression())
232 args.append(arg)
233 self.stream.expect('rparen')
234
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200235 def parse_call_block(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200236 node = nodes.CallBlock(lineno=self.stream.next().lineno)
Armin Ronacher71082072008-04-12 14:19:36 +0200237 if self.stream.current.type is 'lparen':
238 self.parse_signature(node)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200239 else:
240 node.args = []
241 node.defaults = []
Armin Ronacher71082072008-04-12 14:19:36 +0200242
Armin Ronacher8edbe492008-04-10 20:43:43 +0200243 node.call = self.parse_expression()
244 if not isinstance(node.call, nodes.Call):
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200245 self.fail('expected call', node.lineno)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200246 node.body = self.parse_statements(('name:endcall',), drop_needle=True)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200247 return node
248
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200249 def parse_filter_block(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200250 node = nodes.FilterBlock(lineno=self.stream.next().lineno)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200251 node.filter = self.parse_filter(None, start_inline=True)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200252 node.body = self.parse_statements(('name:endfilter',),
253 drop_needle=True)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200254 return node
255
Armin Ronachere791c2a2008-04-07 18:39:54 +0200256 def parse_macro(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200257 node = nodes.Macro(lineno=self.stream.next().lineno)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200258 node.name = self.parse_assign_target(name_only=True).name
Armin Ronacher71082072008-04-12 14:19:36 +0200259 self.parse_signature(node)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200260 node.body = self.parse_statements(('name:endmacro',),
261 drop_needle=True)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200262 return node
263
264 def parse_print(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200265 node = nodes.Output(lineno=self.stream.next().lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200266 node.nodes = []
Armin Ronacher023b5e92008-05-08 11:03:10 +0200267 while self.stream.current.type is not 'block_end':
Armin Ronachere791c2a2008-04-07 18:39:54 +0200268 if node.nodes:
269 self.stream.expect('comma')
270 node.nodes.append(self.parse_expression())
Armin Ronachere791c2a2008-04-07 18:39:54 +0200271 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200272
Armin Ronacherfdf95302008-05-11 22:20:51 +0200273 def parse_assign_target(self, with_tuple=True, name_only=False,
274 extra_end_rules=None):
Armin Ronacher09c002e2008-05-10 22:21:30 +0200275 """Parse an assignment target. As Jinja2 allows assignments to
276 tuples, this function can parse all allowed assignment targets. Per
277 default assignments to tuples are parsed, that can be disable however
278 by setting `with_tuple` to `False`. If only assignments to names are
Armin Ronacherfdf95302008-05-11 22:20:51 +0200279 wanted `name_only` can be set to `True`. The `extra_end_rules`
280 parameter is forwarded to the tuple parsing function.
Armin Ronacher09c002e2008-05-10 22:21:30 +0200281 """
282 if name_only:
283 token = self.stream.expect('name')
284 target = nodes.Name(token.value, 'store', lineno=token.lineno)
285 else:
286 if with_tuple:
Armin Ronacherfdf95302008-05-11 22:20:51 +0200287 target = self.parse_tuple(simplified=True,
288 extra_end_rules=extra_end_rules)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200289 else:
290 target = self.parse_primary(with_postfix=False)
291 target.set_ctx('store')
292 if not target.can_assign():
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200293 self.fail('can\'t assign to %r' % target.__class__.
294 __name__.lower(), target.lineno)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200295 return target
296
297 def parse_expression(self, with_condexpr=True):
Armin Ronacher023b5e92008-05-08 11:03:10 +0200298 """Parse an expression. Per default all expressions are parsed, if
Armin Ronacher09c002e2008-05-10 22:21:30 +0200299 the optional `with_condexpr` parameter is set to `False` conditional
Armin Ronacher023b5e92008-05-08 11:03:10 +0200300 expressions are not parsed.
301 """
Armin Ronacher09c002e2008-05-10 22:21:30 +0200302 if with_condexpr:
303 return self.parse_condexpr()
304 return self.parse_or()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200305
306 def parse_condexpr(self):
307 lineno = self.stream.current.lineno
308 expr1 = self.parse_or()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200309 while self.stream.skip_if('name:if'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200310 expr2 = self.parse_or()
Armin Ronacher115de2e2008-05-01 22:20:05 +0200311 self.stream.expect('name:else')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200312 expr3 = self.parse_condexpr()
313 expr1 = nodes.CondExpr(expr2, expr1, expr3, lineno=lineno)
314 lineno = self.stream.current.lineno
315 return expr1
316
317 def parse_or(self):
318 lineno = self.stream.current.lineno
319 left = self.parse_and()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200320 while self.stream.skip_if('name:or'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200321 right = self.parse_and()
322 left = nodes.Or(left, right, lineno=lineno)
323 lineno = self.stream.current.lineno
324 return left
325
326 def parse_and(self):
327 lineno = self.stream.current.lineno
328 left = self.parse_compare()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200329 while self.stream.skip_if('name:and'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200330 right = self.parse_compare()
331 left = nodes.And(left, right, lineno=lineno)
332 lineno = self.stream.current.lineno
333 return left
334
335 def parse_compare(self):
336 lineno = self.stream.current.lineno
337 expr = self.parse_add()
338 ops = []
339 while 1:
340 token_type = self.stream.current.type
341 if token_type in _compare_operators:
342 self.stream.next()
343 ops.append(nodes.Operand(token_type, self.parse_add()))
Armin Ronacherfdf95302008-05-11 22:20:51 +0200344 elif self.stream.skip_if('name:in'):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200345 ops.append(nodes.Operand('in', self.parse_add()))
346 elif self.stream.current.test('name:not') and \
347 self.stream.look().test('name:in'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200348 self.stream.skip(2)
349 ops.append(nodes.Operand('notin', self.parse_add()))
350 else:
351 break
352 lineno = self.stream.current.lineno
353 if not ops:
354 return expr
355 return nodes.Compare(expr, ops, lineno=lineno)
356
357 def parse_add(self):
358 lineno = self.stream.current.lineno
359 left = self.parse_sub()
360 while self.stream.current.type is 'add':
361 self.stream.next()
362 right = self.parse_sub()
363 left = nodes.Add(left, right, lineno=lineno)
364 lineno = self.stream.current.lineno
365 return left
366
367 def parse_sub(self):
368 lineno = self.stream.current.lineno
369 left = self.parse_concat()
370 while self.stream.current.type is 'sub':
371 self.stream.next()
372 right = self.parse_concat()
373 left = nodes.Sub(left, right, lineno=lineno)
374 lineno = self.stream.current.lineno
375 return left
376
377 def parse_concat(self):
378 lineno = self.stream.current.lineno
379 args = [self.parse_mul()]
380 while self.stream.current.type is 'tilde':
381 self.stream.next()
382 args.append(self.parse_mul())
383 if len(args) == 1:
384 return args[0]
385 return nodes.Concat(args, lineno=lineno)
386
387 def parse_mul(self):
388 lineno = self.stream.current.lineno
389 left = self.parse_div()
390 while self.stream.current.type is 'mul':
391 self.stream.next()
392 right = self.parse_div()
393 left = nodes.Mul(left, right, lineno=lineno)
394 lineno = self.stream.current.lineno
395 return left
396
397 def parse_div(self):
398 lineno = self.stream.current.lineno
399 left = self.parse_floordiv()
400 while self.stream.current.type is 'div':
401 self.stream.next()
402 right = self.parse_floordiv()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200403 left = nodes.Div(left, right, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200404 lineno = self.stream.current.lineno
405 return left
406
407 def parse_floordiv(self):
408 lineno = self.stream.current.lineno
409 left = self.parse_mod()
410 while self.stream.current.type is 'floordiv':
411 self.stream.next()
412 right = self.parse_mod()
413 left = nodes.FloorDiv(left, right, lineno=lineno)
414 lineno = self.stream.current.lineno
415 return left
416
417 def parse_mod(self):
418 lineno = self.stream.current.lineno
419 left = self.parse_pow()
420 while self.stream.current.type is 'mod':
421 self.stream.next()
422 right = self.parse_pow()
423 left = nodes.Mod(left, right, lineno=lineno)
424 lineno = self.stream.current.lineno
425 return left
426
427 def parse_pow(self):
428 lineno = self.stream.current.lineno
429 left = self.parse_unary()
430 while self.stream.current.type is 'pow':
431 self.stream.next()
432 right = self.parse_unary()
433 left = nodes.Pow(left, right, lineno=lineno)
434 lineno = self.stream.current.lineno
435 return left
436
437 def parse_unary(self):
438 token_type = self.stream.current.type
439 lineno = self.stream.current.lineno
Armin Ronacher115de2e2008-05-01 22:20:05 +0200440 if token_type is 'name' and self.stream.current.value == 'not':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200441 self.stream.next()
442 node = self.parse_unary()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200443 return nodes.Not(node, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200444 if token_type is 'sub':
445 self.stream.next()
446 node = self.parse_unary()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200447 return nodes.Neg(node, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200448 if token_type is 'add':
449 self.stream.next()
450 node = self.parse_unary()
451 return nodes.Pos(node, lineno=lineno)
452 return self.parse_primary()
453
Armin Ronacher09c002e2008-05-10 22:21:30 +0200454 def parse_primary(self, with_postfix=True):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200455 token = self.stream.current
456 if token.type is 'name':
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200457 if token.value in ('true', 'false', 'True', 'False'):
458 node = nodes.Const(token.value in ('true', 'True'),
459 lineno=token.lineno)
460 elif token.value in ('none', 'None'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200461 node = nodes.Const(None, lineno=token.lineno)
462 else:
463 node = nodes.Name(token.value, 'load', lineno=token.lineno)
464 self.stream.next()
465 elif token.type in ('integer', 'float', 'string'):
466 self.stream.next()
467 node = nodes.Const(token.value, lineno=token.lineno)
468 elif token.type is 'lparen':
469 self.stream.next()
470 node = self.parse_tuple()
471 self.stream.expect('rparen')
472 elif token.type is 'lbracket':
473 node = self.parse_list()
474 elif token.type is 'lbrace':
475 node = self.parse_dict()
476 else:
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200477 self.fail("unexpected token '%s'" % (token,), token.lineno)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200478 if with_postfix:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200479 node = self.parse_postfix(node)
480 return node
481
Armin Ronacherfdf95302008-05-11 22:20:51 +0200482 def parse_tuple(self, simplified=False, with_condexpr=True,
483 extra_end_rules=None):
Armin Ronacher023b5e92008-05-08 11:03:10 +0200484 """Works like `parse_expression` but if multiple expressions are
485 delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created.
486 This method could also return a regular expression instead of a tuple
487 if no commas where found.
488
489 The default parsing mode is a full tuple. If `simplified` is `True`
490 only names and literals are parsed. The `no_condexpr` parameter is
491 forwarded to :meth:`parse_expression`.
Armin Ronacherfdf95302008-05-11 22:20:51 +0200492
493 Because tuples do not require delimiters and may end in a bogus comma
494 an extra hint is needed that marks the end of a tuple. For example
495 for loops support tuples between `for` and `in`. In that case the
496 `extra_end_rules` is set to ``['name:in']``.
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200497 """
498 lineno = self.stream.current.lineno
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200499 if simplified:
Armin Ronacher09c002e2008-05-10 22:21:30 +0200500 parse = lambda: self.parse_primary(with_postfix=False)
501 elif with_condexpr:
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200502 parse = self.parse_expression
Armin Ronacher09c002e2008-05-10 22:21:30 +0200503 else:
504 parse = lambda: self.parse_expression(with_condexpr=False)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200505 args = []
506 is_tuple = False
507 while 1:
508 if args:
509 self.stream.expect('comma')
Armin Ronacherfdf95302008-05-11 22:20:51 +0200510 if self.is_tuple_end(extra_end_rules):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200511 break
512 args.append(parse())
Armin Ronacherb5124e62008-04-25 00:36:14 +0200513 if self.stream.current.type is 'comma':
514 is_tuple = True
515 else:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200516 break
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200517 lineno = self.stream.current.lineno
518 if not is_tuple and args:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200519 return args[0]
520 return nodes.Tuple(args, 'load', lineno=lineno)
521
522 def parse_list(self):
523 token = self.stream.expect('lbracket')
524 items = []
525 while self.stream.current.type is not 'rbracket':
526 if items:
527 self.stream.expect('comma')
528 if self.stream.current.type == 'rbracket':
529 break
530 items.append(self.parse_expression())
531 self.stream.expect('rbracket')
532 return nodes.List(items, lineno=token.lineno)
533
534 def parse_dict(self):
535 token = self.stream.expect('lbrace')
536 items = []
537 while self.stream.current.type is not 'rbrace':
538 if items:
539 self.stream.expect('comma')
540 if self.stream.current.type == 'rbrace':
541 break
542 key = self.parse_expression()
543 self.stream.expect('colon')
544 value = self.parse_expression()
545 items.append(nodes.Pair(key, value, lineno=key.lineno))
546 self.stream.expect('rbrace')
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200547 return nodes.Dict(items, lineno=token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200548
549 def parse_postfix(self, node):
550 while 1:
551 token_type = self.stream.current.type
552 if token_type is 'dot' or token_type is 'lbracket':
553 node = self.parse_subscript(node)
554 elif token_type is 'lparen':
555 node = self.parse_call(node)
556 elif token_type is 'pipe':
557 node = self.parse_filter(node)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200558 elif token_type is 'name' and self.stream.current.value == 'is':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200559 node = self.parse_test(node)
560 else:
561 break
562 return node
563
564 def parse_subscript(self, node):
565 token = self.stream.next()
566 if token.type is 'dot':
Armin Ronachere791c2a2008-04-07 18:39:54 +0200567 attr_token = self.stream.current
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200568 self.stream.next()
569 if attr_token.type is 'name':
570 return nodes.Getattr(node, attr_token.value, 'load',
571 lineno=token.lineno)
572 elif attr_token.type is not 'integer':
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200573 self.fail('expected name or number', attr_token.lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200574 arg = nodes.Const(attr_token.value, lineno=attr_token.lineno)
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200575 return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
576 if token.type is 'lbracket':
577 priority_on_attribute = False
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200578 args = []
579 while self.stream.current.type is not 'rbracket':
580 if args:
581 self.stream.expect('comma')
582 args.append(self.parse_subscribed())
583 self.stream.expect('rbracket')
584 if len(args) == 1:
585 arg = args[0]
586 else:
Benjamin Wieganda3152742008-04-28 18:07:52 +0200587 arg = nodes.Tuple(args, self.lineno, self.filename)
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200588 return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
589 self.fail('expected subscript expression', self.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200590
591 def parse_subscribed(self):
592 lineno = self.stream.current.lineno
593
594 if self.stream.current.type is 'colon':
595 self.stream.next()
596 args = [None]
597 else:
598 node = self.parse_expression()
599 if self.stream.current.type is not 'colon':
600 return node
601 self.stream.next()
602 args = [node]
603
604 if self.stream.current.type is 'colon':
605 args.append(None)
606 elif self.stream.current.type not in ('rbracket', 'comma'):
607 args.append(self.parse_expression())
608 else:
609 args.append(None)
610
611 if self.stream.current.type is 'colon':
612 self.stream.next()
613 if self.stream.current.type not in ('rbracket', 'comma'):
614 args.append(self.parse_expression())
615 else:
616 args.append(None)
617 else:
618 args.append(None)
619
620 return nodes.Slice(lineno=lineno, *args)
621
622 def parse_call(self, node):
623 token = self.stream.expect('lparen')
624 args = []
625 kwargs = []
626 dyn_args = dyn_kwargs = None
627 require_comma = False
628
629 def ensure(expr):
630 if not expr:
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200631 self.fail('invalid syntax for function call expression',
632 token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200633
634 while self.stream.current.type is not 'rparen':
635 if require_comma:
636 self.stream.expect('comma')
637 # support for trailing comma
638 if self.stream.current.type is 'rparen':
639 break
640 if self.stream.current.type is 'mul':
641 ensure(dyn_args is None and dyn_kwargs is None)
642 self.stream.next()
643 dyn_args = self.parse_expression()
644 elif self.stream.current.type is 'pow':
645 ensure(dyn_kwargs is None)
646 self.stream.next()
647 dyn_kwargs = self.parse_expression()
648 else:
649 ensure(dyn_args is None and dyn_kwargs is None)
650 if self.stream.current.type is 'name' and \
651 self.stream.look().type is 'assign':
652 key = self.stream.current.value
653 self.stream.skip(2)
Armin Ronacher0611e492008-04-25 23:44:14 +0200654 value = self.parse_expression()
655 kwargs.append(nodes.Keyword(key, value,
656 lineno=value.lineno))
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200657 else:
658 ensure(not kwargs)
659 args.append(self.parse_expression())
660
661 require_comma = True
662 self.stream.expect('rparen')
663
664 if node is None:
665 return args, kwargs, dyn_args, dyn_kwargs
666 return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs,
667 lineno=token.lineno)
668
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200669 def parse_filter(self, node, start_inline=False):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200670 while self.stream.current.type == 'pipe' or start_inline:
671 if not start_inline:
672 self.stream.next()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200673 token = self.stream.expect('name')
Armin Ronacherb9e78752008-05-10 23:36:28 +0200674 name = token.value
675 while self.stream.current.type is 'dot':
676 self.stream.next()
677 name += '.' + self.stream.expect('name').value
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200678 if self.stream.current.type is 'lparen':
679 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
680 else:
681 args = []
682 kwargs = []
683 dyn_args = dyn_kwargs = None
Armin Ronacherb9e78752008-05-10 23:36:28 +0200684 node = nodes.Filter(node, name, args, kwargs, dyn_args,
Armin Ronacherd55ab532008-04-09 16:13:39 +0200685 dyn_kwargs, lineno=token.lineno)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200686 start_inline = False
Armin Ronacherd55ab532008-04-09 16:13:39 +0200687 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200688
689 def parse_test(self, node):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200690 token = self.stream.next()
691 if self.stream.current.test('name:not'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200692 self.stream.next()
693 negated = True
694 else:
695 negated = False
696 name = self.stream.expect('name').value
Armin Ronacherb9e78752008-05-10 23:36:28 +0200697 while self.stream.current.type is 'dot':
698 self.stream.next()
699 name += '.' + self.stream.expect('name').value
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200700 dyn_args = dyn_kwargs = None
701 kwargs = []
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200702 if self.stream.current.type is 'lparen':
703 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
704 elif self.stream.current.type in ('name', 'string', 'integer',
705 'float', 'lparen', 'lbracket',
Armin Ronachere3290ea2008-06-12 10:30:01 +0200706 'lbrace') and not \
707 self.stream.current.test_any('name:else', 'name:or',
708 'name:and'):
709 if self.stream.current.test('name:is'):
710 self.fail('You cannot chain multiple tests with is')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200711 args = [self.parse_expression()]
712 else:
713 args = []
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200714 node = nodes.Test(node, name, args, kwargs, dyn_args,
715 dyn_kwargs, lineno=token.lineno)
716 if negated:
Armin Ronacher9a822052008-04-17 18:44:07 +0200717 node = nodes.Not(node, lineno=token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200718 return node
719
720 def subparse(self, end_tokens=None):
721 body = []
722 data_buffer = []
723 add_data = data_buffer.append
724
725 def flush_data():
726 if data_buffer:
727 lineno = data_buffer[0].lineno
728 body.append(nodes.Output(data_buffer[:], lineno=lineno))
729 del data_buffer[:]
730
731 while self.stream:
732 token = self.stream.current
733 if token.type is 'data':
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200734 if token.value:
Armin Ronacher5411ce72008-05-25 11:36:22 +0200735 add_data(nodes.TemplateData(token.value,
736 lineno=token.lineno))
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200737 self.stream.next()
738 elif token.type is 'variable_begin':
739 self.stream.next()
Armin Ronacher09c002e2008-05-10 22:21:30 +0200740 add_data(self.parse_tuple(with_condexpr=True))
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200741 self.stream.expect('variable_end')
742 elif token.type is 'block_begin':
743 flush_data()
744 self.stream.next()
745 if end_tokens is not None and \
Armin Ronachercda43df2008-05-03 17:10:05 +0200746 self.stream.current.test_any(*end_tokens):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200747 return body
Armin Ronacher023b5e92008-05-08 11:03:10 +0200748 rv = self.parse_statement()
749 if isinstance(rv, list):
750 body.extend(rv)
751 else:
752 body.append(rv)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200753 self.stream.expect('block_end')
754 else:
755 raise AssertionError('internal parsing error')
756
757 flush_data()
758 return body
759
760 def parse(self):
761 """Parse the whole template into a `Template` node."""
Armin Ronacherd55ab532008-04-09 16:13:39 +0200762 result = nodes.Template(self.subparse(), lineno=1)
763 result.set_environment(self.environment)
764 return result