15b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
25b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower#
35b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower# Licensed under the Apache License, Version 2.0 (the "License");
45b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower# you may not use this file except in compliance with the License.
55b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower# You may obtain a copy of the License at
65b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower#
75b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower#     http://www.apache.org/licenses/LICENSE-2.0
85b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower#
95b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower# Unless required by applicable law or agreed to in writing, software
105b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower# distributed under the License is distributed on an "AS IS" BASIS,
115b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
125b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower# See the License for the specific language governing permissions and
135b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower# limitations under the License.
145b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower# ==============================================================================
15453f94412f908aadd21561c14feae80dfac1e933A. Unique TensorFlower"""Handles control flow statements: while, if."""
165b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower
175b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlowerfrom __future__ import absolute_import
185b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlowerfrom __future__ import division
195b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlowerfrom __future__ import print_function
205b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower
215b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlowerimport gast
225b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower
235b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlowerfrom tensorflow.contrib.py2tf.pyct import anno
24d9df4313a98fdc62187a94c5ab6d8955b699e9f2A. Unique TensorFlowerfrom tensorflow.contrib.py2tf.pyct import ast_util
255b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlowerfrom tensorflow.contrib.py2tf.pyct import templates
266a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlowerfrom tensorflow.contrib.py2tf.pyct import transformer
276a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlowerfrom tensorflow.contrib.py2tf.pyct.static_analysis.annos import NodeAnno
285b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower
295b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower
305b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlowerclass SymbolNamer(object):
315b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower  """Describes the interface for ControlFlowTransformer's namer."""
325b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower
335b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower  def new_symbol(self, name_root, reserved_locals):
345b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower    """Generate a new unique symbol.
355b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower
365b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower    Args:
375b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower      name_root: String, used as stem in the new name.
385b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower      reserved_locals: Set(string), additional local symbols that are reserved
395b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower          and which should not be used.
405b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower    Returns:
415b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower      String.
425b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower    """
435b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower    raise NotImplementedError()
445b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower
455b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower
466a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlowerclass ControlFlowTransformer(transformer.Base):
475b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower  """Transforms control flow structures like loops an conditionals."""
485b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower
496a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower  def __init__(self, context):
506a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower    super(ControlFlowTransformer, self).__init__(context)
515b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower
525b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower  # pylint:disable=invalid-name
535b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower
54453f94412f908aadd21561c14feae80dfac1e933A. Unique TensorFlower  def visit_For(self, node):
55453f94412f908aadd21561c14feae80dfac1e933A. Unique TensorFlower    assert False, 'for statement should have been canonicalized at this point'
565b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower
5765e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower  def _create_cond_branch(self, body_name, aliased_orig_names,
5865e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower                          aliased_new_names, body, returns):
5965e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower    if aliased_orig_names:
6065e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower      template = """
6165e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower        def body_name():
6265e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower          aliased_new_names, = aliased_orig_names,
6365e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower          body
6465e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower          return (returns,)
6565e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower      """
6665e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower      return templates.replace(
6765e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower          template,
6865e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower          body_name=body_name,
6965e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower          body=body,
7065e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower          aliased_orig_names=aliased_orig_names,
7165e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower          aliased_new_names=aliased_new_names,
7265e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower          returns=returns)
7365e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower    else:
7465e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower      template = """
7565e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower        def body_name():
7665e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower          body
7765e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower          return (returns,)
7865e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower      """
7965e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower      return templates.replace(
8065e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower          template, body_name=body_name, body=body, returns=returns)
8165e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower
8265e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower  def _create_cond_expr(self, results, test, body_name, orelse_name):
8365e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower    if results is not None:
8465e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower      template = """
8565e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower        results = py2tf_utils.run_cond(test, body_name, orelse_name)
8665e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower      """
8765e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower      return templates.replace(
8865e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower          template,
8965e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower          test=test,
9065e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower          results=results,
9165e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower          body_name=body_name,
9265e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower          orelse_name=orelse_name)
9365e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower    else:
9465e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower      template = """
9565e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower        py2tf_utils.run_cond(test, body_name, orelse_name)
9665e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower      """
9765e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower      return templates.replace(
9865e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower          template, test=test, body_name=body_name, orelse_name=orelse_name)
9965e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower
1005b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower  def visit_If(self, node):
1016ee404d17929c613b217400406e7e665010ebf18A. Unique TensorFlower    self.generic_visit(node)
1026ee404d17929c613b217400406e7e665010ebf18A. Unique TensorFlower
1036a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower    body_scope = anno.getanno(node, NodeAnno.BODY_SCOPE)
1046a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower    orelse_scope = anno.getanno(node, NodeAnno.ORELSE_SCOPE)
1056ee404d17929c613b217400406e7e665010ebf18A. Unique TensorFlower
1066ee404d17929c613b217400406e7e665010ebf18A. Unique TensorFlower    if body_scope.created - orelse_scope.created:
1076ee404d17929c613b217400406e7e665010ebf18A. Unique TensorFlower      raise ValueError(
1086ee404d17929c613b217400406e7e665010ebf18A. Unique TensorFlower          'The if branch creates new symbols that the else branch does not.')
1096ee404d17929c613b217400406e7e665010ebf18A. Unique TensorFlower    if orelse_scope.created - body_scope.created:
1106ee404d17929c613b217400406e7e665010ebf18A. Unique TensorFlower      raise ValueError(
1116ee404d17929c613b217400406e7e665010ebf18A. Unique TensorFlower          'The else branch creates new symbols that the if branch does not.')
1126ee404d17929c613b217400406e7e665010ebf18A. Unique TensorFlower
11365e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower    modified = tuple(body_scope.modified | orelse_scope.modified)
1146ee404d17929c613b217400406e7e665010ebf18A. Unique TensorFlower    all_referenced = body_scope.referenced | orelse_scope.referenced
1156ee404d17929c613b217400406e7e665010ebf18A. Unique TensorFlower
1166ee404d17929c613b217400406e7e665010ebf18A. Unique TensorFlower    # Alias the closure variables inside the conditional functions
1176ee404d17929c613b217400406e7e665010ebf18A. Unique TensorFlower    # to avoid errors caused by the local variables created in the branch
1186ee404d17929c613b217400406e7e665010ebf18A. Unique TensorFlower    # functions.
1196ee404d17929c613b217400406e7e665010ebf18A. Unique TensorFlower    need_alias = (
1206ee404d17929c613b217400406e7e665010ebf18A. Unique TensorFlower        (body_scope.modified | orelse_scope.modified) -
1216ee404d17929c613b217400406e7e665010ebf18A. Unique TensorFlower        (body_scope.created | orelse_scope.created))
122949dd29d3a8bdc21328c9e94721b344310686eabA. Unique TensorFlower    aliased_orig_names = tuple(need_alias)
123949dd29d3a8bdc21328c9e94721b344310686eabA. Unique TensorFlower    aliased_new_names = tuple(
1246a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower        self.context.namer.new_symbol(s.ssf(), all_referenced)
1256a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower        for s in aliased_orig_names)
126949dd29d3a8bdc21328c9e94721b344310686eabA. Unique TensorFlower    alias_map = dict(zip(aliased_orig_names, aliased_new_names))
127d9df4313a98fdc62187a94c5ab6d8955b699e9f2A. Unique TensorFlower    node_body = ast_util.rename_symbols(node.body, alias_map)
128d9df4313a98fdc62187a94c5ab6d8955b699e9f2A. Unique TensorFlower    node_orelse = ast_util.rename_symbols(node.orelse, alias_map)
1296ee404d17929c613b217400406e7e665010ebf18A. Unique TensorFlower
13065e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower    if not modified:
13165e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower      # When the cond would return no value, we leave the cond called without
13265e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower      # results. That in turn should trigger the side effect guards. The
13365e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower      # branch functions will return a dummy value that ensures cond
13465e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower      # actually has some return value as well.
13565e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower      results = None
13665e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower    elif len(modified) == 1:
13765e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower      results = modified[0]
1386ee404d17929c613b217400406e7e665010ebf18A. Unique TensorFlower    else:
13965e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower      results = gast.Tuple([s.ast() for s in modified], None)
1406a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower
14165e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower    body_name = self.context.namer.new_symbol('if_true', all_referenced)
14265e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower    orelse_name = self.context.namer.new_symbol('if_false', all_referenced)
14365e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower    if modified:
14465e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower      body_returns = tuple(
14565e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower          alias_map[s] if s in aliased_orig_names else s for s in modified)
1466a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower    else:
14765e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower      body_returns = templates.replace('tf.ones(())')[0].value
14865e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower
14965e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower    body_def = self._create_cond_branch(
15065e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower        body_name,
15165e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower        aliased_orig_names=tuple(aliased_orig_names),
15265e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower        aliased_new_names=tuple(aliased_new_names),
15365e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower        body=node_body,
15465e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower        returns=body_returns)
15565e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower    orelse_def = self._create_cond_branch(
15665e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower        orelse_name,
15765e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower        aliased_orig_names=tuple(aliased_orig_names),
15865e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower        aliased_new_names=tuple(aliased_new_names),
15965e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower        body=node_orelse,
16065e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower        returns=body_returns)
16165e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower    cond_expr = self._create_cond_expr(results, node.test, body_name,
16265e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower                                       orelse_name)
16365e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower
16465e8efa179bc9d75f6fe9a40d2ae1c9ec26e6b47A. Unique TensorFlower    return body_def + orelse_def + cond_expr
1655b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower
1665b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower  def visit_While(self, node):
1675b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower    self.generic_visit(node)
1686ee404d17929c613b217400406e7e665010ebf18A. Unique TensorFlower
1696a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower    body_scope = anno.getanno(node, NodeAnno.BODY_SCOPE)
1706a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower    body_closure = body_scope.modified - body_scope.created
1716a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower    all_referenced = body_scope.referenced
1726a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower
1736a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower    state = list(body_closure)
1746a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower    state_ssf = [
1756a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower        self.context.namer.new_symbol(s.ssf(), all_referenced) for s in state
1766a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower    ]
1776a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower    ssf_map = {
1786a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower        name: ssf
1796a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower        for name, ssf in zip(state, state_ssf)
1806a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower        if str(name) != ssf
1816a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower    }
1826a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower
1836a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower    if len(state) == 1:
1846a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower      state = state[0]
1856a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower      state_ssf = state_ssf[0]
186453f94412f908aadd21561c14feae80dfac1e933A. Unique TensorFlower      state_ast_tuple = state
187453f94412f908aadd21561c14feae80dfac1e933A. Unique TensorFlower    else:
1886a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower      state_ast_tuple = gast.Tuple([n.ast() for n in state], None)
1896a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower
190d9df4313a98fdc62187a94c5ab6d8955b699e9f2A. Unique TensorFlower    node_body = ast_util.rename_symbols(node.body, ssf_map)
191d9df4313a98fdc62187a94c5ab6d8955b699e9f2A. Unique TensorFlower    test = ast_util.rename_symbols(node.test, ssf_map)
1926a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower
193949dd29d3a8bdc21328c9e94721b344310686eabA. Unique TensorFlower    template = """
1946a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower      def test_name(state_ssf):
195949dd29d3a8bdc21328c9e94721b344310686eabA. Unique TensorFlower        return test
1966a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower      def body_name(state_ssf):
197949dd29d3a8bdc21328c9e94721b344310686eabA. Unique TensorFlower        body
1986a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower        return state_ssf,
199474543b4ff5b9ecd2ad949e268c2a81f2986dcccA. Unique TensorFlower      state_ast_tuple = py2tf_utils.run_while(test_name, body_name, [state])
200949dd29d3a8bdc21328c9e94721b344310686eabA. Unique TensorFlower    """
2015b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower    node = templates.replace(
2025b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower        template,
203453f94412f908aadd21561c14feae80dfac1e933A. Unique TensorFlower        state=state,
2046a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower        state_ssf=state_ssf,
205453f94412f908aadd21561c14feae80dfac1e933A. Unique TensorFlower        state_ast_tuple=state_ast_tuple,
2066a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower        test_name=self.context.namer.new_symbol('loop_test',
2076a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower                                                body_scope.referenced),
2086a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower        test=test,
2096a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower        body_name=self.context.namer.new_symbol('loop_body',
2106a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower                                                body_scope.referenced),
2116a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower        body=node_body)
2125b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower
2135b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower    return node
2145b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower
2155b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower  # pylint:enable=invalid-name
2165b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower
2175b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower
2186a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlowerdef transform(node, context):
2196a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower  t = ControlFlowTransformer(context)
2206a822c373818948037baacfbae1c7355e0fc2c48A. Unique TensorFlower  node = t.visit(node)
2215b2aae39b75f5a864e0ec0dd95c7f3a07e9d16e7A. Unique TensorFlower  return node
222