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.
Files changed (95) hide show
  1. data/.gitignore +2 -0
  2. data/README.rdoc +47 -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 +174 -0
  9. data/lib/.gitkeep +0 -0
  10. data/lib/koi-vm/accessors.rb +63 -0
  11. data/lib/koi-vm/core.rb +48 -0
  12. data/lib/koi-vm/exceptions.rb +8 -0
  13. data/lib/koi-vm/helpers.rb +5 -0
  14. data/lib/koi-vm/opcodes/_opcode_constants.rb +58 -0
  15. data/lib/koi-vm/opcodes/_value_constants.rb +10 -0
  16. data/lib/koi-vm/opcodes/comparative_operations/equal.rb +11 -0
  17. data/lib/koi-vm/opcodes/comparative_operations/greater_than.rb +14 -0
  18. data/lib/koi-vm/opcodes/comparative_operations/less_than.rb +14 -0
  19. data/lib/koi-vm/opcodes/control_operations/exit.rb +10 -0
  20. data/lib/koi-vm/opcodes/control_operations/no_op.rb +9 -0
  21. data/lib/koi-vm/opcodes/flow_control_operations/jump.rb +11 -0
  22. data/lib/koi-vm/opcodes/flow_control_operations/jump_if.rb +16 -0
  23. data/lib/koi-vm/opcodes/flow_control_operations/jump_unless.rb +16 -0
  24. data/lib/koi-vm/opcodes/function_operations/call.rb +13 -0
  25. data/lib/koi-vm/opcodes/function_operations/push_function.rb +15 -0
  26. data/lib/koi-vm/opcodes/function_operations/return.rb +11 -0
  27. data/lib/koi-vm/opcodes/function_operations/tailcall.rb +12 -0
  28. data/lib/koi-vm/opcodes/io_operations/gets.rb +10 -0
  29. data/lib/koi-vm/opcodes/io_operations/print.rb +13 -0
  30. data/lib/koi-vm/opcodes/math_operations/add.rb +14 -0
  31. data/lib/koi-vm/opcodes/math_operations/divide.rb +14 -0
  32. data/lib/koi-vm/opcodes/math_operations/multiply.rb +14 -0
  33. data/lib/koi-vm/opcodes/math_operations/subtract.rb +14 -0
  34. data/lib/koi-vm/opcodes/push_operations/push_bool.rb +12 -0
  35. data/lib/koi-vm/opcodes/push_operations/push_float.rb +12 -0
  36. data/lib/koi-vm/opcodes/push_operations/push_int.rb +12 -0
  37. data/lib/koi-vm/opcodes/push_operations/push_nil.rb +10 -0
  38. data/lib/koi-vm/opcodes/push_operations/push_string.rb +12 -0
  39. data/lib/koi-vm/opcodes/stack_operations/dup.rb +11 -0
  40. data/lib/koi-vm/opcodes/stack_operations/pop.rb +11 -0
  41. data/lib/koi-vm/opcodes/stack_operations/stksize.rb +10 -0
  42. data/lib/koi-vm/opcodes/stack_operations/swap.rb +11 -0
  43. data/lib/koi-vm/opcodes/stack_operations/top.rb +13 -0
  44. data/lib/koi-vm/opcodes/stack_operations/typeof.rb +16 -0
  45. data/lib/koi-vm/opcodes/string_operations/concat.rb +12 -0
  46. data/lib/koi-vm/opcodes/string_operations/strlen.rb +12 -0
  47. data/lib/koi-vm/opcodes/string_operations/to_string.rb +16 -0
  48. data/lib/koi-vm/opcodes/variable_operations/get_global.rb +10 -0
  49. data/lib/koi-vm/opcodes/variable_operations/get_local.rb +10 -0
  50. data/lib/koi-vm/opcodes/variable_operations/set_global.rb +11 -0
  51. data/lib/koi-vm/opcodes/variable_operations/set_local.rb +11 -0
  52. data/lib/koi-vm.rb +10 -0
  53. data/test/.gitkeep +0 -0
  54. data/test/performance/.gitignore +1 -0
  55. data/test/performance/simple_benchmark.rb +87 -0
  56. data/test/setup/test_unit_extensions.rb +21 -0
  57. data/test/test_helper.rb +13 -0
  58. data/test/unit/opcodes/comparative_operations/equal_test.rb +116 -0
  59. data/test/unit/opcodes/comparative_operations/greater_than_test.rb +53 -0
  60. data/test/unit/opcodes/comparative_operations/less_than_test.rb +53 -0
  61. data/test/unit/opcodes/control_operations/exit_test.rb +20 -0
  62. data/test/unit/opcodes/control_operations/no_op_test.rb +17 -0
  63. data/test/unit/opcodes/flow_control_operations/jump_if_test.rb +50 -0
  64. data/test/unit/opcodes/flow_control_operations/jump_test.rb +36 -0
  65. data/test/unit/opcodes/flow_control_operations/jump_unless_test.rb +50 -0
  66. data/test/unit/opcodes/function_operations/call_test.rb +39 -0
  67. data/test/unit/opcodes/function_operations/push_function_test.rb +21 -0
  68. data/test/unit/opcodes/function_operations/return_test.rb +31 -0
  69. data/test/unit/opcodes/function_operations/tailcall_test.rb +41 -0
  70. data/test/unit/opcodes/io_operations/gets_test.rb +38 -0
  71. data/test/unit/opcodes/io_operations/print_test.rb +42 -0
  72. data/test/unit/opcodes/math_operations/add_test.rb +62 -0
  73. data/test/unit/opcodes/math_operations/divide_test.rb +62 -0
  74. data/test/unit/opcodes/math_operations/multiply_test.rb +62 -0
  75. data/test/unit/opcodes/math_operations/subtract_test.rb +62 -0
  76. data/test/unit/opcodes/push_operations/push_bool_test.rb +36 -0
  77. data/test/unit/opcodes/push_operations/push_float_test.rb +27 -0
  78. data/test/unit/opcodes/push_operations/push_int_test.rb +27 -0
  79. data/test/unit/opcodes/push_operations/push_nil_test.rb +16 -0
  80. data/test/unit/opcodes/push_operations/push_string_test.rb +27 -0
  81. data/test/unit/opcodes/stack_operations/dup_test.rb +25 -0
  82. data/test/unit/opcodes/stack_operations/pop_test.rb +28 -0
  83. data/test/unit/opcodes/stack_operations/stksize_test.rb +20 -0
  84. data/test/unit/opcodes/stack_operations/swap_test.rb +36 -0
  85. data/test/unit/opcodes/stack_operations/top_test.rb +45 -0
  86. data/test/unit/opcodes/stack_operations/typeof_test.rb +61 -0
  87. data/test/unit/opcodes/string_operations/concat_test.rb +65 -0
  88. data/test/unit/opcodes/string_operations/strlen_test.rb +44 -0
  89. data/test/unit/opcodes/string_operations/to_string_test.rb +70 -0
  90. data/test/unit/opcodes/variable_operations/get_global_test.rb +18 -0
  91. data/test/unit/opcodes/variable_operations/get_local_test.rb +18 -0
  92. data/test/unit/opcodes/variable_operations/set_global_test.rb +27 -0
  93. data/test/unit/opcodes/variable_operations/set_local_test.rb +27 -0
  94. data/test/unit/vm_initialization_test.rb +86 -0
  95. 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,10 @@
