blob: c94afb485473f2f553ae3b56f294cffd47da322d [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 Ronacherbd357722009-08-05 20:25:06 +020013from jinja2.utils import next
Armin Ronacher07bc6842008-03-31 14:18:49 +020014
15
Armin Ronachere791c2a2008-04-07 18:39:54 +020016_statement_keywords = frozenset(['for', 'if', 'block', 'extends', 'print',
Armin Ronacher0a2ac692008-05-13 01:03:08 +020017 'macro', 'include', 'from', 'import',
18 'set'])
Armin Ronacher115de2e2008-05-01 22:20:05 +020019_compare_operators = frozenset(['eq', 'ne', 'lt', 'lteq', 'gt', 'gteq'])
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020020
Armin Ronacher07bc6842008-03-31 14:18:49 +020021
22class Parser(object):
Armin Ronacher023b5e92008-05-08 11:03:10 +020023 """This is the central parsing class Jinja2 uses. It's passed to
24 extensions and can be used to parse expressions or statements.
Armin Ronacher07bc6842008-03-31 14:18:49 +020025 """
26
Armin Ronacherba6e25a2008-11-02 15:58:14 +010027 def __init__(self, environment, source, name=None, filename=None,
28 state=None):
Armin Ronacher07bc6842008-03-31 14:18:49 +020029 self.environment = environment
Armin Ronacherba6e25a2008-11-02 15:58:14 +010030 self.stream = environment._tokenize(source, name, filename, state)
Armin Ronacher7f15ef82008-05-16 09:11:39 +020031 self.name = name
Armin Ronacher07bc6842008-03-31 14:18:49 +020032 self.filename = filename
33 self.closed = False
Armin Ronacher05530932008-04-20 13:27:49 +020034 self.extensions = {}
Armin Ronacher023b5e92008-05-08 11:03:10 +020035 for extension in environment.extensions.itervalues():
Armin Ronacher05530932008-04-20 13:27:49 +020036 for tag in extension.tags:
37 self.extensions[tag] = extension.parse
Armin Ronacher023b5e92008-05-08 11:03:10 +020038 self._last_identifier = 0
Armin Ronacher115de2e2008-05-01 22:20:05 +020039
Armin Ronacher7f15ef82008-05-16 09:11:39 +020040 def fail(self, msg, lineno=None, exc=TemplateSyntaxError):
41 """Convenience method that raises `exc` with the message, passed
42 line number or last line number as well as the current name and
43 filename.
44 """
45 if lineno is None:
46 lineno = self.stream.current.lineno
Armin Ronacher61a5a242008-05-26 12:07:44 +020047 raise exc(msg, lineno, self.name, self.filename)
Armin Ronacher7f15ef82008-05-16 09:11:39 +020048
Armin Ronacherfdf95302008-05-11 22:20:51 +020049 def is_tuple_end(self, extra_end_rules=None):
Armin Ronacher115de2e2008-05-01 22:20:05 +020050 """Are we at the end of a tuple?"""
Armin Ronacherfdf95302008-05-11 22:20:51 +020051 if self.stream.current.type in ('variable_end', 'block_end', 'rparen'):
Armin Ronacher023b5e92008-05-08 11:03:10 +020052 return True
Armin Ronacherfdf95302008-05-11 22:20:51 +020053 elif extra_end_rules is not None:
54 return self.stream.current.test_any(extra_end_rules)
Armin Ronacher762079c2008-05-08 23:57:56 +020055 return False
56
Armin Ronacher023b5e92008-05-08 11:03:10 +020057 def free_identifier(self, lineno=None):
58 """Return a new free identifier as :class:`~jinja2.nodes.InternalName`."""
59 self._last_identifier += 1
60 rv = object.__new__(nodes.InternalName)
61 nodes.Node.__init__(rv, 'fi%d' % self._last_identifier, lineno=lineno)
62 return rv
Armin Ronacher115de2e2008-05-01 22:20:05 +020063
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020064 def parse_statement(self):
65 """Parse a single statement."""
Armin Ronacher0a2ac692008-05-13 01:03:08 +020066 token = self.stream.current
Ali Afshar272ca2a2009-01-05 12:14:14 +010067 if token.type != 'name':
Armin Ronacher7f15ef82008-05-16 09:11:39 +020068 self.fail('tag name expected', token.lineno)
Armin Ronacher0a2ac692008-05-13 01:03:08 +020069 if token.value in _statement_keywords:
70 return getattr(self, 'parse_' + self.stream.current.value)()
71 if token.value == 'call':
72 return self.parse_call_block()
73 if token.value == 'filter':
74 return self.parse_filter_block()
75 ext = self.extensions.get(token.value)
76 if ext is not None:
77 return ext(self)
Armin Ronacher7f15ef82008-05-16 09:11:39 +020078 self.fail('unknown tag %r' % token.value, token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020079
80 def parse_statements(self, end_tokens, drop_needle=False):
Armin Ronacherf59bac22008-04-20 13:11:43 +020081 """Parse multiple statements into a list until one of the end tokens
82 is reached. This is used to parse the body of statements as it also
Armin Ronacher023b5e92008-05-08 11:03:10 +020083 parses template data if appropriate. The parser checks first if the
84 current token is a colon and skips it if there is one. Then it checks
85 for the block end and parses until if one of the `end_tokens` is
86 reached. Per default the active token in the stream at the end of
87 the call is the matched end token. If this is not wanted `drop_needle`
88 can be set to `True` and the end token is removed.
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020089 """
90 # the first token may be a colon for python compatibility
Armin Ronacherfdf95302008-05-11 22:20:51 +020091 self.stream.skip_if('colon')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020092
Armin Ronacher2b60fe52008-04-21 08:23:59 +020093 # in the future it would be possible to add whole code sections
94 # by adding some sort of end of statement token and parsing those here.
95 self.stream.expect('block_end')
96 result = self.subparse(end_tokens)
97
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020098 if drop_needle:
Armin Ronacherbd357722009-08-05 20:25:06 +020099 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200100 return result
101
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200102 def parse_set(self):
103 """Parse an assign statement."""
Armin Ronacherbd357722009-08-05 20:25:06 +0200104 lineno = next(self.stream).lineno
Armin Ronacher0a2ac692008-05-13 01:03:08 +0200105 target = self.parse_assign_target()
106 self.stream.expect('assign')
107 expr = self.parse_tuple()
108 return nodes.Assign(target, expr, lineno=lineno)
109
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200110 def parse_for(self):
111 """Parse a for loop."""
Armin Ronacher115de2e2008-05-01 22:20:05 +0200112 lineno = self.stream.expect('name:for').lineno
Armin Ronacherfdf95302008-05-11 22:20:51 +0200113 target = self.parse_assign_target(extra_end_rules=('name:in',))
Armin Ronacher115de2e2008-05-01 22:20:05 +0200114 self.stream.expect('name:in')
Armin Ronacherfdf95302008-05-11 22:20:51 +0200115 iter = self.parse_tuple(with_condexpr=False,
116 extra_end_rules=('name:recursive',))
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200117 test = None
Armin Ronacherfdf95302008-05-11 22:20:51 +0200118 if self.stream.skip_if('name:if'):
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200119 test = self.parse_expression()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200120 recursive = self.stream.skip_if('name:recursive')
Armin Ronacher115de2e2008-05-01 22:20:05 +0200121 body = self.parse_statements(('name:endfor', 'name:else'))
Armin Ronacherbd357722009-08-05 20:25:06 +0200122 if next(self.stream).value == 'endfor':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200123 else_ = []
124 else:
Armin Ronacher115de2e2008-05-01 22:20:05 +0200125 else_ = self.parse_statements(('name:endfor',), drop_needle=True)
Armin Ronacherfdf95302008-05-11 22:20:51 +0200126 return nodes.For(target, iter, body, else_, test,
127 recursive, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200128
129 def parse_if(self):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200130 """Parse an if construct."""
Armin Ronacher115de2e2008-05-01 22:20:05 +0200131 node = result = nodes.If(lineno=self.stream.expect('name:if').lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200132 while 1:
Armin Ronacher09c002e2008-05-10 22:21:30 +0200133 node.test = self.parse_tuple(with_condexpr=False)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200134 node.body = self.parse_statements(('name:elif', 'name:else',
135 'name:endif'))
Armin Ronacherbd357722009-08-05 20:25:06 +0200136 token = next(self.stream)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200137 if token.test('name:elif'):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200138 new_node = nodes.If(lineno=self.stream.current.lineno)
139 node.else_ = [new_node]
140 node = new_node
141 continue
Armin Ronacher115de2e2008-05-01 22:20:05 +0200142 elif token.test('name:else'):
143 node.else_ = self.parse_statements(('name:endif',),
Armin Ronachere791c2a2008-04-07 18:39:54 +0200144 drop_needle=True)
145 else:
146 node.else_ = []
147 break
148 return result
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200149
150 def parse_block(self):
Armin Ronacherbd357722009-08-05 20:25:06 +0200151 node = nodes.Block(lineno=next(self.stream).lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200152 node.name = self.stream.expect('name').value
Armin Ronacher74a0cd92009-02-19 15:56:53 +0100153 node.scoped = self.stream.skip_if('name:scoped')
Armin Ronacher115de2e2008-05-01 22:20:05 +0200154 node.body = self.parse_statements(('name:endblock',), drop_needle=True)
Armin Ronacherfd310492008-05-25 00:16:51 +0200155 self.stream.skip_if('name:' + node.name)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200156 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200157
158 def parse_extends(self):
Armin Ronacherbd357722009-08-05 20:25:06 +0200159 node = nodes.Extends(lineno=next(self.stream).lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200160 node.template = self.parse_expression()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200161 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200162
Armin Ronacherea847c52008-05-02 20:04:32 +0200163 def parse_import_context(self, node, default):
Armin Ronachercda43df2008-05-03 17:10:05 +0200164 if self.stream.current.test_any('name:with', 'name:without') and \
Armin Ronacherea847c52008-05-02 20:04:32 +0200165 self.stream.look().test('name:context'):
Armin Ronacherbd357722009-08-05 20:25:06 +0200166 node.with_context = next(self.stream).value == 'with'
Armin Ronacherea847c52008-05-02 20:04:32 +0200167 self.stream.skip()
168 else:
169 node.with_context = default
170 return node
171
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200172 def parse_include(self):
Armin Ronacherbd357722009-08-05 20:25:06 +0200173 node = nodes.Include(lineno=next(self.stream).lineno)
Armin Ronacher0611e492008-04-25 23:44:14 +0200174 node.template = self.parse_expression()
Armin Ronacher37f58ce2008-12-27 13:10:38 +0100175 if self.stream.current.test('name:ignore') and \
176 self.stream.look().test('name:missing'):
177 node.ignore_missing = True
178 self.stream.skip(2)
179 else:
180 node.ignore_missing = False
Armin Ronacherea847c52008-05-02 20:04:32 +0200181 return self.parse_import_context(node, True)
Armin Ronacher0611e492008-04-25 23:44:14 +0200182
183 def parse_import(self):
Armin Ronacherbd357722009-08-05 20:25:06 +0200184 node = nodes.Import(lineno=next(self.stream).lineno)
Armin Ronacher0611e492008-04-25 23:44:14 +0200185 node.template = self.parse_expression()
186 self.stream.expect('name:as')
Armin Ronacher09c002e2008-05-10 22:21:30 +0200187 node.target = self.parse_assign_target(name_only=True).name
Armin Ronacherea847c52008-05-02 20:04:32 +0200188 return self.parse_import_context(node, False)
Armin Ronacher0611e492008-04-25 23:44:14 +0200189
190 def parse_from(self):
Armin Ronacherbd357722009-08-05 20:25:06 +0200191 node = nodes.FromImport(lineno=next(self.stream).lineno)
Armin Ronacher0611e492008-04-25 23:44:14 +0200192 node.template = self.parse_expression()
Armin Ronacher115de2e2008-05-01 22:20:05 +0200193 self.stream.expect('name:import')
Armin Ronacher0611e492008-04-25 23:44:14 +0200194 node.names = []
Armin Ronacherea847c52008-05-02 20:04:32 +0200195
196 def parse_context():
197 if self.stream.current.value in ('with', 'without') and \
198 self.stream.look().test('name:context'):
Armin Ronacherbd357722009-08-05 20:25:06 +0200199 node.with_context = next(self.stream).value == 'with'
Armin Ronacherea847c52008-05-02 20:04:32 +0200200 self.stream.skip()
201 return True
202 return False
203
Armin Ronacher0611e492008-04-25 23:44:14 +0200204 while 1:
205 if node.names:
206 self.stream.expect('comma')
Ali Afshar272ca2a2009-01-05 12:14:14 +0100207 if self.stream.current.type == 'name':
Armin Ronacherea847c52008-05-02 20:04:32 +0200208 if parse_context():
209 break
Armin Ronacher09c002e2008-05-10 22:21:30 +0200210 target = self.parse_assign_target(name_only=True)
Armin Ronacher903d1682008-05-23 00:51:58 +0200211 if target.name.startswith('_'):
212 self.fail('names starting with an underline can not '
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200213 'be imported', target.lineno,
214 exc=TemplateAssertionError)
Armin Ronacherfdf95302008-05-11 22:20:51 +0200215 if self.stream.skip_if('name:as'):
Armin Ronacher09c002e2008-05-10 22:21:30 +0200216 alias = self.parse_assign_target(name_only=True)
217 node.names.append((target.name, alias.name))
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200218 else:
219 node.names.append(target.name)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100220 if parse_context() or self.stream.current.type != 'comma':
Armin Ronacher0611e492008-04-25 23:44:14 +0200221 break
222 else:
223 break
Armin Ronacherea847c52008-05-02 20:04:32 +0200224 if not hasattr(node, 'with_context'):
225 node.with_context = False
Armin Ronacherfdf95302008-05-11 22:20:51 +0200226 self.stream.skip_if('comma')
Armin Ronachere791c2a2008-04-07 18:39:54 +0200227 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200228
Armin Ronacher71082072008-04-12 14:19:36 +0200229 def parse_signature(self, node):
230 node.args = args = []
231 node.defaults = defaults = []
232 self.stream.expect('lparen')
Ali Afshar272ca2a2009-01-05 12:14:14 +0100233 while self.stream.current.type != 'rparen':
Armin Ronacher71082072008-04-12 14:19:36 +0200234 if args:
235 self.stream.expect('comma')
Armin Ronacher09c002e2008-05-10 22:21:30 +0200236 arg = self.parse_assign_target(name_only=True)
Armin Ronachere9411b42008-05-15 16:22:07 +0200237 arg.set_ctx('param')
Armin Ronacherfdf95302008-05-11 22:20:51 +0200238 if self.stream.skip_if('assign'):
Armin Ronacher71082072008-04-12 14:19:36 +0200239 defaults.append(self.parse_expression())
240 args.append(arg)
241 self.stream.expect('rparen')
242
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200243 def parse_call_block(self):
Armin Ronacherbd357722009-08-05 20:25:06 +0200244 node = nodes.CallBlock(lineno=next(self.stream).lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100245 if self.stream.current.type == 'lparen':
Armin Ronacher71082072008-04-12 14:19:36 +0200246 self.parse_signature(node)
Armin Ronacherc9705c22008-04-27 21:28:03 +0200247 else:
248 node.args = []
249 node.defaults = []
Armin Ronacher71082072008-04-12 14:19:36 +0200250
Armin Ronacher8edbe492008-04-10 20:43:43 +0200251 node.call = self.parse_expression()
252 if not isinstance(node.call, nodes.Call):
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200253 self.fail('expected call', node.lineno)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200254 node.body = self.parse_statements(('name:endcall',), drop_needle=True)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200255 return node
256
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200257 def parse_filter_block(self):
Armin Ronacherbd357722009-08-05 20:25:06 +0200258 node = nodes.FilterBlock(lineno=next(self.stream).lineno)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200259 node.filter = self.parse_filter(None, start_inline=True)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200260 node.body = self.parse_statements(('name:endfilter',),
261 drop_needle=True)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200262 return node
263
Armin Ronachere791c2a2008-04-07 18:39:54 +0200264 def parse_macro(self):
Armin Ronacherbd357722009-08-05 20:25:06 +0200265 node = nodes.Macro(lineno=next(self.stream).lineno)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200266 node.name = self.parse_assign_target(name_only=True).name
Armin Ronacher71082072008-04-12 14:19:36 +0200267 self.parse_signature(node)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200268 node.body = self.parse_statements(('name:endmacro',),
269 drop_needle=True)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200270 return node
271
272 def parse_print(self):
Armin Ronacherbd357722009-08-05 20:25:06 +0200273 node = nodes.Output(lineno=next(self.stream).lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200274 node.nodes = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100275 while self.stream.current.type != 'block_end':
Armin Ronachere791c2a2008-04-07 18:39:54 +0200276 if node.nodes:
277 self.stream.expect('comma')
278 node.nodes.append(self.parse_expression())
Armin Ronachere791c2a2008-04-07 18:39:54 +0200279 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200280
Armin Ronacherfdf95302008-05-11 22:20:51 +0200281 def parse_assign_target(self, with_tuple=True, name_only=False,
282 extra_end_rules=None):
Armin Ronacher09c002e2008-05-10 22:21:30 +0200283 """Parse an assignment target. As Jinja2 allows assignments to
284 tuples, this function can parse all allowed assignment targets. Per
285 default assignments to tuples are parsed, that can be disable however
286 by setting `with_tuple` to `False`. If only assignments to names are
Armin Ronacherfdf95302008-05-11 22:20:51 +0200287 wanted `name_only` can be set to `True`. The `extra_end_rules`
288 parameter is forwarded to the tuple parsing function.
Armin Ronacher09c002e2008-05-10 22:21:30 +0200289 """
290 if name_only:
291 token = self.stream.expect('name')
292 target = nodes.Name(token.value, 'store', lineno=token.lineno)
293 else:
294 if with_tuple:
Armin Ronacherfdf95302008-05-11 22:20:51 +0200295 target = self.parse_tuple(simplified=True,
296 extra_end_rules=extra_end_rules)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200297 else:
298 target = self.parse_primary(with_postfix=False)
299 target.set_ctx('store')
300 if not target.can_assign():
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200301 self.fail('can\'t assign to %r' % target.__class__.
302 __name__.lower(), target.lineno)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200303 return target
304
305 def parse_expression(self, with_condexpr=True):
Armin Ronacher023b5e92008-05-08 11:03:10 +0200306 """Parse an expression. Per default all expressions are parsed, if
Armin Ronacher09c002e2008-05-10 22:21:30 +0200307 the optional `with_condexpr` parameter is set to `False` conditional
Armin Ronacher023b5e92008-05-08 11:03:10 +0200308 expressions are not parsed.
309 """
Armin Ronacher09c002e2008-05-10 22:21:30 +0200310 if with_condexpr:
311 return self.parse_condexpr()
312 return self.parse_or()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200313
314 def parse_condexpr(self):
315 lineno = self.stream.current.lineno
316 expr1 = self.parse_or()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200317 while self.stream.skip_if('name:if'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200318 expr2 = self.parse_or()
Armin Ronacher547d0b62008-07-04 16:35:10 +0200319 if self.stream.skip_if('name:else'):
320 expr3 = self.parse_condexpr()
321 else:
322 expr3 = None
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200323 expr1 = nodes.CondExpr(expr2, expr1, expr3, lineno=lineno)
324 lineno = self.stream.current.lineno
325 return expr1
326
327 def parse_or(self):
328 lineno = self.stream.current.lineno
329 left = self.parse_and()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200330 while self.stream.skip_if('name:or'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200331 right = self.parse_and()
332 left = nodes.Or(left, right, lineno=lineno)
333 lineno = self.stream.current.lineno
334 return left
335
336 def parse_and(self):
337 lineno = self.stream.current.lineno
Armin Ronacherd89f0f32009-02-04 18:57:27 +0100338 left = self.parse_not()
Armin Ronacherfdf95302008-05-11 22:20:51 +0200339 while self.stream.skip_if('name:and'):
Armin Ronacherd89f0f32009-02-04 18:57:27 +0100340 right = self.parse_not()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200341 left = nodes.And(left, right, lineno=lineno)
342 lineno = self.stream.current.lineno
343 return left
344
Armin Ronacherd89f0f32009-02-04 18:57:27 +0100345 def parse_not(self):
346 if self.stream.current.test('name:not'):
Armin Ronacherbd357722009-08-05 20:25:06 +0200347 lineno = next(self.stream).lineno
Armin Ronacherd89f0f32009-02-04 18:57:27 +0100348 return nodes.Not(self.parse_not(), lineno=lineno)
349 return self.parse_compare()
350
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200351 def parse_compare(self):
352 lineno = self.stream.current.lineno
353 expr = self.parse_add()
354 ops = []
355 while 1:
356 token_type = self.stream.current.type
357 if token_type in _compare_operators:
Armin Ronacherbd357722009-08-05 20:25:06 +0200358 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200359 ops.append(nodes.Operand(token_type, self.parse_add()))
Armin Ronacherfdf95302008-05-11 22:20:51 +0200360 elif self.stream.skip_if('name:in'):
Armin Ronacher115de2e2008-05-01 22:20:05 +0200361 ops.append(nodes.Operand('in', self.parse_add()))
362 elif self.stream.current.test('name:not') and \
363 self.stream.look().test('name:in'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200364 self.stream.skip(2)
365 ops.append(nodes.Operand('notin', self.parse_add()))
366 else:
367 break
368 lineno = self.stream.current.lineno
369 if not ops:
370 return expr
371 return nodes.Compare(expr, ops, lineno=lineno)
372
373 def parse_add(self):
374 lineno = self.stream.current.lineno
375 left = self.parse_sub()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100376 while self.stream.current.type == 'add':
Armin Ronacherbd357722009-08-05 20:25:06 +0200377 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200378 right = self.parse_sub()
379 left = nodes.Add(left, right, lineno=lineno)
380 lineno = self.stream.current.lineno
381 return left
382
383 def parse_sub(self):
384 lineno = self.stream.current.lineno
385 left = self.parse_concat()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100386 while self.stream.current.type == 'sub':
Armin Ronacherbd357722009-08-05 20:25:06 +0200387 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200388 right = self.parse_concat()
389 left = nodes.Sub(left, right, lineno=lineno)
390 lineno = self.stream.current.lineno
391 return left
392
393 def parse_concat(self):
394 lineno = self.stream.current.lineno
395 args = [self.parse_mul()]
Ali Afshar272ca2a2009-01-05 12:14:14 +0100396 while self.stream.current.type == 'tilde':
Armin Ronacherbd357722009-08-05 20:25:06 +0200397 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200398 args.append(self.parse_mul())
399 if len(args) == 1:
400 return args[0]
401 return nodes.Concat(args, lineno=lineno)
402
403 def parse_mul(self):
404 lineno = self.stream.current.lineno
405 left = self.parse_div()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100406 while self.stream.current.type == 'mul':
Armin Ronacherbd357722009-08-05 20:25:06 +0200407 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200408 right = self.parse_div()
409 left = nodes.Mul(left, right, lineno=lineno)
410 lineno = self.stream.current.lineno
411 return left
412
413 def parse_div(self):
414 lineno = self.stream.current.lineno
415 left = self.parse_floordiv()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100416 while self.stream.current.type == 'div':
Armin Ronacherbd357722009-08-05 20:25:06 +0200417 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200418 right = self.parse_floordiv()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200419 left = nodes.Div(left, right, lineno=lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200420 lineno = self.stream.current.lineno
421 return left
422
423 def parse_floordiv(self):
424 lineno = self.stream.current.lineno
425 left = self.parse_mod()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100426 while self.stream.current.type == 'floordiv':
Armin Ronacherbd357722009-08-05 20:25:06 +0200427 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200428 right = self.parse_mod()
429 left = nodes.FloorDiv(left, right, lineno=lineno)
430 lineno = self.stream.current.lineno
431 return left
432
433 def parse_mod(self):
434 lineno = self.stream.current.lineno
435 left = self.parse_pow()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100436 while self.stream.current.type == 'mod':
Armin Ronacherbd357722009-08-05 20:25:06 +0200437 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200438 right = self.parse_pow()
439 left = nodes.Mod(left, right, lineno=lineno)
440 lineno = self.stream.current.lineno
441 return left
442
443 def parse_pow(self):
444 lineno = self.stream.current.lineno
445 left = self.parse_unary()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100446 while self.stream.current.type == 'pow':
Armin Ronacherbd357722009-08-05 20:25:06 +0200447 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200448 right = self.parse_unary()
449 left = nodes.Pow(left, right, lineno=lineno)
450 lineno = self.stream.current.lineno
451 return left
452
453 def parse_unary(self):
454 token_type = self.stream.current.type
455 lineno = self.stream.current.lineno
Ali Afshar272ca2a2009-01-05 12:14:14 +0100456 if token_type == 'sub':
Armin Ronacherbd357722009-08-05 20:25:06 +0200457 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200458 node = self.parse_unary()
Armin Ronachere791c2a2008-04-07 18:39:54 +0200459 return nodes.Neg(node, lineno=lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100460 if token_type == 'add':
Armin Ronacherbd357722009-08-05 20:25:06 +0200461 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200462 node = self.parse_unary()
463 return nodes.Pos(node, lineno=lineno)
464 return self.parse_primary()
465
Armin Ronacher09c002e2008-05-10 22:21:30 +0200466 def parse_primary(self, with_postfix=True):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200467 token = self.stream.current
Ali Afshar272ca2a2009-01-05 12:14:14 +0100468 if token.type == 'name':
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200469 if token.value in ('true', 'false', 'True', 'False'):
470 node = nodes.Const(token.value in ('true', 'True'),
471 lineno=token.lineno)
472 elif token.value in ('none', 'None'):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200473 node = nodes.Const(None, lineno=token.lineno)
474 else:
475 node = nodes.Name(token.value, 'load', lineno=token.lineno)
Armin Ronacherbd357722009-08-05 20:25:06 +0200476 next(self.stream)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100477 elif token.type == 'string':
Armin Ronacherbd357722009-08-05 20:25:06 +0200478 next(self.stream)
Armin Ronacher4778bda2008-06-22 12:48:37 +0200479 buf = [token.value]
480 lineno = token.lineno
Ali Afshar272ca2a2009-01-05 12:14:14 +0100481 while self.stream.current.type == 'string':
Armin Ronacher4778bda2008-06-22 12:48:37 +0200482 buf.append(self.stream.current.value)
Armin Ronacherbd357722009-08-05 20:25:06 +0200483 next(self.stream)
Armin Ronacher4778bda2008-06-22 12:48:37 +0200484 node = nodes.Const(''.join(buf), lineno=lineno)
485 elif token.type in ('integer', 'float'):
Armin Ronacherbd357722009-08-05 20:25:06 +0200486 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200487 node = nodes.Const(token.value, lineno=token.lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100488 elif token.type == 'lparen':
Armin Ronacherbd357722009-08-05 20:25:06 +0200489 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200490 node = self.parse_tuple()
491 self.stream.expect('rparen')
Ali Afshar272ca2a2009-01-05 12:14:14 +0100492 elif token.type == 'lbracket':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200493 node = self.parse_list()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100494 elif token.type == 'lbrace':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200495 node = self.parse_dict()
496 else:
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200497 self.fail("unexpected token '%s'" % (token,), token.lineno)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200498 if with_postfix:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200499 node = self.parse_postfix(node)
500 return node
501
Armin Ronacherfdf95302008-05-11 22:20:51 +0200502 def parse_tuple(self, simplified=False, with_condexpr=True,
503 extra_end_rules=None):
Armin Ronacher023b5e92008-05-08 11:03:10 +0200504 """Works like `parse_expression` but if multiple expressions are
505 delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created.
506 This method could also return a regular expression instead of a tuple
507 if no commas where found.
508
509 The default parsing mode is a full tuple. If `simplified` is `True`
510 only names and literals are parsed. The `no_condexpr` parameter is
511 forwarded to :meth:`parse_expression`.
Armin Ronacherfdf95302008-05-11 22:20:51 +0200512
513 Because tuples do not require delimiters and may end in a bogus comma
514 an extra hint is needed that marks the end of a tuple. For example
515 for loops support tuples between `for` and `in`. In that case the
516 `extra_end_rules` is set to ``['name:in']``.
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200517 """
518 lineno = self.stream.current.lineno
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200519 if simplified:
Armin Ronacher09c002e2008-05-10 22:21:30 +0200520 parse = lambda: self.parse_primary(with_postfix=False)
521 elif with_condexpr:
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200522 parse = self.parse_expression
Armin Ronacher09c002e2008-05-10 22:21:30 +0200523 else:
524 parse = lambda: self.parse_expression(with_condexpr=False)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200525 args = []
526 is_tuple = False
527 while 1:
528 if args:
529 self.stream.expect('comma')
Armin Ronacherfdf95302008-05-11 22:20:51 +0200530 if self.is_tuple_end(extra_end_rules):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200531 break
532 args.append(parse())
Ali Afshar272ca2a2009-01-05 12:14:14 +0100533 if self.stream.current.type == 'comma':
Armin Ronacherb5124e62008-04-25 00:36:14 +0200534 is_tuple = True
535 else:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200536 break
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200537 lineno = self.stream.current.lineno
538 if not is_tuple and args:
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200539 return args[0]
540 return nodes.Tuple(args, 'load', lineno=lineno)
541
542 def parse_list(self):
543 token = self.stream.expect('lbracket')
544 items = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100545 while self.stream.current.type != 'rbracket':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200546 if items:
547 self.stream.expect('comma')
548 if self.stream.current.type == 'rbracket':
549 break
550 items.append(self.parse_expression())
551 self.stream.expect('rbracket')
552 return nodes.List(items, lineno=token.lineno)
553
554 def parse_dict(self):
555 token = self.stream.expect('lbrace')
556 items = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100557 while self.stream.current.type != 'rbrace':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200558 if items:
559 self.stream.expect('comma')
560 if self.stream.current.type == 'rbrace':
561 break
562 key = self.parse_expression()
563 self.stream.expect('colon')
564 value = self.parse_expression()
565 items.append(nodes.Pair(key, value, lineno=key.lineno))
566 self.stream.expect('rbrace')
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200567 return nodes.Dict(items, lineno=token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200568
569 def parse_postfix(self, node):
570 while 1:
571 token_type = self.stream.current.type
Ali Afshar272ca2a2009-01-05 12:14:14 +0100572 if token_type == 'dot' or token_type == 'lbracket':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200573 node = self.parse_subscript(node)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100574 elif token_type == 'lparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200575 node = self.parse_call(node)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100576 elif token_type == 'pipe':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200577 node = self.parse_filter(node)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100578 elif token_type == 'name' and self.stream.current.value == 'is':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200579 node = self.parse_test(node)
580 else:
581 break
582 return node
583
584 def parse_subscript(self, node):
Armin Ronacherbd357722009-08-05 20:25:06 +0200585 token = next(self.stream)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100586 if token.type == 'dot':
Armin Ronachere791c2a2008-04-07 18:39:54 +0200587 attr_token = self.stream.current
Armin Ronacherbd357722009-08-05 20:25:06 +0200588 next(self.stream)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100589 if attr_token.type == 'name':
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200590 return nodes.Getattr(node, attr_token.value, 'load',
591 lineno=token.lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100592 elif attr_token.type != 'integer':
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200593 self.fail('expected name or number', attr_token.lineno)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200594 arg = nodes.Const(attr_token.value, lineno=attr_token.lineno)
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200595 return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100596 if token.type == 'lbracket':
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200597 priority_on_attribute = False
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200598 args = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100599 while self.stream.current.type != 'rbracket':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200600 if args:
601 self.stream.expect('comma')
602 args.append(self.parse_subscribed())
603 self.stream.expect('rbracket')
604 if len(args) == 1:
605 arg = args[0]
606 else:
Armin Ronacheree2d3c42009-02-05 23:13:15 +0100607 arg = nodes.Tuple(args, 'load', lineno=token.lineno)
Armin Ronacher6dc6f292008-06-12 08:50:07 +0200608 return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
609 self.fail('expected subscript expression', self.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200610
611 def parse_subscribed(self):
612 lineno = self.stream.current.lineno
613
Ali Afshar272ca2a2009-01-05 12:14:14 +0100614 if self.stream.current.type == 'colon':
Armin Ronacherbd357722009-08-05 20:25:06 +0200615 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200616 args = [None]
617 else:
618 node = self.parse_expression()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100619 if self.stream.current.type != 'colon':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200620 return node
Armin Ronacherbd357722009-08-05 20:25:06 +0200621 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200622 args = [node]
623
Ali Afshar272ca2a2009-01-05 12:14:14 +0100624 if self.stream.current.type == 'colon':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200625 args.append(None)
626 elif self.stream.current.type not in ('rbracket', 'comma'):
627 args.append(self.parse_expression())
628 else:
629 args.append(None)
630
Ali Afshar272ca2a2009-01-05 12:14:14 +0100631 if self.stream.current.type == 'colon':
Armin Ronacherbd357722009-08-05 20:25:06 +0200632 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200633 if self.stream.current.type not in ('rbracket', 'comma'):
634 args.append(self.parse_expression())
635 else:
636 args.append(None)
637 else:
638 args.append(None)
639
640 return nodes.Slice(lineno=lineno, *args)
641
642 def parse_call(self, node):
643 token = self.stream.expect('lparen')
644 args = []
645 kwargs = []
646 dyn_args = dyn_kwargs = None
647 require_comma = False
648
649 def ensure(expr):
650 if not expr:
Armin Ronacher7f15ef82008-05-16 09:11:39 +0200651 self.fail('invalid syntax for function call expression',
652 token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200653
Ali Afshar272ca2a2009-01-05 12:14:14 +0100654 while self.stream.current.type != 'rparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200655 if require_comma:
656 self.stream.expect('comma')
657 # support for trailing comma
Ali Afshar272ca2a2009-01-05 12:14:14 +0100658 if self.stream.current.type == 'rparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200659 break
Ali Afshar272ca2a2009-01-05 12:14:14 +0100660 if self.stream.current.type == 'mul':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200661 ensure(dyn_args is None and dyn_kwargs is None)
Armin Ronacherbd357722009-08-05 20:25:06 +0200662 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200663 dyn_args = self.parse_expression()
Ali Afshar272ca2a2009-01-05 12:14:14 +0100664 elif self.stream.current.type == 'pow':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200665 ensure(dyn_kwargs is None)
Armin Ronacherbd357722009-08-05 20:25:06 +0200666 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200667 dyn_kwargs = self.parse_expression()
668 else:
669 ensure(dyn_args is None and dyn_kwargs is None)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100670 if self.stream.current.type == 'name' and \
671 self.stream.look().type == 'assign':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200672 key = self.stream.current.value
673 self.stream.skip(2)
Armin Ronacher0611e492008-04-25 23:44:14 +0200674 value = self.parse_expression()
675 kwargs.append(nodes.Keyword(key, value,
676 lineno=value.lineno))
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200677 else:
678 ensure(not kwargs)
679 args.append(self.parse_expression())
680
681 require_comma = True
682 self.stream.expect('rparen')
683
684 if node is None:
685 return args, kwargs, dyn_args, dyn_kwargs
686 return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs,
687 lineno=token.lineno)
688
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200689 def parse_filter(self, node, start_inline=False):
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200690 while self.stream.current.type == 'pipe' or start_inline:
691 if not start_inline:
Armin Ronacherbd357722009-08-05 20:25:06 +0200692 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200693 token = self.stream.expect('name')
Armin Ronacherb9e78752008-05-10 23:36:28 +0200694 name = token.value
Ali Afshar272ca2a2009-01-05 12:14:14 +0100695 while self.stream.current.type == 'dot':
Armin Ronacherbd357722009-08-05 20:25:06 +0200696 next(self.stream)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200697 name += '.' + self.stream.expect('name').value
Ali Afshar272ca2a2009-01-05 12:14:14 +0100698 if self.stream.current.type == 'lparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200699 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
700 else:
701 args = []
702 kwargs = []
703 dyn_args = dyn_kwargs = None
Armin Ronacherb9e78752008-05-10 23:36:28 +0200704 node = nodes.Filter(node, name, args, kwargs, dyn_args,
Armin Ronacherd55ab532008-04-09 16:13:39 +0200705 dyn_kwargs, lineno=token.lineno)
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200706 start_inline = False
Armin Ronacherd55ab532008-04-09 16:13:39 +0200707 return node
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200708
709 def parse_test(self, node):
Armin Ronacherbd357722009-08-05 20:25:06 +0200710 token = next(self.stream)
Armin Ronacher115de2e2008-05-01 22:20:05 +0200711 if self.stream.current.test('name:not'):
Armin Ronacherbd357722009-08-05 20:25:06 +0200712 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200713 negated = True
714 else:
715 negated = False
716 name = self.stream.expect('name').value
Ali Afshar272ca2a2009-01-05 12:14:14 +0100717 while self.stream.current.type == 'dot':
Armin Ronacherbd357722009-08-05 20:25:06 +0200718 next(self.stream)
Armin Ronacherb9e78752008-05-10 23:36:28 +0200719 name += '.' + self.stream.expect('name').value
Armin Ronacher10f3ba22008-04-18 11:30:37 +0200720 dyn_args = dyn_kwargs = None
721 kwargs = []
Ali Afshar272ca2a2009-01-05 12:14:14 +0100722 if self.stream.current.type == 'lparen':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200723 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
724 elif self.stream.current.type in ('name', 'string', 'integer',
725 'float', 'lparen', 'lbracket',
Armin Ronachere3290ea2008-06-12 10:30:01 +0200726 'lbrace') and not \
727 self.stream.current.test_any('name:else', 'name:or',
728 'name:and'):
729 if self.stream.current.test('name:is'):
730 self.fail('You cannot chain multiple tests with is')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200731 args = [self.parse_expression()]
732 else:
733 args = []
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200734 node = nodes.Test(node, name, args, kwargs, dyn_args,
735 dyn_kwargs, lineno=token.lineno)
736 if negated:
Armin Ronacher9a822052008-04-17 18:44:07 +0200737 node = nodes.Not(node, lineno=token.lineno)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200738 return node
739
740 def subparse(self, end_tokens=None):
741 body = []
742 data_buffer = []
743 add_data = data_buffer.append
744
745 def flush_data():
746 if data_buffer:
747 lineno = data_buffer[0].lineno
748 body.append(nodes.Output(data_buffer[:], lineno=lineno))
749 del data_buffer[:]
750
751 while self.stream:
752 token = self.stream.current
Ali Afshar272ca2a2009-01-05 12:14:14 +0100753 if token.type == 'data':
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200754 if token.value:
Armin Ronacher5411ce72008-05-25 11:36:22 +0200755 add_data(nodes.TemplateData(token.value,
756 lineno=token.lineno))
Armin Ronacherbd357722009-08-05 20:25:06 +0200757 next(self.stream)
Ali Afshar272ca2a2009-01-05 12:14:14 +0100758 elif token.type == 'variable_begin':
Armin Ronacherbd357722009-08-05 20:25:06 +0200759 next(self.stream)
Armin Ronacher09c002e2008-05-10 22:21:30 +0200760 add_data(self.parse_tuple(with_condexpr=True))
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200761 self.stream.expect('variable_end')
Ali Afshar272ca2a2009-01-05 12:14:14 +0100762 elif token.type == 'block_begin':
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200763 flush_data()
Armin Ronacherbd357722009-08-05 20:25:06 +0200764 next(self.stream)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200765 if end_tokens is not None and \
Armin Ronachercda43df2008-05-03 17:10:05 +0200766 self.stream.current.test_any(*end_tokens):
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200767 return body
Armin Ronacher023b5e92008-05-08 11:03:10 +0200768 rv = self.parse_statement()
769 if isinstance(rv, list):
770 body.extend(rv)
771 else:
772 body.append(rv)
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200773 self.stream.expect('block_end')
774 else:
775 raise AssertionError('internal parsing error')
776
777 flush_data()
778 return body
779
780 def parse(self):
781 """Parse the whole template into a `Template` node."""
Armin Ronacherd55ab532008-04-09 16:13:39 +0200782 result = nodes.Template(self.subparse(), lineno=1)
783 result.set_environment(self.environment)
784 return result