blob: f3de6e708b6bc35a1c2a768c82d83cbad8c8c180 [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
Armin Ronacher62ccd1b2009-01-04 14:26:19 +01008 :copyright: (c) 2009 by the Jinja Team.
Armin Ronacher07bc6842008-03-31 14:18:49 +02009 :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 Ronacherba6e25a2008-11-02 15:58:14 +010026 def __init__(self, environment, source, name=None, filename=None,
27 state=None):
Armin Ronacher07bc6842008-03-31 14:18:49 +020028 self.environment = environment
Armin Ronacherba6e25a2008-11-02 15:58:14 +010029 self.stream = environment._tokenize(source, name, filename, state)
Armin Ronacher7f15ef82008-05-16 09:11:39 +020030 self.name = name
Armin Ronacher07bc6842008-03-31 14:18:49 +020031 self.filename = filename
32 self.closed = False
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
Ali Afshar272ca2a2009-01-05 12:14:14 +010066 if token.type != '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 Ronacher74a0cd92009-02-19 15:56:53 +0100152 node.scoped = self.stream.skip_if('name:scoped')
Armin Ronacher115de2e2008-05-01 22:20:05 +0200153 node.body = self.parse_statements(('name:endblock',), drop_needle=True)
Armin Ronacherfd310492008-05-25 00:16:51 +0200154 self.stream.skip_if('name:' + node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200155 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200156
157 def parse_extends(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200158 node = nodes.Extends(lineno=self.stream.next().lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200159 node.template = self.parse_expression()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200160 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200161
Armin Ronacherea847c52008-05-02 20:04:32 +0200162 def parse_import_context(self, node, default):
Armin Ronachercda43df2008-05-03 17:10:05 +0200163 if self.stream.current.test_any('name:with', 'name:without') and \
Armin Ronacherea847c52008-05-02 20:04:32 +0200164 self.stream.look().test('name:context'):
165 node.with_context = self.stream.next().value == 'with'
166 self.stream.skip()
167 else:
168 node.with_context = default
169 return node
170
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200171 def parse_include(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200172 node = nodes.Include(lineno=self.stream.next().lineno)
Armin Ronacher0611e492008-04-25 23:44:14 +0200173 node.template = self.parse_expression()
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100174 if self.stream.current.test('name:ignore') and \
175 self.stream.look().test('name:missing'):
176 node.ignore_missing = True
177 self.stream.skip(2)
178 else:
179 node.ignore_missing = False
Armin Ronacherea847c52008-05-02 20:04:32 +0200180 return self.parse_import_context(node, True)
Armin Ronacher0611e492008-04-25 23:44:14 +0200181
182 def parse_import(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200183 node = nodes.Import(lineno=self.stream.next().lineno)
Armin Ronacher0611e492008-04-25 23:44:14 +0200184 node.template = self.parse_expression()
185 self.stream.expect('name:as')
Armin Ronacher09c002e2008-05-10 22:21:30 +0200186 node.target = self.parse_assign_target(name_only=True).name
Armin Ronacherea847c52008-05-02 20:04:32 +0200187 return self.parse_import_context(node, False)
Armin Ronacher0611e492008-04-25 23:44:14 +0200188
189 def parse_from(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200190 node = nodes.FromImport(lineno=self.stream.next().lineno)
Armin Ronacher0611e492008-04-25 23:44:14 +0200191 node.template = self.parse_expression()
Armin Ronacher115de2e2008-05-01 22:20:05 +0200192 self.stream.expect('name:import')
Armin Ronacher0611e492008-04-25 23:44:14 +0200193 node.names = []
Armin Ronacherea847c52008-05-02 20:04:32 +0200194
195 def parse_context():
196 if self.stream.current.value in ('with', 'without') and \
197 self.stream.look().test('name:context'):
198 node.with_context = self.stream.next().value == 'with'
199 self.stream.skip()
200 return True
201 return False
202
Armin Ronacher0611e492008-04-25 23:44:14 +0200203 while 1:
204 if node.names:
205 self.stream.expect('comma')
Ali Afshar272ca2a2009-01-05 12:14:14 +0100206 if self.stream.current.type == 'name':
Armin Ronacherea847c52008-05-02 20:04:32 +0200207 if parse_context():
208 break
Armin Ronacher09c002e2008-05-10 22:21:30 +0200209 target = self.parse_assign_target(name_only=True)
Armin Ronacher903d1682008-05-23 00:51:58 +0200210 if target.name.startswith('_'):
211 self.fail('names starting with an underline can not '
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200212 'be imported', target.lineno,
213 exc=TemplateAssertionError)
Armin Ronacherfdf95302008-05-11 22:20:51 +0200214 if self.stream.skip_if('name:as'):
Armin Ronacher09c002e2008-05-10 22:21:30 +0200215 alias = self.parse_assign_target(name_only=True)
216 node.names.append((target.name, alias.name))
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200217 else:
218 node.names.append(target.name)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100219 if parse_context() or self.stream.current.type != 'comma':
Armin Ronacher0611e492008-04-25 23:44:14 +0200220 break
221 else:
222 break
Armin Ronacherea847c52008-05-02 20:04:32 +0200223 if not hasattr(node, 'with_context'):
224 node.with_context = False
Armin Ronacherfdf95302008-05-11 22:20:51 +0200225 self.stream.skip_if('comma')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200226 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200227
Armin Ronacher71082072008-04-12 14:19:36 +0200228 def parse_signature(self, node):
229 node.args = args = []
230 node.defaults = defaults = []
231 self.stream.expect('lparen')
Ali Afshar272ca2a2009-01-05 12:14:14 +0100232 while self.stream.current.type != 'rparen':
Armin Ronacher71082072008-04-12 14:19:36 +0200233 if args:
234 self.stream.expect('comma')
Armin Ronacher09c002e2008-05-10 22:21:30 +0200235 arg = self.parse_assign_target(name_only=True)
Armin Ronachere9411b42008-05-15 16:22:07 +0200236 arg.set_ctx('param')
Armin Ronacherfdf95302008-05-11 22:20:51 +0200237 if self.stream.skip_if('assign'):
Armin Ronacher71082072008-04-12 14:19:36 +0200238 defaults.append(self.parse_expression())
239 args.append(arg)
240 self.stream.expect('rparen')
241
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200242 def parse_call_block(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200243 node = nodes.CallBlock(lineno=self.stream.next().lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100244 if self.stream.current.type == 'lparen':
Armin Ronacher71082072008-04-12 14:19:36 +0200245 self.parse_signature(node)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200246 else:
247 node.args = []
248 node.defaults = []
Armin Ronacher71082072008-04-12 14:19:36 +0200249
Armin Ronacher8edbe492008-04-10 20:43:43 +0200250 node.call = self.parse_expression()
251 if not isinstance(node.call, nodes.Call):
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200252 self.fail('expected call', node.lineno)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200253 node.body = self.parse_statements(('name:endcall',), drop_needle=True)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200254 return node
255
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200256 def parse_filter_block(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200257 node = nodes.FilterBlock(lineno=self.stream.next().lineno)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200258 node.filter = self.parse_filter(None, start_inline=True)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200259 node.body = self.parse_statements(('name:endfilter',),
260 drop_needle=True)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200261 return node
262
Armin Ronachere791c2a2008-04-07 18:39:54 +0200263 def parse_macro(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200264 node = nodes.Macro(lineno=self.stream.next().lineno)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200265 node.name = self.parse_assign_target(name_only=True).name
Armin Ronacher71082072008-04-12 14:19:36 +0200266 self.parse_signature(node)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200267 node.body = self.parse_statements(('name:endmacro',),
268 drop_needle=True)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200269 return node
270
271 def parse_print(self):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200272 node = nodes.Output(lineno=self.stream.next().lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200273 node.nodes = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100274 while self.stream.current.type != 'block_end':
Armin Ronachere791c2a2008-04-07 18:39:54 +0200275 if node.nodes:
276 self.stream.expect('comma')
277 node.nodes.append(self.parse_expression())
Armin Ronachere791c2a2008-04-07 18:39:54 +0200278 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200279
Armin Ronacherfdf95302008-05-11 22:20:51 +0200280 def parse_assign_target(self, with_tuple=True, name_only=False,
281 extra_end_rules=None):
Armin Ronacher09c002e2008-05-10 22:21:30 +0200282 """Parse an assignment target. As Jinja2 allows assignments to
283 tuples, this function can parse all allowed assignment targets. Per
284 default assignments to tuples are parsed, that can be disable however
285 by setting `with_tuple` to `False`. If only assignments to names are
Armin Ronacherfdf95302008-05-11 22:20:51 +0200286 wanted `name_only` can be set to `True`. The `extra_end_rules`
287 parameter is forwarded to the tuple parsing function.
Armin Ronacher09c002e2008-05-10 22:21:30 +0200288 """
289 if name_only:
290 token = self.stream.expect('name')
291 target = nodes.Name(token.value, 'store', lineno=token.lineno)
292 else:
293 if with_tuple:
Armin Ronacherfdf95302008-05-11 22:20:51 +0200294 target = self.parse_tuple(simplified=True,
295 extra_end_rules=extra_end_rules)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200296 else:
297 target = self.parse_primary(with_postfix=False)
298 target.set_ctx('store')
299 if not target.can_assign():
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200300 self.fail('can\'t assign to %r' % target.__class__.
301 __name__.lower(), target.lineno)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200302 return target
303
304 def parse_expression(self, with_condexpr=True):
Armin Ronacher023b5e92008-05-08 11:03:10 +0200305 """Parse an expression. Per default all expressions are parsed, if
Armin Ronacher09c002e2008-05-10 22:21:30 +0200306 the optional `with_condexpr` parameter is set to `False` conditional
Armin Ronacher023b5e92008-05-08 11:03:10 +0200307 expressions are not parsed.
308 """
Armin Ronacher09c002e2008-05-10 22:21:30 +0200309 if with_condexpr:
310 return self.parse_condexpr()
311 return self.parse_or()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200312
313 def parse_condexpr(self):
314 lineno = self.stream.current.lineno
315 expr1 = self.parse_or()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200316 while self.stream.skip_if('name:if'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200317 expr2 = self.parse_or()
Armin Ronacher547d0b62008-07-04 16:35:10 +0200318 if self.stream.skip_if('name:else'):
319 expr3 = self.parse_condexpr()
320 else:
321 expr3 = None
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200322 expr1 = nodes.CondExpr(expr2, expr1, expr3, lineno=lineno)
323 lineno = self.stream.current.lineno
324 return expr1
325
326 def parse_or(self):
327 lineno = self.stream.current.lineno
328 left = self.parse_and()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200329 while self.stream.skip_if('name:or'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200330 right = self.parse_and()
331 left = nodes.Or(left, right, lineno=lineno)
332 lineno = self.stream.current.lineno
333 return left
334
335 def parse_and(self):
336 lineno = self.stream.current.lineno
Armin Ronacherd89f0f32009-02-04 18:57:27 +0100337 left = self.parse_not()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200338 while self.stream.skip_if('name:and'):
Armin Ronacherd89f0f32009-02-04 18:57:27 +0100339 right = self.parse_not()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200340 left = nodes.And(left, right, lineno=lineno)
341 lineno = self.stream.current.lineno
342 return left
343
Armin Ronacherd89f0f32009-02-04 18:57:27 +0100344 def parse_not(self):
345 if self.stream.current.test('name:not'):
346 lineno = self.stream.next().lineno
347 return nodes.Not(self.parse_not(), lineno=lineno)
348 return self.parse_compare()
349
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200350 def parse_compare(self):
351 lineno = self.stream.current.lineno
352 expr = self.parse_add()
353 ops = []
354 while 1:
355 token_type = self.stream.current.type
356 if token_type in _compare_operators:
357 self.stream.next()
358 ops.append(nodes.Operand(token_type, self.parse_add()))
Armin Ronacherfdf95302008-05-11 22:20:51 +0200359 elif self.stream.skip_if('name:in'):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200360 ops.append(nodes.Operand('in', self.parse_add()))
361 elif self.stream.current.test('name:not') and \
362 self.stream.look().test('name:in'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200363 self.stream.skip(2)
364 ops.append(nodes.Operand('notin', self.parse_add()))
365 else:
366 break
367 lineno = self.stream.current.lineno
368 if not ops:
369 return expr
370 return nodes.Compare(expr, ops, lineno=lineno)
371
372 def parse_add(self):
373 lineno = self.stream.current.lineno
374 left = self.parse_sub()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100375 while self.stream.current.type == 'add':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200376 self.stream.next()
377 right = self.parse_sub()
378 left = nodes.Add(left, right, lineno=lineno)
379 lineno = self.stream.current.lineno
380 return left
381
382 def parse_sub(self):
383 lineno = self.stream.current.lineno
384 left = self.parse_concat()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100385 while self.stream.current.type == 'sub':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200386 self.stream.next()
387 right = self.parse_concat()
388 left = nodes.Sub(left, right, lineno=lineno)
389 lineno = self.stream.current.lineno
390 return left
391
392 def parse_concat(self):
393 lineno = self.stream.current.lineno
394 args = [self.parse_mul()]
Ali Afshar272ca2a2009-01-05 12:14:14 +0100395 while self.stream.current.type == 'tilde':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200396 self.stream.next()
397 args.append(self.parse_mul())
398 if len(args) == 1:
399 return args[0]
400 return nodes.Concat(args, lineno=lineno)
401
402 def parse_mul(self):
403 lineno = self.stream.current.lineno
404 left = self.parse_div()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100405 while self.stream.current.type == 'mul':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200406 self.stream.next()
407 right = self.parse_div()
408 left = nodes.Mul(left, right, lineno=lineno)
409 lineno = self.stream.current.lineno
410 return left
411
412 def parse_div(self):
413 lineno = self.stream.current.lineno
414 left = self.parse_floordiv()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100415 while self.stream.current.type == 'div':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200416 self.stream.next()
417 right = self.parse_floordiv()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200418 left = nodes.Div(left, right, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200419 lineno = self.stream.current.lineno
420 return left
421
422 def parse_floordiv(self):
423 lineno = self.stream.current.lineno
424 left = self.parse_mod()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100425 while self.stream.current.type == 'floordiv':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200426 self.stream.next()
427 right = self.parse_mod()
428 left = nodes.FloorDiv(left, right, lineno=lineno)
429 lineno = self.stream.current.lineno
430 return left
431
432 def parse_mod(self):
433 lineno = self.stream.current.lineno
434 left = self.parse_pow()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100435 while self.stream.current.type == 'mod':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200436 self.stream.next()
437 right = self.parse_pow()
438 left = nodes.Mod(left, right, lineno=lineno)
439 lineno = self.stream.current.lineno
440 return left
441
442 def parse_pow(self):
443 lineno = self.stream.current.lineno
444 left = self.parse_unary()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100445 while self.stream.current.type == 'pow':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200446 self.stream.next()
447 right = self.parse_unary()
448 left = nodes.Pow(left, right, lineno=lineno)
449 lineno = self.stream.current.lineno
450 return left
451
452 def parse_unary(self):
453 token_type = self.stream.current.type
454 lineno = self.stream.current.lineno
Ali Afshar272ca2a2009-01-05 12:14:14 +0100455 if token_type == 'sub':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200456 self.stream.next()
457 node = self.parse_unary()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200458 return nodes.Neg(node, lineno=lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100459 if token_type == 'add':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200460 self.stream.next()
461 node = self.parse_unary()
462 return nodes.Pos(node, lineno=lineno)
463 return self.parse_primary()
464
Armin Ronacher09c002e2008-05-10 22:21:30 +0200465 def parse_primary(self, with_postfix=True):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200466 token = self.stream.current
Ali Afshar272ca2a2009-01-05 12:14:14 +0100467 if token.type == 'name':
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200468 if token.value in ('true', 'false', 'True', 'False'):
469 node = nodes.Const(token.value in ('true', 'True'),
470 lineno=token.lineno)
471 elif token.value in ('none', 'None'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200472 node = nodes.Const(None, lineno=token.lineno)
473 else:
474 node = nodes.Name(token.value, 'load', lineno=token.lineno)
475 self.stream.next()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100476 elif token.type == 'string':
Armin Ronacher4778bda2008-06-22 12:48:37 +0200477 self.stream.next()
478 buf = [token.value]
479 lineno = token.lineno
Ali Afshar272ca2a2009-01-05 12:14:14 +0100480 while self.stream.current.type == 'string':
Armin Ronacher4778bda2008-06-22 12:48:37 +0200481 buf.append(self.stream.current.value)
482 self.stream.next()
483 node = nodes.Const(''.join(buf), lineno=lineno)
484 elif token.type in ('integer', 'float'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200485 self.stream.next()
486 node = nodes.Const(token.value, lineno=token.lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100487 elif token.type == 'lparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200488 self.stream.next()
489 node = self.parse_tuple()
490 self.stream.expect('rparen')
Ali Afshar272ca2a2009-01-05 12:14:14 +0100491 elif token.type == 'lbracket':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200492 node = self.parse_list()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100493 elif token.type == 'lbrace':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200494 node = self.parse_dict()
495 else:
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200496 self.fail("unexpected token '%s'" % (token,), token.lineno)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200497 if with_postfix:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200498 node = self.parse_postfix(node)
499 return node
500
Armin Ronacherfdf95302008-05-11 22:20:51 +0200501 def parse_tuple(self, simplified=False, with_condexpr=True,
502 extra_end_rules=None):
Armin Ronacher023b5e92008-05-08 11:03:10 +0200503 """Works like `parse_expression` but if multiple expressions are
504 delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created.
505 This method could also return a regular expression instead of a tuple
506 if no commas where found.
507
508 The default parsing mode is a full tuple. If `simplified` is `True`
509 only names and literals are parsed. The `no_condexpr` parameter is
510 forwarded to :meth:`parse_expression`.
Armin Ronacherfdf95302008-05-11 22:20:51 +0200511
512 Because tuples do not require delimiters and may end in a bogus comma
513 an extra hint is needed that marks the end of a tuple. For example
514 for loops support tuples between `for` and `in`. In that case the
515 `extra_end_rules` is set to ``['name:in']``.
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200516 """
517 lineno = self.stream.current.lineno
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200518 if simplified:
Armin Ronacher09c002e2008-05-10 22:21:30 +0200519 parse = lambda: self.parse_primary(with_postfix=False)
520 elif with_condexpr:
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200521 parse = self.parse_expression
Armin Ronacher09c002e2008-05-10 22:21:30 +0200522 else:
523 parse = lambda: self.parse_expression(with_condexpr=False)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200524 args = []
525 is_tuple = False
526 while 1:
527 if args:
528 self.stream.expect('comma')
Armin Ronacherfdf95302008-05-11 22:20:51 +0200529 if self.is_tuple_end(extra_end_rules):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200530 break
531 args.append(parse())
Ali Afshar272ca2a2009-01-05 12:14:14 +0100532 if self.stream.current.type == 'comma':
Armin Ronacherb5124e62008-04-25 00:36:14 +0200533 is_tuple = True
534 else:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200535 break
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200536 lineno = self.stream.current.lineno
537 if not is_tuple and args:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200538 return args[0]
539 return nodes.Tuple(args, 'load', lineno=lineno)
540
541 def parse_list(self):
542 token = self.stream.expect('lbracket')
543 items = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100544 while self.stream.current.type != 'rbracket':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200545 if items:
546 self.stream.expect('comma')
547 if self.stream.current.type == 'rbracket':
548 break
549 items.append(self.parse_expression())
550 self.stream.expect('rbracket')
551 return nodes.List(items, lineno=token.lineno)
552
553 def parse_dict(self):
554 token = self.stream.expect('lbrace')
555 items = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100556 while self.stream.current.type != 'rbrace':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200557 if items:
558 self.stream.expect('comma')
559 if self.stream.current.type == 'rbrace':
560 break
561 key = self.parse_expression()
562 self.stream.expect('colon')
563 value = self.parse_expression()
564 items.append(nodes.Pair(key, value, lineno=key.lineno))
565 self.stream.expect('rbrace')
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200566 return nodes.Dict(items, lineno=token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200567
568 def parse_postfix(self, node):
569 while 1:
570 token_type = self.stream.current.type
Ali Afshar272ca2a2009-01-05 12:14:14 +0100571 if token_type == 'dot' or token_type == 'lbracket':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200572 node = self.parse_subscript(node)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100573 elif token_type == 'lparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200574 node = self.parse_call(node)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100575 elif token_type == 'pipe':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200576 node = self.parse_filter(node)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100577 elif token_type == 'name' and self.stream.current.value == 'is':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200578 node = self.parse_test(node)
579 else:
580 break
581 return node
582
583 def parse_subscript(self, node):
584 token = self.stream.next()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100585 if token.type == 'dot':
Armin Ronachere791c2a2008-04-07 18:39:54 +0200586 attr_token = self.stream.current
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200587 self.stream.next()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100588 if attr_token.type == 'name':
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200589 return nodes.Getattr(node, attr_token.value, 'load',
590 lineno=token.lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100591 elif attr_token.type != 'integer':
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200592 self.fail('expected name or number', attr_token.lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200593 arg = nodes.Const(attr_token.value, lineno=attr_token.lineno)
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200594 return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100595 if token.type == 'lbracket':
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200596 priority_on_attribute = False
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200597 args = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100598 while self.stream.current.type != 'rbracket':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200599 if args:
600 self.stream.expect('comma')
601 args.append(self.parse_subscribed())
602 self.stream.expect('rbracket')
603 if len(args) == 1:
604 arg = args[0]
605 else:
Armin Ronacheree2d3c42009-02-05 23:13:15 +0100606 arg = nodes.Tuple(args, 'load', lineno=token.lineno)
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200607 return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
608 self.fail('expected subscript expression', self.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200609
610 def parse_subscribed(self):
611 lineno = self.stream.current.lineno
612
Ali Afshar272ca2a2009-01-05 12:14:14 +0100613 if self.stream.current.type == 'colon':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200614 self.stream.next()
615 args = [None]
616 else:
617 node = self.parse_expression()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100618 if self.stream.current.type != 'colon':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200619 return node
620 self.stream.next()
621 args = [node]
622
Ali Afshar272ca2a2009-01-05 12:14:14 +0100623 if self.stream.current.type == 'colon':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200624 args.append(None)
625 elif self.stream.current.type not in ('rbracket', 'comma'):
626 args.append(self.parse_expression())
627 else:
628 args.append(None)
629
Ali Afshar272ca2a2009-01-05 12:14:14 +0100630 if self.stream.current.type == 'colon':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200631 self.stream.next()
632 if self.stream.current.type not in ('rbracket', 'comma'):
633 args.append(self.parse_expression())
634 else:
635 args.append(None)
636 else:
637 args.append(None)
638
639 return nodes.Slice(lineno=lineno, *args)
640
641 def parse_call(self, node):
642 token = self.stream.expect('lparen')
643 args = []
644 kwargs = []
645 dyn_args = dyn_kwargs = None
646 require_comma = False
647
648 def ensure(expr):
649 if not expr:
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200650 self.fail('invalid syntax for function call expression',
651 token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200652
Ali Afshar272ca2a2009-01-05 12:14:14 +0100653 while self.stream.current.type != 'rparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200654 if require_comma:
655 self.stream.expect('comma')
656 # support for trailing comma
Ali Afshar272ca2a2009-01-05 12:14:14 +0100657 if self.stream.current.type == 'rparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200658 break
Ali Afshar272ca2a2009-01-05 12:14:14 +0100659 if self.stream.current.type == 'mul':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200660 ensure(dyn_args is None and dyn_kwargs is None)
661 self.stream.next()
662 dyn_args = self.parse_expression()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100663 elif self.stream.current.type == 'pow':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200664 ensure(dyn_kwargs is None)
665 self.stream.next()
666 dyn_kwargs = self.parse_expression()
667 else:
668 ensure(dyn_args is None and dyn_kwargs is None)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100669 if self.stream.current.type == 'name' and \
670 self.stream.look().type == 'assign':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200671 key = self.stream.current.value
672 self.stream.skip(2)
Armin Ronacher0611e492008-04-25 23:44:14 +0200673 value = self.parse_expression()
674 kwargs.append(nodes.Keyword(key, value,
675 lineno=value.lineno))
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200676 else:
677 ensure(not kwargs)
678 args.append(self.parse_expression())
679
680 require_comma = True
681 self.stream.expect('rparen')
682
683 if node is None:
684 return args, kwargs, dyn_args, dyn_kwargs
685 return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs,
686 lineno=token.lineno)
687
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200688 def parse_filter(self, node, start_inline=False):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200689 while self.stream.current.type == 'pipe' or start_inline:
690 if not start_inline:
691 self.stream.next()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200692 token = self.stream.expect('name')
Armin Ronacherb9e78752008-05-10 23:36:28 +0200693 name = token.value
Ali Afshar272ca2a2009-01-05 12:14:14 +0100694 while self.stream.current.type == 'dot':
Armin Ronacherb9e78752008-05-10 23:36:28 +0200695 self.stream.next()
696 name += '.' + self.stream.expect('name').value
Ali Afshar272ca2a2009-01-05 12:14:14 +0100697 if self.stream.current.type == 'lparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200698 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
699 else:
700 args = []
701 kwargs = []
702 dyn_args = dyn_kwargs = None
Armin Ronacherb9e78752008-05-10 23:36:28 +0200703 node = nodes.Filter(node, name, args, kwargs, dyn_args,
Armin Ronacherd55ab532008-04-09 16:13:39 +0200704 dyn_kwargs, lineno=token.lineno)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200705 start_inline = False
Armin Ronacherd55ab532008-04-09 16:13:39 +0200706 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200707
708 def parse_test(self, node):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200709 token = self.stream.next()
710 if self.stream.current.test('name:not'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200711 self.stream.next()
712 negated = True
713 else:
714 negated = False
715 name = self.stream.expect('name').value
Ali Afshar272ca2a2009-01-05 12:14:14 +0100716 while self.stream.current.type == 'dot':
Armin Ronacherb9e78752008-05-10 23:36:28 +0200717 self.stream.next()
718 name += '.' + self.stream.expect('name').value
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200719 dyn_args = dyn_kwargs = None
720 kwargs = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100721 if self.stream.current.type == 'lparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200722 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
723 elif self.stream.current.type in ('name', 'string', 'integer',
724 'float', 'lparen', 'lbracket',
Armin Ronachere3290ea2008-06-12 10:30:01 +0200725 'lbrace') and not \
726 self.stream.current.test_any('name:else', 'name:or',
727 'name:and'):
728 if self.stream.current.test('name:is'):
729 self.fail('You cannot chain multiple tests with is')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200730 args = [self.parse_expression()]
731 else:
732 args = []
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200733 node = nodes.Test(node, name, args, kwargs, dyn_args,
734 dyn_kwargs, lineno=token.lineno)
735 if negated:
Armin Ronacher9a822052008-04-17 18:44:07 +0200736 node = nodes.Not(node, lineno=token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200737 return node
738
739 def subparse(self, end_tokens=None):
740 body = []
741 data_buffer = []
742 add_data = data_buffer.append
743
744 def flush_data():
745 if data_buffer:
746 lineno = data_buffer[0].lineno
747 body.append(nodes.Output(data_buffer[:], lineno=lineno))
748 del data_buffer[:]
749
750 while self.stream:
751 token = self.stream.current
Ali Afshar272ca2a2009-01-05 12:14:14 +0100752 if token.type == 'data':
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200753 if token.value:
Armin Ronacher5411ce72008-05-25 11:36:22 +0200754 add_data(nodes.TemplateData(token.value,
755 lineno=token.lineno))
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200756 self.stream.next()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100757 elif token.type == 'variable_begin':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200758 self.stream.next()
Armin Ronacher09c002e2008-05-10 22:21:30 +0200759 add_data(self.parse_tuple(with_condexpr=True))
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200760 self.stream.expect('variable_end')
Ali Afshar272ca2a2009-01-05 12:14:14 +0100761 elif token.type == 'block_begin':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200762 flush_data()
763 self.stream.next()
764 if end_tokens is not None and \
Armin Ronachercda43df2008-05-03 17:10:05 +0200765 self.stream.current.test_any(*end_tokens):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200766 return body
Armin Ronacher023b5e92008-05-08 11:03:10 +0200767 rv = self.parse_statement()
768 if isinstance(rv, list):
769 body.extend(rv)
770 else:
771 body.append(rv)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200772 self.stream.expect('block_end')
773 else:
774 raise AssertionError('internal parsing error')
775
776 flush_data()
777 return body
778
779 def parse(self):
780 """Parse the whole template into a `Template` node."""
Armin Ronacherd55ab532008-04-09 16:13:39 +0200781 result = nodes.Template(self.subparse(), lineno=1)
782 result.set_environment(self.environment)
783 return result