from ParseTreeTransforms import InterpretCompilerDirectives, TransformBuiltinMethods
from ParseTreeTransforms import AlignFunctionDefinitions
from AutoDocTransforms import EmbedSignature
- from Optimize import FlattenInListTransform, SwitchTransform, DictIterTransform
+ from Optimize import FlattenInListTransform, SwitchTransform, IterationTransform
from Optimize import FlattenBuiltinTypeCreation, ConstantFolding, FinalOptimizePhase
from Buffer import IntroduceBufferAuxiliaryVars
from ModuleNode import check_c_declarations
AnalyseExpressionsTransform(self),
FlattenBuiltinTypeCreation(),
ConstantFolding(),
- DictIterTransform(),
+ IterationTransform(),
SwitchTransform(),
FinalOptimizePhase(self),
# ClearResultCodes(self),
def analyse_expressions(self, env):
import ExprNodes
self.target.analyse_target_types(env)
- if Options.convert_range and self.target.type.is_int:
+ if False: # Options.convert_range and self.target.type.is_int:
sequence = self.iterator.sequence
if isinstance(sequence, ExprNodes.SimpleCallNode) \
and sequence.self is None \
# loopvar_name string
# py_loopvar_node PyTempNode or None
child_attrs = ["target", "bound1", "bound2", "step", "body", "else_clause"]
-
+
+ is_py_target = False
+ loopvar_name = None
+ py_loopvar_node = None
+
def analyse_declarations(self, env):
self.target.analyse_target_declaration(env)
self.body.analyse_declarations(env)
self.bound2.release_temp(env)
if self.step is not None:
self.step.release_temp(env)
+
+ def reanalyse_c_loop(self, env):
+ # only make sure all subnodes have an integer type
+ self.bound1 = self.bound1.coerce_to_integer(env)
+ self.bound2 = self.bound2.coerce_to_integer(env)
+ if self.step is not None:
+ self.step = self.step.coerce_to_integer(env)
def generate_execution_code(self, code):
old_loop_labels = code.new_loop_labels()
import UtilNodes
import TypeSlots
import Symtab
+import Options
from StringEncoding import EncodedString
from ParseTreeTransforms import SkipDeclarations
return False
-class DictIterTransform(Visitor.VisitorTransform):
- """Transform a for-in-dict loop into a while loop calling PyDict_Next().
+class IterationTransform(Visitor.VisitorTransform):
+ """Transform some common for-in loop patterns into efficient C loops:
+
+ - for-in-dict loop becomes a while loop calling PyDict_Next()
+ - for-in-range loop becomes a plain C for loop
"""
PyDict_Next_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_bint_type, [
self.visitchildren(node)
return node
+ def visit_ModuleNode(self, node):
+ self.current_scope = node.scope
+ self.visitchildren(node)
+ return node
+
+ def visit_DefNode(self, node):
+ oldscope = self.current_scope
+ self.current_scope = node.entry.scope
+ self.visitchildren(node)
+ self.current_scope = oldscope
+ return node
+
def visit_ForInStatNode(self, node):
self.visitchildren(node)
iterator = node.iterator.sequence
return node
function = iterator.function
+ # dict iteration?
if isinstance(function, ExprNodes.AttributeNode) and \
function.obj.type == Builtin.dict_type:
dict_obj = function.obj
return node
return self._transform_dict_iteration(
node, dict_obj, keys, values)
+
+ # range() iteration?
+ if Options.convert_range and node.target.type.is_int:
+ if iterator.self is None and \
+ isinstance(function, ExprNodes.NameNode) and \
+ function.entry.is_builtin and \
+ function.name in ('range', 'xrange'):
+ return self._transform_range_iteration(
+ node, iterator)
+
return node
+ def _transform_range_iteration(self, node, range_function):
+ args = range_function.arg_tuple.args
+ if len(args) < 3:
+ step_pos = range_function.pos
+ step_value = 1
+ step = ExprNodes.IntNode(step_pos, value=1)
+ else:
+ step = args[2]
+ step_pos = step.pos
+ if step.constant_result is ExprNodes.not_a_constant:
+ # cannot determine step direction
+ return node
+ try:
+ # FIXME: check how Python handles rounding here, e.g. from float
+ step_value = int(step.constant_result)
+ except:
+ return node
+ if not isinstance(step, ExprNodes.IntNode):
+ step = ExprNodes.IntNode(step_pos, value=step_value)
+
+ if step_value > 0:
+ relation1 = '<='
+ relation2 = '<'
+ elif step_value < 0:
+ step.value = -step_value
+ relation1 = '>='
+ relation2 = '>'
+ else:
+ return node
+
+ if len(args) == 1:
+ bound1 = ExprNodes.IntNode(range_function.pos, value=0)
+ bound2 = args[0]
+ else:
+ bound1 = args[0]
+ bound2 = args[1]
+
+ for_node = Nodes.ForFromStatNode(
+ node.pos,
+ target=node.target,
+ bound1=bound1, relation1=relation1,
+ relation2=relation2, bound2=bound2,
+ step=step, body=node.body,
+ else_clause=node.else_clause,
+ loopvar_name = node.target.entry.cname)
+ for_node.reanalyse_c_loop(self.current_scope)
+# for_node.analyse_expressions(self.current_scope)
+ return for_node
+
def _transform_dict_iteration(self, node, dict_obj, keys, values):
py_object_ptr = PyrexTypes.c_void_ptr_type