rubylisp 0.1.1 → 0.2.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.
data/lib/rubylisp/math.rb CHANGED
@@ -120,13 +120,13 @@ largest integer less than or equal to `number` is returned.") do |args, env|
120
120
  end
121
121
 
122
122
  def self.add_impl(args, env)
123
- raise "add needs at least 1 argument" if args.empty?
123
+ return Lisp::Debug.process_error("add needs at least 1 argument", env) if args.empty?
124
124
 
125
125
  acc = 0
126
126
  c = args
127
127
  while !c.nil?
128
128
  n = c.car.evaluate(env)
129
- raise "add needs number arguments but was given a #{n.type}: #{n}" unless n.type == :number
129
+ return Lisp::Debug.process_error("add needs number arguments but was given a #{n.type}: #{n}", env) unless n.type == :number
130
130
  acc += n.value
131
131
  c = c.cdr
132
132
  end
@@ -136,17 +136,17 @@ largest integer less than or equal to `number` is returned.") do |args, env|
136
136
 
137
137
 
138
138
  def self.subtract_impl(args, env)
139
- raise "subtract needs at least 1 argument" if args.empty?
139
+ return Lisp::Debug.process_error("subtract needs at least 1 argument", env) if args.empty?
140
140
 
141
141
  return Number.with_value(-1 * args.car.evaluate(env).value) if args.length == 1
142
142
 
143
143
  first = args.car.evaluate(env)
144
- raise "subtract needs number arguments, but received #{first}" unless first.type == :number
144
+ return Lisp::Debug.process_error("subtract needs number arguments, but received #{first}", env) unless first.type == :number
145
145
  acc = first.value
146
146
  c = args.cdr
147
147
  while !c.nil?
148
148
  n = c.car.evaluate(env)
149
- raise "subtract needs number arguments, but received #{n}" unless n.type == :number
149
+ return Lisp::Debug.process_error("subtract needs number arguments, but received #{n}", env) unless n.type == :number
150
150
  acc -= n.value
151
151
  c = c.cdr
152
152
  end
@@ -156,13 +156,13 @@ largest integer less than or equal to `number` is returned.") do |args, env|
156
156
 
157
157
 
158
158
  def self.multiply_impl(args, env)
159
- raise "multiply needs at least 1 argument" if args.empty?
159
+ return Lisp::Debug.process_error("multiply needs at least 1 argument", env) if args.empty?
160
160
 
161
161
  acc = 1
162
162
  c = args
163
163
  while !c.nil?
164
164
  n = c.car.evaluate(env)
165
- raise "multiply needs number arguments, but received #{n}" unless n.type == :number
165
+ return Lisp::Debug.process_error("multiply needs number arguments, but received #{n}", env) unless n.type == :number
166
166
  acc *= n.value
167
167
  c = c.cdr
168
168
  end
@@ -172,16 +172,17 @@ largest integer less than or equal to `number` is returned.") do |args, env|
172
172
 
173
173
 
174
174
  def self.quotient_impl(args, env)
175
- raise "quotient needs at least 1 argument" if args.empty?
175
+ return Lisp::Debug.process_error("quotient needs at least 1 argument", env) if args.empty?
176
176
 
177
177
  first = args.car.evaluate(env)
178
- raise "quotient needs number arguments, but received #{first}" unless first.type == :number
178
+ return Lisp::Debug.process_error("quotient needs number arguments, but received #{first}", env) unless first.type == :number
179
179
  return first if args.length == 1
180
180
  acc = first.value
181
181
  c = args.cdr
182
182
  while !c.nil?
183
183
  n = c.car.evaluate(env)
184
- raise "quotient needs number arguments, but received #{n}" unless n.type == :number
184
+ return Lisp::Debug.process_error("quotient needs number arguments, but received #{n}", env) unless n.type == :number
185
+ return Lisp::Debug.process_error("divide by zero", env) if n.value == 0
185
186
  acc /= n.value
186
187
  c = c.cdr
187
188
  end
@@ -191,16 +192,17 @@ largest integer less than or equal to `number` is returned.") do |args, env|
191
192
 
192
193
 
193
194
  def self.remainder_impl(args, env)
194
- raise "remainder needs at least 1 argument" if args.empty?
195
+ return Lisp::Debug.process_error("remainder needs at least 1 argument", env) if args.empty?
195
196
 
196
197
  first = args.car.evaluate(env)
