merged
--HG--
branch : trunk
diff --git a/jinja2/compiler.py b/jinja2/compiler.py
index 5c64699..c26c1b2 100644
--- a/jinja2/compiler.py
+++ b/jinja2/compiler.py
@@ -29,9 +29,9 @@
}
-def generate(node, filename, stream=None):
+def generate(node, environment, filename, stream=None):
is_child = node.find(nodes.Extends) is not None
- generator = CodeGenerator(is_child, filename, stream)
+ generator = CodeGenerator(environment, is_child, filename, stream)
generator.visit(node)
if stream is None:
return generator.stream.getvalue()
@@ -56,6 +56,10 @@
# names that are declared by parameters
self.declared_parameter = set()
+ # filters that are declared locally
+ self.declared_filter = set()
+ self.undeclared_filter = dict()
+
def add_special(self, name):
"""Register a special name like `loop`."""
self.undeclared.discard(name)
@@ -123,6 +127,13 @@
if not self.identifiers.is_declared(node.name, self.hard_scope):
self.identifiers.undeclared.add(node.name)
+ def visit_FilterCall(self, node):
+ if not node.name in self.identifiers.declared_filter:
+ uf = self.identifiers.undeclared_filter.get(node.name, 0) + 1
+ if uf > 1:
+ self.identifiers.declared_filter.add(node.name)
+ self.identifiers.undeclared_filter[node.name] = uf
+
def visit_Macro(self, node):
"""Macros set local."""
self.identifiers.declared_locally.add(node.name)
@@ -134,9 +145,10 @@
class CodeGenerator(NodeVisitor):
- def __init__(self, is_child, filename, stream=None):
+ def __init__(self, environment, is_child, filename, stream=None):
if stream is None:
stream = StringIO()
+ self.environment = environment
self.is_child = is_child
self.filename = filename
self.stream = stream
@@ -211,6 +223,9 @@
self.indent()
for name in frame.identifiers.undeclared:
self.writeline('l_%s = context[%r]' % (name, name))
+ for name, count in frame.identifiers.undeclared_filter.iteritems():
+ if count > 1:
+ self.writeline('f_%s = context[%r]' % (name, name))
if not no_indent:
self.outdent()
@@ -549,10 +564,22 @@
self.visit(node.step, frame)
def visit_Filter(self, node, frame):
- for filter in node.filters:
- self.write('context.filters[%r](' % filter.name)
- self.visit(node.node, frame)
- for filter in reversed(node.filters):
+ 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]:
+ 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.signature(filter, frame)
self.write(')')
diff --git a/jinja2/defaults.py b/jinja2/defaults.py
index 37473ea..84c1b08 100644
--- a/jinja2/defaults.py
+++ b/jinja2/defaults.py
@@ -8,7 +8,7 @@
:copyright: 2007 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
-from jinja.filters import FILTERS as DEFAULT_FILTERS
+from jinja2.filters import FILTERS as DEFAULT_FILTERS
from jinja.tests import TESTS as DEFAULT_TESTS
DEFAULT_NAMESPACE = {}
diff --git a/jinja2/filters.py b/jinja2/filters.py
index 6098b6e..4518822 100644
--- a/jinja2/filters.py
+++ b/jinja2/filters.py
@@ -15,6 +15,7 @@
except ImportError:
itemgetter = lambda a: lambda b: b[a]
from urllib import urlencode, quote
+from jinja.utils import escape
_striptags_re = re.compile(r'(<!--.*?-->|<[^>]*>)')
@@ -94,18 +95,16 @@
Convert a value to uppercase.
"""
return s.upper()
-do_upper = stringfilter(do_upper)
-def do_lower(s):
+def do_lower(env, s):
"""
Convert a value to lowercase.
"""
return s.lower()
-do_lower = stringfilter(do_lower)
-def do_escape(attribute=False):
+def do_escape(env, s, attribute=False):
"""
XML escape ``&``, ``<``, and ``>`` in a string of data. If the
optional parameter is `true` this filter will also convert
@@ -114,20 +113,12 @@
This method will have no effect it the value is already escaped.
"""
- #: because filters are cached we can make a local alias to
- #: speed things up a bit
- e = escape
- def wrapped(env, context, s):
- if isinstance(s, TemplateData):
- return s
- elif hasattr(s, '__html__'):
- return s.__html__()
- #: small speedup, do not convert to unicode if we already
- #: have an unicode object.
- if s.__class__ is not unicode:
- s = env.to_unicode(s)
- return e(s, attribute)
- return wrapped
+ # XXX: Does this still exists?
+ #if isinstance(s, TemplateData):
+ # return s
+ if hasattr(s, '__html__'):
+ return s.__html__()
+ return escape(unicode(s), attribute)
def do_xmlattr(autospace=False):
diff --git a/test.py b/test.py
index 3aa44e1..67f19b6 100644
--- a/test.py
+++ b/test.py
@@ -14,4 +14,4 @@
""")
print ast
print
-print generate(ast, "foo.html")
+print generate(ast, env, "foo.html")