whitespace-ruby 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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,14 @@
1
+ module Whitespace
2
+ class Error < StandardError; end
3
+ class EmptyError < Error; end
4
+ class AddressError < Error; end
5
+ class LabelError < Error; end
6
+ class Halt < Error; end
7
+ class ParseError < Error; end
8
+ end
9
+
10
+ require_relative "whitespace/version"
11
+ require_relative "whitespace/util"
12
+ require_relative "whitespace/vm"
13
+ require_relative "whitespace/isa"
14
+ require_relative "whitespace/parser"
@@ -0,0 +1,56 @@
1
+ module Whitespace
2
+ class Console
3
+ attr_reader :stdin, :stdout
4
+
5
+ def initialize(stdin: $stdin, stdout: $stdout)
6
+ @stdin = stdin
7
+ @stdout = stdout
8
+ end
9
+
10
+ def printc(n)
11
+ unless Util.is_ascii?(n)
12
+ raise ArgumentError, "must be an ASCII character: #{n}"
13
+ end
14
+ stdout.print n.chr
15
+ end
16
+
17
+ def printn(n)
18
+ unless Util.is_integer?(n)
19
+ raise ArgumentError, "must be an integer: #{n}"
20
+ end
21
+ stdout.print n
22
+ end
23
+
24
+ def getc
25
+ if c = stdin.getc
26
+ unless Util.is_ascii?(c.ord)
27
+ raise ArgumentError, "must be an ASCII character: #{c}"
28
+ end
29
+ c
30
+ else
31
+ raise ArgumentError, "must be an ASCII character: EOF"
32
+ end
33
+ end
34
+
35
+ LINE_SEPARATOR = "\n"
36
+
37
+ def getn
38
+ input = ""
39
+ loop do
40
+ c = stdin.getc
41
+ break if c.nil?
42
+ input << c
43
+ break if c == LINE_SEPARATOR
44
+ end
45
+
46
+ raise ArgumentError, "must be an integer: EOF" if input.empty?
47
+
48
+ input = input.chomp(LINE_SEPARATOR)
49
+ begin
50
+ Integer input
51
+ rescue
52
+ raise ArgumentError, "must be an integer: #{input}"
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,24 @@
1
+ module Whitespace
2
+ class Counter
3
+ def initialize
4
+ @value = 0
5
+ end
6
+
7
+ def increment
8
+ @value += 1
9
+ end
10
+
11
+ def change_to(new_value)
12
+ new_value = new_value.to_i
13
+ if new_value >= 0
14
+ @value = new_value
15
+ else
16
+ raise ArgumentError, "must be non-negative: #{new_value}"
17
+ end
18
+ end
19
+
20
+ def to_int
21
+ @value
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,19 @@
1
+ module Whitespace
2
+ class Memory
3
+ def initialize
4
+ @store = {}
5
+ end
6
+
7
+ def [](address)
8
+ if @store.key?(address)
9
+ @store[address]
10
+ else
11
+ raise AddressError, "no such address exists: #{address}"
12
+ end
13
+ end
14
+
15
+ def []=(address, value)
16
+ @store[address] = value
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,25 @@
1
+ module Whitespace
2
+ class Stack
3
+ def initialize
4
+ @elements = []
5
+ end
6
+
7
+ def push(x)
8
+ @elements.push x
9
+ end
10
+
11
+ def pop
12
+ return @elements.pop unless @elements.empty?
13
+ raise EmptyError
14
+ end
15
+
16
+ def top
17
+ return @elements.last unless @elements.empty?
18
+ raise EmptyError
19
+ end
20
+
21
+ def size
22
+ @elements.size
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,9 @@
1
+ require_relative "binop"
2
+
3
+ module Whitespace::ISA
4
+ class Add < Binop
5
+ def initialize(vm)
6
+ super(vm, :add)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,18 @@
1
+ module Whitespace::ISA
2
+ class Binop < Instruction
3
+ def initialize(vm, op)
4
+ unless Whitespace::Util.is_binop?(op)
5
+ raise ArgumentError, "must be a binary operator: #{op}"
6
+ end
7
+ super(vm)
8
+ @op = op
9
+ end
10
+
11
+ def execute
12
+ right = vm.vstack.pop
13
+ left = vm.vstack.pop
14
+
15
+ vm.vstack.push Whitespace::Util::BINOPS[@op].call(left, right)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,9 @@
1
+ require_relative "binop"
2
+
3
+ module Whitespace::ISA
4
+ class Div < Binop
5
+ def initialize(vm)
6
+ super(vm, :div)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ require_relative "binop"
2
+
3
+ module Whitespace::ISA
4
+ class Mod < Binop
5
+ def initialize(vm)
6
+ super(vm, :mod)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ require_relative "binop"
2
+
3
+ module Whitespace::ISA
4
+ class Mul < Binop
5
+ def initialize(vm)
6
+ super(vm, :mul)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ require_relative "binop"
2
+
3
+ module Whitespace::ISA
4
+ class Sub < Binop
5
+ def initialize(vm)
6
+ super(vm, :sub)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ module Whitespace::ISA
2
+ class Call < Instruction
3
+ attr_reader :name
4
+
5
+ def initialize(vm, name)
6
+ unless Whitespace::Util.is_label?(name)
7
+ raise ArgumentError, "must be a label: #{name}"
8
+ end
9
+ super(vm)
10
+ @name = name
11
+ end
12
+
13
+ def execute
14
+ index = Whitespace::Util.find_label(vm.instructions, name)
15
+ vm.cstack.push vm.pc.to_int
16
+ vm.pc.change_to index + 1
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,7 @@
1
+ module Whitespace::ISA
2
+ class End < Instruction
3
+ def execute
4
+ raise Whitespace::Halt
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,16 @@
1
+ module Whitespace::ISA
2
+ class Label < Instruction
3
+ attr_reader :name
4
+
5
+ def initialize(vm, name)
6
+ unless Whitespace::Util.is_label?(name)
7
+ raise ArgumentError, "must be a label: #{name}"
8
+ end
9
+ super(vm)
10
+ @name = name
11
+ end
12
+
13
+ def execute
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ module Whitespace::ISA
2
+ class Njmp < Instruction
3
+ attr_reader :name
4
+
5
+ def initialize(vm, name)
6
+ unless Whitespace::Util.is_label?(name)
7
+ raise ArgumentError, "must be a label: #{name}"
8
+ end
9
+ super(vm)
10
+ @name = name
11
+ end
12
+
13
+ def execute
14
+ if vm.vstack.pop < 0
15
+ index = Whitespace::Util.find_label(vm.instructions, name)
16
+ vm.pc.change_to index + 1
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,7 @@
1
+ module Whitespace::ISA
2
+ class Return < Instruction
3
+ def execute
4
+ vm.pc.change_to vm.cstack.pop
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,18 @@
1
+ module Whitespace::ISA
2
+ class Ujmp < Instruction
3
+ attr_reader :name
4
+
5
+ def initialize(vm, name)
6
+ unless Whitespace::Util.is_label?(name)
7
+ raise ArgumentError, "must be a label: #{name}"
8
+ end
9
+ super(vm)
10
+ @name = name
11
+ end
12
+
13
+ def execute
14
+ index = Whitespace::Util.find_label(vm.instructions, name)
15
+ vm.pc.change_to index + 1
16
+ end
17
+ end
18
+ end