Class: Lisp::FfiSend

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

Direct Known Subclasses

FfiStatic

Instance Attribute Summary

Attributes inherited from Atom

#value

Instance Method Summary collapse

Methods inherited from Atom

#alist?, #all?, #car, #cdr, #character?, #class?, #copy, #doc, #eq?, #evaluate, #false?, #frame?, #function?, #length, #lisp_object?, #list?, #macro?, #negative?, #number?, #object?, #pair?, #positive?, #print_string, #quoted, #set!, #special?, #string?, #symbol?, #true?, #vector?, #zero?

Constructor Details

#initialize(name) ⇒ FfiSend



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

def initialize(name)
  @value = name.to_sym
end

Instance Method Details

#apply_to(args, env) ⇒ Object



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

def apply_to(args, env)
  apply_to_without_evaluating(Lisp::ConsCell.array_to_list(args.to_a.map {|a| a.evaluate(env)}), env)
end

#apply_to_without_evaluating(args, env) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/rubylisp/ffi_send.rb', line 47

def apply_to_without_evaluating(args, env)
  target = args.car
  raise "Send target of '#{@value}' evaluated to nil." if target.nil?
  raise "Target of an FFI send of '#{@value}' must be a wrapped ObjC object, was #{target}" unless target.object?

  arguments = args.cdr.nil? ? [] : args.cdr.to_a.map {|a| process_arg(a, env)}      
  result = nil
  
  begin
    result = if arguments[-1].instance_of?(Proc)
               target.value.send(@value, *(arguments[0..-2]), &arguments[-1])
             else
#                   puts "Sending #{@value} with #{arguments}"
               target.value.send(@value, *arguments)
             end
  rescue Exception => e
    raise "Exception sending #{@value}: #{e}"
  end

  convert_value(result)
end

#convert_value(value) ⇒ Object



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/rubylisp/ffi_send.rb', line 13

def convert_value(value)
  case value.class.name
  when "Fixnum", "Float"
    Lisp::Number.with_value(value)
  when "TrueClass"
    Lisp::Boolean.TRUE
  when "FalseClass"
    Lisp::Boolean.FALSE
  when "String"
    Lisp::String.with_value(value)
  when "Symbol"
    Lisp::Symbol.named(value)
  when "Array"
    Lisp::ConsCell.array_to_list(value.map {|a| convert_value(a)})
  else
    Lisp::NativeObject.with_value(value)
  end
end

#primitive?Boolean



73
74
75
# File 'lib/rubylisp/ffi_send.rb', line 73

def primitive?
  true
end

#process_arg(a, env) ⇒ Object



33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/rubylisp/ffi_send.rb', line 33

def process_arg(a, env)
  if a.function?
    proc do |*args|
      arg_list = args.empty? ? nil : Lisp::ConsCell.array_to_list(args.collect {|arg| convert_value(arg) })
      a.apply_to(arg_list, env)
    end
  elsif a.list?
    a.to_a.map {|i| process_arg(i, env)}
  else
    a.value
  end
end

#to_sObject



69
70
71
# File 'lib/rubylisp/ffi_send.rb', line 69

def to_s
  ".#{@value}"
end

#typeObject



77
78
79
# File 'lib/rubylisp/ffi_send.rb', line 77

def type
  :primitive
end