class SyntaxTree::YARV::VM

def setup_arguments(iseq, args, kwargs, block)

def setup_arguments(iseq, args, kwargs, block)
  locals = [*args]
  local_index = 0
  start_label = nil
  # First, set up all of the leading arguments. These are positional and
  # required arguments at the start of the argument list.
  if (lead_num = iseq.argument_options[:lead_num])
    lead_num.times do
      local_set(local_index, 0, locals.shift)
      local_index += 1
    end
  end
  # Next, set up all of the optional arguments. The opt array contains
  # the labels that the frame should start at if the optional is
  # present. The last element of the array is the label that the frame
  # should start at if all of the optional arguments are present.
  if (opt = iseq.argument_options[:opt])
    opt[0...-1].each do |label|
      if locals.empty?
        start_label = label
        break
      else
        local_set(local_index, 0, locals.shift)
        local_index += 1
      end
      start_label = opt.last if start_label.nil?
    end
  end
  # If there is a splat argument, then we'll set that up here. It will
  # grab up all of the remaining positional arguments.
  if (rest_start = iseq.argument_options[:rest_start])
    if (post_start = iseq.argument_options[:post_start])
      length = post_start - rest_start
      local_set(local_index, 0, locals[0...length])
      locals = locals[length..]
    else
      local_set(local_index, 0, locals.dup)
      locals.clear
    end
    local_index += 1
  end
  # Next, set up any post arguments. These are positional arguments that
  # come after the splat argument.
  if (post_num = iseq.argument_options[:post_num])
    post_num.times do
      local_set(local_index, 0, locals.shift)
      local_index += 1
    end
  end
  if (keyword_option = iseq.argument_options[:keyword])
    # First, set up the keyword bits array.
    keyword_bits =
      keyword_option.map do |config|
        kwargs.key?(config.is_a?(Array) ? config[0] : config)
      end
    iseq.local_table.locals.each_with_index do |local, index|
      # If this is the keyword bits local, then set it appropriately.
      if local.name.is_a?(Integer)
        local_set(index, 0, keyword_bits)
        next
      end
      # First, find the configuration for this local in the keywords
      # list if it exists.
      name = local.name
      config =
        keyword_option.find do |keyword|
          keyword.is_a?(Array) ? keyword[0] == name : keyword == name
        end
      # If the configuration doesn't exist, then the local is not a
      # keyword local.
      next unless config
      if !config.is_a?(Array)
        # required keyword
        local_set(index, 0, kwargs.fetch(name))
      elsif !config[1].nil?
        # optional keyword with embedded default value
        local_set(index, 0, kwargs.fetch(name, config[1]))
      else
        # optional keyword with expression default value
        local_set(index, 0, kwargs[name])
      end
    end
  end
  local_set(local_index, 0, block) if iseq.argument_options[:block_start]
  start_label
end