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.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +132 -0
  3. data/bin/hammock +55 -0
  4. data/lib/clojure/core.clj +6872 -0
  5. data/lib/hammock.rb +0 -0
  6. data/lib/hammock/aref.rb +57 -0
  7. data/lib/hammock/array_chunk.rb +49 -0
  8. data/lib/hammock/atom.rb +50 -0
  9. data/lib/hammock/block.rb +8 -0
  10. data/lib/hammock/chunk_buffer.rb +25 -0
  11. data/lib/hammock/chunked_cons.rb +108 -0
  12. data/lib/hammock/chunked_seq.rb +97 -0
  13. data/lib/hammock/compiler.rb +197 -0
  14. data/lib/hammock/environment.rb +40 -0
  15. data/lib/hammock/errors.rb +14 -0
  16. data/lib/hammock/function.rb +187 -0
  17. data/lib/hammock/ichunked_seq.rb +23 -0
  18. data/lib/hammock/ideref.rb +5 -0
  19. data/lib/hammock/ifn.rb +10 -0
  20. data/lib/hammock/ilookup.rb +6 -0
  21. data/lib/hammock/interfaces.rb +80 -0
  22. data/lib/hammock/ipersistent_collection.rb +15 -0
  23. data/lib/hammock/ireference.rb +15 -0
  24. data/lib/hammock/iseq.rb +12 -0
  25. data/lib/hammock/lazy_sequence.rb +82 -0
  26. data/lib/hammock/lazy_transformer.rb +169 -0
  27. data/lib/hammock/list.rb +232 -0
  28. data/lib/hammock/loop_locals.rb +34 -0
  29. data/lib/hammock/map.rb +205 -0
  30. data/lib/hammock/meta.rb +12 -0
  31. data/lib/hammock/multi_method.rb +52 -0
  32. data/lib/hammock/namespace.rb +185 -0
  33. data/lib/hammock/reader.rb +570 -0
  34. data/lib/hammock/recur_locals.rb +16 -0
  35. data/lib/hammock/reduced.rb +15 -0
  36. data/lib/hammock/repl.rb +29 -0
  37. data/lib/hammock/rt.rb +580 -0
  38. data/lib/hammock/sequence.rb +59 -0
  39. data/lib/hammock/set.rb +144 -0
  40. data/lib/hammock/stream.rb +40 -0
  41. data/lib/hammock/symbol.rb +65 -0
  42. data/lib/hammock/var.rb +186 -0
  43. data/lib/hammock/vector.rb +309 -0
  44. data/lib/hammock/version.rb +3 -0
  45. data/lib/hammock/volatile.rb +19 -0
  46. data/spec/examples/data.hmk +4 -0
  47. data/spec/hammock/reader_spec.rb +242 -0
  48. data/spec/hammock/rt_spec.rb +10 -0
  49. data/spec/hammock/sequence_spec.rb +24 -0
  50. 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
@@ -0,0 +1,15 @@
1
+ require 'hammock/ideref'
2
+
3
+ module Hammock
4
+ class Reduced
5
+ include IDeref
6
+
7
+ def initialize(value)
8
+ @value = value
9
+ end
10
+
11
+ def deref
12
+ @value
13
+ end
14
+ end
15
+ end
@@ -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