blob: 974b4edbce585fb41e942eb4405a257c5880f409 [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
37
Armin Ronacher82b3f3d2008-03-31 20:01:08 +020038def set_ctx(node, ctx):
39 """
40 Reset the context of a node and all child nodes. Per default the parser
41 will all generate nodes that have a 'load' context as it's the most common
42 one. This method is used in the parser to set assignment targets and
43 other nodes to a store context.
44 """
45 todo = deque([node])
46 while todo:
47 node = todo.popleft()
48 if 'ctx' in node._fields:
49 node.ctx = ctx
50 todo.extend(node.iter_child_nodes())
51
52
Armin Ronacher07bc6842008-03-31 14:18:49 +020053class Impossible(Exception):
54 """
55 Raised if the node could not perform a requested action.
56 """
57
58
59class NodeType(type):
60
61 def __new__(cls, name, bases, d):
62 for attr in '_fields', '_attributes':
63 storage = []
64 for base in bases:
65 storage.extend(getattr(base, attr, ()))
66 storage.extend(d.get(attr, ()))
67 assert len(storage) == len(set(storage))
68 d[attr] = tuple(storage)
69 return type.__new__(cls, name, bases, d)
70
71
72class Node(object):
73 """
74 Base jinja node.
75 """
76 __metaclass__ = NodeType
77 _fields = ()
78 _attributes = ('lineno',)
79
80 def __init__(self, *args, **kw):
81 if args:
82 if len(args) != len(self._fields):
83 if not self._fields:
84 raise TypeError('%r takes 0 arguments' %
85 self.__class__.__name__)
86 raise TypeError('%r takes 0 or %d argument%s' % (
87 self.__class__.__name__,
88 len(self._fields),
89 len(self._fields) != 1 and 's' or ''
90 ))
91 for name, arg in izip(self._fields, args):
92 setattr(self, name, arg)
93 for attr in self._attributes:
94 setattr(self, attr, kw.pop(attr, None))
95 if kw:
96 raise TypeError('unknown keyword argument %r' %
97 iter(kw).next())
98
99 def iter_fields(self):
100 for name in self._fields:
101 try:
102 yield name, getattr(self, name)
103 except AttributeError:
104 pass
105
106 def iter_child_nodes(self):
107 for field, item in self.iter_fields():
108 if isinstance(item, list):
109 for n in item:
110 if isinstance(n, Node):
111 yield n
112 elif isinstance(item, Node):
113 yield item
114
115 def __repr__(self):
116 return '%s(%s)' % (
117 self.__class__.__name__,
118 ', '.join('%s=%r' % (arg, getattr(self, arg, None)) for
119 arg in self._fields)
120 )
121
122
123class Stmt(Node):
124 """
125 Base node for all statements.
126 """
127
128
129class Helper(Node):
130 """
131 Nodes that exist in a specific context only.
132 """
133
134
135class Template(Node):
136 """
137 Node that represents a template.
138 """
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200139 _fields = ('body',)
Armin Ronacher07bc6842008-03-31 14:18:49 +0200140
141
142class Output(Stmt):
143 """
144 A node that holds multiple expressions which are then printed out. This
145 is used both for the `print` statement and the regular template data.
146 """
147 _fields = ('nodes',)
148
149
150class Extends(Stmt):
151 """
152 Represents an extends statement.
153 """
154 _fields = ('extends',)
155
156
157class For(Stmt):
158 """
159 A node that represents a for loop
160 """
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200161 _fields = ('target', 'iter', 'body', 'else_', 'recursive')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200162
163
164class If(Stmt):
165 """
166 A node that represents an if condition.
167 """
168 _fields = ('test', 'body', 'else_')
169
170
171class Macro(Stmt):
172 """
173 A node that represents a macro.
174 """
175 _fields = ('name', 'arguments', 'body')
176
177
178class CallBlock(Stmt):
179 """
180 A node that represents am extended macro call.
181 """
182 _fields = ('expr', 'body')
183
184
185class Set(Stmt):
186 """
187 Allows defining own variables.
188 """
189 _fields = ('name', 'expr')
190
191
192class FilterBlock(Stmt):
193 """
194 Node for filter sections.
195 """
196 _fields = ('body', 'filters')
197
198
199class Block(Stmt):
200 """
201 A node that represents a block.
202 """
203 _fields = ('name', 'body')
204
205
206class Include(Stmt):
207 """
208 A node that represents the include tag.
209 """
210 _fields = ('template',)
211
212
213class Trans(Stmt):
214 """
215 A node for translatable sections.
216 """
217 _fields = ('singular', 'plural', 'indicator', 'replacements')
218
219
220class ExprStmt(Stmt):
221 """
222 A statement that evaluates an expression to None.
223 """
224 _fields = ('node',)
225
226
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200227class Assign(Stmt):
228 """
229 Assigns an expression to a target.
230 """
231 _fields = ('target', 'node')
232
233
Armin Ronacher07bc6842008-03-31 14:18:49 +0200234class Expr(Node):
235 """
236 Baseclass for all expressions.
237 """
238
239 def as_const(self):
240 """
241 Return the value of the expression as constant or raise `Impossible`
242 if this was not possible.
243 """
244 raise Impossible()
245
246 def can_assign(self):
247 """
248 Check if it's possible to assign something to this node.
249 """
250 return False
251
252
253class BinExpr(Expr):
254 """
255 Baseclass for all binary expressions.
256 """
257 _fields = ('left', 'right')
258 operator = None
259
260 def as_const(self):
261 f = _binop_to_func[self.operator]
262 try:
263 return f(self.left.as_const(), self.right.as_const())
264 except:
265 print self.left, f, self.right
266 raise Impossible()
267
268
269class UnaryExpr(Expr):
270 """
271 Baseclass for all unary expressions.
272 """
273 _fields = ('node',)
274 operator = None
275
276 def as_const(self):
277 f = _uaop_to_func[self.operator]
278 try:
279 return f(self.node.as_const())
280 except:
281 raise Impossible()
282
283
284class Name(Expr):
285 """
286 any name such as {{ foo }}
287 """
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200288 _fields = ('name', 'ctx')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200289
290 def can_assign(self):
291 return True
292
293
294class Literal(Expr):
295 """
296 Baseclass for literals.
297 """
298
299
300class Const(Literal):
301 """
302 any constat such as {{ "foo" }}
303 """
304 _fields = ('value',)
305
306 def as_const(self):
307 return self.value
308
309
310class Tuple(Literal):
311 """
312 For loop unpacking and some other things like multiple arguments
313 for subscripts.
314 """
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200315 _fields = ('items', 'ctx')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200316
317 def as_const(self):
318 return tuple(x.as_const() for x in self.items)
319
320 def can_assign(self):
321 for item in self.items:
322 if not item.can_assign():
323 return False
324 return True
325
326
327class List(Literal):
328 """
329 any list literal such as {{ [1, 2, 3] }}
330 """
331 _fields = ('items',)
332
333 def as_const(self):
334 return [x.as_const() for x in self.items]
335
336
337class Dict(Literal):
338 """
339 any dict literal such as {{ {1: 2, 3: 4} }}
340 """
341 _fields = ('items',)
342
343 def as_const(self):
344 return dict(x.as_const() for x in self.items)
345
346
347class Pair(Helper):
348 """
349 A key, value pair for dicts.
350 """
351 _fields = ('key', 'value')
352
353 def as_const(self):
354 return self.key.as_const(), self.value.as_const()
355
356
357class CondExpr(Expr):
358 """
359 {{ foo if bar else baz }}
360 """
361 _fields = ('test', 'expr1', 'expr2')
362
363 def as_const(self):
364 if self.test.as_const():
365 return self.expr1.as_const()
366 return self.expr2.as_const()
367
368
369class Filter(Expr):
370 """
371 {{ foo|bar|baz }}
372 """
373 _fields = ('node', 'filters')
374
375
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200376class FilterCall(Expr):
377 """
378 {{ |bar() }}
379 """
380 _fields = ('name', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
381
382
Armin Ronacher07bc6842008-03-31 14:18:49 +0200383class Test(Expr):
384 """
385 {{ foo is lower }}
386 """
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200387 _fields = ('name', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200388
389
390class Call(Expr):
391 """
392 {{ foo(bar) }}
393 """
394 _fields = ('node', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
395
396
397class Subscript(Expr):
398 """
399 {{ foo.bar }} and {{ foo['bar'] }} etc.
400 """
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200401 _fields = ('node', 'arg', 'ctx')
Armin Ronacher07bc6842008-03-31 14:18:49 +0200402
403 def as_const(self):
404 try:
405 return self.node.as_const()[self.node.as_const()]
406 except:
407 raise Impossible()
408
409 def can_assign(self):
410 return True
411
412
413class Slice(Expr):
414 """
415 1:2:3 etc.
416 """
417 _fields = ('start', 'stop', 'step')
418
419
420class Concat(Expr):
421 """
422 For {{ foo ~ bar }}. Concatenates strings.
423 """
424 _fields = ('nodes',)
425
426 def as_const(self):
427 return ''.join(unicode(x.as_const()) for x in self.nodes)
428
429
430class Compare(Expr):
431 """
432 {{ foo == bar }}, {{ foo >= bar }} etc.
433 """
434 _fields = ('expr', 'ops')
435
436
Armin Ronacher82b3f3d2008-03-31 20:01:08 +0200437class Operand(Helper):
438 """
439 Operator + expression.
440 """
441 _fields = ('op', 'expr')
442
443
Armin Ronacher07bc6842008-03-31 14:18:49 +0200444class Mul(BinExpr):
445 """
446 {{ foo * bar }}
447 """
448 operator = '*'
449
450
451class Div(BinExpr):
452 """
453 {{ foo / bar }}
454 """
455 operator = '/'
456
457
458class FloorDiv(BinExpr):
459 """
460 {{ foo // bar }}
461 """
462 operator = '//'
463
464
465class Add(BinExpr):
466 """
467 {{ foo + bar }}
468 """
469 operator = '+'
470
471
472class Sub(BinExpr):
473 """
474 {{ foo - bar }}
475 """
476 operator = '-'
477
478
479class Mod(BinExpr):
480 """
481 {{ foo % bar }}
482 """
483 operator = '%'
484
485
486class Pow(BinExpr):
487 """
488 {{ foo ** bar }}
489 """
490 operator = '**'
491
492
493class And(BinExpr):
494 """
495 {{ foo and bar }}
496 """
497 operator = 'and'
498
499 def as_const(self):
500 return self.left.as_const() and self.right.as_const()
501
502
503class Or(BinExpr):
504 """
505 {{ foo or bar }}
506 """
507 operator = 'or'
508
509 def as_const(self):
510 return self.left.as_const() or self.right.as_const()
511
512
513class Not(UnaryExpr):
514 """
515 {{ not foo }}
516 """
517 operator = 'not'
518
519
520class NegExpr(UnaryExpr):
521 """
522 {{ -foo }}
523 """
524 operator = '-'
525
526
527class PosExpr(UnaryExpr):
528 """
529 {{ +foo }}
530 """
531 operator = '+'