koi-vm-ruby 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|