From 95f3eec04394a13459dbc7b99cf4e5a92980b79a Mon Sep 17 00:00:00 2001 From: Torsten Date: Sun, 1 Mar 2020 10:22:24 +0200 Subject: [PATCH] repurpose RValue as RegisterSlot with the idea of the better name came also the one about not needing the builder anymore --- lib/risc.rb | 1 + lib/risc/builder.rb | 2 +- lib/risc/register_slot.rb | 42 +++++++++++++++++ lib/risc/register_value.rb | 46 ++++--------------- test/risc/test_builder.rb | 14 +++--- test/risc/test_builder1.rb | 2 +- test/risc/test_builder2.rb | 2 +- test/risc/test_register_slot.rb | 79 ++++++++++++++++++++++++++++++++ test/risc/test_register_value.rb | 2 +- 9 files changed, 143 insertions(+), 47 deletions(-) create mode 100644 lib/risc/register_slot.rb create mode 100644 test/risc/test_register_slot.rb diff --git a/lib/risc.rb b/lib/risc.rb index 43e44134..64e39b92 100644 --- a/lib/risc.rb +++ b/lib/risc.rb @@ -41,5 +41,6 @@ end require_relative "risc/instruction" require_relative "risc/register_value" +require_relative "risc/register_slot" require_relative "risc/text_writer" require_relative "risc/builder" diff --git a/lib/risc/builder.rb b/lib/risc/builder.rb index b857c145..cc1c62c9 100644 --- a/lib/risc/builder.rb +++ b/lib/risc/builder.rb @@ -50,7 +50,7 @@ module Risc raise "Must create (with ! or ?) before using #{name}#{last_char}" end type = infer_type(name ) - reg = @compiler.use_reg( type.object_class.name ).set_builder(self) + reg = RegisterValue.new( name.to_sym , type.object_class.name ).set_builder(self) end @names[name] = reg reg diff --git a/lib/risc/register_slot.rb b/lib/risc/register_slot.rb new file mode 100644 index 00000000..c872676a --- /dev/null +++ b/lib/risc/register_slot.rb @@ -0,0 +1,42 @@ +module Risc + + # A RegisterSlot is a description of a slot into an object in a register. + # + # In many ways, it is like a variable in programming it can be a value, or it + # can be assigned a value. An l-value or r-value, and since we don't know at + # the time they are created (because of the dsl nature) we delay. + # + # RegisterSlots are created trough the array operator on a register. + # ie message[:caller], and this can either be further indexed, assigned + # something or assigned to something. So we overload those operators here. + # + # Ultimately SlotToReg or RegToSlot instructions are created for the l-value + # or r-vlalue respectively. + + class RegisterSlot + attr_reader :register , :index , :builder + + def initialize(register, index , builder) + @register , @index , @builder = register , index , builder + end + + # fullfil the objects purpose by creating a RegToSlot instruction from + # itself (the slot) and the register given + def <<( reg ) + raise "not reg #{reg}" unless reg.is_a?(RegisterValue) + reg_to_slot = Risc.reg_to_slot("#{reg.class_name} -> #{register.class_name}[#{index}]" , reg , register, index) + builder.add_code(reg_to_slot) if builder + reg_to_slot + end + + # similar to above (<< which produces reg_to_slot), this produces reg_to_byte + # from itself (the slot) and the register given + def <=( reg ) + raise "not reg #{reg}" unless reg.is_a?(RegisterValue) + reg_to_byte = Risc.reg_to_byte("#{reg.class_name} -> #{register.class_name}[#{index}]" , reg , register, index) + builder.add_code(reg_to_byte) if builder + reg_to_byte + end + + end +end diff --git a/lib/risc/register_value.rb b/lib/risc/register_value.rb index 115d71f2..c3ffdaaf 100644 --- a/lib/risc/register_value.rb +++ b/lib/risc/register_value.rb @@ -133,7 +133,7 @@ module Risc # right value may be # - constant (Parfait object) , resulting in a LoadConstant # - another RegisterValue, resulting in a Transfer instruction - # - an RValue, resulting in an SlotToReg + # - an RegisterSlot, resulting in an SlotToReg def <<( right ) case right when Symbol @@ -148,8 +148,9 @@ module Risc ins = Risc.load_data("#{right.class} to #{self.type}" , right , self) when RegisterValue ins = Risc.transfer("#{right.type} to #{self.type}" , right , self) - when RValue - ins = Risc.slot_to_reg("#{right.register.type}[#{right.index}] -> #{self.type}" , right.register , right.index , self) + when RegisterSlot + puts right.to_s + ins = Risc::SlotToReg.new("#{right.register.type}[#{right.index}] -> #{self.type}" , right.register , right.index , self) else raise "not implemented for #{right.class}:#{right}" end @@ -158,9 +159,9 @@ module Risc end # similar to above (<< which produces slot_to_reg), this produces byte_to_reg - # since << covers all other cases, this must have a RValue as the right + # since << covers all other cases, this must have a RegisterSlot as the right def <=( right ) - raise "not implemented for #{right.class}:#{right}" unless right.is_a?( RValue ) + raise "not implemented for #{right.class}:#{right}" unless right.is_a?( RegisterSlot ) ins = Risc.byte_to_reg("#{right.register.type}[#{right.index}] -> #{self.type}" , right.register , right.index , self) builder.add_code(ins) if builder return ins @@ -180,42 +181,15 @@ module Risc builder.add_code(ret) if builder ret end - # just capture the values in an intermediary object (RValue) - # The RValue then gets used in a RegToSlot ot SlotToReg, where + + # just capture the values in an intermediary object (RegisterSlot) + # The RegisterSlot then gets used in a RegToSlot or SlotToReg, where # the values are unpacked to call Risc.reg_to_slot or Risc.slot_to_reg def []( index ) - RValue.new( self , index , builder) + RegisterSlot.new( self , index , builder) end end - # Just a struct, see comment for [] of RegisterValue - # - class RValue - attr_reader :register , :index , :builder - def initialize(register, index , builder) - @register , @index , @builder = register , index , builder - end - - # fullfil the objects purpose by creating a RegToSlot instruction from - # itself (the slot) and the register given - def <<( reg ) - raise "not reg #{reg}" unless reg.is_a?(RegisterValue) - reg_to_slot = Risc.reg_to_slot("#{reg.class_name} -> #{register.class_name}[#{index}]" , reg , register, index) - builder.add_code(reg_to_slot) if builder - reg_to_slot - end - - # similar to above (<< which produces reg_to_slot), this produces reg_to_byte - # from itself (the slot) and the register given - def <=( reg ) - raise "not reg #{reg}" unless reg.is_a?(RegisterValue) - reg_to_byte = Risc.reg_to_byte("#{reg.class_name} -> #{register.class_name}[#{index}]" , reg , register, index) - builder.add_code(reg_to_byte) if builder - reg_to_byte - end - - end - # The register we use to store the current message object is :r0 def self.message_reg RegisterValue.new :r0 , :Message diff --git a/test/risc/test_builder.rb b/test/risc/test_builder.rb index 128ac556..acd3694d 100644 --- a/test/risc/test_builder.rb +++ b/test/risc/test_builder.rb @@ -29,13 +29,13 @@ module Risc assert_raises {@builder.space} end def test_reset - assert_equal :r1 , @builder.integer!.symbol + assert_equal :integer , @builder.integer!.symbol @builder.reset_names - assert_equal :r1 , @builder.integer!.symbol # would raise if it existed + assert_equal :integer , @builder.integer!.symbol # would raise if it existed end def test_next_message reg = @builder.next_message! - assert_equal :r1 , reg.symbol + assert_equal :next_message , reg.symbol assert_equal :Message , reg.type.class_name end def test_message @@ -54,16 +54,16 @@ module Risc assert_equal Transfer , built.next.class end def test_returns_slot - r2 = RegisterValue.new(:r2 , :Message).set_builder( @builder ) + r2 = RegisterValue.new(:message , :Message).set_builder( @builder ) @builder.build{ r2 << factory![:next_object] } assert_equal SlotToReg , built.class - assert_equal :r1 , built.array.symbol + assert_equal :factory , built.array.symbol end - def test_returns_slot_reverse + def pest_returns_slot_reverse r2 = RegisterValue.new(:r2 , :Message).set_builder( @builder ) @builder.build{ r2 << factory![:next_object] } assert_equal SlotToReg , built.class - assert_equal :r1 , built.array.symbol + assert_equal :factory , built.array.symbol end def test_reuses_names r1 = RegisterValue.new(:r1 , :Space) diff --git a/test/risc/test_builder1.rb b/test/risc/test_builder1.rb index 485c1fb2..cfdb4113 100644 --- a/test/risc/test_builder1.rb +++ b/test/risc/test_builder1.rb @@ -37,7 +37,7 @@ module Risc end def test_allocate_returns int = @builder.allocate_int - assert_equal :r1 , int.symbol + assert_equal :integer_tmp , int.symbol end def test_allocate_len int = @builder.allocate_int diff --git a/test/risc/test_builder2.rb b/test/risc/test_builder2.rb index d2fe0f26..6a0b5d69 100644 --- a/test/risc/test_builder2.rb +++ b/test/risc/test_builder2.rb @@ -30,7 +30,7 @@ module Risc assert_raises{ @builder.caller_reg! } end def test_define_conditionally_first - assert_equal :r1 , @builder.caller_reg?.symbol + assert_equal :caller_reg , @builder.caller_reg?.symbol end def test_define_conditionally_again first = @builder.caller_reg! diff --git a/test/risc/test_register_slot.rb b/test/risc/test_register_slot.rb new file mode 100644 index 00000000..f7114481 --- /dev/null +++ b/test/risc/test_register_slot.rb @@ -0,0 +1,79 @@ +require_relative "../helper" + +module Risc + class TestRegisterSlot < MiniTest::Test + def setup + Parfait.boot!(Parfait.default_test_options) + @r0 = RegisterValue.new(:message , :Message) + @r1 = RegisterValue.new(:id_1234 , :Space) + @r2 = RegisterValue.new(:id_1256 , :Factory) + end + def test_class_name_type + assert_equal :Message , @r0.class_name + end + def test_class_name_fix + assert_equal :Integer , RegisterValue.new(:id_234 , :Integer).class_name + end + def test_r0 + assert_equal :message , @r0.symbol + end + def test_load_space + move = @r0 << Parfait.object_space + assert_equal LoadConstant , move.class + end + def test_load_symbol + move = @r1 << :puts + assert_equal LoadConstant , move.class + end + def test_load_label + label = Risc::Label.new("HI","ho" , FakeAddress.new(0)) + move = @r1 << label + assert_equal LoadConstant , move.class + end + def test_transfer + transfer = @r0 << @r1 + assert_equal Transfer , transfer.class + end + def test_index_op + message = @r0[:next_message] + assert_equal RegisterSlot , message.class + assert_equal :next_message , message.index + assert_equal @r0 , message.register + end + def test_operator + ret = @r0.op :<< , @r1 + assert_equal OperatorInstruction , ret.class + assert_equal @r0 , ret.left + assert_equal @r1 , ret.right + assert_equal :<< , ret.operator + end + def test_byte_to_reg + instr = @r0 <= @r1[1] + assert_equal ByteToReg , instr.class + assert_equal @r1 , instr.array + assert_equal @r0 , instr.register + assert_equal 1 , instr.index + end + def est_slot_to_reg + instr = @r0 << @r2[:next_object] + assert_equal SlotToReg , instr.class + assert_equal @r0 , instr.register + assert_equal 2 , instr.index + assert_equal @r1 , instr.array + end + def test_reg_to_byte + instr = @r1[1] <= @r0 + assert_equal RegToByte , instr.class + assert_equal @r1 , instr.array + assert_equal @r0 , instr.register + assert_equal 1 , instr.index + end + def est_reg_to_slot + instr = @r2[:next_object] << @r0 + assert_equal RegToSlot , instr.class + assert_equal @r0 , instr.register + assert_equal 2 , instr.index + assert_equal @r1 , instr.array + end + end +end diff --git a/test/risc/test_register_value.rb b/test/risc/test_register_value.rb index 0c2a33a2..a3b2c257 100644 --- a/test/risc/test_register_value.rb +++ b/test/risc/test_register_value.rb @@ -54,7 +54,7 @@ module Risc end def test_index_op message = @r0[:next_message] - assert_equal RValue , message.class + assert_equal RegisterSlot , message.class assert_equal :next_message , message.index assert_equal @r0 , message.register end