blob: c1231ea9c561b11a5250217889c8827749b5f402 [file] [log] [blame]
Armin Ronacher07bc6842008-03-31 14:18:49 +02001# -*- coding: utf-8 -*-
2"""
3 jinja2.nodes
4 ~~~~~~~~~~~~
5
6 This module implements additional nodes derived from the ast base node.
7
8 It also provides some node tree helper functions like `in_lineno` and
9 `get_nodes` used by the parser and translator in order to normalize
10 python and jinja nodes.
11
Armin Ronacher4f7d2d52008-04-22 10:40:26 +020012 :copyright: 2008 by Armin Ronacher.
Armin Ronacher07bc6842008-03-31 14:18:49 +020013 :license: BSD, see LICENSE for more details.
14"""
15import operator
Armin Ronacher4f7d2d52008-04-22 10:40:26 +020016from types import FunctionType
Armin Ronacher07bc6842008-03-31 14:18:49 +020017from itertools import chain, izip
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020018from collections import deque
Armin Ronacher07bc6842008-03-31 14:18:49 +020019from copy import copy
20
21
22_binop_to_func = {
23 '*': operator.mul,
24 '/': operator.truediv,
25 '//': operator.floordiv,
26 '**': operator.pow,
27 '%': operator.mod,
28 '+': operator.add,
29 '-': operator.sub
30}
31
32_uaop_to_func = {
33 'not': operator.not_,
34 '+': operator.pos,
35 '-': operator.neg
36}
37
Armin Ronacher625215e2008-04-13 16:31:08 +020038_cmpop_to_func = {
39 'eq': operator.eq,
40 'ne': operator.ne,
41 'gt': operator.gt,
42 'gteq': operator.ge,
43 'lt': operator.lt,
44 'lteq': operator.le,
Armin Ronacherb5124e62008-04-25 00:36:14 +020045 'in': lambda a, b: a in b,
46 'notin': lambda a, b: a not in b
Armin Ronacher625215e2008-04-13 16:31:08 +020047}
48
Armin Ronacher07bc6842008-03-31 14:18:49 +020049
50class Impossible(Exception):
Armin Ronacher8efc5222008-04-08 14:47:40 +020051 """Raised if the node could not perform a requested action."""
Armin Ronacher07bc6842008-03-31 14:18:49 +020052
53
54class NodeType(type):
Armin Ronacher8efc5222008-04-08 14:47:40 +020055 """A metaclass for nodes that handles the field and attribute
56 inheritance. fields and attributes from the parent class are
57 automatically forwarded to the child."""
Armin Ronacher07bc6842008-03-31 14:18:49 +020058
59 def __new__(cls, name, bases, d):
Armin Ronachere791c2a2008-04-07 18:39:54 +020060 for attr in 'fields', 'attributes':
Armin Ronacher07bc6842008-03-31 14:18:49 +020061 storage = []
Armin Ronacher7324eb82008-04-21 07:55:52 +020062 storage.extend(getattr(bases[0], attr, ()))
Armin Ronacher07bc6842008-03-31 14:18:49 +020063 storage.extend(d.get(attr, ()))
Armin Ronacher7324eb82008-04-21 07:55:52 +020064 assert len(bases) == 1, 'multiple inheritance not allowed'
65 assert len(storage) == len(set(storage)), 'layout conflict'
Armin Ronacher07bc6842008-03-31 14:18:49 +020066 d[attr] = tuple(storage)
Armin Ronacher7324eb82008-04-21 07:55:52 +020067 return type.__new__(cls, name, bases, d)
Armin Ronacher07bc6842008-03-31 14:18:49 +020068
69
70class Node(object):
Armin Ronacher8efc5222008-04-08 14:47:40 +020071 """Baseclass for all Jinja nodes."""
Armin Ronacher07bc6842008-03-31 14:18:49 +020072 __metaclass__ = NodeType
Armin Ronachere791c2a2008-04-07 18:39:54 +020073 fields = ()
Armin Ronacherd55ab532008-04-09 16:13:39 +020074 attributes = ('lineno', 'environment')
Armin Ronacher07bc6842008-03-31 14:18:49 +020075
76 def __init__(self, *args, **kw):
77 if args:
Armin Ronachere791c2a2008-04-07 18:39:54 +020078 if len(args) != len(self.fields):
79 if not self.fields:
Armin Ronacher07bc6842008-03-31 14:18:49 +020080 raise TypeError('%r takes 0 arguments' %
81 self.__class__.__name__)
82 raise TypeError('%r takes 0 or %d argument%s' % (
83 self.__class__.__name__,
Armin Ronachere791c2a2008-04-07 18:39:54 +020084 len(self.fields),
85 len(self.fields) != 1 and 's' or ''
Armin Ronacher07bc6842008-03-31 14:18:49 +020086 ))
Armin Ronachere791c2a2008-04-07 18:39:54 +020087 for name, arg in izip(self.fields, args):
Armin Ronacher07bc6842008-03-31 14:18:49 +020088 setattr(self, name, arg)
Armin Ronachere791c2a2008-04-07 18:39:54 +020089 for attr in self.attributes:
Armin Ronacher07bc6842008-03-31 14:18:49 +020090 setattr(self, attr, kw.pop(attr, None))
91 if kw:
92 raise TypeError('unknown keyword argument %r' %
93 iter(kw).next())
94
Armin Ronacher2feed1d2008-04-26 16:26:52 +020095 def iter_fields(self, exclude=()):
Armin Ronachere791c2a2008-04-07 18:39:54 +020096 """Iterate over all fields."""
97 for name in self.fields:
Armin Ronacher2feed1d2008-04-26 16:26:52 +020098 if name not in exclude:
99 try:
100 yield name, getattr(self, name)
101 except AttributeError:
102 pass
Armin Ronacher07bc6842008-03-31 14:18:49 +0200103
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200104 def iter_child_nodes(self, exclude=()):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200105 """Iterate over all child nodes."""
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200106 for field, item in self.iter_fields(exclude):
Armin Ronacher07bc6842008-03-31 14:18:49 +0200107 if isinstance(item, list):
108 for n in item:
109 if isinstance(n, Node):
110 yield n
111 elif isinstance(item, Node):
112 yield item
113
Armin Ronachere791c2a2008-04-07 18:39:54 +0200114 def find(self, node_type):
115 """Find the first node of a given type."""
116 for result in self.find_all(node_type):
117 return result
118
119 def find_all(self, node_type):
120 """Find all the nodes of a given type."""
121 for child in self.iter_child_nodes():
122 if isinstance(child, node_type):
123 yield child
124 for result in child.find_all(node_type):
125 yield result
126
Armin Ronacher0ecb8592008-04-09 16:29:47 +0200127 def copy(self):
128 """Return a deep copy of the node."""
129 result = object.__new__(self.__class__)
130 for field, value in self.iter_fields():
131 if isinstance(value, Node):
132 new_value = value.copy()
133 elif isinstance(value, list):
134 new_value = []
Armin Ronacherd436e982008-04-09 16:31:20 +0200135 for item in value:
Armin Ronacher0ecb8592008-04-09 16:29:47 +0200136 if isinstance(item, Node):
137 item = item.copy()
138 else:
139 item = copy(item)
140 new_value.append(item)
141 else:
Armin Ronacherd436e982008-04-09 16:31:20 +0200142 new_value = copy(value)
Armin Ronacher0ecb8592008-04-09 16:29:47 +0200143 setattr(result, field, new_value)
144 for attr in self.attributes:
145 try:
146 setattr(result, attr, getattr(self, attr))
147 except AttributeError:
148 pass
149 return result
150
Armin Ronachere791c2a2008-04-07 18:39:54 +0200151 def set_ctx(self, ctx):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200152 """Reset the context of a node and all child nodes. Per default the
153 parser will all generate nodes that have a 'load' context as it's the
154 most common one. This method is used in the parser to set assignment
155 targets and other nodes to a store context.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200156 """
157 todo = deque([self])
158 while todo:
159 node = todo.popleft()
160 if 'ctx' in node.fields:
161 node.ctx = ctx
162 todo.extend(node.iter_child_nodes())
163
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200164 def set_lineno(self, lineno, override=False):
165 """Set the line numbers of the node and children."""
166 todo = deque([self])
167 while todo:
168 node = todo.popleft()
169 if 'lineno' in node.attributes:
170 if node.lineno is None or override:
171 node.lineno = lineno
172 todo.extend(node.iter_child_nodes())
173
Armin Ronacherd55ab532008-04-09 16:13:39 +0200174 def set_environment(self, environment):
175 """Set the environment for all nodes."""
176 todo = deque([self])
177 while todo:
178 node = todo.popleft()
179 node.environment = environment
180 todo.extend(node.iter_child_nodes())
181
Armin Ronacher07bc6842008-03-31 14:18:49 +0200182 def __repr__(self):
183 return '%s(%s)' % (
184 self.__class__.__name__,
185 ', '.join('%s=%r' % (arg, getattr(self, arg, None)) for
Armin Ronachere791c2a2008-04-07 18:39:54 +0200186 arg in self.fields)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200187 )
188
189
190class Stmt(Node):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200191 """Base node for all statements."""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200192
193
194class Helper(Node):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200195 """Nodes that exist in a specific context only."""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200196
197
198class Template(Node):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200199 """Node that represents a template."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200200 fields = ('body',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200201
202
203class Output(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200204 """A node that holds multiple expressions which are then printed out.
205 This is used both for the `print` statement and the regular template data.
Armin Ronacher07bc6842008-03-31 14:18:49 +0200206 """
Armin Ronachere791c2a2008-04-07 18:39:54 +0200207 fields = ('nodes',)
208
209 def optimized_nodes(self):
210 """Try to optimize the nodes."""
211 buffer = []
212 for node in self.nodes:
213 try:
214 const = unicode(node.as_const())
215 except:
216 buffer.append(node)
217 else:
218 if buffer and isinstance(buffer[-1], unicode):
219 buffer[-1] += const
220 else:
221 buffer.append(const)
222 return buffer
Armin Ronacher07bc6842008-03-31 14:18:49 +0200223
224
225class Extends(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200226 """Represents an extends statement."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200227 fields = ('template',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200228
229
230class For(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200231 """A node that represents a for loop"""
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200232 fields = ('target', 'iter', 'body', 'else_', 'test')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200233
234
235class If(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200236 """A node that represents an if condition."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200237 fields = ('test', 'body', 'else_')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200238
239
240class Macro(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200241 """A node that represents a macro."""
242 fields = ('name', 'args', 'defaults', 'body')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200243
244
245class CallBlock(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200246 """A node that represents am extended macro call."""
Armin Ronacherc9705c22008-04-27 21:28:03 +0200247 fields = ('call', 'args', 'defaults', 'body')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200248
249
250class Set(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200251 """Allows defining own variables."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200252 fields = ('name', 'expr')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200253
254
255class FilterBlock(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200256 """Node for filter sections."""
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200257 fields = ('body', 'filter')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200258
259
260class Block(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200261 """A node that represents a block."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200262 fields = ('name', 'body')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200263
264
265class Include(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200266 """A node that represents the include tag."""
Armin Ronacher0611e492008-04-25 23:44:14 +0200267 fields = ('template',)
268
269
270class Import(Stmt):
271 """A node that represents the import tag."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200272 fields = ('template', 'target')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200273
274
Armin Ronacher0611e492008-04-25 23:44:14 +0200275class FromImport(Stmt):
276 """A node that represents the from import tag. It's important to not
277 pass unsafe names to the name attribute. The compiler translates the
278 attribute lookups directly into getattr calls and does *not* use the
279 subscribe callback of the interface. As exported variables may not
280 start with double underscores (which the parser asserts) this is not a
281 problem for regular Jinja code, but if this node is used in an extension
282 extra care must be taken.
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200283
284 The list of names may contain tuples if aliases are wanted.
Armin Ronacher0611e492008-04-25 23:44:14 +0200285 """
286 fields = ('template', 'names')
287
288
Armin Ronacher07bc6842008-03-31 14:18:49 +0200289class Trans(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200290 """A node for translatable sections."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200291 fields = ('singular', 'plural', 'indicator', 'replacements')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200292
293
294class ExprStmt(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200295 """A statement that evaluates an expression to None."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200296 fields = ('node',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200297
298
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200299class Assign(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200300 """Assigns an expression to a target."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200301 fields = ('target', 'node')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200302
303
Armin Ronacher07bc6842008-03-31 14:18:49 +0200304class Expr(Node):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200305 """Baseclass for all expressions."""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200306
307 def as_const(self):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200308 """Return the value of the expression as constant or raise
309 `Impossible` if this was not possible.
Armin Ronacher07bc6842008-03-31 14:18:49 +0200310 """
311 raise Impossible()
312
313 def can_assign(self):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200314 """Check if it's possible to assign something to this node."""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200315 return False
316
317
318class BinExpr(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200319 """Baseclass for all binary expressions."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200320 fields = ('left', 'right')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200321 operator = None
322
323 def as_const(self):
324 f = _binop_to_func[self.operator]
325 try:
326 return f(self.left.as_const(), self.right.as_const())
327 except:
Armin Ronacher07bc6842008-03-31 14:18:49 +0200328 raise Impossible()
329
330
331class UnaryExpr(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200332 """Baseclass for all unary expressions."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200333 fields = ('node',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200334 operator = None
335
336 def as_const(self):
337 f = _uaop_to_func[self.operator]
338 try:
339 return f(self.node.as_const())
340 except:
341 raise Impossible()
342
343
344class Name(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200345 """any name such as {{ foo }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200346 fields = ('name', 'ctx')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200347
348 def can_assign(self):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200349 return self.name not in ('true', 'false', 'none')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200350
351
352class Literal(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200353 """Baseclass for literals."""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200354
355
356class Const(Literal):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200357 """any constat such as {{ "foo" }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200358 fields = ('value',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200359
360 def as_const(self):
361 return self.value
362
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200363 @classmethod
Armin Ronacherd55ab532008-04-09 16:13:39 +0200364 def from_untrusted(cls, value, lineno=None, environment=None):
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200365 """Return a const object if the value is representable as
366 constant value in the generated code, otherwise it will raise
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200367 an `Impossible` exception.
368 """
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200369 from compiler import has_safe_repr
370 if not has_safe_repr(value):
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200371 raise Impossible()
Armin Ronacherd55ab532008-04-09 16:13:39 +0200372 return cls(value, lineno=lineno, environment=environment)
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200373
Armin Ronacher07bc6842008-03-31 14:18:49 +0200374
375class Tuple(Literal):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200376 """For loop unpacking and some other things like multiple arguments
Armin Ronacher07bc6842008-03-31 14:18:49 +0200377 for subscripts.
378 """
Armin Ronachere791c2a2008-04-07 18:39:54 +0200379 fields = ('items', 'ctx')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200380
381 def as_const(self):
382 return tuple(x.as_const() for x in self.items)
383
384 def can_assign(self):
385 for item in self.items:
386 if not item.can_assign():
387 return False
388 return True
389
390
391class List(Literal):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200392 """any list literal such as {{ [1, 2, 3] }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200393 fields = ('items',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200394
395 def as_const(self):
396 return [x.as_const() for x in self.items]
397
398
399class Dict(Literal):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200400 """any dict literal such as {{ {1: 2, 3: 4} }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200401 fields = ('items',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200402
403 def as_const(self):
404 return dict(x.as_const() for x in self.items)
405
406
407class Pair(Helper):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200408 """A key, value pair for dicts."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200409 fields = ('key', 'value')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200410
411 def as_const(self):
412 return self.key.as_const(), self.value.as_const()
413
414
Armin Ronacher8efc5222008-04-08 14:47:40 +0200415class Keyword(Helper):
416 """A key, value pair for keyword arguments."""
417 fields = ('key', 'value')
418
419
Armin Ronacher07bc6842008-03-31 14:18:49 +0200420class CondExpr(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200421 """{{ foo if bar else baz }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200422 fields = ('test', 'expr1', 'expr2')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200423
424 def as_const(self):
425 if self.test.as_const():
426 return self.expr1.as_const()
427 return self.expr2.as_const()
428
429
430class Filter(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200431 """{{ foo|bar|baz }}"""
Armin Ronacherd55ab532008-04-09 16:13:39 +0200432 fields = ('node', 'name', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200433
Armin Ronacher00d5d212008-04-13 01:10:18 +0200434 def as_const(self, obj=None):
435 if self.node is obj is None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200436 raise Impossible()
Armin Ronacherd55ab532008-04-09 16:13:39 +0200437 filter = self.environment.filters.get(self.name)
438 if filter is None or getattr(filter, 'contextfilter', False):
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200439 raise Impossible()
Armin Ronacher00d5d212008-04-13 01:10:18 +0200440 if obj is None:
441 obj = self.node.as_const()
Armin Ronacherd55ab532008-04-09 16:13:39 +0200442 args = [x.as_const() for x in self.args]
Armin Ronacher9a027f42008-04-17 11:13:40 +0200443 if getattr(filter, 'environmentfilter', False):
444 args.insert(0, self.environment)
Armin Ronacherd55ab532008-04-09 16:13:39 +0200445 kwargs = dict(x.as_const() for x in self.kwargs)
446 if self.dyn_args is not None:
447 try:
448 args.extend(self.dyn_args.as_const())
449 except:
450 raise Impossible()
451 if self.dyn_kwargs is not None:
452 try:
453 kwargs.update(self.dyn_kwargs.as_const())
454 except:
455 raise Impossible()
456 try:
457 return filter(obj, *args, **kwargs)
458 except:
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200459 raise Impossible()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200460
461
Armin Ronacher07bc6842008-03-31 14:18:49 +0200462class Test(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200463 """{{ foo is lower }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200464 fields = ('node', 'name', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200465
466
467class Call(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200468 """{{ foo(bar) }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200469 fields = ('node', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200470
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200471 def as_const(self):
472 obj = self.node.as_const()
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200473
474 # don't evaluate context functions
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200475 args = [x.as_const() for x in self.args]
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200476 if type(obj) is FunctionType:
477 if getattr(obj, 'contextfunction', False):
478 raise Impossible()
479 elif obj.environmentfunction:
480 args.insert(0, self.environment)
481
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200482 kwargs = dict(x.as_const() for x in self.kwargs)
483 if self.dyn_args is not None:
484 try:
485 args.extend(self.dyn_args.as_const())
486 except:
487 raise Impossible()
488 if self.dyn_kwargs is not None:
489 try:
Armin Ronacherd55ab532008-04-09 16:13:39 +0200490 kwargs.update(self.dyn_kwargs.as_const())
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200491 except:
492 raise Impossible()
493 try:
494 return obj(*args, **kwargs)
495 except:
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200496 raise Impossible()
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200497
Armin Ronacher07bc6842008-03-31 14:18:49 +0200498
499class Subscript(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200500 """{{ foo.bar }} and {{ foo['bar'] }} etc."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200501 fields = ('node', 'arg', 'ctx')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200502
503 def as_const(self):
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200504 if self.ctx != 'load':
505 raise Impossible()
Armin Ronacher07bc6842008-03-31 14:18:49 +0200506 try:
Benjamin Wieganda3152742008-04-28 18:07:52 +0200507 return self.environment.subscribe(self.node.as_const(),
508 self.arg.as_const())
Armin Ronacher07bc6842008-03-31 14:18:49 +0200509 except:
510 raise Impossible()
511
512 def can_assign(self):
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200513 return False
Armin Ronacher07bc6842008-03-31 14:18:49 +0200514
515
516class Slice(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200517 """1:2:3 etc."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200518 fields = ('start', 'stop', 'step')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200519
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200520 def as_const(self):
521 def const(obj):
522 if obj is None:
523 return obj
524 return obj.as_const()
525 return slice(const(self.start), const(self.stop), const(self.step))
526
Armin Ronacher07bc6842008-03-31 14:18:49 +0200527
528class Concat(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200529 """For {{ foo ~ bar }}. Concatenates strings."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200530 fields = ('nodes',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200531
532 def as_const(self):
533 return ''.join(unicode(x.as_const()) for x in self.nodes)
534
535
536class Compare(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200537 """{{ foo == bar }}, {{ foo >= bar }} etc."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200538 fields = ('expr', 'ops')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200539
Armin Ronacher625215e2008-04-13 16:31:08 +0200540 def as_const(self):
541 result = value = self.expr.as_const()
Armin Ronacherb5124e62008-04-25 00:36:14 +0200542 try:
543 for op in self.ops:
544 new_value = op.expr.as_const()
545 result = _cmpop_to_func[op.op](value, new_value)
546 value = new_value
547 except:
548 raise Impossible()
Armin Ronacher625215e2008-04-13 16:31:08 +0200549 return result
550
Armin Ronacher07bc6842008-03-31 14:18:49 +0200551
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200552class Operand(Helper):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200553 """Operator + expression."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200554 fields = ('op', 'expr')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200555
556
Armin Ronacher07bc6842008-03-31 14:18:49 +0200557class Mul(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200558 """{{ foo * bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200559 operator = '*'
560
561
562class Div(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200563 """{{ foo / bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200564 operator = '/'
565
566
567class FloorDiv(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200568 """{{ foo // bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200569 operator = '//'
570
571
572class Add(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200573 """{{ foo + bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200574 operator = '+'
575
576
577class Sub(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200578 """{{ foo - bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200579 operator = '-'
580
581
582class Mod(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200583 """{{ foo % bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200584 operator = '%'
585
586
587class Pow(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200588 """{{ foo ** bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200589 operator = '**'
590
591
592class And(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200593 """{{ foo and bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200594 operator = 'and'
595
596 def as_const(self):
597 return self.left.as_const() and self.right.as_const()
598
599
600class Or(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200601 """{{ foo or bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200602 operator = 'or'
603
604 def as_const(self):
605 return self.left.as_const() or self.right.as_const()
606
607
608class Not(UnaryExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200609 """{{ not foo }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200610 operator = 'not'
611
612
Armin Ronachere791c2a2008-04-07 18:39:54 +0200613class Neg(UnaryExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200614 """{{ -foo }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200615 operator = '-'
616
617
Armin Ronachere791c2a2008-04-07 18:39:54 +0200618class Pos(UnaryExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200619 """{{ +foo }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200620 operator = '+'