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,59 @@
|
|
1
|
+
require 'hammock/meta'
|
2
|
+
require 'hammock/list'
|
3
|
+
|
4
|
+
module Hammock
|
5
|
+
class Sequence
|
6
|
+
include List
|
7
|
+
include Meta
|
8
|
+
|
9
|
+
attr_reader :head, :tail
|
10
|
+
|
11
|
+
def self.from_array(array, meta=nil)
|
12
|
+
return EmptyList.new(meta) if array.nil? || array.empty?
|
13
|
+
ret = array.to_a.reverse.inject(EmptyList.new) do |prev, el|
|
14
|
+
new(el, prev)
|
15
|
+
end
|
16
|
+
ret.with_meta(meta)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.alloc_from(other, meta=nil)
|
20
|
+
new(other.head, other.tail, meta)
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(head, tail = Hammock::EmptyList.new, meta=nil)
|
24
|
+
@meta = meta
|
25
|
+
@head = head
|
26
|
+
@tail = tail
|
27
|
+
end
|
28
|
+
|
29
|
+
def car
|
30
|
+
head
|
31
|
+
end
|
32
|
+
|
33
|
+
def cdr
|
34
|
+
tail
|
35
|
+
end
|
36
|
+
|
37
|
+
def ==(other)
|
38
|
+
return false unless other.respond_to?(:tail)
|
39
|
+
first == other.first && tail == other.tail
|
40
|
+
end
|
41
|
+
|
42
|
+
def seq
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
def with_meta(meta)
|
47
|
+
self.class.new(head, tail, meta)
|
48
|
+
end
|
49
|
+
|
50
|
+
def inspect
|
51
|
+
"(#{to_a.map(&:inspect).join(' ')})"
|
52
|
+
end
|
53
|
+
alias to_s inspect
|
54
|
+
|
55
|
+
def empty?
|
56
|
+
false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/hammock/set.rb
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
require 'hamster/immutable'
|
2
|
+
require 'hamster/trie'
|
3
|
+
|
4
|
+
require 'hammock/ipersistent_collection'
|
5
|
+
require 'hammock/meta'
|
6
|
+
require 'hammock/ifn'
|
7
|
+
require 'hammock/ilookup'
|
8
|
+
|
9
|
+
module Hammock
|
10
|
+
class Set
|
11
|
+
include Hamster::Immutable
|
12
|
+
include IPersistentCollection
|
13
|
+
include Meta
|
14
|
+
include IFn
|
15
|
+
include ILookup
|
16
|
+
|
17
|
+
Undefined = Object.new
|
18
|
+
|
19
|
+
def self.alloc_from(other, meta=nil)
|
20
|
+
new(meta, other.instance_variable_get(:@trie))
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.create(coll)
|
24
|
+
if self === coll
|
25
|
+
coll
|
26
|
+
else
|
27
|
+
from_array(coll.to_a)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.from_array(items, meta=nil)
|
32
|
+
items.reduce(new(meta)) { |set, item| set.add(item) }
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize(meta=nil, trie=Hamster::EmptyTrie)
|
36
|
+
@meta = meta
|
37
|
+
@trie = trie
|
38
|
+
end
|
39
|
+
|
40
|
+
def empty?
|
41
|
+
@trie.empty?
|
42
|
+
end
|
43
|
+
|
44
|
+
def size
|
45
|
+
@trie.size
|
46
|
+
end
|
47
|
+
alias count size
|
48
|
+
alias length size
|
49
|
+
|
50
|
+
def add(item)
|
51
|
+
transform_unless(include?(item)) { @trie = @trie.put(item, nil) }
|
52
|
+
end
|
53
|
+
alias conj add
|
54
|
+
alias cons add
|
55
|
+
|
56
|
+
def delete(item)
|
57
|
+
trie = @trie.delete(item)
|
58
|
+
transform_unless(trie.equal?(@trie)) { @trie = trie }
|
59
|
+
end
|
60
|
+
alias remove delete
|
61
|
+
alias disjoin delete
|
62
|
+
|
63
|
+
def each
|
64
|
+
return self unless block_given?
|
65
|
+
@trie.each { |entry| yield(entry.key) }
|
66
|
+
end
|
67
|
+
|
68
|
+
def map
|
69
|
+
return self unless block_given?
|
70
|
+
return self if empty?
|
71
|
+
transform do
|
72
|
+
@trie = @trie.reduce(Hamster::EmptyTrie) do |trie, entry|
|
73
|
+
trie.put(yield(entry.key), nil)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def reduce(memo = Undefined)
|
79
|
+
each do |item|
|
80
|
+
memo = memo.equal?(Undefined) ? item : yield(memo, item)
|
81
|
+
end if block_given?
|
82
|
+
memo unless memo.equal?(Undefined)
|
83
|
+
end
|
84
|
+
|
85
|
+
def any?
|
86
|
+
return any? { |item| item } unless block_given?
|
87
|
+
each { |item| return true if yield(item) }
|
88
|
+
false
|
89
|
+
end
|
90
|
+
|
91
|
+
def include?(object)
|
92
|
+
has_key?(object)
|
93
|
+
end
|
94
|
+
|
95
|
+
def has_key?(key)
|
96
|
+
@trie.has_key?(key)
|
97
|
+
end
|
98
|
+
alias key? has_key?
|
99
|
+
|
100
|
+
def fetch(object, default=Undefined)
|
101
|
+
if has_key?(object)
|
102
|
+
object
|
103
|
+
elsif !default.equal?(Undefined)
|
104
|
+
default
|
105
|
+
end
|
106
|
+
end
|
107
|
+
alias call fetch
|
108
|
+
alias val_at fetch
|
109
|
+
|
110
|
+
def get(object)
|
111
|
+
object if has_key?(object)
|
112
|
+
end
|
113
|
+
|
114
|
+
def seq
|
115
|
+
return if count == 0
|
116
|
+
Sequence.from_array(to_a)
|
117
|
+
end
|
118
|
+
|
119
|
+
def eql?(other)
|
120
|
+
instance_of?(other.class) && @trie.eql?(other.instance_variable_get(:@trie))
|
121
|
+
end
|
122
|
+
alias == eql?
|
123
|
+
|
124
|
+
def hash
|
125
|
+
reduce(0) { |hash, item| (hash << 5) - hash + item.hash }
|
126
|
+
end
|
127
|
+
|
128
|
+
def empty
|
129
|
+
self.class.new(meta)
|
130
|
+
end
|
131
|
+
|
132
|
+
def to_a
|
133
|
+
ret = []
|
134
|
+
each do |obj|
|
135
|
+
ret << obj
|
136
|
+
end
|
137
|
+
ret
|
138
|
+
end
|
139
|
+
|
140
|
+
def inspect
|
141
|
+
"\#{#{to_a.map(&:inspect).join(' ')}}"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'hammock/list'
|
2
|
+
require 'forwardable'
|
3
|
+
|
4
|
+
module Hammock
|
5
|
+
class Stream
|
6
|
+
extend Forwardable
|
7
|
+
include List
|
8
|
+
include Meta
|
9
|
+
|
10
|
+
def initialize(meta=nil, &block)
|
11
|
+
@meta = meta
|
12
|
+
@block = block
|
13
|
+
@lock = Mutex.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def_delegators :target, :head, :tail, :empty?
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
def vivify
|
21
|
+
@lock.synchronize do
|
22
|
+
unless @block.nil?
|
23
|
+
@target = @block.call
|
24
|
+
@block = nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
@target
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def target
|
33
|
+
list = vivify
|
34
|
+
while list.is_a?(Stream)
|
35
|
+
list = list.vivify
|
36
|
+
end
|
37
|
+
list
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Hammock
|
2
|
+
class Symbol
|
3
|
+
include Meta
|
4
|
+
|
5
|
+
attr_reader :name, :ns
|
6
|
+
|
7
|
+
def self.intern(*args)
|
8
|
+
return args.first if Hammock::Symbol === args.first
|
9
|
+
|
10
|
+
if args.length == 1
|
11
|
+
*ns, name = args.first.split("/", 2)
|
12
|
+
new(ns.first, name)
|
13
|
+
else
|
14
|
+
new(*args)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.alloc_from(other, meta)
|
19
|
+
new(other.instance_variable_get("@ns"), other.name, meta)
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(ns, name, meta=nil)
|
23
|
+
@name = name
|
24
|
+
@ns = ns if ns && !ns.to_s.empty?
|
25
|
+
@name.freeze
|
26
|
+
@ns.freeze
|
27
|
+
@meta = meta
|
28
|
+
end
|
29
|
+
|
30
|
+
def ==(other)
|
31
|
+
return false unless other.respond_to?(:name)
|
32
|
+
return false unless other.respond_to?(:ns)
|
33
|
+
other.ns == ns && other.name == name
|
34
|
+
end
|
35
|
+
alias eql? ==
|
36
|
+
|
37
|
+
def constant
|
38
|
+
return @constant if defined?(@constant)
|
39
|
+
n = name.gsub(".", "::")
|
40
|
+
@constant = begin
|
41
|
+
Object.const_defined?(n) && Object.const_get(n)
|
42
|
+
rescue NameError
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def inspect
|
47
|
+
@to_s ||= if @ns
|
48
|
+
"#@ns/#@name"
|
49
|
+
else
|
50
|
+
name
|
51
|
+
end
|
52
|
+
end
|
53
|
+
alias to_s inspect
|
54
|
+
|
55
|
+
def namespace(contextual=nil)
|
56
|
+
inns = Hammock::RT::CURRENT_NS.deref
|
57
|
+
prefer_ns = contextual || inns
|
58
|
+
if @ns
|
59
|
+
prefer_ns.lookup_alias(@ns) || Namespace.find(@ns)
|
60
|
+
else
|
61
|
+
prefer_ns
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/hammock/var.rb
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
require 'atomic'
|
2
|
+
require 'hammock/ideref'
|
3
|
+
require 'hammock/errors'
|
4
|
+
require 'hammock/map'
|
5
|
+
|
6
|
+
module Hammock
|
7
|
+
class Var
|
8
|
+
include Meta
|
9
|
+
include IFn
|
10
|
+
Undefined = Object.new
|
11
|
+
|
12
|
+
BINDING_KEY = "__bindings__".freeze
|
13
|
+
|
14
|
+
class Frame
|
15
|
+
attr_reader :bindings, :prev
|
16
|
+
def initialize(bindings, prev)
|
17
|
+
@bindings, @prev = bindings, prev
|
18
|
+
end
|
19
|
+
TOP = new(Map.new, nil)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.dvals
|
23
|
+
Thread.current[BINDING_KEY] ||= Frame::TOP
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.dvals=(vals)
|
27
|
+
Thread.current[BINDING_KEY] = vals
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.thread_bindings
|
31
|
+
f = dvals
|
32
|
+
ret = Map.new
|
33
|
+
f.bindings.each do |k,v|
|
34
|
+
ret.assoc(k, v)
|
35
|
+
end
|
36
|
+
ret
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.push_thread_bindings(bindings)
|
40
|
+
f = dvals
|
41
|
+
bmap = f.bindings
|
42
|
+
bindings.each do |v,val|
|
43
|
+
if !v.dynamic?
|
44
|
+
raise Error, "Can't dynamically bind non-dynamic var: #{v.inspect}"
|
45
|
+
end
|
46
|
+
v.thread_bound!
|
47
|
+
bmap = bmap.assoc(v, val)
|
48
|
+
end
|
49
|
+
self.dvals = Frame.new(bmap, f)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.pop_thread_bindings
|
53
|
+
f = dvals.prev
|
54
|
+
if f.nil?
|
55
|
+
raise Error, "Pop without matching push"
|
56
|
+
else
|
57
|
+
self.dvals = f
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.intern(ns_name, sym, val=Undefined)
|
62
|
+
if Namespace === ns_name
|
63
|
+
ns = ns_name
|
64
|
+
else
|
65
|
+
ns = Namespace.find_or_create(ns_name)
|
66
|
+
end
|
67
|
+
|
68
|
+
var = ns.intern(sym)
|
69
|
+
var.bind_root(val) unless val == Undefined
|
70
|
+
var
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.find(ns_qualified_sym)
|
74
|
+
unless ns = ns_qualified_sym.ns
|
75
|
+
raise Error, "Symbol must be namespace-qualified"
|
76
|
+
end
|
77
|
+
unless namespace = Namespace.find(ns)
|
78
|
+
raise Error, "No such namespace: #{ns}"
|
79
|
+
end
|
80
|
+
namespace.find_var(ns_qualified_sym.name)
|
81
|
+
end
|
82
|
+
|
83
|
+
attr_reader :ns, :symbol, :root
|
84
|
+
|
85
|
+
def initialize(*args)
|
86
|
+
if args.length > 1
|
87
|
+
@ns, @symbol, @root = args
|
88
|
+
else
|
89
|
+
@root = args.first
|
90
|
+
end
|
91
|
+
|
92
|
+
@meta = nil
|
93
|
+
@dynamic = false
|
94
|
+
@public = true
|
95
|
+
@thread_bound = Atomic.new(false)
|
96
|
+
@rev = 0
|
97
|
+
end
|
98
|
+
|
99
|
+
alias namespace ns
|
100
|
+
|
101
|
+
def trace
|
102
|
+
return unless meta
|
103
|
+
"#{meta[:file]}:#{meta[:line]} in #@symbol"
|
104
|
+
end
|
105
|
+
|
106
|
+
def macro!
|
107
|
+
@meta = meta.assoc :macro, true
|
108
|
+
end
|
109
|
+
|
110
|
+
def dynamic!
|
111
|
+
@dynamic = true
|
112
|
+
self
|
113
|
+
end
|
114
|
+
|
115
|
+
def thread_bound!
|
116
|
+
@thread_bound.value = true
|
117
|
+
end
|
118
|
+
|
119
|
+
def thread_bound?
|
120
|
+
@thread_bound.value
|
121
|
+
end
|
122
|
+
|
123
|
+
def thread_binding
|
124
|
+
if thread_bound?
|
125
|
+
self.class.dvals.bindings[self]
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def bound?
|
130
|
+
root? || (thread_bound? && self.class.dval.bindings.key?(self))
|
131
|
+
end
|
132
|
+
|
133
|
+
def root?
|
134
|
+
@rev > 0
|
135
|
+
end
|
136
|
+
|
137
|
+
def dynamic?
|
138
|
+
@dynamic
|
139
|
+
end
|
140
|
+
|
141
|
+
def public?
|
142
|
+
@public
|
143
|
+
end
|
144
|
+
|
145
|
+
def private?
|
146
|
+
!@public
|
147
|
+
end
|
148
|
+
|
149
|
+
def deref
|
150
|
+
thread_binding || @root
|
151
|
+
end
|
152
|
+
|
153
|
+
def bind_root(val)
|
154
|
+
@rev += 1
|
155
|
+
@root = val
|
156
|
+
end
|
157
|
+
|
158
|
+
def unbind_root
|
159
|
+
@root = nil
|
160
|
+
end
|
161
|
+
|
162
|
+
def meta=(meta)
|
163
|
+
if meta[:private]
|
164
|
+
@public = false
|
165
|
+
end
|
166
|
+
if meta[:dynamic]
|
167
|
+
@dynamic = true
|
168
|
+
end
|
169
|
+
@meta = meta
|
170
|
+
end
|
171
|
+
|
172
|
+
def call(*args)
|
173
|
+
@root.call(*args)
|
174
|
+
end
|
175
|
+
|
176
|
+
def to_s
|
177
|
+
if @ns
|
178
|
+
"#'#{@ns.name}/#{symbol.name}"
|
179
|
+
else
|
180
|
+
n = symbol ? symbol.to_s : "--unnamed--"
|
181
|
+
"#<Var: #{n}>"
|
182
|
+
end
|
183
|
+
end
|
184
|
+
alias inspect to_s
|
185
|
+
end
|
186
|
+
end
|