hammock-ruby 0.0.1.alpha
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 +7 -0
- data/README.md +132 -0
- data/bin/hammock +55 -0
- data/lib/clojure/core.clj +6872 -0
- data/lib/hammock.rb +0 -0
- data/lib/hammock/aref.rb +57 -0
- data/lib/hammock/array_chunk.rb +49 -0
- data/lib/hammock/atom.rb +50 -0
- data/lib/hammock/block.rb +8 -0
- data/lib/hammock/chunk_buffer.rb +25 -0
- data/lib/hammock/chunked_cons.rb +108 -0
- data/lib/hammock/chunked_seq.rb +97 -0
- data/lib/hammock/compiler.rb +197 -0
- data/lib/hammock/environment.rb +40 -0
- data/lib/hammock/errors.rb +14 -0
- data/lib/hammock/function.rb +187 -0
- data/lib/hammock/ichunked_seq.rb +23 -0
- data/lib/hammock/ideref.rb +5 -0
- data/lib/hammock/ifn.rb +10 -0
- data/lib/hammock/ilookup.rb +6 -0
- data/lib/hammock/interfaces.rb +80 -0
- data/lib/hammock/ipersistent_collection.rb +15 -0
- data/lib/hammock/ireference.rb +15 -0
- data/lib/hammock/iseq.rb +12 -0
- data/lib/hammock/lazy_sequence.rb +82 -0
- data/lib/hammock/lazy_transformer.rb +169 -0
- data/lib/hammock/list.rb +232 -0
- data/lib/hammock/loop_locals.rb +34 -0
- data/lib/hammock/map.rb +205 -0
- data/lib/hammock/meta.rb +12 -0
- data/lib/hammock/multi_method.rb +52 -0
- data/lib/hammock/namespace.rb +185 -0
- data/lib/hammock/reader.rb +570 -0
- data/lib/hammock/recur_locals.rb +16 -0
- data/lib/hammock/reduced.rb +15 -0
- data/lib/hammock/repl.rb +29 -0
- data/lib/hammock/rt.rb +580 -0
- data/lib/hammock/sequence.rb +59 -0
- data/lib/hammock/set.rb +144 -0
- data/lib/hammock/stream.rb +40 -0
- data/lib/hammock/symbol.rb +65 -0
- data/lib/hammock/var.rb +186 -0
- data/lib/hammock/vector.rb +309 -0
- data/lib/hammock/version.rb +3 -0
- data/lib/hammock/volatile.rb +19 -0
- data/spec/examples/data.hmk +4 -0
- data/spec/hammock/reader_spec.rb +242 -0
- data/spec/hammock/rt_spec.rb +10 -0
- data/spec/hammock/sequence_spec.rb +24 -0
- metadata +139 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'hammock/vector'
|
2
|
+
|
3
|
+
module Hammock
|
4
|
+
class RecurLocals
|
5
|
+
def initialize(rebinds=[])
|
6
|
+
unless Hammock::Vector === rebinds
|
7
|
+
rebinds = Hammock::Vector.from_array(rebinds)
|
8
|
+
end
|
9
|
+
@rebinds = rebinds
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_a
|
13
|
+
@rebinds.to_a
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/hammock/repl.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'hammock'
|
2
|
+
require 'hammock/rt'
|
3
|
+
require 'readline'
|
4
|
+
require 'stringio'
|
5
|
+
|
6
|
+
module Hammock
|
7
|
+
class REPL
|
8
|
+
def self.start
|
9
|
+
new.start
|
10
|
+
end
|
11
|
+
|
12
|
+
def start
|
13
|
+
Hammock::RT.bootstrap!
|
14
|
+
reader = Hammock::Reader.new
|
15
|
+
|
16
|
+
while line = Readline.readline('> ', true)
|
17
|
+
begin
|
18
|
+
line = StringIO.new(line)
|
19
|
+
p Hammock::RT.compile_and_eval(reader.read(line))
|
20
|
+
rescue Exception => ex
|
21
|
+
puts "ERROR: #{ex.class} #{ex}"
|
22
|
+
puts ex.backtrace
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
exit
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/hammock/rt.rb
ADDED
@@ -0,0 +1,580 @@
|
|
1
|
+
require 'atomic'
|
2
|
+
require 'pathname'
|
3
|
+
require 'hammock/reader'
|
4
|
+
require 'hammock/namespace'
|
5
|
+
require 'hammock/environment'
|
6
|
+
require 'hammock/loop_locals'
|
7
|
+
require 'hammock/recur_locals'
|
8
|
+
require 'hammock/stream'
|
9
|
+
require 'hammock/reduced'
|
10
|
+
require 'hammock/sequence'
|
11
|
+
require 'hammock/lazy_sequence'
|
12
|
+
require 'hammock/lazy_transformer'
|
13
|
+
require 'hammock/var'
|
14
|
+
require 'hammock/vector'
|
15
|
+
require 'hammock/function'
|
16
|
+
require 'hammock/multi_method'
|
17
|
+
require 'hammock/atom'
|
18
|
+
require 'hammock/block'
|
19
|
+
require 'hammock/volatile'
|
20
|
+
require 'hammock/chunked_cons'
|
21
|
+
require 'hammock/chunk_buffer'
|
22
|
+
|
23
|
+
module Hammock
|
24
|
+
class RT
|
25
|
+
CLOJURE_NS = Namespace.find_or_create(Symbol.intern("clojure.core"))
|
26
|
+
CURRENT_NS = Var.intern(CLOJURE_NS, Symbol.intern("*ns*"), CLOJURE_NS).dynamic!
|
27
|
+
OUT = Var.intern(CLOJURE_NS, Symbol.intern("*out*"), $stdout).dynamic!
|
28
|
+
IN = Var.intern(CLOJURE_NS, Symbol.intern("*in*"), $stdin).dynamic!
|
29
|
+
ERR = Var.intern(CLOJURE_NS, Symbol.intern("*err*"), $stderr).dynamic!
|
30
|
+
LOADPATH = Var.intern(CLOJURE_NS, Symbol.intern("*load-path*"),
|
31
|
+
Hammock::Vector.from_array($LOAD_PATH)).dynamic!
|
32
|
+
ID = Atomic.new(0)
|
33
|
+
|
34
|
+
|
35
|
+
def self.next_id
|
36
|
+
ID.update {|v| v + 1}
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.var(*args)
|
40
|
+
sym = Symbol.intern(*args)
|
41
|
+
unless ns = Namespace.find(sym.ns)
|
42
|
+
raise ArgumentError, "must provide an existing namespace to intern a var"
|
43
|
+
end
|
44
|
+
ns.find_var!(sym.name)
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.list(*args)
|
48
|
+
Sequence.from_array(args)
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.global_env
|
52
|
+
@global_env = Hammock::Environment.new(
|
53
|
+
"__stack__" => Vector.new.add("(root)"),
|
54
|
+
"RT" => self,
|
55
|
+
"Map" => Map,
|
56
|
+
"Vector" => Vector,
|
57
|
+
"Set" => Hammock::Set,
|
58
|
+
"Symbol" => Hammock::Symbol,
|
59
|
+
"Keyword" => ::Symbol,
|
60
|
+
"Var" => Hammock::Var,
|
61
|
+
"Atom" => Hammock::Atom,
|
62
|
+
"List" => Hammock::List,
|
63
|
+
"Sequence" => Sequence,
|
64
|
+
"Meta" => Meta
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.bootstrap!
|
69
|
+
return if @bootstrapped
|
70
|
+
Hammock::RT.require("clojure/core.clj")
|
71
|
+
@bootstrapped = true
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.resolve_path(path)
|
75
|
+
return path if ::Pathname === path
|
76
|
+
pathname = nil
|
77
|
+
if File.extname(path).empty?
|
78
|
+
path += ".clj"
|
79
|
+
end
|
80
|
+
LOADPATH.deref.each do |dir|
|
81
|
+
pn = Pathname.new File.join(dir, path)
|
82
|
+
if pn.exist?
|
83
|
+
pathname = pn
|
84
|
+
break
|
85
|
+
end
|
86
|
+
end
|
87
|
+
pathname
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.require(path)
|
91
|
+
if pathname = resolve_path(path)
|
92
|
+
load_resource(pathname)
|
93
|
+
else
|
94
|
+
raise "Cannot resolve file #{path}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.load_resource(file)
|
99
|
+
return_to_ns = CURRENT_NS.deref
|
100
|
+
unless file.respond_to?(:getc)
|
101
|
+
file = File.open(file)
|
102
|
+
end
|
103
|
+
Reader.new.read_all(file) do |form|
|
104
|
+
compile_and_eval(form)
|
105
|
+
end
|
106
|
+
ensure
|
107
|
+
file.close
|
108
|
+
CURRENT_NS.bind_root(return_to_ns)
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.compile_and_eval(form)
|
112
|
+
compiled = Compiler.compile(global_env, form)
|
113
|
+
Compiler.evaluate(global_env, compiled)
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.specials
|
117
|
+
@specials ||= {
|
118
|
+
"def" => Def.new,
|
119
|
+
"if" => If.new,
|
120
|
+
"let*" => Let.new,
|
121
|
+
"do" => Do.new,
|
122
|
+
"fn*" => Fn.new,
|
123
|
+
"loop*" => Loop.new,
|
124
|
+
"recur" => Recur.new,
|
125
|
+
"throw" => Throw.new,
|
126
|
+
"in-ns" => InNS.new,
|
127
|
+
"list" => List.new,
|
128
|
+
"." => Host.new,
|
129
|
+
"quote" => QuoteExpr.new,
|
130
|
+
"var" => VarExpr.new,
|
131
|
+
"try" => Try.new
|
132
|
+
}
|
133
|
+
end
|
134
|
+
|
135
|
+
def self.special(name_or_sym)
|
136
|
+
if Symbol === name_or_sym
|
137
|
+
name = name_or_sym.name
|
138
|
+
else
|
139
|
+
name = name_or_sym
|
140
|
+
end
|
141
|
+
specials[name]
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.cons(val, sequence)
|
145
|
+
case sequence
|
146
|
+
when Hammock::List, LazyTransformer
|
147
|
+
sequence.cons(val)
|
148
|
+
else
|
149
|
+
if s = seq(sequence)
|
150
|
+
s.cons(val)
|
151
|
+
else
|
152
|
+
Sequence.new(val)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def self.conj(sequence, val)
|
158
|
+
sequence.conj(val)
|
159
|
+
end
|
160
|
+
|
161
|
+
def self.assoc(sequence, key, val)
|
162
|
+
if sequence
|
163
|
+
sequence.assoc(key, val)
|
164
|
+
else
|
165
|
+
Map.new.assoc(key, val)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def self.dissoc(sequence, key)
|
170
|
+
if sequence
|
171
|
+
sequence.dissoc(key)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def self.get(sequence, key, not_found=nil)
|
176
|
+
if ILookup === sequence
|
177
|
+
sequence.val_at(key, not_found)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def self.contains?(sequence, key)
|
182
|
+
case sequence
|
183
|
+
when Vector
|
184
|
+
sequence.count > key
|
185
|
+
when Map, Set
|
186
|
+
sequence.has_key?(key)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def self.first(sequence)
|
191
|
+
if coll = seq(sequence)
|
192
|
+
coll.first
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def self.second(sequence)
|
197
|
+
if coll = seq(sequence)
|
198
|
+
if coll = coll.tail
|
199
|
+
coll.first unless coll.empty?
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def self.next(sequence)
|
205
|
+
if coll = seq(sequence)
|
206
|
+
t = coll.tail
|
207
|
+
t unless t.empty?
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def self.more(sequence)
|
212
|
+
if coll = seq(sequence)
|
213
|
+
coll.tail
|
214
|
+
else
|
215
|
+
EmptyList.new
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def self.seq(sequence)
|
220
|
+
case sequence
|
221
|
+
when NilClass
|
222
|
+
nil
|
223
|
+
when LazyTransformer, LazySequence
|
224
|
+
sequence.seq
|
225
|
+
when ISeq
|
226
|
+
sequence.seq
|
227
|
+
else
|
228
|
+
if sequence.respond_to?(:to_a)
|
229
|
+
list = Sequence.from_array sequence.to_a
|
230
|
+
list unless list.empty?
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def self.iter(coll)
|
236
|
+
if coll.respond_to?(:each)
|
237
|
+
coll.to_enum
|
238
|
+
else
|
239
|
+
seq(coll).to_enum
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def self.seq?(sequence)
|
244
|
+
Hammock::List === sequence
|
245
|
+
end
|
246
|
+
|
247
|
+
def self.reduced?(obj)
|
248
|
+
Hammock::Reduced === obj
|
249
|
+
end
|
250
|
+
|
251
|
+
def self.keys(sequence)
|
252
|
+
sequence.keys if sequence
|
253
|
+
end
|
254
|
+
|
255
|
+
def self.vals(sequence)
|
256
|
+
sequence.vals if sequence
|
257
|
+
end
|
258
|
+
|
259
|
+
def self.count(sequence)
|
260
|
+
case sequence
|
261
|
+
when NilClass
|
262
|
+
0
|
263
|
+
when String
|
264
|
+
sequence.length
|
265
|
+
else
|
266
|
+
sequence.count
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
def self.nth(sequence, *args)
|
271
|
+
case sequence
|
272
|
+
when String
|
273
|
+
key = args.first
|
274
|
+
sequence[key,1] if key < sequence
|
275
|
+
when Hammock::List, IChunkedSeq
|
276
|
+
sequence.nth(*args)
|
277
|
+
when ILookup
|
278
|
+
sequence.fetch(*args)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
def self.equal(a, b)
|
283
|
+
a == b
|
284
|
+
end
|
285
|
+
|
286
|
+
def self.subvec(vector, start_idx, end_idx)
|
287
|
+
if end_idx < start_idx || start_idx < 0 || end_idx > vector.count
|
288
|
+
raise IndexError
|
289
|
+
end
|
290
|
+
|
291
|
+
if start_idx == end_idx # empty
|
292
|
+
Vector.new
|
293
|
+
else
|
294
|
+
Vector::SubVector.new(vector.meta, vector, start_idx, end_idx)
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
def self.divide(num1, num2)
|
299
|
+
if (num1 % num2).zero?
|
300
|
+
num1 / num2
|
301
|
+
else
|
302
|
+
num1.quo(num2)
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
def self.make_keyword(*args)
|
307
|
+
return args.first if ::Symbol === args.first
|
308
|
+
if args.length == 1
|
309
|
+
*ns, name = args.first.to_s.split("/", 2)
|
310
|
+
parts = [ns.first, name].compact
|
311
|
+
else
|
312
|
+
parts = args[0..1]
|
313
|
+
end
|
314
|
+
parts.join("/").to_sym
|
315
|
+
end
|
316
|
+
|
317
|
+
def self.splat_last(target, method, *args)
|
318
|
+
*first, last = *args
|
319
|
+
target.send(method, *first, *last)
|
320
|
+
end
|
321
|
+
|
322
|
+
def self.find(coll, key)
|
323
|
+
if Map === coll
|
324
|
+
coll.entry_at(key)
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
class InNS
|
329
|
+
def call(_, env, form)
|
330
|
+
ns = Namespace.find_or_create(Compiler.evaluate(env, form))
|
331
|
+
CURRENT_NS.bind_root(ns)
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
class Def
|
336
|
+
Undefined = Object.new
|
337
|
+
|
338
|
+
def call(_, env, sym, val=Undefined)
|
339
|
+
ns = CURRENT_NS.deref
|
340
|
+
var = ns.find_var(sym) || ns.intern(sym)
|
341
|
+
var.bind_root(Compiler.evaluate(env, val)) unless val == Undefined
|
342
|
+
var.meta = sym.meta
|
343
|
+
var
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
class If
|
348
|
+
def call(_, env, predicate, then_clause, else_clause=nil)
|
349
|
+
if Compiler.evaluate(env, predicate)
|
350
|
+
Compiler.evaluate(env, then_clause)
|
351
|
+
else
|
352
|
+
Compiler.evaluate(env, else_clause)
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
class Do
|
358
|
+
def call(_, env, *body)
|
359
|
+
ret = nil
|
360
|
+
b = body.to_a
|
361
|
+
until b.empty?
|
362
|
+
ret = Compiler.evaluate(env, b.first)
|
363
|
+
b.shift
|
364
|
+
end
|
365
|
+
ret
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
class Let
|
370
|
+
def call(_, env, bindings, *body)
|
371
|
+
unless bindings.count.even?
|
372
|
+
raise "Odd number of binding forms passed to let"
|
373
|
+
end
|
374
|
+
|
375
|
+
bindings.to_a.each_slice(2) do |k, v|
|
376
|
+
env = env.bind(k.name, Compiler.evaluate(env, v))
|
377
|
+
end
|
378
|
+
|
379
|
+
Do.new.call(_, env, *body)
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
class Fn
|
384
|
+
def call(list, env, *args)
|
385
|
+
if Symbol === args.first
|
386
|
+
name = args.first.name
|
387
|
+
args.shift
|
388
|
+
else
|
389
|
+
name = nil
|
390
|
+
end
|
391
|
+
|
392
|
+
bodies = args
|
393
|
+
|
394
|
+
if Vector === RT.first(bodies)
|
395
|
+
bodies = RT.list(bodies)
|
396
|
+
end
|
397
|
+
|
398
|
+
arities = bodies.to_a.map do |body|
|
399
|
+
bindings, *body = *body
|
400
|
+
unless Vector === bindings
|
401
|
+
raise "Function declarations must begin with a binding form"
|
402
|
+
end
|
403
|
+
Function::Arity.new(bindings, *body)
|
404
|
+
end
|
405
|
+
|
406
|
+
ns = env["__namespace__"] || CURRENT_NS.deref
|
407
|
+
Function.create(name, ns, env, arities).tap do |fn|
|
408
|
+
fn.meta = list.meta if list.meta
|
409
|
+
end
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
class Loop
|
414
|
+
def call(form, env, bindings, *body)
|
415
|
+
if body.length < 1
|
416
|
+
raise ArgumentError, "loop* takes at least two args"
|
417
|
+
end
|
418
|
+
|
419
|
+
unless Vector === bindings
|
420
|
+
raise ArgumentError, "loop* takes a vector as it's first argument"
|
421
|
+
end
|
422
|
+
|
423
|
+
if bindings && (bindings.length % 2 != 0)
|
424
|
+
raise ArgumentError, "loop* takes a even number of bindings"
|
425
|
+
end
|
426
|
+
|
427
|
+
locals = LoopLocals.empty
|
428
|
+
|
429
|
+
bindings.to_a.each_slice(2) do |k, v|
|
430
|
+
locals = locals.bind(k.name, Compiler.evaluate(env, v))
|
431
|
+
end
|
432
|
+
|
433
|
+
loop do
|
434
|
+
env = env.merge(locals)
|
435
|
+
ret = nil
|
436
|
+
b = body.to_a.dup
|
437
|
+
until b.empty?
|
438
|
+
ret = Compiler.evaluate(env, b.first)
|
439
|
+
b.shift
|
440
|
+
end
|
441
|
+
ret
|
442
|
+
|
443
|
+
if RecurLocals === ret
|
444
|
+
locals = locals.rebind(ret)
|
445
|
+
else
|
446
|
+
break ret
|
447
|
+
end
|
448
|
+
end
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
class List
|
453
|
+
def call(form, env, *args)
|
454
|
+
if Vector === args.last
|
455
|
+
*first, last = *args
|
456
|
+
args = first + last.to_a
|
457
|
+
end
|
458
|
+
Sequence.from_array(args.to_a.map {|arg| Compiler.evaluate(env, arg)})
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
class Recur
|
463
|
+
def call(_, env, *args)
|
464
|
+
args = args.to_a.map {|arg| Compiler.evaluate(env, arg)}
|
465
|
+
RecurLocals.new(args)
|
466
|
+
end
|
467
|
+
end
|
468
|
+
|
469
|
+
class Throw
|
470
|
+
def call(form, env, message_or_error)
|
471
|
+
raise Compiler.evaluate(env, message_or_error)
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
class Try
|
476
|
+
CATCH = Symbol.intern("catch")
|
477
|
+
FINALLY = Symbol.intern("finally")
|
478
|
+
def call(form, env, *exprs)
|
479
|
+
exp = exprs.reverse
|
480
|
+
catches = []
|
481
|
+
finally = nil
|
482
|
+
|
483
|
+
loop do
|
484
|
+
expr = exp.first
|
485
|
+
if Hammock::List === expr
|
486
|
+
if !finally && expr.first == FINALLY && catches.empty?
|
487
|
+
_, *body = *expr
|
488
|
+
finally = Finally.new(*body)
|
489
|
+
exp.shift
|
490
|
+
elsif expr.first == CATCH
|
491
|
+
_, classname, name, *body = *expr
|
492
|
+
catches << Catch.new(Compiler.evaluate(env, classname), name, *body)
|
493
|
+
exp.shift
|
494
|
+
else
|
495
|
+
break
|
496
|
+
end
|
497
|
+
else
|
498
|
+
break
|
499
|
+
end
|
500
|
+
end
|
501
|
+
|
502
|
+
exprs = exp.reverse
|
503
|
+
catches.reverse!
|
504
|
+
|
505
|
+
begin
|
506
|
+
Do.new.call(nil, env, *exprs)
|
507
|
+
rescue Exception => e
|
508
|
+
if c = catches.detect {|c| c.handles?(e)}
|
509
|
+
env = env.bind(c.local.name, e)
|
510
|
+
return Compiler.evaluate(env, c)
|
511
|
+
else
|
512
|
+
raise e
|
513
|
+
end
|
514
|
+
ensure
|
515
|
+
Compiler.evaluate(env, finally)
|
516
|
+
end
|
517
|
+
end
|
518
|
+
|
519
|
+
end
|
520
|
+
|
521
|
+
class Finally
|
522
|
+
attr_reader :body
|
523
|
+
def initialize(*body)
|
524
|
+
@body = body
|
525
|
+
end
|
526
|
+
end
|
527
|
+
|
528
|
+
class Catch
|
529
|
+
attr_reader :local, :body
|
530
|
+
def initialize(errorclass, local, *body)
|
531
|
+
@errorclass = errorclass
|
532
|
+
@local = local
|
533
|
+
@body = body
|
534
|
+
end
|
535
|
+
|
536
|
+
def handles?(error)
|
537
|
+
@errorclass === error
|
538
|
+
end
|
539
|
+
end
|
540
|
+
|
541
|
+
class Host
|
542
|
+
def call(_, env, target, *args)
|
543
|
+
method = args.first
|
544
|
+
arguments = []
|
545
|
+
|
546
|
+
if Sequence === args.first
|
547
|
+
method, *arguments = *args.first
|
548
|
+
arguments = arguments.to_a.map {|arg| Compiler.evaluate(env, arg)}
|
549
|
+
end
|
550
|
+
target = Compiler.evaluate(env, target)
|
551
|
+
|
552
|
+
if Hammock::Block === arguments.last
|
553
|
+
*arguments, block = arguments
|
554
|
+
block = block.value
|
555
|
+
else
|
556
|
+
block = nil
|
557
|
+
end
|
558
|
+
|
559
|
+
target.send(method.name, *arguments, &block)
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
class VarExpr
|
564
|
+
def call(list, env, sym)
|
565
|
+
namespace = env["__namespace__"] || sym.namespace || CURRENT_NS.deref
|
566
|
+
if namespace.has_var?(sym.name)
|
567
|
+
namespace.find_var(sym.name)
|
568
|
+
else
|
569
|
+
raise "Unable to find var #{sym} in namespace #{namespace.name}"
|
570
|
+
end
|
571
|
+
end
|
572
|
+
end
|
573
|
+
|
574
|
+
class QuoteExpr
|
575
|
+
def call(list, env, form)
|
576
|
+
form
|
577
|
+
end
|
578
|
+
end
|
579
|
+
end
|
580
|
+
end
|