rubylisp 0.1.1 → 0.2.0

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