blob: 6c16c8beac4440917e07ee7200f4a8b97d94d6ca [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
38
39class Impossible(Exception):
Armin Ronacher8efc5222008-04-08 14:47:40 +020040 """Raised if the node could not perform a requested action."""
Armin Ronacher07bc6842008-03-31 14:18:49 +020041
42
43class NodeType(type):
Armin Ronacher8efc5222008-04-08 14:47:40 +020044 """A metaclass for nodes that handles the field and attribute
45 inheritance. fields and attributes from the parent class are
46 automatically forwarded to the child."""
Armin Ronacher07bc6842008-03-31 14:18:49 +020047
48 def __new__(cls, name, bases, d):
Armin Ronachere791c2a2008-04-07 18:39:54 +020049 for attr in 'fields', 'attributes':
Armin Ronacher07bc6842008-03-31 14:18:49 +020050 storage = []
51 for base in bases:
52 storage.extend(getattr(base, attr, ()))
53 storage.extend(d.get(attr, ()))
54 assert len(storage) == len(set(storage))
55 d[attr] = tuple(storage)
56 return type.__new__(cls, name, bases, d)
57
58
59class Node(object):
Armin Ronacher8efc5222008-04-08 14:47:40 +020060 """Baseclass for all Jinja nodes."""
Armin Ronacher07bc6842008-03-31 14:18:49 +020061 __metaclass__ = NodeType
Armin Ronachere791c2a2008-04-07 18:39:54 +020062 fields = ()
63 attributes = ('lineno',)
Armin Ronacher07bc6842008-03-31 14:18:49 +020064
65 def __init__(self, *args, **kw):
66 if args:
Armin Ronachere791c2a2008-04-07 18:39:54 +020067 if len(args) != len(self.fields):
68 if not self.fields:
Armin Ronacher07bc6842008-03-31 14:18:49 +020069 raise TypeError('%r takes 0 arguments' %
70 self.__class__.__name__)
71 raise TypeError('%r takes 0 or %d argument%s' % (
72 self.__class__.__name__,
Armin Ronachere791c2a2008-04-07 18:39:54 +020073 len(self.fields),
74 len(self.fields) != 1 and 's' or ''
Armin Ronacher07bc6842008-03-31 14:18:49 +020075 ))
Armin Ronachere791c2a2008-04-07 18:39:54 +020076 for name, arg in izip(self.fields, args):
Armin Ronacher07bc6842008-03-31 14:18:49 +020077 setattr(self, name, arg)
Armin Ronachere791c2a2008-04-07 18:39:54 +020078 for attr in self.attributes:
Armin Ronacher07bc6842008-03-31 14:18:49 +020079 setattr(self, attr, kw.pop(attr, None))
80 if kw:
81 raise TypeError('unknown keyword argument %r' %
82 iter(kw).next())
83
84 def iter_fields(self):
Armin Ronachere791c2a2008-04-07 18:39:54 +020085 """Iterate over all fields."""
86 for name in self.fields:
Armin Ronacher07bc6842008-03-31 14:18:49 +020087 try:
88 yield name, getattr(self, name)
89 except AttributeError:
90 pass
91
92 def iter_child_nodes(self):
Armin Ronachere791c2a2008-04-07 18:39:54 +020093 """Iterate over all child nodes."""
Armin Ronacher07bc6842008-03-31 14:18:49 +020094 for field, item in self.iter_fields():
95 if isinstance(item, list):
96 for n in item:
97 if isinstance(n, Node):
98 yield n
99 elif isinstance(item, Node):
100 yield item
101
Armin Ronachere791c2a2008-04-07 18:39:54 +0200102 def find(self, node_type):
103 """Find the first node of a given type."""
104 for result in self.find_all(node_type):
105 return result
106
107 def find_all(self, node_type):
108 """Find all the nodes of a given type."""
109 for child in self.iter_child_nodes():
110 if isinstance(child, node_type):
111 yield child
112 for result in child.find_all(node_type):
113 yield result
114
115 def set_ctx(self, ctx):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200116 """Reset the context of a node and all child nodes. Per default the
117 parser will all generate nodes that have a 'load' context as it's the
118 most common one. This method is used in the parser to set assignment
119 targets and other nodes to a store context.
Armin Ronachere791c2a2008-04-07 18:39:54 +0200120 """
121 todo = deque([self])
122 while todo:
123 node = todo.popleft()
124 if 'ctx' in node.fields:
125 node.ctx = ctx
126 todo.extend(node.iter_child_nodes())
127
Armin Ronacher07bc6842008-03-31 14:18:49 +0200128 def __repr__(self):
129 return '%s(%s)' % (
130 self.__class__.__name__,
131 ', '.join('%s=%r' % (arg, getattr(self, arg, None)) for
Armin Ronachere791c2a2008-04-07 18:39:54 +0200132 arg in self.fields)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200133 )
134
135
136class Stmt(Node):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200137 """Base node for all statements."""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200138
139
140class Helper(Node):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200141 """Nodes that exist in a specific context only."""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200142
143
144class Template(Node):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200145 """Node that represents a template."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200146 fields = ('body',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200147
148
149class Output(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200150 """A node that holds multiple expressions which are then printed out.
151 This is used both for the `print` statement and the regular template data.
Armin Ronacher07bc6842008-03-31 14:18:49 +0200152 """
Armin Ronachere791c2a2008-04-07 18:39:54 +0200153 fields = ('nodes',)
154
155 def optimized_nodes(self):
156 """Try to optimize the nodes."""
157 buffer = []
158 for node in self.nodes:
159 try:
160 const = unicode(node.as_const())
161 except:
162 buffer.append(node)
163 else:
164 if buffer and isinstance(buffer[-1], unicode):
165 buffer[-1] += const
166 else:
167 buffer.append(const)
168 return buffer
Armin Ronacher07bc6842008-03-31 14:18:49 +0200169
170
171class Extends(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200172 """Represents an extends statement."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200173 fields = ('template',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200174
175
176class For(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200177 """A node that represents a for loop"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200178 fields = ('target', 'iter', 'body', 'else_', 'recursive')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200179
180
181class If(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200182 """A node that represents an if condition."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200183 fields = ('test', 'body', 'else_')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200184
185
186class Macro(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200187 """A node that represents a macro."""
188 fields = ('name', 'args', 'defaults', 'body')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200189
190
191class CallBlock(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200192 """A node that represents am extended macro call."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200193 fields = ('call', 'body')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200194
195
196class Set(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200197 """Allows defining own variables."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200198 fields = ('name', 'expr')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200199
200
201class FilterBlock(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200202 """Node for filter sections."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200203 fields = ('body', 'filters')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200204
205
206class Block(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200207 """A node that represents a block."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200208 fields = ('name', 'body')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200209
210
211class Include(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200212 """A node that represents the include tag."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200213 fields = ('template', 'target')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200214
215
216class Trans(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200217 """A node for translatable sections."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200218 fields = ('singular', 'plural', 'indicator', 'replacements')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200219
220
221class ExprStmt(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200222 """A statement that evaluates an expression to None."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200223 fields = ('node',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200224
225
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200226class Assign(Stmt):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200227 """Assigns an expression to a target."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200228 fields = ('target', 'node')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200229
230
Armin Ronacher07bc6842008-03-31 14:18:49 +0200231class Expr(Node):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200232 """Baseclass for all expressions."""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200233
234 def as_const(self):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200235 """Return the value of the expression as constant or raise
236 `Impossible` if this was not possible.
Armin Ronacher07bc6842008-03-31 14:18:49 +0200237 """
238 raise Impossible()
239
240 def can_assign(self):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200241 """Check if it's possible to assign something to this node."""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200242 return False
243
244
245class BinExpr(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200246 """Baseclass for all binary expressions."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200247 fields = ('left', 'right')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200248 operator = None
249
250 def as_const(self):
251 f = _binop_to_func[self.operator]
252 try:
253 return f(self.left.as_const(), self.right.as_const())
254 except:
Armin Ronacher07bc6842008-03-31 14:18:49 +0200255 raise Impossible()
256
257
258class UnaryExpr(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200259 """Baseclass for all unary expressions."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200260 fields = ('node',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200261 operator = None
262
263 def as_const(self):
264 f = _uaop_to_func[self.operator]
265 try:
266 return f(self.node.as_const())
267 except:
268 raise Impossible()
269
270
271class Name(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200272 """any name such as {{ foo }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200273 fields = ('name', 'ctx')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200274
275 def can_assign(self):
Armin Ronachere791c2a2008-04-07 18:39:54 +0200276 return self.name not in ('true', 'false', 'none')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200277
278
279class Literal(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200280 """Baseclass for literals."""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200281
282
283class Const(Literal):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200284 """any constat such as {{ "foo" }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200285 fields = ('value',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200286
287 def as_const(self):
288 return self.value
289
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200290 @classmethod
291 def from_untrusted(cls, value, lineno=None, silent=False):
292 """Return a const object if the value is representable as
293 constant value in the generated code, otherwise it will raise
294 an `Impossible` exception."""
295 from compiler import has_safe_repr
296 if not has_safe_repr(value):
297 if silent:
298 return
299 raise Impossible()
300 return cls(value, lineno=lineno)
301
Armin Ronacher07bc6842008-03-31 14:18:49 +0200302
303class Tuple(Literal):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200304 """For loop unpacking and some other things like multiple arguments
Armin Ronacher07bc6842008-03-31 14:18:49 +0200305 for subscripts.
306 """
Armin Ronachere791c2a2008-04-07 18:39:54 +0200307 fields = ('items', 'ctx')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200308
309 def as_const(self):
310 return tuple(x.as_const() for x in self.items)
311
312 def can_assign(self):
313 for item in self.items:
314 if not item.can_assign():
315 return False
316 return True
317
318
319class List(Literal):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200320 """any list literal such as {{ [1, 2, 3] }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200321 fields = ('items',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200322
323 def as_const(self):
324 return [x.as_const() for x in self.items]
325
326
327class Dict(Literal):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200328 """any dict literal such as {{ {1: 2, 3: 4} }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200329 fields = ('items',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200330
331 def as_const(self):
332 return dict(x.as_const() for x in self.items)
333
334
335class Pair(Helper):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200336 """A key, value pair for dicts."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200337 fields = ('key', 'value')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200338
339 def as_const(self):
340 return self.key.as_const(), self.value.as_const()
341
342
Armin Ronacher8efc5222008-04-08 14:47:40 +0200343class Keyword(Helper):
344 """A key, value pair for keyword arguments."""
345 fields = ('key', 'value')
346
347
Armin Ronacher07bc6842008-03-31 14:18:49 +0200348class CondExpr(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200349 """{{ foo if bar else baz }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200350 fields = ('test', 'expr1', 'expr2')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200351
352 def as_const(self):
353 if self.test.as_const():
354 return self.expr1.as_const()
355 return self.expr2.as_const()
356
357
358class Filter(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200359 """{{ foo|bar|baz }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200360 fields = ('node', 'filters')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200361
362
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200363class FilterCall(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200364 """{{ |bar() }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200365 fields = ('name', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200366
367
Armin Ronacher07bc6842008-03-31 14:18:49 +0200368class Test(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200369 """{{ foo is lower }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200370 fields = ('node', 'name', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200371
372
373class Call(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200374 """{{ foo(bar) }}"""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200375 fields = ('node', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200376
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200377 def as_const(self):
378 obj = self.node.as_const()
379 args = [x.as_const() for x in self.args]
380 kwargs = dict(x.as_const() for x in self.kwargs)
381 if self.dyn_args is not None:
382 try:
383 args.extend(self.dyn_args.as_const())
384 except:
385 raise Impossible()
386 if self.dyn_kwargs is not None:
387 try:
388 dyn_kwargs.update(self.dyn_kwargs.as_const())
389 except:
390 raise Impossible()
391 try:
392 return obj(*args, **kwargs)
393 except:
394 raise nodes.Impossible()
395
Armin Ronacher07bc6842008-03-31 14:18:49 +0200396
397class Subscript(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200398 """{{ foo.bar }} and {{ foo['bar'] }} etc."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200399 fields = ('node', 'arg', 'ctx')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200400
401 def as_const(self):
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200402 if self.ctx != 'load':
403 raise Impossible()
Armin Ronacher07bc6842008-03-31 14:18:49 +0200404 try:
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200405 return subscribe(self.node.as_const(), self.arg.as_const())
Armin Ronacher07bc6842008-03-31 14:18:49 +0200406 except:
407 raise Impossible()
408
409 def can_assign(self):
410 return True
411
412
413class Slice(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200414 """1:2:3 etc."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200415 fields = ('start', 'stop', 'step')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200416
Armin Ronacher4dfc9752008-04-09 15:03:29 +0200417 def as_const(self):
418 def const(obj):
419 if obj is None:
420 return obj
421 return obj.as_const()
422 return slice(const(self.start), const(self.stop), const(self.step))
423
Armin Ronacher07bc6842008-03-31 14:18:49 +0200424
425class Concat(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200426 """For {{ foo ~ bar }}. Concatenates strings."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200427 fields = ('nodes',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200428
429 def as_const(self):
430 return ''.join(unicode(x.as_const()) for x in self.nodes)
431
432
433class Compare(Expr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200434 """{{ foo == bar }}, {{ foo >= bar }} etc."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200435 fields = ('expr', 'ops')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200436
437
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200438class Operand(Helper):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200439 """Operator + expression."""
Armin Ronachere791c2a2008-04-07 18:39:54 +0200440 fields = ('op', 'expr')
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200441
442
Armin Ronacher07bc6842008-03-31 14:18:49 +0200443class Mul(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200444 """{{ foo * bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200445 operator = '*'
446
447
448class Div(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200449 """{{ foo / bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200450 operator = '/'
451
452
453class FloorDiv(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200454 """{{ foo // bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200455 operator = '//'
456
457
458class Add(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200459 """{{ foo + bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200460 operator = '+'
461
462
463class Sub(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200464 """{{ foo - bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200465 operator = '-'
466
467
468class Mod(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200469 """{{ foo % bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200470 operator = '%'
471
472
473class Pow(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200474 """{{ foo ** bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200475 operator = '**'
476
477
478class And(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200479 """{{ foo and bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200480 operator = 'and'
481
482 def as_const(self):
483 return self.left.as_const() and self.right.as_const()
484
485
486class Or(BinExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200487 """{{ foo or bar }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200488 operator = 'or'
489
490 def as_const(self):
491 return self.left.as_const() or self.right.as_const()
492
493
494class Not(UnaryExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200495 """{{ not foo }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200496 operator = 'not'
497
498
Armin Ronachere791c2a2008-04-07 18:39:54 +0200499class Neg(UnaryExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200500 """{{ -foo }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200501 operator = '-'
502
503
Armin Ronachere791c2a2008-04-07 18:39:54 +0200504class Pos(UnaryExpr):
Armin Ronacher8efc5222008-04-08 14:47:40 +0200505 """{{ +foo }}"""
Armin Ronacher07bc6842008-03-31 14:18:49 +0200506 operator = '+'