koi-vm-ruby 0.0.4
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 +64 -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 +198 -0
- data/lib/.gitkeep +0 -0
- data/lib/koi-vm-ruby.rb +10 -0
- data/lib/koi-vm-ruby/accessors.rb +63 -0
- data/lib/koi-vm-ruby/core.rb +48 -0
- data/lib/koi-vm-ruby/exceptions.rb +8 -0
- data/lib/koi-vm-ruby/helpers.rb +5 -0
- data/lib/koi-vm-ruby/opcodes/_opcode_constants.rb +68 -0
- data/lib/koi-vm-ruby/opcodes/_value_constants.rb +11 -0
- data/lib/koi-vm-ruby/opcodes/comparative_operations/equal.rb +11 -0
- data/lib/koi-vm-ruby/opcodes/comparative_operations/greater_than.rb +14 -0
- data/lib/koi-vm-ruby/opcodes/comparative_operations/invert.rb +12 -0
- data/lib/koi-vm-ruby/opcodes/comparative_operations/less_than.rb +14 -0
- data/lib/koi-vm-ruby/opcodes/control_operations/exit.rb +10 -0
- data/lib/koi-vm-ruby/opcodes/control_operations/no_op.rb +9 -0
- data/lib/koi-vm-ruby/opcodes/flow_control_operations/jump.rb +11 -0
- data/lib/koi-vm-ruby/opcodes/flow_control_operations/jump_if.rb +16 -0
- data/lib/koi-vm-ruby/opcodes/flow_control_operations/jump_unless.rb +16 -0
- data/lib/koi-vm-ruby/opcodes/function_operations/call.rb +13 -0
- data/lib/koi-vm-ruby/opcodes/function_operations/push_function.rb +19 -0
- data/lib/koi-vm-ruby/opcodes/function_operations/return.rb +11 -0
- data/lib/koi-vm-ruby/opcodes/function_operations/tailcall.rb +12 -0
- data/lib/koi-vm-ruby/opcodes/hash_operations/get_key.rb +14 -0
- data/lib/koi-vm-ruby/opcodes/hash_operations/has_key.rb +18 -0
- data/lib/koi-vm-ruby/opcodes/hash_operations/length.rb +19 -0
- data/lib/koi-vm-ruby/opcodes/hash_operations/num_pairs.rb +12 -0
- data/lib/koi-vm-ruby/opcodes/hash_operations/pairs.rb +22 -0
- data/lib/koi-vm-ruby/opcodes/hash_operations/push_hash.rb +10 -0
- data/lib/koi-vm-ruby/opcodes/hash_operations/set_key.rb +14 -0
- data/lib/koi-vm-ruby/opcodes/io_operations/gets.rb +10 -0
- data/lib/koi-vm-ruby/opcodes/io_operations/print.rb +13 -0
- data/lib/koi-vm-ruby/opcodes/math_operations/add.rb +14 -0
- data/lib/koi-vm-ruby/opcodes/math_operations/divide.rb +14 -0
- data/lib/koi-vm-ruby/opcodes/math_operations/multiply.rb +14 -0
- data/lib/koi-vm-ruby/opcodes/math_operations/subtract.rb +14 -0
- data/lib/koi-vm-ruby/opcodes/push_operations/push_bool.rb +12 -0
- data/lib/koi-vm-ruby/opcodes/push_operations/push_float.rb +12 -0
- data/lib/koi-vm-ruby/opcodes/push_operations/push_int.rb +12 -0
- data/lib/koi-vm-ruby/opcodes/push_operations/push_nil.rb +10 -0
- data/lib/koi-vm-ruby/opcodes/push_operations/push_string.rb +12 -0
- data/lib/koi-vm-ruby/opcodes/stack_operations/dup.rb +11 -0
- data/lib/koi-vm-ruby/opcodes/stack_operations/pop.rb +11 -0
- data/lib/koi-vm-ruby/opcodes/stack_operations/stksize.rb +10 -0
- data/lib/koi-vm-ruby/opcodes/stack_operations/swap.rb +11 -0
- data/lib/koi-vm-ruby/opcodes/stack_operations/top.rb +13 -0
- data/lib/koi-vm-ruby/opcodes/stack_operations/typeof.rb +18 -0
- data/lib/koi-vm-ruby/opcodes/string_operations/concat.rb +12 -0
- data/lib/koi-vm-ruby/opcodes/string_operations/strlen.rb +12 -0
- data/lib/koi-vm-ruby/opcodes/string_operations/to_string.rb +16 -0
- data/lib/koi-vm-ruby/opcodes/variable_operations/get_global.rb +10 -0
- data/lib/koi-vm-ruby/opcodes/variable_operations/get_local.rb +10 -0
- data/lib/koi-vm-ruby/opcodes/variable_operations/set_global.rb +11 -0
- data/lib/koi-vm-ruby/opcodes/variable_operations/set_local.rb +11 -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/invert_test.rb +44 -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 +41 -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/hash_operations/get_key_test.rb +56 -0
- data/test/unit/opcodes/hash_operations/has_key_test.rb +56 -0
- data/test/unit/opcodes/hash_operations/length_test.rb +46 -0
- data/test/unit/opcodes/hash_operations/num_pairs_test.rb +46 -0
- data/test/unit/opcodes/hash_operations/pairs_test.rb +67 -0
- data/test/unit/opcodes/hash_operations/push_hash_test.rb +16 -0
- data/test/unit/opcodes/hash_operations/set_key_test.rb +56 -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 +79 -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 +224 -0
data/lib/.gitkeep
ADDED
File without changes
|
data/lib/koi-vm-ruby.rb
ADDED
@@ -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,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
|
+
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,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
|