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,169 @@
1
+ require 'atomic'
2
+ require 'hammock/reduced'
3
+ require 'hammock/meta'
4
+ require 'hammock/ifn'
5
+
6
+ module Hammock
7
+ class LazyTransformer
8
+ include Meta
9
+
10
+ attr_accessor :rest, :stepper
11
+ attr_writer :first
12
+
13
+ def self.create(xform, coll)
14
+ new(Stepper.new(xform, RT.iter(coll)))
15
+ end
16
+
17
+ def initialize(*args)
18
+ if Stepper === args.first
19
+ @stepper = args.first
20
+ @first = nil
21
+ @rest = nil
22
+ @meta = nil
23
+ else
24
+ @meta, @first, @rest = args
25
+ @stepper = nil
26
+ end
27
+ end
28
+
29
+ def with_meta(meta)
30
+ seq
31
+ self.class.new(meta, first, rest)
32
+ end
33
+
34
+ def stepper
35
+ @stepper
36
+ end
37
+
38
+ def seq
39
+ stepper.step(self) unless stepper.nil?
40
+
41
+ if @rest.nil?
42
+ nil
43
+ else
44
+ self
45
+ end
46
+ end
47
+
48
+ def first
49
+ seq unless stepper.nil?
50
+ if @rest.nil?
51
+ nil
52
+ else
53
+ @first
54
+ end
55
+ end
56
+
57
+ def next
58
+ seq unless stepper.nil?
59
+ if @rest.nil?
60
+ nil
61
+ else
62
+ @rest.seq
63
+ end
64
+ end
65
+ alias tail next
66
+
67
+ def more
68
+ seq unless stepper.nil?
69
+ if @rest.nil?
70
+ EmptyList.new
71
+ else
72
+ @rest.seq
73
+ end
74
+ end
75
+
76
+ def to_a
77
+ ret = []
78
+ s = seq
79
+ until s.nil?
80
+ ret << s.first
81
+ s = s.next
82
+ end
83
+ ret
84
+ end
85
+
86
+ def count
87
+ i = 0
88
+ s = seq
89
+ until s.nil?
90
+ i += 0
91
+ s = s.next
92
+ end
93
+ i
94
+ end
95
+
96
+ def realized?
97
+ stepper.nil?
98
+ end
99
+
100
+ def empty?
101
+ seq.nil?
102
+ end
103
+
104
+ def inspect
105
+ "(#{to_a.map(&:inspect).join(' ')})"
106
+ end
107
+ alias to_s inspect
108
+
109
+
110
+ class Stepper
111
+ class StepFn
112
+ include IFn
113
+ def call(*args)
114
+ if args.length == 1
115
+ apply_result(args.first)
116
+ else
117
+ apply_result_with_input(*args)
118
+ end
119
+ end
120
+
121
+ def apply_result_with_input(result, input)
122
+ lt = result
123
+ lt.first = input
124
+ lt.rest = LazyTransformer.new(lt.stepper)
125
+ lt.stepper = nil
126
+ lt.rest
127
+ end
128
+
129
+ def apply_result(result)
130
+ lt = result
131
+ lt.stepper = nil
132
+ result
133
+ end
134
+ end
135
+
136
+ def initialize(xform, iter)
137
+ @iter = iter
138
+ @xform = xform.call(StepFn.new)
139
+ end
140
+
141
+ def next?
142
+ @iter.peek
143
+ true
144
+ rescue StopIteration
145
+ false
146
+ end
147
+
148
+ def step(lt)
149
+ while !lt.stepper.nil? && next?
150
+ if RT.reduced?(@xform.call(lt, @iter.next))
151
+ lt.stepper = nil
152
+ et = lt
153
+ until et.rest.nil?
154
+ et = et.rest
155
+ et.stepper = nil
156
+ end
157
+ @xform.call(et)
158
+ return
159
+ end
160
+ end
161
+ unless lt.stepper.nil?
162
+ @xform.call(lt)
163
+ end
164
+ nil
165
+ end
166
+ end
167
+
168
+ end
169
+ end
@@ -0,0 +1,232 @@
1
+ require 'thread'
2
+ require 'forwardable'
3
+ require 'hamster/enumerable'
4
+ require 'hammock/set'
5
+ require 'hammock/compiler'
6
+ require 'hammock/ipersistent_collection'
7
+ require 'hammock/iseq'
8
+
9
+ module Hammock
10
+ module List
11
+ include IPersistentCollection
12
+ include Hamster::Enumerable
13
+ include ISeq
14
+
15
+ Undefined = Object.new
16
+
17
+ CADR = /^c([ad]+)r$/
18
+
19
+ def first; head end
20
+ def null?; empty? end
21
+ def rest; tail end
22
+
23
+ def size
24
+ reduce(0) { |memo, item| memo.next }
25
+ end
26
+ alias length size
27
+ alias count size
28
+
29
+ def cons(item)
30
+ Sequence.new(item, self)
31
+ end
32
+ alias conj cons
33
+
34
+ def each
35
+ return self unless block_given?
36
+ list = self
37
+ while !list.empty?
38
+ yield(list.head)
39
+ list = list.tail
40
+ end
41
+ end
42
+
43
+ def to_a
44
+ ret = []
45
+ each do |obj|
46
+ ret << obj
47
+ end
48
+ ret
49
+ end
50
+
51
+ def map(&block)
52
+ return self unless block_given?
53
+ Stream.new do
54
+ next self if empty?
55
+ Sequence.new(yield(head), tail.map(&block))
56
+ end
57
+ end
58
+
59
+ def append(other)
60
+ Stream.new do
61
+ next other if empty?
62
+ Sequence.new(head, tail.append(other))
63
+ end
64
+ end
65
+ alias cat append
66
+ alias concat append
67
+ alias + append
68
+
69
+ def cycle
70
+ Stream.new do
71
+ next self if empty?
72
+ Sequence.new(head, tail.append(self.cycle))
73
+ end
74
+ end
75
+
76
+ def clear
77
+ EmptyList.new
78
+ end
79
+
80
+ def join(sep = "")
81
+ return "" if empty?
82
+ sep = sep.to_s
83
+ tail.reduce(head.to_s.dup) { |result, item| result << sep << item.to_s }
84
+ end
85
+
86
+ def last
87
+ list = self
88
+ while !list.tail.empty?
89
+ list = list.tail
90
+ end
91
+ list.head
92
+ end
93
+
94
+ def drop(number)
95
+ Stream.new do
96
+ list = self
97
+ while !list.empty? && number > 0
98
+ number -= 1
99
+ list = list.tail
100
+ end
101
+ list
102
+ end
103
+ end
104
+
105
+ def nth(n, default=Undefined)
106
+ res = drop(n)
107
+ if res.empty? && default != Undefined
108
+ default
109
+ else
110
+ res.head
111
+ end
112
+ end
113
+
114
+ def chunk(number)
115
+ Stream.new do
116
+ next self if empty?
117
+ first, remainder = split_at(number)
118
+ Sequence.new(first, remainder.chunk(number))
119
+ end
120
+ end
121
+
122
+ def each_chunk(number, &block)
123
+ chunk(number).each(&block)
124
+ end
125
+ alias each_slice each_chunk
126
+
127
+ def flatten
128
+ Stream.new do
129
+ next self if empty?
130
+ next head.append(tail.flatten) if head.is_a?(List)
131
+ Sequence.new(head, tail.flatten)
132
+ end
133
+ end
134
+
135
+ def group_by(&block)
136
+ return group_by { |item| item } unless block_given?
137
+ reduce(EmptyHash) do |hash, item|
138
+ key = yield(item)
139
+ hash.put(key, (hash.get(key) || EmptyList.new).cons(item))
140
+ end
141
+ end
142
+
143
+ def at(index)
144
+ drop(index).head
145
+ end
146
+
147
+ def eql?(other)
148
+ list = self
149
+ loop do
150
+ return true if other.equal?(list)
151
+ return false unless other.is_a?(List)
152
+ return other.empty? if list.empty?
153
+ return false if other.empty?
154
+ return false unless other.head.eql?(list.head)
155
+ list = list.tail
156
+ other = other.tail
157
+ end
158
+ end
159
+ alias == eql?
160
+
161
+ def hash
162
+ reduce(0) { |hash, item| (hash << 5) - hash + item.hash }
163
+ end
164
+
165
+ def empty
166
+ EmptyList.new
167
+ end
168
+
169
+ def dup
170
+ self
171
+ end
172
+ alias clone dup
173
+
174
+ def to_list
175
+ self
176
+ end
177
+
178
+ def respond_to?(name, include_private = false)
179
+ super || CADR === name.to_s
180
+ end
181
+
182
+ private
183
+
184
+ def method_missing(name, *args, &block)
185
+ return accessor($1) if CADR === name.to_s
186
+ super
187
+ end
188
+
189
+ def accessor(sequence)
190
+ sequence.reverse.each_char.reduce(self) do |memo, char|
191
+ case char
192
+ when "a" then memo.head
193
+ when "d" then memo.tail
194
+ end
195
+ end
196
+ end
197
+ end
198
+
199
+ class EmptyList
200
+ include List
201
+ include Meta
202
+
203
+ def initialize(meta=nil)
204
+ @meta = meta
205
+ end
206
+
207
+ def head
208
+ nil
209
+ end
210
+
211
+ def tail
212
+ self
213
+ end
214
+
215
+ def seq
216
+ nil
217
+ end
218
+
219
+ def with_meta(meta)
220
+ self.class.new(meta)
221
+ end
222
+
223
+ def empty?
224
+ true
225
+ end
226
+
227
+ def inspect
228
+ "()"
229
+ end
230
+ alias to_s inspect
231
+ end
232
+ end
@@ -0,0 +1,34 @@
1
+ require 'hammock/map'
2
+ require 'hammock/vector'
3
+
4
+ module Hammock
5
+ class LoopLocals
6
+ def self.empty
7
+ new([], [])
8
+ end
9
+
10
+ def initialize(names, bindings)
11
+ unless Hammock::Map === bindings
12
+ bindings = Hammock::Map.new bindings
13
+ end
14
+ unless Hammock::Vector === names
15
+ names = Hammock::Vector.from_array(names)
16
+ end
17
+ @bindings = bindings
18
+ @names = names
19
+ end
20
+
21
+ def frame
22
+ @bindings
23
+ end
24
+
25
+ def rebind(recur_locals)
26
+ bindings = Hammock::Map.from_array @names.to_a.zip(recur_locals.to_a).flatten(1)
27
+ self.class.new(@names, bindings)
28
+ end
29
+
30
+ def bind(name, val)
31
+ self.class.new(@names.cons(name), @bindings.assoc(name, val))
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,205 @@
1
+ require 'forwardable'
2
+ require 'hamster/immutable'
3
+ require 'hamster/trie'
4
+
5
+ require 'hammock/ipersistent_collection'
6
+ require 'hammock/meta'
7
+ require 'hammock/ifn'
8
+ require 'hammock/ilookup'
9
+ require 'hammock/iseq'
10
+
11
+ module Hammock
12
+ class Map
13
+ include Hamster::Immutable
14
+ include IPersistentCollection
15
+ include Meta
16
+ include IFn
17
+ include ILookup
18
+ include ISeq
19
+
20
+ Undefined = Object.new
21
+
22
+ def self.alloc_from(map, meta=nil)
23
+ map.send(:transform) { @meta = meta }
24
+ end
25
+
26
+ def self.create(coll)
27
+ case coll
28
+ when Map
29
+ coll
30
+ when Hash
31
+ from_hash(coll)
32
+ else
33
+ from_array(coll.to_a)
34
+ end
35
+ end
36
+
37
+ def self.from_hash(hash = {})
38
+ map = new
39
+ hash.reduce(map) { |m, (k, v)| m.put(k, v) }
40
+ end
41
+
42
+ def self.from_array(array, meta=nil)
43
+ map = new(meta)
44
+ array.each_slice(2) do |pair|
45
+ map = map.put(pair.first, pair.last)
46
+ end
47
+ map
48
+ end
49
+
50
+ def self.from_pairs(array, meta=nil)
51
+ map = new(meta)
52
+ array.each do |pair|
53
+ map = map.put(pair.first, pair.last)
54
+ end
55
+ map
56
+ end
57
+
58
+ def initialize(meta=nil)
59
+ @meta = meta
60
+ @trie = Hamster::EmptyTrie
61
+ end
62
+
63
+ def size
64
+ @trie.size
65
+ end
66
+ alias length size
67
+ alias count size
68
+
69
+ def empty?
70
+ @trie.empty?
71
+ end
72
+ alias null? empty?
73
+
74
+ def has_key?(key)
75
+ @trie.has_key?(key)
76
+ end
77
+ alias key? has_key?
78
+
79
+ def entry_at(key)
80
+ @trie.get(key)
81
+ end
82
+
83
+ def get(key)
84
+ if entry = entry_at(key)
85
+ entry.value
86
+ end
87
+ end
88
+ alias [] get
89
+
90
+ def fetch(key, default = Undefined)
91
+ entry = @trie.get(key)
92
+ if entry
93
+ entry.value
94
+ elsif default != Undefined
95
+ default
96
+ elsif block_given?
97
+ yield
98
+ else
99
+ raise KeyError.new("key not found: #{key.inspect}")
100
+ end
101
+ end
102
+ alias val_at fetch
103
+
104
+ def call(key, default=nil)
105
+ fetch(key, default)
106
+ end
107
+
108
+ def put(key, value = Undefined)
109
+ if value.equal?(Undefined)
110
+ put(key, yield(get(key)))
111
+ else
112
+ transform { @trie = @trie.put(key, value) }
113
+ end
114
+ end
115
+ alias assoc put
116
+
117
+ def delete(key)
118
+ trie = @trie.delete(key)
119
+ transform_unless(trie.equal?(@trie)) { @trie = trie }
120
+ end
121
+ alias without delete
122
+ alias dissoc delete
123
+
124
+ def each
125
+ return self unless block_given?
126
+ @trie.each { |entry| yield(entry.key, entry.value) }
127
+ end
128
+
129
+ def reduce(memo)
130
+ return memo unless block_given?
131
+ @trie.reduce(memo) { |memo, entry| yield(memo, entry.key, entry.value) }
132
+ end
133
+
134
+ def merge(other)
135
+ transform { @trie = other.reduce(@trie, &:put) }
136
+ end
137
+ alias + merge
138
+
139
+ def keys
140
+ reduce(Hammock::EmptyList.new) { |keys, key, _| keys.cons(key) }
141
+ end
142
+
143
+ def values
144
+ reduce(Hammock::EmptyList.new) { |values, _, value| values.cons(value) }
145
+ end
146
+
147
+ def seq
148
+ return if count == 0
149
+ @trie.reduce(Hammock::EmptyList.new) { |entries, entry| entries.cons(entry)}
150
+ end
151
+
152
+ def cons(obj)
153
+ case obj
154
+ when Vector
155
+ assoc(obj.get(0), obj.get(1))
156
+ when Hamster::Trie::Entry
157
+ assoc(obj.key, obj.value)
158
+ when obj.respond_to?(:to_a)
159
+ put *obj
160
+ else
161
+ raise "You passed #{pair} as an argument to conj, but needs an Array-like arg"
162
+ end
163
+ end
164
+
165
+ def conj(pair)
166
+ return merge(pair) if Map === pair
167
+ if pair.respond_to?(:to_a)
168
+ put *pair
169
+ else
170
+ raise "You passed #{pair} as an argument to conj, but needs an Array-like arg"
171
+ end
172
+ end
173
+
174
+ def empty
175
+ self.class.new(meta)
176
+ end
177
+
178
+ def eql?(other)
179
+ instance_of?(other.class) && @trie.eql?(other.instance_variable_get(:@trie))
180
+ end
181
+ alias == eql?
182
+
183
+ def hash
184
+ reduce(0) { |hash, key, value| (hash << 32) - hash + key.hash + value.hash }
185
+ end
186
+
187
+ def to_a
188
+ ret = []
189
+ each do |k,v|
190
+ ret << [k,v]
191
+ end
192
+ ret
193
+ end
194
+ alias pairs to_a
195
+
196
+ def inspect
197
+ out = []
198
+ each do |k, v|
199
+ out << "#{k.inspect} #{v.inspect}"
200
+ end
201
+ "{#{out.join(', ')}}"
202
+ end
203
+ alias to_s inspect
204
+ end
205
+ end