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,11 @@
|
|
1
|
+
module KoiVM
|
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 KoiVM
|
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 KoiVM
|
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 KoiVM
|
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,15 @@
|
|
1
|
+
module KoiVM
|
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)
|
9
|
+
break if(vm.opcodes.slice(vm.instruction_pointer, 4) == [END_FUNCTION, 0, END_FUNCTION, function_id])
|
10
|
+
end
|
11
|
+
vm.instruction_pointer = vm.instruction_pointer + 4
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module KoiVM
|
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 KoiVM
|
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,13 @@
|
|
1
|
+
module KoiVM
|
2
|
+
class VM
|
3
|
+
|
4
|
+
@@instruction[PRINT] = Proc.new() do |vm|
|
5
|
+
raise StackError, "Expecting at least one item on the data stack" unless(vm.data_stack.length > 0)
|
6
|
+
value = vm.data_stack.pop
|
7
|
+
raise StackError, "Expecting topmost stack item to be a string but was #{value.class}" unless(value[0] == STRING_)
|
8
|
+
print value[1]
|
9
|
+
vm.instruction_pointer = vm.instruction_pointer + 1
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module KoiVM
|
2
|
+
class VM
|
3
|
+
|
4
|
+
@@instruction[ADD] = 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[-2][1] += vm.data_stack[-1][1]
|
7
|
+
vm.data_stack.pop
|
8
|
+
vm.data_stack[-1][0] = INTEGER_ if(vm.data_stack[-1][1].is_a?(Integer))
|
9
|
+
vm.data_stack[-1][0] = FLOAT_ if(vm.data_stack[-1][1].is_a?(Float))
|
10
|
+
vm.instruction_pointer = vm.instruction_pointer + 1
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module KoiVM
|
2
|
+
class VM
|
3
|
+
|
4
|
+
@@instruction[DIVIDE] = 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[-2][1] = vm.data_stack[-2][1] / vm.data_stack[-1][1]
|
7
|
+
vm.data_stack.pop
|
8
|
+
vm.data_stack[-1][0] = INTEGER_ if(vm.data_stack[-1][1].is_a?(Integer))
|
9
|
+
vm.data_stack[-1][0] = FLOAT_ if(vm.data_stack[-1][1].is_a?(Float))
|
10
|
+
vm.instruction_pointer = vm.instruction_pointer + 1
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module KoiVM
|
2
|
+
class VM
|
3
|
+
|
4
|
+
@@instruction[MULTIPLY] = 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[-2][1] = vm.data_stack[-2][1] * vm.data_stack[-1][1]
|
7
|
+
vm.data_stack.pop
|
8
|
+
vm.data_stack[-1][0] = INTEGER_ if(vm.data_stack[-1][1].is_a?(Integer))
|
9
|
+
vm.data_stack[-1][0] = FLOAT_ if(vm.data_stack[-1][1].is_a?(Float))
|
10
|
+
vm.instruction_pointer = vm.instruction_pointer + 1
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module KoiVM
|
2
|
+
class VM
|
3
|
+
|
4
|
+
@@instruction[SUBTRACT] = 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[-2][1] -= vm.data_stack[-1][1]
|
7
|
+
vm.data_stack.pop
|
8
|
+
vm.data_stack[-1][0] = INTEGER_ if(vm.data_stack[-1][1].is_a?(Integer))
|
9
|
+
vm.data_stack[-1][0] = FLOAT_ if(vm.data_stack[-1][1].is_a?(Float))
|
10
|
+
vm.instruction_pointer = vm.instruction_pointer + 1
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module KoiVM
|
2
|
+
class VM
|
3
|
+
|
4
|
+
@@instruction[PUSH_BOOL] = Proc.new() do |vm|
|
5
|
+
operand = vm.opcodes[vm.instruction_pointer + 1]
|
6
|
+
raise OperandError, "Expecting boolean value but got #{operand.inspect}" unless(operand.is_a?(TrueClass) or operand.is_a?(FalseClass))
|
7
|
+
vm.data_stack.push([BOOL_, operand])
|
8
|
+
vm.instruction_pointer = vm.instruction_pointer + 2
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module KoiVM
|
2
|
+
class VM
|
3
|
+
|
4
|
+
@@instruction[PUSH_FLOAT] = Proc.new() do |vm|
|
5
|
+
operand = vm.opcodes[vm.instruction_pointer + 1]
|
6
|
+
raise OperandError, "Expecting float value but got #{operand.inspect}" unless(operand.is_a?(Float))
|
7
|
+
vm.data_stack.push([FLOAT_, operand])
|
8
|
+
vm.instruction_pointer = vm.instruction_pointer + 2
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module KoiVM
|
2
|
+
class VM
|
3
|
+
|
4
|
+
@@instruction[PUSH_INT] = 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.data_stack.push([INTEGER_, operand])
|
8
|
+
vm.instruction_pointer = vm.instruction_pointer + 2
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module KoiVM
|
2
|
+
class VM
|
3
|
+
|
4
|
+
@@instruction[PUSH_STRING] = Proc.new() do |vm|
|
5
|
+
operand = vm.opcodes[vm.instruction_pointer + 1]
|
6
|
+
raise OperandError, "Expecting string value but got #{operand.inspect}" unless(operand.is_a?(String))
|
7
|
+
vm.data_stack.push([STRING_, operand])
|
8
|
+
vm.instruction_pointer = vm.instruction_pointer + 2
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module KoiVM
|
2
|
+
class VM
|
3
|
+
|
4
|
+
@@instruction[DUP] = Proc.new() do |vm|
|
5
|
+
raise StackError, "Expecting at least two items on the data stack" unless(vm.data_stack.length > 0)
|
6
|
+
vm.data_stack.push(vm.data_stack[-1])
|
7
|
+
vm.instruction_pointer = vm.instruction_pointer + 1
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module KoiVM
|
2
|
+
class VM
|
3
|
+
|
4
|
+
@@instruction[POP] = Proc.new() do |vm|
|
5
|
+
raise StackError, "Expecting at least one item on the data stack" unless(vm.data_stack.length > 0)
|
6
|
+
vm.data_stack.pop
|
7
|
+
vm.instruction_pointer = vm.instruction_pointer + 1
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module KoiVM
|
2
|
+
class VM
|
3
|
+
|
4
|
+
@@instruction[SWAP] = 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.insert(-2, vm.data_stack.pop)
|
7
|
+
vm.instruction_pointer = vm.instruction_pointer + 1
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module KoiVM
|
2
|
+
class VM
|
3
|
+
|
4
|
+
@@instruction[TOP] = Proc.new() do |vm|
|
5
|
+
operand = vm.opcodes[vm.instruction_pointer + 1]
|
6
|
+
raise OperandError, "Expecting operand to be a integer but got #{operand.class}" unless(operand.is_a?(Integer))
|
7
|
+
raise StackError, "Expecting at least #{operand} items on the data stack" unless(vm.data_stack.length > (operand - 1))
|
8
|
+
vm.data_stack.concat(vm.data_stack.slice(-1 - (operand - 1), vm.data_stack.length))
|
9
|
+
vm.instruction_pointer = vm.instruction_pointer + 2
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module KoiVM
|
2
|
+
class VM
|
3
|
+
|
4
|
+
@@instruction[TYPEOF] = Proc.new() do |vm|
|
5
|
+
raise StackError, "Expecting at least one item on the data stack" unless(vm.data_stack.length > 0)
|
6
|
+
value = vm.data_stack.pop
|
7
|
+
vm.data_stack.push([STRING_, "nil"]) if(value[0] == NIL_)
|
8
|
+
vm.data_stack.push([STRING_, "bool"]) if(value[0] == BOOL_)
|
9
|
+
vm.data_stack.push([STRING_, "integer"]) if(value[0] == INTEGER_)
|
10
|
+
vm.data_stack.push([STRING_, "float"]) if(value[0] == FLOAT_)
|
11
|
+
vm.data_stack.push([STRING_, "string"]) if(value[0] == STRING_)
|
12
|
+
vm.instruction_pointer = vm.instruction_pointer + 1
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module KoiVM
|
2
|
+
class VM
|
3
|
+
|
4
|
+
@@instruction[CONCAT] = 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 at least two strings on the stack" unless((vm.data_stack[-1][0] == STRING_) and (vm.data_stack[-2][0] == STRING_))
|
7
|
+
vm.data_stack[-2][1].concat(vm.data_stack.pop[1])
|
8
|
+
vm.instruction_pointer = vm.instruction_pointer + 1
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module KoiVM
|
2
|
+
class VM
|
3
|
+
|
4
|
+
@@instruction[STRLEN] = Proc.new() do |vm|
|
5
|
+
raise StackError, "Expecting at least one items on the data stack" unless(vm.data_stack.length > 0)
|
6
|
+
raise StackError, "Expecting topmost item on stack to be a string" unless((vm.data_stack[-1][0] == STRING_))
|
7
|
+
vm.data_stack.push([INTEGER_, vm.data_stack.pop[1].length])
|
8
|
+
vm.instruction_pointer = vm.instruction_pointer + 1
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module KoiVM
|
2
|
+
class VM
|
3
|
+
|
4
|
+
@@instruction[TO_STRING] = Proc.new() do |vm|
|
5
|
+
raise StackError, "Expecting at least one item on the data stack" unless(vm.data_stack.length > 0)
|
6
|
+
value = vm.data_stack.pop
|
7
|
+
if(value[0] == NIL_)
|
8
|
+
vm.data_stack.push([STRING_, "nil"])
|
9
|
+
else
|
10
|
+
vm.data_stack.push([STRING_, value[1].to_s])
|
11
|
+
end
|
12
|
+
vm.instruction_pointer = vm.instruction_pointer + 1
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module KoiVM
|
2
|
+
class VM
|
3
|
+
|
4
|
+
@@instruction[SET_GLOBAL] = Proc.new() do |vm|
|
5
|
+
raise StackError, "Expecting at least one item on the data stack" unless(vm.data_stack.length > 0)
|
6
|
+
vm.globals[vm.opcodes[vm.instruction_pointer + 1]] = vm.data_stack.pop
|
7
|
+
vm.instruction_pointer = vm.instruction_pointer + 2
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module KoiVM
|
2
|
+
class VM
|
3
|
+
|
4
|
+
@@instruction[SET_LOCAL] = Proc.new() do |vm|
|
5
|
+
raise StackError, "Expecting at least one item on the data stack" unless(vm.data_stack.length > 0)
|
6
|
+
vm.locals[vm.opcodes[vm.instruction_pointer + 1]] = vm.data_stack.pop
|
7
|
+
vm.instruction_pointer = vm.instruction_pointer + 2
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
data/lib/koi-vm.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require_files = []
|
2
|
+
|
3
|
+
require_files << File.join(File.dirname(__FILE__), "koi-vm", "core.rb")
|
4
|
+
require_files << File.join(File.dirname(__FILE__), "koi-vm", "helpers.rb")
|
5
|
+
require_files << File.join(File.dirname(__FILE__), "koi-vm", "exceptions.rb")
|
6
|
+
require_files.concat Dir[File.join(File.dirname(__FILE__), 'koi-vm', '**', '*.rb')]
|
7
|
+
|
8
|
+
require_files.each do |file|
|
9
|
+
require File.expand_path(file)
|
10
|
+
end
|
data/test/.gitkeep
ADDED
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
*.html
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'test_helper.rb'))
|
2
|
+
|
3
|
+
class SimpleBenchmark < Test::Unit::TestCase
|
4
|
+
|
5
|
+
require "benchmark"
|
6
|
+
require "stringio"
|
7
|
+
require 'ruby-prof'
|
8
|
+
include KoiVM
|
9
|
+
|
10
|
+
vm = VM.new
|
11
|
+
|
12
|
+
test "simple benchmark" do
|
13
|
+
Benchmark.bmbm do |b|
|
14
|
+
b.report("Ruby") do
|
15
|
+
silence do
|
16
|
+
1000.times do
|
17
|
+
x = 10
|
18
|
+
while(x > -1) do
|
19
|
+
print "#{x}, "
|
20
|
+
x -= 1
|
21
|
+
end
|
22
|
+
print "Blast off!\n"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
b.report("Koi") do
|
28
|
+
silence do
|
29
|
+
1000.times do
|
30
|
+
vm.run [
|
31
|
+
PUSH_INT, 11,
|
32
|
+
PUSH_INT, 1,
|
33
|
+
SUBTRACT,
|
34
|
+
DUP,
|
35
|
+
TO_STRING,
|
36
|
+
PRINT,
|
37
|
+
PUSH_STRING, ", ",
|
38
|
+
PRINT,
|
39
|
+
DUP,
|
40
|
+
PUSH_INT, 0,
|
41
|
+
EQUAL,
|
42
|
+
JUMP_UNLESS, -13,
|
43
|
+
PUSH_STRING, "Blast Off!\n",
|
44
|
+
PRINT
|
45
|
+
]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
test "simple profile" do
|
53
|
+
silence do
|
54
|
+
result = RubyProf.profile do
|
55
|
+
vm.run [
|
56
|
+
PUSH_INT, 11,
|
57
|
+
PUSH_INT, 1,
|
58
|
+
SUBTRACT,
|
59
|
+
DUP,
|
60
|
+
TO_STRING,
|
61
|
+
PRINT,
|
62
|
+
PUSH_STRING, ", ",
|
63
|
+
PRINT,
|
64
|
+
DUP,
|
65
|
+
PUSH_INT, 0,
|
66
|
+
EQUAL,
|
67
|
+
JUMP_UNLESS, -13,
|
68
|
+
PUSH_STRING, "Blast Off!\n",
|
69
|
+
PRINT
|
70
|
+
]
|
71
|
+
end
|
72
|
+
file = File.new(File.join(File.dirname(__FILE__), "koi_profile.html"), "w+")
|
73
|
+
printer = RubyProf::GraphHtmlPrinter.new(result)
|
74
|
+
printer.print(file, :min_percent=>0)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def silence
|
81
|
+
old_stdout = $stdout
|
82
|
+
$stdout = StringIO.new
|
83
|
+
yield
|
84
|
+
$stdout = old_stdout
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Test::Unit
|
2
|
+
# Used to fix a minor minitest/unit incompatibility in flexmock
|
3
|
+
AssertionFailedError = Class.new(StandardError)
|
4
|
+
|
5
|
+
class TestCase
|
6
|
+
|
7
|
+
def self.test(name, &block)
|
8
|
+
test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym
|
9
|
+
defined = instance_method(test_name) rescue false
|
10
|
+
raise "#{test_name} is already defined in #{self}" if defined
|
11
|
+
if block_given?
|
12
|
+
define_method(test_name, &block)
|
13
|
+
else
|
14
|
+
define_method(test_name) do
|
15
|
+
flunk "No implementation provided for #{name}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
$test = true
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'test/unit'
|
5
|
+
require 'stringio'
|
6
|
+
|
7
|
+
require_files = []
|
8
|
+
require_files << File.join(File.dirname(__FILE__), '..', 'lib', 'koi-vm.rb')
|
9
|
+
require_files.concat Dir[File.join(File.dirname(__FILE__), 'setup', '*.rb')]
|
10
|
+
|
11
|
+
require_files.each do |file|
|
12
|
+
require File.expand_path(file)
|
13
|
+
end
|