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