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
@@ -1,128 +1,140 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  module Lisp
3
3
 
4
- class SpecialForms
4
+ class PrimSpecialForms
5
5
 
6
6
  def self.register
7
- Primitive.register("cond",
7
+ Primitive.register("cond", "*",
8
8
  "(cond (predicate sexpr...)... [(else sexpr...)])\n\nEach predicate is evaluated in order until one results in true value. The expressions associated with this predicate are then evaluated in order, and the result of the `cond` is the result of the last evaluation. If all predicates evaluate to false values, the value of `cond` in indeterminate. If, however, the final predicate is the symbol `else` the expressions associated with it are evaluated, and the value of `cond` is the value of the last evaluation.",
9
9
  true) do |args, env|
10
- Lisp::SpecialForms::cond_impl(args, env)
10
+ Lisp::PrimSpecialForms::cond_impl(args, env)
11
11
  end
12
12
 
13
- Primitive.register("case",
13
+ Primitive.register("case", ">=1",
14
14
  "(case target-sexpr ((value...) sexpr...)... [(else sexpr...)])\n\n`case` chooses code to evaluate based on the value of the target `sexpr`. Each condition clause is a list of possible values. A clause is selected if the target value is in it’s list of possible values. Any number of expressions can be associated with each target value.",
15
15
  true) do |args, env|
16
- Lisp::SpecialForms::case_impl(args, env)
16
+ Lisp::PrimSpecialForms::case_impl(args, env)
17
17
  end
18
18
 
19
- Primitive.register("if",
19
+ Primitive.register("if", "2|3",
20
20
  "(if condition true-clause)\n(if condition true-clause false-clause)\n\n`if` has two forms, one that conditionally evaluates a single `sexpr` (see `begin` which provides a way to use multiple `sexprs` in this context) and one that chooses an `sexpr` to evaluate based on the value of the condition.\n\nIn the single action version, `nil` is the value of the form when the conditions evaluates to `false`. Note that it is preferable to use `when` (see below) instead of this form of `if`.",
21
21
  true) do |args, env|
22
- Lisp::SpecialForms::if_impl(args, env)
22
+ Lisp::PrimSpecialForms::if_impl(args, env)
23
23
  end
24
24
 
25
- Primitive.register("when",
25
+ Primitive.register("when", ">=2",
26
26
  "(when condition sexpr...)\n\nIff the condition evaluates to logically true, the `sexprs` are evaluated and the result of the last one is the result of the form, otherwise nil is the result.",
27
27
  true) do |args, env|
28
- Lisp::SpecialForms::when_impl(args, env)
28
+ Lisp::PrimSpecialForms::when_impl(args, env)
29
29
  end
30
30
 
31
- Primitive.register("unless",
31
+ Primitive.register("unless", ">=2",
32
32
  "(unless condition sexpr...)\n\nIff the condition evaluates to logically false, the `sexprs` are evaluated and the result of the last one is the result of the form, otherwise nil is the result. This is the same functionally as `(when (not condition) sexpr...)` but is simpler and can be clearer.",
33
33
  true) do |args, env|
34
- Lisp::SpecialForms::unless_impl(args, env)
34
+ Lisp::PrimSpecialForms::unless_impl(args, env)
35
35
  end
36
36
 
37
- Primitive.register("lambda",
38
- "(lambda (param...) sexpr...)\n\nCreates an anonymous function. This can then be used in a function call.\n\n ((lambda (x)\n (+ x x))\n 5) ⇒ 10\n\nFunctions can be named (i.e. bound to a symbol) and later referred to by using define (but using `defun` is preferred):\n\n (define foo (lambda (x)\n (+ x x)))\n (foo 5) ⇒ 10\n\n`lambda` creates a local environment at the point of it’s evaluation. This environment is attached to the resulting function, and any binding or symbol lookup starts in this local environment.",
37
+ Primitive.register("lambda", ">=1",
38
+ "(lambda ([param...]) sexpr...)\n\nCreates an anonymous function. This can then be used in a function call.\n\n ((lambda (x)\n (+ x x))\n 5) ⇒ 10\n\nFunctions can be named (i.e. bound to a symbol) and later referred to by using define:\n\n (define foo (lambda (x)\n (+ x x)))\n (foo 5) ⇒ 10\n\n`lambda` creates a local environment at the point of it’s evaluation. This environment is attached to the resulting function, and any binding or symbol lookup starts in this local environment.",
39
39
  true) do |args, env|
40
- Lisp::SpecialForms::lambda_impl(args, env)
40
+ Lisp::PrimSpecialForms::lambda_impl(args, env)
41
41
  end
42
42
 
43
- Primitive.register("define",
43
+ Primitive.register("define", ">=2",
44
44
  "(define symbol value)\n\nEvaluates the value expression and binds it to the symbol, returning the value.",
45
45
  true) do |args, env|
46
- Lisp::SpecialForms::define_impl(args, env)
46
+ Lisp::PrimSpecialForms::define_impl(args, env)
47
47
  end
48
48
 
49
- Primitive.register("defun",
50
- "(defun (symbol param...) doc-string sexpr...)\n\nCreate a named function:\n\n`symbol` specifies the name (how you reference the function)\n\n`param...` parameters of the function, these are bound to the respective arguments when the function is called.\n\n`doc-string` is an optional documentation string.\n\n`sexpr...` the sequence of expressions that are evaluated in order when the function is called. The final evaluation result becomes the value of evaluation of the function.",
51
- true) do |args, env|
52
- Lisp::SpecialForms::defun_impl(args, env)
53
- end
54
-
55
- Primitive.register("defmacro",
49
+ Primitive.register("defmacro", "2|3",
56
50
  "(defmacro (symbol param...) sexpr)\n\nCreate a named macro:\n\n`symbol` specifies the name (how you reference the macro)\n\n`param...` parameters of the macro, these are bound to the respective arguments when the macro is invoked. **NOTE** that the arguments to a macro invokation are **not** evaluated, but are passed as is to the macro to do with as it wishes.\n\n`sexpr` the template expression that is processed when the macro is invoked. The result of evaluating the processed template expression becomes the value of the macro's invocation.",
57
51
  true) do |args, env|
58
- Lisp::SpecialForms::defmacro_impl(args, env)
52
+ Lisp::PrimSpecialForms::defmacro_impl(args, env)
59
53
  end
60
54
 
61
- Primitive.register("let",
55
+ Primitive.register("let", "*",
62
56
  "(let ((name value)...) sexpr...)\n\nCreate a local scope and bindings for evaluating a body of code. The first argument is a list of bindings. Each binding is a raw symbol (doesn’t get evaluated) that is the name to be bound, and a value (which is evaluated). These bindings are added to a scope that is local to the let. The body is evaluated in this local scope. The value of the `let` is the last evaluation result. Bindings values are evaluated in the environment where the `let` is defined, and so are independant.",
63
57
  true) do |args, env|
64
- Lisp::SpecialForms::let_impl(args, env)
58
+ Lisp::PrimSpecialForms::let_impl(args, env)
65
59
  end
66
60
 
67
- Primitive.register("let*",
61
+ Primitive.register("let*", "*",
68
62
  "(let* ((name value)...) sexpr...)\n\nCreate a local scope and bindings for evaluating a body of code. The first argument is a list of bindings. Each binding is a raw symbol (doesn’t get evaluated) that is the name to be bound, and a value (which is evaluated). Each binding’s value is evaluated in the context of the local scope. I.e. bindings cascade. The body is evaluated in this local scope. The value of the `let*` is the last evaluation result.",
69
63
  true) do |args, env|
70
- Lisp::SpecialForms::letstar_impl(args, env)
64
+ Lisp::PrimSpecialForms::letstar_impl(args, env)
71
65
  end
72
66
 
73
- Primitive.register("begin",
67
+ Primitive.register("begin", ">=1",
74
68
  "(begin sexpr...)\n\nEvaluates the each `sexpr` in order, returning the result of the last one evaluated. Used in a context that allows a single `sexpr` but you need multiple.",
75
69
  true) do |args, env|
76
- Lisp::SpecialForms::begin_impl(args, env)
70
+ Lisp::PrimSpecialForms::begin_impl(args, env)
77
71
  end
78
72
 
79
- Primitive.register("do",
73
+ Primitive.register("do", ">=2",
80
74
  "(do ((name initial next)...) ((test sexpr...)) sexpr...)\n\nThis is a general purpose iteration construct. There are three sections:\n\nbindings\nThis is similar to `let` in that it defines names that can be used in the remainder of the scope of the `do`. Like `let` it is a list of lists, each starting with the binding name followed by the initial value of the binding. The difference is that this is followed by an expression that is evaluated at the beginning of each subsequent pass through the loop, and whose result is used as a new binding of the name.\n\ntermination\nThis is a list whose first element is an expression which is evaluated before each pass through the loop (after rebinding the variables). If it evaluates to a truthy value, the remaining expressions are evaluated in turn. The result of the final one is used as the value of the `do`.\n\nbody\nThis is a sequence of expressions that are evaluated in order each time though the loop. This section can be empty.",
81
75
  true) do |args, env|
82
- Lisp::SpecialForms::do_impl(args, env)
76
+ Lisp::PrimSpecialForms::do_impl(args, env)
83
77
  end
84
78
 
85
- Primitive.register("eval",
79
+ Primitive.register("eval", "1",
86
80
  "(eval sexpr)\n\nEvaluate `sexpr`.",
87
81
  true) do |args, env|
88
- Lisp::SpecialForms::eval_impl(args, env)
82
+ Lisp::PrimSpecialForms::eval_impl(args, env)
89
83
  end
90
84
 
91
- Primitive.register("apply",
85
+ Primitive.register("apply", ">=2",
92
86
  "(apply function sexpr...)\n\nApply the function that results from evaluating `function` to the argument list resulting from evaluating each `sexpr`. Each initial `sexpr` can evaluate to any type of object, but the final one (and there must be at least one `sexpr`) must evaluate to a list.",
93
87
  true) do |args, env|
94
- Lisp::SpecialForms::apply_impl(args, env)
88
+ Lisp::PrimSpecialForms::apply_impl(args, env)
95
89
  end
96
90
 
97
- Primitive.register("=>",
91
+ Primitive.register("=>", ">=2",
98
92
  "(=> value sexpr|symbol...)\n\nThis creates a cascade.\n\n`value` (evaluated once at the beginning) is used as the initial argument to **each** function, and they are independent and do not pass results one to another. `value` is the result of the form.\n\nSince this is implemented by syntactic modification, a `lambda` form **cannot** be used here as an `sexpr`.",
99
93
  true) do |args, env|
100
- Lisp::SpecialForms::tap_impl(args, env)
94
+ Lisp::PrimSpecialForms::tap_impl(args, env)
101
95
  end
102
96
 
103
- Primitive.register("->",
97
+ Primitive.register("->", ">=2",
104
98
  "(-> value sexpr|symbol...)\n\nThis creates a function chain. `value` (evaluated first) is used as the first argument to the first `sexpr`. The result of each `sexpr` is used as the first argument of the next, and the result of the final `sexpr` is the value of the `->` form. If a `sexpr` would take a single argument (which would be provided by the `value` or the result of the previous `sexpr`, just the function name can be used. Since this is implemented by syntactic modification, a `lambda` form cannot be used here as an `sexpr`.\n\nThe form `(-> 0 a b c)` is equivalent to `(c (b (a 0)))`.",
105
99
  true) do |args, env|
106
- Lisp::SpecialForms::chain_impl(args, env)
100
+ Lisp::PrimSpecialForms::chain_impl(args, env)
107
101
  end
108
102
 
109
- Primitive.register("quote", "(quote _expr_)\n\nSurpresses evaluation of the expression.\n\n (quote (+ 1 2)) ⇒ (+ 1 2)\n\nThere is a shortcut for quote that uses the single quote:\n\n '(+ 1 2) ⇒ (+ 1 2)") do |args, env|
110
- Lisp::SpecialForms::quote_impl(args, env)
111
- end
103
+ Primitive.register("quote", "1",
104
+ "(quote _expr_)\n\nSurpresses evaluation of the expression.\n\n (quote (+ 1 2)) ⇒ (+ 1 2)\n\nThere is a shortcut for quote that uses the single quote:\n\n '(+ 1 2) ⇒ (+ 1 2)",
105
+ true) do |args, env|
106
+ Lisp::PrimSpecialForms::quote_impl(args, env)
107
+ end
112
108
 
113
- Primitive.register("quasiquote", "(quasiquote _sexpr_)\n\nThis defines a template expression that can be filled in by unquote and unquote-splicing. The backquote character can be used as a shorthand for quasiquote: `sexpr.") do |args, env|
114
- Lisp::SpecialForms::quasiquote_impl(args, env)
115
- end
109
+ Primitive.register("quasiquote", "1",
110
+ "(quasiquote _sexpr_)\n\nThis defines a template expression that can be filled in by unquote and unquote-splicing. The backquote character can be used as a shorthand for quasiquote: `sexpr.",
111
+ true) do |args, env|
112
+ Lisp::PrimSpecialForms::quasiquote_impl(args, env)
113
+ end
116
114
 
117
- Primitive.register("gensym", "(gensym)\n(gensym _prefix_)\n\nThis creates a unique symbol. If you provide the optional prefix string it is
118
- used as the initial part of the symbol, otherwise GENSYM is used. gensym is
119
- useful in macros when you need a unique name for something.") do |args, env|
120
- Lisp::SpecialForms::gensym_impl(args, env)
121
- end
115
+ Primitive.register("gensym", "0|1",
116
+ "(gensym)\n(gensym _prefix_)\n\nThis creates a unique symbol. If you provide the optional prefix string it is used as the initial part of the symbol, otherwise GENSYM is used. gensym is useful in macros when you need a unique name for something.",
117
+ true) do |args, env|
118
+ Lisp::PrimSpecialForms::gensym_impl(args, env)
119
+ end
122
120
 
123
- Primitive.register("expand", "(expand _symbol_ _sexpr_...)\n\nExpands the macro named by symbol, passing the evaluated sequence of sexpr as arguments.\n\nNOTE: whereas invoking the macro (in the same way you invoke a function) expands and evaluates, expand (as you would expect) only expands the macro, resulting in the expanded template sexpr. This can then be evaluated as desired.") do |args, env|
124
- Lisp::SpecialForms::expand_impl(args, env)
125
- end
121
+ Primitive.register("expand", ">=1",
122
+ "(expand _symbol_ _sexpr_...)\n\nExpands the macro named by symbol, passing the evaluated sequence of sexpr as arguments.\n\nNOTE: whereas invoking the macro (in the same way you invoke a function) expands and evaluates, expand (as you would expect) only expands the macro, resulting in the expanded template sexpr. This can then be evaluated as desired.",
123
+ true) do |args, env|
124
+ Lisp::PrimSpecialForms::expand_impl(args, env)
125
+ end
126
+
127
+ Primitive.register("doc-string", "1",
128
+ "(doc-string _symbol_)\n\Prints the documentation associated with the form, function, or macro named by symbol.",
129
+ true) do |args, env|
130
+ Lisp::PrimSpecialForms::doc_string_impl(args, env)
131
+ end
132
+
133
+ Primitive.register("definition", "1",
134
+ "(definition _symbol_)\n\Prints the code associated with the function or macro named by symbol.",
135
+ true) do |args, env|
136
+ Lisp::PrimSpecialForms::definition_impl(args, env)
137
+ end
126
138
 
127
139
  @@SYMBOL_COUNT = 0
128
140
  end
@@ -164,12 +176,11 @@ useful in macros when you need a unique name for something.") do |args, env|
164
176
  return Lisp::Debug.process_error("Case requires non-atomic clauses", env)
165
177
  end
166
178
  end
167
- return nil
179
+ nil
168
180
  end
169
181
 
170
182
 
171
183
  def self.if_impl(args, env)
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
184
  condition = args.car.evaluate(env)
174
185
  if condition.true?
175
186
  args.cadr.evaluate(env)
@@ -182,7 +193,6 @@ useful in macros when you need a unique name for something.") do |args, env|
182
193
 
183
194
 
184
195
  def self.when_impl(args, env)
185
- return Lisp::Debug.process_error("WHEN requires a condition and sexprs to evaluate.", env) unless args.length >= 2
186
196
  condition = args.car.evaluate(env)
187
197
  return args.cdr.evaluate_each(env) if condition.true?
188
198
  nil
@@ -190,7 +200,6 @@ useful in macros when you need a unique name for something.") do |args, env|
190
200
 
191
201
 
192
202
  def self.unless_impl(args, env)
193
- return Lisp::Debug.process_error("UNLESS requires a condition and sexprs to evaluate.", env) unless args.length >= 2
194
203
  condition = args.car.evaluate(env)
195
204
  return args.cdr.evaluate_each(env) unless condition.true?
196
205
  nil
@@ -200,7 +209,7 @@ useful in macros when you need a unique name for something.") do |args, env|
200
209
  def self.lambda_impl(args, env)
201
210
  arguments = args.car
202
211
  body = args.cdr
203
- Lisp::Function.new("lambda", arguments, "", body, env)
212
+ Lisp::Function.new("anonymous_function", arguments.empty? ? nil : arguments, "", body, env)
204
213
  end
205
214
 
206
215
 
@@ -208,7 +217,7 @@ useful in macros when you need a unique name for something.") do |args, env|
208
217
  return Lisp::Debug.process_error("Variable names must be literal symbols.", env) unless definition.symbol?
209
218
 
210
219
  ev = value.evaluate(env)
211
- Lisp::EnvironmentFrame.global.bind(definition, ev)
220
+ env.bind_locally(definition, ev)
212
221
  ev
213
222
  end
214
223
 
@@ -228,13 +237,6 @@ useful in macros when you need a unique name for something.") do |args, env|
228
237
  end
229
238
 
230
239
 
231
- def self.defun_impl(args, env)
232
- definition = args.car
233
- return Lisp::Debug.process_error("Function definition must specify name and parameters in a list", env) unless definition.list?
234
- define_function(definition, args.cdr, env)
235
- end
236
-
237
-
238
240
  def self.define_impl(args, env)
239
241
  definition = args.car
240
242
  if definition.list?
@@ -247,12 +249,11 @@ useful in macros when you need a unique name for something.") do |args, env|
247
249
 
248
250
 
249
251
  def self.defmacro_impl(args, env)
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
252
  definition = args.car
252
253
  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
254
  name = definition.car
254
255
  arguments = definition.cdr
255
- doc = nil
256
+ doc = ""
256
257
  if args.cadr.string?
257
258
  doc = args.cadr
258
259
  body = args.caddr
@@ -275,13 +276,27 @@ useful in macros when you need a unique name for something.") do |args, env|
275
276
  "GENSYM"
276
277
  else
277
278
  return Lisp::Debug.process_error("gensym's argument must be a string", env) unless args.car.string?
278
- args.car.to_s
279
+ args.car.evaluate(env).to_s
279
280
  end
280
281
  sym = Lisp::Symbol.named("#{prefix}-#{@@SYMBOL_COUNT}")
281
282
  @@SYMBOL_COUNT += 1
282
283
  sym
283
284
  end
284
285
 
286
+
287
+ def self.doc_string_impl(args, env)
288
+ thing = args.car.evaluate(env)
289
+ return Lisp::Debug.process_error("doc-string expects a form, macro, or function as its argument", env) unless thing.macro? || thing.function? || thing.primitive?
290
+ puts thing.doc
291
+ end
292
+
293
+
294
+ def self.definition_impl(args, env)
295
+ thing = args.car.evaluate(env)
296
+ return Lisp::Debug.process_error("definition expects a macro or function as its argument", env) unless thing.macro? || thing.function?
297
+ puts thing.body.print_string
298
+ end
299
+
285
300
 
286
301
  def self.expand_impl(args, env)
287
302
  macro = args.car.evaluate(env)
@@ -291,7 +306,9 @@ useful in macros when you need a unique name for something.") do |args, env|
291
306
 
292
307
 
293
308
  def self.process_quasiquoted(sexpr, level, env)
294
- if !sexpr.list?
309
+ if sexpr.nil?
310
+ ConsCell.new
311
+ elsif !sexpr.list?
295
312
  ConsCell.cons(sexpr)
296
313
  elsif sexpr.car.symbol? && sexpr.car.name == "quasiquote"
297
314
  ConsCell.cons(ConsCell.cons(Symbol.named("quasiquote"), process_quasiquoted(sexpr.cadr, level + 1, env)))
@@ -308,7 +325,8 @@ useful in macros when you need a unique name for something.") do |args, env|
308
325
  ConsCell.cons(ConsCell.cons(Symbol.named("unquote-splicing"), process_quasiquoted(sexpr.cadr, level - 1, env)))
309
326
  end
310
327
  else
311
- l = ConsCell.array_to_list(sexpr.to_a.map {|e| process_quasiquoted(e, level, env)}).flatten
328
+ processed_sexpr = sexpr.to_a.map {|e| process_quasiquoted(e, level, env)}
329
+ l = ConsCell.array_to_list(processed_sexpr).flatten
312
330
  ConsCell.cons(l)
313
331
  end
314
332
  end
@@ -333,7 +351,7 @@ useful in macros when you need a unique name for something.") do |args, env|
333
351
  def self.let_impl(args, env)
334
352
  bindings = args.car || Lisp::ConsCell.new
335
353
  return Lisp::Debug.process_error("let requires a list of bindings as it's firest argument", env) unless bindings.list?
336
- local_frame = EnvironmentFrame.extending(env)
354
+ local_frame = EnvironmentFrame.extending(env, "let")
337
355
  local_frame.previous = env
338
356
  do_let_bindings(bindings, env, local_frame)
339
357
  args.cdr.evaluate_each(local_frame)
@@ -343,7 +361,7 @@ useful in macros when you need a unique name for something.") do |args, env|
343
361
  def self.letstar_impl(args, env)
344
362
  bindings = args.car || Lisp::ConsCell.new
345
363
  return Lisp::Debug.process_error("let requires a list of bindings as it's firest argument", env) unless bindings.list?
346
- local_frame = EnvironmentFrame.extending(env)
364
+ local_frame = EnvironmentFrame.extending(env, "let*")
347
365
  do_let_bindings(bindings, local_frame, local_frame)
348
366
  args.cdr.evaluate_each(local_frame)
349
367
  end
@@ -355,14 +373,13 @@ useful in macros when you need a unique name for something.") do |args, env|
355
373
 
356
374
 
357
375
  def self.do_impl(args, env)
358
- return Lisp::Debug.process_error("Do requires at least a list of bindings and a test clause", env) if args.length < 2
359
376
  bindings = args.car
360
377
  return Lisp::Debug.process_error("Do requires a list of bindings as it's first argument", env) unless bindings.list?
361
378
  test_clause = args.cadr
362
379
  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?
363
380
  body = args.cddr
364
381
 
365
- local_frame = EnvironmentFrame.extending(env)
382
+ local_frame = EnvironmentFrame.extending(env, "do")
366
383
  local_frame.previous = env
367
384
 
368
385
  bindings.each do |binding|
@@ -393,7 +410,6 @@ useful in macros when you need a unique name for something.") do |args, env|
393
410
 
394
411
 
395
412
  def self.eval_impl(args, env)
396
- return Lisp::Debug.process_error("eval expects a single argument, received #{args.length}.", env) if args.length != 1
397
413
  arg = args.car.evaluate(env)
398
414
  return Lisp::Debug.process_error("eval expect a list argument, received a #{arg.type}.", env) unless arg.list?
399
415
  arg.evaluate(env)
@@ -402,20 +418,18 @@ useful in macros when you need a unique name for something.") do |args, env|
402
418
 
403
419
  def self.apply_impl(args, env)
404
420
  func = args.car.evaluate(env)
405
- return Lisp::Debug.process_error("Expected #{args.car} to evaluate to a function.", env) unless func.primitive? || func.function?
421
+ return Lisp::Debug.process_error("apply required the first qrgument to be a function but it was #{args.car.to_s}.", env) unless func.primitive? || func.function?
406
422
 
407
423
  a = args.cdr.to_a.collect {|sexpr| sexpr.evaluate(env)}
408
- arg_list = if a[-1].list?
409
- Lisp::ConsCell.array_to_list(a[0..-2], a[-1])
410
- else
411
- args.cdr
412
- end
424
+
425
+ return Lisp::Debug.process_error("Apply required the last argument to bea list but it was #{a[-1].to_s}.", env) unless a[-1].list?
426
+
427
+ arg_list = Lisp::ConsCell.array_to_list(a[0..-2], a[-1])
413
428
  func.apply_to(arg_list, env)
414
429
  end
415
430
 
416
431
 
417
432
  def self.chain_impl(args, env)
418
- return Lisp::Debug.process_error("-> requires at the very least an initial value.", env) unless args.length > 0
419
433
  value = args.car.evaluate(env)
420
434
  cell = args.cdr
421
435
  while !cell.nil?
@@ -434,7 +448,6 @@ useful in macros when you need a unique name for something.") do |args, env|
434
448
 
435
449
 
436
450
  def self.tap_impl(args, env)
437
- return Lisp::Debug.process_error("tap requires at the very least an initial value.", env) unless args.length > 0
438
451
  value = args.car.evaluate(env)
439
452
  cell = args.cdr
440
453
  while !cell.nil?