blob: 8c58959ed09f43bf5b8eb79d179841949ebfbb41 [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)
Armin Ronacherf59bac22008-04-20 13:11:43 +020066 rv = type.__new__(cls, name, bases, d)
67
68 # unless the node is a subclass of `CustomNode` it may not
69 # be defined in any other module than the jinja2.nodes module.
70 # the reason for this is that the we don't want users to take
71 # advantage of the fact that the parser is using the node name
72 # only as callback name for non custom nodes. This could lead
73 # to broken code in the future and is disallowed because of this.
74 if rv.__module__ != 'jinja2.nodes' and not \
75 isinstance(rv, CustomStmt):
76 raise TypeError('non builtin node %r is not a subclass of '
77 'CustomStmt.' % node.__class__.__name__)
78 return rv
Armin Ronacher07bc6842008-03-31 14:18:49 +020079
80
81class Node(object):
Armin Ronacher8efc5222008-04-08 14:47:40 +020082 """Baseclass for all Jinja nodes."""
Armin Ronacher07bc6842008-03-31 14:18:49 +020083 __metaclass__ = NodeType
Armin Ronachere791c2a2008-04-07 18:39:54 +020084 fields = ()
Armin Ronacherd55ab532008-04-09 16:13:39 +020085 attributes = ('lineno', 'environment')
Armin Ronacher07bc6842008-03-31 14:18:49 +020086
87 def __init__(self, *args, **kw):
88 if args:
Armin Ronachere791c2a2008-04-07 18:39:54 +020089 if len(args) != len(self.fields):
90 if not self.fields:
Armin Ronacher07bc6842008-03-31 14:18:49 +020091 raise TypeError('%r takes 0 arguments' %
92 self.__class__.__name__)
93 raise TypeError('%r takes 0 or %d argument%s' % (
94 self.__class__.__name__,
Armin Ronachere791c2a2008-04-07 18:39:54 +020095 len(self.fields),
96 len(self.fields) != 1 and 's' or ''
Armin Ronacher07bc6842008-03-31 14:18:49 +020097 ))
Armin Ronachere791c2a2008-04-07 18:39:54 +020098 for name, arg in izip(self.fields, args):
Armin Ronacher07bc6842008-03-31 14:18:49 +020099 setattr(self, name, arg)
Armin Ronachere791c2a2008-04-07 18:39:54 +0200100 for attr in self.attributes:
Armin Ronacher07bc6842008-03-31 14:18:49 +0200101 setattr(self, attr, kw.pop(attr, None))
102 if kw:
103 raise TypeError('unknown keyword argument %r' %
104 iter(kw).next())
105
106 def iter_fields(self):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200107 """Iterate over all fields."""
108 for name in self.fields:
Armin Ronacher07bc6842008-03-31 14:18:49 +0200109 try:
110 yield name, getattr(self, name)
111 except AttributeError:
112 pass
113
114 def iter_child_nodes(self):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200115 """Iterate over all child nodes."""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200116 for field, item in self.iter_fields():
117 if isinstance(item, list):
118 for n in item:
119 if isinstance(n, Node):
120 yield n
121 elif isinstance(item, Node):
122 yield item
123
Armin Ronachere791c2a2008-04-07 18:39:54 +0200124 def find(self, node_type):
125 """Find the first node of a given type."""
126 for result in self.find_all(node_type):
127 return result
128
129 def find_all(self, node_type):
130 """Find all the nodes of a given type."""
131 for child in self.iter_child_nodes():
132 if isinstance(child, node_type):
133 yield child
134 for result in child.find_all(node_type):
135 yield result
136
Armin Ronacher0ecb8592008-04-09 16:29:47 +0200137 def copy(self):
138 """Return a deep copy of the node."""
139 result = object.__new__(self.__class__)
140 for field, value in self.iter_fields():
141 if isinstance(value, Node):
142 new_value = value.copy()
143 elif isinstance(value, list):
144 new_value = []
Armin Ronacherd436e982008-04-09 16:31:20 +0200145 for item in value:
Armin Ronacher0ecb8592008-04-09 16:29:47 +0200146 if isinstance(item, Node):
147 item = item.copy()
148 else:
149 item = copy(item)
150 new_value.append(item)
151 else:
Armin Ronacherd436e982008-04-09 16:31:20 +0200152 new_value = copy(value)
Armin Ronacher0ecb8592008-04-09 16:29:47 +0200153 setattr(result, field, new_value)
154 for attr in self.attributes:
155 try:
156 setattr(result, attr, getattr(self, attr))
157 except AttributeError:
158 pass
159 return result
160
Armin Ronachere791c2a2008-04-07 18:39:54 +0200161 def set_ctx(self, ctx):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200162 """Reset the context of a node and all child nodes. Per default the
163 parser will all generate nodes that have a 'load' context as it's the
164 most common one. This method is used in the parser to set assignment
165 targets and other nodes to a store context.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200166 """
167 todo = deque([self])
168 while todo:
169 node = todo.popleft()
170 if 'ctx' in node.fields:
171 node.ctx = ctx
172 todo.extend(node.iter_child_nodes())
173
Armin Ronacher2e9396b2008-04-16 14:21:57 +0200174 def set_lineno(self, lineno, override=False):
175 """Set the line numbers of the node and children."""
176 todo = deque([self])
177 while todo:
178 node = todo.popleft()
179 if 'lineno' in node.attributes:
180 if node.lineno is None or override:
181 node.lineno = lineno
182 todo.extend(node.iter_child_nodes())
183
Armin Ronacherd55ab532008-04-09 16:13:39 +0200184 def set_environment(self, environment):
185 """Set the environment for all nodes."""
186 todo = deque([self])
187 while todo:
188 node = todo.popleft()
189 node.environment = environment
190 todo.extend(node.iter_child_nodes())
191
Armin Ronacher07bc6842008-03-31 14:18:49 +0200192 def __repr__(self):
193 return '%s(%s)' % (
194 self.__class__.__name__,
195 ', '.join('%s=%r' % (arg, getattr(self, arg, None)) for
Armin Ronachere791c2a2008-04-07 18:39:54 +0200196 arg in self.fields)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200197 )
198
199
200class Stmt(Node):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200201 """Base node for all statements."""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200202
203
204class Helper(Node):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200205 """Nodes that exist in a specific context only."""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200206
207
Armin Ronacherf59bac22008-04-20 13:11:43 +0200208class CustomStmt(Stmt):
209 """Custom statements must extend this node."""
210
211 def compile(self, compiler):
212 """The compiler calls this method to get the python sourcecode
213 for the statement.
214 """
215
216
Armin Ronacher07bc6842008-03-31 14:18:49 +0200217class Template(Node):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200218 """Node that represents a template."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200219 fields = ('body',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200220
221
222class Output(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200223 """A node that holds multiple expressions which are then printed out.
224 This is used both for the `print` statement and the regular template data.
Armin Ronacher07bc6842008-03-31 14:18:49 +0200225 """
Armin Ronachere791c2a2008-04-07 18:39:54 +0200226 fields = ('nodes',)
227
228 def optimized_nodes(self):
229 """Try to optimize the nodes."""
230 buffer = []
231 for node in self.nodes:
232 try:
233 const = unicode(node.as_const())
234 except:
235 buffer.append(node)
236 else:
237 if buffer and isinstance(buffer[-1], unicode):
238 buffer[-1] += const
239 else:
240 buffer.append(const)
241 return buffer
Armin Ronacher07bc6842008-03-31 14:18:49 +0200242
243
244class Extends(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200245 """Represents an extends statement."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200246 fields = ('template',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200247
248
249class For(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200250 """A node that represents a for loop"""
Armin Ronacher3d8b7842008-04-13 13:16:50 +0200251 fields = ('target', 'iter', 'body', 'else_', 'test')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200252
253
254class If(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200255 """A node that represents an if condition."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200256 fields = ('test', 'body', 'else_')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200257
258
259class Macro(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200260 """A node that represents a macro."""
261 fields = ('name', 'args', 'defaults', 'body')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200262
263
264class CallBlock(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200265 """A node that represents am extended macro call."""
Armin Ronacher71082072008-04-12 14:19:36 +0200266 fields = ('call', 'args', 'defaults', 'body')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200267
268
269class Set(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200270 """Allows defining own variables."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200271 fields = ('name', 'expr')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200272
273
274class FilterBlock(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200275 """Node for filter sections."""
Armin Ronacherfa865fb2008-04-12 22:11:53 +0200276 fields = ('body', 'filter')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200277
278
279class Block(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200280 """A node that represents a block."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200281 fields = ('name', 'body')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200282
283
284class Include(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200285 """A node that represents the include tag."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200286 fields = ('template', 'target')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200287
288
289class 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()
473 args = [x.as_const() for x in self.args]
474 kwargs = dict(x.as_const() for x in self.kwargs)
475 if self.dyn_args is not None:
476 try:
477 args.extend(self.dyn_args.as_const())
478 except:
479 raise Impossible()
480 if self.dyn_kwargs is not None:
481 try:
Armin Ronacherd55ab532008-04-09 16:13:39 +0200482 kwargs.update(self.dyn_kwargs.as_const())
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200483 except:
484 raise Impossible()
485 try:
486 return obj(*args, **kwargs)
487 except:
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200488 raise Impossible()
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200489
Armin Ronacher07bc6842008-03-31 14:18:49 +0200490
491class Subscript(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200492 """{{ foo.bar }} and {{ foo['bar'] }} etc."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200493 fields = ('node', 'arg', 'ctx')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200494
495 def as_const(self):
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200496 if self.ctx != 'load':
497 raise Impossible()
Armin Ronacher07bc6842008-03-31 14:18:49 +0200498 try:
Armin Ronacherc63243e2008-04-14 22:53:58 +0200499 return environmen.subscribe(self.node.as_const(), self.arg.as_const())
Armin Ronacher07bc6842008-03-31 14:18:49 +0200500 except:
501 raise Impossible()
502
503 def can_assign(self):
504 return True
505
506
507class Slice(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200508 """1:2:3 etc."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200509 fields = ('start', 'stop', 'step')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200510
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200511 def as_const(self):
512 def const(obj):
513 if obj is None:
514 return obj
515 return obj.as_const()
516 return slice(const(self.start), const(self.stop), const(self.step))
517
Armin Ronacher07bc6842008-03-31 14:18:49 +0200518
519class Concat(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200520 """For {{ foo ~ bar }}. Concatenates strings."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200521 fields = ('nodes',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200522
523 def as_const(self):
524 return ''.join(unicode(x.as_const()) for x in self.nodes)
525
526
527class Compare(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200528 """{{ foo == bar }}, {{ foo >= bar }} etc."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200529 fields = ('expr', 'ops')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200530
Armin Ronacher625215e2008-04-13 16:31:08 +0200531 def as_const(self):
532 result = value = self.expr.as_const()
533 for op in self.ops:
534 new_value = op.expr.as_const()
535 result = _cmpop_to_func[op.op](value, new_value)
536 value = new_value
537 return result
538
Armin Ronacher07bc6842008-03-31 14:18:49 +0200539
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200540class Operand(Helper):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200541 """Operator + expression."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200542 fields = ('op', 'expr')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200543
544
Armin Ronacher07bc6842008-03-31 14:18:49 +0200545class Mul(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200546 """{{ foo * bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200547 operator = '*'
548
549
550class Div(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200551 """{{ foo / bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200552 operator = '/'
553
554
555class FloorDiv(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200556 """{{ foo // bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200557 operator = '//'
558
559
560class Add(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200561 """{{ foo + bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200562 operator = '+'
563
564
565class Sub(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200566 """{{ foo - bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200567 operator = '-'
568
569
570class Mod(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200571 """{{ foo % bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200572 operator = '%'
573
574
575class Pow(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200576 """{{ foo ** bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200577 operator = '**'
578
579
580class And(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200581 """{{ foo and bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200582 operator = 'and'
583
584 def as_const(self):
585 return self.left.as_const() and self.right.as_const()
586
587
588class Or(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200589 """{{ foo or bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200590 operator = 'or'
591
592 def as_const(self):
593 return self.left.as_const() or self.right.as_const()
594
595
596class Not(UnaryExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200597 """{{ not foo }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200598 operator = 'not'
599
600
Armin Ronachere791c2a2008-04-07 18:39:54 +0200601class Neg(UnaryExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200602 """{{ -foo }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200603 operator = '-'
604
605
Armin Ronachere791c2a2008-04-07 18:39:54 +0200606class Pos(UnaryExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200607 """{{ +foo }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200608 operator = '+'