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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3e43b771e458951f6724a4ea368359b651af68aa
|
4
|
+
data.tar.gz: 32043fab0730d6414558a3fed26e3063b0a16943
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 13a455aa9220f5f7850a5a2f9e6c54f2544cc6b5f946d3529cc056a0d4b589ca856f426da3604f22e1c986ff7535b1b96690a08fd4d30f25883eed3c2151a23a
|
7
|
+
data.tar.gz: c5fd927f7d655390e1dc5d9a415f1ccb04fb1ed775e59d8b60aa5b16da3eb19325aeb99bc74aff20ef76321736c7c6866fbb77593deefad49bcee2a404b7499d
|
data/bin/rubylisp
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubylisp'
|
4
|
+
require 'readline'
|
5
|
+
|
6
|
+
Lisp::Initializer.register_builtins
|
7
|
+
|
8
|
+
puts 'RubyLisp REPL'
|
9
|
+
parser = Lisp::Parser.new
|
10
|
+
|
11
|
+
while line = Readline.readline('> ', true)
|
12
|
+
puts parser.parse(line).evaluate(Lisp::EnvironmentFrame.global).to_s
|
13
|
+
end
|
14
|
+
|
@@ -0,0 +1,230 @@
|
|
1
|
+
module Lisp
|
2
|
+
|
3
|
+
class AList < Object
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
def self.register
|
7
|
+
Primitive.register("acons") {|args, env| Lisp::AList::acons_impl(args, env) }
|
8
|
+
Primitive.register("assoc") {|args, env| Lisp::AList::assoc_impl(args, env) }
|
9
|
+
Primitive.register("rassoc") {|args, env| Lisp::AList::rassoc_impl(args, env) }
|
10
|
+
Primitive.register("dissoc") {|args, env| Lisp::AList::dissoc_impl(args, env) }
|
11
|
+
Primitive.register("zip") {|args, env| Lisp::AList::zip_impl(args, env) }
|
12
|
+
Primitive.register("alist-to-list") {|args, env| Lisp::AList::alist_to_list_impl(args, env) }
|
13
|
+
Primitive.register("list-to-alist") {|args, env| Lisp::AList::list_to_alist_impl(args, env) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.acons_impl(args, env)
|
17
|
+
raise "acons require at least 2 or 3 arguments" unless args.length == 2 || args.length == 3
|
18
|
+
key = args.car.evaluate(env)
|
19
|
+
value = args.cadr.evaluate(env)
|
20
|
+
alist = args.length == 2 ? nil : args.caddr.evaluate(env)
|
21
|
+
alist = Lisp::AList.from_list(alist) if !alist.nil? && alist.list? && !alist.alist?
|
22
|
+
raise "the last argument to acons has to be an association list" unless alist.nil? || alist.alist?
|
23
|
+
|
24
|
+
if alist.nil?
|
25
|
+
Lisp::AList.new({key => value})
|
26
|
+
else
|
27
|
+
alist.acons(key, value)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.assoc_impl(args, env)
|
32
|
+
raise "assoc require 2 arguments" unless args.length == 2
|
33
|
+
key = args.car.evaluate(env)
|
34
|
+
alist = args.cadr.evaluate(env)
|
35
|
+
alist = Lisp::AList.from_list(alist) if alist.list? && !alist.alist?
|
36
|
+
raise "the last argument to assoc has to be an association list" unless alist.alist?
|
37
|
+
alist.assoc(key)
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.rassoc_impl(args, env)
|
41
|
+
raise "assoc require 2 arguments" unless args.length == 2
|
42
|
+
value = args.car.evaluate(env)
|
43
|
+
alist = args.cadr.evaluate(env)
|
44
|
+
alist = Lisp::AList.from_list(alist) if alist.list? && !alist.alist?
|
45
|
+
raise "the last argument to rassoc has to be an association list" unless alist.alist?
|
46
|
+
alist.rassoc(value)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.dissoc_impl(args, env)
|
50
|
+
raise "assoc require 2 arguments" unless args.length == 2
|
51
|
+
key = args.car.evaluate(env)
|
52
|
+
alist = args.cadr.evaluate(env)
|
53
|
+
alist = Lisp::AList.from_list(alist) if alist.list? && !alist.alist?
|
54
|
+
raise "the last argument to dissoc has to be an association list" unless alist.alist?
|
55
|
+
alist.dissoc(key)
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.zip_impl(args, env)
|
59
|
+
raise "assoc require 2 or 3arguments" unless args.length == 2 || args.length == 3
|
60
|
+
key_list = args.car.evaluate(env)
|
61
|
+
raise "the keys supplied to zip has to be a list" unless key_list.list?
|
62
|
+
value_list = args.cadr.evaluate(env)
|
63
|
+
raise "the values supplied to zip has to be a list" unless value_list.list?
|
64
|
+
raise "zip requires the same number of keys and values" unless key_list.length == value_list.length
|
65
|
+
|
66
|
+
if args.length == 3
|
67
|
+
alist = args.caddr.evaluate(env)
|
68
|
+
alist = Lisp::AList.from_list(alist) if alist.list? && !alist.alist?
|
69
|
+
raise "the third argument to zip has to be an association list" unless alist.alist?
|
70
|
+
alist.zip(key_list.to_a, value_list.to_a)
|
71
|
+
else
|
72
|
+
Lisp::AList.zip(key_list.to_a, value_list.to_a)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.alist_to_list_impl(args, env)
|
77
|
+
raise "alist-to-list requires 1 arguments" unless args.length == 1
|
78
|
+
alist = args.car.evaluate(env)
|
79
|
+
return alist if alist.list? && !alist.alist?
|
80
|
+
raise "the argument to alist-to-list has to be an association list" unless alist.alist?
|
81
|
+
|
82
|
+
alist.to_list
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.list_to_alist_impl(args, env)
|
86
|
+
raise "list-to-alist requires 1 arguments" unless args.length == 1
|
87
|
+
list = args.car.evaluate(env)
|
88
|
+
raise "the argument to list-to-alist has to be a list" unless list.list?
|
89
|
+
|
90
|
+
Lisp::AList.from_list(list)
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
def initialize(h=nil)
|
95
|
+
@value = h || {}
|
96
|
+
end
|
97
|
+
|
98
|
+
def lisp_object?
|
99
|
+
true
|
100
|
+
end
|
101
|
+
|
102
|
+
def eq?(sexpr)
|
103
|
+
return false unless sexpr.alist?
|
104
|
+
@value == sexpr.value
|
105
|
+
end
|
106
|
+
|
107
|
+
def empty?
|
108
|
+
@value.empty?
|
109
|
+
end
|
110
|
+
|
111
|
+
def string?
|
112
|
+
false
|
113
|
+
end
|
114
|
+
|
115
|
+
def character?
|
116
|
+
false
|
117
|
+
end
|
118
|
+
|
119
|
+
def number?
|
120
|
+
false
|
121
|
+
end
|
122
|
+
|
123
|
+
def positive?
|
124
|
+
false
|
125
|
+
end
|
126
|
+
|
127
|
+
def zero?
|
128
|
+
false
|
129
|
+
end
|
130
|
+
|
131
|
+
def negative?
|
132
|
+
false
|
133
|
+
end
|
134
|
+
|
135
|
+
def symbol?
|
136
|
+
false
|
137
|
+
end
|
138
|
+
|
139
|
+
def primitive?
|
140
|
+
false
|
141
|
+
end
|
142
|
+
|
143
|
+
def function?
|
144
|
+
false
|
145
|
+
end
|
146
|
+
|
147
|
+
def macro?
|
148
|
+
false
|
149
|
+
end
|
150
|
+
|
151
|
+
def pair?
|
152
|
+
true
|
153
|
+
end
|
154
|
+
|
155
|
+
def list?
|
156
|
+
true
|
157
|
+
end
|
158
|
+
|
159
|
+
def alist?
|
160
|
+
true
|
161
|
+
end
|
162
|
+
|
163
|
+
def frame?
|
164
|
+
false
|
165
|
+
end
|
166
|
+
|
167
|
+
def length
|
168
|
+
return @value.length
|
169
|
+
end
|
170
|
+
|
171
|
+
def car
|
172
|
+
@value.first
|
173
|
+
end
|
174
|
+
|
175
|
+
def cdr
|
176
|
+
end
|
177
|
+
|
178
|
+
def acons(k, v)
|
179
|
+
@value[k] = v
|
180
|
+
self
|
181
|
+
end
|
182
|
+
|
183
|
+
def assoc(k)
|
184
|
+
v = @value[k]
|
185
|
+
Lisp::ConsCell.cons(k, v)
|
186
|
+
end
|
187
|
+
|
188
|
+
def rassoc(value)
|
189
|
+
@value.each do |k, v|
|
190
|
+
return Lisp::ConsCell.cons(k, v) if value == v || value.eq?(v)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def dissoc(k)
|
195
|
+
@value.delete(k)
|
196
|
+
self
|
197
|
+
end
|
198
|
+
|
199
|
+
def zip(keys, values)
|
200
|
+
keys.zip(values).each {|k, v| @value[k] = v}
|
201
|
+
self
|
202
|
+
end
|
203
|
+
|
204
|
+
def self.zip(keys, values)
|
205
|
+
self.new.zip(keys, values)
|
206
|
+
end
|
207
|
+
|
208
|
+
def self.from_list(list)
|
209
|
+
h = {}
|
210
|
+
list.each do |pair|
|
211
|
+
h[pair.car] = pair.cdr
|
212
|
+
end
|
213
|
+
self.new(h)
|
214
|
+
end
|
215
|
+
|
216
|
+
def to_list
|
217
|
+
Lisp::ConsCell.array_to_list(@value.map {|k, v| Lisp::ConsCell.cons(k, v)})
|
218
|
+
end
|
219
|
+
|
220
|
+
def to_s
|
221
|
+
to_list.to_s
|
222
|
+
end
|
223
|
+
|
224
|
+
def print_string
|
225
|
+
self.to_s
|
226
|
+
end
|
227
|
+
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Lisp
|
2
|
+
|
3
|
+
class Assignment
|
4
|
+
|
5
|
+
def self.register
|
6
|
+
Primitive.register("set!", "(set! _name_ _new-value_)\n\nThe way to assign (i.e. rebind) a symbol. `name` is the symbol to be rebound.
|
7
|
+
The `new-value` sexpr is evaluated to arrive at the new value to be bound to. Use of `set!` is frowned upon, and should not be used without thought.") do |args, env|
|
8
|
+
Lisp::Assignment::setbang_impl(args, env)
|
9
|
+
end
|
10
|
+
|
11
|
+
Primitive.register("set-car!", "(set-car! _cons-cell_ _new-value_)\n\nSet the `car` pointer of `cons-cell`.") do |args, env|
|
12
|
+
Lisp::Assignment::setcarbang_impl(args, env)
|
13
|
+
end
|
14
|
+
|
15
|
+
Primitive.register("set-cdr!", "(set-cdr! _cons-cell_ _new-value_)\n\nSet the `cdr` pointer of `cons-cell`.") do |args, env|
|
16
|
+
Lisp::Assignment::setcdrbang_impl(args, env)
|
17
|
+
end
|
18
|
+
|
19
|
+
Primitive.register("set-nth!", "(set-nth! _n_ _list-or-vector_ _new-value_)\n\nSets the `n`th element of `list-or-vector` to `new-value`.") do |args, env|
|
20
|
+
Lisp::Assignment::setnthbang_impl(args, env)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def self.setbang_impl(args, env)
|
27
|
+
sym = args.car
|
28
|
+
raise "set! requires a raw (unevaluated) symbol as it's first argument." unless sym.symbol?
|
29
|
+
value = args.cadr.evaluate(env)
|
30
|
+
env.set(sym, value)
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
def self.setcarbang_impl(args, env)
|
35
|
+
pair = args.car.evaluate(env)
|
36
|
+
raise "set-car! requires a pair as it's first argument." unless pair.pair?
|
37
|
+
value = args.cadr.evaluate(env)
|
38
|
+
pair.set_car!(value)
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
def self.setcdrbang_impl(args, env)
|
43
|
+
pair = args.car.evaluate(env)
|
44
|
+
raise "set-cdr! requires a pair as it's first argument." unless pair.pair?
|
45
|
+
value = args.cadr.evaluate(env)
|
46
|
+
pair.set_cdr!(value)
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
def self.setnthbang_impl(args, env)
|
51
|
+
raise "set-nth! requires 3 arguments." unless args.length == 3
|
52
|
+
n = args.car.evaluate(env)
|
53
|
+
raise "The first argument of set-nth! has to be an number." unless n.number?
|
54
|
+
raise "The first argument of set-nth! has to be positive." unless n.value > 0
|
55
|
+
|
56
|
+
l = args.cadr.evaluate(env)
|
57
|
+
raise "set-nth! requires a list or vector as it's first argument." unless l.list? || l.vector?
|
58
|
+
value = args.caddr.evaluate(env)
|
59
|
+
l.set_nth!(n.value, value)
|
60
|
+
l
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
module Lisp
|
2
|
+
|
3
|
+
class Atom < Object
|
4
|
+
|
5
|
+
attr_reader :value
|
6
|
+
|
7
|
+
def lisp_object?
|
8
|
+
true
|
9
|
+
end
|
10
|
+
|
11
|
+
def string?
|
12
|
+
false
|
13
|
+
end
|
14
|
+
|
15
|
+
def character?
|
16
|
+
false
|
17
|
+
end
|
18
|
+
|
19
|
+
def number?
|
20
|
+
false
|
21
|
+
end
|
22
|
+
|
23
|
+
def positive?
|
24
|
+
false
|
25
|
+
end
|
26
|
+
|
27
|
+
def zero?
|
28
|
+
false
|
29
|
+
end
|
30
|
+
|
31
|
+
def negative?
|
32
|
+
false
|
33
|
+
end
|
34
|
+
|
35
|
+
def symbol?
|
36
|
+
false
|
37
|
+
end
|
38
|
+
|
39
|
+
def pair?
|
40
|
+
false
|
41
|
+
end
|
42
|
+
|
43
|
+
def list?
|
44
|
+
false
|
45
|
+
end
|
46
|
+
|
47
|
+
def primitive?
|
48
|
+
false
|
49
|
+
end
|
50
|
+
|
51
|
+
def special?
|
52
|
+
false
|
53
|
+
end
|
54
|
+
|
55
|
+
def function?
|
56
|
+
false
|
57
|
+
end
|
58
|
+
|
59
|
+
def macro?
|
60
|
+
false
|
61
|
+
end
|
62
|
+
|
63
|
+
def object?
|
64
|
+
false
|
65
|
+
end
|
66
|
+
|
67
|
+
def class?
|
68
|
+
false
|
69
|
+
end
|
70
|
+
|
71
|
+
def alist?
|
72
|
+
false
|
73
|
+
end
|
74
|
+
|
75
|
+
def frame?
|
76
|
+
false
|
77
|
+
end
|
78
|
+
|
79
|
+
def vector?
|
80
|
+
false
|
81
|
+
end
|
82
|
+
|
83
|
+
def length
|
84
|
+
1
|
85
|
+
end
|
86
|
+
|
87
|
+
def copy
|
88
|
+
self.class.new(self.value)
|
89
|
+
end
|
90
|
+
|
91
|
+
def eq?(sexpr)
|
92
|
+
return false if sexpr.nil?
|
93
|
+
return false if self.type != sexpr.type
|
94
|
+
self.value == sexpr.value
|
95
|
+
end
|
96
|
+
|
97
|
+
def type
|
98
|
+
:unknown
|
99
|
+
end
|
100
|
+
|
101
|
+
def evaluate(env)
|
102
|
+
self
|
103
|
+
end
|
104
|
+
|
105
|
+
def apply_to(args, env)
|
106
|
+
nil
|
107
|
+
end
|
108
|
+
|
109
|
+
def all?(&block)
|
110
|
+
false
|
111
|
+
end
|
112
|
+
|
113
|
+
def true?
|
114
|
+
true
|
115
|
+
end
|
116
|
+
|
117
|
+
def false?
|
118
|
+
false
|
119
|
+
end
|
120
|
+
|
121
|
+
def car
|
122
|
+
nil
|
123
|
+
end
|
124
|
+
|
125
|
+
def cdr
|
126
|
+
nil
|
127
|
+
end
|
128
|
+
|
129
|
+
def quoted
|
130
|
+
Lisp::ConsCell.cons(Symbol.named("quote"), self)
|
131
|
+
end
|
132
|
+
|
133
|
+
def set!(v)
|
134
|
+
end
|
135
|
+
|
136
|
+
def print_string
|
137
|
+
self.to_s
|
138
|
+
end
|
139
|
+
|
140
|
+
alias print_string_helper print_string
|
141
|
+
|
142
|
+
|
143
|
+
def doc
|
144
|
+
nil
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Lisp
|
2
|
+
|
3
|
+
class Boolean < Atom
|
4
|
+
def self.TRUE
|
5
|
+
@true_constant ||= Boolean.new(true)
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.FALSE
|
9
|
+
@false_constant ||= Boolean.new(false)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.with_value(b)
|
13
|
+
b ? self.TRUE : self.FALSE
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(b)
|
17
|
+
@value = b
|
18
|
+
end
|
19
|
+
|
20
|
+
def type
|
21
|
+
:boolean
|
22
|
+
end
|
23
|
+
|
24
|
+
def boolean?
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
return "#t" if @value
|
30
|
+
"#f"
|
31
|
+
end
|
32
|
+
|
33
|
+
def true?
|
34
|
+
@value
|
35
|
+
end
|
36
|
+
|
37
|
+
def false?
|
38
|
+
!@value
|
39
|
+
end
|
40
|
+
|
41
|
+
def negate
|
42
|
+
Lisp::Boolean.with_value(!@value)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
TRUE = Boolean.TRUE
|
48
|
+
FALSE = Boolean.FALSE
|
49
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Lisp
|
2
|
+
|
3
|
+
class Initializer
|
4
|
+
|
5
|
+
def self.initialize_global_environment
|
6
|
+
Lisp::EnvironmentFrame.global.bind(Symbol.named("nil"), nil)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.register_builtins
|
10
|
+
Lisp::Equivalence.register
|
11
|
+
Lisp::Math.register
|
12
|
+
Lisp::Logical.register
|
13
|
+
Lisp::SpecialForms.register
|
14
|
+
Lisp::ListSupport.register
|
15
|
+
Lisp::Relational.register
|
16
|
+
Lisp::TypeChecks.register
|
17
|
+
Lisp::Assignment.register
|
18
|
+
Lisp::Testing.register
|
19
|
+
Lisp::IO.register
|
20
|
+
Lisp::AList.register
|
21
|
+
Lisp::Frame.register
|
22
|
+
Lisp::Character.register
|
23
|
+
Lisp::String.register
|
24
|
+
Lisp::NativeObject.register
|
25
|
+
Lisp::ClassObject.register
|
26
|
+
Lisp::System.register
|
27
|
+
Lisp::Vector.register
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|