class Lisp::Function

Attributes

arity[R]
body[R]
doc[R]
env[R]
name[R]

Public Class Methods

new(name, arguments, doc, body, env) click to toggle source
# File lib/rubylisp/function.rb, line 23
def initialize(name, arguments, doc, body, env)
  sig = ([name] << arguments.to_a).flatten
  @doc = "(#{(sig.collect {|e| e.to_s}).join(" ")})"
  @name = name
  @arguments = arguments
  @doc = [@doc, doc].join("\n\n") unless doc.nil? || doc.to_s.empty?
  @body = body
  @env = env
  @local_env = nil
  compute_required_argument_count(@arguments)
end

Public Instance Methods

apply_to(parameters, env) click to toggle source
# File lib/rubylisp/function.rb, line 72
def apply_to(parameters, env)
  internal_apply_to(parameters, env, true)
end
apply_to_without_evaluating(parameters, env) click to toggle source
# File lib/rubylisp/function.rb, line 76
def apply_to_without_evaluating(parameters, env)
  internal_apply_to(parameters, env, false)
end
compute_required_argument_count(args) click to toggle source
# File lib/rubylisp/function.rb, line 7
def compute_required_argument_count(args)
  a = args
  @arity = 0
  @var_args = false
  while a
    if a.symbol?
      @var_args = true
      return
    else
      @arity += 1
    end
    a = a.cdr
  end
end
function?() click to toggle source
# File lib/rubylisp/function.rb, line 84
def function?
  true
end
internal_apply_to(parameters, env, should_eval) click to toggle source
# File lib/rubylisp/function.rb, line 36
def internal_apply_to(parameters, env, should_eval)
  if @var_args
    return Lisp::Debug.process_error("#{@name} expected at least #{@arity} parameters, received #{parameters.length}.", env) if parameters.length < @arity
  else
    puts "#{@name} #{@arguments.print_string} #{@body.print_string}" unless parameters.length == @arity
    puts caller unless parameters.length == @arity
    return Lisp::Debug.process_error("#{@name} expected #{@arity} parameters, received #{parameters.length}.", env) unless parameters.length == @arity        
  end
  local_env = EnvironmentFrame.extending(@env, @name, env.frame)
  local_env.previous = env
  self_sym = Symbol.named("self")
  if env.frame
    local_env.bind_locally(self_sym, env.frame)
  elsif env.local_binding_for(self_sym)
    local_env.bind_locally(self_sym, env.value_of(self_sym))
  end
  arg = @arguments
  param = parameters
  accumulating_arg = nil
  accumulated_params = []
  while !param.nil?        
    param_value = should_eval ? param.car.evaluate(env) : param.car
    if accumulating_arg
      accumulated_params << param_value
    else
      local_env.bind_locally(arg.car, param_value) unless arg.car.nil?
    end
    param = param.cdr
    arg = arg.cdr unless accumulating_arg
    accumulating_arg = arg if arg.symbol?
  end
  local_env.bind_locally(accumulating_arg, Lisp::ConsCell.array_to_list(accumulated_params)) if accumulating_arg
  
  @body.evaluate_each(local_env)
end
to_s() click to toggle source
# File lib/rubylisp/function.rb, line 80
def to_s
  "<function: #{@name}>"
end
type() click to toggle source
# File lib/rubylisp/function.rb, line 88
def type
  :function
end