rubylisp 0.2.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|