From: Christoph Hack Date: Tue, 8 Apr 2008 18:21:11 +0000 (+0200) Subject: added optimizer X-Git-Tag: 2.0rc1~206 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=9d99e47c0cf4b9e6589083e2021949fd304c1b07;p=jinja2.git added optimizer --HG-- branch : trunk --- 9d99e47c0cf4b9e6589083e2021949fd304c1b07 diff --cc jinja2/compiler.py index c26c1b2,bdf195f..f173685 --- a/jinja2/compiler.py +++ b/jinja2/compiler.py @@@ -564,22 -551,10 +566,13 @@@ class CodeGenerator(NodeVisitor) self.visit(node.step, frame) def visit_Filter(self, node, frame): - value = node.node - flen = len(node.filters) - if isinstance(value, nodes.Const): - # try to optimize filters on constant values - for filter in reversed(node.filters): - value = nodes.Const(self.environment.filters \ - .get(filter.name)(self.environment, value.value)) - print value - flen -= 1 - for filter in node.filters[:flen]: + for filter in node.filters: - self.write('context.filters[%r](' % filter.name) + if filter.name in frame.identifiers.declared_filter: + self.write('f_%s(' % filter.name) + else: + self.write('context.filter[%r](' % filter.name) - self.visit(value, frame) - for filter in reversed(node.filters[:flen]): + self.visit(node.node, frame) + for filter in reversed(node.filters): self.signature(filter, frame) self.write(')') diff --cc jinja2/optimizer.py index 0000000,0000000..8793a88 new file mode 100644 --- /dev/null +++ b/jinja2/optimizer.py @@@ -1,0 -1,0 +1,62 @@@ ++# -*- 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 the 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 copy ++from random import randrange ++from operator import xor ++from cStringIO import StringIO ++from jinja2 import nodes ++from jinja2.visitor import NodeVisitor, NodeTransformer ++from jinja2.exceptions import TemplateAssertionError ++ ++ ++class Optimizer(NodeVisitor): ++ ++ def __init__(self, environment, context={}): ++ self.environment = environment ++ self.context = context ++ ++ def visit_Output(self, node): ++ node.nodes = [self.visit(n) for n in node.nodes] ++ return node ++ ++ def visit_Filter(self, node): ++ """Try to evaluate filters if possible.""" ++ value = self.visit(node.node) ++ if isinstance(value, nodes.Const): ++ x = value.value ++ 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) ++ return node ++ ++ def generic_visit(self, node, *args, **kwargs): ++ NodeVisitor.generic_visit(self, node, *args, **kwargs) ++ return node ++ ++ ++def optimize(ast, env, clone=True): ++ optimizer = Optimizer(env) ++ if clone: ++ ast = copy(ast) ++ return optimizer.visit(ast) diff --cc test_optimizer.py index 0000000,0000000..d632777 new file mode 100644 --- /dev/null +++ b/test_optimizer.py @@@ -1,0 -1,0 +1,18 @@@ ++from jinja2 import Environment ++from jinja2.compiler import generate ++from jinja2.optimizer import optimize ++ ++ ++env = Environment() ++ast = env.parse(""" ++ Hi {{ ""|e }}, ++ how are you? ++""") ++print ast ++print ++print generate(ast, env, "foo.html") ++print ++ast = optimize(ast, env) ++print ast ++print ++print generate(ast, env, "foo.html")