blob: 5b95c99a4027db427ec40df499a0ac0395c73993 [file] [log] [blame]
Christoph Hack9d99e472008-04-08 20:21:11 +02001# -*- coding: utf-8 -*-
2"""
3 jinja2.optimizer
4 ~~~~~~~~~~~~~~~~
5
Armin Ronacher07a21ba2008-04-23 22:28:42 +02006 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 Hack9d99e472008-04-08 20:21:11 +02008
Armin Ronacher07a21ba2008-04-23 22:28:42 +02009 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 Hack9d99e472008-04-08 20:21:11 +020013
Armin Ronacher07a21ba2008-04-23 22:28:42 +020014 The solution would be a second syntax tree that has the scoping rules stored.
Christoph Hack9d99e472008-04-08 20:21:11 +020015
Armin Ronacher2e9396b2008-04-16 14:21:57 +020016 :copyright: Copyright 2008 by Christoph Hack, Armin Ronacher.
Christoph Hack9d99e472008-04-08 20:21:11 +020017 :license: GNU GPL.
18"""
Christoph Hack9d99e472008-04-08 20:21:11 +020019from jinja2 import nodes
Armin Ronacher981cbf62008-05-13 09:12:27 +020020from jinja2.visitor import NodeTransformer
Christoph Hack9d99e472008-04-08 20:21:11 +020021
22
Armin Ronacher981cbf62008-05-13 09:12:27 +020023def optimize(node, environment):
Armin Ronacherbcb7c532008-04-11 16:30:34 +020024 """The context hint can be used to perform an static optimization
25 based on the context given."""
26 optimizer = Optimizer(environment)
Armin Ronacher981cbf62008-05-13 09:12:27 +020027 return optimizer.visit(node)
Armin Ronacher81b88172008-04-09 00:40:05 +020028
29
Christoph Hackb40b8802008-04-08 23:01:58 +020030class Optimizer(NodeTransformer):
Christoph Hack9d99e472008-04-08 20:21:11 +020031
Armin Ronacher81b88172008-04-09 00:40:05 +020032 def __init__(self, environment):
Christoph Hack9d99e472008-04-08 20:21:11 +020033 self.environment = environment
Christoph Hack9d99e472008-04-08 20:21:11 +020034
Armin Ronacher981cbf62008-05-13 09:12:27 +020035 def visit_If(self, node):
36 """Eliminate dead code."""
Armin Ronacherc9705c22008-04-27 21:28:03 +020037 try:
Armin Ronacher981cbf62008-05-13 09:12:27 +020038 val = self.visit(node.test).as_const()
Armin Ronacher81b88172008-04-09 00:40:05 +020039 except nodes.Impossible:
Armin Ronacher981cbf62008-05-13 09:12:27 +020040 return self.generic_visit(node)
Armin Ronacher81b88172008-04-09 00:40:05 +020041 if val:
Armin Ronacherc9705c22008-04-27 21:28:03 +020042 body = node.body
43 else:
44 body = node.else_
45 result = []
46 for node in body:
Armin Ronacher981cbf62008-05-13 09:12:27 +020047 result.extend(self.visit_list(node))
Armin Ronacherc9705c22008-04-27 21:28:03 +020048 return result
Armin Ronacher81b88172008-04-09 00:40:05 +020049
Armin Ronacher981cbf62008-05-13 09:12:27 +020050 def fold(self, node):
Armin Ronacher180a1bd2008-04-09 12:14:24 +020051 """Do constant folding."""
Armin Ronacher981cbf62008-05-13 09:12:27 +020052 node = self.generic_visit(node)
Armin Ronacher180a1bd2008-04-09 12:14:24 +020053 try:
Armin Ronacher4dfc9752008-04-09 15:03:29 +020054 return nodes.Const.from_untrusted(node.as_const(),
Armin Ronacherd55ab532008-04-09 16:13:39 +020055 lineno=node.lineno,
56 environment=self.environment)
Armin Ronacher180a1bd2008-04-09 12:14:24 +020057 except nodes.Impossible:
58 return node
Armin Ronacherfed44b52008-04-13 19:42:53 +020059
Armin Ronacher180a1bd2008-04-09 12:14:24 +020060 visit_Add = visit_Sub = visit_Mul = visit_Div = visit_FloorDiv = \
61 visit_Pow = visit_Mod = visit_And = visit_Or = visit_Pos = visit_Neg = \
Armin Ronacherd55ab532008-04-09 16:13:39 +020062 visit_Not = visit_Compare = visit_Subscript = visit_Call = \
Armin Ronacherfed44b52008-04-13 19:42:53 +020063 visit_Filter = visit_Test = visit_CondExpr = fold
Armin Ronacher4dfc9752008-04-09 15:03:29 +020064 del fold