def make_while_from_for(for_node): "Create a While from a For. The 'test' (loop condition) must still be set." while_node = nodes.While(test=None, body=for_node.body, orelse=for_node.orelse) copy_basic_blocks(for_node, while_node) while_node = nodes.build_while(**vars(while_node)) return while_node
def visit_While(self, node): node.cond_block = self.flow.nextblock(label='while_condition', pos=node.test) node.exit_block = self.flow.exit_block(label='exit_while', pos=node) # Condition block self.flow.loops.append(LoopDescr(node.exit_block, node.cond_block)) node.test = self.visit(node.test) self._visit_loop_body(node) return nodes.build_while(**vars(node))
def rewrite_range_iteration(self, node): """ Handle range iteration: for i in range(start, stop, step): ... becomes nsteps = compute_nsteps(start, stop, step) temp = 0 while temp < nsteps: target = start + temp * step ... temp += 1 """ self.generic_visit(node) temp = nodes.TempNode(node.target.type, 'target_temp') nsteps = nodes.TempNode(Py_ssize_t, 'nsteps') start, stop, step = unpack_range_args(node.iter) if isinstance(step, nodes.ConstNode): have_step = step.pyval != 1 else: have_step = True start, stop, step = [ nodes.CloneableNode(n) for n in (start, stop, step) ] if have_step: compute_nsteps = """ $length = {{stop}} - {{start}} {{nsteps}} = $length / {{step}} if {{nsteps_load}} * {{step}} != $length: #$length % {{step}}: # Test for truncation {{nsteps}} = {{nsteps_load}} + 1 # print "nsteps", {{nsteps_load}} """ else: compute_nsteps = "{{nsteps}} = {{stop}} - {{start}}" if node.orelse: else_clause = "else: {{else_body}}" else: else_clause = "" templ = textwrap.dedent(""" %s {{temp}} = 0 while {{temp_load}} < {{nsteps_load}}: {{target}} = {{start}} + {{temp_load}} * {{step}} {{body}} {{temp}} = {{temp_load}} + 1 %s """) % (textwrap.dedent(compute_nsteps), else_clause) # Leave the bodies empty, they are already analyzed body = ast.Suite(body=[]) else_body = ast.Suite(body=[]) #-------------------------------------------------------------------- # Substitute template and infer types #-------------------------------------------------------------------- result = self.run_template(templ, vars=dict(length=Py_ssize_t), start=start, stop=stop, step=step, nsteps=nsteps.store(), nsteps_load=nsteps.load(), temp=temp.store(), temp_load=temp.load(), target=node.target, body=body, else_body=else_body) #-------------------------------------------------------------------- # Patch the body and else clause #-------------------------------------------------------------------- body.body.extend(node.body) else_body.body.extend(node.orelse) while_node = result.body[-1] assert isinstance(while_node, ast.While) target_increment = while_node.body[-1] assert isinstance(target_increment, ast.Assign) # Add target variable increment basic block node.incr_block.body = [target_increment] while_node.body[-1] = node.incr_block #-------------------------------------------------------------------- # Create a While with the ForNode's cfg blocks merged in #-------------------------------------------------------------------- while_node = make_while_loop(while_node) copy_basic_blocks(node, while_node) while_node = nodes.build_while(**vars(while_node)) # Create the place to jump to for 'continue' while_node.continue_block = node.incr_block # Set the new while loop in the templated Suite result.body[-1] = while_node return result
def rewrite_range_iteration(self, node): """ Handle range iteration: for i in range(start, stop, step): ... becomes nsteps = compute_nsteps(start, stop, step) temp = 0 while temp < nsteps: target = start + temp * step ... temp += 1 """ self.generic_visit(node) temp = nodes.TempNode(node.target.type, 'target_temp') nsteps = nodes.TempNode(Py_ssize_t, 'nsteps') start, stop, step = unpack_range_args(node.iter) if isinstance(step, nodes.ConstNode): have_step = step.pyval != 1 else: have_step = True start, stop, step = map(nodes.CloneableNode, (start, stop, step)) if have_step: templ = textwrap.dedent(""" {{temp}} = 0 {{nsteps}} = ({{stop}} - {{start}} + {{step}} - (1 if {{step}} >= 0 else -1)) / {{step}} while {{temp_load}} < {{nsteps_load}}: {{target}} = {{start}} + {{temp_load}} * {{step}} {{temp}} = {{temp_load}} + 1 {{body}} """) else: templ = textwrap.dedent(""" {{temp}} = {{start}} {{nsteps}} = {{stop}} while {{temp_load}} < {{nsteps_load}}: {{target}} = {{temp_load}} {{temp}} = {{temp_load}} + 1 {{body}} """) if node.orelse: templ += "\nelse: {{else_body}}" # Leave the bodies empty, they are already analyzed body = ast.Suite(body=[]) else_body = ast.Suite(body=[]) #-------------------------------------------------------------------- # Substitute template and infer types #-------------------------------------------------------------------- result = self.run_template(templ, vars=dict(length=Py_ssize_t), start=start, stop=stop, step=step, nsteps=nsteps.store(), nsteps_load=nsteps.load(), temp=temp.store(), temp_load=temp.load(), target=node.target, body=body, else_body=else_body) ast.copy_location(result, node) if hasattr(node, 'lineno'): visitor = missing.FixMissingLocations(node.lineno, node.col_offset, override=True) visitor.visit(result) #-------------------------------------------------------------------- # Patch the body and else clause #-------------------------------------------------------------------- body.body.extend(node.body) else_body.body.extend(node.orelse) while_node = result.body[-1] assert isinstance(while_node, ast.While) #-------------------------------------------------------------------- # Create a While with the ForNode's cfg blocks merged in #-------------------------------------------------------------------- while_node = make_while_loop(while_node) copy_basic_blocks(node, while_node) while_node = nodes.build_while(**vars(while_node)) # Create the place to jump to for 'continue' while_node.continue_block = node.cond_block # Set the new while loop in the templated Suite result.body[-1] = while_node return result
def rewrite_range_iteration(self, node): """ Handle range iteration: for i in range(start, stop, step): ... becomes nsteps = compute_nsteps(start, stop, step) temp = 0 while temp < nsteps: target = start + temp * step ... temp += 1 """ self.generic_visit(node) temp = nodes.TempNode(node.target.type, 'target_temp') nsteps = nodes.TempNode(Py_ssize_t, 'nsteps') start, stop, step = unpack_range_args(node.iter) if isinstance(step, nodes.ConstNode): have_step = step.pyval != 1 else: have_step = True start, stop, step = [nodes.CloneableNode(n) for n in (start, stop, step)] if have_step: compute_nsteps = """ $length = {{stop}} - {{start}} {{nsteps}} = $length / {{step}} if {{nsteps_load}} * {{step}} != $length: #$length % {{step}}: # Test for truncation {{nsteps}} = {{nsteps_load}} + 1 # print "nsteps", {{nsteps_load}} """ else: compute_nsteps = "{{nsteps}} = {{stop}} - {{start}}" if node.orelse: else_clause = "else: {{else_body}}" else: else_clause = "" templ = textwrap.dedent(""" %s {{temp}} = 0 while {{temp_load}} < {{nsteps_load}}: {{target}} = {{start}} + {{temp_load}} * {{step}} {{body}} {{temp}} = {{temp_load}} + 1 %s """) % (textwrap.dedent(compute_nsteps), else_clause) # Leave the bodies empty, they are already analyzed body = ast.Suite(body=[]) else_body = ast.Suite(body=[]) #-------------------------------------------------------------------- # Substitute template and infer types #-------------------------------------------------------------------- result = self.run_template( templ, vars=dict(length=Py_ssize_t), start=start, stop=stop, step=step, nsteps=nsteps.store(), nsteps_load=nsteps.load(), temp=temp.store(), temp_load=temp.load(), target=node.target, body=body, else_body=else_body) #-------------------------------------------------------------------- # Patch the body and else clause #-------------------------------------------------------------------- body.body.extend(node.body) else_body.body.extend(node.orelse) while_node = result.body[-1] assert isinstance(while_node, ast.While) target_increment = while_node.body[-1] assert isinstance(target_increment, ast.Assign) # Add target variable increment basic block node.incr_block.body = [target_increment] while_node.body[-1] = node.incr_block #-------------------------------------------------------------------- # Create a While with the ForNode's cfg blocks merged in #-------------------------------------------------------------------- while_node = make_while_loop(while_node) copy_basic_blocks(node, while_node) while_node = nodes.build_while(**vars(while_node)) # Create the place to jump to for 'continue' while_node.continue_block = node.incr_block # Set the new while loop in the templated Suite result.body[-1] = while_node return result
def rewrite_range_iteration(self, node): """ Handle range iteration: for i in range(start, stop, step): ... becomes nsteps = compute_nsteps(start, stop, step) temp = 0 while temp < nsteps: target = start + temp * step ... temp += 1 """ self.generic_visit(node) temp = nodes.TempNode(node.target.type, 'target_temp') nsteps = nodes.TempNode(Py_ssize_t, 'nsteps') start, stop, step = unpack_range_args(node.iter) if isinstance(step, nodes.ConstNode): have_step = step.pyval != 1 else: have_step = True start, stop, step = map(nodes.CloneableNode, (start, stop, step)) if have_step: templ = textwrap.dedent(""" {{temp}} = 0 {{nsteps}} = ({{stop}} - {{start}} + {{step}} - (1 if {{step}} >= 0 else -1)) / {{step}} while {{temp_load}} < {{nsteps_load}}: {{target}} = {{start}} + {{temp_load}} * {{step}} {{temp}} = {{temp_load}} + 1 {{body}} """) else: templ = textwrap.dedent(""" {{temp}} = {{start}} {{nsteps}} = {{stop}} while {{temp_load}} < {{nsteps_load}}: {{target}} = {{temp_load}} {{temp}} = {{temp_load}} + 1 {{body}} """) if node.orelse: templ += "\nelse: {{else_body}}" # Leave the bodies empty, they are already analyzed body = ast.Suite(body=[]) else_body = ast.Suite(body=[]) #-------------------------------------------------------------------- # Substitute template and infer types #-------------------------------------------------------------------- result = self.run_template( templ, vars=dict(length=Py_ssize_t), start=start, stop=stop, step=step, nsteps=nsteps.store(), nsteps_load=nsteps.load(), temp=temp.store(), temp_load=temp.load(), target=node.target, body=body, else_body=else_body) ast.copy_location(result, node) if hasattr(node, 'lineno'): visitor = missing.FixMissingLocations(node.lineno, node.col_offset, override=True) visitor.visit(result) #-------------------------------------------------------------------- # Patch the body and else clause #-------------------------------------------------------------------- body.body.extend(node.body) else_body.body.extend(node.orelse) while_node = result.body[-1] assert isinstance(while_node, ast.While) #-------------------------------------------------------------------- # Create a While with the ForNode's cfg blocks merged in #-------------------------------------------------------------------- while_node = make_while_loop(while_node) copy_basic_blocks(node, while_node) while_node = nodes.build_while(**vars(while_node)) # Create the place to jump to for 'continue' while_node.continue_block = node.cond_block # Set the new while loop in the templated Suite result.body[-1] = while_node return result