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.
- data/.gitignore +2 -0
- data/README.rdoc +47 -0
- data/Rakefile +42 -0
- data/VERSION +1 -0
- data/architecture.rdoc +112 -0
- data/examples/blastoff.rb +20 -0
- data/examples/hello_world.rb +8 -0
- data/koi-vm.gemspec +174 -0
- data/lib/.gitkeep +0 -0
- data/lib/koi-vm/accessors.rb +63 -0
- data/lib/koi-vm/core.rb +48 -0
- data/lib/koi-vm/exceptions.rb +8 -0
- data/lib/koi-vm/helpers.rb +5 -0
- data/lib/koi-vm/opcodes/_opcode_constants.rb +58 -0
- data/lib/koi-vm/opcodes/_value_constants.rb +10 -0
- data/lib/koi-vm/opcodes/comparative_operations/equal.rb +11 -0
- data/lib/koi-vm/opcodes/comparative_operations/greater_than.rb +14 -0
- data/lib/koi-vm/opcodes/comparative_operations/less_than.rb +14 -0
- data/lib/koi-vm/opcodes/control_operations/exit.rb +10 -0
- data/lib/koi-vm/opcodes/control_operations/no_op.rb +9 -0
- data/lib/koi-vm/opcodes/flow_control_operations/jump.rb +11 -0
- data/lib/koi-vm/opcodes/flow_control_operations/jump_if.rb +16 -0
- data/lib/koi-vm/opcodes/flow_control_operations/jump_unless.rb +16 -0
- data/lib/koi-vm/opcodes/function_operations/call.rb +13 -0
- data/lib/koi-vm/opcodes/function_operations/push_function.rb +15 -0
- data/lib/koi-vm/opcodes/function_operations/return.rb +11 -0
- data/lib/koi-vm/opcodes/function_operations/tailcall.rb +12 -0
- data/lib/koi-vm/opcodes/io_operations/gets.rb +10 -0
- data/lib/koi-vm/opcodes/io_operations/print.rb +13 -0
- data/lib/koi-vm/opcodes/math_operations/add.rb +14 -0
- data/lib/koi-vm/opcodes/math_operations/divide.rb +14 -0
- data/lib/koi-vm/opcodes/math_operations/multiply.rb +14 -0
- data/lib/koi-vm/opcodes/math_operations/subtract.rb +14 -0
- data/lib/koi-vm/opcodes/push_operations/push_bool.rb +12 -0
- data/lib/koi-vm/opcodes/push_operations/push_float.rb +12 -0
- data/lib/koi-vm/opcodes/push_operations/push_int.rb +12 -0
- data/lib/koi-vm/opcodes/push_operations/push_nil.rb +10 -0
- data/lib/koi-vm/opcodes/push_operations/push_string.rb +12 -0
- data/lib/koi-vm/opcodes/stack_operations/dup.rb +11 -0
- data/lib/koi-vm/opcodes/stack_operations/pop.rb +11 -0
- data/lib/koi-vm/opcodes/stack_operations/stksize.rb +10 -0
- data/lib/koi-vm/opcodes/stack_operations/swap.rb +11 -0
- data/lib/koi-vm/opcodes/stack_operations/top.rb +13 -0
- data/lib/koi-vm/opcodes/stack_operations/typeof.rb +16 -0
- data/lib/koi-vm/opcodes/string_operations/concat.rb +12 -0
- data/lib/koi-vm/opcodes/string_operations/strlen.rb +12 -0
- data/lib/koi-vm/opcodes/string_operations/to_string.rb +16 -0
- data/lib/koi-vm/opcodes/variable_operations/get_global.rb +10 -0
- data/lib/koi-vm/opcodes/variable_operations/get_local.rb +10 -0
- data/lib/koi-vm/opcodes/variable_operations/set_global.rb +11 -0
- data/lib/koi-vm/opcodes/variable_operations/set_local.rb +11 -0
- data/lib/koi-vm.rb +10 -0
- data/test/.gitkeep +0 -0
- data/test/performance/.gitignore +1 -0
- data/test/performance/simple_benchmark.rb +87 -0
- data/test/setup/test_unit_extensions.rb +21 -0
- data/test/test_helper.rb +13 -0
- data/test/unit/opcodes/comparative_operations/equal_test.rb +116 -0
- data/test/unit/opcodes/comparative_operations/greater_than_test.rb +53 -0
- data/test/unit/opcodes/comparative_operations/less_than_test.rb +53 -0
- data/test/unit/opcodes/control_operations/exit_test.rb +20 -0
- data/test/unit/opcodes/control_operations/no_op_test.rb +17 -0
- data/test/unit/opcodes/flow_control_operations/jump_if_test.rb +50 -0
- data/test/unit/opcodes/flow_control_operations/jump_test.rb +36 -0
- data/test/unit/opcodes/flow_control_operations/jump_unless_test.rb +50 -0
- data/test/unit/opcodes/function_operations/call_test.rb +39 -0
- data/test/unit/opcodes/function_operations/push_function_test.rb +21 -0
- data/test/unit/opcodes/function_operations/return_test.rb +31 -0
- data/test/unit/opcodes/function_operations/tailcall_test.rb +41 -0
- data/test/unit/opcodes/io_operations/gets_test.rb +38 -0
- data/test/unit/opcodes/io_operations/print_test.rb +42 -0
- data/test/unit/opcodes/math_operations/add_test.rb +62 -0
- data/test/unit/opcodes/math_operations/divide_test.rb +62 -0
- data/test/unit/opcodes/math_operations/multiply_test.rb +62 -0
- data/test/unit/opcodes/math_operations/subtract_test.rb +62 -0
- data/test/unit/opcodes/push_operations/push_bool_test.rb +36 -0
- data/test/unit/opcodes/push_operations/push_float_test.rb +27 -0
- data/test/unit/opcodes/push_operations/push_int_test.rb +27 -0
- data/test/unit/opcodes/push_operations/push_nil_test.rb +16 -0
- data/test/unit/opcodes/push_operations/push_string_test.rb +27 -0
- data/test/unit/opcodes/stack_operations/dup_test.rb +25 -0
- data/test/unit/opcodes/stack_operations/pop_test.rb +28 -0
- data/test/unit/opcodes/stack_operations/stksize_test.rb +20 -0
- data/test/unit/opcodes/stack_operations/swap_test.rb +36 -0
- data/test/unit/opcodes/stack_operations/top_test.rb +45 -0
- data/test/unit/opcodes/stack_operations/typeof_test.rb +61 -0
- data/test/unit/opcodes/string_operations/concat_test.rb +65 -0
- data/test/unit/opcodes/string_operations/strlen_test.rb +44 -0
- data/test/unit/opcodes/string_operations/to_string_test.rb +70 -0
- data/test/unit/opcodes/variable_operations/get_global_test.rb +18 -0
- data/test/unit/opcodes/variable_operations/get_local_test.rb +18 -0
- data/test/unit/opcodes/variable_operations/set_global_test.rb +27 -0
- data/test/unit/opcodes/variable_operations/set_local_test.rb +27 -0
- data/test/unit/vm_initialization_test.rb +86 -0
- 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
|