koi-vm 0.0.1

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 (95) hide show
  1. data/.gitignore +2 -0
  2. data/README.rdoc +47 -0
  3. data/Rakefile +42 -0
  4. data/VERSION +1 -0
  5. data/architecture.rdoc +112 -0
  6. data/examples/blastoff.rb +20 -0
  7. data/examples/hello_world.rb +8 -0
  8. data/koi-vm.gemspec +174 -0
  9. data/lib/.gitkeep +0 -0
  10. data/lib/koi-vm/accessors.rb +63 -0
  11. data/lib/koi-vm/core.rb +48 -0
  12. data/lib/koi-vm/exceptions.rb +8 -0
  13. data/lib/koi-vm/helpers.rb +5 -0
  14. data/lib/koi-vm/opcodes/_opcode_constants.rb +58 -0
  15. data/lib/koi-vm/opcodes/_value_constants.rb +10 -0
  16. data/lib/koi-vm/opcodes/comparative_operations/equal.rb +11 -0
  17. data/lib/koi-vm/opcodes/comparative_operations/greater_than.rb +14 -0
  18. data/lib/koi-vm/opcodes/comparative_operations/less_than.rb +14 -0
  19. data/lib/koi-vm/opcodes/control_operations/exit.rb +10 -0
  20. data/lib/koi-vm/opcodes/control_operations/no_op.rb +9 -0
  21. data/lib/koi-vm/opcodes/flow_control_operations/jump.rb +11 -0
  22. data/lib/koi-vm/opcodes/flow_control_operations/jump_if.rb +16 -0
  23. data/lib/koi-vm/opcodes/flow_control_operations/jump_unless.rb +16 -0
  24. data/lib/koi-vm/opcodes/function_operations/call.rb +13 -0
  25. data/lib/koi-vm/opcodes/function_operations/push_function.rb +15 -0
  26. data/lib/koi-vm/opcodes/function_operations/return.rb +11 -0
  27. data/lib/koi-vm/opcodes/function_operations/tailcall.rb +12 -0
  28. data/lib/koi-vm/opcodes/io_operations/gets.rb +10 -0
  29. data/lib/koi-vm/opcodes/io_operations/print.rb +13 -0
  30. data/lib/koi-vm/opcodes/math_operations/add.rb +14 -0
  31. data/lib/koi-vm/opcodes/math_operations/divide.rb +14 -0
  32. data/lib/koi-vm/opcodes/math_operations/multiply.rb +14 -0
  33. data/lib/koi-vm/opcodes/math_operations/subtract.rb +14 -0
  34. data/lib/koi-vm/opcodes/push_operations/push_bool.rb +12 -0
  35. data/lib/koi-vm/opcodes/push_operations/push_float.rb +12 -0
  36. data/lib/koi-vm/opcodes/push_operations/push_int.rb +12 -0
  37. data/lib/koi-vm/opcodes/push_operations/push_nil.rb +10 -0
  38. data/lib/koi-vm/opcodes/push_operations/push_string.rb +12 -0
  39. data/lib/koi-vm/opcodes/stack_operations/dup.rb +11 -0
  40. data/lib/koi-vm/opcodes/stack_operations/pop.rb +11 -0
  41. data/lib/koi-vm/opcodes/stack_operations/stksize.rb +10 -0
  42. data/lib/koi-vm/opcodes/stack_operations/swap.rb +11 -0
  43. data/lib/koi-vm/opcodes/stack_operations/top.rb +13 -0
  44. data/lib/koi-vm/opcodes/stack_operations/typeof.rb +16 -0
  45. data/lib/koi-vm/opcodes/string_operations/concat.rb +12 -0
  46. data/lib/koi-vm/opcodes/string_operations/strlen.rb +12 -0
  47. data/lib/koi-vm/opcodes/string_operations/to_string.rb +16 -0
  48. data/lib/koi-vm/opcodes/variable_operations/get_global.rb +10 -0
  49. data/lib/koi-vm/opcodes/variable_operations/get_local.rb +10 -0
  50. data/lib/koi-vm/opcodes/variable_operations/set_global.rb +11 -0
  51. data/lib/koi-vm/opcodes/variable_operations/set_local.rb +11 -0
  52. data/lib/koi-vm.rb +10 -0
  53. data/test/.gitkeep +0 -0
  54. data/test/performance/.gitignore +1 -0
  55. data/test/performance/simple_benchmark.rb +87 -0
  56. data/test/setup/test_unit_extensions.rb +21 -0
  57. data/test/test_helper.rb +13 -0
  58. data/test/unit/opcodes/comparative_operations/equal_test.rb +116 -0
  59. data/test/unit/opcodes/comparative_operations/greater_than_test.rb +53 -0
  60. data/test/unit/opcodes/comparative_operations/less_than_test.rb +53 -0
  61. data/test/unit/opcodes/control_operations/exit_test.rb +20 -0
  62. data/test/unit/opcodes/control_operations/no_op_test.rb +17 -0
  63. data/test/unit/opcodes/flow_control_operations/jump_if_test.rb +50 -0
  64. data/test/unit/opcodes/flow_control_operations/jump_test.rb +36 -0
  65. data/test/unit/opcodes/flow_control_operations/jump_unless_test.rb +50 -0
  66. data/test/unit/opcodes/function_operations/call_test.rb +39 -0
  67. data/test/unit/opcodes/function_operations/push_function_test.rb +21 -0
  68. data/test/unit/opcodes/function_operations/return_test.rb +31 -0
  69. data/test/unit/opcodes/function_operations/tailcall_test.rb +41 -0
  70. data/test/unit/opcodes/io_operations/gets_test.rb +38 -0
  71. data/test/unit/opcodes/io_operations/print_test.rb +42 -0
  72. data/test/unit/opcodes/math_operations/add_test.rb +62 -0
  73. data/test/unit/opcodes/math_operations/divide_test.rb +62 -0
  74. data/test/unit/opcodes/math_operations/multiply_test.rb +62 -0
  75. data/test/unit/opcodes/math_operations/subtract_test.rb +62 -0
  76. data/test/unit/opcodes/push_operations/push_bool_test.rb +36 -0
  77. data/test/unit/opcodes/push_operations/push_float_test.rb +27 -0
  78. data/test/unit/opcodes/push_operations/push_int_test.rb +27 -0
  79. data/test/unit/opcodes/push_operations/push_nil_test.rb +16 -0
  80. data/test/unit/opcodes/push_operations/push_string_test.rb +27 -0
  81. data/test/unit/opcodes/stack_operations/dup_test.rb +25 -0
  82. data/test/unit/opcodes/stack_operations/pop_test.rb +28 -0
  83. data/test/unit/opcodes/stack_operations/stksize_test.rb +20 -0
  84. data/test/unit/opcodes/stack_operations/swap_test.rb +36 -0
  85. data/test/unit/opcodes/stack_operations/top_test.rb +45 -0
  86. data/test/unit/opcodes/stack_operations/typeof_test.rb +61 -0
  87. data/test/unit/opcodes/string_operations/concat_test.rb +65 -0
  88. data/test/unit/opcodes/string_operations/strlen_test.rb +44 -0
  89. data/test/unit/opcodes/string_operations/to_string_test.rb +70 -0
  90. data/test/unit/opcodes/variable_operations/get_global_test.rb +18 -0
  91. data/test/unit/opcodes/variable_operations/get_local_test.rb +18 -0
  92. data/test/unit/opcodes/variable_operations/set_global_test.rb +27 -0
  93. data/test/unit/opcodes/variable_operations/set_local_test.rb +27 -0
  94. data/test/unit/vm_initialization_test.rb +86 -0
  95. metadata +200 -0
