rubylisp 0.2.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +129 -2
  3. data/bin/rubylisp +87 -12
  4. data/lib/rubylisp/atom.rb +25 -6
  5. data/lib/rubylisp/boolean.rb +9 -6
  6. data/lib/rubylisp/builtins.rb +19 -18
  7. data/lib/rubylisp/character.rb +14 -275
  8. data/lib/rubylisp/class_object.rb +56 -0
  9. data/lib/rubylisp/cons_cell.rb +56 -25
  10. data/lib/rubylisp/debug.rb +15 -19
  11. data/lib/rubylisp/environment.rb +27 -0
  12. data/lib/rubylisp/environment_frame.rb +31 -6
  13. data/lib/rubylisp/eof_object.rb +26 -0
  14. data/lib/rubylisp/exception.rb +61 -61
  15. data/lib/rubylisp/ext.rb +32 -6
  16. data/lib/rubylisp/ffi_new.rb +2 -1
  17. data/lib/rubylisp/ffi_send.rb +15 -5
  18. data/lib/rubylisp/frame.rb +5 -164
  19. data/lib/rubylisp/function.rb +4 -3
  20. data/lib/rubylisp/macro.rb +13 -8
  21. data/lib/rubylisp/{object.rb → native_object.rb} +0 -15
  22. data/lib/rubylisp/number.rb +5 -0
  23. data/lib/rubylisp/parser.rb +81 -52
  24. data/lib/rubylisp/port.rb +27 -0
  25. data/lib/rubylisp/prim_alist.rb +115 -0
  26. data/lib/rubylisp/prim_assignment.rb +61 -0
  27. data/lib/rubylisp/prim_character.rb +273 -0
  28. data/lib/rubylisp/{ffi_class.rb → prim_class_object.rb} +16 -69
  29. data/lib/rubylisp/prim_environment.rb +203 -0
  30. data/lib/rubylisp/prim_equivalence.rb +93 -0
  31. data/lib/rubylisp/prim_frame.rb +166 -0
  32. data/lib/rubylisp/prim_io.rb +266 -0
  33. data/lib/rubylisp/prim_list_support.rb +496 -0
  34. data/lib/rubylisp/{logical.rb → prim_logical.rb} +9 -14
  35. data/lib/rubylisp/prim_math.rb +397 -0
  36. data/lib/rubylisp/prim_native_object.rb +21 -0
  37. data/lib/rubylisp/prim_relational.rb +42 -0
  38. data/lib/rubylisp/{special_forms.rb → prim_special_forms.rb} +98 -85
  39. data/lib/rubylisp/prim_string.rb +792 -0
  40. data/lib/rubylisp/prim_system.rb +55 -0
  41. data/lib/rubylisp/prim_type_checks.rb +58 -0
  42. data/lib/rubylisp/prim_vector.rb +497 -0
  43. data/lib/rubylisp/primitive.rb +51 -6
  44. data/lib/rubylisp/string.rb +4 -803
  45. data/lib/rubylisp/symbol.rb +0 -1
  46. data/lib/rubylisp/tokenizer.rb +161 -137
  47. data/lib/rubylisp/vector.rb +10 -31
  48. data/lib/rubylisp.rb +1 -0
  49. metadata +46 -17
  50. data/lib/rubylisp/alist.rb +0 -230
  51. data/lib/rubylisp/assignment.rb +0 -65
  52. data/lib/rubylisp/equivalence.rb +0 -118
  53. data/lib/rubylisp/io.rb +0 -74
  54. data/lib/rubylisp/list_support.rb +0 -526
  55. data/lib/rubylisp/math.rb +0 -405
  56. data/lib/rubylisp/relational.rb +0 -46
  57. data/lib/rubylisp/system.rb +0 -20
  58. data/lib/rubylisp/testing.rb +0 -136
  59. data/lib/rubylisp/type_checks.rb +0 -60
