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
data/lib/hammock.rb ADDED
File without changes
@@ -0,0 +1,57 @@
1
+ require 'hammock/map'
2
+ require 'hammock/errors'
3
+ require 'hammock/ireference'
4
+
5
+ module Hammock
6
+ class ARef
7
+ include IReference
8
+
9
+ attr_writer :validator
10
+
11
+ def initialize(meta=nil)
12
+ @meta = meta
13
+ @watches = Map.new
14
+ @validator = nil
15
+ end
16
+
17
+ def validate(fn_or_obj, obj=nil)
18
+ if obj
19
+ fn = fn_or_obj
20
+ else
21
+ obj = fn_or_obj
22
+ fn = validator
23
+ end
24
+
25
+ if fn && !fn.call(obj)
26
+ raise Error, "Illegal reference state"
27
+ end
28
+ end
29
+
30
+ def add_watch(key, cb)
31
+ @watches = watches.assoc(key, cb)
32
+ end
33
+
34
+ def remove_watch(key)
35
+ @watches = watches.without(key)
36
+ end
37
+
38
+ def notify_watches(oldval, newval)
39
+ return if watches.count == 0
40
+ watches.each do |key, fn|
41
+ if fn
42
+ fn.call(key, self, oldval, newval)
43
+ end
44
+ end
45
+ end
46
+
47
+ def watches
48
+ @watches
49
+ end
50
+
51
+ protected
52
+
53
+ def validator
54
+ @validator
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,49 @@
1
+ require 'hammock/errors'
2
+
3
+ module Hammock
4
+ class ArrayChunk
5
+ Undefined = Object.new
6
+
7
+ def initialize(array, offset, endi=nil)
8
+ @array = array
9
+ @offset = offset
10
+ @end = endi || array.length
11
+ end
12
+
13
+ def fetch(i, not_found=Undefined)
14
+ if not_found == Undefined || (i >= 0 && i < count)
15
+ @array[@offset + i]
16
+ else
17
+ not_found
18
+ end
19
+ end
20
+ alias nth fetch
21
+
22
+ def count
23
+ @end - @offset
24
+ end
25
+ alias size count
26
+ alias length count
27
+
28
+ def drop_first
29
+ if @offset == @end
30
+ raise Error, "drop_first of empty chunk"
31
+ else
32
+ self.class.new(@array, @offset + 1, @end)
33
+ end
34
+ end
35
+
36
+ def reduce(fn, start)
37
+ ret = fn.call(start, @array[@offset])
38
+ return ret if RT.reduced?(ret)
39
+
40
+ x = @offset + 1
41
+ while x < @end
42
+ ret = fn.call(ret, @array[x])
43
+ return ret if RT.reduced?(ret)
44
+ x += 1
45
+ end
46
+ ret
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,50 @@
1
+ require 'atomic'
2
+ require 'hammock/aref'
3
+ require 'hammock/ideref'
4
+
5
+ module Hammock
6
+ class Atom < ARef
7
+ include IDeref
8
+ def initialize(obj, meta=nil)
9
+ super(meta)
10
+ @state = Atomic.new(obj)
11
+ end
12
+
13
+ def deref
14
+ @state.get
15
+ end
16
+
17
+ def swap(fn, *args)
18
+ loop do
19
+ v = deref
20
+ new_value = fn.call(v, *args)
21
+ validate(new_value)
22
+ if @state.compare_and_set(v, new_value)
23
+ notify_watches(v, new_value)
24
+ return new_value
25
+ end
26
+ end
27
+ end
28
+
29
+ def compare_and_set(old_value, new_value)
30
+ validate(new_value)
31
+ ret = @state.compare_and_set(old_value, new_value)
32
+ notify_watches(old_value, new_value) if ret
33
+ ret
34
+ end
35
+
36
+ def reset(new_value)
37
+ old_value = deref
38
+ validate(new_value)
39
+ @state.value = new_value
40
+ notify_watches(old_value, new_value)
41
+ new_value
42
+ end
43
+
44
+ def inspect
45
+ prefix = "#<#{self.class}:0x#{self.__id__.to_s(16)}"
46
+ "#{prefix} #{deref.inspect}>"
47
+ end
48
+ alias to_s inspect
49
+ end
50
+ end
@@ -0,0 +1,8 @@
1
+ module Hammock
2
+ class Block
3
+ attr_reader :value
4
+ def initialize(value)
5
+ @value = value
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,25 @@
1
+ require 'hammock/array_chunk'
2
+
3
+ module Hammock
4
+ class ChunkBuffer
5
+ def initialize(capacity)
6
+ @buffer = ::Array.new(capacity)
7
+ @end = 0
8
+ end
9
+
10
+ def add(obj)
11
+ @buffer[@end] = obj
12
+ @end += 1
13
+ end
14
+
15
+ def chunk
16
+ ret = ArrayChunk.new(@buffer, 0, @end)
17
+ @buffer = nil
18
+ ret
19
+ end
20
+
21
+ def count
22
+ @end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,108 @@
1
+ require 'hammock/meta'
2
+ require 'hammock/ichunked_seq'
3
+ require 'hammock/iseq'
4
+
5
+ module Hammock
6
+ class ChunkedCons
7
+ include Meta
8
+ include IChunkedSeq
9
+ include ISeq
10
+
11
+ def initialize(chunk, more, meta=nil)
12
+ @chunk = chunk
13
+ @_more = more
14
+ @meta = meta
15
+ end
16
+
17
+ def with_meta(meta)
18
+ if @meta == meta
19
+ self
20
+ else
21
+ self.class.new(@chunk, @_more, meta)
22
+ end
23
+ end
24
+
25
+ def first
26
+ @chunk.nth(0)
27
+ end
28
+ alias head first
29
+
30
+ def rest
31
+ if @chunk.count > 1
32
+ self.class.new(@chunk.drop_first, @_more)
33
+ elsif @_more.nil?
34
+ EmptyList.new
35
+ else
36
+ @_more
37
+ end
38
+ end
39
+
40
+ def next
41
+ if @chunk.count > 1
42
+ self.class.new(@chunk.drop_first, @_more)
43
+ else
44
+ chunked_next
45
+ end
46
+ end
47
+ alias tail next
48
+
49
+ def chunked_first
50
+ @chunk
51
+ end
52
+
53
+ def chunked_next
54
+ chunked_rest.seq
55
+ end
56
+
57
+ def chunked_rest
58
+ if @_more.nil?
59
+ EmptyList.new
60
+ else
61
+ @_more
62
+ end
63
+ end
64
+
65
+ def each
66
+ return self unless block_given?
67
+ list = self
68
+ until list.nil? || list.empty?
69
+ yield(list.head)
70
+ list = list.tail
71
+ end
72
+ end
73
+
74
+ def to_a
75
+ ret = []
76
+ each do |i|
77
+ ret << i
78
+ end
79
+ ret
80
+ end
81
+
82
+ def empty?
83
+ false
84
+ end
85
+
86
+ def seq
87
+ self
88
+ end
89
+
90
+ def empty
91
+ EmptyList.new
92
+ end
93
+
94
+ def dup
95
+ self
96
+ end
97
+ alias clone dup
98
+
99
+ def to_list
100
+ self
101
+ end
102
+
103
+ def inspect
104
+ "(#{to_a.map(&:inspect).join(' ')})"
105
+ end
106
+ alias to_s inspect
107
+ end
108
+ end
@@ -0,0 +1,97 @@
1
+ require 'hammock/meta'
2
+ require 'hammock/array_chunk'
3
+ require 'hammock/ichunked_seq'
4
+ require 'hammock/iseq'
5
+
6
+ module Hammock
7
+ class ChunkedSeq
8
+ include IChunkedSeq
9
+ include ISeq
10
+ include Meta
11
+
12
+ def initialize(vec, i, offset, node=nil, meta=nil)
13
+ @vec = vec
14
+ @i = i
15
+ @offset = offset
16
+ @meta = meta
17
+ @node = node || @vec.array_for(i)
18
+ end
19
+
20
+ def chunked_first
21
+ ArrayChunk.new(@node, @offset)
22
+ end
23
+
24
+ def chunked_next
25
+ if @i + @node.length < @vec.count
26
+ ChunkedSeq.new(vec, @i + @node.length, 0)
27
+ end
28
+ end
29
+
30
+ def chunked_rest
31
+ seq = chunked_next
32
+ return EmptyList.new if seq.nil?
33
+ seq
34
+ end
35
+
36
+ def with_meta(meta)
37
+ self.class.new(@vec, @i, @offset, @node, meta)
38
+ end
39
+
40
+ def first
41
+ @node[@offset]
42
+ end
43
+ alias head first
44
+
45
+ def next?
46
+ (@offset + 1 < @node.length) || (@i + @node.length < @vec.count)
47
+ end
48
+
49
+ def each
50
+ return self unless block_given?
51
+ list = self
52
+ while list.next?
53
+ yield(list.head)
54
+ list = list.next
55
+ end
56
+ end
57
+
58
+ def to_a
59
+ ret = []
60
+ each do |v|
61
+ ret << v
62
+ end
63
+ ret
64
+ end
65
+
66
+ def next
67
+ if @offset + 1 < @node.length
68
+ ChunkedSeq.new(@vec, @i, @offset + 1, @node)
69
+ else
70
+ chunked_next
71
+ end
72
+ end
73
+
74
+ def rest
75
+ t = self.next
76
+ return EmptyList.new if t.nil?
77
+ t
78
+ end
79
+ alias tail rest
80
+
81
+ def seq
82
+ self
83
+ end
84
+
85
+ def empty?
86
+ seq.nil?
87
+ end
88
+
89
+ def count
90
+ @vec.count - (@i + @offset)
91
+ end
92
+
93
+ def inspect
94
+ "[#{to_a.map(&:inspect).join(' ')}]"
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,197 @@
1
+ require 'hammock/symbol'
2
+ require 'hammock/errors'
3
+
4
+ module Hammock
5
+ module Compiler
6
+ extend self
7
+ DOT = Symbol.intern(".")
8
+ NEW = Symbol.intern("new")
9
+
10
+ def namespace(env, sym)
11
+ env["__namespace__"] || sym.namespace || RT::CURRENT_NS.deref
12
+ end
13
+
14
+ def find_var(env, sym)
15
+ namespace(env, sym).find_var(sym)
16
+ end
17
+
18
+ def macro?(form)
19
+ Meta === form && form.meta && form.meta[:macro]
20
+ end
21
+
22
+ def expand_method(form)
23
+ meta = form.meta
24
+ method, target, *args = *form
25
+ args = Sequence.from_array(args)
26
+ method = Symbol.intern(method.name[1..-1])
27
+ if args
28
+ args = args.cons(method)
29
+ else
30
+ args = method
31
+ end
32
+ Sequence.from_array([DOT, target, args], meta)
33
+ end
34
+
35
+ def expand_new(form)
36
+ meta = form.meta
37
+ klass, *args = *form
38
+ args = Sequence.from_array(args)
39
+ klass = Symbol.intern(klass.name[0..-2])
40
+ if args
41
+ args = args.cons(NEW)
42
+ else
43
+ args = NEW
44
+ end
45
+ Sequence.from_array([DOT, klass, args], meta)
46
+ end
47
+
48
+ def macroexpand1(form, env=RT.global_env)
49
+ form, _ = _macroexpand1(env, form)
50
+ form
51
+ end
52
+
53
+ def _macroexpand1(env, form)
54
+ return form, false unless form.is_a?(List)
55
+ sym = form.car
56
+ return form, false unless Hammock::Symbol === sym
57
+ meta = form.meta
58
+
59
+ if item = find_var(env, sym)
60
+ dreffed = item.deref
61
+ if macro?(item) || macro?(dreffed)
62
+ begin
63
+ form = dreffed.call(form, env, *form.tail)
64
+ if meta && Meta === form
65
+ form = form.with_meta(meta)
66
+ end
67
+ rescue => e
68
+ raise Hammock::CompileError.new(form), "Error compiling: #{e}", e.backtrace
69
+ end
70
+ return form, true
71
+ else
72
+ return form, false
73
+ end
74
+ elsif sym.name == DOT.name
75
+ return form, false
76
+ elsif sym.name.start_with?(DOT.name)
77
+ form = expand_method(form)
78
+ return form, false
79
+ elsif sym.name.end_with?(DOT.name)
80
+ form = expand_new(form)
81
+ return form, false
82
+ else
83
+ return form, false
84
+ end
85
+ end
86
+
87
+ def special(form)
88
+ return unless form.is_a?(List)
89
+ RT.special(form.car)
90
+ end
91
+
92
+ def macroexpand(env, form)
93
+ return form unless List === form && Hammock::Symbol === form.first
94
+ ret = true
95
+ spec = nil
96
+ while ret && !spec
97
+ form, ret = _macroexpand1(env, form)
98
+ spec = special(form) if form
99
+ end
100
+ form
101
+ end
102
+
103
+ def compile(env, form)
104
+ return form unless IPersistentCollection === form
105
+ meta = form.meta
106
+ new_form = form.to_a.map do |f|
107
+ compile(env, f)
108
+ end
109
+ case form
110
+ when List
111
+ list = Sequence.from_array(new_form, meta)
112
+ macroexpand(env, list)
113
+ when Vector
114
+ Vector.from_array(new_form, meta)
115
+ when Map
116
+ Map.from_pairs(new_form).with_meta(meta)
117
+ when Set
118
+ Set.from_array(new_form, meta)
119
+ end
120
+ end
121
+
122
+ def evaluate(env, form)
123
+ form = macroexpand(env, form)
124
+
125
+ case form
126
+ when Var
127
+ form.root
128
+ when EmptyList
129
+ form
130
+ when Hammock::Symbol
131
+ return env[form.name] if env.key?(form.name) && !form.ns
132
+ namespace = form.namespace(env["__namespace__"])
133
+ if namespace.has_var?(form.name) && (v = namespace.find_var(form.name))
134
+ v.deref
135
+ elsif form.constant
136
+ form.constant
137
+ else
138
+ raise "Unable to resolve symbol #{form.name} in this context"
139
+ end
140
+ when List
141
+ if s = special(form)
142
+ return s.call(form, env, *form.tail)
143
+ end
144
+
145
+ head = form.car
146
+
147
+ fn = evaluate(env, head)
148
+
149
+ if Var === fn
150
+ fn = fn.deref
151
+ end
152
+
153
+ if fn.respond_to?(:trace) && (t = fn.trace)
154
+ env = env.bind("__stack__", env["__stack__"].add(t))
155
+ end
156
+
157
+ case fn
158
+ when IFn
159
+ args = (form.tail || []).to_a.map { |elem| evaluate(env, elem) }
160
+ begin
161
+ fn.call *args
162
+ rescue => e
163
+ raise e.class, e.message, (env["__stack__"].to_a.reverse)
164
+ end
165
+ when ::Symbol
166
+ args = (form.tail || []).to_a.map { |elem| evaluate(env, elem) }
167
+ if args.count > 2
168
+ raise ArgumentError, "more than one arg passed as argument to Keyword #{fn}", env["__stack__"].to_a
169
+ end
170
+ map, default = *args
171
+ if ILookup === map
172
+ map.fetch(fn, default)
173
+ end
174
+ else
175
+ raise Error, "What? #{head.inspect}, #{fn.inspect}, #{form}, #{form.meta}"
176
+ end
177
+ when Map
178
+ ret = []
179
+ form.each do |k,v|
180
+ ret << [evaluate(env, k), evaluate(env, v)]
181
+ end
182
+ Map.from_pairs(ret, form.meta)
183
+ when RT::Finally, RT::Catch
184
+ RT::Do.new.call(nil, env, *form.body)
185
+ when Hammock::Set, Vector
186
+ klass = form.class
187
+ ret = []
188
+ form.each do |v|
189
+ ret << evaluate(env, v)
190
+ end
191
+ klass.from_array(ret, form.meta)
192
+ else # un-evaluable
193
+ form
194
+ end
195
+ end
196
+ end
197
+ end