@@ -0,0 +1,116 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper.rb'))
2
+
3
+ class EqualTest < Test::Unit::TestCase
4
+
5
+ include KoiVM
6
+
7
+ test "should push bool value onto stack representing equality of topmost 2 stack items (true int)" do
8
+ vm = VM.new
9
+ vm.data_stack = [[INTEGER_, 2],[INTEGER_, 2]]
10
+ vm.run [
11
+ EQUAL
12
+ ]
13
+ assert_equal [[BOOL_, true]], vm.data_stack
14
+ end
15
+
16
+ test "should push bool value onto stack representing equality of topmost 2 stack items (false int)" do
17
+ vm = VM.new
18
+ vm.data_stack = [[INTEGER_, 2],[INTEGER_, 1]]
19
+ vm.run [
20
+ EQUAL
21
+ ]
22
+ assert_equal [[BOOL_, false]], vm.data_stack
23
+ end
24
+
25
+ test "should push bool value onto stack representing equality of topmost 2 stack items (true nil)" do
26
+ vm = VM.new
27
+ vm.data_stack = [[NIL_, nil],[NIL_, nil]]
28
+ vm.run [
29
+ EQUAL
30
+ ]
31
+ assert_equal [[BOOL_, true]], vm.data_stack
32
+ end
33
+
34
+ test "should push bool value onto stack representing equality of topmost 2 stack items (false nil)" do
35
+ vm = VM.new
36
+ vm.data_stack = [[NIL_, 2],[INTEGER_, 1]]
37
+ vm.run [
38
+ EQUAL
39
+ ]
40
+ assert_equal [[BOOL_, false]], vm.data_stack
41
+ end
42
+
43
+ test "should push bool value onto stack representing equality of topmost 2 stack items (true float)" do
44
+ vm = VM.new
45
+ vm.data_stack = [[FLOAT_, 2.0],[FLOAT_, 2.0]]
46
+ vm.run [
47
+ EQUAL
48
+ ]
49
+ assert_equal [[BOOL_, true]], vm.data_stack
50
+ end
51
+
52
+ test "should push bool value onto stack representing equality of topmost 2 stack items (false float)" do
53
+ vm = VM.new
54
+ vm.data_stack = [[FLOAT_, 2.0],[FLOAT_, 1.0]]
55
+ vm.run [
56
+ EQUAL
57
+ ]
58
+ assert_equal [[BOOL_, false]], vm.data_stack
59
+ end
60
+
61
+ test "should push bool value onto stack representing equality of topmost 2 stack items (true bool)" do
62
+ vm = VM.new
63
+ vm.data_stack = [[BOOL_, true],[BOOL_, true]]
64
+ vm.run [
65
+ EQUAL
66
+ ]
67
+ assert_equal [[BOOL_, true]], vm.data_stack
68
+ end
69
+
70
+ test "should push bool value onto stack representing equality of topmost 2 stack items (false bool)" do
71
+ vm = VM.new
72
+ vm.data_stack = [[BOOL_, true],[BOOL_, false]]
73
+ vm.run [
74
+ EQUAL
75
+ ]
76
+ assert_equal [[BOOL_, false]], vm.data_stack
77
+ end
78
+
79
+ test "should push bool value onto stack representing equality of topmost 2 stack items (true string)" do
80
+ vm = VM.new
81
+ vm.data_stack = [[STRING_, "hi"],[STRING_, "hi"]]
82
+ vm.run [
83
+ EQUAL
84
+ ]
85
+ assert_equal [[BOOL_, true]], vm.data_stack
86
+ end
87
+
88
+ test "should push bool value onto stack representing equality of topmost 2 stack items (false string)" do
89
+ vm = VM.new
90
+ vm.data_stack = [[STRING_, "hi"],[STRING_, ""]]
91
+ vm.run [
92
+ EQUAL
93
+ ]
94
+ assert_equal [[BOOL_, false]], vm.data_stack
95
+ end
96
+
97
+ test "should raise StackError if there are less than 2 items on the stack" do
98
+ assert_raises StackError do
99
+ vm = VM.new
100
+ vm.data_stack = [1]
101
+ vm.run [
102
+ EQUAL
103
+ ]
104
+ end
105
+ end
106
+
107
+ test "should raise StackError if there are no items on the stack" do
108
+ assert_raises StackError do
109
+ vm = VM.new
110
+ vm.run [
111
+ EQUAL
112
+ ]
113
+ end
114
+ end
115
+
116
+ end
@@ -0,0 +1,53 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper.rb'))
2
+
3
+ class GreaterThanTest < Test::Unit::TestCase
4
+
5
+ include KoiVM
6
+
7
+ test "should push bool value onto stack representing whether stack[-2] > stack[-1] (2 2)" do
8
+ vm = VM.new
9
+ vm.data_stack = [[INTEGER_, 2],[INTEGER_, 2]]
10
+ vm.run [
11
+ GREATER_THAN
12
+ ]
13
+ assert_equal [[BOOL_, false]], vm.data_stack
14
+ end
15
+
16
+ test "should push bool value onto stack representing whether stack[-2] > stack[-1] (1 2)" do
17
+ vm = VM.new
18
+ vm.data_stack = [[INTEGER_, 1],[INTEGER_, 2]]
19
+ vm.run [
20
+ GREATER_THAN
21
+ ]
22
+ assert_equal [[BOOL_, false]], vm.data_stack
23
+ end
24
+
25
+ test "should push bool value onto stack representing whether stack[-2] > stack[-1] (3 2)" do
26
+ vm = VM.new
27
+ vm.data_stack = [[INTEGER_, 3],[INTEGER_, 2]]
28
+ vm.run [
29
+ GREATER_THAN
30
+ ]
31
+ assert_equal [[BOOL_, true]], vm.data_stack
32
+ end
33
+
34
+ test "should raise StackError if there are less than 2 items on the stack" do
35
+ assert_raises StackError do
36
+ vm = VM.new
37
+ vm.data_stack = [1]
38
+ vm.run [
39
+ GREATER_THAN
40
+ ]
41
+ end
42
+ end
43
+
44
+ test "should raise StackError if there are no items on the stack" do
45
+ assert_raises StackError do
46
+ vm = VM.new
47
+ vm.run [
48
+ GREATER_THAN
49
+ ]
50
+ end
51
+ end
52
+
53
+ end
@@ -0,0 +1,53 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper.rb'))
2
+
3
+ class LessThanTest < Test::Unit::TestCase
4
+
5
+ include KoiVM
6
+
7
+ test "should push bool value onto stack representing whether stack[-2] < stack[-1] (2 2)" do
8
+ vm = VM.new
9
+ vm.data_stack = [[INTEGER_, 2],[INTEGER_, 2]]
10
+ vm.run [
11
+ LESS_THAN
12
+ ]
13
+ assert_equal [[BOOL_, false]], vm.data_stack
14
+ end
15
+
16
+ test "should push bool value onto stack representing whether stack[-2] < stack[-1] (1 2)" do
17
+ vm = VM.new
18
+ vm.data_stack = [[INTEGER_, 1],[INTEGER_, 2]]
19
+ vm.run [
20
+ LESS_THAN
21
+ ]
22
+ assert_equal [[BOOL_, true]], vm.data_stack
23
+ end
24
+
25
+ test "should push bool value onto stack representing whether stack[-2] < stack[-1] (3 2)" do
26
+ vm = VM.new
27
+ vm.data_stack = [[INTEGER_, 3],[INTEGER_, 2]]
28
+ vm.run [
29
+ LESS_THAN
30
+ ]
31
+ assert_equal [[BOOL_, false]], vm.data_stack
32
+ end
33
+
34
+ test "should raise StackError if there are less than 2 items on the stack" do
35
+ assert_raises StackError do
36
+ vm = VM.new
37
+ vm.data_stack = [1]
38
+ vm.run [
39
+ LESS_THAN
40
+ ]
41
+ end
42
+ end
43
+
44
+ test "should raise StackError if there are no items on the stack" do
45
+ assert_raises StackError do
46
+ vm = VM.new
47
+ vm.run [
48
+ LESS_THAN
49
+ ]
50
+ end
51
+ end
52
+
53
+ end
@@ -0,0 +1,20 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper.rb'))
2
+
3
+ class ExitTest < Test::Unit::TestCase
4
+
5
+ include KoiVM
6
+
7
+ test "should exit" do
8
+ vm = VM.new
9
+ vm.run [
10
+ EXIT,
11
+ NO_OP,
12
+ NO_OP,
13
+ NO_OP
14
+ ]
15
+ assert_equal [], vm.data_stack
16
+ assert_equal 1, vm.instruction_pointer
17
+ end
18
+
19
+
20
+ end
@@ -0,0 +1,17 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper.rb'))
2
+
3
+ class NoOpTest < Test::Unit::TestCase
4
+
5
+ include KoiVM
6
+
7
+ test "should perform no-op" do
8
+ vm = VM.new
9
+ vm.run [
10
+ NO_OP
11
+ ]
12
+ assert_equal [], vm.data_stack
13
+ assert_equal 1, vm.instruction_pointer
14
+ end
15
+
16
+
17
+ end
@@ -0,0 +1,50 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper.rb'))
2
+
3
+ class JumpIfTest < Test::Unit::TestCase
4
+
5
+ include KoiVM
6
+
7
+ test "should set instruction_pointer to 10 when data_stack[0] != (false || nil)" do
8
+ [[INTEGER_, 0], [STRING_, ""], [BOOL_, true]].each do |x|
9
+ vm = VM.new
10
+ vm.data_stack = [x]
11
+ vm.run [
12
+ JUMP_IF, 10
13
+ ]
14
+ assert_equal 10, vm.instruction_pointer
15
+ end
16
+ end
17
+
18
+ test "should not set instruction_pointer to 10 when data_stack[0] == (false || nil)" do
19
+ [[NIL_, nil], [BOOL_, false]].each do |x|
20
+ vm = VM.new
21
+ vm.data_stack = [x]
22
+ vm.run [
23
+ JUMP_IF, 10
24
+ ]
25
+ assert_equal 2, vm.instruction_pointer
26
+ end
27
+ end
28
+
29
+ test "should raise error if there is not at least 1 item on the data stack" do
30
+ assert_raises StackError do
31
+ vm = VM.new
32
+ vm.run [
33
+ JUMP_IF, 20
34
+ ]
35
+ end
36
+ end
37
+
38
+ test "should raise error if operand is not an integer" do
39
+ [false, 2.0 ,"string", [1], {:t=>1}].each do |x|
40
+ assert_raises OperandError do
41
+ vm = VM.new
42
+ vm.data_stack = [[BOOL_, true]]
43
+ vm.run [
44
+ JUMP_IF, x
45
+ ]
46
+ end
47
+ end
48
+ end
49
+
50
+ end
@@ -0,0 +1,36 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper.rb'))
2
+
3
+ class JumpTest < Test::Unit::TestCase
4
+
5
+ include KoiVM
6
+
7
+ test "should set instruction_pointer to 10" do
8
+ vm = VM.new
9
+ vm.run [
10
+ JUMP, 10
11
+ ]
12
+ assert_equal 10, vm.instruction_pointer
13
+ end
14
+
15
+ test "should set instruction_pointer to 11" do
16
+ vm = VM.new
17
+ vm.instruction_pointer = 1
18
+ vm.run [
19
+ 0,
20
+ JUMP, 10
21
+ ]
22
+ assert_equal 11, vm.instruction_pointer
23
+ end
24
+
25
+ test "should raise error if operand is not an integer" do
26
+ [false, 2.0 ,"string", [1], {:t=>1}].each do |x|
27
+ assert_raises OperandError do
28
+ vm = VM.new
29
+ vm.run [
30
+ JUMP, x
31
+ ]
32
+ end
33
+ end
34
+ end
35
+
36
+ end
@@ -0,0 +1,50 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper.rb'))
2
+
3
+ class JumpUnlessTest < Test::Unit::TestCase
4
+
5
+ include KoiVM
6
+
7
+ test "should not set instruction_pointer to 10 when data_stack[0] != (false || nil)" do
8
+ [[INTEGER_, 0], [STRING_, ""], [BOOL_, true]].each do |x|
9
+ vm = VM.new
10
+ vm.data_stack = [x]
11
+ vm.run [
12
+ JUMP_UNLESS, 10
13
+ ]
14
+ assert_equal 2, vm.instruction_pointer
15
+ end
16
+ end
17
+
18
+ test "should set instruction_pointer to 10 when data_stack[0] == (false || nil)" do
19
+ [[NIL_, nil], [BOOL_, false]].each do |x|
20
+ vm = VM.new
21
+ vm.data_stack = [x]
22
+ vm.run [
23
+ JUMP_UNLESS, 10
24
+ ]
25
+ assert_equal 10, vm.instruction_pointer
26
+ end
27
+ end
28
+
29
+ test "should raise error if there is not at least 1 item on the data stack" do
30
+ assert_raises StackError do
31
+ vm = VM.new
32
+ vm.run [
33
+ JUMP_IF, 20
34
+ ]
35
+ end
36
+ end
37
+
38
+ test "should raise error if operand is not an integer" do
39
+ [false, 2.0 ,"string", [1], {:t=>1}].each do |x|
40
+ assert_raises OperandError do
41
+ vm = VM.new
42
+ vm.data_stack = [[BOOL_, true]]
43
+ vm.run [
44
+ JUMP_UNLESS, x
45
+ ]
46
+ end
47
+ end
48
+ end
49
+
50
+ end
@@ -0,0 +1,39 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper.rb'))
2
+
3
+ class CallTest < Test::Unit::TestCase
4
+
5
+ include KoiVM
6
+
7
+ test "should pass execution to function and push return position on the return stack" do
8
+ vm = VM.new
9
+ vm.data_stack = [[FUNCTION_, 101]]
10
+ vm.run [
11
+ CALL
12
+ ]
13
+ assert_equal [], vm.data_stack
14
+ assert_equal [1], vm.return_stack
15
+ assert_equal 101, vm.instruction_pointer
16
+ assert_equal 1, vm.level
17
+ end
18
+
19
+ test "should raise StackError if there are no items on the stack" do
20
+ assert_raises StackError do
21
+ vm = VM.new
22
+ vm.run [
23
+ CALL
24
+ ]
25
+ end
26
+ end
27
+
28
+ test "should raise StackError if topmost stack item is not a function" do
29
+ assert_raises StackError do
30
+ vm = VM.new
31
+ vm.data_stack = [[INTEGER_, 101]]
32
+ vm.run [
33
+ CALL
34
+ ]
35
+ end
36
+ end
37
+
38
+
39
+ end
@@ -0,0 +1,21 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper.rb'))
2
+
3
+ class PushFunctionTest < Test::Unit::TestCase
4
+
5
+ include KoiVM
6
+
7
+ test "should push function reference onto stack" do
8
+ vm = VM.new
9
+ vm.run [
10
+ PUSH_FUNCTION, 1,
11
+ NO_OP,
12
+ NO_OP,
13
+ END_FUNCTION, 0,
14
+ END_FUNCTION, 1
15
+ ]
16
+ assert_equal [[FUNCTION_, 2]], vm.data_stack
17
+ assert_equal 8, vm.instruction_pointer
18
+ end
19
+
20
+
21
+ end
@@ -0,0 +1,31 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper.rb'))
2
+
3
+ class ReturnTest < Test::Unit::TestCase
4
+
5
+ include KoiVM
6
+
7
+ test "should pass execution to topmost address on return stack and decrement scope" do
8
+ vm = VM.new
9
+ vm.return_stack = [101]
10
+ assert_equal [101], vm.return_stack
11
+ vm.level = 1
12
+ vm.run [
13
+ RETURN
14
+ ]
15
+ assert_equal [], vm.data_stack
16
+ assert_equal [], vm.return_stack
17
+ assert_equal 101, vm.instruction_pointer
18
+ assert_equal 0, vm.level
19
+ end
20
+
21
+ test "should raise ReturnStackError if there are no items on the return stack" do
22
+ assert_raises ReturnStackError do
23
+ vm = VM.new
24
+ vm.run [
25
+ RETURN
26
+ ]
27
+ end
28
+ end
29
+
30
+
31
+ end
@@ -0,0 +1,41 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper.rb'))
2
+
3
+ class TailcallTest < Test::Unit::TestCase
4
+
5
+ include KoiVM
6
+
7
+ test "should pass execution to new function without altering return stack, and reload scope" do
8
+ vm = VM.new
9
+ vm.data_stack = [[FUNCTION_, 101]]
10
+ vm.level = 1
11
+ vm.return_stack = [1]
12
+ vm.run [
13
+ TAILCALL
14
+ ]
15
+ assert_equal [], vm.data_stack
16
+ assert_equal [1], vm.return_stack
17
+ assert_equal 101, vm.instruction_pointer
18
+ assert_equal 1, vm.level
19
+ end
20
+
21
+ test "should raise StackError if there are no items on the stack" do
22
+ assert_raises StackError do
23
+ vm = VM.new
24
+ vm.run [
25
+ TAILCALL
26
+ ]
27
+ end
28
+ end
29
+
30
+ test "should raise StackError if topmost stack item is not a function" do
31
+ assert_raises StackError do
32
+ vm = VM.new
33
+ vm.data_stack = [[INTEGER_, 101]]
34
+ vm.run [
35
+ TAILCALL
36
+ ]
37
+ end
38
+ end
39
+
40
+
41
+ end
@@ -0,0 +1,38 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper.rb'))
2
+
3
+ class GetsTest < Test::Unit::TestCase
4
+
5
+ include KoiVM
6
+
7
+ require "stringio"
8
+
9
+ test "should get string from stdin and push it onto stack as a string" do
10
+ input = "Test"
11
+ old_stdin = $stdin
12
+ buffer = StringIO.new
13
+ $stdin = buffer
14
+ buffer.string = input
15
+ vm = VM.new
16
+ vm.run [
17
+ GETS
18
+ ]
19
+ assert_equal [[STRING_, input]], vm.data_stack
20
+ $stdin = old_stdin
21
+ end
22
+
23
+ test "should get newline separated strings from stdin and push onto stack as a string" do
24
+ input = "Test\nstring"
25
+ old_stdin = $stdin
26
+ buffer = StringIO.new
27
+ $stdin = buffer
28
+ buffer.string = input
29
+ vm = VM.new
30
+ vm.run [
31
+ GETS,
32
+ GETS
33
+ ]
34
+ assert_equal [[STRING_, "Test\n"], [STRING_, "string"]], vm.data_stack
35
+ $stdin = old_stdin
36
+ end
37
+
38
+ end
@@ -0,0 +1,42 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper.rb'))
2
+
3
+ class PrintTest < Test::Unit::TestCase
4
+
5
+ include KoiVM
6
+
7
+ require "stringio"
8
+
9
+ test "should print topmost string value from stack" do
10
+ old_stdout = $stdout
11
+ buffer = StringIO.new
12
+ $stdout = buffer
13
+ vm = VM.new
14
+ vm.data_stack = [[STRING_, "test"]]
15
+ vm.run [
16
+ PRINT
17
+ ]
18
+ assert_equal [], vm.data_stack
19
+ assert_equal "test", buffer.string
20
+ $stdout = old_stdout
21
+ end
22
+
23
+ test "should raise StackError if topmost item is not a string" do
24
+ assert_raises StackError do
25
+ vm = VM.new
26
+ vm.data_stack = [[INTEGER_, 1]]
27
+ vm.run [
28
+ PRINT
29
+ ]
30
+ end
31
+ end
32
+
33
+ test "should raise StackError if there are no items on the stack" do
34
+ assert_raises StackError do
35
+ vm = VM.new
36
+ vm.run [
37
+ PRINT
38
+ ]
39
+ end
40
+ end
41
+
42
+ end
@@ -0,0 +1,62 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper.rb'))
2
+
3
+ class AddTest < Test::Unit::TestCase
4
+
5
+ include KoiVM
6
+
7
+ test "should add top two integers on stack" do
8
+ vm = VM.new
9
+ vm.data_stack = [[INTEGER_, 9], [INTEGER_, 9]]
10
+ vm.run [
11
+ ADD
12
+ ]
13
+ assert_equal [[INTEGER_, 18]], vm.data_stack
14
+ end
15
+
16
+ test "should add top two floats on stack" do
17
+ vm = VM.new
18
+ vm.data_stack = [[FLOAT_, 9.0], [FLOAT_, 9.0]]
19
+ vm.run [
20
+ ADD
21
+ ]
22
+ assert_equal [[FLOAT_, 18.0]], vm.data_stack
23
+ end
24
+
25
+ test "should add top two numbers on stack and implicitly convert them to floats" do
26
+ vm = VM.new
27
+ vm.data_stack = [[INTEGER_, 9], [FLOAT_, 9.0]]
28
+ vm.run [
29
+ ADD
30
+ ]
31
+ assert_equal [[FLOAT_, 18.0]], vm.data_stack
32
+ end
33
+
34
+ test "should add top two numbers on stack and implicitly convert them to floats if receiver is a float" do
35
+ vm = VM.new
36
+ vm.data_stack = [[FLOAT_, 9.0], [INTEGER_, 9]]
37
+ vm.run [
38
+ ADD
39
+ ]
40
+ assert_equal [[FLOAT_, 18.0]], vm.data_stack
41
+ end
42
+
43
+ test "should raise StackError if there is only one item on the stack" do
44
+ assert_raises StackError do
45
+ vm = VM.new
46
+ vm.data_stack = [1]
47
+ vm.run [
48
+ ADD
49
+ ]
50
+ end
51
+ end
52
+
53
+ test "should raise StackError if there are no items on the stack" do
54
+ assert_raises StackError do
55
+ vm = VM.new
56
+ vm.run [
57
+ ADD
58
+ ]
59
+ end
60
+ end
61
+
62
+ end