@@ -0,0 +1,397 @@
1
+ module Lisp
2
+
3
+ class PrimMath
4
+
5
+ def self.register
6
+ self.bind("PI", ::Math::PI)
7
+ self.bind("E", ::Math::E)
8
+
9
+ Primitive.register("+", ">=1", "(+ number...)\n\nAdds a series of numbers.") do |args, env|
10
+ Lisp::PrimMath.add_impl(args, env)
11
+ end
12
+
13
+ Primitive.register("-", ">=1", "(- number...)\n\nSequentially subtracts a sequence of numbers.\nAs expected, a unary form of - is available as well.") do |args, env|
14
+ Lisp::PrimMath.subtract_impl(args, env)
15
+ end
16
+
17
+ Primitive.register("*", ">=1", "(* number...)\n\nMultiplies a series of numbers.") do |args, env|
18
+ Lisp::PrimMath.multiply_impl(args, env)
19
+ end
20
+
21
+ Primitive.register("/", ">=1", "(/ number...)\n\nSequentially divides a sequence of numbers.") do |args, env|
22
+ Lisp::PrimMath.quotient_impl(args, env)
23
+ end
24
+
25
+ Primitive.register("%", "1|2", "(% number number)\n\nReturns the remainder of the division of two numbers. NOTE: modulus only works for integers.") do |args, env|
26
+ Lisp::PrimMath.remainder_impl(args, env)
27
+ end
28
+
29
+ Primitive.register("modulo", "1|2", "(modulo number number)\n\nReturns the remainder of the division of two numbers. NOTE: modulus only works for integers.") do |args, env|
30
+ Lisp::PrimMath.remainder_impl(args, env)
31
+ end
32
+
33
+ Primitive.register("even?", "1", "(even? number)\n\nReturns whether the argument is even.") do |args, env|
34
+ Lisp::PrimMath.even_impl(args, env)
35
+ end
36
+
37
+ Primitive.register("odd?", "1", "(odd? number)\n\nReturns whether the argument is odd.") do |args, env|
38
+ Lisp::PrimMath.odd_impl(args, env)
39
+ end
40
+
41
+ Primitive.register("zero?", "1", "(zero? number)\n\nReturns whether the argument is zero.") do |args, env|
42
+ Lisp::PrimMath.zero_impl(args, env)
43
+ end
44
+
45
+ Primitive.register("positive?", "1", "(positive? number)\n\nReturns whether the argument is positive.") do |args, env|
46
+ Lisp::PrimMath.positive_impl(args, env)
47
+ end
48
+
49
+ Primitive.register("negative?", "1", "(negative? number)\n\nReturns whether the argument is negative.") do |args, env|
50
+ Lisp::PrimMath.negative_impl(args, env)
51
+ end
52
+
53
+ Primitive.register("interval", "2", "(interval lo hi)\n\nCreates a list of numbers from `lo` to `hi`, inclusive.") do |args, env|
54
+ Lisp::PrimMath.interval_impl(args, env)
55
+ end
56
+
57
+ Primitive.register("truncate", "1", "(truncate number)\n\nReturns the integer value of number. If it is an integer, it is simply returned. However, if it is a float the integer part is returned.") do |args, env|
58
+ Lisp::PrimMath.truncate_impl(args, env)
59
+ end
60
+
61
+ Primitive.register("round", "1", "(round number)\n\nIf number is an integer, it is simply returned. However, if it is a float the closest integer is returned.") do |args, env|
62
+ Lisp::PrimMath.round_impl(args, env)
63
+ end
64
+
65
+ Primitive.register("ceiling", "1", "(ceiling number)\n\nIf `number` is an integer, it is simply returned. However, if it is a float the smallest integer greater than or equal to `number` is returned.") do |args, env|
66
+ Lisp::PrimMath.ceiling_impl(args, env)
67
+ end
68
+
69
+ Primitive.register("floor", "1", "(floor number)\n\nIf `number` is an integer, it is simply returned. However, if it is a float the
70
+ largest integer less than or equal to `number` is returned.") do |args, env|
71
+ Lisp::PrimMath.floor_impl(args, env)
72
+ end
73
+
74
+ Primitive.register("random", "0|1", "(random)\n\nReturns a pseudo-random floating point number between 0.0 and 1.0, including 0.0 and excluding 1.0.\n\n(random n)\n\nReturns a pseudo-random integer greater than or equal to 0 and less than n.") do |args, env|
75
+ Lisp::PrimMath.random_impl(args, env)
76
+ end
77
+
78
+ Primitive.register("float", "1", "(float number)\n\nReturns the floating point value of number. If it is a float, it is simply returned. However, if it is an integer it is converted to float and returned.") do |args, env|
79
+ Lisp::PrimMath.float_impl(args, env)
80
+ end
81
+
82
+ Primitive.register("integer", "1", "(integer number)\n\nReturns the integer value of number. If it is an integer, it is simply returned. However, if it is a float the integer part is returned. This is the same as tuncate.") do |args, env|
83
+ Lisp::PrimMath.integer_impl(args, env)
84
+ end
85
+
86
+ Primitive.register("sqrt", "1", "(sqrt number)\n\nReturns the square root of `number'.") do |args, env|
87
+ Lisp::PrimMath.sqrt_impl(args, env)
88
+ end
89
+
90
+ Primitive.register("min", ">=1", "(min number...)\n\nReturns the smallest of all the `number` arguments.") do |args, env|
91
+ Lisp::PrimMath.min_impl(args, env)
92
+ end
93
+
94
+ Primitive.register("max", ">=1", "(max number...)\n\nReturns the largest of all the `number` arguments.") do |args, env|
95
+ Lisp::PrimMath.max_impl(args, env)
96
+ end
97
+
98
+ Primitive.register("abs", "1", "(abs number)\n\nReturns the absolute value of `number'.") do |args, env|
99
+ Lisp::PrimMath.abs_impl(args, env)
100
+ end
101
+
102
+ Primitive.register("sin", "1", "(sin number)\n\nReturns the sine of `number'.") do |args, env|
103
+ Lisp::PrimMath.sin_impl(args, env)
104
+ end
105
+
106
+ Primitive.register("cos", "1", "(cos number)\n\nReturns the cosine of `number'.") do |args, env|
107
+ Lisp::PrimMath.cos_impl(args, env)
108
+ end
109
+
110
+ Primitive.register("tan", "1", "(tan number)\n\nReturns the tangent of `number'.") do |args, env|
111
+ Lisp::PrimMath.tan_impl(args, env)
112
+ end
113
+
114
+ Primitive.register("pred", "1", "(pred number)\n\nReturns one less than `number'.") do |args, env|
115
+ Lisp::PrimMath.pred_impl(args, env)
116
+ end
117
+
118
+ Primitive.register("succ", "1", "(succ number)\n\nReturns one more than `number'.") do |args, env|
119
+ Lisp::PrimMath.succ_impl(args, env)
120
+ end
121
+
122
+
123
+ end
124
+
125
+
126
+ def self.bind(name, number)
127
+ EnvironmentFrame.global.bind(Symbol.named(name), Number.with_value(number))
128
+ end
129
+
130
+ def self.add_impl(args, env)
131
+ acc = 0
132
+ c = args
133
+ while !c.nil?
134
+ n = c.car
135
+ return Lisp::Debug.process_error("add needs number arguments but was given a #{n.type}: #{n}", env) unless n.type == :number
136
+ acc += n.value
137
+ c = c.cdr
138
+ end
139
+
140
+ Number.with_value(acc)
141
+ end
142
+
143
+
144
+ def self.subtract_impl(args, env)
145
+ return Number.with_value(-1 * args.car.value) if args.length == 1
146
+
147
+ first = args.car
148
+ return Lisp::Debug.process_error("subtract needs number arguments, but received #{first}", env) unless first.number?
149
+ acc = first.value
150
+ c = args.cdr
151
+ while !c.nil?
152
+ n = c.car
153
+ return Lisp::Debug.process_error("subtract needs number arguments, but received #{n}", env) unless n.number?
154
+ acc -= n.value
155
+ c = c.cdr
156
+ end
157
+
158
+ Number.with_value(acc)
159
+ end
160
+
161
+
162
+ def self.multiply_impl(args, env)
163
+ acc = 1
164
+ c = args
165
+ while !c.nil?
166
+ n = c.car
167
+ return Lisp::Debug.process_error("multiply needs number arguments, but received #{n}", env) unless n.number?
168
+ acc *= n.value
169
+ c = c.cdr
170
+ end
171
+
172
+ Number.with_value(acc)
173
+ end
174
+
175
+
176
+ def self.quotient_impl(args, env)
177
+ first = args.car
178
+ return Lisp::Debug.process_error("quotient needs number arguments, but received #{first}", env) unless first.number?
179
+ return first if args.length == 1
180
+ acc = first.value
181
+ c = args.cdr
182
+ while !c.nil?
183
+ n = c.car
184
+ return Lisp::Debug.process_error("quotient needs number arguments, but received #{n}", env) unless n.number?
185
+ return Lisp::Debug.process_error("divide by zero", env) if n.value == 0
186
+ acc /= n.value
187
+ c = c.cdr
188
+ end
189
+
190
+ Number.with_value(acc)
191
+ end
192
+
193
+
194
+ def self.remainder_impl(args, env)
195
+ first = args.car
196
+ return Lisp::Debug.process_error("remainder needs number arguments, but received #{first}", env) unless first.number?
197
+ return first if args.length == 1
198
+ acc = first.value
199
+ c = args.cdr
200
+ while !c.nil?
201
+ n = c.car
202
+ return Lisp::Debug.process_error("remainder needs number arguments, but received #{n}", env) unless n.number?
203
+ return Lisp::Debug.process_error("divide by zero", env) if n.value == 0
204
+ acc %= n.value
205
+ c = c.cdr
206
+ end
207
+
208
+ Number.with_value(acc)
209
+ end
210
+
211
+ def self.truncate_impl(args, env)
212
+ arg = args.car
213
+ return Lisp::Debug.process_error("truncate needs a number argument, but received #{arg}", env) unless arg.number?
214
+ Number.with_value(arg.value.truncate)
215
+ end
216
+
217
+
218
+ def self.round_impl(args, env)
219
+ arg = args.car
220
+ return Lisp::Debug.process_error("round needs a number argument, but received #{arg}", env) unless arg.number?
221
+ num = arg.value
222
+ int = num.to_i
223
+ Number.with_value(if (num - int).abs == 0.5
224
+ if int.even?
225
+ int
226
+ else
227
+ int + (int < 0 ? -1 : 1)
228
+ end
229
+ else
230
+ arg.value.round
231
+ end)
232
+ end
233
+
234
+
235
+ def self.ceiling_impl(args, env)
236
+ arg = args.car
237
+ return Lisp::Debug.process_error("ceiling needs a number argument, but received #{arg}", env) unless arg.number?
238
+ Number.with_value(arg.value.ceil)
239
+ end
240
+
241
+
242
+ def self.floor_impl(args, env)
243
+ arg = args.car
244
+ return Lisp::Debug.process_error("floor needs a number argument, but received #{arg}", env) unless arg.number?
245
+ Number.with_value(arg.value.floor)
246
+ end
247
+
248
+
249
+ def self.even_impl(args, env)
250
+ arg = args.car
251
+ return Lisp::Debug.process_error("even? needs a number argument, but received #{arg}", env) unless arg.number?
252
+ Boolean.with_value(arg.value.even?)
253
+ end
254
+
255
+
256
+ def self.odd_impl(args, env)
257
+ arg = args.car
258
+ return Lisp::Debug.process_error("odd? needs a number argument, but received #{arg}", env) unless arg.number?
259
+ Boolean.with_value(arg.value.odd?)
260
+ end
261
+
262
+
263
+ def self.zero_impl(args, env)
264
+ arg = args.car
265
+ return Lisp::Debug.process_error("zero? needs a number argument, but received #{arg}", env) unless arg.number?
266
+ Boolean.with_value(arg.value.zero?)
267
+ end
268
+
269
+
270
+ def self.positive_impl(args, env)
271
+ arg = args.car
272
+ return Lisp::Debug.process_error("positive? needs a number argument, but received #{arg}", env) unless arg.number?
273
+ Boolean.with_value(arg.value > 0)
274
+ end
275
+
276
+
277
+ def self.negative_impl(args, env)
278
+ arg = args.car
279
+ return Lisp::Debug.process_error("negative? needs a number argument, but received #{arg}", env) unless arg.number?
280
+ Boolean.with_value(arg.value < 0)
281
+ end
282
+
283
+
284
+ def self.interval_impl(args, env)
285
+ initial = args.car
286
+ return Lisp::Debug.process_error("interval needs number arguments, but received #{initial}", env) unless initial.number?
287
+ final = args.cadr
288
+ return Lisp::Debug.process_error("interval needs number arguments, but received #{final}", env) unless final.number?
289
+ return Lisp::Debug.process_error("interval's arguments need to be in natural order", env) unless initial.value <= final.value
290
+ Lisp::ConsCell.array_to_list((initial.value..final.value).to_a.map {|n| Number.with_value(n)})
291
+ end
292
+
293
+
294
+ def self.random_impl(args, env)
295
+ arg = args.car
296
+ return Lisp::Debug.process_error("random needs a number argument, but received #{arg}", env) unless arg.nil? || arg.number?
297
+ Number.with_value(arg.nil? ? rand() : rand(arg.value))
298
+ end
299
+
300
+
301
+ def self.float_impl(args, env)
302
+ arg = args.car
303
+ return Lisp::Debug.process_error("float needs a numeric or string argument, but received #{arg}", env) unless arg.number? || arg.string?
304
+ Number.with_value(arg.value.to_f)
305
+ end
306
+
307
+
308
+ def self.integer_impl(args, env)
309
+ arg = args.car
310
+ return Lisp::Debug.process_error("integer needs a numeric or string argument, but received #{arg}", env) unless arg.number? || arg.string?
311
+ Number.with_value(arg.value.to_i)
312
+ end
313
+
314
+
315
+ def self.abs_impl(args, env)
316
+ arg = args.car
317
+ return Lisp::Debug.process_error("abs needs a numeric argument, but received #{arg}", env) unless arg.number?
318
+ Number.with_value(arg.value.abs)
319
+ end
320
+
321
+
322
+ def self.sqrt_impl(args, env)
323
+ arg = args.car
324
+ return Lisp::Debug.process_error("sqrt needs a numeric argument, but received #{arg}", env) unless arg.number?
325
+ Number.with_value(::Math.sqrt(arg.value).round(5))
326
+ end
327
+
328
+
329
+ def self.min_impl(args, env)
330
+ initial = args.car
331
+ return Lisp::Debug.process_error("min requires numeric arguments, but received #{initial}", env) unless initial.number?
332
+ acc = initial.value
333
+ c = args.cdr
334
+ while !c.nil?
335
+ n = c.car
336
+ return Lisp::Debug.process_error("min needs number arguments, but received #{n}", env) unless n.number?
337
+ acc = n.value if n.value < acc
338
+ c = c.cdr
339
+ end
340
+
341
+ Number.with_value(acc)
342
+ end
343
+
344
+
345
+ def self.max_impl(args, env)
346
+ initial = args.car
347
+ return Lisp::Debug.process_error("max requires numeric arguments, but received #{initial}", env) unless initial.number?
348
+ acc = initial.value
349
+ c = args.cdr
350
+ while !c.nil?
351
+ n = c.car
352
+ return Lisp::Debug.process_error("max needs number arguments, but received #{n}", env) unless n.number?
353
+ acc = n.value if n.value > acc
354
+ c = c.cdr
355
+ end
356
+
357
+ Number.with_value(acc)
358
+ end
359
+
360
+
361
+ def self.sin_impl(args, env)
362
+ arg = args.car
363
+ return Lisp::Debug.process_error("sin needs a numeric argument, but received #{arg}", env) unless arg.number?
364
+ Number.with_value(::Math.sin(arg.value).round(5))
365
+ end
366
+
367
+
368
+ def self.cos_impl(args, env)
369
+ arg = args.car
370
+ return Lisp::Debug.process_error("cos needs a numeric argument, but received #{arg}", env) unless arg.number?
371
+ Number.with_value(::Math.cos(arg.value).round(5))
372
+ end
373
+
374
+
375
+ def self.tan_impl(args, env)
376
+ arg = args.car
377
+ return Lisp::Debug.process_error("tan needs a numeric argument, but received #{arg}", env) unless arg.number?
378
+ Number.with_value(::Math.tan(arg.value).round(5))
379
+ end
380
+
381
+
382
+ def self.pred_impl(args, env)
383
+ arg = args.car
384
+ return Lisp::Debug.process_error("pred needs a numeric argument, but received #{arg}", env) unless arg.number?
385
+ Number.with_value(arg.value - 1)
386
+ end
387
+
388
+
389
+ def self.succ_impl(args, env)
390
+ arg = args.car
391
+ return Lisp::Debug.process_error("succ needs a numeric argument, but received #{arg}", env) unless arg.number?
392
+ Number.with_value(arg.value + 1)
393
+ end
394
+
395
+
396
+ end
397
+ end
@@ -0,0 +1,21 @@
1
+ module Lisp
2
+
3
+ class PrimNativeObject
4
+
5
+ def self.register
6
+ Primitive.register("wrap-object", "1") {|args, env| Lisp::NativeObject::wrap_impl(args, env) }
7
+ end
8
+
9
+ def self.wrap_impl(args, env)
10
+ raw_val = args.car.evaluate(env)
11
+ val = if raw_val.list?
12
+ raw_val.to_a
13
+ else
14
+ raw_val
15
+ end
16
+ NativeObject.with_value(val)
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,42 @@
1
+ module Lisp
2
+
3
+ class PrimRelational
4
+
5
+ def self.register
6
+ Primitive.register("<", "2", "(< number number)\n\nReturns whether the first argument is less than the second argument.") do |args, env|
7
+ Lisp::PrimRelational::lt_impl(args, env)
8
+ end
9
+
10
+ Primitive.register(">", "2", "(> number number)\n\nReturns whether the first argument is greater than the second argument.") do |args, env|
11
+ Lisp::PrimRelational::gt_impl(args, env)
12
+ end
13
+
14
+ Primitive.register("<=", "2", "(<= number number)\n\nReturns whether the first argument is less than or equal to the second argument.") do |args, env|
15
+ Lisp::PrimRelational::lteq_impl(args, env)
16
+ end
17
+
18
+ Primitive.register(">=", "2", "(>= number number)\n\nReturns whether the first argument is greater than or equal to the second argument.") do |args, env|
19
+ Lisp::PrimRelational::gteq_impl(args, env)
20
+ end
21
+ end
22
+
23
+
24
+ def self.lt_impl(args, env)
25
+ return Lisp::Boolean.with_value(args.car.value < args.cadr.value)
26
+ end
27
+
28
+ def self.gt_impl(args, env)
29
+ return Lisp::Boolean.with_value(args.car.value > args.cadr.value)
30
+ end
31
+
32
+ def self.lteq_impl(args, env)
33
+ return Lisp::Boolean.with_value(args.car.value <= args.cadr.value)
34
+ end
35
+
36
+ def self.gteq_impl(args, env)
37
+ return Lisp::Boolean.with_value(args.car.value >= args.cadr.value)
38
+ end
39
+
40
+
41
+ end
42
+ end