loops and `tests` tests pass now
--HG--
branch : trunk
diff --git a/jinja2/compiler.py b/jinja2/compiler.py
index b7aae46..871728f 100644
--- a/jinja2/compiler.py
+++ b/jinja2/compiler.py
@@ -76,6 +76,9 @@
# frames or because they are special for the frame)
self.declared = set()
+ # undeclared variables from outer scopes
+ self.outer_undeclared = set()
+
# names that are accessed without being explicitly declared by
# this one or any of the outer scopes. Names can appear both in
# declared and undeclared.
@@ -106,7 +109,8 @@
def find_shadowed(self):
"""Find all the shadowed names."""
- return self.declared & (self.declared_locally | self.declared_parameter)
+ return (self.declared | self.outer_undeclared) & \
+ (self.declared_locally | self.declared_parameter)
class Frame(object):
@@ -145,6 +149,10 @@
parent.identifiers.declared_locally |
parent.identifiers.declared_parameter
)
+ self.identifiers.outer_undeclared.update(
+ parent.identifiers.undeclared -
+ self.identifiers.declared
+ )
self.buffer = parent.buffer
self.name_overrides = parent.name_overrides.copy()
diff --git a/jinja2/parser.py b/jinja2/parser.py
index 84a317c..8b82a4d 100644
--- a/jinja2/parser.py
+++ b/jinja2/parser.py
@@ -626,6 +626,8 @@
else:
negated = False
name = self.stream.expect('name').value
+ dyn_args = dyn_kwargs = None
+ kwargs = []
if self.stream.current.type is 'lparen':
args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
elif self.stream.current.type in ('name', 'string', 'integer',
@@ -634,8 +636,6 @@
args = [self.parse_expression()]
else:
args = []
- kwargs = []
- dyn_args = dyn_kwargs = None
node = nodes.Test(node, name, args, kwargs, dyn_args,
dyn_kwargs, lineno=token.lineno)
if negated:
diff --git a/jinja2/runtime.py b/jinja2/runtime.py
index 1f1d7bd..e1bf486 100644
--- a/jinja2/runtime.py
+++ b/jinja2/runtime.py
@@ -142,8 +142,8 @@
first = property(lambda x: x.index0 == 0)
last = property(lambda x: x.revindex0 == 0)
index = property(lambda x: x.index0 + 1)
- revindex = property(lambda x: x.length)
- revindex0 = property(lambda x: x.length - 1)
+ revindex = property(lambda x: x.length - x.index0)
+ revindex0 = property(lambda x: x.length - x.index)
def __len__(self):
return self.length
@@ -191,7 +191,8 @@
"""The static loop context is used in the optimizer to "freeze" the
status of an iteration. The only reason for this object is if the
loop object is accessed in a non static way (eg: becomes part of a
- function call)."""
+ function call).
+ """
def __init__(self, index0, length):
self.index0 = index0
diff --git a/tests/test_forloop.py b/tests/test_forloop.py
index ed1cc2e..dd25494 100644
--- a/tests/test_forloop.py
+++ b/tests/test_forloop.py
@@ -6,6 +6,8 @@
:copyright: 2007 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
+from py.test import raises
+
SIMPLE = '''{% for item in seq %}{{ item }}{% endfor %}'''
ELSE = '''{% for item in seq %}XXX{% else %}...{% endfor %}'''
@@ -13,9 +15,9 @@
CONTEXTVARS = '''{% for item in seq %}\
{{ loop.index }}|{{ loop.index0 }}|{{ loop.revindex }}|{{
loop.revindex0 }}|{{ loop.first }}|{{ loop.last }}|{{
- loop.even }}|{{ loop.odd }}|{{ loop.length }}###{% endfor %}'''
-CYCLING = '''{% for item in seq %}{% cycle '<1>', '<2>' %}{% endfor %}\
-{% for item in seq %}{% cycle through %}{% endfor %}'''
+ loop.length }}###{% endfor %}'''
+CYCLING = '''{% for item in seq %}{{ loop.cycle('<1>', '<2>') }}{% endfor %}\
+{% for item in seq %}{{ loop.cycle(*through) }}{% endfor %}'''
SCOPE = '''{% for item in seq %}{% endfor %}{{ item }}'''
VARLEN = '''{% for item in iter %}{{ item }}{% endfor %}'''
NONITER = '''{% for item in none %}...{% endfor %}'''
@@ -40,9 +42,9 @@
tmpl = env.from_string(CONTEXTVARS)
one, two, _ = tmpl.render(seq=[0, 1]).split('###')
(one_index, one_index0, one_revindex, one_revindex0, one_first,
- one_last, one_even, one_odd, one_length) = one.split('|')
+ one_last, one_length) = one.split('|')
(two_index, two_index0, two_revindex, two_revindex0, two_first,
- two_last, two_even, two_odd, two_length) = two.split('|')
+ two_last, two_length) = two.split('|')
assert int(one_index) == 1 and int(two_index) == 2
assert int(one_index0) == 0 and int(two_index0) == 1
@@ -50,8 +52,6 @@
assert int(one_revindex0) == 1 and int(two_revindex0) == 0
assert one_first == 'True' and two_first == 'False'
assert one_last == 'False' and two_last == 'True'
- assert one_even == 'False' and two_even == 'True'
- assert one_odd == 'True' and two_odd == 'False'
assert one_length == two_length == '2'
@@ -78,4 +78,4 @@
def test_noniter(env):
tmpl = env.from_string(NONITER)
- assert not tmpl.render()
+ raises(TypeError, tmpl.render)