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,40 @@
|
|
1
|
+
module Hammock
|
2
|
+
class Environment
|
3
|
+
attr_reader :frame
|
4
|
+
|
5
|
+
def initialize(frame)
|
6
|
+
unless Hammock::Map === frame
|
7
|
+
frame = Hammock::Map.create frame
|
8
|
+
end
|
9
|
+
@frame = frame
|
10
|
+
end
|
11
|
+
|
12
|
+
def bind(name, val)
|
13
|
+
self.class.new(@frame.assoc name, val)
|
14
|
+
end
|
15
|
+
|
16
|
+
def merge(env)
|
17
|
+
self.class.new(@frame.merge(env.frame))
|
18
|
+
end
|
19
|
+
|
20
|
+
def find(name)
|
21
|
+
if item = @frame[name]
|
22
|
+
item
|
23
|
+
end
|
24
|
+
end
|
25
|
+
alias [] find
|
26
|
+
|
27
|
+
def key?(name)
|
28
|
+
@frame.key?(name)
|
29
|
+
end
|
30
|
+
|
31
|
+
def inspect
|
32
|
+
parts = []
|
33
|
+
f = frame.each do |k,v|
|
34
|
+
parts << " #{k}\t#{v.inspect}"
|
35
|
+
end
|
36
|
+
"#<#{self.class}\n#{parts.join("\n")}"
|
37
|
+
end
|
38
|
+
alias to_s inspect
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Hammock
|
2
|
+
class Error < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
class CompileError < Error
|
6
|
+
def initialize(form, msg=nil)
|
7
|
+
parts = [msg || "Error compiling form"]
|
8
|
+
if Meta === form && form.meta && form.meta[:line]
|
9
|
+
parts << "Originated from #{form.meta[:file]}:#{form.meta[:line]}, col #{form.meta[:column]}"
|
10
|
+
end
|
11
|
+
super(parts.join("\n"))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
require 'hammock/meta'
|
2
|
+
require 'hammock/ifn'
|
3
|
+
|
4
|
+
module Hammock
|
5
|
+
class Function
|
6
|
+
include Meta
|
7
|
+
include IFn
|
8
|
+
|
9
|
+
attr_reader :arities
|
10
|
+
attr_writer :meta
|
11
|
+
|
12
|
+
def self.alloc_from(fn, meta)
|
13
|
+
new(fn.internal_name, fn.ns, fn.env, fn.arities).tap do |fn|
|
14
|
+
fn.meta = meta
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.create(name, ns, env, arities)
|
19
|
+
new(name, ns, env, arities)
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(internal_name, ns, env, arities)
|
23
|
+
@internal_name = internal_name || generate_name
|
24
|
+
@ns = ns
|
25
|
+
@env = env
|
26
|
+
@arities = arities
|
27
|
+
@meta = nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def variadic?
|
31
|
+
arities.any?(&:variadic?)
|
32
|
+
end
|
33
|
+
|
34
|
+
def arity_counts
|
35
|
+
arities.map(&:arity)
|
36
|
+
end
|
37
|
+
|
38
|
+
def find_arity!(*args)
|
39
|
+
needed = args.to_a.length
|
40
|
+
arities.detect {|a| a.handles_arity?(needed)} or \
|
41
|
+
raise ArgumentError, wrong_arity_message(needed)
|
42
|
+
end
|
43
|
+
|
44
|
+
def wrong_arity_message(needed)
|
45
|
+
c = arity_counts.map(&:to_s)
|
46
|
+
c << "more" if variadic?
|
47
|
+
if c.length == 1
|
48
|
+
counts = c.first
|
49
|
+
else
|
50
|
+
counts = c[0..-2].join(", ") + " or #{c.last}"
|
51
|
+
end
|
52
|
+
"Wrong number of args passed to #{name}. Expected #{counts}; Got #{needed}"
|
53
|
+
end
|
54
|
+
|
55
|
+
def name
|
56
|
+
"#{ns.name}/#@internal_name"
|
57
|
+
end
|
58
|
+
|
59
|
+
def meta=(meta)
|
60
|
+
@meta = meta
|
61
|
+
end
|
62
|
+
|
63
|
+
def trace
|
64
|
+
return unless meta
|
65
|
+
"#{meta[:file]}:#{meta[:line]} in #@internal_name"
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_proc
|
69
|
+
fn = self
|
70
|
+
lambda { |*args| fn.call(*args) }
|
71
|
+
end
|
72
|
+
|
73
|
+
def to_block
|
74
|
+
Block.new(self)
|
75
|
+
end
|
76
|
+
|
77
|
+
def call(*args)
|
78
|
+
arity = find_arity!(*args)
|
79
|
+
|
80
|
+
env = @env.bind("__namespace__", @ns)
|
81
|
+
env = env.bind(@internal_name, self)
|
82
|
+
|
83
|
+
locals = args
|
84
|
+
|
85
|
+
loop do
|
86
|
+
env = arity.bind_env(env, locals.to_a)
|
87
|
+
ret = nil
|
88
|
+
body = arity.body.dup
|
89
|
+
until body.empty?
|
90
|
+
ret = Compiler.evaluate(env, body.first)
|
91
|
+
body.shift
|
92
|
+
end
|
93
|
+
if RecurLocals === ret
|
94
|
+
if ret.to_a.last.nil?
|
95
|
+
locals = ret.to_a[0..-2]
|
96
|
+
else
|
97
|
+
locals = ret
|
98
|
+
end
|
99
|
+
else
|
100
|
+
break ret
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def inspect
|
106
|
+
"#<Hammock::Function #@internal_name>"
|
107
|
+
end
|
108
|
+
|
109
|
+
protected
|
110
|
+
|
111
|
+
attr_reader :ns, :env, :internal_name
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
def generate_name
|
116
|
+
"fn__#{RT.next_id}"
|
117
|
+
end
|
118
|
+
|
119
|
+
class Arity
|
120
|
+
AMPERSAND = Symbol.intern("&")
|
121
|
+
|
122
|
+
attr_reader :bindings, :body, :arity, :args
|
123
|
+
|
124
|
+
def initialize(bindings, *body)
|
125
|
+
@bindings, @body = bindings, body
|
126
|
+
@locals, @args, @variadic, @variadic_name = unpack_args(bindings)
|
127
|
+
@arity = @args.length
|
128
|
+
end
|
129
|
+
|
130
|
+
def bind_env(env, args)
|
131
|
+
max = variadic? ? @args.length - 1 : @args.length
|
132
|
+
|
133
|
+
0.upto(max) do |i|
|
134
|
+
env = env.bind @args[i], args[i]
|
135
|
+
end
|
136
|
+
|
137
|
+
if variadic?
|
138
|
+
lastarg = nil
|
139
|
+
if args.length > max
|
140
|
+
tail = args[max..-1]
|
141
|
+
lastarg = Sequence.from_array(tail) if tail && !tail.empty?
|
142
|
+
end
|
143
|
+
env = env.bind @variadic_name, lastarg
|
144
|
+
end
|
145
|
+
|
146
|
+
env
|
147
|
+
end
|
148
|
+
|
149
|
+
def handles_arity?(count)
|
150
|
+
if variadic?
|
151
|
+
count >= @arity - 1
|
152
|
+
else
|
153
|
+
count == @arity
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def variadic?
|
158
|
+
@variadic
|
159
|
+
end
|
160
|
+
|
161
|
+
def unpack_args(form)
|
162
|
+
locals = {}
|
163
|
+
args = []
|
164
|
+
lastisargs = false
|
165
|
+
argsname = nil
|
166
|
+
|
167
|
+
form.each do |x|
|
168
|
+
if x == AMPERSAND
|
169
|
+
lastisargs = true
|
170
|
+
next
|
171
|
+
end
|
172
|
+
if lastisargs and argsname
|
173
|
+
raise "variable length argument must be the last in the function #{form.inspect}"
|
174
|
+
end
|
175
|
+
argsname = x.name if lastisargs
|
176
|
+
if !(Symbol === x) || x.ns
|
177
|
+
raise "fn* arguments must be non namespaced symbols, got #{x}: in #{form.inspect}"
|
178
|
+
end
|
179
|
+
locals[x] = RT.list(x)
|
180
|
+
args << x.name
|
181
|
+
end
|
182
|
+
|
183
|
+
return locals, args, lastisargs, argsname
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Hammock
|
2
|
+
module IChunkedSeq
|
3
|
+
Undefined = Object.new
|
4
|
+
|
5
|
+
def nth(n, notfound=Undefined)
|
6
|
+
list = seq
|
7
|
+
|
8
|
+
n.times do
|
9
|
+
list = list.rest
|
10
|
+
end
|
11
|
+
|
12
|
+
if list.empty?
|
13
|
+
if notfound == Undefined
|
14
|
+
raise IndexError
|
15
|
+
else
|
16
|
+
notfound
|
17
|
+
end
|
18
|
+
else
|
19
|
+
list.first
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/hammock/ifn.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
module IPersistentCollection
|
2
|
+
# returns int
|
3
|
+
def count; end
|
4
|
+
|
5
|
+
# returns a collection
|
6
|
+
def cons(obj); end
|
7
|
+
|
8
|
+
# returns empty collection
|
9
|
+
def empty(); end
|
10
|
+
|
11
|
+
# returns true or false
|
12
|
+
# def equiv(obj); end
|
13
|
+
end
|
14
|
+
|
15
|
+
module IPersistentVector
|
16
|
+
# returns int
|
17
|
+
def length; end
|
18
|
+
|
19
|
+
# returns IPersistentVector
|
20
|
+
def assocN(i, obj); end
|
21
|
+
|
22
|
+
# returns IPersistentVector
|
23
|
+
def cons(obj); end
|
24
|
+
end
|
25
|
+
|
26
|
+
module ILookup
|
27
|
+
def val_at(key, not_found=nil); end
|
28
|
+
end
|
29
|
+
|
30
|
+
module Associative
|
31
|
+
# returns MapEntry
|
32
|
+
def entry_at(key); end
|
33
|
+
|
34
|
+
# returns Associative
|
35
|
+
def assoc(key, val); end
|
36
|
+
end
|
37
|
+
|
38
|
+
module IPersistentMap
|
39
|
+
# returns IPersistentMap
|
40
|
+
def assoc(key, val); end
|
41
|
+
|
42
|
+
# returns IPersistentMap
|
43
|
+
def assocEx(key, val); end
|
44
|
+
|
45
|
+
# returns IPersistentMap
|
46
|
+
def without(key); end
|
47
|
+
end
|
48
|
+
|
49
|
+
module IMeta
|
50
|
+
def meta; end
|
51
|
+
end
|
52
|
+
|
53
|
+
module IObj
|
54
|
+
# returns IObj
|
55
|
+
def with_meta(meta); end
|
56
|
+
end
|
57
|
+
|
58
|
+
module ISeq
|
59
|
+
def first; end
|
60
|
+
def next; end
|
61
|
+
def more; end
|
62
|
+
def cons(obj); end
|
63
|
+
end
|
64
|
+
|
65
|
+
module IFn
|
66
|
+
def invoke(*args); end
|
67
|
+
end
|
68
|
+
|
69
|
+
module IReduce
|
70
|
+
def reduce(fn, start=nil); end
|
71
|
+
end
|
72
|
+
|
73
|
+
# module IEditableCollection
|
74
|
+
# def as_transient; end
|
75
|
+
# end
|
76
|
+
|
77
|
+
# module ITransientCollection
|
78
|
+
# def conj(obj); end
|
79
|
+
# def persistent; end
|
80
|
+
# end
|
data/lib/hammock/iseq.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'atomic'
|
2
|
+
require 'hammock/meta'
|
3
|
+
require 'hammock/list'
|
4
|
+
|
5
|
+
module Hammock
|
6
|
+
class LazySequence
|
7
|
+
include List
|
8
|
+
include Meta
|
9
|
+
|
10
|
+
attr_reader :s
|
11
|
+
|
12
|
+
def self.alloc_from(ls, meta=nil)
|
13
|
+
new(meta, ls.fn, ls.s)
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(meta=nil, fn=nil, s=nil)
|
17
|
+
@meta = meta
|
18
|
+
@fn = Atomic.new(fn)
|
19
|
+
@s = s
|
20
|
+
@target = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def seq
|
24
|
+
list = sval
|
25
|
+
while list.is_a?(LazySequence)
|
26
|
+
list = list.sval
|
27
|
+
end
|
28
|
+
@s = RT.seq(list)
|
29
|
+
end
|
30
|
+
|
31
|
+
def empty?
|
32
|
+
seq.nil?
|
33
|
+
end
|
34
|
+
|
35
|
+
def head
|
36
|
+
seq
|
37
|
+
return nil if @s.nil?
|
38
|
+
@s.head
|
39
|
+
end
|
40
|
+
|
41
|
+
def tail
|
42
|
+
seq
|
43
|
+
return nil if @s.nil?
|
44
|
+
@s.tail
|
45
|
+
end
|
46
|
+
|
47
|
+
def rest
|
48
|
+
seq
|
49
|
+
return EmptyList.new if @s.nil?
|
50
|
+
@s.rest
|
51
|
+
end
|
52
|
+
|
53
|
+
def each
|
54
|
+
return self unless block_given?
|
55
|
+
list = self
|
56
|
+
while !list.empty?
|
57
|
+
yield(list.head)
|
58
|
+
list = list.rest
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def inspect
|
63
|
+
seq.inspect
|
64
|
+
end
|
65
|
+
|
66
|
+
def fn
|
67
|
+
@fn.value
|
68
|
+
end
|
69
|
+
|
70
|
+
protected
|
71
|
+
|
72
|
+
def sval
|
73
|
+
unless fn.nil?
|
74
|
+
@fn.update do |v|
|
75
|
+
@target = v.call
|
76
|
+
nil
|
77
|
+
end
|
78
|
+
end
|
79
|
+
@target.nil? ? @s : @target
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|