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,49 @@
1
+ require "test_helper"
2
+
3
+ module Whitespace::ISA
4
+ describe Retrieve 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 { Retrieve.new(@vm).execute }.must_raise Whitespace::EmptyError
15
+ end
16
+ end
17
+
18
+ describe "when the value stack has at least 1 element" do
19
+ describe "when the address does not exist" do
20
+ it "raises Whitespace::AddressError" do
21
+ @vm.vstack.push 1
22
+ @vm.vstack.push :address
23
+ expect(@vm.vstack.size).must_equal 2
24
+
25
+ expect { Retrieve.new(@vm).execute }.must_raise \
26
+ Whitespace::AddressError
27
+ end
28
+ end
29
+
30
+ describe "when the address exists" do
31
+ it "retrieves the value at the given address and puts it on top " \
32
+ "the value stack" do
33
+ @vm.memory[:address] = :value
34
+
35
+ @vm.vstack.push 1
36
+ @vm.vstack.push :address
37
+ expect(@vm.vstack.size).must_equal 2
38
+
39
+ Retrieve.new(@vm).execute
40
+
41
+ expect(@vm.vstack.pop).must_equal :value
42
+ expect(@vm.vstack.pop).must_equal 1
43
+ expect(@vm.vstack.size).must_equal 0
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,44 @@
1
+ require "test_helper"
2
+
3
+ module Whitespace::ISA
4
+ describe Store 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 { Store.new(@vm).execute }.must_raise Whitespace::EmptyError
15
+ end
16
+ end
17
+
18
+ describe "when the value stack has 1 element" do
19
+ it "raises Whitespace::EmptyError" do
20
+ @vm.vstack.push :address
21
+ expect(@vm.vstack.size).must_equal 1
22
+
23
+ expect { Store.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 "stores the value at the given address in memory" do
29
+ @vm.vstack.push 1
30
+ @vm.vstack.push :address
31
+ @vm.vstack.push :value
32
+ expect(@vm.vstack.size).must_equal 3
33
+ expect { @vm.memory[:address] }.must_raise Whitespace::AddressError
34
+
35
+ Store.new(@vm).execute
36
+
37
+ expect(@vm.memory[:address]).must_equal :value
38
+ expect(@vm.vstack.pop).must_equal 1
39
+ expect(@vm.vstack.size).must_equal 0
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,11 @@
1
+ require "test_helper"
2
+
3
+ module Whitespace::ISA
4
+ describe Instruction do
5
+ describe "#execute" do
6
+ it "raises NotImplementedError" do
7
+ expect { Instruction.new(:vm).execute }.must_raise NotImplementedError
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,42 @@
1
+ require "test_helper"
2
+
3
+ module Whitespace::ISA
4
+ describe Putc 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 { Putc.new(@vm, Whitespace::Console.new).execute }.must_raise \
13
+ Whitespace::EmptyError
14
+ end
15
+ end
16
+
17
+ describe "when the value stack has at least 1 element" do
18
+ describe "when the top element is an ASCII character" do
19
+ it "outputs it as a character" do
20
+ @vm.vstack.push 65
21
+ expect(@vm.vstack.size).must_equal 1
22
+
23
+ expect { Putc.new(@vm, Whitespace::Console.new).execute } \
24
+ .must_output "A"
25
+ expect(@vm.vstack.size).must_equal 0
26
+ end
27
+ end
28
+
29
+ describe "when the top element is not an ASCII character" do
30
+ it "raises ArgumentError" do
31
+ @vm.vstack.push 0
32
+ expect(@vm.vstack.size).must_equal 1
33
+
34
+ e = expect { Putc.new(@vm, Whitespace::Console.new).execute } \
35
+ .must_raise ArgumentError
36
+ expect(e.message).must_match /must be an ASCII character/
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,42 @@
1
+ require "test_helper"
2
+
3
+ module Whitespace::ISA
4
+ describe Putn 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 { Putn.new(@vm, Whitespace::Console.new).execute }.must_raise \
13
+ Whitespace::EmptyError
14
+ end
15
+ end
16
+
17
+ describe "when the value stack has at least 1 element" do
18
+ describe "when it is an integer" do
19
+ it "outputs it as an integer" do
20
+ @vm.vstack.push 65
21
+ expect(@vm.vstack.size).must_equal 1
22
+
23
+ expect { Putn.new(@vm, Whitespace::Console.new).execute } \
24
+ .must_output "65"
25
+ expect(@vm.vstack.size).must_equal 0
26
+ end
27
+ end
28
+
29
+ describe "when it is not an integer" do
30
+ it "raises ArgumentError" do
31
+ @vm.vstack.push "6s"
32
+ expect(@vm.vstack.size).must_equal 1
33
+
34
+ e = expect { Putn.new(@vm, Whitespace::Console.new).execute } \
35
+ .must_raise ArgumentError
36
+ expect(e.message).must_match /must be an integer: 6s/
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,71 @@
1
+ require "test_helper"
2
+
3
+ module Whitespace::ISA
4
+ describe Readc do
5
+ before do
6
+ @vm = Whitespace::VM.new
7
+ @stdin = Object.new
8
+ end
9
+
10
+ describe "#execute" do
11
+ describe "when there is no character" do
12
+ it "raises ArgumentError" do
13
+ def @stdin.getc
14
+ end
15
+
16
+ console = Whitespace::Console.new(stdin: @stdin)
17
+ e = expect { Readc.new(@vm, console).execute }.must_raise \
18
+ ArgumentError
19
+ expect(e.message).must_match /must be an ASCII character/
20
+ end
21
+ end
22
+
23
+ describe "when there is a character" do
24
+ describe "when it is an ASCII character" do
25
+ before do
26
+ def @stdin.getc
27
+ "A"
28
+ end
29
+ end
30
+
31
+ describe "when the value stack is empty" do
32
+ it "raises Whitespace::EmptyError" do
33
+ expect(@vm.vstack.size).must_equal 0
34
+
35
+ console = Whitespace::Console.new(stdin: @stdin)
36
+ expect { Readc.new(@vm, console).execute }.must_raise \
37
+ Whitespace::EmptyError
38
+ end
39
+ end
40
+
41
+ describe "when the value stack has at least 1 element" do
42
+ it "reads the character and places its integer value at the " \
43
+ "address in the heap given by the top of the stack" do
44
+ @vm.vstack.push :address
45
+ expect(@vm.vstack.size).must_equal 1
46
+
47
+ console = Whitespace::Console.new(stdin: @stdin)
48
+ Readc.new(@vm, console).execute
49
+
50
+ expect(@vm.memory[:address]).must_equal 65
51
+ expect(@vm.vstack.size).must_equal 0
52
+ end
53
+ end
54
+ end
55
+
56
+ describe "when it is not an ASCII character" do
57
+ it "raises ArgumentError" do
58
+ def @stdin.getc
59
+ "\a"
60
+ end
61
+
62
+ console = Whitespace::Console.new(stdin: @stdin)
63
+ e = expect { Readc.new(@vm, console).execute }.must_raise \
64
+ ArgumentError
65
+ expect(e.message).must_match /must be an ASCII character/
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,79 @@
1
+ require "test_helper"
2
+
3
+ module Whitespace::ISA
4
+ describe Readn do
5
+ before do
6
+ @vm = Whitespace::VM.new
7
+ @stdin = Object.new
8
+ end
9
+
10
+ describe "#execute" do
11
+ describe "when there is no character" do
12
+ it "raises ArgumentError" do
13
+ def @stdin.getc
14
+ end
15
+
16
+ console = Whitespace::Console.new(stdin: @stdin)
17
+ e = expect { Readn.new(@vm, console).execute }.must_raise \
18
+ ArgumentError
19
+ expect(e.message).must_match /must be an integer/
20
+ end
21
+ end
22
+
23
+ describe "when there is a character" do
24
+ describe "when it is an integer" do
25
+ before do
26
+ def @stdin.getc
27
+ @chars ||= ["-", "5", "\n"]
28
+ @i ||= 0
29
+
30
+ @i += 1
31
+ @chars[@i - 1]
32
+ end
33
+ end
34
+
35
+ describe "when the value stack is empty" do
36
+ it "raises Whitespace::EmptyError" do
37
+ expect(@vm.vstack.size).must_equal 0
38
+
39
+ console = Whitespace::Console.new(stdin: @stdin)
40
+ expect { Readn.new(@vm, console).execute }.must_raise \
41
+ Whitespace::EmptyError
42
+ end
43
+ end
44
+
45
+ describe "when the value stack has at least 1 element" do
46
+ it "reads the integer and places it at the address in the heap" \
47
+ "given by the top of the stack" do
48
+ @vm.vstack.push :address
49
+ expect(@vm.vstack.size).must_equal 1
50
+
51
+ console = Whitespace::Console.new(stdin: @stdin)
52
+ Readn.new(@vm, console).execute
53
+
54
+ expect(@vm.memory[:address]).must_equal -5
55
+ expect(@vm.vstack.size).must_equal 0
56
+ end
57
+ end
58
+ end
59
+
60
+ describe "when it is not an integer" do
61
+ it "raises ArgumentError" do
62
+ def @stdin.getc
63
+ @chars ||= ["x"]
64
+ @i ||= 0
65
+
66
+ @i += 1
67
+ @chars[@i - 1]
68
+ end
69
+
70
+ console = Whitespace::Console.new(stdin: @stdin)
71
+ e = expect { Readn.new(@vm, console).execute }.must_raise \
72
+ ArgumentError
73
+ expect(e.message).must_match /must be an integer/
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,30 @@
1
+ require "test_helper"
2
+
3
+ module Whitespace::ISA
4
+ describe Discard 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 { Discard.new(@vm).execute }.must_raise Whitespace::EmptyError
13
+ end
14
+ end
15
+
16
+ describe "when the value stack is not empty" do
17
+ it "discards the top element on the value stack" do
18
+ @vm.vstack.push 1
19
+ @vm.vstack.push 2
20
+ @vm.vstack.size.must_equal 2
21
+
22
+ Discard.new(@vm).execute
23
+
24
+ expect(@vm.vstack.pop).must_equal 1
25
+ expect(@vm.vstack.size).must_equal 0
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,32 @@
1
+ require "test_helper"
2
+
3
+ module Whitespace::ISA
4
+ describe Dup 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 { Dup.new(@vm).execute }.must_raise Whitespace::EmptyError
15
+ end
16
+ end
17
+
18
+ describe "when the value stack is not empty" do
19
+ it "duplicates the top element on the value stack" do
20
+ @vm.vstack.push 1
21
+ expect(@vm.vstack.size).must_equal 1
22
+
23
+ Dup.new(@vm).execute
24
+
25
+ expect(@vm.vstack.pop).must_equal 1
26
+ expect(@vm.vstack.pop).must_equal 1
27
+ expect(@vm.vstack.size).must_equal 0
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,30 @@
1
+ require "test_helper"
2
+
3
+ module Whitespace::ISA
4
+ describe Push do
5
+ before do
6
+ @vm = Whitespace::VM.new
7
+ end
8
+
9
+ describe "initialization" do
10
+ describe "when given a non-integer value" do
11
+ it "raises ArgumentError" do
12
+ e = expect { Push.new(@vm, "1") }.must_raise(ArgumentError)
13
+ e.message.must_match /must be an integer/
14
+ end
15
+ end
16
+ end
17
+
18
+ describe "#execute" do
19
+ it "pushes the integer onto the value stack" do
20
+ expect(@vm.vstack.size).must_equal 0
21
+
22
+ i = Push.new(@vm, 1)
23
+ i.execute
24
+
25
+ expect(@vm.vstack.pop).must_equal 1
26
+ expect(@vm.vstack.size).must_equal 0
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,43 @@
1
+ require "test_helper"
2
+
3
+ module Whitespace::ISA
4
+ describe Swap 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 { Swap.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 { Swap.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 "swaps the top two elements on the stack" 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
+ Swap.new(@vm).execute
35
+
36
+ expect(@vm.vstack.pop).must_equal 2
37
+ expect(@vm.vstack.pop).must_equal 3
38
+ expect(@vm.vstack.size).must_equal 1
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end