diff --git a/lib/risc/builder.rb b/lib/risc/builder.rb index f039df67..32db670d 100644 --- a/lib/risc/builder.rb +++ b/lib/risc/builder.rb @@ -12,7 +12,7 @@ module Risc # class Builder - attr_reader :built , :compiler , :names + attr_reader :built , :compiler # pass a compiler, to which instruction are added (usually) # call build with a block to build @@ -22,38 +22,6 @@ module Risc @compiler = compiler @source = for_source @source_used = false - @names = {} - end - - # make the magic: convert incoming names into registers that have the - # type set according to the name (using infer_type) - # names are stored, so subsequent calls use the same register - def method_missing(name , *args) - return super if args.length != 0 - name = name.to_s - return @names[name] if @names.has_key?(name) - if name == "message" - return Risc.message_reg.set_builder(self) - end - if name.index("label") - reg = Risc.label( @source , "#{name}_#{object_id}") - @source_used = true - else - last_char = name[-1] - name = name[0 ... -1] - if last_char == "!" or last_char == "?" - if @names.has_key?(name) - return @names[name] if last_char == "?" - raise "Name exists (#{@names.keys})before creating it #{name}#{last_char}" - end - else - raise "Must create (with ! or ?) before using #{name}#{last_char}" - end - type = infer_type(name ) - reg = RegisterValue.new( name.to_sym , type.object_class.name ).set_builder(self) - end - @names[name] = reg - reg end # Infer the type from a symbol. In the simplest case the symbol is the class name. @@ -94,31 +62,6 @@ module Risc add_code Risc::Branch.new(@source, label) end - # To avoid many an if, it can be handy to swap variable names. - # But since the names in the builder are not variables, we need this method. - # As it says, swap the two names around. Names must exist - def swap_names(left , right) - left , right = left.to_s , right.to_s - l = @names[left] - r = @names[right] - raise "No such name #{left}" unless l - raise "No such name #{right}" unless r - @names[left] = r - @names[right] = l - end - - # Reset the names stored by the builder. The names are sort of variables names - # that can be used in the build block due to method_missing magic. - # - # But just as the compiler has reset_regs, the builder has this reset button, to - # start fresh. Quite crude for now, and only used in allocate_int - # - # Compiler regs are reset as well - def reset_names - @names = {} - compiler.reset_regs - end - # Build code using dsl (see __init__ or MessageSetup for examples). # Names (that ruby would resolve to a variable/method) are converted # to registers. << means assignment and [] is supported both on @@ -136,6 +79,11 @@ module Risc instance_eval(&block) end + # make the message register available for the dsl + def message + Risc.message_named_reg.set_compiler(@compiler) + end + # add code straight to the compiler def add_code(ins) @compiler.add_code(ins) @@ -178,23 +126,18 @@ module Risc # # Return RegisterValue(:r1) that will be named integer_tmp def allocate_int - compiler.reset_regs - integer = self.integer! + cont_label = Risc.label("continue int allocate" , "cont_label") + factory = load_object Parfait.object_space.get_factory_for(:Integer) + null = load_object Parfait.object_space.nil_object build do - factory! << Parfait.object_space.get_factory_for(:Integer) - integer << factory[:next_object] - object! << Parfait.object_space.nil_object - object - integer + null.op :- , factory[:next_object] if_not_zero cont_label - integer_2! << factory[:reserve] - factory[:next_object] << integer_2 + factory[:next_object] << factory[:reserve] call_get_more integer << factory[:next_object] add_code cont_label - integer_2 << integer[:next_integer] - factory[:next_object] << integer_2 + factory[:next_object] << integer[:next_integer] end - reset_names integer_tmp! end @@ -207,15 +150,13 @@ module Risc # - issuing the call # These steps shadow the SlotMachineInstructions MessageSetup, ArgumentTransfer and SimpleCall def call_get_more - factory = Parfait.object_space.get_factory_for( :Integer ) - calling = factory.get_type.get_method( :get_more ) + int_factory = Parfait.object_space.get_factory_for(:Integer) + factory = load_object int_factory + calling = int_factory.get_type.get_method( :get_more ) calling = Parfait.object_space.get_method!(:Space,:main) #until we actually parse Factory raise "no main defined" unless calling SlotMachine::MessageSetup.new( calling ).build_with( self ) - self.build do - factory_reg! << factory - message[:receiver] << factory_reg - end + message[:receiver] << factory SlotMachine::SimpleCall.new(calling).to_risc(compiler) end diff --git a/test/risc/test_builder.rb b/test/risc/test_builder.rb index acd3694d..5f74bb2d 100644 --- a/test/risc/test_builder.rb +++ b/test/risc/test_builder.rb @@ -20,72 +20,11 @@ module Risc def test_has_attribute assert_nil @builder.built end - def test_alloc_space - reg = @builder.space! - assert_equal RegisterValue , reg.class - assert_equal :Space , reg.type.class_name - end - def test_not_alloc_space - assert_raises {@builder.space} - end - def test_reset - assert_equal :integer , @builder.integer!.symbol - @builder.reset_names - assert_equal :integer , @builder.integer!.symbol # would raise if it existed - end - def test_next_message - reg = @builder.next_message! - assert_equal :next_message , reg.symbol - assert_equal :Message , reg.type.class_name - end def test_message reg = @builder.message - assert_equal :r0 , reg.symbol + assert_equal :message , reg.symbol assert_equal :Message , reg.type.class_name end - def test_returns_built - r1 = RegisterValue.new(:r1 , :Space) - @builder.build{ space! << r1 } - assert_equal Transfer , built.class - end - def test_returns_two - r1 = RegisterValue.new(:r1 , :Space) - @builder.build{ space! << r1 ; space << r1} - assert_equal Transfer , built.next.class - end - def test_returns_slot - r2 = RegisterValue.new(:message , :Message).set_builder( @builder ) - @builder.build{ r2 << factory![:next_object] } - assert_equal SlotToReg , built.class - assert_equal :factory , built.array.symbol - end - 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 :factory , built.array.symbol - end - def test_reuses_names - r1 = RegisterValue.new(:r1 , :Space) - @builder.build{ space! << r1 ; space << r1} - assert_equal built.to.symbol , built.next.to.symbol - end - def test_uses_message_as_message - r1 = RegisterValue.new(:r1 , :Space) - @builder.build{ message[:receiver] << r1} - assert_equal RegToSlot , built.class - assert_equal :r0 , built.array.symbol - end - def test_label - label = @builder.exit_label - assert_equal Label , label.class - assert label.name.index("exit") - end - def test_two_label - label1 = @builder.exit_label - label2 = @builder.exit_label - assert_equal label1 , label2 - end def test_if_zero ret = @builder.if_zero @label assert_equal IsZero , ret.class @@ -101,11 +40,5 @@ module Risc assert_equal Branch , ret.class assert_equal @label , ret.label end - def test_minus - op = @builder.build {space! - callable_method!} - assert_equal OperatorInstruction , op.class - assert_equal :- , op.operator - assert_equal :Space , op.left.type.class_name - end end end diff --git a/test/risc/test_builder1.rb b/test/risc/test_builder1.rb index cfdb4113..078f3d85 100644 --- a/test/risc/test_builder1.rb +++ b/test/risc/test_builder1.rb @@ -9,31 +9,8 @@ module Risc @compiler = Risc::MethodCompiler.new( @method , SlotMachine::Label.new( "source_name", "return_label")) @builder = @compiler.builder(@method) end - def test_inserts_built - r1 = RegisterValue.new(:r1 , :Space) - @builder.build{ space! << r1 } - assert_equal Transfer , @compiler.risc_instructions.next.class - assert_equal RegisterValue , @builder.space.class - end - def test_loads - @builder.build{ space! << Parfait.object_space } - assert_equal LoadConstant , @compiler.risc_instructions.next.class - assert_equal RegisterValue , @builder.space.class - end - def test_two - @builder.build{ space! << Parfait.object_space ; integer! << 1} - assert_equal LoadConstant , @compiler.risc_instructions.next.class - assert_equal LoadData , @compiler.risc_instructions.next(2).class - end - def test_swap - test_two - @builder.swap_names( :space , :integer) - assert_equal :Integer , @builder.space.type.class_name - assert_equal :Space , @builder.integer.type.class_name - end def test_prepare_int - int = @builder.prepare_int_return - assert_raises { @builder.integer_tmp} + assert @builder.prepare_int_return end def test_allocate_returns int = @builder.allocate_int diff --git a/test/risc/test_builder2.rb b/test/risc/test_builder2.rb index 6a0b5d69..1b56fc79 100644 --- a/test/risc/test_builder2.rb +++ b/test/risc/test_builder2.rb @@ -25,17 +25,6 @@ module Risc def test_caller_reg assert_equal :Message , @builder.infer_type(:caller_reg).class_name end - def test_define_twice - @builder.caller_reg! - assert_raises{ @builder.caller_reg! } - end - def test_define_conditionally_first - assert_equal :caller_reg , @builder.caller_reg?.symbol - end - def test_define_conditionally_again - first = @builder.caller_reg! - assert_equal first , @builder.caller_reg? - end def test_caller_tmp assert_equal :Message , @builder.infer_type(:caller_tmp).class_name end