rbl 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +9 -7
- data/bin/rbl +5 -5
- data/lib/rubylisp/environment.rb +19 -5
- data/lib/rubylisp/evaluator.rb +218 -187
- data/lib/rubylisp/function.rb +154 -0
- data/lib/rubylisp/parser.rb +4 -4
- data/lib/rubylisp/printer.rb +7 -4
- data/lib/rubylisp/rbl_readline.rb +29 -0
- data/lib/rubylisp/reader.rb +26 -28
- data/lib/rubylisp/repl.rb +4 -4
- data/lib/rubylisp/types.rb +51 -82
- data/lib/rubylisp/util.rb +64 -0
- data/lib/rubylisp/version.rb +1 -1
- data/rubylisp/core.rbl +378 -229
- data/rubylisp.gemspec +1 -0
- metadata +19 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7e9f93f61446acfe3a434444b82dd743f9a1b4fc
|
4
|
+
data.tar.gz: f3d8e18c04933b302bfc2a54950f09b474815bf8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c8601be4ccdfc976d27a12a75b1215b2ea906b46418e6dfd4a85f281f37a5c7b367f076920e215d9b584900d75651b34fa7b6ee96668c84d8f60c68053faa876
|
7
|
+
data.tar.gz: 37c7beccfaae69fd0711941a2d0b274475df20ae8f1f3b36ae90f9910c62ca3cd0f60ca17930e17590a77dbe04afc3c3c93a521d9d12a4284ad765bf4594a7c7
|
data/README.md
CHANGED
@@ -29,8 +29,9 @@ I think I was right. Check it out, everyone -- you can write your Ruby scripts i
|
|
29
29
|
* Fire up a REPL or run it in a script.
|
30
30
|
* Immutable linked lists, vectors, and hashes courtesy of the [Hamster][hamster]
|
31
31
|
library.
|
32
|
-
*
|
33
|
-
* _(TODO)_
|
32
|
+
* Clojure-style atoms, courtesy of [concurrent-ruby][concurrent].
|
33
|
+
* _(TODO)_ Clojure-style macros.
|
34
|
+
* _(TODO)_ Clojure-style namespaces.
|
34
35
|
* _(TODO)_ Dependency management / the ability to use some sort of build tool to
|
35
36
|
include Ruby libraries and use them via inter-op.
|
36
37
|
|
@@ -158,18 +159,18 @@ user> (:species barbara)
|
|
158
159
|
But that's not all -- you can also use keywords to get the value of an instance variable:
|
159
160
|
|
160
161
|
```clojure
|
161
|
-
|
162
|
-
define a class in RubyLisp.
|
162
|
+
;; FIXME: This is a contrived example because it is not yet possible to easily
|
163
|
+
;; define a class in RubyLisp.
|
163
164
|
|
164
|
-
|
165
|
-
object... even a string!
|
165
|
+
;; rbl.core/=@ is provided as a convenient way to set instance variables on any
|
166
|
+
;; object... even a string!
|
166
167
|
user> (def s "my string")
|
167
168
|
"my string"
|
168
169
|
|
169
170
|
user> (=@ s :object_level 9001)
|
170
171
|
9001
|
171
172
|
|
172
|
-
|
173
|
+
;; instance variables can then be retrieved by using a keyword as a function
|
173
174
|
user> (:object_level s)
|
174
175
|
9001
|
175
176
|
```
|
@@ -271,3 +272,4 @@ The gem is available as open source under the terms of the [MIT License](http://
|
|
271
272
|
[ruby]: http://ruby-lang.org
|
272
273
|
[mal]: https://github.com/kanaka/mal
|
273
274
|
[hamster]: https://github.com/hamstergem/hamster
|
275
|
+
[concurrent]: https://github.com/ruby-concurrency/concurrent-ruby
|
data/bin/rbl
CHANGED
@@ -13,13 +13,13 @@ USAGE = <<~HEREDOC
|
|
13
13
|
#{File.basename $0} <filename>
|
14
14
|
HEREDOC
|
15
15
|
|
16
|
-
|
17
|
-
when 0
|
16
|
+
if ARGV.empty?
|
18
17
|
RubyLisp::REPL::start
|
19
|
-
|
18
|
+
elsif ARGV[0] == '--help'
|
19
|
+
puts USAGE
|
20
|
+
else
|
20
21
|
file_contents = File.read ARGV[0]
|
22
|
+
ARGV.shift
|
21
23
|
input = file_contents.gsub(/\A#!.*\n/, '')
|
22
24
|
puts RubyLisp::Parser.parse(input)
|
23
|
-
else
|
24
|
-
puts USAGE
|
25
25
|
end
|
data/lib/rubylisp/environment.rb
CHANGED
@@ -2,14 +2,28 @@ require 'rubylisp/parser'
|
|
2
2
|
|
3
3
|
module RubyLisp
|
4
4
|
class Environment
|
5
|
-
attr_accessor :namespace, :vars, :outer
|
5
|
+
attr_accessor :namespace, :vars, :outer, :is_namespace, :out_env
|
6
6
|
|
7
|
-
def initialize(outer: nil, namespace: nil)
|
7
|
+
def initialize(outer: nil, namespace: nil, is_namespace: false, out_env: nil)
|
8
8
|
@vars = {'*ns*' => (outer or self)}
|
9
9
|
@outer = outer
|
10
10
|
@namespace = namespace or
|
11
11
|
(outer.namespace if outer) or
|
12
12
|
"__ns_#{rand 10000}"
|
13
|
+
@is_namespace = is_namespace
|
14
|
+
@out_env = if out_env
|
15
|
+
out_env
|
16
|
+
else
|
17
|
+
find_namespace
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def find_namespace
|
22
|
+
env = self
|
23
|
+
while !env.is_namespace && !env.outer.nil?
|
24
|
+
env = env.outer
|
25
|
+
end
|
26
|
+
env
|
13
27
|
end
|
14
28
|
|
15
29
|
def set key, val
|
@@ -31,7 +45,7 @@ module RubyLisp
|
|
31
45
|
if env
|
32
46
|
env.vars[key]
|
33
47
|
else
|
34
|
-
raise
|
48
|
+
raise RuntimeError, "Unable to resolve symbol: #{key}"
|
35
49
|
end
|
36
50
|
end
|
37
51
|
|
@@ -55,8 +69,8 @@ module RubyLisp
|
|
55
69
|
root = File.expand_path '../..', File.dirname(__FILE__)
|
56
70
|
input = File.read "#{root}/#{path}"
|
57
71
|
|
58
|
-
namespace =
|
59
|
-
|
72
|
+
namespace = Environment.new
|
73
|
+
Parser.parse input, namespace
|
60
74
|
namespace
|
61
75
|
end
|
62
76
|
|
data/lib/rubylisp/evaluator.rb
CHANGED
@@ -1,226 +1,257 @@
|
|
1
1
|
require 'rubylisp/environment'
|
2
2
|
require 'rubylisp/printer'
|
3
3
|
require 'rubylisp/types'
|
4
|
+
require 'rubylisp/util'
|
5
|
+
|
6
|
+
include RubyLisp::Util
|
4
7
|
|
5
8
|
module RubyLisp
|
6
9
|
module Evaluator
|
7
10
|
module_function
|
8
11
|
|
9
|
-
def
|
10
|
-
|
11
|
-
|
12
|
-
unless
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
12
|
+
def macro_call? ast, env
|
13
|
+
return false unless ast.is_a? Hamster::List
|
14
|
+
symbol = ast[0]
|
15
|
+
return false unless symbol.class == Symbol
|
16
|
+
return false unless env.find(symbol.value)
|
17
|
+
value = symbol.resolve(env)
|
18
|
+
value.class == Function && value.is_macro
|
17
19
|
end
|
18
20
|
|
19
|
-
def
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
raise RubyLisp::RuntimeError,
|
24
|
-
"Wrong number of arguments passed to `#{fn_name}`; " +
|
25
|
-
"got #{args.count}, expected at least #{num_args}."
|
21
|
+
def macroexpand input, env
|
22
|
+
while macro_call? input, env
|
23
|
+
macro = input[0].resolve(env)
|
24
|
+
input = macro.call(*input[1..-1])
|
26
25
|
end
|
26
|
+
input
|
27
27
|
end
|
28
28
|
|
29
|
-
def
|
30
|
-
|
31
|
-
|
32
|
-
arg = if arg_number == 'last'
|
33
|
-
sexp.value.last
|
34
|
-
else
|
35
|
-
sexp.value[arg_number]
|
36
|
-
end
|
29
|
+
def pair? form
|
30
|
+
sequential?(form) && form.count > 0
|
31
|
+
end
|
37
32
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
arg_types.join(', ') + " or #{last_arg_type}"
|
58
|
-
end
|
59
|
-
|
60
|
-
if arg_types.none? {|type| arg.is_a? type}
|
61
|
-
raise RubyLisp::RuntimeError,
|
62
|
-
"#{arg_description} to `#{fn_name}` must be a " +
|
63
|
-
"#{expected}; got a #{arg.class}."
|
33
|
+
def quasiquote ast
|
34
|
+
if !pair?(ast)
|
35
|
+
list [Symbol.new('quote'), ast]
|
36
|
+
elsif vector? ast
|
37
|
+
list [Symbol.new('vec'), quasiquote(ast.to_list)]
|
38
|
+
else
|
39
|
+
elem_a, *elems = ast
|
40
|
+
|
41
|
+
if elem_a.class == Symbol && elem_a.value == 'unquote'
|
42
|
+
elems[0]
|
43
|
+
elsif pair?(elem_a) &&
|
44
|
+
elem_a[0].class == Symbol &&
|
45
|
+
elem_a[0].value == 'splice-unquote'
|
46
|
+
list [Symbol.new('concat'), elem_a[1], quasiquote(elems)]
|
47
|
+
else
|
48
|
+
list [Symbol.new('cons'),
|
49
|
+
quasiquote(elem_a),
|
50
|
+
quasiquote(elems.to_list)]
|
51
|
+
end
|
64
52
|
end
|
65
53
|
end
|
66
54
|
|
55
|
+
def special_form? input, name
|
56
|
+
input[0].class == Symbol && input[0].value == name
|
57
|
+
end
|
58
|
+
|
67
59
|
def eval_ast input, env
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
input
|
73
|
-
when RubyLisp::List
|
74
|
-
if input.value.empty?
|
75
|
-
input.value
|
76
|
-
elsif input.value[0].value == 'apply'
|
77
|
-
coll = eval_ast(input.value[-1], env) || Hamster::Vector[]
|
78
|
-
|
79
|
-
# evaluate the last argument
|
80
|
-
sexp = RubyLisp::List.new(input.value.fill(coll, -1, 1))
|
81
|
-
# assert that it's enumerable
|
82
|
-
assert_arg_type sexp, 'last', Enumerable
|
83
|
-
|
84
|
-
# drop `apply` and pull the last form's contents into the sexp as
|
85
|
-
# multiple arguments
|
86
|
-
all_but_last_arg = sexp.value[1..-2].map {|arg| eval_ast arg, env}
|
87
|
-
fn, *args = all_but_last_arg + coll.to_list
|
88
|
-
sexp = RubyLisp::List.new([RubyLisp::Symbol.new("apply"), fn])
|
89
|
-
assert_arg_type sexp, 1, Proc
|
90
|
-
fn.call(*args)
|
91
|
-
elsif input.value[0].value == 'def'
|
92
|
-
assert_arg_type input, 1, RubyLisp::Symbol
|
93
|
-
key, val = input.value[1..-1]
|
94
|
-
env.set key.value, eval_ast(val, env)
|
95
|
-
elsif input.value[0].value == 'do'
|
96
|
-
body = input.value[1..-1]
|
97
|
-
body.map {|form| eval_ast(form, env)}.last
|
98
|
-
elsif input.value[0].value == 'fn'
|
99
|
-
if input.value[1].class == RubyLisp::Symbol
|
100
|
-
fn_name = input.value[1].value
|
101
|
-
bindings, *body = input.value[2..-1]
|
102
|
-
else
|
103
|
-
fn_name = "__fn_#{rand 10000}"
|
104
|
-
bindings, *body = input.value[1..-1]
|
105
|
-
end
|
60
|
+
# loop forever until a value is returned;
|
61
|
+
# this is for tail call optimization
|
62
|
+
while true
|
63
|
+
# (no-op if this is not a macro call)
|
64
|
+
input = macroexpand(input, env)
|
106
65
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
66
|
+
case input
|
67
|
+
when Array # of ASTs to be evaluated, e.g. multiple expressions in a file
|
68
|
+
# discard nils that can be produced by the reader, e.g. when a comment
|
69
|
+
# is read
|
70
|
+
input = input.compact
|
111
71
|
|
112
|
-
|
113
|
-
if
|
114
|
-
|
115
|
-
|
116
|
-
|
72
|
+
# if input is empty (e.g. only comments), there is nothing to evaluate
|
73
|
+
return nil if input.empty?
|
74
|
+
|
75
|
+
# discard the return value of all but the last form
|
76
|
+
input[0..-2].each {|form| eval_ast(form, env)}
|
77
|
+
# recur; evaluate and return the value of the last form
|
78
|
+
input = input.last
|
79
|
+
when Hamster::Hash
|
80
|
+
return input.map {|k, v| [eval_ast(k, env), eval_ast(v, env)]}
|
81
|
+
when Hamster::List
|
82
|
+
if input.empty?
|
83
|
+
return input
|
84
|
+
elsif special_form? input, 'apply'
|
85
|
+
# evaluate the last argument
|
86
|
+
coll = eval_ast(input[-1], env) || vector()
|
87
|
+
# assert that it's enumerable
|
88
|
+
sexp = list input.fill(coll, -1, 1)
|
89
|
+
assert_arg_type sexp, 'last', Enumerable
|
90
|
+
|
91
|
+
# drop `apply` and pull the last form's contents into the sexp as
|
92
|
+
# multiple arguments
|
93
|
+
all_but_last_arg = sexp[1..-2].map {|arg| eval_ast arg, env}
|
94
|
+
fn, *args = all_but_last_arg + coll.to_list
|
95
|
+
sexp = list [Symbol.new("apply"), fn]
|
96
|
+
assert_arg_type sexp, 1, [Function, Proc]
|
97
|
+
return fn.call(*args)
|
98
|
+
# Provides a way to call a Ruby method that expects a block. Blocks
|
99
|
+
# are not first-class in Ruby, but they have similar semantics to
|
100
|
+
# functions.
|
101
|
+
#
|
102
|
+
# The last argument to call-with-block can be a Function or
|
103
|
+
# Proc that takes any number of arguments; it will be provided to the
|
104
|
+
# instance method as a block.
|
105
|
+
#
|
106
|
+
# ruby: instance.method(arg1, arg2, arg3) { do_something }
|
107
|
+
# rbl: (call-with-block .method instance [arg1 arg2 arg3] fn)
|
108
|
+
elsif special_form? input, 'call-with-block'
|
109
|
+
assert_number_of_args input, 4
|
117
110
|
|
118
|
-
|
119
|
-
inner_env = RubyLisp::Environment.new(outer: env)
|
120
|
-
inner_env.set(fn_name, fn) # self-referential lambda omg
|
111
|
+
assert_arg_type input, 1, Symbol
|
121
112
|
|
122
|
-
sexp =
|
123
|
-
|
124
|
-
|
125
|
-
assert_at_least_n_args sexp, required_args
|
113
|
+
sexp = input[2..-1].map {|form| eval_ast(form, env)}
|
114
|
+
.cons(input[1].value[1..-1].to_sym)
|
115
|
+
.cons(input[0])
|
126
116
|
|
127
|
-
|
128
|
-
|
129
|
-
end
|
117
|
+
assert_arg_type sexp, 3, [Hamster::List, Hamster::Vector]
|
118
|
+
assert_arg_type sexp, 4, [Function, Proc]
|
130
119
|
|
131
|
-
|
132
|
-
args[required_args..-1].to_list
|
133
|
-
else
|
134
|
-
nil
|
135
|
-
end
|
120
|
+
method, receiver, method_args, fn = sexp[1..-1]
|
136
121
|
|
137
|
-
|
122
|
+
return receiver.send(method, *method_args) do |*block_args|
|
123
|
+
fn.call(*block_args)
|
124
|
+
end
|
125
|
+
elsif special_form? input, 'def'
|
126
|
+
assert_arg_type input, 1, Symbol
|
127
|
+
k, v = input[1..-1]
|
128
|
+
key, val = [k.value, eval_ast(v, env)]
|
129
|
+
return env.out_env.set key, val
|
130
|
+
elsif special_form? input, 'defmacro*'
|
131
|
+
assert_arg_type input, 1, Symbol
|
132
|
+
key, val = input[1..-1]
|
133
|
+
macro = eval_ast(val, env)
|
134
|
+
macro.is_macro = true
|
135
|
+
return env.set key.value, macro
|
136
|
+
elsif special_form? input, 'do'
|
137
|
+
body = input[1..-1]
|
138
|
+
# discard the return values of all but the last form
|
139
|
+
body[0..-2].each {|form| eval_ast(form, env)}
|
140
|
+
# recur; evaluate and return the last form
|
141
|
+
input = body.last
|
142
|
+
elsif special_form? input, 'eval'
|
143
|
+
assert_number_of_args input, 1
|
144
|
+
|
145
|
+
form = eval_ast(input[1], env)
|
146
|
+
input = form
|
147
|
+
elsif special_form? input, 'fn'
|
148
|
+
if input[1].class == Symbol
|
149
|
+
fn_name = input[1].value
|
150
|
+
more = input[2..-1]
|
138
151
|
else
|
139
|
-
|
140
|
-
|
152
|
+
fn_name = "__fn_#{rand 10000}"
|
153
|
+
more = input[1..-1]
|
154
|
+
end
|
141
155
|
|
142
|
-
|
143
|
-
|
144
|
-
|
156
|
+
arities = more[0].class == Hamster::Vector ? [list(more)] : more
|
157
|
+
|
158
|
+
return fn = Function.new(fn_name, env, arities) {|*fn_args|
|
159
|
+
arity = fn.get_arity(fn_args)
|
160
|
+
eval_ast arity.body, fn.gen_env(arity, fn_args, env)
|
161
|
+
}
|
162
|
+
elsif special_form? input, 'if'
|
163
|
+
unless input[1..-1].count > 1
|
164
|
+
raise RuntimeError,
|
165
|
+
"An `if` form must at least have a 'then' branch."
|
145
166
|
end
|
146
167
|
|
147
|
-
|
148
|
-
end
|
149
|
-
elsif input.value[0].value == 'if'
|
150
|
-
cond, then_form, else_form = input.value[1..-1]
|
151
|
-
unless then_form
|
152
|
-
raise RubyLisp::RuntimeError,
|
153
|
-
"An `if` form must at least have a 'then' branch."
|
154
|
-
end
|
168
|
+
cond, then_form, else_form = input[1..-1]
|
155
169
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
170
|
+
if (eval_ast cond, env)
|
171
|
+
input = then_form
|
172
|
+
elsif else_form
|
173
|
+
input = else_form
|
174
|
+
else
|
175
|
+
return nil
|
176
|
+
end
|
177
|
+
elsif special_form? input, 'in-ns'
|
178
|
+
assert_number_of_args input, 1
|
179
|
+
input[1] = eval_ast(input[1], env)
|
180
|
+
assert_arg_type input, 1, Symbol
|
181
|
+
ns_name = input[1].to_s
|
182
|
+
# TODO: register ns and switch to it
|
183
|
+
env.is_namespace = true
|
184
|
+
return env.namespace = ns_name
|
185
|
+
elsif special_form? input, 'let'
|
186
|
+
assert_arg_type input, 1, Hamster::Vector
|
187
|
+
inner_env = Environment.new(outer: env)
|
188
|
+
bindings, *body = input[1..-1]
|
189
|
+
unless bindings.count.even?
|
190
|
+
raise RuntimeError,
|
191
|
+
"The bindings vector of `let` must contain an even number " +
|
192
|
+
" of forms."
|
193
|
+
end
|
177
194
|
|
178
|
-
|
179
|
-
|
180
|
-
|
195
|
+
bindings.each_slice(2) do |(binding, value)|
|
196
|
+
inner_env.set binding.value, eval_ast(value, inner_env)
|
197
|
+
end
|
181
198
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
199
|
+
# discard the return values of all but the last form
|
200
|
+
body[0..-2].each {|expr| eval_ast(expr, inner_env)}
|
201
|
+
# recur; evaluate and return the last form's value
|
202
|
+
env = inner_env
|
203
|
+
input = body.last
|
204
|
+
elsif special_form? input, 'macroexpand'
|
205
|
+
assert_number_of_args input, 1
|
206
|
+
form = eval_ast(input[1], env)
|
207
|
+
return macroexpand(form, env)
|
208
|
+
elsif special_form? input, 'ns'
|
209
|
+
# ns will be defined more robustly in rbl.core, but rbl.core also
|
210
|
+
# needs the `ns` form in order to declare that it is rbl.core.
|
211
|
+
#
|
212
|
+
# defining it here in a minimal form where it is equivalent to in-ns,
|
213
|
+
# except that you don't have to quote the namespace name
|
214
|
+
assert_number_of_args input, 1
|
215
|
+
assert_arg_type input, 1, Symbol
|
216
|
+
ns_name = input[1].to_s
|
217
|
+
# TODO: register ns and switch to it
|
218
|
+
env.is_namespace = true
|
219
|
+
return env.namespace = ns_name
|
220
|
+
elsif special_form? input, 'quasiquote'
|
221
|
+
assert_number_of_args input, 1
|
222
|
+
ast = input[1]
|
223
|
+
input = quasiquote(ast)
|
224
|
+
elsif special_form? input, 'quote'
|
225
|
+
assert_number_of_args input, 1
|
226
|
+
return input[1]
|
227
|
+
elsif special_form? input, 'resolve'
|
228
|
+
assert_number_of_args input, 1
|
229
|
+
symbol = eval_ast(input[1], env)
|
230
|
+
sexp = list input.fill(symbol, 1, 1)
|
231
|
+
assert_arg_type sexp, 1, Symbol
|
232
|
+
return symbol.resolve(env)
|
201
233
|
else
|
202
|
-
|
234
|
+
fn, *args = input.map {|value| eval_ast(value, env)}
|
235
|
+
if fn.class == Function
|
236
|
+
# recur with input and env set to the body of the function and an
|
237
|
+
# inner environment where the function's bindings are set to the
|
238
|
+
# values of the arguments
|
239
|
+
arity = fn.get_arity(args)
|
240
|
+
env = fn.gen_env(arity, args, env)
|
241
|
+
input = arity.body
|
242
|
+
else
|
243
|
+
return fn.call(*args)
|
244
|
+
end
|
203
245
|
end
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
else
|
211
|
-
fn, *args = input.value.map {|value| eval_ast(value, env)}
|
212
|
-
fn.call(*args)
|
213
|
-
end
|
214
|
-
when RubyLisp::Symbol
|
215
|
-
if input.quoted
|
216
|
-
input
|
246
|
+
when Hamster::Vector
|
247
|
+
return input.map {|value| eval_ast(value, env)}
|
248
|
+
when Symbol
|
249
|
+
return input.resolve(env)
|
250
|
+
when Value
|
251
|
+
return input.value
|
217
252
|
else
|
218
|
-
input
|
253
|
+
return input
|
219
254
|
end
|
220
|
-
when RubyLisp::Vector
|
221
|
-
input.value.map {|value| eval_ast(value, env)}
|
222
|
-
else
|
223
|
-
input.value
|
224
255
|
end
|
225
256
|
end
|
226
257
|
end
|