rubylisp 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/rubylisp +14 -0
- data/lib/rubylisp/alist.rb +230 -0
- data/lib/rubylisp/assignment.rb +65 -0
- data/lib/rubylisp/atom.rb +149 -0
- data/lib/rubylisp/binding.rb +17 -0
- data/lib/rubylisp/boolean.rb +49 -0
- data/lib/rubylisp/builtins.rb +31 -0
- data/lib/rubylisp/character.rb +383 -0
- data/lib/rubylisp/cons_cell.rb +255 -0
- data/lib/rubylisp/environment_frame.rb +116 -0
- data/lib/rubylisp/equivalence.rb +118 -0
- data/lib/rubylisp/exception.rb +98 -0
- data/lib/rubylisp/ext.rb +122 -0
- data/lib/rubylisp/ffi_class.rb +162 -0
- data/lib/rubylisp/ffi_new.rb +32 -0
- data/lib/rubylisp/ffi_send.rb +83 -0
- data/lib/rubylisp/ffi_static.rb +22 -0
- data/lib/rubylisp/frame.rb +284 -0
- data/lib/rubylisp/function.rb +92 -0
- data/lib/rubylisp/io.rb +74 -0
- data/lib/rubylisp/list_support.rb +527 -0
- data/lib/rubylisp/logical.rb +38 -0
- data/lib/rubylisp/macro.rb +95 -0
- data/lib/rubylisp/math.rb +403 -0
- data/lib/rubylisp/number.rb +63 -0
- data/lib/rubylisp/object.rb +62 -0
- data/lib/rubylisp/parser.rb +184 -0
- data/lib/rubylisp/primitive.rb +45 -0
- data/lib/rubylisp/relational.rb +46 -0
- data/lib/rubylisp/special_forms.rb +454 -0
- data/lib/rubylisp/string.rb +841 -0
- data/lib/rubylisp/symbol.rb +56 -0
- data/lib/rubylisp/system.rb +19 -0
- data/lib/rubylisp/testing.rb +136 -0
- data/lib/rubylisp/tokenizer.rb +292 -0
- data/lib/rubylisp/type_checks.rb +58 -0
- data/lib/rubylisp/vector.rb +114 -0
- data/lib/rubylisp.rb +1 -0
- metadata +82 -0
@@ -0,0 +1,116 @@
|
|
1
|
+
module Lisp
|
2
|
+
|
3
|
+
class EnvironmentFrame
|
4
|
+
|
5
|
+
attr_accessor :frame
|
6
|
+
|
7
|
+
def self.global
|
8
|
+
@@global_frame ||= EnvironmentFrame.new(nil)
|
9
|
+
@@global_frame
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.extending(parent, f=nil)
|
13
|
+
f ||= parent.frame if parent && parent.has_frame?
|
14
|
+
self.new(parent, f)
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(parent, f=nil)
|
18
|
+
@bindings = []
|
19
|
+
@parent = parent
|
20
|
+
@frame = f
|
21
|
+
end
|
22
|
+
|
23
|
+
def has_frame?
|
24
|
+
!@frame.nil?
|
25
|
+
end
|
26
|
+
|
27
|
+
# Bindings following parent env frame pointer
|
28
|
+
|
29
|
+
def is_name_bound?(str)
|
30
|
+
if !@frame && @frame.has_slot?(Lisp:Symbol.named("#{str}:", true))
|
31
|
+
return true
|
32
|
+
end
|
33
|
+
|
34
|
+
binding = @bindings.detect {|b| b.symbol.name == str}
|
35
|
+
return true unless binding.nil?
|
36
|
+
return false if @parent.nil?
|
37
|
+
return @parent.is_name_bound?(str)
|
38
|
+
end
|
39
|
+
|
40
|
+
def binding_for(symbol)
|
41
|
+
binding = @bindings.detect {|b| b.symbol.name == symbol.name}
|
42
|
+
return binding unless binding.nil?
|
43
|
+
return @parent.binding_for(symbol) unless @parent.nil?
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
|
47
|
+
def bind(symbol, value)
|
48
|
+
b = self.binding_for(symbol)
|
49
|
+
if b.nil?
|
50
|
+
@bindings << Lisp::Binding.new(symbol, value)
|
51
|
+
else
|
52
|
+
b.value = value
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def set(symbol, value)
|
57
|
+
naked_symbol = symbol.to_naked
|
58
|
+
if @frame && @frame.has_slot?(naked_symbol)
|
59
|
+
return @frame.at_put(naked_symbol, value)
|
60
|
+
end
|
61
|
+
|
62
|
+
b = self.binding_for(symbol)
|
63
|
+
if b.nil?
|
64
|
+
raise "#{symbol} is undefined."
|
65
|
+
else
|
66
|
+
b.value = value
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Bindings local to this env frame only
|
71
|
+
|
72
|
+
def local_binding_for(symbol)
|
73
|
+
@bindings.detect {|b| b.symbol.name == symbol.name}
|
74
|
+
end
|
75
|
+
|
76
|
+
def bind_locally(symbol, value)
|
77
|
+
b = self.local_binding_for(symbol)
|
78
|
+
if b.nil?
|
79
|
+
@bindings << Lisp::Binding.new(symbol, value)
|
80
|
+
else
|
81
|
+
b.value = value
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Look up a symbol
|
86
|
+
|
87
|
+
def value_of(symbol)
|
88
|
+
b = local_binding_for(symbol)
|
89
|
+
return b.value unless b.nil?
|
90
|
+
|
91
|
+
naked_symbol = symbol.to_naked
|
92
|
+
if @frame && @frame.has_slot?(naked_symbol)
|
93
|
+
return @frame.get(naked_symbol)
|
94
|
+
end
|
95
|
+
|
96
|
+
b = binding_for(symbol)
|
97
|
+
return b.value unless b.nil?
|
98
|
+
nil
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
def quick_value_of(symbol_name)
|
103
|
+
b = binding_for(Symbol.new(symbol_name))
|
104
|
+
b.nil? ? nil : b.value
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
def dump
|
109
|
+
@bindings.each do |b|
|
110
|
+
puts b.to_s
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
module Lisp
|
2
|
+
|
3
|
+
class Equivalence
|
4
|
+
|
5
|
+
def self.register
|
6
|
+
Primitive.register("=", "(= number number)\n\nReturns whether the first numeric argument is equal to the second numeric argument.") do |args, env|
|
7
|
+
Lisp::Equivalence::num_eq_impl(args, env)
|
8
|
+
end
|
9
|
+
|
10
|
+
Primitive.register("==", "(== number number)\n\nReturns whether the first numeric argument is equal to the second numeric argument.") do |args, env|
|
11
|
+
Lisp::Equivalence::num_eq_impl(args, env)
|
12
|
+
end
|
13
|
+
|
14
|
+
Primitive.register("!=", "(!= number number)\n\nReturns whether the first numeric argument is not equal to the second numeric argument.") do |args, env|
|
15
|
+
Lisp::Equivalence::num_neq_impl(args, env)
|
16
|
+
end
|
17
|
+
|
18
|
+
Primitive.register("/=", "(/= number number)\n\nReturns whether the first numeric argument is not equal to the second numeric argument.") do |args, env|
|
19
|
+
Lisp::Equivalence::num_neq_impl(args, env)
|
20
|
+
end
|
21
|
+
|
22
|
+
Primitive.register("eq?", "(eq? sexpr sexpr)\n\nReturns whether the first argument is the same type as the second argument, and the same object, except in the case of numbers where the values are compared.") do |args, env|
|
23
|
+
Lisp::Equivalence::eq_impl(args, env)
|
24
|
+
end
|
25
|
+
|
26
|
+
Primitive.register("eqv?", "(eqv? sexpr sexpr)\n\nReturns whether the first argument is the same type as the second argument, and the same object, except in the case of numbers where the values are compared.") do |args, env|
|
27
|
+
Lisp::Equivalence::eqv_impl(args, env)
|
28
|
+
end
|
29
|
+
|
30
|
+
Primitive.register("equal?", "(equal? sexpr sexpr)\n\nReturns whether the first argument is the same type as the second argument, and are lists containing the same elements, are identical strings, are frames with matching slots, are numbers with the same value, or are the same object (if none of the above).") do |args, env|
|
31
|
+
Lisp::Equivalence::equal_impl(args, env)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
# == - Check two integers for equivalence
|
37
|
+
|
38
|
+
def self.num_eq_impl(args, env)
|
39
|
+
raise "= and == need 2 arguments, received #{args.length}" if args.length != 2
|
40
|
+
c1 = args.car.evaluate(env)
|
41
|
+
c2 = args.cadr.evaluate(env)
|
42
|
+
return Lisp::FALSE unless c1.integer? && c2.integer?
|
43
|
+
Lisp::Boolean.with_value(c1.value == c2.value)
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.num_neq_impl(args, env)
|
47
|
+
raise "!= and /= needs 2 arguments, received #{args.length}" if args.length != 2
|
48
|
+
c1 = args.car.evaluate(env)
|
49
|
+
c2 = args.cadr.evaluate(env)
|
50
|
+
return Lisp::TRUE unless c1.integer? && c2.integer?
|
51
|
+
Lisp::Boolean.with_value(c1.value != c2.value)
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
# eq? - identity, typically used for symbols
|
56
|
+
|
57
|
+
def self.eq_check(o1, o2)
|
58
|
+
return Lisp::FALSE unless o1.type == o2.type
|
59
|
+
Lisp::Boolean.with_value(case o1.type
|
60
|
+
when :number
|
61
|
+
(o1.integer? == o2.integer?) && (o1.value == o2.value)
|
62
|
+
else
|
63
|
+
o1.equal?(o2)
|
64
|
+
end)
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
def self.eq_impl(args, env)
|
69
|
+
raise "eq? needs 2 arguments, received #{args.length}" if args.length != 2
|
70
|
+
o1 = args.car.evaluate(env)
|
71
|
+
o2 = args.cadr.evaluate(env)
|
72
|
+
eq_check(o1, o2)
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
# eqv? - same as eq?
|
77
|
+
|
78
|
+
def self.eqv_check(o1, o2)
|
79
|
+
eq_check(o1, o2)
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
def self.eqv_impl(args, env)
|
84
|
+
raise "eq? needs 2 arguments, received #{args.length}" if args.length != 2
|
85
|
+
o1 = args.car.evaluate(env)
|
86
|
+
o2 = args.cadr.evaluate(env)
|
87
|
+
eqv_check(o1, o2)
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
# equal? - object equality: same value
|
92
|
+
|
93
|
+
def self.equal_check(o1, o2)
|
94
|
+
return Lisp::FALSE unless o1.type == o2.type
|
95
|
+
Lisp::Boolean.with_value(case o1.type
|
96
|
+
when :pair
|
97
|
+
o1.eq?(o2)
|
98
|
+
when :string
|
99
|
+
o1.value.eql?(o2.value)
|
100
|
+
when :frame
|
101
|
+
o1.eq?(o2)
|
102
|
+
when :number
|
103
|
+
(o1.integer? == o2.integer?) && (o1.value == o2.value)
|
104
|
+
else
|
105
|
+
o1.equal?(o2)
|
106
|
+
end)
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
def self.equal_impl(args, env)
|
111
|
+
raise "equal? needs 2 arguments, received #{args.length}" if args.length != 2
|
112
|
+
o1 = args.car.evaluate(env)
|
113
|
+
o2 = args.cadr.evaluate(env)
|
114
|
+
self.equal_check(o1, o2)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module Lisp
|
2
|
+
|
3
|
+
class Exception
|
4
|
+
|
5
|
+
def self.register
|
6
|
+
Primitive.register("raise") {|args, env| Lisp::Exception::raise_impl(args, env) }
|
7
|
+
Primitive.register("reraise") {|args, env| Lisp::Exception::reraise_impl(args, env) }
|
8
|
+
Primitive.register("try") {|args, env| Lisp::Exception::try_impl(args, env) }
|
9
|
+
Primitive.register("reraise") {|args, env| Lisp::Exception::reraise_impl(args, env) }
|
10
|
+
Primitive.register("resume") {|args, env| Lisp::Exception::resume_impl(args, env) }
|
11
|
+
Primitive.register("restart") {|args, env| Lisp::Exception::restart_impl(args, env) }
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def handler_or_nil(handlers, exception_name)
|
16
|
+
handlers.each do |handler_pair|
|
17
|
+
exceptions = handler_pair.car
|
18
|
+
if exceptions.eq(exception_name) || (exceptions.pair? && exceptions.include?(exception_name))
|
19
|
+
handler_pair.cdr
|
20
|
+
else
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.do_exception(name, with_message, args, env)
|
27
|
+
frame = env
|
28
|
+
while !frame.nil?
|
29
|
+
handlers = frame.value_of(Symbol.named("__handlers__"))
|
30
|
+
unless handlers.nil?
|
31
|
+
handler = handler_or_nil(handlers, for: name)
|
32
|
+
unless handler.nil?
|
33
|
+
handler.apply_to_without_evaluating(args, in: frame)
|
34
|
+
break
|
35
|
+
end
|
36
|
+
end
|
37
|
+
frame = frame.parent
|
38
|
+
if frame.nil?
|
39
|
+
exception_message = message.empty? ? "" : ": #{message}"
|
40
|
+
raise "Unhandled Exception: #{exception_name}#{exception_message}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.raise_impl(args, env)
|
46
|
+
raise "'raise' requires at least one argument." unless args.length > 0
|
47
|
+
exception_name = args.car.evaluate(env)
|
48
|
+
raise "'raise' requires an exception name as it's first argument." unless exception_name.string? || class_name.symbol?
|
49
|
+
|
50
|
+
message = ""
|
51
|
+
if args.length > 1
|
52
|
+
message = args.cadr.evaluate(env)
|
53
|
+
raise "The message parameter to 'raise' must be a string." unless message.string?
|
54
|
+
end
|
55
|
+
|
56
|
+
handler_args = args.length > 2 ? Lisp::ConsCell.array_to_list(args.cdr.to_a.collect {|a| a.evaluate(env)}) : Lisp::ConsCell.new
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
def self.try_impl(args, env)
|
61
|
+
raw_handlers = args.car
|
62
|
+
body = args.cdr
|
63
|
+
|
64
|
+
raise "Exception handlers must be a list." unless raw_handlers.list?
|
65
|
+
raise "Exception handlers must be a list of pairs." unless raw_handlers.all? {|h| h.list?}
|
66
|
+
raise "Exception clause must be a symbol/string or a list of symbol/string." unless raw_handlers.all? do |h|
|
67
|
+
ex = h.car
|
68
|
+
ex.symbol? || ex.string? || (ex.list? && ex.all? {|h2| h2.symbol? || h2.string?})
|
69
|
+
end
|
70
|
+
|
71
|
+
array_of_handlers = raw_handlers.to_a.collect do |h|
|
72
|
+
ex = h.car
|
73
|
+
f = h.cadr.evaluate(env)
|
74
|
+
raise "Exception handler has to be a function." unless f.function?
|
75
|
+
Lisp::ConsCell.cons(ex, f)
|
76
|
+
end
|
77
|
+
handlers = Lisp::ConsCell.array_to_list(array_of_handlers)
|
78
|
+
env.bind_locally(Symbol.named("__handlers__"), handlers)
|
79
|
+
|
80
|
+
body.evaluate_each(env)
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
def self.reraise_impl(args, env)
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
def self.resume_impl(args, env)
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
def self.restart_impl(args, env)
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
data/lib/rubylisp/ext.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
class NilClass
|
2
|
+
|
3
|
+
def true?
|
4
|
+
false
|
5
|
+
end
|
6
|
+
|
7
|
+
def false?
|
8
|
+
true
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
"()"
|
13
|
+
end
|
14
|
+
|
15
|
+
def eq?(other)
|
16
|
+
other.nil?
|
17
|
+
end
|
18
|
+
|
19
|
+
def print_string
|
20
|
+
self.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
def evaluate(env)
|
24
|
+
nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def evaluate_each(env)
|
28
|
+
nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def car
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def cdr
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
|
39
|
+
def set_car!(s)
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
|
43
|
+
def set_cdr!(s)
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
|
47
|
+
def quoted
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
|
51
|
+
def empty?
|
52
|
+
true
|
53
|
+
end
|
54
|
+
|
55
|
+
def length
|
56
|
+
0
|
57
|
+
end
|
58
|
+
|
59
|
+
def value
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
|
63
|
+
def string?
|
64
|
+
false
|
65
|
+
end
|
66
|
+
|
67
|
+
def number?
|
68
|
+
false
|
69
|
+
end
|
70
|
+
|
71
|
+
def symbol?
|
72
|
+
false
|
73
|
+
end
|
74
|
+
|
75
|
+
def pair?
|
76
|
+
false
|
77
|
+
end
|
78
|
+
|
79
|
+
def list?
|
80
|
+
true
|
81
|
+
end
|
82
|
+
|
83
|
+
def method_missing(name, *args, &block)
|
84
|
+
if name[0] == ?c && name[-1] == ?r && (name[1..-2].chars.all? {|e| "ad".include?(e)})
|
85
|
+
nil
|
86
|
+
else
|
87
|
+
super
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def primitive?
|
92
|
+
false
|
93
|
+
end
|
94
|
+
|
95
|
+
def function?
|
96
|
+
false
|
97
|
+
end
|
98
|
+
|
99
|
+
def object?
|
100
|
+
false
|
101
|
+
end
|
102
|
+
|
103
|
+
def type
|
104
|
+
:nil
|
105
|
+
end
|
106
|
+
|
107
|
+
def lisp_object?
|
108
|
+
true
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
class Object
|
117
|
+
|
118
|
+
def lisp_onject?
|
119
|
+
false
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module Lisp
|
3
|
+
|
4
|
+
class ClassObject < Atom
|
5
|
+
|
6
|
+
def self.register
|
7
|
+
Primitive.register("extend", "(extend parent child)\n\nCreates a new class named child that extends (i.e. inherits from) the class parent. The names (parent and child can be either stirngs or symbols). The new class is accessible by name and is returned.") do |args, env|
|
8
|
+
Lisp::ClassObject::extend_impl(args, env)
|
9
|
+
end
|
10
|
+
|
11
|
+
Primitive.register("add-method", "(add-method class selector function)\n\nAdd a method named selector to the class named class using function as it’s body. function can be a reference to a named function or, more likely, a lambda expression.") do |args, env|
|
12
|
+
Lisp::ClassObject::add_method_impl(args, env)
|
13
|
+
end
|
14
|
+
|
15
|
+
Primitive.register("add-static-method", "Not Implemented.") do |args, env|
|
16
|
+
Lisp::ClassObject::add_static_method_impl(args, env)
|
17
|
+
end
|
18
|
+
|
19
|
+
Primitive.register("super", "Not implemented.") do |args, env|
|
20
|
+
Lisp::ClassObject::super_impl(args, env)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def self.extend_impl(args, env)
|
27
|
+
raise "'extend' requires 2 arguments." if args.length != 2
|
28
|
+
|
29
|
+
class_name = args.car.evaluate(env)
|
30
|
+
raise "'extend' requires a name as it's first argument." unless class_name.string? || class_name.symbol?
|
31
|
+
super_class = Object.const_get(class_name.to_s)
|
32
|
+
raise "'extend' requires the name of an existing class as it's first argument." if super_class.nil?
|
33
|
+
|
34
|
+
new_class_name = args.cadr.evaluate(env)
|
35
|
+
raise "'extend' requires a name as it's second argument." unless new_class_name.string? || new_class_name.symbol?
|
36
|
+
new_class = Class.new(super_class)
|
37
|
+
raise "'extend' requires the name of a new (i.e. nonexistant) class as it's second argument." if Object.const_defined?(new_class_name.to_s)
|
38
|
+
|
39
|
+
Object.const_set(new_class_name.to_s, new_class)
|
40
|
+
ClassObject.with_class(new_class)
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
def self.convert_to_lisp(value)
|
45
|
+
case value.class.name
|
46
|
+
when "Fixnum", "Float"
|
47
|
+
Lisp::Number.with_value(value)
|
48
|
+
when "TrueClass"
|
49
|
+
Lisp::Boolean.TRUE
|
50
|
+
when "FalseClass"
|
51
|
+
Lisp::Boolean.FALSE
|
52
|
+
when "String"
|
53
|
+
Lisp::String.with_value(value)
|
54
|
+
when "Symbol"
|
55
|
+
Lisp::Symbol.named(value)
|
56
|
+
when "Array"
|
57
|
+
Lisp::ConsCell.array_to_list(value.map {|a| convert_to_lisp(a)})
|
58
|
+
else
|
59
|
+
value.lisp_object? ? value : Lisp::NativeObject.with_value(value)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
def self.convert_to_ruby(a, env)
|
65
|
+
if a.nil?
|
66
|
+
nil
|
67
|
+
elsif a.function?
|
68
|
+
proc do
|
69
|
+
a.apply_to(Lisp::ConsCell.new, env)
|
70
|
+
end
|
71
|
+
elsif a.list?
|
72
|
+
a.to_a.map {|i| convert_to_ruby(i, env)}
|
73
|
+
else
|
74
|
+
a.value
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
def self.add_method_impl(args, env)
|
80
|
+
raise "'add-method' requires 3 arguments." if args.length != 3
|
81
|
+
class_name = args.car.evaluate(env)
|
82
|
+
raise "'add-method' requires a class name as it's first argument." unless class_name.string? || class_name.symbol?
|
83
|
+
target_class = Object.const_get(class_name.to_s)
|
84
|
+
raise "'add-method' requires the name of an existing class." if target_class.nil?
|
85
|
+
|
86
|
+
method_name = args.cadr.evaluate(env)
|
87
|
+
raise "'add-method' requires a method name as it's second argument." unless class_name.string? || class_name.symbol?
|
88
|
+
|
89
|
+
body = args.caddr.evaluate(env)
|
90
|
+
raise "'add-method' requires a function as it's third argument." unless body.function?
|
91
|
+
|
92
|
+
target_class.send(:define_method, method_name.to_s) do |*args|
|
93
|
+
local_env = Lisp::EnvironmentFrame.extending(env)
|
94
|
+
local_env.bind_locally(Symbol.named("self"), Lisp::NativeObject.with_value(self))
|
95
|
+
processed_args = args.map {|a| Lisp::ClassObject.convert_to_lisp(a)}
|
96
|
+
Lisp::ClassObject.convert_to_ruby(body.apply_to(Lisp::ConsCell.array_to_list(processed_args), in: local_env), in: local_env)
|
97
|
+
end
|
98
|
+
Lisp::String.with_value("OK")
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
def self.super_impl(args, env)
|
103
|
+
Lisp::String.with_value("NOT IMPLEMENTED")
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
def self.add_static_method_impl(args, env)
|
108
|
+
Lisp::String.with_value("NOT IMPLEMENTED")
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
def self.new_instance
|
113
|
+
self.new(@value.alloc.init)
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
def self.with_class(c)
|
118
|
+
self.new(c)
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
def initialize(c)
|
123
|
+
@value = c
|
124
|
+
end
|
125
|
+
|
126
|
+
|
127
|
+
def with_value(&block)
|
128
|
+
block.call(@value)
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
def class?
|
133
|
+
true
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
def type
|
138
|
+
:class
|
139
|
+
end
|
140
|
+
|
141
|
+
|
142
|
+
def native_type
|
143
|
+
@value.class
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
def to_s
|
148
|
+
"<a class: #{@value.name}>"
|
149
|
+
end
|
150
|
+
|
151
|
+
|
152
|
+
def true?
|
153
|
+
@value != nil
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
def false?
|
158
|
+
@value == nil
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Lisp
|
2
|
+
|
3
|
+
class FfiNew < Atom
|
4
|
+
|
5
|
+
def initialize(name)
|
6
|
+
@value = name
|
7
|
+
@klass = Object.const_get(name)
|
8
|
+
end
|
9
|
+
|
10
|
+
def apply_to(args, env)
|
11
|
+
NativeObject.with_value(@klass.new)
|
12
|
+
end
|
13
|
+
|
14
|
+
def apply_to_without_evaluating(args, env)
|
15
|
+
NativeObject.with_value(@klass.new)
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
"#{@value}."
|
20
|
+
end
|
21
|
+
|
22
|
+
def primitive?
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
def type
|
27
|
+
:primitive
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|