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,309 @@
|
|
1
|
+
require 'hamster/immutable'
|
2
|
+
|
3
|
+
require 'hammock/ipersistent_collection'
|
4
|
+
require 'hammock/meta'
|
5
|
+
require 'hammock/ifn'
|
6
|
+
require 'hammock/ilookup'
|
7
|
+
require 'hammock/chunked_seq'
|
8
|
+
require 'hammock/iseq'
|
9
|
+
|
10
|
+
module Hammock
|
11
|
+
class Vector
|
12
|
+
include Hamster::Immutable
|
13
|
+
include IPersistentCollection
|
14
|
+
include Meta
|
15
|
+
include IFn
|
16
|
+
include ILookup
|
17
|
+
include ISeq
|
18
|
+
|
19
|
+
Undefined = Object.new
|
20
|
+
|
21
|
+
BLOCK_SIZE = 32
|
22
|
+
INDEX_MASK = BLOCK_SIZE - 1
|
23
|
+
BITS_PER_LEVEL = 5
|
24
|
+
|
25
|
+
def self.alloc_from(vec, meta = nil)
|
26
|
+
vec.send(:transform) { @meta = meta }
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.create(coll)
|
30
|
+
if Vector === coll
|
31
|
+
coll
|
32
|
+
else
|
33
|
+
from_array(coll.to_a)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.from_array(items, meta=nil)
|
38
|
+
items.reduce(new(meta)) { |vector, item| vector.add(item) }
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize(meta=nil)
|
42
|
+
@meta = meta
|
43
|
+
@levels = 0
|
44
|
+
@root = []
|
45
|
+
@size = 0
|
46
|
+
end
|
47
|
+
|
48
|
+
def empty?
|
49
|
+
@size == 0
|
50
|
+
end
|
51
|
+
alias null? empty?
|
52
|
+
|
53
|
+
def size
|
54
|
+
@size
|
55
|
+
end
|
56
|
+
alias count size
|
57
|
+
alias length size
|
58
|
+
|
59
|
+
def first
|
60
|
+
get(0)
|
61
|
+
end
|
62
|
+
alias head first
|
63
|
+
|
64
|
+
def last
|
65
|
+
get(-1)
|
66
|
+
end
|
67
|
+
|
68
|
+
def add(item)
|
69
|
+
transform do
|
70
|
+
update_leaf_node(@size, item)
|
71
|
+
@size += 1
|
72
|
+
end
|
73
|
+
end
|
74
|
+
alias cons add
|
75
|
+
alias conj add
|
76
|
+
|
77
|
+
def concat(arraylike)
|
78
|
+
arraylike.to_a.reduce(self) do |v, item|
|
79
|
+
v.add(item)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def set(index, item = Undefined)
|
84
|
+
return set(index, yield(get(index))) if item.equal?(Undefined)
|
85
|
+
raise IndexError if empty? or index == @size
|
86
|
+
raise IndexError if index.abs > @size
|
87
|
+
return set(@size + index, item) if index < 0
|
88
|
+
transform do
|
89
|
+
update_leaf_node(index, item)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def get(index)
|
94
|
+
return nil if empty? or index == @size
|
95
|
+
return nil if index.abs > @size
|
96
|
+
return get(@size + index) if index < 0
|
97
|
+
leaf_node_for(@root, root_index_bits, index)[index & INDEX_MASK]
|
98
|
+
end
|
99
|
+
alias nth get
|
100
|
+
|
101
|
+
def fetch(n, missing=Undefined)
|
102
|
+
unless Integer === n
|
103
|
+
raise "Index must be an Integer. Received #{n.inspect}"
|
104
|
+
end
|
105
|
+
if n >= count
|
106
|
+
if missing == Undefined
|
107
|
+
raise IndexError
|
108
|
+
else
|
109
|
+
missing
|
110
|
+
end
|
111
|
+
else
|
112
|
+
get(n)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
alias val_at fetch
|
116
|
+
|
117
|
+
def call(n, missing=nil)
|
118
|
+
fetch(n, missing)
|
119
|
+
end
|
120
|
+
|
121
|
+
def each(&block)
|
122
|
+
return self unless block_given?
|
123
|
+
traverse_depth_first(&block)
|
124
|
+
nil
|
125
|
+
end
|
126
|
+
|
127
|
+
def map(&block)
|
128
|
+
return self unless block_given?
|
129
|
+
reduce(EmptyVector) { |vector, item| vector.add(yield(item)) }
|
130
|
+
end
|
131
|
+
|
132
|
+
def reduce(memo = Undefined)
|
133
|
+
each do |item|
|
134
|
+
memo = memo.equal?(Undefined) ? item : yield(memo, item)
|
135
|
+
end if block_given?
|
136
|
+
memo unless memo.equal?(Undefined)
|
137
|
+
end
|
138
|
+
|
139
|
+
def empty
|
140
|
+
self.class.new(meta)
|
141
|
+
end
|
142
|
+
|
143
|
+
def eql?(other)
|
144
|
+
return true if other.equal?(self)
|
145
|
+
return false unless instance_of?(other.class) && @size == other.size
|
146
|
+
@root.eql?(other.instance_variable_get(:@root))
|
147
|
+
end
|
148
|
+
alias == eql?
|
149
|
+
|
150
|
+
def to_a
|
151
|
+
ret = []
|
152
|
+
each do |obj|
|
153
|
+
ret << obj
|
154
|
+
end
|
155
|
+
ret
|
156
|
+
end
|
157
|
+
|
158
|
+
def assoc_n(idx, obj)
|
159
|
+
if idx == count
|
160
|
+
add(obj)
|
161
|
+
else
|
162
|
+
set(idx, obj)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
alias assoc assoc_n
|
167
|
+
|
168
|
+
def seq
|
169
|
+
return if count == 0
|
170
|
+
ChunkedSeq.new(self, 0, 0)
|
171
|
+
end
|
172
|
+
|
173
|
+
def array_for(i)
|
174
|
+
leaf_node_for(@root, root_index_bits, i)
|
175
|
+
end
|
176
|
+
|
177
|
+
def inspect
|
178
|
+
"[#{self.map(&:inspect).to_a.join(' ')}]"
|
179
|
+
end
|
180
|
+
|
181
|
+
private
|
182
|
+
|
183
|
+
def traverse_depth_first(node = @root, level = @levels, &block)
|
184
|
+
return node.each(&block) if level == 0
|
185
|
+
node.each { |child| traverse_depth_first(child, level - 1, &block) }
|
186
|
+
end
|
187
|
+
|
188
|
+
def leaf_node_for(node, child_index_bits, index)
|
189
|
+
return node if child_index_bits == 0
|
190
|
+
child_index = (index >> child_index_bits) & INDEX_MASK
|
191
|
+
leaf_node_for(node[child_index], child_index_bits - BITS_PER_LEVEL, index)
|
192
|
+
end
|
193
|
+
|
194
|
+
def update_leaf_node(index, item)
|
195
|
+
copy_leaf_node_for(new_root, root_index_bits, index)[index & INDEX_MASK] = item
|
196
|
+
end
|
197
|
+
|
198
|
+
def copy_leaf_node_for(node, child_index_bits, index)
|
199
|
+
return node if child_index_bits == 0
|
200
|
+
child_index = (index >> child_index_bits) & INDEX_MASK
|
201
|
+
if child_node = node[child_index]
|
202
|
+
child_node = child_node.dup
|
203
|
+
else
|
204
|
+
child_node = []
|
205
|
+
end
|
206
|
+
node[child_index] = child_node
|
207
|
+
copy_leaf_node_for(child_node, child_index_bits - BITS_PER_LEVEL, index)
|
208
|
+
end
|
209
|
+
|
210
|
+
def new_root
|
211
|
+
if full?
|
212
|
+
@levels += 1
|
213
|
+
@root = [@root]
|
214
|
+
else
|
215
|
+
@root = @root.dup
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def full?
|
220
|
+
(@size >> root_index_bits) > 0
|
221
|
+
end
|
222
|
+
|
223
|
+
def root_index_bits
|
224
|
+
@levels * BITS_PER_LEVEL
|
225
|
+
end
|
226
|
+
|
227
|
+
class SubVector
|
228
|
+
include IPersistentCollection
|
229
|
+
include Meta
|
230
|
+
include IFn
|
231
|
+
include ILookup
|
232
|
+
attr_reader :start_idx, :end_idx, :v
|
233
|
+
|
234
|
+
def self.alloc_from(subvec, meta)
|
235
|
+
new(meta, subvec.v, subvec.start_idx, subvec.end_idx)
|
236
|
+
end
|
237
|
+
|
238
|
+
def initialize(meta, vec, start_idx, end_idx)
|
239
|
+
@meta = meta
|
240
|
+
if SubVector === vec
|
241
|
+
start_idx += vec.start_idx
|
242
|
+
end_idx += vec.end_idx
|
243
|
+
vec = vec.v
|
244
|
+
end
|
245
|
+
@v, @start_idx, @end_idx = vec, start_idx, end_idx
|
246
|
+
end
|
247
|
+
|
248
|
+
def to_a
|
249
|
+
a = @v.to_a
|
250
|
+
a[start_idx..end_idx]
|
251
|
+
end
|
252
|
+
|
253
|
+
def size
|
254
|
+
@end_idx - @start_idx
|
255
|
+
end
|
256
|
+
alias count size
|
257
|
+
alias length size
|
258
|
+
|
259
|
+
def add(obj)
|
260
|
+
self.class.new(meta, v.assoc_n(@end_idx, obj), @start_idx, @end_idx + 1)
|
261
|
+
end
|
262
|
+
alias conj add
|
263
|
+
alias cons add
|
264
|
+
|
265
|
+
def get(i)
|
266
|
+
if (@start_idx + i) >= @end_idx || i < 0
|
267
|
+
raise IndexError, "Index #{i} out of bounds."
|
268
|
+
end
|
269
|
+
return v.nth(@start_idx + i);
|
270
|
+
end
|
271
|
+
alias nth get
|
272
|
+
alias val_at get
|
273
|
+
|
274
|
+
def fetch(n, missing=Undefined)
|
275
|
+
if n >= count
|
276
|
+
if missing == Undefined
|
277
|
+
raise IndexError
|
278
|
+
else
|
279
|
+
missing
|
280
|
+
end
|
281
|
+
else
|
282
|
+
get(n)
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
def call(n, missing=nil)
|
287
|
+
fetch(n, missing)
|
288
|
+
end
|
289
|
+
|
290
|
+
def assoc_n(i, obj)
|
291
|
+
if (@start_idx + i) > @end_idx
|
292
|
+
raise IndexError, "Index #{i} out of bounds."
|
293
|
+
elsif (@start_idx + i) == @end_idx
|
294
|
+
cons(val)
|
295
|
+
else
|
296
|
+
self.class.new v.assoc_n(@start_idx + i, obj), @start_idx, @end_idx
|
297
|
+
end
|
298
|
+
end
|
299
|
+
alias assoc assoc_n
|
300
|
+
|
301
|
+
def inspect
|
302
|
+
"[#{to_a.map(&:inspect).join(' ')}]"
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
end
|
307
|
+
|
308
|
+
EmptyVector = Vector.new
|
309
|
+
end
|
@@ -0,0 +1,242 @@
|
|
1
|
+
require 'hammock/reader'
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
describe Hammock::Reader do
|
5
|
+
def read_string(string)
|
6
|
+
io = StringIO.new(string)
|
7
|
+
Hammock::Reader.new.read(io)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "reads a list of numbers" do
|
11
|
+
result = read_string "(1 21 331)"
|
12
|
+
expect(result.to_a).to eq [1, 21, 331]
|
13
|
+
end
|
14
|
+
|
15
|
+
it "reads nested lists of numbers" do
|
16
|
+
result = read_string "(1 (21 331))"
|
17
|
+
expect(result.to_a).to eq [1, Hammock::Sequence.from_array([21, 331])]
|
18
|
+
end
|
19
|
+
|
20
|
+
it "reads bare numbers" do
|
21
|
+
result = read_string "324"
|
22
|
+
expect(result).to eq 324
|
23
|
+
end
|
24
|
+
|
25
|
+
it "reads floats" do
|
26
|
+
result = read_string "3.24"
|
27
|
+
expect(result).to eq 3.24
|
28
|
+
end
|
29
|
+
|
30
|
+
it "reads negative numbers" do
|
31
|
+
result = read_string "-3.24"
|
32
|
+
expect(result).to be_a Numeric
|
33
|
+
expect(result).to eq -3.24
|
34
|
+
end
|
35
|
+
|
36
|
+
it "reads symbols prefixed with -" do
|
37
|
+
result = read_string "-foo"
|
38
|
+
expect(result).to eq Hammock::Symbol.intern("-foo")
|
39
|
+
end
|
40
|
+
|
41
|
+
it "reads strings" do
|
42
|
+
result = read_string '"Hello"'
|
43
|
+
expect(result).to eq "Hello"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "reads strings with escaped double quotes" do
|
47
|
+
result = read_string '"Hello \"Mate\""'
|
48
|
+
expect(result).to eq 'Hello "Mate"'
|
49
|
+
end
|
50
|
+
|
51
|
+
it "reads strings with escapes" do
|
52
|
+
result = read_string '"Hello \\\\"'
|
53
|
+
expect(result).to eq 'Hello \\'
|
54
|
+
end
|
55
|
+
|
56
|
+
it "reads strings with newlines" do
|
57
|
+
result = read_string '"Hello\nThere"'
|
58
|
+
expect(result).to eq "Hello\nThere"
|
59
|
+
end
|
60
|
+
|
61
|
+
it "reads strings with unicode escape sequences" do
|
62
|
+
result = read_string '"Hello snowman \u2603"'
|
63
|
+
expect(result).to eq "Hello snowman ☃"
|
64
|
+
end
|
65
|
+
|
66
|
+
it "reads character literals" do
|
67
|
+
result = read_string '[\u2603]'
|
68
|
+
expect(result.to_a.first).to eq "☃"
|
69
|
+
end
|
70
|
+
|
71
|
+
it "reads character literal newlines" do
|
72
|
+
result = read_string '[\newline]'
|
73
|
+
expect(result.to_a.first).to eq "\n"
|
74
|
+
end
|
75
|
+
|
76
|
+
it "reads lists with strings and numbers" do
|
77
|
+
result = read_string '(1.2 ("Foo" 3))'
|
78
|
+
expect(result.to_a).to eq [1.2, Hammock::Sequence.from_array(["Foo", 3])]
|
79
|
+
end
|
80
|
+
|
81
|
+
it "reads vectors" do
|
82
|
+
result = read_string '["foo" ["bar"]]'
|
83
|
+
expect(result.to_a).to eq ["foo", Hammock::Vector.from_array(["bar"])]
|
84
|
+
end
|
85
|
+
|
86
|
+
it "reads maps" do
|
87
|
+
result = read_string '{"key" "value"}'
|
88
|
+
expect(result).to eq Hammock::Map.from_array ["key", "value"]
|
89
|
+
end
|
90
|
+
|
91
|
+
it "reads nested maps" do
|
92
|
+
result = read_string '{"key1" {"key2" "value"}}'
|
93
|
+
expect(result).to eq Hammock::Map.from_array(["key1", Hammock::Map.from_array(["key2", "value"])])
|
94
|
+
end
|
95
|
+
|
96
|
+
it "ignores optional commas" do
|
97
|
+
result = read_string '{"key1" "val", "key2", "val"}'
|
98
|
+
expect(result).to eq Hammock::Map.from_array ["key1", "val", "key2", "val"]
|
99
|
+
end
|
100
|
+
|
101
|
+
it "parses basic keywords" do
|
102
|
+
result = read_string ':foo'
|
103
|
+
expect(result).to eq :foo
|
104
|
+
end
|
105
|
+
|
106
|
+
it "parses namespaced keywords" do
|
107
|
+
result = read_string ':foo/bar'
|
108
|
+
expect(result).to eq :"foo/bar"
|
109
|
+
end
|
110
|
+
|
111
|
+
it "parses implicitly namespaced keywords" do
|
112
|
+
result = read_string '::foo'
|
113
|
+
expect(result).to eq :"clojure.core/foo"
|
114
|
+
end
|
115
|
+
|
116
|
+
it "parses complex nested data structures" do
|
117
|
+
|
118
|
+
result = read_string '{:foo [1 2 3]
|
119
|
+
:bar "Baz"
|
120
|
+
:quux {:a 1 :b 2}}'
|
121
|
+
expect(result).to eq Hammock::Map.from_array([:foo,
|
122
|
+
Hammock::Vector.from_array([1,2,3]),
|
123
|
+
:bar, "Baz",
|
124
|
+
:quux,
|
125
|
+
Hammock::Map.from_array([:a, 1, :b, 2])])
|
126
|
+
end
|
127
|
+
|
128
|
+
it "parses character literals" do
|
129
|
+
result = read_string '\\a'
|
130
|
+
expect(result).to eq "a"
|
131
|
+
end
|
132
|
+
|
133
|
+
it "parses nil, true, and false" do
|
134
|
+
result = read_string '[true false nil]'
|
135
|
+
expect(result.to_a).to eq [true, false, nil]
|
136
|
+
end
|
137
|
+
|
138
|
+
it "ignores line-ending comments" do
|
139
|
+
result = read_string '["foo" ; ignore me
|
140
|
+
"bar"] ; me too'
|
141
|
+
expect(result.to_a).to eq ["foo", "bar"]
|
142
|
+
end
|
143
|
+
|
144
|
+
it "reads set literals" do
|
145
|
+
result = read_string '#{1 2 3}'
|
146
|
+
expect(result).to eq Hammock::Set.from_array([1, 2, 3])
|
147
|
+
end
|
148
|
+
|
149
|
+
it "reads regex literals" do
|
150
|
+
str = '#"[\\\\d]+"'
|
151
|
+
result = read_string str
|
152
|
+
expect(result).to eq Regexp.new "[\\d]+"
|
153
|
+
end
|
154
|
+
|
155
|
+
it "reads symbols" do
|
156
|
+
str = '(map foo)'
|
157
|
+
result = read_string str
|
158
|
+
expect(result).to eq Hammock::Sequence.from_array [
|
159
|
+
Hammock::Symbol.intern("map"),
|
160
|
+
Hammock::Symbol.intern("foo")]
|
161
|
+
end
|
162
|
+
|
163
|
+
it "reads symbols with ticks too" do
|
164
|
+
str = "(map' foo)"
|
165
|
+
result = read_string str
|
166
|
+
expect(result).to eq Hammock::Sequence.from_array [
|
167
|
+
Hammock::Symbol.intern("map'"),
|
168
|
+
Hammock::Symbol.intern("foo")]
|
169
|
+
end
|
170
|
+
|
171
|
+
it "reads Ruby constants" do
|
172
|
+
str = 'Object'
|
173
|
+
result = read_string str
|
174
|
+
expect(result).to eq Hammock::Symbol.intern("Object")
|
175
|
+
end
|
176
|
+
|
177
|
+
it "reads quoted symbols" do
|
178
|
+
str = "'foo"
|
179
|
+
result = read_string str
|
180
|
+
expect(result).to eq Hammock::Sequence.from_array [Hammock::Symbol.intern("quote"), Hammock::Symbol.intern("foo")]
|
181
|
+
end
|
182
|
+
|
183
|
+
it "reads quoted lists" do
|
184
|
+
str = "'(foo bar)"
|
185
|
+
result = read_string str
|
186
|
+
expected = Hammock::Sequence.from_array([Hammock::Symbol.intern("quote"), Hammock::Sequence.from_array([Hammock::Symbol.intern("foo"), Hammock::Symbol.intern("bar")])])
|
187
|
+
expect(result).to eq expected
|
188
|
+
end
|
189
|
+
|
190
|
+
it "assigns metadata to the following form" do
|
191
|
+
str = "^{:foo true} [1 2]"
|
192
|
+
result = read_string str
|
193
|
+
expected_meta = Hammock::Map.from_array [:foo, true]
|
194
|
+
expect(result.meta).to eq expected_meta
|
195
|
+
end
|
196
|
+
|
197
|
+
it "assigns keyword metadata" do
|
198
|
+
str = "^:foo [1 2]"
|
199
|
+
result = read_string str
|
200
|
+
expected_meta = Hammock::Map.from_array [:foo, true]
|
201
|
+
expect(result.meta).to eq expected_meta
|
202
|
+
end
|
203
|
+
|
204
|
+
it "assigns keyword metadata" do
|
205
|
+
str = "^:foo ^:bar [1 2]"
|
206
|
+
result = read_string str
|
207
|
+
expected_meta = Hammock::Map.from_array [:foo, true, :bar, true]
|
208
|
+
expect(result.meta).to eq expected_meta
|
209
|
+
end
|
210
|
+
|
211
|
+
it "raises error when attempting to apply meta-data to non-meta-data objects" do
|
212
|
+
str = '^:foo ^:bar "hello"'
|
213
|
+
expect { read_string(str) }.to raise_error
|
214
|
+
end
|
215
|
+
|
216
|
+
it "reads syntax quoted clojure.core things" do
|
217
|
+
form = read_string("(def foo 1)")
|
218
|
+
Hammock::Compiler.evaluate(Hammock::RT.global_env, form)
|
219
|
+
str = '`foo'
|
220
|
+
result = read_string(str)
|
221
|
+
expected = Hammock::Symbol.intern("clojure.core", "foo")
|
222
|
+
expect(result.tail.first).to eq expected
|
223
|
+
end
|
224
|
+
|
225
|
+
it "reads unquotes" do
|
226
|
+
str = '`~blah'
|
227
|
+
result = read_string(str)
|
228
|
+
expected = Hammock::Symbol.intern("blah")
|
229
|
+
expect(result).to eq expected
|
230
|
+
end
|
231
|
+
|
232
|
+
it "reads from a file" do
|
233
|
+
reader = Hammock::Reader.new
|
234
|
+
result = nil
|
235
|
+
File.open(File.expand_path("../../examples/data.hmk", __FILE__)) do |f|
|
236
|
+
result = reader.read(f)
|
237
|
+
end
|
238
|
+
expect(result.to_a).to eq [Hammock::Symbol.intern("map"),
|
239
|
+
Hammock::Symbol.intern("foo"),
|
240
|
+
Hammock::Map.from_array([:foo, "bar", :bar, 1, :quux, 1.4])]
|
241
|
+
end
|
242
|
+
end
|