whitespace-ruby 1.0.0
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/.gitignore +3 -0
- data/Gemfile +3 -0
- data/LICENSE.md +21 -0
- data/README.md +52 -0
- data/Rakefile +10 -0
- data/bin/whitespace +67 -0
- data/examples/count.ws +76 -0
- data/examples/fact.ws +135 -0
- data/examples/hello.ws +110 -0
- data/examples/name.ws +135 -0
- data/lib/whitespace.rb +14 -0
- data/lib/whitespace/data_structures/console.rb +56 -0
- data/lib/whitespace/data_structures/counter.rb +24 -0
- data/lib/whitespace/data_structures/memory.rb +19 -0
- data/lib/whitespace/data_structures/stack.rb +25 -0
- data/lib/whitespace/instructions/arithmetic/add.rb +9 -0
- data/lib/whitespace/instructions/arithmetic/binop.rb +18 -0
- data/lib/whitespace/instructions/arithmetic/div.rb +9 -0
- data/lib/whitespace/instructions/arithmetic/mod.rb +9 -0
- data/lib/whitespace/instructions/arithmetic/mul.rb +9 -0
- data/lib/whitespace/instructions/arithmetic/sub.rb +9 -0
- data/lib/whitespace/instructions/flow_control/call.rb +19 -0
- data/lib/whitespace/instructions/flow_control/end.rb +7 -0
- data/lib/whitespace/instructions/flow_control/label.rb +16 -0
- data/lib/whitespace/instructions/flow_control/njmp.rb +20 -0
- data/lib/whitespace/instructions/flow_control/return.rb +7 -0
- data/lib/whitespace/instructions/flow_control/ujmp.rb +18 -0
- data/lib/whitespace/instructions/flow_control/zjmp.rb +20 -0
- data/lib/whitespace/instructions/heap_access/retrieve.rb +9 -0
- data/lib/whitespace/instructions/heap_access/store.rb +10 -0
- data/lib/whitespace/instructions/instruction.rb +13 -0
- data/lib/whitespace/instructions/io/putc.rb +15 -0
- data/lib/whitespace/instructions/io/putn.rb +15 -0
- data/lib/whitespace/instructions/io/readc.rb +16 -0
- data/lib/whitespace/instructions/io/readn.rb +16 -0
- data/lib/whitespace/instructions/stack_manipulation/discard.rb +7 -0
- data/lib/whitespace/instructions/stack_manipulation/dup.rb +7 -0
- data/lib/whitespace/instructions/stack_manipulation/push.rb +17 -0
- data/lib/whitespace/instructions/stack_manipulation/swap.rb +11 -0
- data/lib/whitespace/isa.rb +9 -0
- data/lib/whitespace/parser.rb +243 -0
- data/lib/whitespace/util.rb +37 -0
- data/lib/whitespace/version.rb +3 -0
- data/lib/whitespace/vm.rb +44 -0
- data/test/test_helper.rb +4 -0
- data/test/whitespace/data_structures/console_test.rb +113 -0
- data/test/whitespace/data_structures/counter_test.rb +37 -0
- data/test/whitespace/data_structures/memory_test.rb +25 -0
- data/test/whitespace/data_structures/stack_test.rb +63 -0
- data/test/whitespace/instructions/arithmetic/add_test.rb +43 -0
- data/test/whitespace/instructions/arithmetic/div_test.rb +52 -0
- data/test/whitespace/instructions/arithmetic/mod_test.rb +52 -0
- data/test/whitespace/instructions/arithmetic/mul_test.rb +43 -0
- data/test/whitespace/instructions/arithmetic/sub_test.rb +43 -0
- data/test/whitespace/instructions/flow_control/call_test.rb +50 -0
- data/test/whitespace/instructions/flow_control/end_test.rb +15 -0
- data/test/whitespace/instructions/flow_control/label_test.rb +24 -0
- data/test/whitespace/instructions/flow_control/njmp_test.rb +94 -0
- data/test/whitespace/instructions/flow_control/return_test.rb +33 -0
- data/test/whitespace/instructions/flow_control/ujmp_test.rb +44 -0
- data/test/whitespace/instructions/flow_control/zjmp_test.rb +94 -0
- data/test/whitespace/instructions/heap_access/retrieve_test.rb +49 -0
- data/test/whitespace/instructions/heap_access/store_test.rb +44 -0
- data/test/whitespace/instructions/instruction_test.rb +11 -0
- data/test/whitespace/instructions/io/putc_test.rb +42 -0
- data/test/whitespace/instructions/io/putn_test.rb +42 -0
- data/test/whitespace/instructions/io/readc_test.rb +71 -0
- data/test/whitespace/instructions/io/readn_test.rb +79 -0
- data/test/whitespace/instructions/stack_manipulation/discard_test.rb +30 -0
- data/test/whitespace/instructions/stack_manipulation/dup_test.rb +32 -0
- data/test/whitespace/instructions/stack_manipulation/push_test.rb +30 -0
- data/test/whitespace/instructions/stack_manipulation/swap_test.rb +43 -0
- data/test/whitespace/parser_test.rb +362 -0
- data/test/whitespace/util_test.rb +87 -0
- data/test/whitespace/vm_test.rb +80 -0
- data/whitespace-ruby.gemspec +30 -0
- metadata +178 -0
@@ -0,0 +1,43 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
module Whitespace::ISA
|
4
|
+
describe Mul do
|
5
|
+
before do
|
6
|
+
@vm = Whitespace::VM.new
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#execute" do
|
10
|
+
describe "when the value stack is empty" do
|
11
|
+
it "raises Whitespace::EmptyError" do
|
12
|
+
expect(@vm.vstack.size).must_equal 0
|
13
|
+
|
14
|
+
expect { Mul.new(@vm).execute }.must_raise Whitespace::EmptyError
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "when the value stack has one element" do
|
19
|
+
it "raises Whitespace::EmptyError" do
|
20
|
+
@vm.vstack.push 1
|
21
|
+
expect(@vm.vstack.size).must_equal 1
|
22
|
+
|
23
|
+
expect { Mul.new(@vm).execute }.must_raise Whitespace::EmptyError
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "when the value stack has at least 2 elements" do
|
28
|
+
it "replaces the top 2 elements with their product" do
|
29
|
+
@vm.vstack.push 1
|
30
|
+
@vm.vstack.push 2
|
31
|
+
@vm.vstack.push 3
|
32
|
+
expect(@vm.vstack.size).must_equal 3
|
33
|
+
|
34
|
+
Mul.new(@vm).execute
|
35
|
+
|
36
|
+
expect(@vm.vstack.pop).must_equal 6
|
37
|
+
expect(@vm.vstack.pop).must_equal 1
|
38
|
+
expect(@vm.vstack.size).must_equal 0
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
module Whitespace::ISA
|
4
|
+
describe Sub do
|
5
|
+
before do
|
6
|
+
@vm = Whitespace::VM.new
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#execute" do
|
10
|
+
describe "when the value stack is empty" do
|
11
|
+
it "raises Whitespace::EmptyError" do
|
12
|
+
expect(@vm.vstack.size).must_equal 0
|
13
|
+
|
14
|
+
expect { Sub.new(@vm).execute }.must_raise Whitespace::EmptyError
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "when the value stack has one element" do
|
19
|
+
it "raises Whitespace::EmptyError" do
|
20
|
+
@vm.vstack.push 1
|
21
|
+
expect(@vm.vstack.size).must_equal 1
|
22
|
+
|
23
|
+
expect { Sub.new(@vm).execute }.must_raise Whitespace::EmptyError
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "when the value stack has at least 2 elements" do
|
28
|
+
it "replaces the top 2 elements with their difference" do
|
29
|
+
@vm.vstack.push 1
|
30
|
+
@vm.vstack.push 3
|
31
|
+
@vm.vstack.push 2
|
32
|
+
expect(@vm.vstack.size).must_equal 3
|
33
|
+
|
34
|
+
Sub.new(@vm).execute
|
35
|
+
|
36
|
+
expect(@vm.vstack.pop).must_equal 1
|
37
|
+
expect(@vm.vstack.pop).must_equal 1
|
38
|
+
expect(@vm.vstack.size).must_equal 0
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
module Whitespace::ISA
|
4
|
+
describe Call do
|
5
|
+
before do
|
6
|
+
@vm = Whitespace::VM.new
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "initialization" do
|
10
|
+
describe "when given a non-label value" do
|
11
|
+
it "raises ArgumentError" do
|
12
|
+
e = expect { Call.new(@vm, :not_a_label) }.must_raise(ArgumentError)
|
13
|
+
e.message.must_match /must be a label/
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#execute" do
|
19
|
+
describe "when the label doesn't exist" do
|
20
|
+
it "raises Whitespace::LabelError" do
|
21
|
+
e = expect { Call.new(@vm, " ").execute }.must_raise \
|
22
|
+
Whitespace::LabelError
|
23
|
+
expect(e.message).must_match /missing: " "/
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "when the label does exist" do
|
28
|
+
it "puts the current value of the pc on the call stack and sets it " \
|
29
|
+
"to the index of the instruction after the label" do
|
30
|
+
@vm.load [
|
31
|
+
"instruction 1",
|
32
|
+
Label.new(@vm, " "),
|
33
|
+
"instruction 3",
|
34
|
+
"instruction 4",
|
35
|
+
"instruction 5"
|
36
|
+
]
|
37
|
+
@vm.pc.change_to 4
|
38
|
+
|
39
|
+
expect(@vm.cstack.size).must_equal 0
|
40
|
+
|
41
|
+
Call.new(@vm, " ").execute
|
42
|
+
|
43
|
+
expect(@vm.cstack.size).must_equal 1
|
44
|
+
expect(@vm.cstack.top).must_equal 4
|
45
|
+
expect(@vm.pc.to_int).must_equal 2
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
module Whitespace::ISA
|
4
|
+
describe End do
|
5
|
+
before do
|
6
|
+
@vm = Whitespace::VM.new
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#execute" do
|
10
|
+
it "raise Whitespace::Halt" do
|
11
|
+
expect { End.new(@vm).execute }.must_raise Whitespace::Halt
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
module Whitespace::ISA
|
4
|
+
describe Label do
|
5
|
+
before do
|
6
|
+
@vm = Whitespace::VM.new
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "initialization" do
|
10
|
+
describe "when given a non-label value" do
|
11
|
+
it "raises ArgumentError" do
|
12
|
+
e = expect { Label.new(@vm, :not_a_label) }.must_raise(ArgumentError)
|
13
|
+
e.message.must_match /must be a label/
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#execute" do
|
19
|
+
it "doesn't raise NotImplementedError" do
|
20
|
+
Label.new(@vm, " ").execute
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
module Whitespace::ISA
|
4
|
+
describe Njmp do
|
5
|
+
before do
|
6
|
+
@vm = Whitespace::VM.new
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "initialization" do
|
10
|
+
describe "when given a non-label value" do
|
11
|
+
it "raises ArgumentError" do
|
12
|
+
e = expect { Njmp.new(@vm, :not_a_label) }.must_raise(ArgumentError)
|
13
|
+
e.message.must_match /must be a label/
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#execute" do
|
19
|
+
describe "when the value stack is empty" do
|
20
|
+
it "raises Whitespace::EmptyError" do
|
21
|
+
expect { Njmp.new(@vm, " ").execute }.must_raise \
|
22
|
+
Whitespace::EmptyError
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "when the value stack has at least 1 element" do
|
27
|
+
describe "when the top element is negative" do
|
28
|
+
before do
|
29
|
+
@vm.vstack.push -5
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "when the label exists" do
|
33
|
+
it "changes the current value of the pc to the index of the " \
|
34
|
+
"instruction after the label" do
|
35
|
+
@vm.load [
|
36
|
+
"instruction 1",
|
37
|
+
Label.new(@vm, " "),
|
38
|
+
"instruction 3"
|
39
|
+
]
|
40
|
+
expect(@vm.pc.to_int).must_equal 0
|
41
|
+
|
42
|
+
Njmp.new(@vm, " ").execute
|
43
|
+
|
44
|
+
expect(@vm.pc.to_int).must_equal 2
|
45
|
+
expect(@vm.vstack.size).must_equal 0
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "when the label doesn't exist" do
|
50
|
+
it "raises Whitespace::LabelError" do
|
51
|
+
e = expect { Njmp.new(@vm, " ").execute }.must_raise \
|
52
|
+
Whitespace::LabelError
|
53
|
+
expect(e.message).must_match /missing: " "/
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "when the top element is non-negative" do
|
59
|
+
before do
|
60
|
+
@vm.vstack.push 0
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "when the label exists" do
|
64
|
+
it "pops the top element but does not change the pc" do
|
65
|
+
@vm.load [
|
66
|
+
"instruction 1",
|
67
|
+
Label.new(@vm, " "),
|
68
|
+
"instruction 3"
|
69
|
+
]
|
70
|
+
|
71
|
+
expect(@vm.pc.to_int).must_equal 0
|
72
|
+
|
73
|
+
Njmp.new(@vm, " ").execute
|
74
|
+
|
75
|
+
expect(@vm.pc.to_int).must_equal 0
|
76
|
+
expect(@vm.vstack.size).must_equal 0
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "when the label doesn't exist" do
|
81
|
+
it "pops the top element but does not change the pc" do
|
82
|
+
expect(@vm.pc.to_int).must_equal 0
|
83
|
+
|
84
|
+
Njmp.new(@vm, " ").execute
|
85
|
+
|
86
|
+
expect(@vm.pc.to_int).must_equal 0
|
87
|
+
expect(@vm.vstack.size).must_equal 0
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
module Whitespace::ISA
|
4
|
+
describe Return do
|
5
|
+
before do
|
6
|
+
@vm = Whitespace::VM.new
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#execute" do
|
10
|
+
describe "when the call stack is empty" do
|
11
|
+
it "raises Whitespace::EmptyError" do
|
12
|
+
expect { Return.new(@vm).execute }.must_raise Whitespace::EmptyError
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "when the call stack has at least 1 element" do
|
17
|
+
it "changes the current value of the pc to the value taken from the " \
|
18
|
+
"top of the call stack" do
|
19
|
+
@vm.cstack.push 4
|
20
|
+
@vm.cstack.push 5
|
21
|
+
|
22
|
+
expect(@vm.pc.to_int).must_equal 0
|
23
|
+
|
24
|
+
Return.new(@vm).execute
|
25
|
+
|
26
|
+
expect(@vm.pc.to_int).must_equal 5
|
27
|
+
expect(@vm.cstack.top).must_equal 4
|
28
|
+
expect(@vm.cstack.size).must_equal 1
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
module Whitespace::ISA
|
4
|
+
describe Ujmp do
|
5
|
+
before do
|
6
|
+
@vm = Whitespace::VM.new
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "initialization" do
|
10
|
+
describe "when given a non-label value" do
|
11
|
+
it "raises ArgumentError" do
|
12
|
+
e = expect { Ujmp.new(@vm, :not_a_label) }.must_raise(ArgumentError)
|
13
|
+
e.message.must_match /must be a label/
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#execute" do
|
19
|
+
describe "when the label doesn't exist" do
|
20
|
+
it "raises Whitespace::LabelError" do
|
21
|
+
e = expect { Ujmp.new(@vm, " ").execute }.must_raise \
|
22
|
+
Whitespace::LabelError
|
23
|
+
expect(e.message).must_match /missing: " "/
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "when the label does exist" do
|
28
|
+
it "changes the current value of the pc to the index of the " \
|
29
|
+
"instruction after the label" do
|
30
|
+
@vm.load [
|
31
|
+
Label.new(@vm, " "),
|
32
|
+
"instruction 2",
|
33
|
+
"instruction 3"
|
34
|
+
]
|
35
|
+
@vm.pc.change_to 2
|
36
|
+
|
37
|
+
Ujmp.new(@vm, " ").execute
|
38
|
+
|
39
|
+
expect(@vm.pc.to_int).must_equal 1
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
module Whitespace::ISA
|
4
|
+
describe Zjmp do
|
5
|
+
before do
|
6
|
+
@vm = Whitespace::VM.new
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "initialization" do
|
10
|
+
describe "when given a non-label value" do
|
11
|
+
it "raises ArgumentError" do
|
12
|
+
e = expect { Zjmp.new(@vm, :not_a_label) }.must_raise(ArgumentError)
|
13
|
+
e.message.must_match /must be a label/
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#execute" do
|
19
|
+
describe "when the value stack is empty" do
|
20
|
+
it "raises Whitespace::EmptyError" do
|
21
|
+
expect { Zjmp.new(@vm, " ").execute }.must_raise \
|
22
|
+
Whitespace::EmptyError
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "when the value stack has at least 1 element" do
|
27
|
+
describe "when the top element is 0" do
|
28
|
+
before do
|
29
|
+
@vm.vstack.push 0
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "when the label exists" do
|
33
|
+
it "changes the current value of the pc to the index of the " \
|
34
|
+
"instruction after the label" do
|
35
|
+
@vm.load [
|
36
|
+
"instruction 1",
|
37
|
+
Label.new(@vm, " "),
|
38
|
+
"instruction 3"
|
39
|
+
]
|
40
|
+
expect(@vm.pc.to_int).must_equal 0
|
41
|
+
|
42
|
+
Zjmp.new(@vm, " ").execute
|
43
|
+
|
44
|
+
expect(@vm.pc.to_int).must_equal 2
|
45
|
+
expect(@vm.vstack.size).must_equal 0
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "when the label doesn't exist" do
|
50
|
+
it "raises Whitespace::LabelError" do
|
51
|
+
e = expect { Zjmp.new(@vm, " ").execute }.must_raise \
|
52
|
+
Whitespace::LabelError
|
53
|
+
expect(e.message).must_match /missing: " "/
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "when the top element is non-zero" do
|
59
|
+
before do
|
60
|
+
@vm.vstack.push 1
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "when the label exists" do
|
64
|
+
it "pops the top element but does not change the pc" do
|
65
|
+
@vm.load [
|
66
|
+
"instruction 1",
|
67
|
+
Label.new(@vm, " "),
|
68
|
+
"instruction 3"
|
69
|
+
]
|
70
|
+
|
71
|
+
expect(@vm.pc.to_int).must_equal 0
|
72
|
+
|
73
|
+
Zjmp.new(@vm, " ").execute
|
74
|
+
|
75
|
+
expect(@vm.pc.to_int).must_equal 0
|
76
|
+
expect(@vm.vstack.size).must_equal 0
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "when the label doesn't exist" do
|
81
|
+
it "pops the top element but does not change the pc" do
|
82
|
+
expect(@vm.pc.to_int).must_equal 0
|
83
|
+
|
84
|
+
Zjmp.new(@vm, " ").execute
|
85
|
+
|
86
|
+
expect(@vm.pc.to_int).must_equal 0
|
87
|
+
expect(@vm.vstack.size).must_equal 0
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|