197
- raise "remainder needs number arguments, but received #{first}" unless first.type == :number
198
+ return Lisp::Debug.process_error("remainder needs number arguments, but received #{first}", env) unless first.type == :number
198
199
  return first if args.length == 1
199
200
  acc = first.value
200
201
  c = args.cdr
201
202
  while !c.nil?
202
203
  n = c.car.evaluate(env)
203
- raise "remainder needs number arguments, but received #{n}" unless n.type == :number
204
+ return Lisp::Debug.process_error("remainder needs number arguments, but received #{n}", env) unless n.type == :number
205
+ return Lisp::Debug.process_error("divide by zero", env) if n.value == 0
204
206
  acc %= n.value
205
207
  c = c.cdr
206
208
  end
@@ -209,17 +211,17 @@ largest integer less than or equal to `number` is returned.") do |args, env|
209
211
  end
210
212
 
211
213
  def self.truncate_impl(args, env)
212
- raise "truncate needs 1 argument, but received #{args.length}" if args.length != 1
214
+ return Lisp::Debug.process_error("truncate needs 1 argument, but received #{args.length}", env) if args.length != 1
213
215
  arg = args.car.evaluate(env)
214
- raise "truncate needs a number argument, but received #{arg}" unless arg.type == :number
216
+ return Lisp::Debug.process_error("truncate needs a number argument, but received #{arg}", env) unless arg.type == :number
215
217
  Number.with_value(arg.value.truncate)
216
218
  end
217
219
 
218
220
 
219
221
  def self.round_impl(args, env)
220
- raise "round needs 1 argument, but received #{args.length}" if args.length != 1
222
+ return Lisp::Debug.process_error("round needs 1 argument, but received #{args.length}", env) if args.length != 1
221
223
  arg = args.car.evaluate(env)
222
- raise "round needs a number argument, but received #{arg}" unless arg.type == :number
224
+ return Lisp::Debug.process_error("round needs a number argument, but received #{arg}", env) unless arg.type == :number
223
225
  num = arg.value
224
226
  int = num.to_i
