blob: 992752a1b197e59b630f314876d3bfc042f658af [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 = []
Armin Ronacher7324eb82008-04-21 07:55:52 +020061 storage.extend(getattr(bases[0], attr, ()))
Armin Ronacher07bc6842008-03-31 14:18:49 +020062 storage.extend(d.get(attr, ()))
Armin Ronacher7324eb82008-04-21 07:55:52 +020063 assert len(bases) == 1, 'multiple inheritance not allowed'
64 assert len(storage) == len(set(storage)), 'layout conflict'
Armin Ronacher07bc6842008-03-31 14:18:49 +020065 d[attr] = tuple(storage)
Armin Ronacher7324eb82008-04-21 07:55:52 +020066 return type.__new__(cls, name, bases, d)
Armin Ronacher07bc6842008-03-31 14:18:49 +020067
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]
Armin Ronacher9a027f42008-04-17 11:13:40 +0200422 if getattr(filter, 'environmentfilter', False):
423 args.insert(0, self.environment)
Armin Ronacherd55ab532008-04-09 16:13:39 +0200424 kwargs = dict(x.as_const() for x in self.kwargs)
425 if self.dyn_args is not None:
426 try:
427 args.extend(self.dyn_args.as_const())
428 except:
429 raise Impossible()
430 if self.dyn_kwargs is not None:
431 try:
432 kwargs.update(self.dyn_kwargs.as_const())
433 except:
434 raise Impossible()
435 try:
436 return filter(obj, *args, **kwargs)
437 except:
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200438 raise Impossible()
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200439
440
Armin Ronacher07bc6842008-03-31 14:18:49 +0200441class Test(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200442 """{{ foo is lower }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200443 fields = ('node', 'name', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200444
445
446class Call(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200447 """{{ foo(bar) }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200448 fields = ('node', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200449
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200450 def as_const(self):
451 obj = self.node.as_const()
452 args = [x.as_const() for x in self.args]
453 kwargs = dict(x.as_const() for x in self.kwargs)
454 if self.dyn_args is not None:
455 try:
456 args.extend(self.dyn_args.as_const())
457 except:
458 raise Impossible()
459 if self.dyn_kwargs is not None:
460 try:
Armin Ronacherd55ab532008-04-09 16:13:39 +0200461 kwargs.update(self.dyn_kwargs.as_const())
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200462 except:
463 raise Impossible()
464 try:
465 return obj(*args, **kwargs)
466 except:
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200467 raise Impossible()
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200468
Armin Ronacher07bc6842008-03-31 14:18:49 +0200469
470class Subscript(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200471 """{{ foo.bar }} and {{ foo['bar'] }} etc."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200472 fields = ('node', 'arg', 'ctx')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200473
474 def as_const(self):
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200475 if self.ctx != 'load':
476 raise Impossible()
Armin Ronacher07bc6842008-03-31 14:18:49 +0200477 try:
Armin Ronacherc63243e2008-04-14 22:53:58 +0200478 return environmen.subscribe(self.node.as_const(), self.arg.as_const())
Armin Ronacher07bc6842008-03-31 14:18:49 +0200479 except:
480 raise Impossible()
481
482 def can_assign(self):
483 return True
484
485
486class Slice(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200487 """1:2:3 etc."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200488 fields = ('start', 'stop', 'step')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200489
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200490 def as_const(self):
491 def const(obj):
492 if obj is None:
493 return obj
494 return obj.as_const()
495 return slice(const(self.start), const(self.stop), const(self.step))
496
Armin Ronacher07bc6842008-03-31 14:18:49 +0200497
498class Concat(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200499 """For {{ foo ~ bar }}. Concatenates strings."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200500 fields = ('nodes',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200501
502 def as_const(self):
503 return ''.join(unicode(x.as_const()) for x in self.nodes)
504
505
506class Compare(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200507 """{{ foo == bar }}, {{ foo >= bar }} etc."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200508 fields = ('expr', 'ops')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200509
Armin Ronacher625215e2008-04-13 16:31:08 +0200510 def as_const(self):
511 result = value = self.expr.as_const()
512 for op in self.ops:
513 new_value = op.expr.as_const()
514 result = _cmpop_to_func[op.op](value, new_value)
515 value = new_value
516 return result
517
Armin Ronacher07bc6842008-03-31 14:18:49 +0200518
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200519class Operand(Helper):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200520 """Operator + expression."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200521 fields = ('op', 'expr')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200522
523
Armin Ronacher07bc6842008-03-31 14:18:49 +0200524class Mul(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200525 """{{ foo * bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200526 operator = '*'
527
528
529class Div(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200530 """{{ foo / bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200531 operator = '/'
532
533
534class FloorDiv(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200535 """{{ foo // bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200536 operator = '//'
537
538
539class Add(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200540 """{{ foo + bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200541 operator = '+'
542
543
544class Sub(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200545 """{{ foo - bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200546 operator = '-'
547
548
549class Mod(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200550 """{{ foo % bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200551 operator = '%'
552
553
554class Pow(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200555 """{{ foo ** bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200556 operator = '**'
557
558
559class And(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200560 """{{ foo and bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200561 operator = 'and'
562
563 def as_const(self):
564 return self.left.as_const() and self.right.as_const()
565
566
567class Or(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200568 """{{ foo or bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200569 operator = 'or'
570
571 def as_const(self):
572 return self.left.as_const() or self.right.as_const()
573
574
575class Not(UnaryExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200576 """{{ not foo }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200577 operator = 'not'
578
579
Armin Ronachere791c2a2008-04-07 18:39:54 +0200580class Neg(UnaryExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200581 """{{ -foo }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200582 operator = '-'
583
584
Armin Ronachere791c2a2008-04-07 18:39:54 +0200585class Pos(UnaryExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200586 """{{ +foo }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200587 operator = '+'