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