rubylisp 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +82 -0
- data/bin/rubylisp +6 -0
- data/lib/rubylisp/alist.rb +17 -17
- data/lib/rubylisp/assignment.rb +7 -7
- data/lib/rubylisp/builtins.rb +1 -0
- data/lib/rubylisp/character.rb +21 -20
- data/lib/rubylisp/cons_cell.rb +46 -3
- data/lib/rubylisp/debug.rb +238 -0
- data/lib/rubylisp/environment_frame.rb +47 -4
- data/lib/rubylisp/exception.rb +8 -8
- data/lib/rubylisp/ext.rb +4 -0
- data/lib/rubylisp/ffi_class.rb +10 -10
- data/lib/rubylisp/ffi_send.rb +3 -3
- data/lib/rubylisp/frame.rb +51 -31
- data/lib/rubylisp/function.rb +4 -3
- data/lib/rubylisp/io.rb +6 -6
- data/lib/rubylisp/list_support.rb +93 -94
- data/lib/rubylisp/logical.rb +3 -3
- data/lib/rubylisp/macro.rb +4 -2
- data/lib/rubylisp/math.rb +58 -56
- data/lib/rubylisp/object.rb +1 -1
- data/lib/rubylisp/parser.rb +5 -5
- data/lib/rubylisp/primitive.rb +1 -1
- data/lib/rubylisp/relational.rb +4 -4
- data/lib/rubylisp/special_forms.rb +29 -27
- data/lib/rubylisp/string.rb +75 -75
- data/lib/rubylisp/system.rb +3 -2
- data/lib/rubylisp/testing.rb +3 -3
- data/lib/rubylisp/type_checks.rb +10 -8
- data/lib/rubylisp/vector.rb +1 -1
- data/lib/rubylisp.rb +1 -0
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ed25cdabf9d69adf654828879d800947d2d69624
|
4
|
+
data.tar.gz: cc25906946d3020ead7a82284a65f47796cc16f5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7984fd29e98ac9c002d515954630d894802c9c2a1e161a3e6cc880033f959b761845a23d9f198b98303bfb10a40c91660c51045d89db09fbb1f9eefe400752a5
|
7
|
+
data.tar.gz: 4f675b07e8f92ac250eeef84eeaf1a7cb8cecd56ca810d9d38b2bd4fa7797a3fd8e417376a7d682b5908569d64bc64532f52bd21e8c3e04782a91f3bb024ed6e
|
data/README.md
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
## Overview
|
2
|
+
|
3
|
+
RubyLisp is a relatively simple Lisp dialect based on Scheme
|
4
|
+
implimented using Ruby.
|
5
|
+
|
6
|
+
RubyLisp is a lexically scoped Lisp-1:
|
7
|
+
|
8
|
+
**Lexically scoped:**
|
9
|
+
The scope of definitions are determined by where they are made in the
|
10
|
+
lexical structure of the code. Each `lambda`, `let`, and `do` creates
|
11
|
+
a new lexical scope. From [2]:
|
12
|
+
|
13
|
+
> Here references to the established entity can occur only within
|
14
|
+
> certain program portions that are lexically (that is, textually)
|
15
|
+
> contained within the establishing construct. Typically the construct
|
16
|
+
> will have a part designated the body, and the scope of all entities
|
17
|
+
> established will be (or include) the body.
|
18
|
+
|
19
|
+
**Lisp-1:**
|
20
|
+
A Lisp where functions and variables share a single namespace. This
|
21
|
+
differs from a Lisp-2 in which functions and variables have separate
|
22
|
+
namespaces.
|
23
|
+
|
24
|
+
## Installation
|
25
|
+
|
26
|
+
Add this line to your application's Gemfile:
|
27
|
+
|
28
|
+
gem 'rubylisp'
|
29
|
+
|
30
|
+
And then execute:
|
31
|
+
|
32
|
+
$ bundle
|
33
|
+
|
34
|
+
Or install it yourself as:
|
35
|
+
|
36
|
+
$ gem install rubylisp
|
37
|
+
|
38
|
+
## Contributing
|
39
|
+
|
40
|
+
1. Fork it
|
41
|
+
2. Create your feature branch (git checkout -b my-new-feature)
|
42
|
+
3. Commit your changes (git commit -am 'Add some feature')
|
43
|
+
4. Push to the branch (git push origin my-new-feature)
|
44
|
+
5. Create new Pull Request
|
45
|
+
|
46
|
+
## REPL
|
47
|
+
|
48
|
+
RubyLisp includes a very basic REPL that, as expected, lets you type
|
49
|
+
in snippets (it does not support multiline snippets) of Lisp code,
|
50
|
+
evaluates them, and prints the result.
|
51
|
+
|
52
|
+
>: rubylisp
|
53
|
+
|
54
|
+
RubyLisp REPL
|
55
|
+
> 4
|
56
|
+
4
|
57
|
+
> (+ 2 3)
|
58
|
+
5
|
59
|
+
> (define (fib x) (if (eq? x 0) 1 (* x (fib (- x 1)))))
|
60
|
+
<function: fib>
|
61
|
+
> (fib 4)
|
62
|
+
24
|
63
|
+
|
64
|
+
## Integrating
|
65
|
+
|
66
|
+
|
67
|
+
The simplist way to integrate RubyLisp is to have it parse and
|
68
|
+
evaluate strings of lisp code.
|
69
|
+
|
70
|
+
>: irb
|
71
|
+
2.0.0-p247 :001 > require 'rubylisp'
|
72
|
+
=> true
|
73
|
+
2.0.0-p247 :002 > Lisp::Initializer.register_builtins
|
74
|
+
=> ...
|
75
|
+
2.0.0-p247 :003 > Lisp::Parser.new.parse_and_eval('(+ 1 2)').to_s
|
76
|
+
=> "3"
|
77
|
+
2.0.0-p247 :004 >
|
78
|
+
|
79
|
+
But lets say you are using rubylisp to do something more embedded such as provide an extension language to your application. It's easy to provide the Lisp runtime with functions written in Ruby that can be called from Lisp code.
|
80
|
+
|
81
|
+
to be continued...
|
82
|
+
|
data/bin/rubylisp
CHANGED
@@ -4,15 +4,21 @@ require 'rubylisp'
|
|
4
4
|
require 'readline'
|
5
5
|
|
6
6
|
Lisp::Initializer.register_builtins
|
7
|
+
Lisp::Debug.interactive = true
|
7
8
|
|
8
9
|
puts 'RubyLisp REPL'
|
10
|
+
puts 'Copyright 2014 David R. Astels'
|
11
|
+
puts
|
9
12
|
parser = Lisp::Parser.new
|
10
13
|
|
11
14
|
while line = Readline.readline('> ', true)
|
12
15
|
begin
|
13
16
|
puts parser.parse_and_eval(line)
|
14
17
|
rescue Exception => ex
|
18
|
+
exit if ex.to_s == "exit"
|
15
19
|
puts "ERROR: #{ex}"
|
20
|
+
puts ex.backtrace
|
16
21
|
end
|
17
22
|
end
|
18
23
|
|
24
|
+
|
data/lib/rubylisp/alist.rb
CHANGED
@@ -14,12 +14,12 @@ module Lisp
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def self.acons_impl(args, env)
|
17
|
-
|
17
|
+
return Lisp::Debug.process_error("acons require at least 2 or 3 arguments", env) unless args.length == 2 || args.length == 3
|
18
18
|
key = args.car.evaluate(env)
|
19
19
|
value = args.cadr.evaluate(env)
|
20
20
|
alist = args.length == 2 ? nil : args.caddr.evaluate(env)
|
21
21
|
alist = Lisp::AList.from_list(alist) if !alist.nil? && alist.list? && !alist.alist?
|
22
|
-
|
22
|
+
return Lisp::Debug.process_error("the last argument to acons has to be an association list", env) unless alist.nil? || alist.alist?
|
23
23
|
|
24
24
|
if alist.nil?
|
25
25
|
Lisp::AList.new({key => value})
|
@@ -29,44 +29,44 @@ module Lisp
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def self.assoc_impl(args, env)
|
32
|
-
|
32
|
+
return Lisp::Debug.process_error("assoc require 2 arguments", env) unless args.length == 2
|
33
33
|
key = args.car.evaluate(env)
|
34
34
|
alist = args.cadr.evaluate(env)
|
35
35
|
alist = Lisp::AList.from_list(alist) if alist.list? && !alist.alist?
|
36
|
-
|
36
|
+
return Lisp::Debug.process_error("the last argument to assoc has to be an association list", env) unless alist.alist?
|
37
37
|
alist.assoc(key)
|
38
38
|
end
|
39
39
|
|
40
40
|
def self.rassoc_impl(args, env)
|
41
|
-
|
41
|
+
return Lisp::Debug.process_error("assoc require 2 arguments", env) unless args.length == 2
|
42
42
|
value = args.car.evaluate(env)
|
43
43
|
alist = args.cadr.evaluate(env)
|
44
44
|
alist = Lisp::AList.from_list(alist) if alist.list? && !alist.alist?
|
45
|
-
|
45
|
+
return Lisp::Debug.process_error("the last argument to rassoc has to be an association list", env) unless alist.alist?
|
46
46
|
alist.rassoc(value)
|
47
47
|
end
|
48
48
|
|
49
49
|
def self.dissoc_impl(args, env)
|
50
|
-
|
50
|
+
return Lisp::Debug.process_error("assoc require 2 arguments", env) unless args.length == 2
|
51
51
|
key = args.car.evaluate(env)
|
52
52
|
alist = args.cadr.evaluate(env)
|
53
53
|
alist = Lisp::AList.from_list(alist) if alist.list? && !alist.alist?
|
54
|
-
|
54
|
+
return Lisp::Debug.process_error("the last argument to dissoc has to be an association list", env) unless alist.alist?
|
55
55
|
alist.dissoc(key)
|
56
56
|
end
|
57
57
|
|
58
58
|
def self.zip_impl(args, env)
|
59
|
-
|
59
|
+
return Lisp::Debug.process_error("assoc require 2 or 3arguments", env) unless args.length == 2 || args.length == 3
|
60
60
|
key_list = args.car.evaluate(env)
|
61
|
-
|
61
|
+
return Lisp::Debug.process_error("the keys supplied to zip has to be a list", env) unless key_list.list?
|
62
62
|
value_list = args.cadr.evaluate(env)
|
63
|
-
|
64
|
-
|
63
|
+
return Lisp::Debug.process_error("the values supplied to zip has to be a list", env) unless value_list.list?
|
64
|
+
return Lisp::Debug.process_error("zip requires the same number of keys and values", env) unless key_list.length == value_list.length
|
65
65
|
|
66
66
|
if args.length == 3
|
67
67
|
alist = args.caddr.evaluate(env)
|
68
68
|
alist = Lisp::AList.from_list(alist) if alist.list? && !alist.alist?
|
69
|
-
|
69
|
+
return Lisp::Debug.process_error("the third argument to zip has to be an association list", env) unless alist.alist?
|
70
70
|
alist.zip(key_list.to_a, value_list.to_a)
|
71
71
|
else
|
72
72
|
Lisp::AList.zip(key_list.to_a, value_list.to_a)
|
@@ -74,18 +74,18 @@ module Lisp
|
|
74
74
|
end
|
75
75
|
|
76
76
|
def self.alist_to_list_impl(args, env)
|
77
|
-
|
77
|
+
return Lisp::Debug.process_error("alist-to-list requires 1 arguments", env) unless args.length == 1
|
78
78
|
alist = args.car.evaluate(env)
|
79
79
|
return alist if alist.list? && !alist.alist?
|
80
|
-
|
80
|
+
return Lisp::Debug.process_error("the argument to alist-to-list has to be an association list", env) unless alist.alist?
|
81
81
|
|
82
82
|
alist.to_list
|
83
83
|
end
|
84
84
|
|
85
85
|
def self.list_to_alist_impl(args, env)
|
86
|
-
|
86
|
+
return Lisp::Debug.process_error("list-to-alist requires 1 arguments", env) unless args.length == 1
|
87
87
|
list = args.car.evaluate(env)
|
88
|
-
|
88
|
+
return Lisp::Debug.process_error("the argument to list-to-alist has to be a list", env) unless list.list?
|
89
89
|
|
90
90
|
Lisp::AList.from_list(list)
|
91
91
|
end
|
data/lib/rubylisp/assignment.rb
CHANGED
@@ -25,7 +25,7 @@ The `new-value` sexpr is evaluated to arrive at the new value to be bound to. Us
|
|
25
25
|
|
26
26
|
def self.setbang_impl(args, env)
|
27
27
|
sym = args.car
|
28
|
-
|
28
|
+
return Lisp::Debug.process_error("set! requires a raw (unevaluated) symbol as it's first argument.", env) unless sym.symbol?
|
29
29
|
value = args.cadr.evaluate(env)
|
30
30
|
env.set(sym, value)
|
31
31
|
end
|
@@ -33,7 +33,7 @@ The `new-value` sexpr is evaluated to arrive at the new value to be bound to. Us
|
|
33
33
|
|
34
34
|
def self.setcarbang_impl(args, env)
|
35
35
|
pair = args.car.evaluate(env)
|
36
|
-
|
36
|
+
return Lisp::Debug.process_error("set-car! requires a pair as it's first argument.", env) unless pair.pair?
|
37
37
|
value = args.cadr.evaluate(env)
|
38
38
|
pair.set_car!(value)
|
39
39
|
end
|
@@ -41,20 +41,20 @@ The `new-value` sexpr is evaluated to arrive at the new value to be bound to. Us
|
|
41
41
|
|
42
42
|
def self.setcdrbang_impl(args, env)
|
43
43
|
pair = args.car.evaluate(env)
|
44
|
-
|
44
|
+
return Lisp::Debug.process_error("set-cdr! requires a pair as it's first argument.", env) unless pair.pair?
|
45
45
|
value = args.cadr.evaluate(env)
|
46
46
|
pair.set_cdr!(value)
|
47
47
|
end
|
48
48
|
|
49
49
|
|
50
50
|
def self.setnthbang_impl(args, env)
|
51
|
-
|
51
|
+
return Lisp::Debug.process_error("set-nth! requires 3 arguments.", env) unless args.length == 3
|
52
52
|
n = args.car.evaluate(env)
|
53
|
-
|
54
|
-
|
53
|
+
return Lisp::Debug.process_error("The first argument of set-nth! has to be an number.", env) unless n.number?
|
54
|
+
return Lisp::Debug.process_error("The first argument of set-nth! has to be positive.", env) unless n.value > 0
|
55
55
|
|
56
56
|
l = args.cadr.evaluate(env)
|
57
|
-
|
57
|
+
return Lisp::Debug.process_error("set-nth! requires a list or vector as it's first argument.", env) unless l.list? || l.vector?
|
58
58
|
value = args.caddr.evaluate(env)
|
59
59
|
l.set_nth!(n.value, value)
|
60
60
|
l
|
data/lib/rubylisp/builtins.rb
CHANGED
data/lib/rubylisp/character.rb
CHANGED
@@ -99,39 +99,40 @@ module Lisp
|
|
99
99
|
|
100
100
|
|
101
101
|
def self.char_name_impl(args, env)
|
102
|
-
|
102
|
+
return Lisp::Debug.process_error("char->name requires a single argument, found #{args.length}", env) unless args.length == 1
|
103
103
|
char = args.car.evaluate(env)
|
104
|
-
|
104
|
+
return Lisp::Debug.process_error("char->name requires a character argument", env) unless char.character?
|
105
105
|
kv = @@character_constants.rassoc(char)
|
106
106
|
return Lisp::String.with_value(kv[0]) unless kv.nil?
|
107
|
-
|
107
|
+
return Lisp::Debug.process_error("char->name was passed an invalid character", env)
|
108
108
|
end
|
109
109
|
|
110
110
|
|
111
111
|
def self.name_char_impl(args, env)
|
112
|
-
|
112
|
+
return Lisp::Debug.process_error("name->char requires a single argument, found #{args.length}", env) unless args.length == 1
|
113
113
|
name = args.car.evaluate(env)
|
114
|
-
|
114
|
+
return Lisp::Debug.process_error("name->char requires a string argument", env) unless name.string?
|
115
115
|
ch = find_character_for_name(name.value)
|
116
116
|
return ch unless ch.nil?
|
117
|
-
|
117
|
+
return Lisp::Debug.process_error("There is no character with the name #{name}", env)
|
118
118
|
end
|
119
119
|
|
120
120
|
|
121
121
|
def self.get_one_character_arg(func, args, env)
|
122
|
-
|
122
|
+
return Lisp::Debug.process_error("#{func} requires a character argument, found no args", env) unless args.length >= 1
|
123
123
|
char1 = args.car.evaluate(env)
|
124
|
-
|
124
|
+
return Lisp::Debug.process_error("#{func} requires a character argument, found #{char1}", env) unless char1.character?
|
125
125
|
return char1
|
126
126
|
end
|
127
127
|
|
128
128
|
|
129
129
|
def self.get_two_character_args(func, args, env)
|
130
|
-
|
130
|
+
return Lisp::Debug.process_error("#{func} requires two arguments, found
|
131
|
+
##{args.length}", env) unless args.length == 2
|
131
132
|
char1 = args.car.evaluate(env)
|
132
|
-
|
133
|
+
return Lisp::Debug.process_error("#{func} requires character arguments, found #{char1}", env) unless char1.character?
|
133
134
|
char2 = args.cadr.evaluate(env)
|
134
|
-
|
135
|
+
return Lisp::Debug.process_error("#{func} requires character arguments, found #{char2}", env) unless char2.character?
|
135
136
|
return [char1, char2]
|
136
137
|
end
|
137
138
|
|
@@ -197,7 +198,7 @@ module Lisp
|
|
197
198
|
|
198
199
|
|
199
200
|
def self.charp_impl(args, env)
|
200
|
-
|
201
|
+
return Lisp::Debug.process_error("char->name requires a single argument, found #{args.length}", env) unless args.length == 1
|
201
202
|
char = args.car.evaluate(env)
|
202
203
|
Lisp::Boolean.with_value(char.character?)
|
203
204
|
end
|
@@ -221,8 +222,8 @@ module Lisp
|
|
221
222
|
10
|
222
223
|
else
|
223
224
|
b = args.cadr.evaluate(env)
|
224
|
-
|
225
|
-
|
225
|
+
return Lisp::Debug.process_error("Base for char->digit has to be an integer", env) unless b.integer?
|
226
|
+
return Lisp::Debug.process_error("Base for char->digit has to be between 2 and 36", env) unless b.value >=2 && b.value <= 36
|
226
227
|
b.value
|
227
228
|
end
|
228
229
|
ch = char.value.upcase
|
@@ -246,13 +247,13 @@ module Lisp
|
|
246
247
|
|
247
248
|
def self.digit_char_impl(args, env)
|
248
249
|
d = args.car.evaluate(env)
|
249
|
-
|
250
|
+
return Lisp::Debug.process_error("Digit value for digit->char has to be an integer", env) unless d.integer?
|
250
251
|
base = if args.length == 1
|
251
252
|
10
|
252
253
|
else
|
253
254
|
b = args.cadr.evaluate(env)
|
254
|
-
|
255
|
-
|
255
|
+
return Lisp::Debug.process_error("Base for char->digit has to be an integer", env) unless b.integer?
|
256
|
+
return Lisp::Debug.process_error("Base for char->digit has to be between 2 and 36", env) unless b.value >=2 && b.value <= 36
|
256
257
|
b.value
|
257
258
|
end
|
258
259
|
val = d.value
|
@@ -269,7 +270,7 @@ module Lisp
|
|
269
270
|
|
270
271
|
def self.int_char_impl(args, env)
|
271
272
|
i = args.car.evaluate(env)
|
272
|
-
|
273
|
+
return Lisp::Debug.process_error("Integer value for int->char has to be an integer", env) unless i.integer?
|
273
274
|
find_character_for_chr(i.value.chr)
|
274
275
|
end
|
275
276
|
|
@@ -374,10 +375,10 @@ module Lisp
|
|
374
375
|
elsif n[0..1] == "U+"
|
375
376
|
find_character_for_chr(n[2..-1].to_i(16).chr)
|
376
377
|
else
|
377
|
-
|
378
|
+
return Lisp::Debug.process_error("Invalid character name: #{n}", env)
|
378
379
|
end
|
379
380
|
end
|
380
381
|
|
381
|
-
end
|
382
|
+
end
|
382
383
|
|
383
384
|
end
|
data/lib/rubylisp/cons_cell.rb
CHANGED
@@ -123,6 +123,8 @@ module Lisp
|
|
123
123
|
def to_s
|
124
124
|
return "()" if self.empty?
|
125
125
|
return "'#{@cdr.car.to_s}" if @car.symbol? && @car.name == "quote"
|
126
|
+
return "{#{@cdr.to_s_helper}}" if @car.symbol? && @car.name == "make-frame"
|
127
|
+
return "[#{@cdr.to_s_helper}]" if @car.symbol? && @car.name == "make-vector"
|
126
128
|
return "(#{@car.to_s} . #{@cdr.to_s})" if !@cdr.nil? && !@cdr.pair?
|
127
129
|
return "(#{self.to_s_helper})"
|
128
130
|
end
|
@@ -134,6 +136,8 @@ module Lisp
|
|
134
136
|
def print_string
|
135
137
|
return "()" if self.empty?
|
136
138
|
return "'#{@cdr.car.print_string}" if @car.symbol? && @car.name == "quote"
|
139
|
+
return "{#{@cdr.print_string_helper}}" if @car.symbol? && @car.name == "make-frame"
|
140
|
+
return "[#{@cdr.print_string_helper}]" if @car.symbol? && @car.name == "make-vector"
|
137
141
|
return "(#{@car.print_string} . #{@cdr.print_string})" if !@cdr.nil? && !@cdr.pair?
|
138
142
|
return "(#{self.print_string_helper})"
|
139
143
|
end
|
@@ -203,13 +207,52 @@ module Lisp
|
|
203
207
|
return nil unless obj.object?
|
204
208
|
return obj.value
|
205
209
|
end
|
210
|
+
|
211
|
+
|
212
|
+
|
213
|
+
def inner_eval(env)
|
214
|
+
func = @car.evaluate(env)
|
215
|
+
return Lisp::Debug.process_error("There is no function or macro named #{@car}", env) if func.nil?
|
216
|
+
env.current_code.unshift(self.print_string()) if !Lisp::Debug.eval_in_debug_repl && Lisp::Debug.interactive
|
217
|
+
|
218
|
+
Lisp::Debug.log_eval(self, env)
|
206
219
|
|
220
|
+
unless Lisp::Debug.eval_in_debug_repl
|
221
|
+
if !Lisp::Debug.target_env.nil? && env == Lisp::Debug.target_env.previous
|
222
|
+
Lisp::Debug.target_env = nil
|
223
|
+
Lisp::Debug.debug_repl(env)
|
224
|
+
elsif Lisp::Debug.single_step || (func.function? && Lisp::Debug.on_entry.include?(func.name))
|
225
|
+
Lisp::Debug.debug_repl(env)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
result = func.apply_to(@cdr, env)
|
229
|
+
env.current_code.shift() if !Lisp::Debug.eval_in_debug_repl && Lisp::Debug.interactive
|
230
|
+
Lisp::Debug.log_result(result, env)
|
231
|
+
result
|
232
|
+
end
|
233
|
+
|
207
234
|
|
208
235
|
def evaluate(env)
|
209
236
|
return self if empty?
|
210
|
-
|
211
|
-
|
212
|
-
|
237
|
+
sexpr = if @car.symbol?
|
238
|
+
key = @car
|
239
|
+
frame = nth(2)
|
240
|
+
value = nth(3)
|
241
|
+
|
242
|
+
s = key.name
|
243
|
+
if s.end_with?(":")
|
244
|
+
ConsCell.array_to_list([Symbol.named("get-slot"), frame, key])
|
245
|
+
elsif s.end_with?(":!")
|
246
|
+
ConsCell.array_to_list([Symbol.named("set-slot!"), frame, Symbol.named(s[0..-2]), value])
|
247
|
+
elsif s.end_with?(":?")
|
248
|
+
ConsCell.array_to_list([Symbol.named("has-slot?"), frame, Symbol.named(s[0..-2])])
|
249
|
+
else
|
250
|
+
self
|
251
|
+
end
|
252
|
+
else
|
253
|
+
self
|
254
|
+
end
|
255
|
+
sexpr.inner_eval(env)
|
213
256
|
end
|
214
257
|
|
215
258
|
def evaluate_each(env)
|