koi-vm-ruby 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. data/.gitignore +2 -0
  2. data/README.rdoc +64 -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 +198 -0
  9. data/lib/.gitkeep +0 -0
  10. data/lib/koi-vm-ruby.rb +10 -0
  11. data/lib/koi-vm-ruby/accessors.rb +63 -0
  12. data/lib/koi-vm-ruby/core.rb +48 -0
  13. data/lib/koi-vm-ruby/exceptions.rb +8 -0
  14. data/lib/koi-vm-ruby/helpers.rb +5 -0
  15. data/lib/koi-vm-ruby/opcodes/_opcode_constants.rb +68 -0
  16. data/lib/koi-vm-ruby/opcodes/_value_constants.rb +11 -0
  17. data/lib/koi-vm-ruby/opcodes/comparative_operations/equal.rb +11 -0
  18. data/lib/koi-vm-ruby/opcodes/comparative_operations/greater_than.rb +14 -0
  19. data/lib/koi-vm-ruby/opcodes/comparative_operations/invert.rb +12 -0
  20. data/lib/koi-vm-ruby/opcodes/comparative_operations/less_than.rb +14 -0
  21. data/lib/koi-vm-ruby/opcodes/control_operations/exit.rb +10 -0
  22. data/lib/koi-vm-ruby/opcodes/control_operations/no_op.rb +9 -0
  23. data/lib/koi-vm-ruby/opcodes/flow_control_operations/jump.rb +11 -0
  24. data/lib/koi-vm-ruby/opcodes/flow_control_operations/jump_if.rb +16 -0
  25. data/lib/koi-vm-ruby/opcodes/flow_control_operations/jump_unless.rb +16 -0
  26. data/lib/koi-vm-ruby/opcodes/function_operations/call.rb +13 -0
  27. data/lib/koi-vm-ruby/opcodes/function_operations/push_function.rb +19 -0
  28. data/lib/koi-vm-ruby/opcodes/function_operations/return.rb +11 -0
  29. data/lib/koi-vm-ruby/opcodes/function_operations/tailcall.rb +12 -0
  30. data/lib/koi-vm-ruby/opcodes/hash_operations/get_key.rb +14 -0
  31. data/lib/koi-vm-ruby/opcodes/hash_operations/has_key.rb +18 -0
  32. data/lib/koi-vm-ruby/opcodes/hash_operations/length.rb +19 -0
  33. data/lib/koi-vm-ruby/opcodes/hash_operations/num_pairs.rb +12 -0
  34. data/lib/koi-vm-ruby/opcodes/hash_operations/pairs.rb +22 -0
  35. data/lib/koi-vm-ruby/opcodes/hash_operations/push_hash.rb +10 -0
  36. data/lib/koi-vm-ruby/opcodes/hash_operations/set_key.rb +14 -0
  37. data/lib/koi-vm-ruby/opcodes/io_operations/gets.rb +10 -0
  38. data/lib/koi-vm-ruby/opcodes/io_operations/print.rb +13 -0
  39. data/lib/koi-vm-ruby/opcodes/math_operations/add.rb +14 -0
  40. data/lib/koi-vm-ruby/opcodes/math_operations/divide.rb +14 -0
  41. data/lib/koi-vm-ruby/opcodes/math_operations/multiply.rb +14 -0
  42. data/lib/koi-vm-ruby/opcodes/math_operations/subtract.rb +14 -0
  43. data/lib/koi-vm-ruby/opcodes/push_operations/push_bool.rb +12 -0
  44. data/lib/koi-vm-ruby/opcodes/push_operations/push_float.rb +12 -0
  45. data/lib/koi-vm-ruby/opcodes/push_operations/push_int.rb +12 -0
  46. data/lib/koi-vm-ruby/opcodes/push_operations/push_nil.rb +10 -0
  47. data/lib/koi-vm-ruby/opcodes/push_operations/push_string.rb +12 -0
  48. data/lib/koi-vm-ruby/opcodes/stack_operations/dup.rb +11 -0
  49. data/lib/koi-vm-ruby/opcodes/stack_operations/pop.rb +11 -0
  50. data/lib/koi-vm-ruby/opcodes/stack_operations/stksize.rb +10 -0
  51. data/lib/koi-vm-ruby/opcodes/stack_operations/swap.rb +11 -0
  52. data/lib/koi-vm-ruby/opcodes/stack_operations/top.rb +13 -0
  53. data/lib/koi-vm-ruby/opcodes/stack_operations/typeof.rb +18 -0
  54. data/lib/koi-vm-ruby/opcodes/string_operations/concat.rb +12 -0
  55. data/lib/koi-vm-ruby/opcodes/string_operations/strlen.rb +12 -0
  56. data/lib/koi-vm-ruby/opcodes/string_operations/to_string.rb +16 -0
  57. data/lib/koi-vm-ruby/opcodes/variable_operations/get_global.rb +10 -0
  58. data/lib/koi-vm-ruby/opcodes/variable_operations/get_local.rb +10 -0
  59. data/lib/koi-vm-ruby/opcodes/variable_operations/set_global.rb +11 -0
  60. data/lib/koi-vm-ruby/opcodes/variable_operations/set_local.rb +11 -0
  61. data/test/.gitkeep +0 -0
  62. data/test/performance/.gitignore +1 -0
  63. data/test/performance/simple_benchmark.rb +87 -0
  64. data/test/setup/test_unit_extensions.rb +21 -0
  65. data/test/test_helper.rb +13 -0
  66. data/test/unit/opcodes/comparative_operations/equal_test.rb +116 -0
  67. data/test/unit/opcodes/comparative_operations/greater_than_test.rb +53 -0
  68. data/test/unit/opcodes/comparative_operations/invert_test.rb +44 -0
  69. data/test/unit/opcodes/comparative_operations/less_than_test.rb +53 -0
  70. data/test/unit/opcodes/control_operations/exit_test.rb +20 -0
  71. data/test/unit/opcodes/control_operations/no_op_test.rb +17 -0
  72. data/test/unit/opcodes/flow_control_operations/jump_if_test.rb +50 -0
  73. data/test/unit/opcodes/flow_control_operations/jump_test.rb +36 -0
  74. data/test/unit/opcodes/flow_control_operations/jump_unless_test.rb +50 -0
  75. data/test/unit/opcodes/function_operations/call_test.rb +39 -0
  76. data/test/unit/opcodes/function_operations/push_function_test.rb +41 -0
  77. data/test/unit/opcodes/function_operations/return_test.rb +31 -0
  78. data/test/unit/opcodes/function_operations/tailcall_test.rb +41 -0
  79. data/test/unit/opcodes/hash_operations/get_key_test.rb +56 -0
  80. data/test/unit/opcodes/hash_operations/has_key_test.rb +56 -0
  81. data/test/unit/opcodes/hash_operations/length_test.rb +46 -0
  82. data/test/unit/opcodes/hash_operations/num_pairs_test.rb +46 -0
  83. data/test/unit/opcodes/hash_operations/pairs_test.rb +67 -0
  84. data/test/unit/opcodes/hash_operations/push_hash_test.rb +16 -0
  85. data/test/unit/opcodes/hash_operations/set_key_test.rb +56 -0
  86. data/test/unit/opcodes/io_operations/gets_test.rb +38 -0
  87. data/test/unit/opcodes/io_operations/print_test.rb +42 -0
  88. data/test/unit/opcodes/math_operations/add_test.rb +62 -0
  89. data/test/unit/opcodes/math_operations/divide_test.rb +62 -0
  90. data/test/unit/opcodes/math_operations/multiply_test.rb +62 -0
  91. data/test/unit/opcodes/math_operations/subtract_test.rb +62 -0
  92. data/test/unit/opcodes/push_operations/push_bool_test.rb +36 -0
  93. data/test/unit/opcodes/push_operations/push_float_test.rb +27 -0
  94. data/test/unit/opcodes/push_operations/push_int_test.rb +27 -0
  95. data/test/unit/opcodes/push_operations/push_nil_test.rb +16 -0
  96. data/test/unit/opcodes/push_operations/push_string_test.rb +27 -0
  97. data/test/unit/opcodes/stack_operations/dup_test.rb +25 -0
  98. data/test/unit/opcodes/stack_operations/pop_test.rb +28 -0
  99. data/test/unit/opcodes/stack_operations/stksize_test.rb +20 -0
  100. data/test/unit/opcodes/stack_operations/swap_test.rb +36 -0
  101. data/test/unit/opcodes/stack_operations/top_test.rb +45 -0
  102. data/test/unit/opcodes/stack_operations/typeof_test.rb +79 -0
  103. data/test/unit/opcodes/string_operations/concat_test.rb +65 -0
  104. data/test/unit/opcodes/string_operations/strlen_test.rb +44 -0
  105. data/test/unit/opcodes/string_operations/to_string_test.rb +70 -0
  106. data/test/unit/opcodes/variable_operations/get_global_test.rb +18 -0
  107. data/test/unit/opcodes/variable_operations/get_local_test.rb +18 -0
  108. data/test/unit/opcodes/variable_operations/set_global_test.rb +27 -0
  109. data/test/unit/opcodes/variable_operations/set_local_test.rb +27 -0
  110. data/test/unit/vm_initialization_test.rb +86 -0
  111. metadata +224 -0
