rouge-lang 0.0.1
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.
- data/.autotest +11 -0
- data/.gitignore +20 -0
- data/.rspec +1 -0
- data/.travis.yml +3 -0
- data/Gemfile +6 -0
- data/LICENSE +19 -0
- data/README.md +119 -0
- data/Rakefile +8 -0
- data/bin/rouge +2 -0
- data/lib/boot.rg +402 -0
- data/lib/rouge.rb +56 -0
- data/lib/rouge/atom.rb +25 -0
- data/lib/rouge/builtins.rb +596 -0
- data/lib/rouge/compiler.rb +108 -0
- data/lib/rouge/context.rb +235 -0
- data/lib/rouge/metadata.rb +19 -0
- data/lib/rouge/namespace.rb +125 -0
- data/lib/rouge/printer.rb +78 -0
- data/lib/rouge/reader.rb +433 -0
- data/lib/rouge/repl.rb +82 -0
- data/lib/rouge/seq.rb +221 -0
- data/lib/rouge/symbol.rb +77 -0
- data/lib/rouge/var.rb +69 -0
- data/lib/rouge/version.rb +7 -0
- data/lib/rouge/wrappers.rb +27 -0
- data/misc/TODO +45 -0
- data/misc/vimrc +1 -0
- data/rouge-lang.gemspec +28 -0
- data/spec/atom_spec.rb +39 -0
- data/spec/builtins_spec.rb +708 -0
- data/spec/compiler_spec.rb +137 -0
- data/spec/context_spec.rb +293 -0
- data/spec/core_spec.rg +123 -0
- data/spec/metadata_spec.rb +59 -0
- data/spec/namespace_spec.rb +125 -0
- data/spec/printer_spec.rb +191 -0
- data/spec/reader_spec.rb +422 -0
- data/spec/rouge_spec.rb +66 -0
- data/spec/seq_spec.rb +202 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/symbol_spec.rb +35 -0
- data/spec/var_spec.rb +61 -0
- data/spec/wrappers_spec.rb +51 -0
- metadata +216 -0
@@ -0,0 +1,137 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'rouge'
|
4
|
+
|
5
|
+
describe Rouge::Compiler do
|
6
|
+
before do
|
7
|
+
@ns = Rouge[:"user.spec"].clear
|
8
|
+
@ns.refer Rouge[:"rouge.builtin"]
|
9
|
+
|
10
|
+
@read = lambda do |input|
|
11
|
+
Rouge::Reader.new(@ns, input).lex
|
12
|
+
end
|
13
|
+
|
14
|
+
@compile = lambda do |input|
|
15
|
+
form = @read.call(input)
|
16
|
+
Rouge::Compiler.compile(@ns, Set.new, form)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "lexical lookup" do
|
21
|
+
it "should compile with respect to locals" do
|
22
|
+
lambda {
|
23
|
+
@compile.call("(fn [] a)")
|
24
|
+
}.should raise_exception(Rouge::Namespace::VarNotFoundError)
|
25
|
+
|
26
|
+
lambda {
|
27
|
+
@compile.call("q")
|
28
|
+
}.should raise_exception(Rouge::Namespace::VarNotFoundError)
|
29
|
+
|
30
|
+
lambda {
|
31
|
+
@compile.call("(let [x 8] x)").
|
32
|
+
should eq @read.call("(let [x 8] x)")
|
33
|
+
}.should_not raise_exception
|
34
|
+
|
35
|
+
lambda {
|
36
|
+
@compile.call("(let [x 8] y)")
|
37
|
+
}.should raise_exception(Rouge::Namespace::VarNotFoundError)
|
38
|
+
|
39
|
+
lambda {
|
40
|
+
@compile.call("(let [x 8] ((fn [& b] (b)) | [e] e))")
|
41
|
+
}.should_not raise_exception
|
42
|
+
|
43
|
+
lambda {
|
44
|
+
@compile.call("(let [x 8] ((fn [& b] (b)) | [e] f))")
|
45
|
+
}.should raise_exception(Rouge::Namespace::VarNotFoundError)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "macro behaviour" do
|
50
|
+
it "should execute macro calls when compiling" do
|
51
|
+
@ns.set_here :thingy, Rouge::Macro[lambda {|f|
|
52
|
+
Rouge::Seq::Cons[Rouge::Symbol[:list], *f.to_a]
|
53
|
+
}]
|
54
|
+
@compile.call("(let [list 'thing] (thingy (1 2 3)))").
|
55
|
+
should eq @read.call("(let [list 'thing] (list 1 2 3))")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "symbol lookup" do
|
60
|
+
it "should compile X. symbols to procs which call X.new" do
|
61
|
+
x = double("<class>")
|
62
|
+
x.stub(:new => nil)
|
63
|
+
|
64
|
+
@ns.set_here :x, x
|
65
|
+
x_new = @compile.call("x.")
|
66
|
+
x_new.should be_an_instance_of Rouge::Compiler::Resolved
|
67
|
+
|
68
|
+
x.should_receive(:new).with(1, :z)
|
69
|
+
x_new.res.call(1, :z)
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should find the var in our namespace for an unqualified symbol" do
|
73
|
+
@ns.set_here :tiffany, "wha?"
|
74
|
+
@compile.call("tiffany").res.
|
75
|
+
should eq Rouge::Var.new(:"user.spec", :tiffany, "wha?")
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should find the var in a referred ns for an unqualified symbol" do
|
79
|
+
v = @compile.call("def").res
|
80
|
+
v.should be_an_instance_of(Rouge::Var)
|
81
|
+
v.ns.should eq :"rouge.builtin"
|
82
|
+
v.name.should eq :def
|
83
|
+
v.deref.should be_an_instance_of(Rouge::Builtin)
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should find the var in any namespace for a qualified symbol" do
|
87
|
+
v = @compile.call("ruby/Kernel").res
|
88
|
+
v.should be_an_instance_of(Rouge::Var)
|
89
|
+
v.ns.should eq :ruby
|
90
|
+
v.name.should eq :Kernel
|
91
|
+
v.deref.should eq Kernel
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should find the method for a new class instantiation" do
|
95
|
+
m = @compile.call("ruby/String.").res
|
96
|
+
m.should be_an_instance_of Method
|
97
|
+
m.receiver.should eq String
|
98
|
+
m.name.should eq :new
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "sub-compilation behaviour" do
|
103
|
+
it "should compile Arrays and Hashes" do
|
104
|
+
lambda {
|
105
|
+
@compile.call("[a]")
|
106
|
+
}.should raise_exception(Rouge::Namespace::VarNotFoundError)
|
107
|
+
|
108
|
+
@ns.set_here :a, :a
|
109
|
+
lambda {
|
110
|
+
@compile.call("[a]")
|
111
|
+
}.should_not raise_exception
|
112
|
+
|
113
|
+
lambda {
|
114
|
+
@compile.call("{b c}")
|
115
|
+
}.should raise_exception(Rouge::Namespace::VarNotFoundError)
|
116
|
+
|
117
|
+
@ns.set_here :b, :b
|
118
|
+
lambda {
|
119
|
+
@compile.call("{b c}")
|
120
|
+
}.should raise_exception(Rouge::Namespace::VarNotFoundError)
|
121
|
+
|
122
|
+
@ns.set_here :c, :c
|
123
|
+
lambda {
|
124
|
+
@compile.call("{b c}")
|
125
|
+
}.should_not raise_exception
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should compile inline blocks to fns" do
|
129
|
+
@compile.call("(let [a 'thing] (a | [b] b))").
|
130
|
+
should eq @read.call("(let [a 'thing] (a | (fn [b] b)))")
|
131
|
+
end
|
132
|
+
|
133
|
+
it { @compile.call("()").should eq Rouge::Seq::Empty }
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# vim: set sw=2 et cc=80:
|
@@ -0,0 +1,293 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'rouge'
|
4
|
+
|
5
|
+
describe Rouge::Context do
|
6
|
+
before do
|
7
|
+
@a = Rouge::Context.new nil
|
8
|
+
@ab = Rouge::Context.new @a
|
9
|
+
@abb = Rouge::Context.new @ab
|
10
|
+
@ac = Rouge::Context.new @a
|
11
|
+
@a.set_here :root, 42
|
12
|
+
@a.set_here :bah, (@bah = Object.new)
|
13
|
+
@ab.set_here :root, 80
|
14
|
+
@ac.set_here :non, 50
|
15
|
+
|
16
|
+
@spec = Rouge::Namespace[:"user.spec"].clear
|
17
|
+
@spec.refer Rouge::Namespace[:"rouge.builtin"]
|
18
|
+
@spec.set_here :tiffany, "wha?"
|
19
|
+
@in_spec = Rouge::Context.new @spec
|
20
|
+
@in_spec.set_here :blah, "code code"
|
21
|
+
|
22
|
+
@ns = Rouge[:"rouge.builtin"]
|
23
|
+
@context = Rouge::Context.new @ns
|
24
|
+
@nested_context = Rouge::Context.new @context
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "the [] method" do
|
28
|
+
it "should get the closest binding" do
|
29
|
+
@a[:root].should eq 42
|
30
|
+
@ab[:root].should eq 80
|
31
|
+
@abb[:root].should eq 80
|
32
|
+
@ac[:root].should eq 42
|
33
|
+
# var, because it's from a namespace
|
34
|
+
@context[:let].deref.should be_an_instance_of Rouge::Builtin
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should raise an exception if a binding is not found" do
|
38
|
+
lambda {
|
39
|
+
@a[:non]
|
40
|
+
}.should raise_exception(Rouge::Context::BindingNotFoundError)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "the ns method" do
|
45
|
+
it "should get the namespace of a context that has one" do
|
46
|
+
@context.ns.should eq Rouge::Namespace[:"rouge.builtin"]
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should get the namespace of a nested context that has one" do
|
50
|
+
@nested_context.ns.should eq Rouge::Namespace[:"rouge.builtin"]
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should return nil if a context has none" do
|
54
|
+
@a.ns.should eq nil
|
55
|
+
@ab.ns.should eq nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "the set_here method" do
|
60
|
+
it "should set in the given context, shadowing outer bindings" do
|
61
|
+
@ac.set_here :root, 90
|
62
|
+
@ac[:root].should eq 90
|
63
|
+
@a[:root].should eq 42
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "the set_lexical method" do
|
68
|
+
it "should set in the closest context" do
|
69
|
+
@abb.set_lexical :root, 777
|
70
|
+
@abb[:root].should eq 777
|
71
|
+
@ab[:root].should eq 777
|
72
|
+
@a[:root].should eq 42
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should raise an exception if a closest binding is not found" do
|
76
|
+
lambda {
|
77
|
+
@abb.set_lexical :non, 10
|
78
|
+
}.should raise_exception(Rouge::Context::BindingNotFoundError)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "the eval method" do
|
83
|
+
it "should eval a form in this context without processing the backtrace" do
|
84
|
+
@a.eval([5]).should eq [5]
|
85
|
+
|
86
|
+
begin
|
87
|
+
@a.eval(Rouge::Seq::Cons[Rouge::Symbol[:blorgh]])
|
88
|
+
raise "failed!"
|
89
|
+
rescue Rouge::Context::BindingNotFoundError => e
|
90
|
+
e.backtrace.any? {|line| line =~ /^\(rouge\):/}.should be_false
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "the readeval method" do
|
96
|
+
it "should post-process the backtrace", :pending do
|
97
|
+
Rouge.boot!
|
98
|
+
context = Rouge::Context.new Rouge[:user]
|
99
|
+
|
100
|
+
ex = nil
|
101
|
+
begin
|
102
|
+
context.readeval(<<-ROUGE)
|
103
|
+
(do
|
104
|
+
(defn z [] (throw (RuntimeError. "boo")))
|
105
|
+
(defn y [] (z))
|
106
|
+
(defn x [] (y))
|
107
|
+
(x))
|
108
|
+
ROUGE
|
109
|
+
rescue RuntimeError => e
|
110
|
+
ex = e
|
111
|
+
end
|
112
|
+
|
113
|
+
ex.should_not be_nil
|
114
|
+
ex.backtrace[0..3].
|
115
|
+
should eq ["(rouge):?:rouge.builtin/throw",
|
116
|
+
"(rouge):?:user/z",
|
117
|
+
"(rouge):?:user/y",
|
118
|
+
"(rouge):?:user/x"]
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should compile with lexicals from the found context" do
|
122
|
+
context = Rouge::Context.new nil
|
123
|
+
context.set_here :quux, 4
|
124
|
+
context.set_here :bar, 5
|
125
|
+
|
126
|
+
Rouge::Compiler.should_receive(:compile).
|
127
|
+
with(context.ns, kind_of(Set), true) do |ns, lexicals, f|
|
128
|
+
lexicals.should eq Set[:quux, :bar]
|
129
|
+
end
|
130
|
+
|
131
|
+
context.readeval("true")
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe "the locate method" do
|
136
|
+
it "should find the method for a new call to a lexical" do
|
137
|
+
arg = double("<arg>")
|
138
|
+
m = @a.locate(Rouge::Symbol[:"bah."])
|
139
|
+
m.should be_an_instance_of Proc
|
140
|
+
@bah.should_receive(:new).with(arg)
|
141
|
+
m.call(arg)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should evaluate quotations to their unquoted form" do
|
146
|
+
@context.readeval("'x").should eq @ns.read("x")
|
147
|
+
@context.readeval("'':zzy").should eq @ns.read("':zzy")
|
148
|
+
end
|
149
|
+
|
150
|
+
describe "symbols" do
|
151
|
+
it "should evaluate symbols to the object within their context" do
|
152
|
+
@context.set_here :vitamin_b, "vegemite"
|
153
|
+
@context.readeval("vitamin_b").should eq "vegemite"
|
154
|
+
|
155
|
+
subcontext = Rouge::Context.new @context
|
156
|
+
subcontext.set_here :joy, [:yes]
|
157
|
+
subcontext.set_here :/, "wah"
|
158
|
+
subcontext.readeval("joy").should eq [:yes]
|
159
|
+
subcontext.readeval("vitamin_b").should eq "vegemite"
|
160
|
+
subcontext.readeval("/").should eq "wah"
|
161
|
+
end
|
162
|
+
|
163
|
+
it "should evaluate symbols in other namespaces" do
|
164
|
+
@context.readeval("ruby/Object").should eq Object
|
165
|
+
@context.readeval("ruby/Exception").should eq Exception
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should evaluate nested objects" do
|
169
|
+
@context.readeval("ruby/Rouge.Context").should eq Rouge::Context
|
170
|
+
@context.readeval("ruby/Errno.EAGAIN").should eq Errno::EAGAIN
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
it "should evaluate other things to themselves" do
|
175
|
+
@context.eval(4).should eq 4
|
176
|
+
@context.eval("bleep bloop").should eq "bleep bloop"
|
177
|
+
@context.eval(:"nom it").should eq :"nom it"
|
178
|
+
@context.readeval("{:a :b, 1 2}").to_s.should eq({:a => :b, 1 => 2}.to_s)
|
179
|
+
|
180
|
+
l = lambda {}
|
181
|
+
@context.eval(l).should eq l
|
182
|
+
|
183
|
+
o = Object.new
|
184
|
+
@context.eval(o).should eq o
|
185
|
+
end
|
186
|
+
|
187
|
+
it "should evaluate hash and vector arguments" do
|
188
|
+
@context.readeval("{\"z\" 92, 'x ''5}").to_s.
|
189
|
+
should eq @ns.read("{\"z\" 92, x '5}").to_s
|
190
|
+
|
191
|
+
subcontext = Rouge::Context.new @context
|
192
|
+
subcontext.set_here :lolwut, "off"
|
193
|
+
subcontext.readeval("{lolwut [lolwut]}").
|
194
|
+
should eq @ns.read('{"off" ["off"]}')
|
195
|
+
end
|
196
|
+
|
197
|
+
describe "function calls" do
|
198
|
+
it "should evaluate function calls" do
|
199
|
+
subcontext = Rouge::Context.new @context
|
200
|
+
subcontext.set_here :f, lambda {|x| "hello #{x}"}
|
201
|
+
subcontext.readeval('(f "world")').should eq "hello world"
|
202
|
+
end
|
203
|
+
|
204
|
+
it "should evaluate macro calls" do
|
205
|
+
macro = Rouge::Macro[lambda {|n, *body|
|
206
|
+
Rouge::Seq::Cons[Rouge::Symbol[:let], Rouge::Seq::Cons[n, "example"].freeze,
|
207
|
+
*body]
|
208
|
+
}]
|
209
|
+
|
210
|
+
@ns.set_here :macro, macro
|
211
|
+
|
212
|
+
subcontext = Rouge::Context.new @context
|
213
|
+
subcontext.set_here :f, lambda {|x,y| x + y}
|
214
|
+
subcontext.readeval('(macro bar (f bar bar))').should eq "exampleexample"
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should evaluate calls with inline blocks and block binds" do
|
218
|
+
@context.readeval('((fn [a | b] (b a)) 42 | [e] (./ e 2))').should eq 21
|
219
|
+
end
|
220
|
+
|
221
|
+
describe "Ruby interop" do
|
222
|
+
describe "new object creation" do
|
223
|
+
it "should call X.new with (X.)" do
|
224
|
+
klass = double("klass")
|
225
|
+
klass.should_receive(:new).with(@ns.read('a')).and_return(:b)
|
226
|
+
|
227
|
+
subcontext = Rouge::Context.new @context
|
228
|
+
subcontext.set_here :klass, klass
|
229
|
+
subcontext.readeval("(klass. 'a)").should eq :b
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
describe "generic method calls" do
|
234
|
+
it "should call x.y(:z) with (.y x 'z)" do
|
235
|
+
x = double("x")
|
236
|
+
x.should_receive(:y).with(@ns.read('z')).and_return(:tada)
|
237
|
+
|
238
|
+
subcontext = Rouge::Context.new @context
|
239
|
+
subcontext.set_here :x, x
|
240
|
+
subcontext.readeval("(.y x 'z)").should eq :tada
|
241
|
+
end
|
242
|
+
|
243
|
+
it "should call q.r(:s, &t) with (.r q 's | t)" do
|
244
|
+
q = double("q")
|
245
|
+
t = lambda {}
|
246
|
+
q.should_receive(:r).with(@ns.read('s'), &t).and_return(:bop)
|
247
|
+
|
248
|
+
subcontext = Rouge::Context.new @context
|
249
|
+
subcontext.set_here :q, q
|
250
|
+
subcontext.set_here :t, t
|
251
|
+
subcontext.readeval("(.r q 's | t)").should eq :bop
|
252
|
+
end
|
253
|
+
|
254
|
+
it "should call a.b(:c) {|d| d + 1} with (.b a 'c | [d] (.+ d 1))" do
|
255
|
+
a = double("a")
|
256
|
+
a.should_receive(:b) do |c, &b|
|
257
|
+
c.should eq @ns.read('c')
|
258
|
+
b.call(1).should eq 2
|
259
|
+
b.call(2).should eq 3
|
260
|
+
b.call(3).should eq 4
|
261
|
+
:ok
|
262
|
+
end
|
263
|
+
|
264
|
+
subcontext = Rouge::Context.new @context
|
265
|
+
subcontext.set_here :a, a
|
266
|
+
subcontext.readeval("(.b a 'c | [d] (.+ d 1))").should eq :ok
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
describe "keywords in call position" do
|
272
|
+
it { @context.readeval('(:nope {:yep true})').should be_nil }
|
273
|
+
it { @context.readeval('(:test "fail")').should be_nil }
|
274
|
+
it { @context.readeval('(:pale {:pale "ale"})').should eq "ale" }
|
275
|
+
it { @context.readeval('(:red {:white "moscato"} "merlot")').
|
276
|
+
should eq "merlot" }
|
277
|
+
|
278
|
+
it { expect { @context.readeval('(:will "raise" "an" "error")')
|
279
|
+
}.to raise_error(ArgumentError) }
|
280
|
+
end
|
281
|
+
|
282
|
+
describe "hashes in call position" do
|
283
|
+
it { @context.readeval('({:wham "bam"} :boom)').should be_nil }
|
284
|
+
it { @context.readeval('({:slam "dunk"} :slam)').should eq "dunk" }
|
285
|
+
it { @context.readeval('({:immortal false} :mortal true)').
|
286
|
+
should be_true }
|
287
|
+
it { expect { @context.readeval('({:this "will"} :raise "an" "error")')
|
288
|
+
}.to raise_error(ArgumentError) }
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
# vim: set sw=2 et cc=80:
|
data/spec/core_spec.rg
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
;; -*- mode: clojure; -*-
|
2
|
+
|
3
|
+
(ns ^{:doc "Spec tests for the Rouge core."
|
4
|
+
:author "Arlen Christian Mart Cuss"}
|
5
|
+
spec.rouge.core
|
6
|
+
(:use rouge.test))
|
7
|
+
|
8
|
+
(testing "list"
|
9
|
+
(testing "empty list creation"
|
10
|
+
(is (= (list) '())))
|
11
|
+
(testing "unary list creation"
|
12
|
+
(is (= (list "trent") '("trent")))
|
13
|
+
(is (= (list true) '(true))))
|
14
|
+
(testing "n-ary list creation"
|
15
|
+
(is (= (apply list (range 1 6)) (.to_a (ruby/Range. 1 5))))))
|
16
|
+
|
17
|
+
(testing "or"
|
18
|
+
(is (let [q (atom 0)]
|
19
|
+
(or 1 (swap! q inc))
|
20
|
+
(= @q 0))))
|
21
|
+
|
22
|
+
(testing "and"
|
23
|
+
(is (let [q (atom 0)]
|
24
|
+
(and nil (swap! q inc))
|
25
|
+
(= @q 0))))
|
26
|
+
|
27
|
+
(testing "sequential"
|
28
|
+
(is (sequential? []))
|
29
|
+
(is (sequential? [1]))
|
30
|
+
(is (sequential? ()))
|
31
|
+
(is (sequential? '(1)))
|
32
|
+
(is (not (sequential? nil))))
|
33
|
+
|
34
|
+
(testing "="
|
35
|
+
(is (.== false (= () nil))))
|
36
|
+
|
37
|
+
(testing "seq"
|
38
|
+
(is (.nil? (seq ())))
|
39
|
+
(is (.nil? (seq nil)))
|
40
|
+
(is (.nil? (seq []))))
|
41
|
+
|
42
|
+
(testing "first"
|
43
|
+
(is (.nil? (first nil)))
|
44
|
+
(is (.nil? (first ()))))
|
45
|
+
|
46
|
+
(testing "rest"
|
47
|
+
(is (.== (rest nil) ()))
|
48
|
+
(is (.== (rest ()) ())))
|
49
|
+
|
50
|
+
(testing "next"
|
51
|
+
(is (.nil? (next nil)))
|
52
|
+
(is (.nil? (next ()))))
|
53
|
+
|
54
|
+
(testing "nth"
|
55
|
+
(is (= 1 (nth [1 2 3] 0)))
|
56
|
+
(is (= 2 (nth [1 2 3] 1)))
|
57
|
+
(is (= 3 (nth [1 2 3] 2))))
|
58
|
+
|
59
|
+
(defmacro sample-1 [f] `(do ~f))
|
60
|
+
(defmacro sample-2 [f] `(do ~@f ~@f))
|
61
|
+
|
62
|
+
(testing "macroexpand"
|
63
|
+
(is (= '(do x) (macroexpand '(sample-1 x))))
|
64
|
+
(is (= '(do x y x y) (macroexpand '(sample-2 (x y))))))
|
65
|
+
|
66
|
+
#_(testing "var passing"
|
67
|
+
(is (= #'my-var (do
|
68
|
+
(def my-var 4)
|
69
|
+
(let [take-var (fn [v] v)]
|
70
|
+
(take-var #'my-var))))))
|
71
|
+
|
72
|
+
#_(testing "for")
|
73
|
+
|
74
|
+
(testing "the -> macro"
|
75
|
+
(is (= 3 (macroexpand '(-> 3))))
|
76
|
+
(is (= '(:x 3) (macroexpand '(-> 3 :x))))
|
77
|
+
(is (= '(:y 3 2) (macroexpand '(-> 3 (:y 2)))))
|
78
|
+
(is (= '(:z (:y 3 2)) (macroexpand '(-> 3 (:y 2) :z))))
|
79
|
+
(is (= '(:z (:y 3 2) 8 9) (macroexpand '(-> 3 (:y 2) (:z 8 9)))))
|
80
|
+
|
81
|
+
(pending
|
82
|
+
; this fails -- it compiles the inc ref.
|
83
|
+
(is (= '(inc 3) (macroexpand '(-> 3 inc))))
|
84
|
+
; this fails too -- something weird.
|
85
|
+
(is (= '('inc 3) (macroexpand '(-> 3 'inc))))))
|
86
|
+
|
87
|
+
(testing "map"
|
88
|
+
(is (= Rouge.Seq.Lazy (class (map inc [1 2 3]))))
|
89
|
+
(is (= '(2 3 4) (map inc [1 2 3])))
|
90
|
+
(is (= 1
|
91
|
+
(let [q (atom 0)
|
92
|
+
lazy (map #(do (swap! q inc) (inc %)) [1 2 3])]
|
93
|
+
(first lazy)
|
94
|
+
@q)))
|
95
|
+
(is (= 1
|
96
|
+
(let [q (atom 0)
|
97
|
+
lazy (map #(do (swap! q inc) (inc %)) [1 2 3])]
|
98
|
+
(first lazy)
|
99
|
+
(first lazy)
|
100
|
+
@q)))
|
101
|
+
(is (= 2
|
102
|
+
(let [q (atom 0)
|
103
|
+
lazy (map #(do (swap! q inc) (inc %)) [1 2 3])]
|
104
|
+
(first (next lazy))
|
105
|
+
@q)))
|
106
|
+
(is (= 3
|
107
|
+
(let [q (atom 0)
|
108
|
+
lazy (map #(do (swap! q inc) (inc %)) [1 2 3])]
|
109
|
+
(first (next (next lazy)))
|
110
|
+
@q)))
|
111
|
+
(is (= 3
|
112
|
+
(let [q (atom 0)
|
113
|
+
lazy (map #(do (swap! q inc) (inc %)) [1 2 3])]
|
114
|
+
(first (next (next (next lazy))))
|
115
|
+
@q)))
|
116
|
+
|
117
|
+
(testing "in destructuring"
|
118
|
+
(is (= 2
|
119
|
+
(let [q (atom 0)
|
120
|
+
[hd & tl] (map #(do (swap! q inc) (inc %)) [1 2 3])]
|
121
|
+
@q)))))
|
122
|
+
|
123
|
+
; vim: set ft=clojure:
|