blob: c9787f655ea376ac89a42ac15db1897461c776b7 [file] [log] [blame]
# -*- coding: utf-8 -*-
"""
jinja2.optimizer
~~~~~~~~~~~~~~~~
This module tries to optimize template trees by:
* eliminating constant nodes
* evaluating filters and macros on constant nodes
* unroll loops on constant values
* replace variables which are already known (because they doesn't
change often and you want to prerender a template) with constants
After the optimation you will get a new, simplier template which can
be saved again for later rendering. But even if you don't want to
prerender a template, this module might speed up your templates a bit
if you are using a lot of constants.
:copyright: Copyright 2008 by Christoph Hack.
:license: GNU GPL.
"""
from copy import deepcopy
from jinja2 import nodes
from jinja2.visitor import NodeVisitor, NodeTransformer
class Optimizer(NodeTransformer):
def __init__(self, environment, context={}):
self.environment = environment
self.context = context
def visit_Filter(self, node):
"""Try to evaluate filters if possible."""
try:
x = self.visit(node.node).as_const()
except nodes.Impossible:
return node
for filter in reversed(node.filters):
# XXX: call filters with arguments
x = self.environment.filters[filter.name](self.environment, x)
# XXX: don't optimize context dependent filters
return nodes.Const(x)
def visit_For(self, node):
"""Loop unrolling for constant values."""
try:
iter = self.visit(node.iter).as_const()
except nodes.Impossible:
return node
result = []
target = node.target.name
for item in iter:
# XXX: take care of variable scopes
self.context[target] = item
result.extend(self.visit(n) for n in deepcopy(node.body))
return result
def visit_Name(self, node):
# XXX: take care of variable scopes!
if node.name not in self.context:
return node
return nodes.Const(self.context[node.name])
def optimize(node, environment):
optimizer = Optimizer(environment)
return optimizer.visit(node)