def visit_Assign( self, node ):

    # Because the lhs could contain arbitrary nesting of tuples or lists,
    # flatten these all out to get the target for each assignment.

    def flatten_targets( tgt, lst ):
      if   isinstance( tgt, list ):
        for x in tgt: flatten_targets( x, lst )
      elif isinstance( tgt, (ast.Tuple,ast.List) ):
        for x in tgt.elts: flatten_targets( x, lst )
      elif isinstance( tgt, (ast.Attribute,ast.Name,ast.Subscript) ):
        lst.append( tgt )
      else:
        from ..ast_helpers import print_simple_ast
        print_simple_ast( tgt )
        raise Exception(
          'Unsupported assignment type ({kind})!\n'
          'Please notify the PyMTL developers!\n\n'
          ' {lineno} {srccode}\n'
          ' File: {filename}\n'
          ' Function: {funcname}\n'
          ' Line: {lineno}\n'.format(
            attr     = self.attr[0],
            kind     = tgt.__class__,
            srccode  = self.src[ node.lineno - 1 ],
            filename = inspect.getfile( self.func ),
            funcname = self.func.func_name,
            lineno   = self.funclineno + node.lineno - 1
          )
        )

    targets = []
    flatten_targets( node.targets, targets )

    # For each assignment AST node, get the targets. If targets do not
    # end with .value or .next, verify this is not a Signal object
    # (InPort, OutPort, Wire)
    # FIXME: second item of self.attr tuple is for .n and .v. Rm these?

    for lhs in targets:
      if not isinstance( lhs, ast.Attribute ) or lhs.attr not in self.attr:

        # TODO: this is super hacky. Grab each left-hand side (LHS)
        # target, give them Load() instead of Store() contexts, and wrap
        # them in an ast.Expression node. This allows us to compile the
        # AST as an expression and execute it with eval(), which will
        # return the object stored in the lhs target. The second argument
        # to eval() is closure dictionary we extracted from the function.

        ## DEBUG
        #print inspect.getfile( self.func )
        #print self.funclineno + node.lineno - 1, self.src[ node.lineno - 1 ]
        ## DEBUG

        # In order to handle lists of Signals, we replace all complex
        # Indexes with the value zero. This will return the first element
        # in the list.
        try:
          lhs     = ReplaceIndexesWithZero().visit( lhs )
          lhs.ctx = ast.Load()
          _code   = compile( ast.Expression( lhs ), '<ast>', 'eval' )
          _temp   = eval( _code, self.dict_ )
        except (__HOLE__, AttributeError) as e:
          # We can't really do anything about temporaries created inside
          # the combinational block without performing a real type
          # inference analysis pass.
          _temp = None
        except IndexError as e:
          # Empty list, nothing to do.
          _temp = None

        # if the object stored in LHS is a Signal, raise a PyMTLError
        if isinstance( _temp, Signal ):
          raise PyMTLError(
            'Attempting to write a(n) {kind} without .{attr}!\n\n'
            ' {lineno} {srccode}\n'
            ' File: {filename}\n'
            ' Function: {funcname}\n'
            ' Line: {lineno}\n'.format(
              attr     = self.attr[0],
              kind     = _temp.__class__.__name__,
              srccode  = self.src[ node.lineno - 1 ],
              filename = inspect.getfile( self.func ),
              funcname = self.func.func_name,
              lineno   = self.funclineno + node.lineno - 1
            )
          )

#------------------------------------------------------------------------
# ReplaceIndexesWithZero
#------------------------------------------------------------------------
dataset/ETHPy150Open cornell-brg/pymtl/pymtl/tools/simulation/ast_visitor.py/DetectMissingValueNext.visit_Assign