rubylisp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|