• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# -*- coding: utf-8 -*-
2"""
3    jinja2.optimizer
4    ~~~~~~~~~~~~~~~~
5
6    The jinja optimizer is currently trying to constant fold a few expressions
7    and modify the AST in place so that it should be easier to evaluate it.
8
9    Because the AST does not contain all the scoping information and the
10    compiler has to find that out, we cannot do all the optimizations we
11    want.  For example loop unrolling doesn't work because unrolled loops would
12    have a different scoping.
13
14    The solution would be a second syntax tree that has the scoping rules stored.
15
16    :copyright: (c) 2010 by the Jinja Team.
17    :license: BSD.
18"""
19from jinja2 import nodes
20from jinja2.visitor import NodeTransformer
21
22
23def optimize(node, environment):
24    """The context hint can be used to perform an static optimization
25    based on the context given."""
26    optimizer = Optimizer(environment)
27    return optimizer.visit(node)
28
29
30class Optimizer(NodeTransformer):
31
32    def __init__(self, environment):
33        self.environment = environment
34
35    def visit_If(self, node):
36        """Eliminate dead code."""
37        # do not optimize ifs that have a block inside so that it doesn't
38        # break super().
39        if node.find(nodes.Block) is not None:
40            return self.generic_visit(node)
41        try:
42            val = self.visit(node.test).as_const()
43        except nodes.Impossible:
44            return self.generic_visit(node)
45        if val:
46            body = node.body
47        else:
48            body = node.else_
49        result = []
50        for node in body:
51            result.extend(self.visit_list(node))
52        return result
53
54    def fold(self, node):
55        """Do constant folding."""
56        node = self.generic_visit(node)
57        try:
58            return nodes.Const.from_untrusted(node.as_const(),
59                                              lineno=node.lineno,
60                                              environment=self.environment)
61        except nodes.Impossible:
62            return node
63
64    visit_Add = visit_Sub = visit_Mul = visit_Div = visit_FloorDiv = \
65    visit_Pow = visit_Mod = visit_And = visit_Or = visit_Pos = visit_Neg = \
66    visit_Not = visit_Compare = visit_Getitem = visit_Getattr = visit_Call = \
67    visit_Filter = visit_Test = visit_CondExpr = fold
68    del fold
69