1
+ module KoiVM
2
+ class VM
3
+
4
+ @@instruction[GETS] = Proc.new() do |vm|
5
+ vm.data_stack.push([STRING_, $stdin.gets("\n")])
6
+ vm.instruction_pointer = vm.instruction_pointer + 1
7
+ end
8
+
9
+ end
10
+ 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,10 @@
1
+ module KoiVM
2
+ class VM
3
+
4
+ @@instruction[PUSH_NIL] = Proc.new() do |vm|
5
+ vm.data_stack.push([NIL_, nil])
6
+ vm.instruction_pointer = vm.instruction_pointer + 1
7
+ end
8
+
9
+ end
10
+ 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,10 @@
1
+ module KoiVM
2
+ class VM
3
+
4
+ @@instruction[STKSIZE] = Proc.new() do |vm|
5
+ vm.data_stack.push([INTEGER_, vm.data_stack.length])
6
+ vm.instruction_pointer = vm.instruction_pointer + 1
7
+ end
8
+
9
+ end
10
+ 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,10 @@
1
+ module KoiVM
2
+ class VM
3
+
4
+ @@instruction[GET_GLOBAL] = Proc.new() do |vm|
5
+ vm.data_stack.push( vm.globals[vm.opcodes[vm.instruction_pointer + 1]] )
6
+ vm.instruction_pointer = vm.instruction_pointer + 2
7
+ end
8
+
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ module KoiVM
2
+ class VM
3
+
4
+ @@instruction[GET_LOCAL] = Proc.new() do |vm|
5
+ vm.data_stack.push( vm.locals[vm.opcodes[vm.instruction_pointer + 1]] )
6
+ vm.instruction_pointer = vm.instruction_pointer + 2
7
+ end
8
+
9
+ end
10
+ 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
@@ -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