Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/tensorflow/python/autograph/converters/continue_statements.py: 26%
91 statements
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-03 07:57 +0000
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-03 07:57 +0000
1# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ==============================================================================
15"""Canonicalizes continue statements by de-sugaring into a control boolean."""
17from tensorflow.python.autograph.core import converter
18from tensorflow.python.autograph.pyct import anno
19from tensorflow.python.autograph.pyct import qual_names
20from tensorflow.python.autograph.pyct import templates
21from tensorflow.python.autograph.pyct.static_analysis import activity
22from tensorflow.python.autograph.pyct.static_analysis.annos import NodeAnno
25class _Continue(object):
27 def __init__(self):
28 self.used = False
29 self.control_var_name = None
31 def __repr__(self):
32 return '<_Continue(used: {}, var: {})>'.format(self.used,
33 self.control_var_name)
36class _Block(object):
37 """Tracks information about lexical blocks as they are visited in the AST.
39 Mainly, this object tracks the creation of block guards that replace
40 `continue` statements (e.g. `if not continue_:`).
42 Attributes:
43 create_guard_current: bool, whether to create a guard for the current
44 statement.
45 create_guard_next: bool, whether to create a guard for the next
46 statement.
47 is_loop_type: bool, whether this block is the body of a loop.
48 """
50 def __init__(self):
51 self.is_loop_type = False
52 self.create_guard_current = False
53 self.create_guard_next = False
56class ContinueCanonicalizationTransformer(converter.Base):
57 """Canonicalizes continue statements into additional conditionals."""
59 def visit_Continue(self, node):
60 self.state[_Continue].used = True
61 for block in reversed(self.state[_Block].stack):
62 # See ContinueCanonicalizationTest.test_multiple_continues for an example
63 # it's necessary to create guards for all enclosing affected blocks, not
64 # just that of the current block.
65 block.create_guard_next = True
66 if block.is_loop_type:
67 # continue only affects the innermost loop
68 break
69 template = """
70 var_name = True
71 """
72 return templates.replace(
73 template, var_name=self.state[_Continue].control_var_name)
75 def _postprocess_statement(self, node):
76 if self.state[_Continue].used:
77 block = self.state[_Block]
78 should_wrap_current = block.create_guard_current
79 # After processing propagate whether to guard the next statement
80 block.create_guard_current = block.create_guard_next
81 block.create_guard_next = False
82 if should_wrap_current:
83 template = """
84 if not var_name:
85 original_node
86 """
87 cond, = templates.replace(
88 template,
89 var_name=self.state[_Continue].control_var_name,
90 original_node=node)
91 return cond, cond.body
92 return node, None
94 def _visit_loop_body(self, node, nodes):
95 self.state[_Continue].enter()
96 self.state[_Block].enter()
97 self.state[_Block].is_loop_type = True
98 scope = anno.getanno(node, NodeAnno.BODY_SCOPE)
99 continue_var = self.ctx.namer.new_symbol('continue_', scope.referenced)
100 self.state[_Continue].control_var_name = continue_var
102 nodes = self.visit_block(nodes, after_visit=self._postprocess_statement)
104 if self.state[_Continue].used:
105 template = """
106 var_name = False
107 """
108 control_var_init = templates.replace(template, var_name=continue_var)
109 nodes = control_var_init + nodes
111 self.state[_Block].exit()
112 self.state[_Continue].exit()
113 return nodes
115 def _visit_non_loop_body(self, nodes):
116 self.state[_Block].enter()
117 nodes = self.visit_block(nodes, after_visit=self._postprocess_statement)
118 self.state[_Block].exit()
119 return nodes
121 def visit_While(self, node):
122 node.test = self.visit(node.test)
123 node.body = self._visit_loop_body(node, node.body)
124 # A continue in the else clause applies to the containing scope.
125 node.orelse = self._visit_non_loop_body(node.orelse)
126 return node
128 def visit_For(self, node):
129 node.target = self.generic_visit(node.target)
130 node.iter = self.generic_visit(node.iter)
131 node.body = self._visit_loop_body(node, node.body)
132 # A continue in the else clause applies to the containing scope.
133 node.orelse = self._visit_non_loop_body(node.orelse)
134 return node
136 def visit_If(self, node):
137 node.body = self._visit_non_loop_body(node.body)
138 node.orelse = self._visit_non_loop_body(node.orelse)
139 return node
141 def visit_With(self, node):
142 node.items = self.visit_block(node.items)
143 node.body = self._visit_non_loop_body(node.body)
144 return node
146 def visit_Try(self, node):
147 node.body = self._visit_non_loop_body(node.body)
148 node.orelse = self._visit_non_loop_body(node.orelse)
149 # In Python 3.8 and later continue is allowed in finally blocks
150 node.finalbody = self._visit_non_loop_body(node.finalbody)
151 node.handlers = self.visit_block(node.handlers)
152 return node
154 def visit_ExceptHandler(self, node):
155 node.body = self._visit_non_loop_body(node.body)
156 return node
159def transform(node, ctx):
160 node = qual_names.resolve(node)
161 node = activity.resolve(node, ctx, None)
163 node = ContinueCanonicalizationTransformer(ctx).visit(node)
164 return node