class Lisp::Macro

Attributes

body[R]
doc[R]
name[R]

Public Class Methods

new(name, arguments, doc, body, env) click to toggle source
# File lib/rubylisp/macro.rb, line 22
def initialize(name, arguments, doc, body, env)
  #puts "Macro#initialize #{name} #{arguments.to_a}"
  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/macro.rb, line 80
def apply_to(parameters, env)
  internal_apply_to(parameters, env, false)
end
apply_to_without_evaluating(parameters, env) click to toggle source
# File lib/rubylisp/macro.rb, line 84
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/macro.rb, line 7
def compute_required_argument_count(args)
  a = args
  @required_argument_count = 0
  @var_args = false
  while a
    if a.symbol?
      @var_args = true
      return
    else
      @required_argument_count += 1
    end
    a = a.cdr
  end
end
expand(parameters, env, should_eval) click to toggle source
# File lib/rubylisp/macro.rb, line 35
def expand(parameters, env, should_eval)
  if @var_args
    return Lisp::Debug.process_error("#{@name} expected at least #{@required_argument_count} parameters, received #{parameters.length}.", env) if parameters.length < @required_argument_count
  else
    return Lisp::Debug.process_error("#{@name} expected #{@required_argument_count} parameters, received #{parameters.length}.", env) unless parameters.length == @required_argument_count        
  end
  
  local_env = EnvironmentFrame.extending(@env, @name, env.frame)
  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

  #puts "expanding #{@name}"
  #puts "     #{@body.print_string}"
  
  result = @body.evaluate(local_env)

  #puts "     #{result.print_string}"
  result
end
internal_apply_to(parameters, env, should_eval) click to toggle source
# File lib/rubylisp/macro.rb, line 75
def internal_apply_to(parameters, env, should_eval)
  expanded_macro = expand(parameters, env, should_eval)
  expanded_macro.evaluate(env)
end
macro?() click to toggle source
# File lib/rubylisp/macro.rb, line 92
def macro?
  true
end
to_s() click to toggle source
# File lib/rubylisp/macro.rb, line 88
def to_s
  "<macro: #{@name}>"
end
type() click to toggle source
# File lib/rubylisp/macro.rb, line 96
def type
  :macro
end