From e460e0041b851acff165cc0e664860e21c216615 Mon Sep 17 00:00:00 2001 From: Torsten Ruger Date: Sun, 26 Jul 2015 18:27:12 +0300 Subject: [PATCH] finishes the yellow world instructions --- lib/interpreter.rb | 29 ++++++++++++++++++++++++++--- test/interpreter_test.rb | 21 +++++++++++++++++---- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/lib/interpreter.rb b/lib/interpreter.rb index 6d3f5ec..52c8f1b 100644 --- a/lib/interpreter.rb +++ b/lib/interpreter.rb @@ -2,12 +2,22 @@ require "eventable" class Interpreter + # fire events for changed pc and register contents include Eventable - attr_accessor :instruction - attr_accessor :link - attr_accessor :block + # current instruction or pc + attr_reader :instruction + + # an (arm style) link register. store the return address to return to + attr_reader :link + + # current executing block. since this is not a hardware simulator this is luxury + attr_reader :block + + # the registers, 12 attr_reader :registers + + # collect the output attr_reader :stdout def initialize @@ -54,6 +64,7 @@ class Interpreter end def tick + return unless @instruction name = @instruction.class.name.split("::").last fetch = send "execute_#{name}" return unless fetch @@ -130,9 +141,21 @@ class Interpreter str = object_for( :r1 ) # should test length, ie r2 raise "NO string for putstring #{str}" unless str.is_a? Symbol @stdout += str.to_s + when :exit + @instruction = nil + return false else raise "un-implemented syscall #{name}" end true end + + def execute_FunctionReturn + object = object_for( @instruction.register ) + #wouldn't need to assign to link, but makes tsting easier + @link = object.internal_object_get( @instruction.index ) + @block , @instruction = @link + # we jump back to the call instruction. so it is as if the call never happened and we continue + true + end end diff --git a/test/interpreter_test.rb b/test/interpreter_test.rb index 7636faf..6b3d787 100644 --- a/test/interpreter_test.rb +++ b/test/interpreter_test.rb @@ -53,17 +53,30 @@ class InterpreterTest < MiniTest::Test ["Branch" , "LoadConstant" , "GetSlot" , "SetSlot" , "RegisterTransfer" , "GetSlot" , "FunctionCall" , "SaveReturn" , "LoadConstant" , "SetSlot" , "GetSlot" , "GetSlot" , "SetSlot" , "LoadConstant" , "SetSlot" , - "RegisterTransfer" , "GetSlot" , "FunctionCall" , "SaveReturn" , - "RegisterTransfer" , "Syscall"].each_with_index do |name , index| + "RegisterTransfer" , "GetSlot" , "FunctionCall" , "SaveReturn" , "RegisterTransfer" , + "Syscall" , "RegisterTransfer" , "RegisterTransfer" , "SetSlot" , "GetSlot" , + "GetSlot" , "RegisterTransfer" ,"GetSlot" , "GetSlot","GetSlot", + "FunctionReturn" , "RegisterTransfer" , "Syscall" , "NilClass"].each_with_index do |name , index| got = ticks(1) - assert got.class.name.index(name) , "Wrong class for #{index}, expect #{name} , got #{got}" + assert got.class.name.index(name) , "Wrong class for #{index+1}, expect #{name} , got #{got}" end end def test_putstring done = ticks(21) assert_equal Register::Syscall , done.class - assert_equal "Hello again" , @interpreter.stdout + assert_equal "Hello again" , @interpreter.stdout end + def test_return + done = ticks(31) + assert_equal Register::FunctionReturn , done.class + assert @interpreter.block.is_a?(Virtual::Block) + assert @interpreter.instruction.is_a?(Register::Instruction) , "not instruction #{@interpreter.instruction}" + end + + def test_exit + done = ticks(34) + assert_equal NilClass , done.class + end end