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