Class: Lisp::Primitive

Inherits:
Atom show all
Defined in:
lib/rubylisp/primitive.rb

Instance Attribute Summary collapse

Attributes inherited from Atom

#value

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Atom

#all?, #car, #cdr, #character?, #class?, #copy, #environment?, #eof_object?, #eq?, #equal?, #eqv?, #evaluate, #false?, #frame?, #function?, #length, #lisp_object?, #list?, #macro?, #negative?, #number?, #object?, #pair?, #port?, #positive?, #print_string, #quoted, #set!, #set_location, #string?, #symbol?, #true?, #vector?, #zero?

Constructor Details

#initialize(name, arity, doc, special, &implementation) ⇒ Primitive

Returns a new instance of Primitive.



14
15
16
17
18
19
20
# File 'lib/rubylisp/primitive.rb', line 14

def initialize(name, arity, doc, special, &implementation)
  @name = name
  @arity = arity
  @doc = doc
  @special = special
  @implementation = implementation
end

Instance Attribute Details

#docObject (readonly)

Returns the value of attribute doc.



5
6
7
# File 'lib/rubylisp/primitive.rb', line 5

def doc
  @doc
end

#nameObject (readonly)

Returns the value of attribute name.



5
6
7
# File 'lib/rubylisp/primitive.rb', line 5

def name
  @name
end

Class Method Details

.register(name, arity, doc = "", special = false, env = Lisp::EnvironmentFrame.global, &implementation) ⇒ Object



8
9
10
11
# File 'lib/rubylisp/primitive.rb', line 8

def self.register(name, arity, doc="", special=false, env=Lisp::EnvironmentFrame.global, &implementation)
  instance = self.new(name, arity, doc, special, &implementation)
  env.bind(Symbol.named(name), instance)
end

Instance Method Details

#apply_to(args, env) ⇒ Object



43
44
45
46
47
48
49
50
51
52
# File 'lib/rubylisp/primitive.rb', line 43

def apply_to(args, env)
  return Lisp::Debug.process_error("Wrong number of arguments to #{@name}. Expected #{@arity} but got #{args.length}.", env) unless check_arity(args)

  cooked_args = if @special
                  args
                else
                  Lisp::ConsCell.array_to_list(args.to_a.map {|i| i.evaluate(env)})
                end
  @implementation.call(cooked_args, env)
end

#apply_to_without_evaluating(args, env) ⇒ Object



55
56
57
58
# File 'lib/rubylisp/primitive.rb', line 55

def apply_to_without_evaluating(args, env)
  return Lisp::Debug.process_error("Wrong number of arguments to #{@name}. Expected #{@arity} but got #{args.length}.", env) unless check_arity(args)
  @implementation.call(args, env)
end

#check_arity(args) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/rubylisp/primitive.rb', line 23

def check_arity(args)
  return true if @arity == "*"

  number_of_args = args.length

  @arity.split("|").map do |term|
    m = /^(\d+)$/.match(term)
    return true if m && number_of_args == m[1].to_i

    m = /^>=(\d+)$/.match(term)
    return true if m && number_of_args >= m[1].to_i
    
    m = /^\((\d+),(\d+)\)$/.match(term)
    return true if m && number_of_args >= m[1].to_i && number_of_args <= m[2].to_i
  end

  false
end

#primitive?Boolean

Returns:



70
71
72
# File 'lib/rubylisp/primitive.rb', line 70

def primitive?
  true
end

#special?Boolean

Returns:



75
76
77
# File 'lib/rubylisp/primitive.rb', line 75

def special?
  @special
end

#to_sObject



61
62
63
64
65
66
67
# File 'lib/rubylisp/primitive.rb', line 61

def to_s
  if @special
    "<specialform: #{@name}>"
  else
    "<primitive: #{@name}>"
  end
end

#typeObject



80
81
82
83
84
85
86
# File 'lib/rubylisp/primitive.rb', line 80

def type
  if @special
    :specialform
  else
    :primitive
  end
end