hammock-ruby 0.0.1.alpha

Sign up to get free protection for your applications and to get access to all the features.
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