class Apricot::SpecialForm::ArgList

Attributes

block_arg[R]
num_optional[R]
num_required[R]
num_total[R]
optional_args[R]
required_args[R]
rest_arg[R]

Public Class Methods

new(args, g) click to toggle source
# File lib/apricot/special_forms/fn.rb, line 7
def initialize(args, g)
  state = :required

  @required_args = []
  @optional_args = []
  @rest_arg = nil
  @block_arg = nil

  args.each do |arg|
    # Check if we got one of the special identifiers which moves us to a
    # different part of the argument list. If so, move to the new state
    # and skip to the next argument. Also check that the current state
    # is allowed to move to the new state (the arguments must come in a
    # strict order: required, optional, rest, block).
    if arg.is_a? Identifier
      case arg.name
      # '?' starts the optional arguments section.
      when :'?'
        case state
        when :required
          state = :start_optional
          next
        else
          g.compile_error "Unexpected '?' in argument list"
        end

      # '&' precedes the rest argument.
      when :&
        case state
        when :required, :optional
          state = :rest
          next
        else
          g.compile_error "Unexpected '&' in argument list"
        end

      # '|' precedes the block argument.
      when :|
        case state
        when :required, :optional, :after_rest
          state = :block
          next
        else
          g.compile_error "Unexpected '|' in argument list"
        end
      end
    end

    # Deal with the argument based on the current state.
    case state
    when :required
      g.compile_error "Required argument in argument list must be an identifier" unless arg.is_a? Identifier
      @required_args << arg.name

    when :optional, :start_optional
      unless arg.is_a?(Seq) && arg.count == 2 && arg.first.is_a?(Identifier)
        g.compile_error "Optional argument in argument list must be of the form (name default)"
      end

      state = :optional
      @optional_args << [arg.first.name, arg.rest.first]

    when :rest
      g.compile_error "Rest argument in argument list must be an identifier" unless arg.is_a? Identifier
      @rest_arg = arg.name
      state = :after_rest

    when :block
      g.compile_error "Block argument in argument list must be an identifier" unless arg.is_a? Identifier
      @block_arg = arg.name
      state = :after_block

    when :after_rest
      g.compile_error "Unexpected argument after rest argument"

    when :after_block
      g.compile_error "Unexpected arguments after block argument"
    end
  end

  # Check if we finished in the middle of things without getting an
  # argument where we expected one.
  case state
  when :start_optional
    g.compile_error "Expected optional arguments after '?' in argument list"

  when :rest
    g.compile_error "Expected rest argument after '&' in argument list"

  when :block
    g.compile_error "Expected block argument after '|' in argument list"
  end

  @num_required = @required_args.length
  @num_optional = @optional_args.length
  @num_total = @num_required + @num_optional
end

Public Instance Methods

to_array() click to toggle source
# File lib/apricot/special_forms/fn.rb, line 105
def to_array
  args = @required_args.map {|id| Identifier.intern(id) }
  args += @optional_args.map {|name, val| [Identifier.intern(name), val.to_value] }
  args += [Identifier.intern(:|), Identifier.intern(@block_arg)] if @block_arg
  args += [Identifier.intern(:&), Identifier.intern(@rest_arg)] if @rest_arg
  args
end