rouge-lang 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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,59 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'rouge'
|
4
|
+
|
5
|
+
describe Rouge::Metadata do
|
6
|
+
before do
|
7
|
+
@class = Class.new do
|
8
|
+
include Rouge::Metadata
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "the metadata accessors" do
|
13
|
+
it "should be present on class instances" do
|
14
|
+
@class.new.should respond_to(:meta).with(0).arguments
|
15
|
+
@class.new.should respond_to(:meta=).with(1).argument
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should default to nil" do
|
19
|
+
@class.new.meta.should be_nil
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should return the new value when set" do
|
23
|
+
i = @class.new
|
24
|
+
i.meta = {:x => 4}
|
25
|
+
i.meta.to_s.should eq({:x => 4}.to_s)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should not allow being set to anything other than a Hash or nil" do
|
29
|
+
lambda {
|
30
|
+
@class.new.meta = {:a => 1}
|
31
|
+
@class.new.meta = {}
|
32
|
+
@class.new.meta = {1 => 2, 3 => 4, 5 => {}}
|
33
|
+
@class.new.meta = nil
|
34
|
+
}.should_not raise_exception
|
35
|
+
|
36
|
+
lambda {
|
37
|
+
@class.new.meta = 4
|
38
|
+
}.should raise_exception(Rouge::Metadata::InvalidMetadataError)
|
39
|
+
|
40
|
+
lambda {
|
41
|
+
@class.new.meta = true
|
42
|
+
}.should raise_exception(Rouge::Metadata::InvalidMetadataError)
|
43
|
+
|
44
|
+
lambda {
|
45
|
+
@class.new.meta = Rouge::Symbol[:blah]
|
46
|
+
}.should raise_exception(Rouge::Metadata::InvalidMetadataError)
|
47
|
+
|
48
|
+
lambda {
|
49
|
+
@class.new.meta = []
|
50
|
+
}.should raise_exception(Rouge::Metadata::InvalidMetadataError)
|
51
|
+
|
52
|
+
lambda {
|
53
|
+
@class.new.meta = Rouge::Seq::Cons["what"]
|
54
|
+
}.should raise_exception(Rouge::Metadata::InvalidMetadataError)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# vim: set sw=2 et cc=80:
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'rouge'
|
4
|
+
|
5
|
+
describe Rouge::Namespace do
|
6
|
+
describe "the [] method" do
|
7
|
+
it "should vivify non-extant namespaces" do
|
8
|
+
Rouge::Namespace.exists?(:vivify_test).should eq false
|
9
|
+
Rouge::Namespace[:vivify_test].should be_an_instance_of Rouge::Namespace
|
10
|
+
Rouge::Namespace.exists?(:vivify_test).should eq true
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "the Rouge[] shortcut" do
|
15
|
+
it "should directly call the [] method" do
|
16
|
+
Rouge::Namespace.should_receive(:[]).with(:trazzle)
|
17
|
+
Rouge[:trazzle]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "the set_here method" do
|
22
|
+
it "should create a var for the name, assigning the root to the value" do
|
23
|
+
w = Rouge::Namespace.new :w
|
24
|
+
w.set_here :waldorf, "Yes!"
|
25
|
+
w[:waldorf].should eq Rouge::Var.new(:w, :waldorf, "Yes!")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "the intern method" do
|
30
|
+
it "should create an unbound var for the name if it doesn't exist" do
|
31
|
+
m = Rouge::Namespace.new :m
|
32
|
+
m.intern :connor
|
33
|
+
m[:connor].should eq Rouge::Var.new(:m, :connor)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should do nothing if the var already exists" do
|
37
|
+
q = Rouge::Namespace.new :q
|
38
|
+
q.set_here :matthias, 50
|
39
|
+
q.intern :matthias
|
40
|
+
q[:matthias].should eq Rouge::Var.new(:q, :matthias, 50)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "the refer method" do
|
45
|
+
it "should cause items in one namespace to be locatable from the other" do
|
46
|
+
abc = Rouge::Namespace.new :abc
|
47
|
+
xyz = Rouge::Namespace.new :xyz
|
48
|
+
|
49
|
+
xyz.refer abc
|
50
|
+
|
51
|
+
abc.set_here :hello, :wow
|
52
|
+
xyz[:hello].deref.should eq :wow
|
53
|
+
end
|
54
|
+
|
55
|
+
it "may not be used to refer namespaces to themselves" do
|
56
|
+
lambda {
|
57
|
+
Rouge[:user].refer Rouge[:user]
|
58
|
+
}.should raise_exception(Rouge::Namespace::RecursiveNamespaceError)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "the destroy method" do
|
63
|
+
it "should obliterate a namespace" do
|
64
|
+
Rouge[:"user.spec2"].set_here :nope, :ok
|
65
|
+
Rouge::Namespace.destroy :"user.spec2"
|
66
|
+
lambda {
|
67
|
+
Rouge[:"user.spec2"][:nope]
|
68
|
+
}.should raise_exception(Rouge::Namespace::VarNotFoundError)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "the rouge.builtin namespace" do
|
73
|
+
before do
|
74
|
+
@ns = Rouge[:"rouge.builtin"]
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should contain elements from Rouge::Builtins" do
|
78
|
+
@ns[:let].deref.should be_an_instance_of Rouge::Builtin
|
79
|
+
@ns[:quote].deref.should be_an_instance_of Rouge::Builtin
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should not find objects from ruby" do
|
83
|
+
lambda {
|
84
|
+
@ns[:Float]
|
85
|
+
}.should raise_exception(Rouge::Namespace::VarNotFoundError)
|
86
|
+
lambda {
|
87
|
+
@ns[:String]
|
88
|
+
}.should raise_exception(Rouge::Namespace::VarNotFoundError)
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should have a name" do
|
92
|
+
@ns.name.should eq :"rouge.builtin"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "the ruby namespace" do
|
97
|
+
before do
|
98
|
+
@ns = Rouge::Namespace[:ruby]
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should contain elements from Kernel" do
|
102
|
+
@ns[:Hash].should eq Rouge::Var.new(:ruby, :Hash, Hash)
|
103
|
+
@ns[:Fixnum].should eq Rouge::Var.new(:ruby, :Fixnum, Fixnum)
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should contain global variables" do
|
107
|
+
@ns[:"$LOAD_PATH"].
|
108
|
+
should eq Rouge::Var.new(:ruby, :$LOAD_PATH, $LOAD_PATH)
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should have a name" do
|
112
|
+
@ns.name.should eq :ruby
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe "the read method" do
|
117
|
+
it "should read input in this namespace" do
|
118
|
+
Rouge::Namespace[:xyz].read("`ham").
|
119
|
+
should eq Rouge::Seq::Cons[Rouge::Symbol[:quote],
|
120
|
+
Rouge::Symbol[:"xyz/ham"]]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# vim: set sw=2 et cc=80:
|
@@ -0,0 +1,191 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'rouge'
|
4
|
+
|
5
|
+
describe Rouge::Printer do
|
6
|
+
describe ".print" do
|
7
|
+
context "numbers" do
|
8
|
+
it { Rouge.print(12755, "").should eq "12755" }
|
9
|
+
end
|
10
|
+
|
11
|
+
context "symbols" do
|
12
|
+
it { Rouge.print(Rouge::Symbol[:loki], "").should eq "loki" }
|
13
|
+
it { Rouge.print(Rouge::Symbol[:/], "").should eq "/" }
|
14
|
+
it { Rouge.print(Rouge::Symbol[:wah?], "").should eq "wah?" }
|
15
|
+
it { Rouge.print(Rouge::Symbol[:"!ruby!"], "").should eq "!ruby!" }
|
16
|
+
it { Rouge.print(Rouge::Symbol[:nil], "").should eq "nil" }
|
17
|
+
it { Rouge.print(Rouge::Symbol[:true], "").should eq "true" }
|
18
|
+
it { Rouge.print(Rouge::Symbol[:false], "").should eq "false" }
|
19
|
+
end
|
20
|
+
|
21
|
+
context "keywords" do
|
22
|
+
context "plain keywords" do
|
23
|
+
it { Rouge.print(:loki, "").should eq ":loki" }
|
24
|
+
it { Rouge.print(:/, "").should eq ":/" }
|
25
|
+
it { Rouge.print(:wah?, "").should eq ":wah?" }
|
26
|
+
it { Rouge.print(:nil, "").should eq ":nil" }
|
27
|
+
it { Rouge.print(:true, "").should eq ":true" }
|
28
|
+
it { Rouge.print(:false, "").should eq ":false" }
|
29
|
+
end
|
30
|
+
|
31
|
+
context "string-symbols" do
|
32
|
+
it { Rouge.print(:"!ruby!", "").should eq ":\"!ruby!\"" }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "strings" do
|
37
|
+
context "plain strings" do
|
38
|
+
it { Rouge.print("akashi yo", "").should eq "\"akashi yo\"" }
|
39
|
+
it { Rouge.print("akashi\nwoah!", "").should eq "\"akashi\\nwoah!\"" }
|
40
|
+
end
|
41
|
+
|
42
|
+
context "escape sequences" do
|
43
|
+
it { Rouge.print("here \" goes", "").should eq "\"here \\\" goes\"" }
|
44
|
+
it { Rouge.print("here \\ goes", "").should eq "\"here \\\\ goes\"" }
|
45
|
+
it { Rouge.print("\a\b\e\f\n", "").should eq "\"\\a\\b\\e\\f\\n\"" }
|
46
|
+
it { Rouge.print("\r\t\v", "").should eq "\"\\r\\t\\v\"" }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "lists" do
|
51
|
+
context "empty list" do
|
52
|
+
it { Rouge.print(Rouge::Seq::Cons[], "").should eq "()" }
|
53
|
+
end
|
54
|
+
|
55
|
+
context "one-element lists" do
|
56
|
+
it { Rouge.print(Rouge::Seq::Cons[Rouge::Symbol[:tiffany]], "").
|
57
|
+
should eq "(tiffany)" }
|
58
|
+
it { Rouge.print(Rouge::Seq::Cons[:raaaaash], "").
|
59
|
+
should eq "(:raaaaash)" }
|
60
|
+
end
|
61
|
+
|
62
|
+
context "multiple-element lists" do
|
63
|
+
it { Rouge.print(Rouge::Seq::Cons[1, 2, 3], "").should eq "(1 2 3)" }
|
64
|
+
it { Rouge.print(Rouge::Seq::Cons[Rouge::Symbol[:true],
|
65
|
+
Rouge::Seq::Cons[], [], "no"], "").
|
66
|
+
should eq "(true () [] \"no\")" }
|
67
|
+
end
|
68
|
+
|
69
|
+
context "nested lists" do
|
70
|
+
it { Rouge.print(
|
71
|
+
Rouge::Seq::Cons[
|
72
|
+
Rouge::Seq::Cons[Rouge::Seq::Cons[3],
|
73
|
+
Rouge::Seq::Cons[Rouge::Seq::Cons[]]],
|
74
|
+
9,
|
75
|
+
Rouge::Seq::Cons[Rouge::Seq::Cons[8],
|
76
|
+
Rouge::Seq::Cons[8]]],
|
77
|
+
"").
|
78
|
+
should eq "(((3) (())) 9 ((8) (8)))" }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context "vectors" do
|
83
|
+
context "the empty vector" do
|
84
|
+
it { Rouge.print([], "").should eq "[]" }
|
85
|
+
end
|
86
|
+
|
87
|
+
context "one-element vectors" do
|
88
|
+
it { Rouge.print([Rouge::Symbol[:tiffany]], "").should eq "[tiffany]" }
|
89
|
+
it { Rouge.print([:raaaaash], "").should eq "[:raaaaash]" }
|
90
|
+
end
|
91
|
+
|
92
|
+
context "multiple-element vectors" do
|
93
|
+
it { Rouge.print([1, 2, 3], "").should eq "[1 2 3]" }
|
94
|
+
it { Rouge.print([Rouge::Symbol[:true], Rouge::Seq::Cons[], [], "no"], "").
|
95
|
+
should eq "[true () [] \"no\"]" }
|
96
|
+
end
|
97
|
+
|
98
|
+
context "nested vectors" do
|
99
|
+
it { Rouge.print([[[3], [[]]], 9, [[8], [8]]], "").
|
100
|
+
should eq "[[[3] [[]]] 9 [[8] [8]]]" }
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context "quotations" do
|
105
|
+
it { Rouge.print(
|
106
|
+
Rouge::Seq::Cons[Rouge::Symbol[:quote], Rouge::Symbol[:x]],
|
107
|
+
"").
|
108
|
+
should eq "'x" }
|
109
|
+
it { Rouge.print(Rouge::Seq::Cons[Rouge::Symbol[:quote],
|
110
|
+
Rouge::Seq::Cons[Rouge::Symbol[:quote],
|
111
|
+
Rouge::Seq::Cons[Rouge::Seq::Cons[Rouge::Symbol[:quote],
|
112
|
+
Rouge::Symbol[:x]]]]], "").
|
113
|
+
should eq "''('x)" }
|
114
|
+
end
|
115
|
+
|
116
|
+
context "vars" do
|
117
|
+
it { Rouge.print(Rouge::Seq::Cons[Rouge::Symbol[:var],
|
118
|
+
Rouge::Symbol[:"x/y"]], "").
|
119
|
+
should eq "#'x/y" }
|
120
|
+
|
121
|
+
it { Rouge.print(Rouge::Seq::Cons[Rouge::Symbol[:var],
|
122
|
+
Rouge::Seq::Cons[Rouge::Symbol[:var],
|
123
|
+
Rouge::Seq::Cons[Rouge::Seq::Cons[Rouge::Symbol[:var],
|
124
|
+
Rouge::Symbol[:"x/y"]]]]], "").
|
125
|
+
should eq "#'#'(#'x/y)" }
|
126
|
+
|
127
|
+
it { Rouge.print(Rouge::Var.new(:x, :y), "").should eq "#'x/y" }
|
128
|
+
end
|
129
|
+
|
130
|
+
context "maps" do
|
131
|
+
context "the empty map" do
|
132
|
+
it { Rouge.print({}, "").should eq "{}" }
|
133
|
+
end
|
134
|
+
|
135
|
+
context "one-element maps" do
|
136
|
+
it { Rouge.print({Rouge::Symbol[:a] => 1}, "").should eq "{a 1}" }
|
137
|
+
it { Rouge.print({"quux" => [Rouge::Symbol[:lambast]]}, "").
|
138
|
+
should eq "{\"quux\" [lambast]}" }
|
139
|
+
end
|
140
|
+
|
141
|
+
context "multiple-element maps" do
|
142
|
+
# XXX(arlen): these tests rely on stable-ish Hash order
|
143
|
+
it { Rouge.print({:a => 1, :b => 2}, "").should eq "{:a 1, :b 2}" }
|
144
|
+
it { Rouge.print({:f => :f, :y => :y, :z => :z}, "").
|
145
|
+
should eq "{:f :f, :y :y, :z :z}" }
|
146
|
+
end
|
147
|
+
|
148
|
+
context "nested maps" do
|
149
|
+
# XXX(arlen): this test relies on stable-ish Hash order
|
150
|
+
it { Rouge.print({:a => {:z => 9},
|
151
|
+
:b => {:q => Rouge::Symbol[:q]}}, "").
|
152
|
+
should eq "{:a {:z 9}, :b {:q q}}" }
|
153
|
+
it { Rouge.print({{9 => 7} => 5}, "").should eq "{{9 7} 5}" }
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
context "fundamental objects" do
|
158
|
+
it { Rouge.print(nil, "").should eq "nil" }
|
159
|
+
it { Rouge.print(true, "").should eq "true" }
|
160
|
+
it { Rouge.print(false, "").should eq "false" }
|
161
|
+
end
|
162
|
+
|
163
|
+
context "Ruby classes" do
|
164
|
+
it { Rouge.print(Object, "").should eq "ruby/Object" }
|
165
|
+
it { Rouge.print(Class, "").should eq "ruby/Class" }
|
166
|
+
it { Rouge.print(Rouge::Context, "").should eq "ruby/Rouge.Context" }
|
167
|
+
|
168
|
+
let(:anon) { Class.new }
|
169
|
+
it { Rouge.print(anon, "").should eq anon.inspect }
|
170
|
+
end
|
171
|
+
|
172
|
+
context "builtin forms" do
|
173
|
+
it { Rouge.print(Rouge::Builtin[Rouge::Builtins.method(:let)], "").
|
174
|
+
should eq "rouge.builtin/let" }
|
175
|
+
it { Rouge.print(Rouge::Builtin[Rouge::Builtins.method(:def)], "").
|
176
|
+
should eq "rouge.builtin/def" }
|
177
|
+
end
|
178
|
+
|
179
|
+
context "unknown forms" do
|
180
|
+
let(:l) { lambda {} }
|
181
|
+
it { Rouge.print(l, "").should eq l.inspect }
|
182
|
+
end
|
183
|
+
|
184
|
+
context "regexp" do
|
185
|
+
let(:rx) { Regexp.new("abc") }
|
186
|
+
it { Rouge.print(rx, "").should eq "#\"abc\"" }
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# vim: set sw=2 et cc=80:
|
data/spec/reader_spec.rb
ADDED
@@ -0,0 +1,422 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'rouge'
|
4
|
+
|
5
|
+
describe Rouge::Reader do
|
6
|
+
before do
|
7
|
+
@ns = Rouge[:"user.spec"].clear
|
8
|
+
@ns.refer Rouge[:"rouge.builtin"]
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "reading numbers" do
|
12
|
+
it { @ns.read("12755").should eq 12755 }
|
13
|
+
it { @ns.read("2_50_9").should eq 2509 }
|
14
|
+
it { @ns.read("-999").should eq(-999) }
|
15
|
+
it { @ns.read("+1704").should eq(1704) }
|
16
|
+
|
17
|
+
context "floats" do
|
18
|
+
it { @ns.read("23.0").should be_an_instance_of Float }
|
19
|
+
it { @ns.read("23.0").should eq 23.0 }
|
20
|
+
it { @ns.read("23.1").should eq 23.1 }
|
21
|
+
it { @ns.read("-23.1").should eq(-23.1) }
|
22
|
+
it { @ns.read("+17.04").should eq(17.04) }
|
23
|
+
it { @ns.read("+1_000e-3").should eq(1.0) }
|
24
|
+
it { @ns.read("+1E+3").should eq(1000) }
|
25
|
+
end
|
26
|
+
|
27
|
+
context "binary" do
|
28
|
+
it { @ns.read("+0b10").should eq(2) }
|
29
|
+
it { @ns.read("-0b10").should eq(-2) }
|
30
|
+
end
|
31
|
+
|
32
|
+
context "hexadecimal" do
|
33
|
+
it { @ns.read("+0xf").should eq(15) }
|
34
|
+
it { @ns.read("-0xf").should eq(-15) }
|
35
|
+
end
|
36
|
+
|
37
|
+
context "octal" do
|
38
|
+
it { @ns.read("+0333").should eq(219) }
|
39
|
+
it { @ns.read("-0333").should eq(-219) }
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should fail on invalid numbers" do
|
43
|
+
lambda { @ns.read("1.2.3") }.should raise_exception(Rouge::Reader::UnexpectedCharacterError)
|
44
|
+
lambda { @ns.read("12..") }.should raise_exception(Rouge::Reader::UnexpectedCharacterError)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should read symbols" do
|
49
|
+
@ns.read("loki").should eq Rouge::Symbol[:loki]
|
50
|
+
@ns.read("wah?").should eq Rouge::Symbol[:wah?]
|
51
|
+
@ns.read("!ruby!").should eq Rouge::Symbol[:"!ruby!"]
|
52
|
+
@ns.read("nil").should eq Rouge::Symbol[:nil]
|
53
|
+
@ns.read("nil").should eq nil
|
54
|
+
@ns.read("true").should eq Rouge::Symbol[:true]
|
55
|
+
@ns.read("true").should eq true
|
56
|
+
@ns.read("false").should eq Rouge::Symbol[:false]
|
57
|
+
@ns.read("false").should eq false
|
58
|
+
@ns.read("&").should eq Rouge::Symbol[:&]
|
59
|
+
@ns.read("*").should eq Rouge::Symbol[:*]
|
60
|
+
@ns.read("-").should eq Rouge::Symbol[:-]
|
61
|
+
@ns.read("+").should eq Rouge::Symbol[:+]
|
62
|
+
@ns.read("/").should eq Rouge::Symbol[:/]
|
63
|
+
@ns.read("|").should eq Rouge::Symbol[:|]
|
64
|
+
@ns.read("$").should eq Rouge::Symbol[:"$"]
|
65
|
+
@ns.read(".").should eq Rouge::Symbol[:"."]
|
66
|
+
@ns.read(".[]").should eq Rouge::Symbol[:".[]"]
|
67
|
+
@ns.read("=").should eq Rouge::Symbol[:"="]
|
68
|
+
@ns.read("%").should eq Rouge::Symbol[:"%"]
|
69
|
+
@ns.read(">").should eq Rouge::Symbol[:">"]
|
70
|
+
@ns.read("<").should eq Rouge::Symbol[:"<"]
|
71
|
+
@ns.read("%50").should eq Rouge::Symbol[:"%50"]
|
72
|
+
@ns.read("xyz#").should eq Rouge::Symbol[:"xyz#"]
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "keywords" do
|
76
|
+
it "should read plain keywords" do
|
77
|
+
@ns.read(":loki").should eq :loki
|
78
|
+
@ns.read(":/").should eq :/
|
79
|
+
@ns.read(":wah?").should eq :wah?
|
80
|
+
@ns.read(":nil").should eq :nil
|
81
|
+
@ns.read(":true").should eq :true
|
82
|
+
@ns.read(":false").should eq :false
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should read string-symbols" do
|
86
|
+
@ns.read(":\"!ruby!\"").should eq :"!ruby!"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "strings" do
|
91
|
+
it "should read plain strings" do
|
92
|
+
@ns.read("\"akashi yo\"").should eq "akashi yo"
|
93
|
+
@ns.read("\"akashi \n woah!\"").should eq "akashi \n woah!"
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should read escape sequences" do
|
97
|
+
@ns.read("\"here \\\" goes\"").should eq "here \" goes"
|
98
|
+
@ns.read("\"here \\\\ goes\"").should eq "here \\ goes"
|
99
|
+
@ns.read("\"\\a\\b\\e\\f\\n\\r\"").should eq "\a\b\e\f\n\r"
|
100
|
+
@ns.read("\"\\s\\t\\v\"").should eq "\s\t\v"
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should read strings as frozen" do
|
104
|
+
@ns.read("\"bah\"").should be_frozen
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "lists" do
|
109
|
+
it "should read the empty list" do
|
110
|
+
@ns.read("()").should eq Rouge::Seq::Cons[]
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should read one-element lists" do
|
114
|
+
@ns.read("(tiffany)").should eq Rouge::Seq::Cons[Rouge::Symbol[:tiffany]]
|
115
|
+
@ns.read("(:raaaaash)").
|
116
|
+
should eq Rouge::Seq::Cons[:raaaaash]
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should read multiple-element lists" do
|
120
|
+
@ns.read("(1 2 3)").should eq Rouge::Seq::Cons[1, 2, 3]
|
121
|
+
@ns.read("(true () [] \"no\")").
|
122
|
+
should eq Rouge::Seq::Cons[Rouge::Symbol[:true], Rouge::Seq::Cons[], [], "no"]
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should read nested lists" do
|
126
|
+
@ns.read("(((3) (())) 9 ((8) (8)))").
|
127
|
+
should eq Rouge::Seq::Cons[Rouge::Seq::Cons[Rouge::Seq::Cons[3],
|
128
|
+
Rouge::Seq::Cons[Rouge::Seq::Cons[]]], 9,
|
129
|
+
Rouge::Seq::Cons[Rouge::Seq::Cons[8], Rouge::Seq::Cons[8]]]
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should read lists as frozen" do
|
133
|
+
@ns.read("()").should be_frozen
|
134
|
+
@ns.read("(1)").should be_frozen
|
135
|
+
@ns.read("(1 2)").should be_frozen
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe "vectors" do
|
140
|
+
it "should read the empty vector" do
|
141
|
+
@ns.read("[]").should eq []
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should read one-element vectors" do
|
145
|
+
@ns.read("[tiffany]").should eq [Rouge::Symbol[:tiffany]]
|
146
|
+
@ns.read("[:raaaaash]").should eq [:raaaaash]
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should read multiple-element vectors" do
|
150
|
+
@ns.read("[1 2 3]").should eq [1, 2, 3]
|
151
|
+
@ns.read("[true () [] \"no\"]").
|
152
|
+
should eq [Rouge::Symbol[:true], Rouge::Seq::Cons[], [], "no"]
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should read nested vectors" do
|
156
|
+
@ns.read("[[[3] [[]]] 9 [[8] [8]]]").
|
157
|
+
should eq [[[3], [[]]], 9, [[8], [8]]]
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should read vectors as frozen" do
|
161
|
+
@ns.read("[]").should be_frozen
|
162
|
+
@ns.read("[1]").should be_frozen
|
163
|
+
@ns.read("[1 2]").should be_frozen
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
describe "quotations" do
|
168
|
+
it "should read 'X as (QUOTE X)" do
|
169
|
+
@ns.read("'x").
|
170
|
+
should eq Rouge::Seq::Cons[Rouge::Symbol[:quote], Rouge::Symbol[:x]]
|
171
|
+
end
|
172
|
+
|
173
|
+
it "should read ''('X) as (QUOTE (QUOTE ((QUOTE X))))" do
|
174
|
+
@ns.read("''('x)").
|
175
|
+
should eq Rouge::Seq::Cons[Rouge::Symbol[:quote],
|
176
|
+
Rouge::Seq::Cons[Rouge::Symbol[:quote],
|
177
|
+
Rouge::Seq::Cons[Rouge::Seq::Cons[Rouge::Symbol[:quote],
|
178
|
+
Rouge::Symbol[:x]]]]]
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
describe "vars" do
|
183
|
+
it "should read #'X as (VAR X)" do
|
184
|
+
@ns.read("#'x").
|
185
|
+
should eq Rouge::Seq::Cons[Rouge::Symbol[:var], Rouge::Symbol[:x]]
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should read #'#'(#'X) as (VAR (VAR ((VAR X))))" do
|
189
|
+
@ns.read("#'#'(#'x)").
|
190
|
+
should eq Rouge::Seq::Cons[Rouge::Symbol[:var],
|
191
|
+
Rouge::Seq::Cons[Rouge::Symbol[:var],
|
192
|
+
Rouge::Seq::Cons[Rouge::Seq::Cons[Rouge::Symbol[:var],
|
193
|
+
Rouge::Symbol[:x]]]]]
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
describe "maps" do
|
198
|
+
it "should read the empty map" do
|
199
|
+
@ns.read("{}").should eq({})
|
200
|
+
end
|
201
|
+
|
202
|
+
it "should read one-element maps" do
|
203
|
+
@ns.read("{a 1}").to_s.should eq({Rouge::Symbol[:a] => 1}.to_s)
|
204
|
+
@ns.read("{\"quux\" [lambast]}").
|
205
|
+
should eq({"quux" => [Rouge::Symbol[:lambast]]})
|
206
|
+
end
|
207
|
+
|
208
|
+
it "should read multiple-element maps" do
|
209
|
+
@ns.read("{:a 1 :b 2}").should eq({:a => 1, :b => 2})
|
210
|
+
@ns.read("{:f :f, :y :y\n:z :z}").
|
211
|
+
should eq({:f => :f, :y => :y, :z => :z})
|
212
|
+
end
|
213
|
+
|
214
|
+
it "should read nested maps" do
|
215
|
+
@ns.read("{:a {:z 9} :b {:q q}}").should eq(
|
216
|
+
{:a => {:z => 9}, :b => {:q => Rouge::Symbol[:q]}})
|
217
|
+
@ns.read("{{9 7} 5}").should eq({{9 => 7} => 5})
|
218
|
+
end
|
219
|
+
|
220
|
+
it "should read maps as frozen" do
|
221
|
+
@ns.read("{}").should be_frozen
|
222
|
+
@ns.read("{:a 1}").should be_frozen
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
describe "whitespace behaviour" do
|
227
|
+
it "should not fail with trailing whitespace" do
|
228
|
+
lambda {
|
229
|
+
@ns.read(":hello \n\n\t\t ").should eq :hello
|
230
|
+
}.should_not raise_exception
|
231
|
+
end
|
232
|
+
|
233
|
+
it "should deal with whitespace in strange places" do
|
234
|
+
lambda {
|
235
|
+
@ns.read("[1 ]").should eq [1]
|
236
|
+
@ns.read(" [ 2 ] ").should eq [2]
|
237
|
+
}.should_not raise_exception
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
describe "empty reads" do
|
242
|
+
it "should fail on empty reads" do
|
243
|
+
lambda {
|
244
|
+
@ns.read("")
|
245
|
+
}.should raise_exception(Rouge::Reader::EndOfDataError)
|
246
|
+
|
247
|
+
lambda {
|
248
|
+
@ns.read(" \n ")
|
249
|
+
}.should raise_exception(Rouge::Reader::EndOfDataError)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
describe "comments" do
|
254
|
+
it "should ignore comments" do
|
255
|
+
@ns.read("42 ;what!").should eq 42
|
256
|
+
@ns.read("[42 ;what!\n15]").should eq [42, 15]
|
257
|
+
|
258
|
+
lambda {
|
259
|
+
@ns.read(";what!")
|
260
|
+
}.should raise_exception(Rouge::Reader::EndOfDataError)
|
261
|
+
|
262
|
+
@ns.read(";what!\nhmm").should eq Rouge::Symbol[:hmm]
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
describe "syntax-quoting" do
|
267
|
+
describe "non-cons lists" do
|
268
|
+
it "should quote non-cons lists" do
|
269
|
+
@ns.read('`3').should eq @ns.read("'3")
|
270
|
+
@ns.read('`"my my my"').should eq @ns.read(%{'"my my my"})
|
271
|
+
end
|
272
|
+
|
273
|
+
it "should dequote within non-cons lists" do
|
274
|
+
@ns.read('`~3').should eq @ns.read("3")
|
275
|
+
@ns.read('``~3').should eq @ns.read("'3")
|
276
|
+
@ns.read('``~~3').should eq @ns.read("3")
|
277
|
+
end
|
278
|
+
|
279
|
+
it "should qualify symbols" do
|
280
|
+
@ns.read('`a').should eq @ns.read("'user.spec/a")
|
281
|
+
end
|
282
|
+
|
283
|
+
it "should not qualify special symbols" do
|
284
|
+
@ns.read('`.a').should eq @ns.read("'.a")
|
285
|
+
@ns.read('`&').should eq @ns.read("'&")
|
286
|
+
@ns.read('`|').should eq @ns.read("'|")
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
describe "cons-lists" do
|
291
|
+
it "should quote cons lists" do
|
292
|
+
@ns.read('`(1 2)').should eq @ns.read("(list '1 '2)")
|
293
|
+
@ns.read('`(a b)').
|
294
|
+
should eq @ns.read("(list 'user.spec/a 'user.spec/b)")
|
295
|
+
end
|
296
|
+
|
297
|
+
it "should dequote within cons lists" do
|
298
|
+
@ns.read('`(a ~b)').should eq @ns.read("(list 'user.spec/a b)")
|
299
|
+
@ns.read('`(a ~(b `(c ~d)))').
|
300
|
+
should eq @ns.read("(list 'user.spec/a (b (list 'user.spec/c d)))")
|
301
|
+
@ns.read('`(a `(b ~c))').
|
302
|
+
should eq @ns.read("(list 'user.spec/a (list 'user.spec/list " \
|
303
|
+
"(list 'quote 'user.spec/b) 'user.spec/c))")
|
304
|
+
@ns.read('`~`(x)').should eq @ns.read("(list 'user.spec/x)")
|
305
|
+
end
|
306
|
+
|
307
|
+
it "should dequote within maps" do
|
308
|
+
@ns.read('`{a ~b}').to_s.should eq @ns.read("{'user.spec/a b}").to_s
|
309
|
+
end
|
310
|
+
|
311
|
+
it "should splice within seqs and vectors" do
|
312
|
+
@ns.read('`(a ~@b c)').
|
313
|
+
should eq @ns.read("(seq (concat (list 'user.spec/a) b " \
|
314
|
+
"(list 'user.spec/c)))")
|
315
|
+
@ns.read('`(~@(a b) ~c)').
|
316
|
+
should eq @ns.read("(seq (concat (a b) (list c)))")
|
317
|
+
@ns.read('`[a ~@b c]').should eq @ns.read(<<-ROUGE)
|
318
|
+
(apply vector (concat (list 'user.spec/a) b (list 'user.spec/c)))
|
319
|
+
ROUGE
|
320
|
+
@ns.read('`[~@(a b) ~c]').
|
321
|
+
should eq @ns.read("(apply vector (concat (a b) (list c)))")
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
describe "gensyms" do
|
326
|
+
it "should read as unique in each invocation" do
|
327
|
+
a1 = @ns.read('`a#')
|
328
|
+
a2 = @ns.read('`a#')
|
329
|
+
a1.to_s.should_not eq a2.to_s
|
330
|
+
end
|
331
|
+
|
332
|
+
it "should read identically within each invocation" do
|
333
|
+
as = @ns.read('`(a# a# `(a# a#))')
|
334
|
+
as = as
|
335
|
+
.map {|e| e.respond_to?(:to_a) ? e.to_a : e}.to_a.flatten
|
336
|
+
.flat_map {|e| e.respond_to?(:to_a) ? e.to_a : e}
|
337
|
+
.flat_map {|e| e.respond_to?(:to_a) ? e.to_a : e}
|
338
|
+
.find_all {|e|
|
339
|
+
e.is_a?(Rouge::Symbol) and e.name.to_s =~ /^a/
|
340
|
+
}
|
341
|
+
as.length.should eq 4
|
342
|
+
as[0].should eq as[1]
|
343
|
+
as[2].should eq as[3]
|
344
|
+
as[0].should_not eq as[2]
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
describe "anonymous functions" do
|
350
|
+
it "should read anonymous functions" do
|
351
|
+
@ns.read('#(1)').should eq @ns.read('(fn [] (1))')
|
352
|
+
@ns.read('#(do 1)').should eq @ns.read('(fn [] (do 1))')
|
353
|
+
@ns.read('#(%)').should eq @ns.read('(fn [%1] (%1))')
|
354
|
+
@ns.read('#(%2)').should eq @ns.read('(fn [%1 %2] (%2))')
|
355
|
+
@ns.read('#(%5)').should eq @ns.read('(fn [%1 %2 %3 %4 %5] (%5))')
|
356
|
+
@ns.read('#(%2 %)').should eq @ns.read('(fn [%1 %2] (%2 %1))')
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
describe "metadata" do
|
361
|
+
it "should read metadata" do
|
362
|
+
y = @ns.read('^{:x 1} y')
|
363
|
+
y.should eq Rouge::Symbol[:y]
|
364
|
+
y.meta.to_s.should eq({:x => 1}.to_s)
|
365
|
+
end
|
366
|
+
|
367
|
+
it "should stack metadata" do
|
368
|
+
y = @ns.read('^{:y 2} ^{:y 3 :z 2} y')
|
369
|
+
y.should eq Rouge::Symbol[:y]
|
370
|
+
y.meta.should include({:y => 2, :z => 2})
|
371
|
+
end
|
372
|
+
|
373
|
+
it "should assign tags" do
|
374
|
+
y = @ns.read('^"xyz" y')
|
375
|
+
y.should eq Rouge::Symbol[:y]
|
376
|
+
y.meta.should include({:tag => "xyz"})
|
377
|
+
end
|
378
|
+
|
379
|
+
it "should assign symbol markers" do
|
380
|
+
y = @ns.read('^:blargh y')
|
381
|
+
y.should eq Rouge::Symbol[:y]
|
382
|
+
y.meta.should include({:blargh => true})
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
describe "deref" do
|
387
|
+
it "should read derefs" do
|
388
|
+
@ns.read('@(boo)').should eq @ns.read('(rouge.core/deref (boo))')
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
describe "multiple reading" do
|
393
|
+
it "should read multiple forms in turn" do
|
394
|
+
r = Rouge::Reader.new(@ns, "a b c")
|
395
|
+
r.lex.should eq Rouge::Symbol[:a]
|
396
|
+
r.lex.should eq Rouge::Symbol[:b]
|
397
|
+
r.lex.should eq Rouge::Symbol[:c]
|
398
|
+
|
399
|
+
lambda {
|
400
|
+
r.lex
|
401
|
+
}.should raise_exception(Rouge::Reader::EndOfDataError)
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
describe "the ns property" do
|
406
|
+
it "should return the ns the reader is in" do
|
407
|
+
Rouge::Reader.new(@ns, "").ns.should be @ns
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
411
|
+
describe "the comment dispatch" do
|
412
|
+
it "should be completely ignored" do
|
413
|
+
@ns.read('#_(xyz abc) :f').should eq :f
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
describe "regexp" do
|
418
|
+
it { @ns.read('#"abc"').should be_an_instance_of Regexp }
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
# vim: set sw=2 et cc=80:
|