File without changes
@@ -0,0 +1,10 @@
1
+ require_files = []
2
+
3
+ require_files << File.join(File.dirname(__FILE__), "koi-vm-ruby", "core.rb")
4
+ require_files << File.join(File.dirname(__FILE__), "koi-vm-ruby", "helpers.rb")
5
+ require_files << File.join(File.dirname(__FILE__), "koi-vm-ruby", "exceptions.rb")
6
+ require_files.concat Dir[File.join(File.dirname(__FILE__), 'koi-vm-ruby', '**', '*.rb')]
7
+
8
+ require_files.each do |file|
9
+ require File.expand_path(file)
10
+ end
@@ -0,0 +1,63 @@
1
+ module KoiVMRuby
2
+ class VM
3
+
4
+ def data_stack
5
+ return @state[:fiber][:data_stack]
6
+ end
7
+
8
+ def data_stack=(stack)
9
+ @state[:fiber][:data_stack] = stack
10
+ end
11
+
12
+ def return_stack
13
+ return @state[:fiber][:return_stack]
14
+ end
15
+
16
+ def return_stack=(stack)
17
+ @state[:fiber][:return_stack] = stack
18
+ end
19
+
20
+ def instruction_pointer
21
+ return @state[:fiber][:instruction_pointer]
22
+ end
23
+
24
+ def instruction_pointer=(ip)
25
+ @state[:fiber][:instruction_pointer] = ip
26
+ end
27
+
28
+ def opcodes
29
+ return @state[:opcodes]
30
+ end
31
+
32
+ def locals
33
+ return @state[:fiber][:locals][@state[:fiber][:level]]
34
+ end
35
+
36
+ def globals
37
+ return @state[:globals]
38
+ end
39
+
40
+ def increment_scope
41
+ @state[:fiber][:level] += 1
42
+ @state[:fiber][:locals][@state[:fiber][:level]] = @state[:fiber][:locals][@state[:fiber][:level] - 1].dup
43
+ end
44
+
45
+ def decrement_scope
46
+ @state[:fiber][:locals].delete_at(@state[:fiber][:level])
47
+ @state[:fiber][:level] -= 1
48
+ end
49
+
50
+ def reload_scope
51
+ @state[:fiber][:locals][@state[:fiber][:level]] = {}
52
+ end
53
+
54
+ def level
55
+ return @state[:fiber][:level]
56
+ end
57
+
58
+ def level=(level)
59
+ @state[:fiber][:level] = level
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,48 @@
1
+ module KoiVMRuby
2
+ class VM
3
+
4
+ @@instruction = []
5
+
6
+ attr_accessor :state, :files
7
+
8
+ def initialize(state = {}, opcodes = [])
9
+ default_state = {
10
+ :opcodes => opcodes,
11
+ :globals => {},
12
+ :fiber => {
13
+ :data_stack => [],
14
+ :return_stack => [],
15
+ :locals => [{}],
16
+ :instruction_pointer => 0,
17
+ :level => 0
18
+ }
19
+ }
20
+ @state = default_state.merge(state)
21
+ @files = {}
22
+ raise ArgumentError, "state[:fibers][x] must be a hash" unless(@state[:fiber].is_a?(Hash))
23
+ raise ArgumentError, "state[:fibers][x][:stack] must be an Array" unless(@state[:fiber][:data_stack].is_a?(Array))
24
+ raise ArgumentError, "state[:fibers][x][:stack] must be an Array" unless(@state[:fiber][:return_stack].is_a?(Array))
25
+ raise ArgumentError, "state[:fibers][x][:instruction_pointer] must be an Integer" unless(@state[:fiber][:instruction_pointer].is_a?(Integer))
26
+ raise ArgumentError, "state[:fibers][x][:level] must be an Integer" unless(@state[:fiber][:level].is_a?(Integer))
27
+ raise ArgumentError, "state[:globals] must be a hash" unless(@state[:globals].is_a?(Hash))
28
+ raise ArgumentError, "state[:opcodes] must be an array" unless(@state[:opcodes].is_a?(Array))
29
+ end
30
+
31
+ def run(opcodes = [])
32
+ @state[:opcodes].concat(opcodes)
33
+ opcode_size = @state[:opcodes].size
34
+ while (@state[:fiber][:instruction_pointer] < opcode_size)
35
+ begin
36
+ break if(@@instruction[@state[:opcodes][@state[:fiber][:instruction_pointer]]].call(self) == true)
37
+ rescue NoMethodError
38
+ @state.delete(:opcodes)
39
+ puts "\n\n" + @state.inspect + "\n\n" unless(defined?($test) && $test == true)
40
+ raise
41
+ end
42
+ end
43
+
44
+ return @state
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,8 @@
1
+ class StackError < RuntimeError
2
+ end
3
+
4
+ class ReturnStackError < RuntimeError
5
+ end
6
+
7
+ class OperandError < RuntimeError
8
+ end
@@ -0,0 +1,5 @@
1
+ module KoiVMRuby
2
+ class VM
3
+
4
+ end
5
+ end
@@ -0,0 +1,68 @@
1
+ module KoiVMRuby
2
+ # 0
3
+ PUSH_NIL = 0
4
+ PUSH_BOOL = 1
5
+ PUSH_INT = 2
6
+ PUSH_FLOAT = 3
7
+ PUSH_STRING = 4
8
+
9
+ # 20
10
+ JUMP = 20
11
+ JUMP_IF = 21
12
+ JUMP_UNLESS = 22
13
+
14
+ # 40
15
+ POP = 40
16
+ SWAP = 41
17
+ DUP = 42
18
+ STKSIZE = 43
19
+ TYPEOF = 44
20
+ TOP = 45
21
+
22
+ # 60
23
+ ADD = 60
24
+ SUBTRACT = 61
25
+ MULTIPLY = 62
26
+ DIVIDE = 63
27
+
28
+ # 80
29
+ CONCAT = 80
30
+ STRLEN = 81
31
+ TO_STRING = 82
32
+
33
+ # 100
34
+ EQUAL = 100
35
+ LESS_THAN = 101
36
+ GREATER_THAN = 102
37
+ INVERT = 103
38
+
39
+ # 120
40
+ PRINT = 120
41
+ GETS = 121
42
+
43
+ # 140
44
+ SET_LOCAL = 140
45
+ GET_LOCAL = 141
46
+ SET_GLOBAL = 142
47
+ GET_GLOBAL = 143
48
+
49
+ # 160
50
+ PUSH_FUNCTION = 160
51
+ END_FUNCTION = 161
52
+ CALL = 162
53
+ RETURN = 163
54
+ TAILCALL = 164
55
+
56
+ # 180
57
+ PUSH_HASH = 180
58
+ SET_KEY = 181
59
+ GET_KEY = 182
60
+ HAS_KEY = 183
61
+ LENGTH = 184
62
+ NUM_PAIRS = 185
63
+ PAIRS = 186
64
+
65
+ # 240
66
+ NO_OP = 240
67
+ EXIT = 255
68
+ end
@@ -0,0 +1,11 @@
1
+ module KoiVMRuby
2
+ NIL_ = 0
3
+ BOOL_ = 1
4
+ INTEGER_ = 2
5
+ FLOAT_ = 3
6
+ STRING_ = 4
7
+ HASH_ = 5
8
+
9
+
10
+ FUNCTION_ = 16
11
+ end
@@ -0,0 +1,11 @@
1
+ module KoiVMRuby
2
+ class VM
3
+
4
+ @@instruction[EQUAL] = Proc.new() do |vm|
5
+ raise StackError, "Expecting at least two items on the data stack" unless(vm.data_stack.length > 1)
6
+ vm.data_stack.push([BOOL_, vm.data_stack.pop == vm.data_stack.pop])
7
+ vm.instruction_pointer = vm.instruction_pointer + 1
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ module KoiVMRuby
2
+ class VM
3
+
4
+ @@instruction[GREATER_THAN] = Proc.new() do |vm|
5
+ raise StackError, "Expecting at least two items on the data stack" unless(vm.data_stack.length > 1)
6
+ result = [BOOL_, vm.data_stack[-2][1] > vm.data_stack[-1][1]]
7
+ vm.data_stack.pop
8
+ vm.data_stack.pop
9
+ vm.data_stack.push(result)
10
+ vm.instruction_pointer = vm.instruction_pointer + 1
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ module KoiVMRuby
2
+ class VM
3
+
4
+ @@instruction[INVERT] = Proc.new() do |vm|
5
+ raise StackError, "Expecting at least one item on the data stack" unless(vm.data_stack.length > 0)
6
+ raise StackError, "Expecting boolean value" unless(vm.data_stack[-1][0] == BOOL_)
7
+ vm.data_stack[-1][1] = !vm.data_stack[-1][1]
8
+ vm.instruction_pointer = vm.instruction_pointer + 1
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ module KoiVMRuby
2
+ class VM
3
+
4
+ @@instruction[LESS_THAN] = Proc.new() do |vm|
5
+ raise StackError, "Expecting at least two items on the data stack" unless(vm.data_stack.length > 1)
6
+ result = [BOOL_, vm.data_stack[-2][1] < vm.data_stack[-1][1]]
7
+ vm.data_stack.pop
8
+ vm.data_stack.pop
9
+ vm.data_stack.push(result)
10
+ vm.instruction_pointer = vm.instruction_pointer + 1
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ module KoiVMRuby
2
+ class VM
3
+
4
+ @@instruction[EXIT] = Proc.new() do |vm|
5
+ vm.instruction_pointer = vm.instruction_pointer + 1
6
+ true
7
+ end
8
+
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ module KoiVMRuby
2
+ class VM
3
+
4
+ @@instruction[NO_OP] = Proc.new() do |vm|
5
+ vm.instruction_pointer = vm.instruction_pointer + 1
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ module KoiVMRuby
2
+ class VM
3
+
4
+ @@instruction[JUMP] = Proc.new() do |vm|
5
+ operand = vm.opcodes[vm.instruction_pointer + 1]
6
+ raise OperandError, "Expecting integer value but got #{operand.inspect}" unless(operand.is_a?(Integer))
7
+ vm.instruction_pointer = vm.instruction_pointer + operand
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ module KoiVMRuby
2
+ class VM
3
+
4
+ @@instruction[JUMP_IF] = Proc.new() do |vm|
5
+ operand = vm.opcodes[vm.instruction_pointer + 1]
6
+ raise OperandError, "Expecting integer value but got #{operand.inspect}" unless(operand.is_a?(Integer))
7
+ raise StackError, "Expecting at least one item on the data stack" unless(vm.data_stack.length > 0)
8
+ if(vm.data_stack.pop[1])
9
+ vm.instruction_pointer = vm.instruction_pointer + operand
10
+ else
11
+ vm.instruction_pointer = vm.instruction_pointer + 2
12
+ end
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module KoiVMRuby
2
+ class VM
3
+
4
+ @@instruction[JUMP_UNLESS] = Proc.new() do |vm|
5
+ operand = vm.opcodes[vm.instruction_pointer + 1]
6
+ raise OperandError, "Expecting integer value but got #{operand.inspect}" unless(operand.is_a?(Integer))
7
+ raise StackError, "Expecting at least one item on the data stack" unless(vm.data_stack.length > 0)
8
+ unless(vm.data_stack.pop[1])
9
+ vm.instruction_pointer = vm.instruction_pointer + operand
10
+ else
11
+ vm.instruction_pointer = vm.instruction_pointer + 2
12
+ end
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,13 @@
1
+ module KoiVMRuby
2
+ class VM
3
+
4
+ @@instruction[CALL] = Proc.new() do |vm|
5
+ raise StackError, "Expecting at least one item on the data stack" unless(vm.data_stack.length > 0)
6
+ raise StackError, "Expecting function" unless(vm.data_stack[-1][0] == FUNCTION_)
7
+ vm.return_stack.push( vm.instruction_pointer + 1 )
8
+ vm.instruction_pointer = vm.data_stack.pop[1]
9
+ vm.increment_scope
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ module KoiVMRuby
2
+ class VM
3
+
4
+ @@instruction[PUSH_FUNCTION] = Proc.new() do |vm|
5
+ vm.data_stack.push([FUNCTION_, vm.instruction_pointer + 2])
6
+ function_id = vm.opcodes[vm.instruction_pointer + 1]
7
+ while(true)
8
+ vm.instruction_pointer = vm.opcodes.slice(vm.instruction_pointer, vm.opcodes.length).index(END_FUNCTION) + vm.instruction_pointer
9
+ if(vm.opcodes.slice(vm.instruction_pointer, 4) == [END_FUNCTION, 0, END_FUNCTION, function_id])
10
+ break
11
+ else
12
+ vm.instruction_pointer = vm.instruction_pointer + 1
13
+ end
14
+ end
15
+ vm.instruction_pointer = vm.instruction_pointer + 4
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,11 @@
1
+ module KoiVMRuby
2
+ class VM
3
+
4
+ @@instruction[RETURN] = Proc.new() do |vm|
5
+ raise ReturnStackError, "Expecting at least one item on the return stack" unless(vm.return_stack.length > 0)
6
+ vm.instruction_pointer = vm.return_stack.pop
7
+ vm.decrement_scope
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ module KoiVMRuby
2
+ class VM
3
+
4
+ @@instruction[TAILCALL] = Proc.new() do |vm|
5
+ raise StackError, "Expecting at least one item on the data stack" unless(vm.data_stack.length > 0)
6
+ raise StackError, "Expecting function" unless(vm.data_stack[-1][0] == FUNCTION_)
7
+ vm.instruction_pointer = vm.data_stack.pop[1]
8
+ vm.reload_scope
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ module KoiVMRuby
2
+ class VM
3
+
4
+ @@instruction[GET_KEY] = Proc.new() do |vm|
5
+ raise StackError, "Expecting at least two items on the data stack" unless(vm.data_stack.length > 1)
6
+ raise StackError, "Expecting a hash" unless(vm.data_stack[-2][0] == HASH_)
7
+ key = vm.data_stack.pop
8
+ vm.data_stack.push( vm.data_stack.pop[1][key] )
9
+ vm.data_stack[-1] = [NIL_, nil] if(vm.data_stack[-1] == nil)
10
+ vm.instruction_pointer = vm.instruction_pointer + 1
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,18 @@
1
+ module KoiVMRuby
2
+ class VM
3
+
4
+ @@instruction[HAS_KEY] = Proc.new() do |vm|
5
+ raise StackError, "Expecting at least two items on the data stack" unless(vm.data_stack.length > 1)
6
+ raise StackError, "Expecting a hash" unless(vm.data_stack[-2][0] == HASH_)
7
+ key = vm.data_stack.pop
8
+ hash = vm.data_stack.pop[1]
9
+ if(hash.has_key?(key))
10
+ vm.data_stack.push([BOOL_, true])
11
+ else
12
+ vm.data_stack.push([BOOL_, false])
13
+ end
14
+ vm.instruction_pointer = vm.instruction_pointer + 1
15
+ end
16
+
17
+ end
18
+ end