# 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.
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):
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()
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',
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:
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
"""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
: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 %}'''
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 %}'''
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
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'
def test_noniter(env):
tmpl = env.from_string(NONITER)
- assert not tmpl.render()
+ raises(TypeError, tmpl.render)