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,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
|