blob: 51c30396419d4313bf4eece44cc2f6a4b4d69999 [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
19
20
21_binop_to_func = {
22 '*': operator.mul,
23 '/': operator.truediv,
24 '//': operator.floordiv,
25 '**': operator.pow,
26 '%': operator.mod,
27 '+': operator.add,
28 '-': operator.sub
29}
30
31_uaop_to_func = {
32 'not': operator.not_,
33 '+': operator.pos,
34 '-': operator.neg
35}
36
Armin Ronacher625215e2008-04-13 16:31:08 +020037_cmpop_to_func = {
38 'eq': operator.eq,
39 'ne': operator.ne,
40 'gt': operator.gt,
41 'gteq': operator.ge,
42 'lt': operator.lt,
43 'lteq': operator.le,
44 'in': operator.contains,
45 'notin': lambda a, b: not operator.contains(a, b)
46}
47
Armin Ronacher07bc6842008-03-31 14:18:49 +020048
49class Impossible(Exception):
Armin Ronacher8efc5222008-04-08 14:47:40 +020050 """Raised if the node could not perform a requested action."""
Armin Ronacher07bc6842008-03-31 14:18:49 +020051
52
53class NodeType(type):
Armin Ronacher8efc5222008-04-08 14:47:40 +020054 """A metaclass for nodes that handles the field and attribute
55 inheritance. fields and attributes from the parent class are
56 automatically forwarded to the child."""
Armin Ronacher07bc6842008-03-31 14:18:49 +020057
58 def __new__(cls, name, bases, d):
Armin Ronachere791c2a2008-04-07 18:39:54 +020059 for attr in 'fields', 'attributes':
Armin Ronacher07bc6842008-03-31 14:18:49 +020060 storage = []
61 for base in bases:
62 storage.extend(getattr(base, attr, ()))
63 storage.extend(d.get(attr, ()))
64 assert len(storage) == len(set(storage))
65 d[attr] = tuple(storage)
66 return type.__new__(cls, name, bases, d)
67
68
69class Node(object):
Armin Ronacher8efc5222008-04-08 14:47:40 +020070 """Baseclass for all Jinja nodes."""
Armin Ronacher07bc6842008-03-31 14:18:49 +020071 __metaclass__ = NodeType
Armin Ronachere791c2a2008-04-07 18:39:54 +020072 fields = ()
Armin Ronacherd55ab532008-04-09 16:13:39 +020073 attributes = ('lineno', 'environment')
Armin Ronacher07bc6842008-03-31 14:18:49 +020074
75 def __init__(self, *args, **kw):
76 if args:
Armin Ronachere791c2a2008-04-07 18:39:54 +020077 if len(args) != len(self.fields):
78 if not self.fields:
Armin Ronacher07bc6842008-03-31 14:18:49 +020079 raise TypeError('%r takes 0 arguments' %
80 self.__class__.__name__)
81 raise TypeError('%r takes 0 or %d argument%s' % (
82 self.__class__.__name__,
Armin Ronachere791c2a2008-04-07 18:39:54 +020083 len(self.fields),
84 len(self.fields) != 1 and 's' or ''
Armin Ronacher07bc6842008-03-31 14:18:49 +020085 ))
Armin Ronachere791c2a2008-04-07 18:39:54 +020086 for name, arg in izip(self.fields, args):
Armin Ronacher07bc6842008-03-31 14:18:49 +020087 setattr(self, name, arg)
Armin Ronachere791c2a2008-04-07 18:39:54 +020088 for attr in self.attributes:
Armin Ronacher07bc6842008-03-31 14:18:49 +020089 setattr(self, attr, kw.pop(attr, None))
90 if kw:
91 raise TypeError('unknown keyword argument %r' %
92 iter(kw).next())
93
94 def iter_fields(self):
Armin Ronachere791c2a2008-04-07 18:39:54 +020095 """Iterate over all fields."""
96 for name in self.fields:
Armin Ronacher07bc6842008-03-31 14:18:49 +020097 try:
98 yield name, getattr(self, name)
99 except AttributeError:
100 pass
101
102 def iter_child_nodes(self):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200103 """Iterate over all child nodes."""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200104 for field, item in self.iter_fields():
105 if isinstance(item, list):
106 for n in item:
107 if isinstance(n, Node):
108 yield n
109 elif isinstance(item, Node):
110 yield item
111
Armin Ronachere791c2a2008-04-07 18:39:54 +0200112 def find(self, node_type):
113 """Find the first node of a given type."""
114 for result in self.find_all(node_type):
115 return result
116
117 def find_all(self, node_type):
118 """Find all the nodes of a given type."""
119 for child in self.iter_child_nodes():
120 if isinstance(child, node_type):
121 yield child
122 for result in child.find_all(node_type):
123 yield result
124
Armin Ronacher0ecb8592008-04-09 16:29:47 +0200125 def copy(self):
126 """Return a deep copy of the node."""
127 result = object.__new__(self.__class__)
128 for field, value in self.iter_fields():
129 if isinstance(value, Node):
130 new_value = value.copy()
131 elif isinstance(value, list):
132 new_value = []
Armin Ronacherd436e982008-04-09 16:31:20 +0200133 for item in value:
Armin Ronacher0ecb8592008-04-09 16:29:47 +0200134 if isinstance(item, Node):
135 item = item.copy()
136 else:
137 item = copy(item)
138 new_value.append(item)
139 else:
Armin Ronacherd436e982008-04-09 16:31:20 +0200140 new_value = copy(value)
Armin Ronacher0ecb8592008-04-09 16:29:47 +0200141 setattr(result, field, new_value)
142 for attr in self.attributes:
143 try:
144 setattr(result, attr, getattr(self, attr))
145 except AttributeError:
146 pass
147 return result
148
Armin Ronachere791c2a2008-04-07 18:39:54 +0200149 def set_ctx(self, ctx):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200150 """Reset the context of a node and all child nodes. Per default the
151 parser will all generate nodes that have a 'load' context as it's the
152 most common one. This method is used in the parser to set assignment
153 targets and other nodes to a store context.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200154 """
155 todo = deque([self])
156 while todo:
157 node = todo.popleft()
158 if 'ctx' in node.fields:
159 node.ctx = ctx
160 todo.extend(node.iter_child_nodes())
161
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200162 def set_lineno(self, lineno, override=False):
163 """Set the line numbers of the node and children."""
164 todo = deque([self])
165 while todo:
166 node = todo.popleft()
167 if 'lineno' in node.attributes:
168 if node.lineno is None or override:
169 node.lineno = lineno
170 todo.extend(node.iter_child_nodes())
171
Armin Ronacherd55ab532008-04-09 16:13:39 +0200172 def set_environment(self, environment):
173 """Set the environment for all nodes."""
174 todo = deque([self])
175 while todo:
176 node = todo.popleft()
177 node.environment = environment
178 todo.extend(node.iter_child_nodes())
179
Armin Ronacher07bc6842008-03-31 14:18:49 +0200180 def __repr__(self):
181 return '%s(%s)' % (
182 self.__class__.__name__,
183 ', '.join('%s=%r' % (arg, getattr(self, arg, None)) for
Armin Ronachere791c2a2008-04-07 18:39:54 +0200184 arg in self.fields)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200185 )
186
187
188class Stmt(Node):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200189 """Base node for all statements."""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200190
191
192class Helper(Node):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200193 """Nodes that exist in a specific context only."""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200194
195
196class Template(Node):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200197 """Node that represents a template."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200198 fields = ('body',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200199
200
201class Output(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200202 """A node that holds multiple expressions which are then printed out.
203 This is used both for the `print` statement and the regular template data.
Armin Ronacher07bc6842008-03-31 14:18:49 +0200204 """
Armin Ronachere791c2a2008-04-07 18:39:54 +0200205 fields = ('nodes',)
206
207 def optimized_nodes(self):
208 """Try to optimize the nodes."""
209 buffer = []
210 for node in self.nodes:
211 try:
212 const = unicode(node.as_const())
213 except:
214 buffer.append(node)
215 else:
216 if buffer and isinstance(buffer[-1], unicode):
217 buffer[-1] += const
218 else:
219 buffer.append(const)
220 return buffer
Armin Ronacher07bc6842008-03-31 14:18:49 +0200221
222
223class Extends(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200224 """Represents an extends statement."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200225 fields = ('template',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200226
227
228class For(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200229 """A node that represents a for loop"""
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200230 fields = ('target', 'iter', 'body', 'else_', 'test')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200231
232
233class If(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200234 """A node that represents an if condition."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200235 fields = ('test', 'body', 'else_')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200236
237
238class Macro(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200239 """A node that represents a macro."""
240 fields = ('name', 'args', 'defaults', 'body')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200241
242
243class CallBlock(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200244 """A node that represents am extended macro call."""
Armin Ronacher71082072008-04-12 14:19:36 +0200245 fields = ('call', 'args', 'defaults', 'body')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200246
247
248class Set(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200249 """Allows defining own variables."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200250 fields = ('name', 'expr')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200251
252
253class FilterBlock(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200254 """Node for filter sections."""
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200255 fields = ('body', 'filter')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200256
257
258class Block(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200259 """A node that represents a block."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200260 fields = ('name', 'body')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200261
262
263class Include(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200264 """A node that represents the include tag."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200265 fields = ('template', 'target')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200266
267
268class Trans(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200269 """A node for translatable sections."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200270 fields = ('singular', 'plural', 'indicator', 'replacements')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200271
272
273class ExprStmt(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200274 """A statement that evaluates an expression to None."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200275 fields = ('node',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200276
277
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200278class Assign(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200279 """Assigns an expression to a target."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200280 fields = ('target', 'node')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200281
282
Armin Ronacher07bc6842008-03-31 14:18:49 +0200283class Expr(Node):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200284 """Baseclass for all expressions."""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200285
286 def as_const(self):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200287 """Return the value of the expression as constant or raise
288 `Impossible` if this was not possible.
Armin Ronacher07bc6842008-03-31 14:18:49 +0200289 """
290 raise Impossible()
291
292 def can_assign(self):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200293 """Check if it's possible to assign something to this node."""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200294 return False
295
296
297class BinExpr(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200298 """Baseclass for all binary expressions."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200299 fields = ('left', 'right')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200300 operator = None
301
302 def as_const(self):
303 f = _binop_to_func[self.operator]
304 try:
305 return f(self.left.as_const(), self.right.as_const())
306 except:
Armin Ronacher07bc6842008-03-31 14:18:49 +0200307 raise Impossible()
308
309
310class UnaryExpr(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200311 """Baseclass for all unary expressions."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200312 fields = ('node',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200313 operator = None
314
315 def as_const(self):
316 f = _uaop_to_func[self.operator]
317 try:
318 return f(self.node.as_const())
319 except:
320 raise Impossible()
321
322
323class Name(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200324 """any name such as {{ foo }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200325 fields = ('name', 'ctx')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200326
327 def can_assign(self):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200328 return self.name not in ('true', 'false', 'none')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200329
330
331class Literal(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200332 """Baseclass for literals."""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200333
334
335class Const(Literal):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200336 """any constat such as {{ "foo" }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200337 fields = ('value',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200338
339 def as_const(self):
340 return self.value
341
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200342 @classmethod
Armin Ronacherd55ab532008-04-09 16:13:39 +0200343 def from_untrusted(cls, value, lineno=None, environment=None):
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200344 """Return a const object if the value is representable as
345 constant value in the generated code, otherwise it will raise
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200346 an `Impossible` exception.
347 """
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200348 from compiler import has_safe_repr
349 if not has_safe_repr(value):
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200350 raise Impossible()
Armin Ronacherd55ab532008-04-09 16:13:39 +0200351 return cls(value, lineno=lineno, environment=environment)
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200352
Armin Ronacher07bc6842008-03-31 14:18:49 +0200353
354class Tuple(Literal):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200355 """For loop unpacking and some other things like multiple arguments
Armin Ronacher07bc6842008-03-31 14:18:49 +0200356 for subscripts.
357 """
Armin Ronachere791c2a2008-04-07 18:39:54 +0200358 fields = ('items', 'ctx')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200359
360 def as_const(self):
361 return tuple(x.as_const() for x in self.items)
362
363 def can_assign(self):
364 for item in self.items:
365 if not item.can_assign():
366 return False
367 return True
368
369
370class List(Literal):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200371 """any list literal such as {{ [1, 2, 3] }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200372 fields = ('items',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200373
374 def as_const(self):
375 return [x.as_const() for x in self.items]
376
377
378class Dict(Literal):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200379 """any dict literal such as {{ {1: 2, 3: 4} }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200380 fields = ('items',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200381
382 def as_const(self):
383 return dict(x.as_const() for x in self.items)
384
385
386class Pair(Helper):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200387 """A key, value pair for dicts."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200388 fields = ('key', 'value')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200389
390 def as_const(self):
391 return self.key.as_const(), self.value.as_const()
392
393
Armin Ronacher8efc5222008-04-08 14:47:40 +0200394class Keyword(Helper):
395 """A key, value pair for keyword arguments."""
396 fields = ('key', 'value')
397
398
Armin Ronacher07bc6842008-03-31 14:18:49 +0200399class CondExpr(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200400 """{{ foo if bar else baz }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200401 fields = ('test', 'expr1', 'expr2')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200402
403 def as_const(self):
404 if self.test.as_const():
405 return self.expr1.as_const()
406 return self.expr2.as_const()
407
408
409class Filter(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200410 """{{ foo|bar|baz }}"""
Armin Ronacherd55ab532008-04-09 16:13:39 +0200411 fields = ('node', 'name', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200412
Armin Ronacher00d5d212008-04-13 01:10:18 +0200413 def as_const(self, obj=None):
414 if self.node is obj is None:
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200415 raise Impossible()
Armin Ronacherd55ab532008-04-09 16:13:39 +0200416 filter = self.environment.filters.get(self.name)
417 if filter is None or getattr(filter, 'contextfilter', False):
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200418 raise Impossible()
Armin Ronacher00d5d212008-04-13 01:10:18 +0200419 if obj is None:
420 obj = self.node.as_const()
Armin Ronacherd55ab532008-04-09 16:13:39 +0200421 args = [x.as_const() for x in self.args]
422 kwargs = dict(x.as_const() for x in self.kwargs)
423 if self.dyn_args is not None:
424 try:
425 args.extend(self.dyn_args.as_const())
426 except:
427 raise Impossible()
428 if self.dyn_kwargs is not None:
429 try:
430 kwargs.update(self.dyn_kwargs.as_const())
431 except:
432 raise Impossible()
433 try:
434 return filter(obj, *args, **kwargs)
435 except:
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200436 raise Impossible()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200437
438
Armin Ronacher07bc6842008-03-31 14:18:49 +0200439class Test(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200440 """{{ foo is lower }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200441 fields = ('node', 'name', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200442
443
444class Call(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200445 """{{ foo(bar) }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200446 fields = ('node', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200447
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200448 def as_const(self):
449 obj = self.node.as_const()
450 args = [x.as_const() for x in self.args]
451 kwargs = dict(x.as_const() for x in self.kwargs)
452 if self.dyn_args is not None:
453 try:
454 args.extend(self.dyn_args.as_const())
455 except:
456 raise Impossible()
457 if self.dyn_kwargs is not None:
458 try:
Armin Ronacherd55ab532008-04-09 16:13:39 +0200459 kwargs.update(self.dyn_kwargs.as_const())
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200460 except:
461 raise Impossible()
462 try:
463 return obj(*args, **kwargs)
464 except:
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200465 raise Impossible()
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200466
Armin Ronacher07bc6842008-03-31 14:18:49 +0200467
468class Subscript(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200469 """{{ foo.bar }} and {{ foo['bar'] }} etc."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200470 fields = ('node', 'arg', 'ctx')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200471
472 def as_const(self):
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200473 if self.ctx != 'load':
474 raise Impossible()
Armin Ronacher07bc6842008-03-31 14:18:49 +0200475 try:
Armin Ronacherc63243e2008-04-14 22:53:58 +0200476 return environmen.subscribe(self.node.as_const(), self.arg.as_const())
Armin Ronacher07bc6842008-03-31 14:18:49 +0200477 except:
478 raise Impossible()
479
480 def can_assign(self):
481 return True
482
483
484class Slice(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200485 """1:2:3 etc."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200486 fields = ('start', 'stop', 'step')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200487
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200488 def as_const(self):
489 def const(obj):
490 if obj is None:
491 return obj
492 return obj.as_const()
493 return slice(const(self.start), const(self.stop), const(self.step))
494
Armin Ronacher07bc6842008-03-31 14:18:49 +0200495
496class Concat(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200497 """For {{ foo ~ bar }}. Concatenates strings."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200498 fields = ('nodes',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200499
500 def as_const(self):
501 return ''.join(unicode(x.as_const()) for x in self.nodes)
502
503
504class Compare(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200505 """{{ foo == bar }}, {{ foo >= bar }} etc."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200506 fields = ('expr', 'ops')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200507
Armin Ronacher625215e2008-04-13 16:31:08 +0200508 def as_const(self):
509 result = value = self.expr.as_const()
510 for op in self.ops:
511 new_value = op.expr.as_const()
512 result = _cmpop_to_func[op.op](value, new_value)
513 value = new_value
514 return result
515
Armin Ronacher07bc6842008-03-31 14:18:49 +0200516
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200517class Operand(Helper):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200518 """Operator + expression."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200519 fields = ('op', 'expr')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200520
521
Armin Ronacher07bc6842008-03-31 14:18:49 +0200522class Mul(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200523 """{{ foo * bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200524 operator = '*'
525
526
527class Div(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200528 """{{ foo / bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200529 operator = '/'
530
531
532class FloorDiv(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200533 """{{ foo // bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200534 operator = '//'
535
536
537class Add(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200538 """{{ foo + bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200539 operator = '+'
540
541
542class Sub(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200543 """{{ foo - bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200544 operator = '-'
545
546
547class Mod(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200548 """{{ foo % bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200549 operator = '%'
550
551
552class Pow(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200553 """{{ foo ** bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200554 operator = '**'
555
556
557class And(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200558 """{{ foo and bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200559 operator = 'and'
560
561 def as_const(self):
562 return self.left.as_const() and self.right.as_const()
563
564
565class Or(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200566 """{{ foo or bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200567 operator = 'or'
568
569 def as_const(self):
570 return self.left.as_const() or self.right.as_const()
571
572
573class Not(UnaryExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200574 """{{ not foo }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200575 operator = 'not'
576
577
Armin Ronachere791c2a2008-04-07 18:39:54 +0200578class Neg(UnaryExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200579 """{{ -foo }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200580 operator = '-'
581
582
Armin Ronachere791c2a2008-04-07 18:39:54 +0200583class Pos(UnaryExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200584 """{{ +foo }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200585 operator = '+'