rubylisp 0.2.1 → 1.0.2
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 +4 -4
- data/README.md +129 -2
- data/bin/rubylisp +87 -12
- data/lib/rubylisp/atom.rb +25 -6
- data/lib/rubylisp/boolean.rb +9 -6
- data/lib/rubylisp/builtins.rb +19 -18
- data/lib/rubylisp/character.rb +14 -275
- data/lib/rubylisp/class_object.rb +56 -0
- data/lib/rubylisp/cons_cell.rb +56 -25
- data/lib/rubylisp/debug.rb +15 -19
- data/lib/rubylisp/environment.rb +27 -0
- data/lib/rubylisp/environment_frame.rb +31 -6
- data/lib/rubylisp/eof_object.rb +26 -0
- data/lib/rubylisp/exception.rb +61 -61
- data/lib/rubylisp/ext.rb +32 -6
- data/lib/rubylisp/ffi_new.rb +2 -1
- data/lib/rubylisp/ffi_send.rb +15 -5
- data/lib/rubylisp/frame.rb +5 -164
- data/lib/rubylisp/function.rb +4 -3
- data/lib/rubylisp/macro.rb +13 -8
- data/lib/rubylisp/{object.rb → native_object.rb} +0 -15
- data/lib/rubylisp/number.rb +5 -0
- data/lib/rubylisp/parser.rb +81 -52
- data/lib/rubylisp/port.rb +27 -0
- data/lib/rubylisp/prim_alist.rb +115 -0
- data/lib/rubylisp/prim_assignment.rb +61 -0
- data/lib/rubylisp/prim_character.rb +273 -0
- data/lib/rubylisp/{ffi_class.rb → prim_class_object.rb} +16 -69
- data/lib/rubylisp/prim_environment.rb +203 -0
- data/lib/rubylisp/prim_equivalence.rb +93 -0
- data/lib/rubylisp/prim_frame.rb +166 -0
- data/lib/rubylisp/prim_io.rb +266 -0
- data/lib/rubylisp/prim_list_support.rb +496 -0
- data/lib/rubylisp/{logical.rb → prim_logical.rb} +9 -14
- data/lib/rubylisp/prim_math.rb +397 -0
- data/lib/rubylisp/prim_native_object.rb +21 -0
- data/lib/rubylisp/prim_relational.rb +42 -0
- data/lib/rubylisp/{special_forms.rb → prim_special_forms.rb} +98 -85
- data/lib/rubylisp/prim_string.rb +792 -0
- data/lib/rubylisp/prim_system.rb +55 -0
- data/lib/rubylisp/prim_type_checks.rb +58 -0
- data/lib/rubylisp/prim_vector.rb +497 -0
- data/lib/rubylisp/primitive.rb +51 -6
- data/lib/rubylisp/string.rb +4 -803
- data/lib/rubylisp/symbol.rb +0 -1
- data/lib/rubylisp/tokenizer.rb +161 -137
- data/lib/rubylisp/vector.rb +10 -31
- data/lib/rubylisp.rb +1 -0
- metadata +46 -17
- data/lib/rubylisp/alist.rb +0 -230
- data/lib/rubylisp/assignment.rb +0 -65
- data/lib/rubylisp/equivalence.rb +0 -118
- data/lib/rubylisp/io.rb +0 -74
- data/lib/rubylisp/list_support.rb +0 -526
- data/lib/rubylisp/math.rb +0 -405
- data/lib/rubylisp/relational.rb +0 -46
- data/lib/rubylisp/system.rb +0 -20
- data/lib/rubylisp/testing.rb +0 -136
- data/lib/rubylisp/type_checks.rb +0 -60
@@ -1,21 +1,6 @@
|
|
1
1
|
module Lisp
|
2
2
|
|
3
3
|
class NativeObject < Atom
|
4
|
-
|
5
|
-
def self.register
|
6
|
-
Primitive.register("wrap-object") {|args, env| Lisp::NativeObject::wrap_impl(args, env) }
|
7
|
-
end
|
8
|
-
|
9
|
-
def self.wrap_impl(args, env)
|
10
|
-
return Lisp::Debug.process_error("wrap-object requires 1 argument", env) unless args.length == 1
|
11
|
-
raw_val = args.car.evaluate(env)
|
12
|
-
val = if raw_val.list?
|
13
|
-
raw_val.to_a
|
14
|
-
else
|
15
|
-
raw_val
|
16
|
-
end
|
17
|
-
NativeObject.with_value(val)
|
18
|
-
end
|
19
4
|
|
20
5
|
def self.new_instance_of(c)
|
21
6
|
self.new(c.alloc.init)
|
data/lib/rubylisp/number.rb
CHANGED
data/lib/rubylisp/parser.rb
CHANGED
@@ -10,7 +10,7 @@ module Lisp
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def make_hex_number(str)
|
13
|
-
Lisp::Number.with_value(
|
13
|
+
Lisp::Number.with_value(["0x", str].join.to_i(0))
|
14
14
|
end
|
15
15
|
|
16
16
|
def make_float(str)
|
@@ -18,7 +18,7 @@ module Lisp
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def make_string(str)
|
21
|
-
Lisp::String.with_value(str
|
21
|
+
Lisp::String.with_value(str)
|
22
22
|
end
|
23
23
|
|
24
24
|
def make_symbol(str)
|
@@ -33,7 +33,7 @@ module Lisp
|
|
33
33
|
tok, lit = tokens.next_token
|
34
34
|
if tok == :RPAREN
|
35
35
|
tokens.consume_token
|
36
|
-
return
|
36
|
+
return Lisp::ConsCell.cons()
|
37
37
|
end
|
38
38
|
|
39
39
|
car = nil
|
@@ -45,67 +45,85 @@ module Lisp
|
|
45
45
|
cdr = self.parse_sexpr(tokens)
|
46
46
|
return nil if tokens.next_token[0] == :EOF
|
47
47
|
tok, lit = tokens.next_token
|
48
|
-
return Lisp::Debug.process_error("Expected ')' to follow a dotted tail on line #{tokens.line_number}",
|
48
|
+
return Lisp::Debug.process_error("Expected ')' to follow a dotted tail on line #{tokens.line_number}", Lisp::EnvironmentFrame.global) if tok != :RPAREN
|
49
49
|
tokens.consume_token
|
50
50
|
return Lisp::ConsCell.array_to_list(cells, cdr)
|
51
51
|
else
|
52
52
|
car = self.parse_sexpr(tokens)
|
53
|
-
return Lisp::Debug.process_error("Unexpected EOF (expected ')') on line #{tokens.line_number}",
|
53
|
+
return Lisp::Debug.process_error("Unexpected EOF (expected ')') on line #{tokens.line_number}", Lisp::EnvironmentFrame.global) if tokens.next_token[0] == :EOF
|
54
54
|
cells << car
|
55
55
|
end
|
56
56
|
tok, lit = tokens.next_token
|
57
57
|
end
|
58
58
|
|
59
59
|
tokens.consume_token
|
60
|
-
|
60
|
+
Lisp::ConsCell.array_to_list(cells)
|
61
61
|
end
|
62
62
|
|
63
|
-
def
|
63
|
+
def parse_frame(tokens, literal)
|
64
64
|
m = {}
|
65
65
|
tok, lit = tokens.next_token
|
66
66
|
if tok == :RBRACE
|
67
67
|
tokens.consume_token
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
68
|
+
if literal
|
69
|
+
Lisp::Frame.new
|
70
|
+
else
|
71
|
+
Lisp::ConsCell.cons(Lisp::Symbol.named("make-frame"), nil)
|
72
|
+
end
|
73
|
+
else
|
74
|
+
cells = []
|
75
|
+
while tok != :RBRACE
|
76
|
+
item = self.parse_sexpr(tokens)
|
77
|
+
return Lisp::Debug.process_error("Unexpected EOF (expected '}') on line #{tokens.line_number}", env) if tokens.next_token[0] == :EOF
|
78
|
+
cells << item
|
79
|
+
tok, lit = tokens.next_token
|
80
|
+
end
|
81
|
+
|
82
|
+
tokens.consume_token
|
83
|
+
keys_and_values = Lisp::ConsCell.array_to_list(cells)
|
84
|
+
if literal
|
85
|
+
Lisp::PrimFrame.make_frame_impl(keys_and_values, Lisp::EnvironmentFrame.global)
|
86
|
+
else
|
87
|
+
Lisp::ConsCell.cons(Lisp::Symbol.named("make-frame"), keys_and_values)
|
88
|
+
end
|
77
89
|
end
|
78
|
-
|
79
|
-
tokens.consume_token
|
80
|
-
return ConsCell.cons(Symbol.named("make-frame"), ConsCell.array_to_list(cells))
|
81
90
|
end
|
82
91
|
|
83
92
|
|
84
|
-
def parse_vector(tokens)
|
93
|
+
def parse_vector(tokens, literal)
|
85
94
|
v = []
|
86
95
|
tok, lit = tokens.next_token
|
87
|
-
if tok == :
|
96
|
+
if tok == :RPAREN
|
88
97
|
tokens.consume_token
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
+
if literal
|
99
|
+
Lisp::Vector.new
|
100
|
+
else
|
101
|
+
Lisp::ConsCell.cons(Lis::Symbol.named("vector"), nil)
|
102
|
+
end
|
103
|
+
else
|
104
|
+
cells = []
|
105
|
+
while tok != :RPAREN
|
106
|
+
item = self.parse_sexpr(tokens)
|
107
|
+
return Lisp::Debug.process_error("Unexpected EOF (expected ')') on line #{tokens.line_number}", env) if tokens.next_token[0] == :EOF
|
108
|
+
cells << item
|
109
|
+
tok, lit = tokens.next_token
|
110
|
+
end
|
111
|
+
|
112
|
+
tokens.consume_token
|
113
|
+
|
114
|
+
if literal
|
115
|
+
Lisp::Vector.with_array(cells)
|
116
|
+
else
|
117
|
+
Lisp::ConsCell.cons(Lisp::Symbol.named("vector"), Lisp::ConsCell.array_to_list(cells))
|
118
|
+
end
|
98
119
|
end
|
99
|
-
|
100
|
-
tokens.consume_token
|
101
|
-
return ConsCell.cons(Symbol.named("make-vector"), ConsCell.array_to_list(cells))
|
102
120
|
end
|
103
121
|
|
104
122
|
|
105
123
|
def parse_sexpr(tokens)
|
106
124
|
while true
|
107
125
|
tok, lit = tokens.next_token
|
108
|
-
#puts "token: <#{tok}, #{lit}>"
|
126
|
+
# puts "token: <#{tok}, #{lit}>"
|
109
127
|
return nil if tok == :EOF
|
110
128
|
tokens.consume_token
|
111
129
|
case tok
|
@@ -124,33 +142,37 @@ module Lisp
|
|
124
142
|
when :LPAREN
|
125
143
|
return parse_cons_cell(tokens)
|
126
144
|
when :LBRACE
|
127
|
-
return
|
128
|
-
when :
|
129
|
-
return
|
145
|
+
return parse_frame(tokens, false)
|
146
|
+
when :QUOTE_LBRACE
|
147
|
+
return parse_frame(tokens, true)
|
148
|
+
when :HASH_LPAREN
|
149
|
+
return parse_vector(tokens, false)
|
150
|
+
when :QUOTE_HASH_LPAREN
|
151
|
+
return parse_vector(tokens, true)
|
130
152
|
when :SYMBOL
|
131
153
|
return make_symbol(lit)
|
132
154
|
when :FFI_NEW_SYMBOL
|
133
|
-
return FfiNew.new(lit)
|
155
|
+
return Lisp::FfiNew.new(lit)
|
134
156
|
when :FFI_SEND_SYMBOL
|
135
|
-
return FfiSend.new(lit)
|
157
|
+
return Lisp::FfiSend.new(lit)
|
136
158
|
when :FFI_STATIC_SYMBOL
|
137
|
-
return FfiStatic.new(lit)
|
159
|
+
return Lisp::FfiStatic.new(lit)
|
138
160
|
when :FALSE
|
139
161
|
return Lisp::FALSE
|
140
162
|
when :TRUE
|
141
163
|
return Lisp::TRUE
|
142
164
|
when :QUOTE
|
143
165
|
expr = parse_sexpr(tokens)
|
144
|
-
return ConsCell.array_to_list([Symbol.named('quote'), expr])
|
166
|
+
return Lisp::ConsCell.array_to_list([Lisp::Symbol.named('quote'), expr])
|
145
167
|
when :BACKQUOTE
|
146
168
|
expr = parse_sexpr(tokens)
|
147
|
-
return ConsCell.array_to_list([Symbol.named('quasiquote'), expr])
|
169
|
+
return Lisp::ConsCell.array_to_list([Lisp::Symbol.named('quasiquote'), expr])
|
148
170
|
when :COMMA
|
149
171
|
expr = parse_sexpr(tokens)
|
150
|
-
return ConsCell.array_to_list([Symbol.named('unquote'), expr])
|
172
|
+
return Lisp::ConsCell.array_to_list([Lisp::Symbol.named('unquote'), expr])
|
151
173
|
when :COMMAAT
|
152
174
|
expr = parse_sexpr(tokens)
|
153
|
-
return ConsCell.array_to_list([Symbol.named('unquote-splicing'), expr])
|
175
|
+
return Lisp::ConsCell.array_to_list([Lisp::Symbol.named('unquote-splicing'), expr])
|
154
176
|
when :ILLEGAL
|
155
177
|
return Lisp::Debug.process_error("Illegal token: #{lit} on line #{tokens.line_number}", Lisp::EnvironmentFrame.global)
|
156
178
|
else
|
@@ -160,21 +182,23 @@ module Lisp
|
|
160
182
|
end
|
161
183
|
|
162
184
|
def parse(src)
|
163
|
-
tokenizer = Tokenizer.
|
164
|
-
tokenizer
|
165
|
-
|
166
|
-
sexpr = self.parse_sexpr(tokenizer)
|
167
|
-
return sexpr
|
185
|
+
tokenizer = Tokenizer.from_string(src)
|
186
|
+
self.parse_sexpr(tokenizer)
|
168
187
|
end
|
169
188
|
|
189
|
+
def parse_object_from_file(port, env=Lisp::EnvironmentFrame.global)
|
190
|
+
tokenizer = Tokenizer.from_file(port)
|
191
|
+
result = self.parse_sexpr(tokenizer)
|
192
|
+
result.nil? ? Lisp::EofObject.instance : result
|
193
|
+
end
|
194
|
+
|
170
195
|
def parse_and_eval(src, env=Lisp::EnvironmentFrame.global)
|
171
196
|
sexpr = self.parse(src)
|
172
197
|
return sexpr.evaluate(env)
|
173
198
|
end
|
174
199
|
|
175
200
|
def parse_and_eval_all(src, env=Lisp::EnvironmentFrame.global)
|
176
|
-
tokenizer = Tokenizer.
|
177
|
-
tokenizer.init
|
201
|
+
tokenizer = Tokenizer.from_string(src)
|
178
202
|
result = nil
|
179
203
|
until tokenizer.eof?
|
180
204
|
sexpr = self.parse_sexpr(tokenizer)
|
@@ -183,7 +207,12 @@ module Lisp
|
|
183
207
|
result
|
184
208
|
end
|
185
209
|
|
186
|
-
|
210
|
+
def process_file(fname)
|
211
|
+
File.open(fname) do |f|
|
212
|
+
parse_and_eval_all(f.read)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
187
216
|
end
|
188
217
|
|
189
218
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Lisp
|
2
|
+
|
3
|
+
class Port < Atom
|
4
|
+
|
5
|
+
def self.with_value(p)
|
6
|
+
self.new(p)
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(p)
|
10
|
+
@value = p
|
11
|
+
end
|
12
|
+
|
13
|
+
def type
|
14
|
+
:port
|
15
|
+
end
|
16
|
+
|
17
|
+
def port?
|
18
|
+
true
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
"<port: #{@value}>"
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
module Lisp
|
2
|
+
|
3
|
+
class PrimAlist
|
4
|
+
|
5
|
+
|
6
|
+
def self.register
|
7
|
+
Primitive.register("acons", "2|3") {|args, env| Lisp::PrimAlist::acons_impl(args, env) }
|
8
|
+
Primitive.register("assq", "2") {|args, env| Lisp::PrimAlist::assoc_impl(args, env) {|a, b| a.eq?(b) } }
|
9
|
+
Primitive.register("assv", "2") {|args, env| Lisp::PrimAlist::assoc_impl(args, env) {|a, b| a.eqv?(b) } }
|
10
|
+
Primitive.register("assoc", "2") {|args, env| Lisp::PrimAlist::assoc_impl(args, env) {|a, b| a.equal?(b) } }
|
11
|
+
Primitive.register("rassq", "2") {|args, env| Lisp::PrimAlist::rassoc_impl(args, env) {|a, b| a.eq?(b) } }
|
12
|
+
Primitive.register("rassv", "2") {|args, env| Lisp::PrimAlist::rassoc_impl(args, env) {|a, b| a.eqv?(b) } }
|
13
|
+
Primitive.register("rassoc", "2") {|args, env| Lisp::PrimAlist::rassoc_impl(args, env) {|a, b| a.equal?(b) } }
|
14
|
+
Primitive.register("del-assq", "2") {|args, env| Lisp::PrimAlist::dissoc_impl(args, env) {|a, b| a.eq?(b) } }
|
15
|
+
Primitive.register("dissq", "2") {|args, env| Lisp::PrimAlist::dissoc_impl(args, env) {|a, b| a.eq?(b) } }
|
16
|
+
Primitive.register("del-assv", "2") {|args, env| Lisp::PrimAlist::dissoc_impl(args, env) {|a, b| a.eqv?(b) } }
|
17
|
+
Primitive.register("dissv", "2") {|args, env| Lisp::PrimAlist::dissoc_impl(args, env) {|a, b| a.eqv?(b) } }
|
18
|
+
Primitive.register("del-assoc", "2") {|args, env| Lisp::PrimAlist::dissoc_impl(args, env) {|a, b| a.equal?(b) } }
|
19
|
+
Primitive.register("dissoc", "2") {|args, env| Lisp::PrimAlist::dissoc_impl(args, env) {|a, b| a.equal?(b) } }
|
20
|
+
Primitive.register("zip", "2|3") {|args, env| Lisp::PrimAlist::zip_impl(args, env) }
|
21
|
+
Primitive.register("pairlis", "2|3") {|args, env| Lisp::PrimAlist::zip_impl(args, env) }
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def self.acons_impl(args, env)
|
26
|
+
key = args.car
|
27
|
+
value = args.cadr
|
28
|
+
alist = args.length == 2 ? nil : args.caddr
|
29
|
+
return Lisp::Debug.process_error("the last argument to acons has to be a list", env) unless alist.list?
|
30
|
+
|
31
|
+
pair = ConsCell.cons(key, value)
|
32
|
+
if alist.nil?
|
33
|
+
ConsCell.cons(pair)
|
34
|
+
else
|
35
|
+
ConsCell.cons(pair, alist)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
def self.assoc_impl(args, env, &equivalence_block)
|
41
|
+
key = args.car
|
42
|
+
alist = args.cadr
|
43
|
+
return Lisp::Debug.process_error("the last argument to assoc has to be a list", env) unless alist.list?
|
44
|
+
|
45
|
+
alist.each do |pair|
|
46
|
+
if equivalence_block.call(pair.car, key)
|
47
|
+
return pair
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
def self.rassoc_impl(args, env, &equivalence_block)
|
54
|
+
value = args.car
|
55
|
+
alist = args.cadr
|
56
|
+
return Lisp::Debug.process_error("the last argument to rassoc has to be a list", env) unless alist.list?
|
57
|
+
alist.each do |pair|
|
58
|
+
if equivalence_block.call(pair.cdr, value)
|
59
|
+
return pair
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
def self.dissoc_impl(args, env, &equivalence_block)
|
66
|
+
key = args.car
|
67
|
+
alist = args.cadr
|
68
|
+
return Lisp::Debug.process_error("the last argument to dissoc has to be a list", env) unless alist.list?
|
69
|
+
|
70
|
+
new_prefix = nil
|
71
|
+
trailing_end = nil
|
72
|
+
crawler = alist
|
73
|
+
while !crawler.nil?
|
74
|
+
if equivalence_block.call(crawler.caar, key)
|
75
|
+
if new_prefix.nil?
|
76
|
+
new_prefix = crawler.cdr
|
77
|
+
else
|
78
|
+
trailing_end.set_cdr!(crawler.cdr)
|
79
|
+
end
|
80
|
+
return new_prefix
|
81
|
+
else
|
82
|
+
new_cell = ConsCell.cons(ConsCell.cons(crawler.caar, crawler.cdar))
|
83
|
+
if new_prefix.nil?
|
84
|
+
new_prefix = new_cell
|
85
|
+
trailing_end = new_prefix
|
86
|
+
else
|
87
|
+
trailing_end.set_cdr!(new_cell)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
crawler = crawler.cdr
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
def self.zip_impl(args, env)
|
96
|
+
key_list = args.car
|
97
|
+
return Lisp::Debug.process_error("the keys supplied to zip has to be a list", env) unless key_list.list?
|
98
|
+
value_list = args.cadr
|
99
|
+
return Lisp::Debug.process_error("the values supplied to zip has to be a list", env) unless value_list.list?
|
100
|
+
return Lisp::Debug.process_error("zip requires the same number of keys and values", env) unless key_list.length == value_list.length
|
101
|
+
|
102
|
+
old_list = if args.length == 3
|
103
|
+
alist = args.caddr
|
104
|
+
return Lisp::Debug.process_error("the third argument to zip has to be a list", env) unless alist.list?
|
105
|
+
alist
|
106
|
+
else
|
107
|
+
nil
|
108
|
+
end
|
109
|
+
pairs = key_list.to_a.zip(value_list.to_a)
|
110
|
+
pairs.inject(old_list) {|alist, pair| ConsCell.cons(ConsCell.cons(*pair), alist)}
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Lisp
|
2
|
+
|
3
|
+
class PrimAssignment
|
4
|
+
|
5
|
+
def self.register
|
6
|
+
Primitive.register("set!", "2",
|
7
|
+
"(set! name new-value)\n\nThe way to assign (i.e. rebind) a symbol. `name` is the symbol to be rebound.
|
8
|
+
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.",
|
9
|
+
true) { |args, env| Lisp::PrimAssignment::setbang_impl(args, env) }
|
10
|
+
|
11
|
+
Primitive.register("set-car!", "2",
|
12
|
+
"(set-car! cons-cell new-value)\n\nSet the `car` pointer of `cons-cell`.") { |args, env| Lisp::PrimAssignment::setcarbang_impl(args, env) }
|
13
|
+
|
14
|
+
Primitive.register("set-cdr!", "2",
|
15
|
+
"(set-cdr! cons-cell new-value)\n\nSet the `cdr` pointer of `cons-cell`.") { |args, env| Lisp::PrimAssignment::setcdrbang_impl(args, env) }
|
16
|
+
|
17
|
+
Primitive.register("set-nth!", "3",
|
18
|
+
"(set-nth! n list-or-vector new-value)\n\nSets the `n`th element of `list-or-vector` to `new-value`.") { |args, env| Lisp::PrimAssignment::setnthbang_impl(args, env) }
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
def self.setbang_impl(args, env)
|
24
|
+
sym = args.car
|
25
|
+
return Lisp::Debug.process_error("set! requires a raw (unevaluated) symbol as it's first argument.", env) unless sym.symbol?
|
26
|
+
value = args.cadr.evaluate(env)
|
27
|
+
env.set(sym, value)
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def self.setcarbang_impl(args, env)
|
32
|
+
pair = args.car
|
33
|
+
return Lisp::Debug.process_error("set-car! requires a pair as it's first argument.", env) unless pair.pair?
|
34
|
+
value = args.cadr
|
35
|
+
pair.set_car!(value)
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
def self.setcdrbang_impl(args, env)
|
40
|
+
pair = args.car
|
41
|
+
return Lisp::Debug.process_error("set-cdr! requires a pair as it's first argument.", env) unless pair.pair?
|
42
|
+
value = args.cadr
|
43
|
+
pair.set_cdr!(value)
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def self.setnthbang_impl(args, env)
|
48
|
+
n = args.car
|
49
|
+
return Lisp::Debug.process_error("The first argument of set-nth! has to be an number.", env) unless n.number?
|
50
|
+
return Lisp::Debug.process_error("The first argument of set-nth! has to be non negative.", env) unless n.value >= 0
|
51
|
+
|
52
|
+
l = args.cadr
|
53
|
+
return Lisp::Debug.process_error("set-nth! requires a list or vector as it's first argument.", env) unless l.list? || l.vector?
|
54
|
+
value = args.caddr
|
55
|
+
l.set_nth!(n.value, value)
|
56
|
+
l
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|