Christoph Hack | 9d99e47 | 2008-04-08 20:21:11 +0200 | [diff] [blame] | 1 | # -*- coding: utf-8 -*- |
| 2 | """ |
| 3 | jinja2.optimizer |
| 4 | ~~~~~~~~~~~~~~~~ |
| 5 | |
Armin Ronacher | 07a21ba | 2008-04-23 22:28:42 +0200 | [diff] [blame] | 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. |
Christoph Hack | 9d99e47 | 2008-04-08 20:21:11 +0200 | [diff] [blame] | 8 | |
Armin Ronacher | 07a21ba | 2008-04-23 22:28:42 +0200 | [diff] [blame] | 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. |
Christoph Hack | 9d99e47 | 2008-04-08 20:21:11 +0200 | [diff] [blame] | 13 | |
Armin Ronacher | 07a21ba | 2008-04-23 22:28:42 +0200 | [diff] [blame] | 14 | The solution would be a second syntax tree that has the scoping rules stored. |
Christoph Hack | 9d99e47 | 2008-04-08 20:21:11 +0200 | [diff] [blame] | 15 | |
Armin Ronacher | 2e9396b | 2008-04-16 14:21:57 +0200 | [diff] [blame] | 16 | :copyright: Copyright 2008 by Christoph Hack, Armin Ronacher. |
Christoph Hack | 9d99e47 | 2008-04-08 20:21:11 +0200 | [diff] [blame] | 17 | :license: GNU GPL. |
| 18 | """ |
Christoph Hack | 9d99e47 | 2008-04-08 20:21:11 +0200 | [diff] [blame] | 19 | from jinja2 import nodes |
Armin Ronacher | 981cbf6 | 2008-05-13 09:12:27 +0200 | [diff] [blame^] | 20 | from jinja2.visitor import NodeTransformer |
Christoph Hack | 9d99e47 | 2008-04-08 20:21:11 +0200 | [diff] [blame] | 21 | |
| 22 | |
Armin Ronacher | 981cbf6 | 2008-05-13 09:12:27 +0200 | [diff] [blame^] | 23 | def optimize(node, environment): |
Armin Ronacher | bcb7c53 | 2008-04-11 16:30:34 +0200 | [diff] [blame] | 24 | """The context hint can be used to perform an static optimization |
| 25 | based on the context given.""" |
| 26 | optimizer = Optimizer(environment) |
Armin Ronacher | 981cbf6 | 2008-05-13 09:12:27 +0200 | [diff] [blame^] | 27 | return optimizer.visit(node) |
Armin Ronacher | 81b8817 | 2008-04-09 00:40:05 +0200 | [diff] [blame] | 28 | |
| 29 | |
Christoph Hack | b40b880 | 2008-04-08 23:01:58 +0200 | [diff] [blame] | 30 | class Optimizer(NodeTransformer): |
Christoph Hack | 9d99e47 | 2008-04-08 20:21:11 +0200 | [diff] [blame] | 31 | |
Armin Ronacher | 81b8817 | 2008-04-09 00:40:05 +0200 | [diff] [blame] | 32 | def __init__(self, environment): |
Christoph Hack | 9d99e47 | 2008-04-08 20:21:11 +0200 | [diff] [blame] | 33 | self.environment = environment |
Christoph Hack | 9d99e47 | 2008-04-08 20:21:11 +0200 | [diff] [blame] | 34 | |
Armin Ronacher | 981cbf6 | 2008-05-13 09:12:27 +0200 | [diff] [blame^] | 35 | def visit_If(self, node): |
| 36 | """Eliminate dead code.""" |
Armin Ronacher | c9705c2 | 2008-04-27 21:28:03 +0200 | [diff] [blame] | 37 | try: |
Armin Ronacher | 981cbf6 | 2008-05-13 09:12:27 +0200 | [diff] [blame^] | 38 | val = self.visit(node.test).as_const() |
Armin Ronacher | 81b8817 | 2008-04-09 00:40:05 +0200 | [diff] [blame] | 39 | except nodes.Impossible: |
Armin Ronacher | 981cbf6 | 2008-05-13 09:12:27 +0200 | [diff] [blame^] | 40 | return self.generic_visit(node) |
Armin Ronacher | 81b8817 | 2008-04-09 00:40:05 +0200 | [diff] [blame] | 41 | if val: |
Armin Ronacher | c9705c2 | 2008-04-27 21:28:03 +0200 | [diff] [blame] | 42 | body = node.body |
| 43 | else: |
| 44 | body = node.else_ |
| 45 | result = [] |
| 46 | for node in body: |
Armin Ronacher | 981cbf6 | 2008-05-13 09:12:27 +0200 | [diff] [blame^] | 47 | result.extend(self.visit_list(node)) |
Armin Ronacher | c9705c2 | 2008-04-27 21:28:03 +0200 | [diff] [blame] | 48 | return result |
Armin Ronacher | 81b8817 | 2008-04-09 00:40:05 +0200 | [diff] [blame] | 49 | |
Armin Ronacher | 981cbf6 | 2008-05-13 09:12:27 +0200 | [diff] [blame^] | 50 | def fold(self, node): |
Armin Ronacher | 180a1bd | 2008-04-09 12:14:24 +0200 | [diff] [blame] | 51 | """Do constant folding.""" |
Armin Ronacher | 981cbf6 | 2008-05-13 09:12:27 +0200 | [diff] [blame^] | 52 | node = self.generic_visit(node) |
Armin Ronacher | 180a1bd | 2008-04-09 12:14:24 +0200 | [diff] [blame] | 53 | try: |
Armin Ronacher | 4dfc975 | 2008-04-09 15:03:29 +0200 | [diff] [blame] | 54 | return nodes.Const.from_untrusted(node.as_const(), |
Armin Ronacher | d55ab53 | 2008-04-09 16:13:39 +0200 | [diff] [blame] | 55 | lineno=node.lineno, |
| 56 | environment=self.environment) |
Armin Ronacher | 180a1bd | 2008-04-09 12:14:24 +0200 | [diff] [blame] | 57 | except nodes.Impossible: |
| 58 | return node |
Armin Ronacher | fed44b5 | 2008-04-13 19:42:53 +0200 | [diff] [blame] | 59 | |
Armin Ronacher | 180a1bd | 2008-04-09 12:14:24 +0200 | [diff] [blame] | 60 | visit_Add = visit_Sub = visit_Mul = visit_Div = visit_FloorDiv = \ |
| 61 | visit_Pow = visit_Mod = visit_And = visit_Or = visit_Pos = visit_Neg = \ |
Armin Ronacher | d55ab53 | 2008-04-09 16:13:39 +0200 | [diff] [blame] | 62 | visit_Not = visit_Compare = visit_Subscript = visit_Call = \ |
Armin Ronacher | fed44b5 | 2008-04-13 19:42:53 +0200 | [diff] [blame] | 63 | visit_Filter = visit_Test = visit_CondExpr = fold |
Armin Ronacher | 4dfc975 | 2008-04-09 15:03:29 +0200 | [diff] [blame] | 64 | del fold |