225
227
  Number.with_value(if (num - int).abs == 0.5
@@ -235,121 +237,121 @@ largest integer less than or equal to `number` is returned.") do |args, env|
235
237
 
236
238
 
237
239
  def self.ceiling_impl(args, env)
238
- raise "ceiling needs 1 argument, but received #{args.length}" if args.length != 1
240
+ return Lisp::Debug.process_error("ceiling needs 1 argument, but received #{args.length}", env) if args.length != 1
239
241
  arg = args.car.evaluate(env)
240
- raise "ceiling needs a number argument, but received #{arg}" unless arg.type == :number
242
+ return Lisp::Debug.process_error("ceiling needs a number argument, but received #{arg}", env) unless arg.type == :number
241
243
  Number.with_value(arg.value.ceil)
242
244
  end
243
245
 
244
246
 
245
247
  def self.floor_impl(args, env)
246
- raise "floor needs 1 argument, but received #{args.length}" if args.length != 1
248
+ return Lisp::Debug.process_error("floor needs 1 argument, but received #{args.length}", env) if args.length != 1
247
249
  arg = args.car.evaluate(env)
248
- raise "floor needs a number argument, but received #{arg}" unless arg.type == :number
250
+ return Lisp::Debug.process_error("floor needs a number argument, but received #{arg}", env) unless arg.type == :number
249
251
  Number.with_value(arg.value.floor)
250
252
  end
251
253
 
252
254
 
253
255
  def self.even_impl(args, env)
254
- raise "even? needs 1 argument, but received #{args.length}" if args.length != 1
256
+ return Lisp::Debug.process_error("even? needs 1 argument, but received #{args.length}", env) if args.length != 1
255
257
  arg = args.car.evaluate(env)
256
- raise "even? needs a number argument, but received #{arg}" unless arg.type == :number
258
+ return Lisp::Debug.process_error("even? needs a number argument, but received #{arg}", env) unless arg.type == :number
257
259
  Boolean.with_value(arg.value.even?)
258
260
  end
259
261
 
260
262
 
261
263
  def self.odd_impl(args, env)
262
- raise "odd? needs 1 argument, but received #{args.length}" if args.length != 1
264
+ return Lisp::Debug.process_error("odd? needs 1 argument, but received #{args.length}", env) if args.length != 1
263
265
  arg = args.car.evaluate(env)
264
- raise "odd? needs a number argument, but received #{arg}" unless arg.type == :number
266
+ return Lisp::Debug.process_error("odd? needs a number argument, but received #{arg}", env) unless arg.type == :number
265
267
  Boolean.with_value(arg.value.odd?)
266
268
  end
267
269
 
268
270
 
269
271
  def self.zero_impl(args, env)
270
- raise "zero? needs 1 argument, but received #{args.length}" if args.length != 1
272
+ return Lisp::Debug.process_error("zero? needs 1 argument, but received #{args.length}", env) if args.length != 1
271
273
  arg = args.car.evaluate(env)
272
- raise "zero? needs a number argument, but received #{arg}" unless arg.type == :number
274
+ return Lisp::Debug.process_error("zero? needs a number argument, but received #{arg}", env) unless arg.type == :number
273
275
  Boolean.with_value(arg.value.zero?)
274
276
  end
275
277
 
276
278
 
277
279
  def self.positive_impl(args, env)
278
- raise "positive? needs 1 argument, but received #{args.length}" if args.length != 1
280
+ return Lisp::Debug.process_error("positive? needs 1 argument, but received #{args.length}", env) if args.length != 1
279
281
  arg = args.car.evaluate(env)
280
- raise "positive? needs a number argument, but received #{arg}" unless arg.type == :number
282
+ return Lisp::Debug.process_error("positive? needs a number argument, but received #{arg}", env) unless arg.type == :number
281
283
  Boolean.with_value(arg.value > 0)
282
284
  end
283
285
 
284
286
 
285
287
  def self.negative_impl(args, env)
286
- raise "negative? needs 1 argument, but received #{args.length}" if args.length != 1
288
+ return Lisp::Debug.process_error("negative? needs 1 argument, but received #{args.length}", env) if args.length != 1
287
289
  arg = args.car.evaluate(env)
288
- raise "negative? needs a number argument, but received #{arg}" unless arg.type == :number
290
+ return Lisp::Debug.process_error("negative? needs a number argument, but received #{arg}", env) unless arg.type == :number
289
291
  Boolean.with_value(arg.value < 0)
290
292
  end
291
293
 
292
294
 
293
295
  def self.interval_impl(args, env)
294
- raise "interval needs 2 arguments, but received #{args.length}" if args.length != 2
296
+ return Lisp::Debug.process_error("interval needs 2 arguments, but received #{args.length}", env) if args.length != 2
295
297
  initial = args.car.evaluate(env)
296
- raise "interval needs number arguments, but received #{initial}" unless initial.type == :number
298
+ return Lisp::Debug.process_error("interval needs number arguments, but received #{initial}", env) unless initial.type == :number
297
299
  final = args.cadr.evaluate(env)
298
- raise "interval needs number arguments, but received #{final}" unless final.type == :number
299
- raise "interval's arguments need to be in natural order" unless initial.value <= final.value
300
+ return Lisp::Debug.process_error("interval needs number arguments, but received #{final}", env) unless final.type == :number
301
+ return Lisp::Debug.process_error("interval's arguments need to be in natural order", env) unless initial.value <= final.value
300
302
  Lisp::ConsCell.array_to_list((initial.value..final.value).to_a.map {|n| Number.with_value(n)})
301
303
  end
302
304
 
303
305
 
304
306
  def self.random_impl(args, env)
305
307
  arg = args.car.evaluate(env)
306
- raise "random needs a number argument, but received #{arg}" unless arg.nil? || arg.type == :number
308
+ return Lisp::Debug.process_error("random needs a number argument, but received #{arg}", env) unless arg.nil? || arg.type == :number
307
309
  Number.with_value(arg.nil? ? rand() : rand(arg.value))
308
310
  end
309
311
 
310
312
 
311
313
  def self.float_impl(args, env)
312
- raise "float needs 1 argument, but received #{args.length}" if args.length != 1
314
+ return Lisp::Debug.process_error("float needs 1 argument, but received #{args.length}", env) if args.length != 1
313
315
  arg = args.car.evaluate(env)
314
- raise "float needs a numeric or string argument, but received #{arg}" unless arg.number? || arg.string?
316
+ return Lisp::Debug.process_error("float needs a numeric or string argument, but received #{arg}", env) unless arg.number? || arg.string?
315
317
  Number.with_value(arg.value.to_f)
316
318
  end
317
319
 
318
320
 
319
321
  def self.integer_impl(args, env)
320
- raise "integer needs 1 argument, but received #{args.length}" if args.length != 1
322
+ return Lisp::Debug.process_error("integer needs 1 argument, but received #{args.length}", env) if args.length != 1
321
323
  arg = args.car.evaluate(env)
322
- raise "integer needs a numeric or string argument, but received #{arg}" unless arg.number? || arg.string?
324
+ return Lisp::Debug.process_error("integer needs a numeric or string argument, but received #{arg}", env) unless arg.number? || arg.string?
323
325
  Number.with_value(arg.value.to_i)
324
326
  end
325
327
 
326
328
 
327
329
  def self.abs_impl(args, env)
328
- raise "abs needs 1 argument, but received #{args.length}" if args.length != 1
330
+ return Lisp::Debug.process_error("abs needs 1 argument, but received #{args.length}", env) if args.length != 1
329
331
  arg = args.car.evaluate(env)
330
- raise "abs needs a numeric argument, but received #{arg}" unless arg.number?
332
+ return Lisp::Debug.process_error("abs needs a numeric argument, but received #{arg}", env) unless arg.number?
331
333
  Number.with_value(arg.value.abs)
332
334
  end
333
335
 
334
336
 
335
337
  def self.sqrt_impl(args, env)
336
- raise "sqrt needs 1 argument, but received #{args.length}" if args.length != 1
338
+ return Lisp::Debug.process_error("sqrt needs 1 argument, but received #{args.length}", env) if args.length != 1
337
339
  arg = args.car.evaluate(env)
338
- raise "sqrt needs a numeric argument, but received #{arg}" unless arg.number?
340
+ return Lisp::Debug.process_error("sqrt needs a numeric argument, but received #{arg}", env) unless arg.number?
339
341
  Number.with_value(::Math.sqrt(arg.value).round(5))
340
342
  end
341
343
 
342
344
 
343
345
  def self.min_impl(args, env)
344
- raise "min needs at least 1 argument" if args.length == 0
346
+ return Lisp::Debug.process_error("min needs at least 1 argument", env) if args.length == 0
345
347
 
346
348
  initial = args.car.evaluate(env)
347
- raise "min requires numeric arguments, but received #{initial}" unless initial.type ==:number
349
+ return Lisp::Debug.process_error("min requires numeric arguments, but received #{initial}", env) unless initial.type ==:number
348
350
  acc = initial.value
349
351
  c = args.cdr
350
352
  while !c.nil?
351
353
  n = c.car.evaluate(env)
352
- raise "min needs number arguments, but received #{n}" unless n.type == :number
354
+ return Lisp::Debug.process_error("min needs number arguments, but received #{n}", env) unless n.type == :number
353
355
  acc = n.value if n.value < acc
354
356
  c = c.cdr
355
357
  end
@@ -359,14 +361,14 @@ largest integer less than or equal to `number` is returned.") do |args, env|
359
361
 
360
362
 
361
363
  def self.max_impl(args, env)
362
- raise "max needs at least 1 argumenta" if args.length == 0
364
+ return Lisp::Debug.process_error("max needs at least 1 argumenta", env) if args.length == 0
363
365
  initial = args.car.evaluate(env)
364
- raise "max requires numeric arguments, but received #{initial}" unless initial.type ==:number
366
+ return Lisp::Debug.process_error("max requires numeric arguments, but received #{initial}", env) unless initial.type ==:number
365
367
  acc = initial.value
366
368
  c = args.cdr
367
369
  while !c.nil?
368
370
  n = c.car.evaluate(env)
369
- raise "max needs number arguments, but received #{n}" unless n.type == :number
371
+ return Lisp::Debug.process_error("max needs number arguments, but received #{n}", env) unless n.type == :number
370
372
  acc = n.value if n.value > acc
371
373
  c = c.cdr
372
374
  end
@@ -376,25 +378,25 @@ largest integer less than or equal to `number` is returned.") do |args, env|
376
378
 
377
379
 
378
380
  def self.sin_impl(args, env)
379
- raise "sin needs 1 argument, but received #{args.length}" if args.length != 1
381
+ return Lisp::Debug.process_error("sin needs 1 argument, but received #{args.length}", env) if args.length != 1
380
382
  arg = args.car.evaluate(env)
381
- raise "sin needs a numeric argument, but received #{arg}" unless arg.number?
383
+ return Lisp::Debug.process_error("sin needs a numeric argument, but received #{arg}", env) unless arg.number?
382
384
  Number.with_value(::Math.sin(arg.value).round(5))
383
385
  end
384
386
 
385
387
 
386
388
  def self.cos_impl(args, env)
387
- raise "cos needs 1 argument, but received #{args.length}" if args.length != 1
389
+ return Lisp::Debug.process_error("cos needs 1 argument, but received #{args.length}", env) if args.length != 1
388
390
  arg = args.car.evaluate(env)
389
- raise "cos needs a numeric argument, but received #{arg}" unless arg.number?
391
+ return Lisp::Debug.process_error("cos needs a numeric argument, but received #{arg}", env) unless arg.number?
390
392
  Number.with_value(::Math.cos(arg.value).round(5))
391
393
  end
392
394
 
393
395
 
394
396
  def self.tan_impl(args, env)
395
- raise "tan needs 1 argument, but received #{args.length}" if args.length != 1
397
+ return Lisp::Debug.process_error("tan needs 1 argument, but received #{args.length}", env) if args.length != 1
396
398
  arg = args.car.evaluate(env)
397
- raise "tan needs a numeric argument, but received #{arg}" unless arg.number?
399
+ return Lisp::Debug.process_error("tan needs a numeric argument, but received #{arg}", env) unless arg.number?
398
400
  Number.with_value(::Math.tan(arg.value).round(5))
399
401
  end
400
402
 
@@ -7,7 +7,7 @@ module Lisp
7
7
  end
8
8
 
9
9
  def self.wrap_impl(args, env)
10
- raise "wrap-object requires 1 argument" unless args.length == 1
10
+ return Lisp::Debug.process_error("wrap-object requires 1 argument", env) unless args.length == 1
11
11
  raw_val = args.car.evaluate(env)
12
12
  val = if raw_val.list?
13
13
  raw_val.to_a
@@ -45,12 +45,12 @@ 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
- raise "Expected ')' on line #{tokens.line_number}" if tok != :RPAREN
48
+ return Lisp::Debug.process_error("Expected ')' to follow a dotted tail on line #{tokens.line_number}", env) 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
- raise "Unexpected EOF (expected closing parenthesis) on line #{tokens.line_number}" if tokens.next_token[0] == :EOF
53
+ return Lisp::Debug.process_error("Unexpected EOF (expected ')') on line #{tokens.line_number}", env) if tokens.next_token[0] == :EOF
54
54
  cells << car
55
55
  end
56
56
  tok, lit = tokens.next_token
@@ -71,7 +71,7 @@ module Lisp
71
71
  cells = []
72
72
  while tok != :RBRACE
73
73
  item = self.parse_sexpr(tokens)
74
- raise "Unexpected EOF (expected closing brace) on line #{tokens.line_number}" if tokens.next_token[0] == :EOF
74
+ return Lisp::Debug.process_error("Unexpected EOF (expected '}') on line #{tokens.line_number}", env) if tokens.next_token[0] == :EOF
75
75
  cells << item
76
76
  tok, lit = tokens.next_token
77
77
  end
@@ -92,7 +92,7 @@ module Lisp
92
92
  cells = []
93
93
  while tok != :RBRACKET
94
94
  item = self.parse_sexpr(tokens)
95
- raise "Unexpected EOF (expected closing bracket) on line #{tokens.line_number}" if tokens.next_token[0] == :EOF
95
+ return Lisp::Debug.process_error("Unexpected EOF (expected ']') on line #{tokens.line_number}", env) if tokens.next_token[0] == :EOF
96
96
  cells << item
97
97
  tok, lit = tokens.next_token
98
98
  end
@@ -152,7 +152,7 @@ module Lisp
152
152
  expr = parse_sexpr(tokens)
153
153
  return ConsCell.array_to_list([Symbol.named('unquote-splicing'), expr])
154
154
  when :ILLEGAL
155
- raise "Illegal token: #{lit} on line #{tokens.line_number}"
155
+ return Lisp::Debug.process_error("Illegal token: #{lit} on line #{tokens.line_number}", Lisp::EnvironmentFrame.global)
156
156
  else
157
157
  return make_symbol(lit)
158
158
  end
@@ -2,7 +2,7 @@ module Lisp
2
2
 
3
3
  class Primitive < Atom
4
4
 
5
- attr_reader :doc
5
+ attr_reader :doc, :name
6
6
 
7
7
  def self.register(name, doc="", special=false, env=Lisp::EnvironmentFrame.global, &implementation)
8
8
  instance = self.new(name, doc, special, &implementation)
@@ -22,22 +22,22 @@ module Lisp
22
22
 
23
23
 
24
24
  def self.lt_impl(args, env)
25
- raise "< needs at least 2 arguments" unless args.length > 1
25
+ return Lisp::Debug.process_error("< needs at least 2 arguments", env) unless args.length > 1
26
26
  return Lisp::Boolean.with_value(args.car.evaluate(env).value < args.cadr.evaluate(env).value)
27
27
  end
28
28
 
29
29
  def self.gt_impl(args, env)
30
- raise "> needs at least 2 arguments" unless args.length > 1
30
+ return Lisp::Debug.process_error("> needs at least 2 arguments", env) unless args.length > 1
31
31
  return Lisp::Boolean.with_value(args.car.evaluate(env).value > args.cadr.evaluate(env).value)
32
32
  end
33
33
 
34
34
  def self.lteq_impl(args, env)
35
- raise "<= needs at least 2 arguments" unless args.length > 1
35
+ return Lisp::Debug.process_error("<= needs at least 2 arguments", env) unless args.length > 1
36
36
  return Lisp::Boolean.with_value(args.car.evaluate(env).value <= args.cadr.evaluate(env).value)
37
37
  end
38
38
 
39
39
  def self.gteq_impl(args, env)
40
- raise ">= needs at least 2 arguments" unless args.length > 1
40
+ return Lisp::Debug.process_error(">= needs at least 2 arguments", env) unless args.length > 1
41
41
  return Lisp::Boolean.with_value(args.car.evaluate(env).value >= args.cadr.evaluate(env).value)
42
42
  end
43
43
 
@@ -161,7 +161,7 @@ useful in macros when you need a unique name for something.") do |args, env|
161
161
  return result
162
162
  end
163
163
  else
164
- raise "Case requires non-atomic clauses"
164
+ return Lisp::Debug.process_error("Case requires non-atomic clauses", env)
165
165
  end
166
166
  end
167
167
  return nil
@@ -169,7 +169,7 @@ useful in macros when you need a unique name for something.") do |args, env|
169
169
 
170
170
 
171
171
  def self.if_impl(args, env)
172
- raise "IF requires a condition, true action, and possibly an else action" unless args.length == 2 || args.length == 3
172
+ return Lisp::Debug.process_error("IF requires a condition, true action, and possibly an else action", env) unless args.length == 2 || args.length == 3
173
173
  condition = args.car.evaluate(env)
174
174
  if condition.true?
175
175
  args.cadr.evaluate(env)
@@ -182,7 +182,7 @@ useful in macros when you need a unique name for something.") do |args, env|
182
182
 
183
183
 
184
184
  def self.when_impl(args, env)
185
- raise "WHEN requires a condition and sexprs to evaluate." unless args.length >= 2
185
+ return Lisp::Debug.process_error("WHEN requires a condition and sexprs to evaluate.", env) unless args.length >= 2
186
186
  condition = args.car.evaluate(env)
187
187
  return args.cdr.evaluate_each(env) if condition.true?
188
188
  nil
@@ -190,7 +190,7 @@ useful in macros when you need a unique name for something.") do |args, env|
190
190
 
191
191
 
192
192
  def self.unless_impl(args, env)
193
- raise "UNLESS requires a condition and sexprs to evaluate." unless args.length >= 2
193
+ return Lisp::Debug.process_error("UNLESS requires a condition and sexprs to evaluate.", env) unless args.length >= 2
194
194
  condition = args.car.evaluate(env)
195
195
  return args.cdr.evaluate_each(env) unless condition.true?
196
196
  nil
@@ -205,7 +205,7 @@ useful in macros when you need a unique name for something.") do |args, env|
205
205
 
206
206
 
207
207
  def self.define_variable(definition, value, env)
208
- raise "Variable names must be literal symbols." unless definition.symbol?
208
+ return Lisp::Debug.process_error("Variable names must be literal symbols.", env) unless definition.symbol?
209
209
 
210
210
  ev = value.evaluate(env)
211
211
  Lisp::EnvironmentFrame.global.bind(definition, ev)
@@ -215,7 +215,7 @@ useful in macros when you need a unique name for something.") do |args, env|
215
215
 
216
216
  def self.define_function(definition, body, env)
217
217
  name = definition.car
218
- raise "Function name must be a symbol" unless name.symbol?
218
+ return Lisp::Debug.process_error("Function name must be a symbol", env) unless name.symbol?
219
219
  arguments = definition.cdr
220
220
  doc = nil
221
221
  if body.car.string?
@@ -230,7 +230,7 @@ useful in macros when you need a unique name for something.") do |args, env|
230
230
 
231
231
  def self.defun_impl(args, env)
232
232
  definition = args.car
233
- raise("Function definition must specify name and parameters in a list") unless definition.list?
233
+ return Lisp::Debug.process_error("Function definition must specify name and parameters in a list", env) unless definition.list?
234
234
  define_function(definition, args.cdr, env)
235
235
  end
236
236
 
@@ -240,16 +240,16 @@ useful in macros when you need a unique name for something.") do |args, env|
240
240
  if definition.list?
241
241
  define_function(definition, args.cdr, env)
242
242
  else
243
- raise "A symbol can be bound to only a single value." unless args.cdr.length == 1
243
+ return Lisp::Debug.process_error("A symbol can be bound to only a single value.", env) unless args.cdr.length == 1
244
244
  define_variable(definition, args.cadr, env)
245
245
  end
246
246
  end
247
247
 
248
248
 
249
249
  def self.defmacro_impl(args, env)
250
- raise "defmacro requires 2 or 3 arguments: a name and argument list, and a template expression." unless args.length == 2 || args.length == 3
250
+ return Lisp::Debug.process_error("defmacro requires 2 or 3 arguments: a name and argument list, and a template expression.", env) unless args.length == 2 || args.length == 3
251
251
  definition = args.car
252
- raise "defmacro requires macro name and args in a list as it's first argument." if definition.nil? || !definition.list?
252
+ return Lisp::Debug.process_error("defmacro requires macro name and args in a list as it's first argument.", env) if definition.nil? || !definition.list?
253
253
  name = definition.car
254
254
  arguments = definition.cdr
255
255
  doc = nil
@@ -270,11 +270,11 @@ useful in macros when you need a unique name for something.") do |args, env|
270
270
 
271
271
 
272
272
  def self.gensym_impl(args, env)
273
- raise "gensym requires 0 or 1 argument" if args.length > 1
273
+ return Lisp::Debug.process_error("gensym requires 0 or 1 argument", env) if args.length > 1
274
274
  prefix = if args.length == 0
275
275
  "GENSYM"
276
276
  else
277
- raise "gensym's argument must be a string" unless args.car.string?
277
+ return Lisp::Debug.process_error("gensym's argument must be a string", env) unless args.car.string?
278
278
  args.car.to_s
279
279
  end
280
280
  sym = Lisp::Symbol.named("#{prefix}-#{@@SYMBOL_COUNT}")
@@ -285,7 +285,7 @@ useful in macros when you need a unique name for something.") do |args, env|
285
285
 
286
286
  def self.expand_impl(args, env)
287
287
  macro = args.car.evaluate(env)
288
- raise "The first argument to expand must be a macro" unless macro.macro?
288
+ return Lisp::Debug.process_error("The first argument to expand must be a macro", env) unless macro.macro?
289
289
  macro.expand(args.cdr, env, true)
290
290
  end
291
291
 
@@ -321,9 +321,9 @@ useful in macros when you need a unique name for something.") do |args, env|
321
321
 
322
322
  def self.do_let_bindings(bindings, binding_env, local_env)
323
323
  bindings.each do |binding_pair|
324
- raise "let requires a list of bindings (that are 2 element lists) as it's first argument" unless binding_pair.list?
324
+ return Lisp::Debug.process_error("let requires a list of bindings (that are 2 element lists) as it's first argument", env) unless binding_pair.list?
325
325
  name = binding_pair.car
326
- raise "the first part of a let binding pair must be a symbol" unless name.symbol?
326
+ return Lisp::Debug.process_error("the first part of a let binding pair must be a symbol", env) unless name.symbol?
327
327
  value = binding_pair.cadr.evaluate(binding_env)
328
328
  local_env.bind_locally(name, value)
329
329
  end
@@ -332,8 +332,9 @@ useful in macros when you need a unique name for something.") do |args, env|
332
332
 
333
333
  def self.let_impl(args, env)
334
334
  bindings = args.car || Lisp::ConsCell.new
335
- raise "let requires a list of bindings as it's firest argument" unless bindings.list?
335
+ return Lisp::Debug.process_error("let requires a list of bindings as it's firest argument", env) unless bindings.list?
336
336
  local_frame = EnvironmentFrame.extending(env)
337
+ local_frame.previous = env
337
338
  do_let_bindings(bindings, env, local_frame)
338
339
  args.cdr.evaluate_each(local_frame)
339
340
  end
@@ -341,7 +342,7 @@ useful in macros when you need a unique name for something.") do |args, env|
341
342
 
342
343
  def self.letstar_impl(args, env)
343
344
  bindings = args.car || Lisp::ConsCell.new
344
- raise "let requires a list of bindings as it's firest argument" unless bindings.list?
345
+ return Lisp::Debug.process_error("let requires a list of bindings as it's firest argument", env) unless bindings.list?
345
346
  local_frame = EnvironmentFrame.extending(env)
346
347
  do_let_bindings(bindings, local_frame, local_frame)
347
348
  args.cdr.evaluate_each(local_frame)
@@ -354,19 +355,20 @@ useful in macros when you need a unique name for something.") do |args, env|
354
355
 
355
356
 
356
357
  def self.do_impl(args, env)
357
- raise "Do requires at least a list of bindings and a test clause" if args.length < 2
358
+ return Lisp::Debug.process_error("Do requires at least a list of bindings and a test clause", env) if args.length < 2
358
359
  bindings = args.car
359
- raise "Do requires a list of bindings as it's first argument" unless bindings.list?
360
+ return Lisp::Debug.process_error("Do requires a list of bindings as it's first argument", env) unless bindings.list?
360
361
  test_clause = args.cadr
361
- raise "Do requires a list of termination condition and result expressions as it's second argument" unless test_clause.list?
362
+ return Lisp::Debug.process_error("Do requires a list of termination condition and result expressions as it's second argument", env) unless test_clause.list?
362
363
  body = args.cddr
363
364
 
364
365
  local_frame = EnvironmentFrame.extending(env)
366
+ local_frame.previous = env
365
367
 
366
368
  bindings.each do |binding|
367
- raise "do bindings must be (name initial next)" unless binding.list?
369
+ return Lisp::Debug.process_error("do bindings must be (name initial next)", env) unless binding.list?
368
370
  name = binding.car
369
- raise "binding name must be a symbol" unless name.symbol?
371
+ return Lisp::Debug.process_error("binding name must be a symbol", env) unless name.symbol?
370
372
  value = binding.cadr.evaluate(local_frame)
371
373
  local_frame.bind_locally(name, value)
372
374
  end
@@ -391,16 +393,16 @@ useful in macros when you need a unique name for something.") do |args, env|
391
393
 
392
394
 
393
395
  def self.eval_impl(args, env)
394
- raise "eval expects a single argument, received #{args.length}." if args.length != 1
396
+ return Lisp::Debug.process_error("eval expects a single argument, received #{args.length}.", env) if args.length != 1
395
397
  arg = args.car.evaluate(env)
396
- raise "eval expect a list argument, received a #{arg.type}." unless arg.list?
398
+ return Lisp::Debug.process_error("eval expect a list argument, received a #{arg.type}.", env) unless arg.list?
397
399
  arg.evaluate(env)
398
400
  end
399
401
 
400
402
 
401
403
  def self.apply_impl(args, env)
402
404
  func = args.car.evaluate(env)
403
- raise "Expected #{args.car} to evaluate to a function." unless func.primitive? || func.function?
405
+ return Lisp::Debug.process_error("Expected #{args.car} to evaluate to a function.", env) unless func.primitive? || func.function?
404
406
 
405
407
  a = args.cdr.to_a.collect {|sexpr| sexpr.evaluate(env)}
406
408
  arg_list = if a[-1].list?
@@ -413,7 +415,7 @@ useful in macros when you need a unique name for something.") do |args, env|
413
415
 
414
416
 
415
417
  def self.chain_impl(args, env)
416
- raise "-> requires at the very least an initial value." unless args.length > 0
418
+ return Lisp::Debug.process_error("-> requires at the very least an initial value.", env) unless args.length > 0
417
419
  value = args.car.evaluate(env)
418
420
  cell = args.cdr
419
421
  while !cell.nil?
@@ -432,7 +434,7 @@ useful in macros when you need a unique name for something.") do |args, env|
432
434
 
433
435
 
434
436
  def self.tap_impl(args, env)
435
- raise "tap requires at the very least an initial value." unless args.length > 0
437
+ return Lisp::Debug.process_error("tap requires at the very least an initial value.", env) unless args.length > 0
436
438
  value = args.car.evaluate(env)
437
439
  cell = args.cdr
438
440
  while !cell.nil?