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.
Files changed (78) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/Gemfile +3 -0
  4. data/LICENSE.md +21 -0
  5. data/README.md +52 -0
  6. data/Rakefile +10 -0
  7. data/bin/whitespace +67 -0
  8. data/examples/count.ws +76 -0
  9. data/examples/fact.ws +135 -0
  10. data/examples/hello.ws +110 -0
  11. data/examples/name.ws +135 -0
  12. data/lib/whitespace.rb +14 -0
  13. data/lib/whitespace/data_structures/console.rb +56 -0
  14. data/lib/whitespace/data_structures/counter.rb +24 -0
  15. data/lib/whitespace/data_structures/memory.rb +19 -0
  16. data/lib/whitespace/data_structures/stack.rb +25 -0
  17. data/lib/whitespace/instructions/arithmetic/add.rb +9 -0
  18. data/lib/whitespace/instructions/arithmetic/binop.rb +18 -0
  19. data/lib/whitespace/instructions/arithmetic/div.rb +9 -0
  20. data/lib/whitespace/instructions/arithmetic/mod.rb +9 -0
  21. data/lib/whitespace/instructions/arithmetic/mul.rb +9 -0
  22. data/lib/whitespace/instructions/arithmetic/sub.rb +9 -0
  23. data/lib/whitespace/instructions/flow_control/call.rb +19 -0
  24. data/lib/whitespace/instructions/flow_control/end.rb +7 -0
  25. data/lib/whitespace/instructions/flow_control/label.rb +16 -0
  26. data/lib/whitespace/instructions/flow_control/njmp.rb +20 -0
  27. data/lib/whitespace/instructions/flow_control/return.rb +7 -0
  28. data/lib/whitespace/instructions/flow_control/ujmp.rb +18 -0
  29. data/lib/whitespace/instructions/flow_control/zjmp.rb +20 -0
  30. data/lib/whitespace/instructions/heap_access/retrieve.rb +9 -0
  31. data/lib/whitespace/instructions/heap_access/store.rb +10 -0
  32. data/lib/whitespace/instructions/instruction.rb +13 -0
  33. data/lib/whitespace/instructions/io/putc.rb +15 -0
  34. data/lib/whitespace/instructions/io/putn.rb +15 -0
  35. data/lib/whitespace/instructions/io/readc.rb +16 -0
  36. data/lib/whitespace/instructions/io/readn.rb +16 -0
  37. data/lib/whitespace/instructions/stack_manipulation/discard.rb +7 -0
  38. data/lib/whitespace/instructions/stack_manipulation/dup.rb +7 -0
  39. data/lib/whitespace/instructions/stack_manipulation/push.rb +17 -0
  40. data/lib/whitespace/instructions/stack_manipulation/swap.rb +11 -0
  41. data/lib/whitespace/isa.rb +9 -0
  42. data/lib/whitespace/parser.rb +243 -0
  43. data/lib/whitespace/util.rb +37 -0
  44. data/lib/whitespace/version.rb +3 -0
  45. data/lib/whitespace/vm.rb +44 -0
  46. data/test/test_helper.rb +4 -0
  47. data/test/whitespace/data_structures/console_test.rb +113 -0
  48. data/test/whitespace/data_structures/counter_test.rb +37 -0
  49. data/test/whitespace/data_structures/memory_test.rb +25 -0
  50. data/test/whitespace/data_structures/stack_test.rb +63 -0
  51. data/test/whitespace/instructions/arithmetic/add_test.rb +43 -0
  52. data/test/whitespace/instructions/arithmetic/div_test.rb +52 -0
  53. data/test/whitespace/instructions/arithmetic/mod_test.rb +52 -0
  54. data/test/whitespace/instructions/arithmetic/mul_test.rb +43 -0
  55. data/test/whitespace/instructions/arithmetic/sub_test.rb +43 -0
  56. data/test/whitespace/instructions/flow_control/call_test.rb +50 -0
  57. data/test/whitespace/instructions/flow_control/end_test.rb +15 -0
  58. data/test/whitespace/instructions/flow_control/label_test.rb +24 -0
  59. data/test/whitespace/instructions/flow_control/njmp_test.rb +94 -0
  60. data/test/whitespace/instructions/flow_control/return_test.rb +33 -0
  61. data/test/whitespace/instructions/flow_control/ujmp_test.rb +44 -0
  62. data/test/whitespace/instructions/flow_control/zjmp_test.rb +94 -0
  63. data/test/whitespace/instructions/heap_access/retrieve_test.rb +49 -0
  64. data/test/whitespace/instructions/heap_access/store_test.rb +44 -0
  65. data/test/whitespace/instructions/instruction_test.rb +11 -0
  66. data/test/whitespace/instructions/io/putc_test.rb +42 -0
  67. data/test/whitespace/instructions/io/putn_test.rb +42 -0
  68. data/test/whitespace/instructions/io/readc_test.rb +71 -0
  69. data/test/whitespace/instructions/io/readn_test.rb +79 -0
  70. data/test/whitespace/instructions/stack_manipulation/discard_test.rb +30 -0
  71. data/test/whitespace/instructions/stack_manipulation/dup_test.rb +32 -0
  72. data/test/whitespace/instructions/stack_manipulation/push_test.rb +30 -0
  73. data/test/whitespace/instructions/stack_manipulation/swap_test.rb +43 -0
  74. data/test/whitespace/parser_test.rb +362 -0
  75. data/test/whitespace/util_test.rb +87 -0
  76. data/test/whitespace/vm_test.rb +80 -0
  77. data/whitespace-ruby.gemspec +30 -0
  78. 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