blob: 02eb3c0e618ae6dabb04e0bbd4086499f9f184a2 [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
12 :copyright: 2007 by Armin Ronacher.
13 :license: BSD, see LICENSE for more details.
14"""
15import operator
16from itertools import chain, izip
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020017from collections import deque
Armin Ronacher07bc6842008-03-31 14:18:49 +020018from copy import copy
Armin Ronacher4dfc9752008-04-09 15:03:29 +020019from jinja2.runtime import Undefined, subscribe
Armin Ronacher07bc6842008-03-31 14:18:49 +020020
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,
45 'in': operator.contains,
46 'notin': lambda a, b: not operator.contains(a, b)
47}
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 = []
62 for base in bases:
63 storage.extend(getattr(base, attr, ()))
64 storage.extend(d.get(attr, ()))
65 assert len(storage) == len(set(storage))
66 d[attr] = tuple(storage)
67 return type.__new__(cls, name, bases, d)
68
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
95 def iter_fields(self):
Armin Ronachere791c2a2008-04-07 18:39:54 +020096 """Iterate over all fields."""
97 for name in self.fields:
Armin Ronacher07bc6842008-03-31 14:18:49 +020098 try:
99 yield name, getattr(self, name)
100 except AttributeError:
101 pass
102
103 def iter_child_nodes(self):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200104 """Iterate over all child nodes."""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200105 for field, item in self.iter_fields():
106 if isinstance(item, list):
107 for n in item:
108 if isinstance(n, Node):
109 yield n
110 elif isinstance(item, Node):
111 yield item
112
Armin Ronachere791c2a2008-04-07 18:39:54 +0200113 def find(self, node_type):
114 """Find the first node of a given type."""
115 for result in self.find_all(node_type):
116 return result
117
118 def find_all(self, node_type):
119 """Find all the nodes of a given type."""
120 for child in self.iter_child_nodes():
121 if isinstance(child, node_type):
122 yield child
123 for result in child.find_all(node_type):
124 yield result
125
Armin Ronacher0ecb8592008-04-09 16:29:47 +0200126 def copy(self):
127 """Return a deep copy of the node."""
128 result = object.__new__(self.__class__)
129 for field, value in self.iter_fields():
130 if isinstance(value, Node):
131 new_value = value.copy()
132 elif isinstance(value, list):
133 new_value = []
Armin Ronacherd436e982008-04-09 16:31:20 +0200134 for item in value:
Armin Ronacher0ecb8592008-04-09 16:29:47 +0200135 if isinstance(item, Node):
136 item = item.copy()
137 else:
138 item = copy(item)
139 new_value.append(item)
140 else:
Armin Ronacherd436e982008-04-09 16:31:20 +0200141 new_value = copy(value)
Armin Ronacher0ecb8592008-04-09 16:29:47 +0200142 setattr(result, field, new_value)
143 for attr in self.attributes:
144 try:
145 setattr(result, attr, getattr(self, attr))
146 except AttributeError:
147 pass
148 return result
149
Armin Ronachere791c2a2008-04-07 18:39:54 +0200150 def set_ctx(self, ctx):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200151 """Reset the context of a node and all child nodes. Per default the
152 parser will all generate nodes that have a 'load' context as it's the
153 most common one. This method is used in the parser to set assignment
154 targets and other nodes to a store context.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200155 """
156 todo = deque([self])
157 while todo:
158 node = todo.popleft()
159 if 'ctx' in node.fields:
160 node.ctx = ctx
161 todo.extend(node.iter_child_nodes())
162
Armin Ronacherd55ab532008-04-09 16:13:39 +0200163 def set_environment(self, environment):
164 """Set the environment for all nodes."""
165 todo = deque([self])
166 while todo:
167 node = todo.popleft()
168 node.environment = environment
169 todo.extend(node.iter_child_nodes())
170
Armin Ronacher07bc6842008-03-31 14:18:49 +0200171 def __repr__(self):
172 return '%s(%s)' % (
173 self.__class__.__name__,
174 ', '.join('%s=%r' % (arg, getattr(self, arg, None)) for
Armin Ronachere791c2a2008-04-07 18:39:54 +0200175 arg in self.fields)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200176 )
177
178
179class Stmt(Node):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200180 """Base node for all statements."""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200181
182
183class Helper(Node):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200184 """Nodes that exist in a specific context only."""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200185
186
187class Template(Node):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200188 """Node that represents a template."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200189 fields = ('body',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200190
191
192class Output(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200193 """A node that holds multiple expressions which are then printed out.
194 This is used both for the `print` statement and the regular template data.
Armin Ronacher07bc6842008-03-31 14:18:49 +0200195 """
Armin Ronachere791c2a2008-04-07 18:39:54 +0200196 fields = ('nodes',)
197
198 def optimized_nodes(self):
199 """Try to optimize the nodes."""
200 buffer = []
201 for node in self.nodes:
202 try:
203 const = unicode(node.as_const())
204 except:
205 buffer.append(node)
206 else:
207 if buffer and isinstance(buffer[-1], unicode):
208 buffer[-1] += const
209 else:
210 buffer.append(const)
211 return buffer
Armin Ronacher07bc6842008-03-31 14:18:49 +0200212
213
214class Extends(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200215 """Represents an extends statement."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200216 fields = ('template',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200217
218
219class For(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200220 """A node that represents a for loop"""
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200221 fields = ('target', 'iter', 'body', 'else_', 'test')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200222
223
224class If(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200225 """A node that represents an if condition."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200226 fields = ('test', 'body', 'else_')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200227
228
229class Macro(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200230 """A node that represents a macro."""
231 fields = ('name', 'args', 'defaults', 'body')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200232
233
234class CallBlock(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200235 """A node that represents am extended macro call."""
Armin Ronacher71082072008-04-12 14:19:36 +0200236 fields = ('call', 'args', 'defaults', 'body')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200237
238
239class Set(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200240 """Allows defining own variables."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200241 fields = ('name', 'expr')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200242
243
244class FilterBlock(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200245 """Node for filter sections."""
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200246 fields = ('body', 'filter')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200247
248
249class Block(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200250 """A node that represents a block."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200251 fields = ('name', 'body')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200252
253
254class Include(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200255 """A node that represents the include tag."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200256 fields = ('template', 'target')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200257
258
259class Trans(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200260 """A node for translatable sections."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200261 fields = ('singular', 'plural', 'indicator', 'replacements')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200262
263
264class ExprStmt(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200265 """A statement that evaluates an expression to None."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200266 fields = ('node',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200267
268
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200269class Assign(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200270 """Assigns an expression to a target."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200271 fields = ('target', 'node')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200272
273
Armin Ronacher07bc6842008-03-31 14:18:49 +0200274class Expr(Node):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200275 """Baseclass for all expressions."""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200276
277 def as_const(self):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200278 """Return the value of the expression as constant or raise
279 `Impossible` if this was not possible.
Armin Ronacher07bc6842008-03-31 14:18:49 +0200280 """
281 raise Impossible()
282
283 def can_assign(self):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200284 """Check if it's possible to assign something to this node."""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200285 return False
286
287
288class BinExpr(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200289 """Baseclass for all binary expressions."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200290 fields = ('left', 'right')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200291 operator = None
292
293 def as_const(self):
294 f = _binop_to_func[self.operator]
295 try:
296 return f(self.left.as_const(), self.right.as_const())
297 except:
Armin Ronacher07bc6842008-03-31 14:18:49 +0200298 raise Impossible()
299
300
301class UnaryExpr(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200302 """Baseclass for all unary expressions."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200303 fields = ('node',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200304 operator = None
305
306 def as_const(self):
307 f = _uaop_to_func[self.operator]
308 try:
309 return f(self.node.as_const())
310 except:
311 raise Impossible()
312
313
314class Name(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200315 """any name such as {{ foo }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200316 fields = ('name', 'ctx')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200317
318 def can_assign(self):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200319 return self.name not in ('true', 'false', 'none')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200320
321
322class Literal(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200323 """Baseclass for literals."""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200324
325
326class Const(Literal):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200327 """any constat such as {{ "foo" }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200328 fields = ('value',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200329
330 def as_const(self):
331 return self.value
332
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200333 @classmethod
Armin Ronacherd55ab532008-04-09 16:13:39 +0200334 def from_untrusted(cls, value, lineno=None, environment=None):
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200335 """Return a const object if the value is representable as
336 constant value in the generated code, otherwise it will raise
337 an `Impossible` exception."""
338 from compiler import has_safe_repr
339 if not has_safe_repr(value):
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200340 raise Impossible()
Armin Ronacherd55ab532008-04-09 16:13:39 +0200341 return cls(value, lineno=lineno, environment=environment)
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200342
Armin Ronacher07bc6842008-03-31 14:18:49 +0200343
344class Tuple(Literal):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200345 """For loop unpacking and some other things like multiple arguments
Armin Ronacher07bc6842008-03-31 14:18:49 +0200346 for subscripts.
347 """
Armin Ronachere791c2a2008-04-07 18:39:54 +0200348 fields = ('items', 'ctx')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200349
350 def as_const(self):
351 return tuple(x.as_const() for x in self.items)
352
353 def can_assign(self):
354 for item in self.items:
355 if not item.can_assign():
356 return False
357 return True
358
359
360class List(Literal):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200361 """any list literal such as {{ [1, 2, 3] }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200362 fields = ('items',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200363
364 def as_const(self):
365 return [x.as_const() for x in self.items]
366
367
368class Dict(Literal):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200369 """any dict literal such as {{ {1: 2, 3: 4} }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200370 fields = ('items',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200371
372 def as_const(self):
373 return dict(x.as_const() for x in self.items)
374
375
376class Pair(Helper):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200377 """A key, value pair for dicts."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200378 fields = ('key', 'value')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200379
380 def as_const(self):
381 return self.key.as_const(), self.value.as_const()
382
383
Armin Ronacher8efc5222008-04-08 14:47:40 +0200384class Keyword(Helper):
385 """A key, value pair for keyword arguments."""
386 fields = ('key', 'value')
387
388
Armin Ronacher07bc6842008-03-31 14:18:49 +0200389class CondExpr(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200390 """{{ foo if bar else baz }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200391 fields = ('test', 'expr1', 'expr2')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200392
393 def as_const(self):
394 if self.test.as_const():
395 return self.expr1.as_const()
396 return self.expr2.as_const()
397
398
399class Filter(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200400 """{{ foo|bar|baz }}"""
Armin Ronacherd55ab532008-04-09 16:13:39 +0200401 fields = ('node', 'name', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200402
Armin Ronacher00d5d212008-04-13 01:10:18 +0200403 def as_const(self, obj=None):
404 if self.node is obj is None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200405 raise Impossible()
Armin Ronacherd55ab532008-04-09 16:13:39 +0200406 filter = self.environment.filters.get(self.name)
407 if filter is None or getattr(filter, 'contextfilter', False):
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200408 raise Impossible()
Armin Ronacher00d5d212008-04-13 01:10:18 +0200409 if obj is None:
410 obj = self.node.as_const()
Armin Ronacherd55ab532008-04-09 16:13:39 +0200411 args = [x.as_const() for x in self.args]
412 kwargs = dict(x.as_const() for x in self.kwargs)
413 if self.dyn_args is not None:
414 try:
415 args.extend(self.dyn_args.as_const())
416 except:
417 raise Impossible()
418 if self.dyn_kwargs is not None:
419 try:
420 kwargs.update(self.dyn_kwargs.as_const())
421 except:
422 raise Impossible()
423 try:
424 return filter(obj, *args, **kwargs)
425 except:
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200426 raise Impossible()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200427
428
Armin Ronacher07bc6842008-03-31 14:18:49 +0200429class Test(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200430 """{{ foo is lower }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200431 fields = ('node', 'name', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200432
433
434class Call(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200435 """{{ foo(bar) }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200436 fields = ('node', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200437
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200438 def as_const(self):
439 obj = self.node.as_const()
440 args = [x.as_const() for x in self.args]
441 kwargs = dict(x.as_const() for x in self.kwargs)
442 if self.dyn_args is not None:
443 try:
444 args.extend(self.dyn_args.as_const())
445 except:
446 raise Impossible()
447 if self.dyn_kwargs is not None:
448 try:
Armin Ronacherd55ab532008-04-09 16:13:39 +0200449 kwargs.update(self.dyn_kwargs.as_const())
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200450 except:
451 raise Impossible()
452 try:
453 return obj(*args, **kwargs)
454 except:
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200455 raise Impossible()
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200456
Armin Ronacher07bc6842008-03-31 14:18:49 +0200457
458class Subscript(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200459 """{{ foo.bar }} and {{ foo['bar'] }} etc."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200460 fields = ('node', 'arg', 'ctx')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200461
462 def as_const(self):
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200463 if self.ctx != 'load':
464 raise Impossible()
Armin Ronacher07bc6842008-03-31 14:18:49 +0200465 try:
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200466 return subscribe(self.node.as_const(), self.arg.as_const())
Armin Ronacher07bc6842008-03-31 14:18:49 +0200467 except:
468 raise Impossible()
469
470 def can_assign(self):
471 return True
472
473
474class Slice(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200475 """1:2:3 etc."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200476 fields = ('start', 'stop', 'step')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200477
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200478 def as_const(self):
479 def const(obj):
480 if obj is None:
481 return obj
482 return obj.as_const()
483 return slice(const(self.start), const(self.stop), const(self.step))
484
Armin Ronacher07bc6842008-03-31 14:18:49 +0200485
486class Concat(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200487 """For {{ foo ~ bar }}. Concatenates strings."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200488 fields = ('nodes',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200489
490 def as_const(self):
491 return ''.join(unicode(x.as_const()) for x in self.nodes)
492
493
494class Compare(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200495 """{{ foo == bar }}, {{ foo >= bar }} etc."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200496 fields = ('expr', 'ops')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200497
Armin Ronacher625215e2008-04-13 16:31:08 +0200498 def as_const(self):
499 result = value = self.expr.as_const()
500 for op in self.ops:
501 new_value = op.expr.as_const()
502 result = _cmpop_to_func[op.op](value, new_value)
503 value = new_value
504 return result
505
Armin Ronacher07bc6842008-03-31 14:18:49 +0200506
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200507class Operand(Helper):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200508 """Operator + expression."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200509 fields = ('op', 'expr')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200510
511
Armin Ronacher07bc6842008-03-31 14:18:49 +0200512class Mul(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200513 """{{ foo * bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200514 operator = '*'
515
516
517class Div(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200518 """{{ foo / bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200519 operator = '/'
520
521
522class FloorDiv(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200523 """{{ foo // bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200524 operator = '//'
525
526
527class Add(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200528 """{{ foo + bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200529 operator = '+'
530
531
532class Sub(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200533 """{{ foo - bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200534 operator = '-'
535
536
537class Mod(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200538 """{{ foo % bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200539 operator = '%'
540
541
542class Pow(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200543 """{{ foo ** bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200544 operator = '**'
545
546
547class And(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200548 """{{ foo and bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200549 operator = 'and'
550
551 def as_const(self):
552 return self.left.as_const() and self.right.as_const()
553
554
555class Or(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200556 """{{ foo or bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200557 operator = 'or'
558
559 def as_const(self):
560 return self.left.as_const() or self.right.as_const()
561
562
563class Not(UnaryExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200564 """{{ not foo }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200565 operator = 'not'
566
567
Armin Ronachere791c2a2008-04-07 18:39:54 +0200568class Neg(UnaryExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200569 """{{ -foo }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200570 operator = '-'
571
572
Armin Ronachere791c2a2008-04-07 18:39:54 +0200573class Pos(UnaryExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200574 """{{ +foo }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200575 operator = '+'