#
# iterator IteratorNode
- def __init__(self, iterator, lives_in_outer_scope=False):
+ def __init__(self, iterator):
AtomicExprNode.__init__(self, iterator.pos)
- self.lives_in_outer_scope = lives_in_outer_scope
self.iterator = iterator
def type_dependencies(self, env):
- if self.lives_in_outer_scope:
- env = Symtab.NonLocalScopeWrapper(env)
return self.iterator.type_dependencies(env)
- def infer_type(self, env, iterator_type=None):
- if self.lives_in_outer_scope:
- env = Symtab.NonLocalScopeWrapper(env)
+ def infer_type(self, env, iterator_type = None):
if iterator_type is None:
iterator_type = self.iterator.infer_type(env)
if iterator_type.is_ptr or iterator_type.is_array:
return iterator_type.base_type
elif iterator_type.is_cpp_class:
- item_type = env.lookup_operator_for_types(
- self.pos, "*", [iterator_type]).type.return_type
+ item_type = env.lookup_operator_for_types(self.pos, "*", [iterator_type]).type.return_type
if item_type.is_reference:
item_type = item_type.ref_base_type
if item_type.is_const:
return item_type
else:
# Avoid duplication of complicated logic.
- fake_index_node = IndexNode(
- self.pos,
- base=self.iterator.sequence,
- index=IntNode(self.pos, value='0'))
+ fake_index_node = IndexNode(self.pos,
+ base=self.iterator.sequence,
+ index=IntNode(self.pos, value='0'))
return fake_index_node.infer_type(env)
def analyse_types(self, env):
import ExprNodes
import Nodes
import Options
-import Symtab
from PyrexTypes import py_object_type, unspecified_type
import PyrexTypes
next_block = self.flow.newblock()
# Condition with iterator
self.flow.loops.append(LoopDescr(next_block, condition_block))
-
- is_normal_for_loop = isinstance(node, Nodes.ForInStatNode)
- if is_normal_for_loop and node.first_in_genexp:
- self.env_stack.append(self.env)
- self.env = Symtab.NonLocalScopeWrapper(self.env)
self._visit(node.iterator)
- if is_normal_for_loop and node.first_in_genexp:
- self.env = self.env_stack.pop()
-
# Target assignment
self.flow.nextblock()
- if is_normal_for_loop:
+
+ if isinstance(node, Nodes.ForInStatNode):
self.mark_forloop_target(node)
- else: # Parallel
+ else: # Parallel
self.mark_assignment(node.target)
# Body block
import TypeSlots
from PyrexTypes import py_object_type, error_type
from Symtab import ModuleScope, LocalScope, ClosureScope, \
- StructOrUnionScope, PyClassScope, CppClassScope, NonLocalScopeWrapper
+ StructOrUnionScope, PyClassScope, CppClassScope
from Code import UtilityCode
from StringEncoding import EncodedString, escape_byte_string, split_string_literal
import Options
target.generate_assignment_code(result, code)
var.release(code)
-
def ForStatNode(pos, **kw):
if 'iterator' in kw:
return ForInStatNode(pos, **kw)
else:
return ForFromStatNode(pos, **kw)
-
class ForInStatNode(LoopNode, StatNode):
# for statement
#
# body StatNode
# else_clause StatNode
# item NextNode used internally
- # first_in_genexp bool True for outer loop of a scoped genexp/comprehension
child_attrs = ["target", "iterator", "body", "else_clause"]
item = None
- first_in_genexp = False
def analyse_declarations(self, env):
import ExprNodes
self.body.analyse_declarations(env)
if self.else_clause:
self.else_clause.analyse_declarations(env)
- self.item = ExprNodes.NextNode(
- self.iterator, lives_in_outer_scope=self.first_in_genexp)
+ self.item = ExprNodes.NextNode(self.iterator)
def analyse_expressions(self, env):
self.target = self.target.analyse_target_types(env)
- iterator_env = env
- if self.first_in_genexp:
- # outermost iterator in a genexpr or scoped comprehension is
- # looked up in the outer scope
- iterator_env = NonLocalScopeWrapper(iterator_env)
- self.iterator = self.iterator.analyse_expressions(iterator_env)
- # rewrap in NextNode
- import ExprNodes
- self.item = ExprNodes.NextNode(
- self.iterator, lives_in_outer_scope=self.first_in_genexp)
+ self.iterator = self.iterator.analyse_expressions(env)
+ if self.item is None:
+ # Hack. Sometimes analyse_declarations not called.
+ import ExprNodes
+ self.item = ExprNodes.NextNode(self.iterator)
self.item = self.item.analyse_expressions(env)
- if ((self.iterator.type.is_ptr or self.iterator.type.is_array) and
- self.target.type.assignable_from(self.iterator.type)):
+ if (self.iterator.type.is_ptr or self.iterator.type.is_array) and \
+ self.target.type.assignable_from(self.iterator.type):
# C array slice optimization.
pass
else:
cdef p_string_literal(PyrexScanner s, kind_override=*)
cdef p_list_maker(PyrexScanner s)
cdef p_comp_iter(PyrexScanner s, body)
-cdef p_comp_for(PyrexScanner s, body, bint first_in_genexp)
+cdef p_comp_for(PyrexScanner s, body)
cdef p_comp_if(PyrexScanner s, body)
cdef p_dict_or_set_maker(PyrexScanner s)
cdef p_backquote_expr(PyrexScanner s)
return ExprNodes.ListNode(pos, args = [])
expr = p_test(s)
if s.sy == 'for':
- has_local_scope = s.context.language_level >= 3
append = ExprNodes.ComprehensionAppendNode(pos, expr=expr)
- loop = p_comp_for(s, append, first_in_genexp=has_local_scope)
+ loop = p_comp_for(s, append)
s.expect(']')
return ExprNodes.ComprehensionNode(
- pos, loop=loop, append=append, type=Builtin.list_type,
+ pos, loop=loop, append=append, type = Builtin.list_type,
# list comprehensions leak their loop variable in Py2
- has_local_scope=has_local_scope)
+ has_local_scope = s.context.language_level >= 3)
else:
if s.sy == ',':
s.next()
else:
exprs = [expr]
s.expect(']')
- return ExprNodes.ListNode(pos, args=exprs)
+ return ExprNodes.ListNode(pos, args = exprs)
def p_comp_iter(s, body):
if s.sy == 'for':
- return p_comp_for(s, body, first_in_genexp=False)
+ return p_comp_for(s, body)
elif s.sy == 'if':
return p_comp_if(s, body)
else:
# insert the 'append' operation into the loop
return body
-def p_comp_for(s, body, first_in_genexp):
+def p_comp_for(s, body):
# s.sy == 'for'
pos = s.position()
s.next()
kw = p_for_bounds(s, allow_testlist=False)
- kw.update(else_clause=None, body=p_comp_iter(s, body),
- first_in_genexp=first_in_genexp)
+ kw.update(else_clause = None, body = p_comp_iter(s, body))
return Nodes.ForStatNode(pos, **kw)
def p_comp_if(s, body):
# set comprehension
append = ExprNodes.ComprehensionAppendNode(
item.pos, expr=item)
- loop = p_comp_for(s, append, first_in_genexp=True)
+ loop = p_comp_for(s, append)
s.expect('}')
return ExprNodes.ComprehensionNode(
pos, loop=loop, append=append, type=Builtin.set_type)
# dict comprehension
append = ExprNodes.DictComprehensionAppendNode(
item.pos, key_expr=key, value_expr=value)
- loop = p_comp_for(s, append, first_in_genexp=True)
+ loop = p_comp_for(s, append)
s.expect('}')
return ExprNodes.ComprehensionNode(
pos, loop=loop, append=append, type=Builtin.dict_type)
def p_genexp(s, expr):
# s.sy == 'for'
- yield_node = Nodes.ExprStatNode(
- expr.pos, expr=ExprNodes.YieldExprNode(expr.pos, arg=expr))
- loop = p_comp_for(s, yield_node, first_in_genexp=True)
+ loop = p_comp_for(s, Nodes.ExprStatNode(
+ expr.pos, expr = ExprNodes.YieldExprNode(expr.pos, arg=expr)))
return ExprNodes.GeneratorExpressionNode(expr.pos, loop=loop)
expr_terminators = cython.declare(set, set([
entry.cname = "%s->%s" % (Naming.cur_scope_cname, entry.cname)
-class ForeignName(str):
- """
- String wrapper to store unnamed entries in Scope.entries dict.
- """
- def __hash__(self):
- return str.__hash__(self) + 1
-
- def __eq__(self, other):
- if self is other:
- return True
- return type(self) is type(other) and str.__eq__(self, other)
-
-
-class NonLocalScopeWrapper(object):
- """
- Wrapper around a local scope that inherits all names from the outer scope.
- Used in generator expressions to analyse the outermost iterable.
- """
- def __init__(self, scope):
- self._scope = scope
- self._lookup_outer = scope.outer_scope.lookup
-
- def lookup(self, name):
- foreign_name = ForeignName(name)
- entry = self._scope.entries.get(foreign_name)
- if entry is not None:
- return entry
- entry = self._lookup_outer(name)
- if entry and entry.scope.is_closure_scope:
- entry.in_closure = True
- inner_entry = InnerEntry(entry, self._scope)
- inner_entry.is_variable = True
- # do not overwrite locally declared names
- self._scope.entries[foreign_name] = inner_entry
- return inner_entry
- return entry
-
- def __getattr__(self, name):
- return getattr(self._scope, name)
-
-
class GeneratorExpressionScope(Scope):
"""Scope for generator expressions and comprehensions. As opposed
to generators, these can be easily inlined in some cases, so all
cfunc_call_tuple_args_T408
cpp_structs
closure_inside_cdef_T554
+genexpr_iterable_lookup_T600
generator_expressions_in_class
for_from_pyvar_loop_T601
temp_sideeffects_T654 # not really a bug, Cython warns about it