module SlotMachine

  # Transering the arguments from the current frame into the next frame
  #
  # This could be _done_ at this level, and in fact used to be.
  # The instruction was introduced to
  # 1. make optimisations easier
  # 2. localise the inevitable change
  #
  # 1. The optimal risc implementation for this loads old and new frames into registers
  #    and does a whole bunch of transfers
  #    But if we do individual SlotMoves here, each one has to load the frames,
  #    thus making advanced analysis/optimisation neccessary to achieve the same effect.
  #
  # 2. Closures will have to have access to variables after the frame goes out of scope
  #    and in fact be able to change the parents variables. The current design does not allow
  #    for this, and so will have to be change in the not so distant future.
  #
  class ArgumentTransfer < Instruction

    attr_reader :receiver , :arguments

    # receiver is a slot_definition
    # arguments is an array of SlotLoads
    def initialize( source , receiver,arguments )
      super(source)
      @receiver , @arguments = receiver , arguments
      raise "Receiver not Slot #{@receiver}" unless @receiver.is_a?(Slotted)
      @arguments.each{|a| raise "args not Slotted #{a}" unless a.is_a?(Slotted)}
    end

    def to_s
      "ArgumentTransfer " + ([@receiver] + @arguments).join(",")
    end

    # load receiver and then each arg into the new message
    # delegates to SlotLoad for receiver and to the actual args.to_risc
    def to_risc(compiler)
      transfer = SlotLoad.new(self.source ,[:message , :next_message , :receiver] , @receiver, self).to_risc(compiler)
      #TODO transfer the Number of arguments to :arguments_given (to be checked on entry)
      arg_target = [:message , :next_message ]
      @arguments.each_with_index do |arg , index| # +1 because of type
        load = SlotMachine::SlotLoad.new(self.source, arg_target + ["arg#{index+1}".to_sym] , arg)
        load.to_risc(compiler)
      end
      transfer
    end
  end


end