diff --git a/lib/mom/block_compiler.rb b/lib/mom/block_compiler.rb index 350cb120..7cef35b3 100644 --- a/lib/mom/block_compiler.rb +++ b/lib/mom/block_compiler.rb @@ -4,7 +4,7 @@ module Mom # class BlockCompiler < CallableCompiler - attr_reader :block , :risc_instructions , :constants + attr_reader :block , :mom_instructions alias :block :callable def initialize( block , method) @@ -16,6 +16,13 @@ module Mom "#{@method.self_type.name}.init" end + def to_risc(in_method) + risc_compiler = Risc::BlockCompiler.new(@callable , in_method , mom_instructions) + instructions_to_risc(risc_compiler) + #recursive blocks not done + risc_compiler + end + # resolve the type of the slot, by inferring from it's name, using the type # scope related slots are resolved by the compiler by method/block # diff --git a/lib/mom/callable_compiler.rb b/lib/mom/callable_compiler.rb index 88848412..cef779fa 100644 --- a/lib/mom/callable_compiler.rb +++ b/lib/mom/callable_compiler.rb @@ -84,5 +84,21 @@ module Mom @callable.self_type end + private + + # convert al instruction to risc + # method is called by Method/BlockCompiler from to_risc + def instructions_to_risc(risc_compiler) + instruction = mom_instructions.next + while( instruction ) + raise "whats this a #{instruction}" unless instruction.is_a?(Mom::Instruction) + #puts "adding mom #{instruction.to_s}:#{instruction.next.to_s}" + instruction.to_risc( risc_compiler ) + risc_compiler.reset_regs + #puts "adding risc #{risc.to_s}:#{risc.next.to_s}" + instruction = instruction.next + end + end + end end diff --git a/lib/mom/method_compiler.rb b/lib/mom/method_compiler.rb index 5765927b..9581f142 100644 --- a/lib/mom/method_compiler.rb +++ b/lib/mom/method_compiler.rb @@ -4,16 +4,12 @@ module Mom # and to instantiate the methods correctly. class MethodCompiler < CallableCompiler + alias :callable :method def initialize( method ) super(method) end - #include block_compilers constants - def constants - block_compilers.inject(@constants.dup){|all, compiler| all += compiler.constants} - end - def source_name "#{@callable.self_type.name}.#{@callable.name}" end @@ -27,19 +23,16 @@ module Mom @callable end - # drop down to risc + # drop down to risc by converting this compilers instructions to risc. + # and the doing the same for any block_compilers def to_risc - risc_comp = Risc::MethodCompiler.new(@callable , mom_instructions) - instruction = mom_instructions.next - while( instruction ) - raise "whats this a #{instruction}" unless instruction.is_a?(Mom::Instruction) - #puts "adding mom #{instruction.to_s}:#{instruction.next.to_s}" - instruction.to_risc( risc_comp ) - risc_comp.reset_regs - #puts "adding risc #{risc.to_s}:#{risc.next.to_s}" - instruction = instruction.next + risc_compiler = Risc::MethodCompiler.new(@callable , mom_instructions) + instructions_to_risc(risc_compiler) + block_compilers.each do |m_comp| + puts "BLOCK #{m_comp}" + risc_compiler.block_compilers << m_comp.to_risc(@callable) end - risc_comp + risc_compiler end # helper method for builtin mainly diff --git a/lib/mom/mom_collection.rb b/lib/mom/mom_collection.rb index 61b78f1c..cdb6df5f 100644 --- a/lib/mom/mom_collection.rb +++ b/lib/mom/mom_collection.rb @@ -26,11 +26,6 @@ module Mom @method_compilers + boot_compilers end - # collects constants from all compilers into one array - def constants - compilers.inject([]){|sum ,comp| sum + comp.constants } - end - # Append another MomCompilers method_compilers to this one. def append(mom_compiler) @method_compilers += mom_compiler.method_compilers diff --git a/lib/risc/block_compiler.rb b/lib/risc/block_compiler.rb index 73eef675..5ad409b9 100644 --- a/lib/risc/block_compiler.rb +++ b/lib/risc/block_compiler.rb @@ -4,16 +4,15 @@ module Risc # class BlockCompiler < CallableCompiler - attr_reader :block , :risc_instructions , :constants - alias :block :callable + attr_reader :block , :risc_instructions , :constants , :in_method - def initialize( block , method) - @method = method - super(block) + def initialize( block , in_method , mom_label) + @in_method = in_method + super(block , mom_label) end def source_name - "#{@method.self_type.name}.init" + "#{@in_method.self_type.name}.init" end # resolve the type of the slot, by inferring from it's name, using the type @@ -24,9 +23,9 @@ module Risc def slot_type( slot , type) new_type = super if slot == :caller - extra_info = { type_frame: @method.frame_type , - type_arguments: @method.arguments_type , - type_self: @method.self_type} + extra_info = { type_frame: @in_method.frame_type , + type_arguments: @in_method.arguments_type , + type_self: @in_method.self_type} end return new_type , extra_info end @@ -38,9 +37,9 @@ module Risc slot_def = [:arguments] elsif @callable.frame_type.variable_index(name) slot_def = [:frame] - elsif @method.arguments_type.variable_index(name) + elsif @in_method.arguments_type.variable_index(name) slot_def = [:caller , :caller ,:arguments ] - elsif @method.frame_type.variable_index(name) + elsif @in_method.frame_type.variable_index(name) slot_def = [:caller ,:caller , :frame ] elsif raise "no variable #{name} , need to resolve at runtime" diff --git a/lib/risc/callable_compiler.rb b/lib/risc/callable_compiler.rb index c5e13530..85b0aef9 100644 --- a/lib/risc/callable_compiler.rb +++ b/lib/risc/callable_compiler.rb @@ -30,7 +30,6 @@ module Risc end end - # add a constant (which get created during compilation and need to be linked) def add_constant(const) raise "Must be Parfait #{const}" unless const.is_a?(Parfait::Object) diff --git a/lib/rubyx/rubyx_compiler.rb b/lib/rubyx/rubyx_compiler.rb index 564dbf33..b10f710f 100644 --- a/lib/rubyx/rubyx_compiler.rb +++ b/lib/rubyx/rubyx_compiler.rb @@ -51,9 +51,9 @@ module RubyX # # After creating vool, we call to_target # Return a Linker - def ruby_to_target(ruby) + def ruby_to_target(ruby , platform) ruby_to_vool(ruby) - to_target() + to_target( platform ) end # ruby_to_risc creates Risc instructions diff --git a/lib/vool/assignment.rb b/lib/vool/assignment.rb index 0c29b35d..e5838e0f 100644 --- a/lib/vool/assignment.rb +++ b/lib/vool/assignment.rb @@ -3,6 +3,8 @@ module Vool class Assignment < Statement attr_reader :name , :value def initialize(name , value ) + raise "Name nil #{self}" unless name + raise "Value nil #{self}" unless value @name , @value = name , value end diff --git a/test/mom/blocks/test_block_assign.rb b/test/mom/blocks/test_block_assign.rb new file mode 100644 index 00000000..8f9d0bc5 --- /dev/null +++ b/test/mom/blocks/test_block_assign.rb @@ -0,0 +1,56 @@ +require_relative "../helper" + +module Risc + class TestBlockAssign < MiniTest::Test + include Statements + + def setup + super + @input = as_block("return 5") + @expect = [LoadConstant, SlotToReg, RegToSlot, LoadConstant, SlotToReg, #4 + RegToSlot, LoadConstant, LoadConstant, SlotToReg, SlotToReg, #9 + RegToSlot, RegToSlot, RegToSlot, RegToSlot, SlotToReg, #14 + SlotToReg, RegToSlot, SlotToReg, SlotToReg, SlotToReg, #19 + SlotToReg, RegToSlot, LoadConstant, SlotToReg, RegToSlot, #24 + SlotToReg, FunctionCall, Label] + end + def test_send_instructions + assert_nil msg = check_nil(produce_block) , msg + end + def test_load_5 + produced = produce_body + assert_load( produced , Parfait::Integer) + assert_equal 5 , produced.constant.value + end + def test_load_block + produced = produce_body.next(3) + assert_load( produced , Parfait::Block) + assert_equal :main_block , produced.constant.name + end + def test_load_method_to_call + produced = produce_body.next(6) + assert_load( produced , Parfait::CallableMethod) + assert_equal :main , produced.constant.name + end + def test_load_next_message + produced = produce_body.next(7) + assert_load( produced , Parfait::Factory) + assert_equal "Message_Type" , produced.constant.for_type.name + end + def test_load_return + produced = produce_body.next(22) + assert_load( produced , Label) + assert produced.constant.name.start_with?("continue_") + end + def test_function_call + produced = produce_body.next(26) + assert_equal FunctionCall , produced.class + assert_equal :main , produced.method.name + end + def test_check_continue + produced = produce_body.next(27) + assert_equal Label , produced.class + assert produced.name.start_with?("continue_") + end + end +end diff --git a/test/mom/blocks/test_block_compiler.rb b/test/mom/blocks/test_block_compiler.rb new file mode 100644 index 00000000..37eeab7b --- /dev/null +++ b/test/mom/blocks/test_block_compiler.rb @@ -0,0 +1,32 @@ +require_relative "../helper" + +module Risc + class TestBlockSetup < MiniTest::Test + include Statements + + def setup + super + @input = as_block("return 5") + @mom = RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_mom(as_test_main) + end + def main_risc + @mom.to_risc.method_compilers.find{|c| c.callable.name == :main } + end + def test_mom + assert_equal Mom::MomCollection , @mom.class + end + def test_mom_block_comp + assert_equal 1 , @mom.method_compilers.first.block_compilers.length + end + def test_risc + assert_equal Risc::RiscCollection , @mom.to_risc.class + end + def test_risc_comp + assert_equal :main , main_risc.callable.name + end + def test_risc_block_comp + assert_equal 1 , main_risc.block_compilers.length + end + + end +end diff --git a/test/mom/blocks/test_block_setup.rb b/test/mom/blocks/test_block_setup.rb new file mode 100644 index 00000000..e51f3e1f --- /dev/null +++ b/test/mom/blocks/test_block_setup.rb @@ -0,0 +1,57 @@ +require_relative "../helper" + +module Risc + class TestBlockSetup < MiniTest::Test + include Statements + + def setup + super + @input = as_block("return 5") + @expect = [LoadConstant, SlotToReg, RegToSlot, LoadConstant, SlotToReg, #4 + RegToSlot, LoadConstant, LoadConstant, SlotToReg, SlotToReg, #9 + RegToSlot, RegToSlot, RegToSlot, RegToSlot, SlotToReg, #14 + SlotToReg, RegToSlot, SlotToReg, SlotToReg, SlotToReg, #19 + SlotToReg, RegToSlot, LoadConstant, SlotToReg, RegToSlot, #24 + SlotToReg, FunctionCall, Label] + end + + def test_send_instructions + assert_nil msg = check_nil , msg + end + def test_load_5 + produced = produce_body + assert_load( produced , Parfait::Integer) + assert_equal 5 , produced.constant.value + end + def test_load_block + produced = produce_body.next(3) + assert_load( produced , Parfait::Block) + assert_equal :main_block , produced.constant.name + end + def test_load_method_to_call + produced = produce_body.next(6) + assert_load( produced , Parfait::CallableMethod) + assert_equal :main , produced.constant.name + end + def test_load_next_message + produced = produce_body.next(7) + assert_load( produced , Parfait::Factory) + assert_equal "Message_Type" , produced.constant.for_type.name + end + def test_load_return + produced = produce_body.next(22) + assert_load( produced , Label) + assert produced.constant.name.start_with?("continue_") + end + def test_function_call + produced = produce_body.next(26) + assert_equal FunctionCall , produced.class + assert_equal :main , produced.method.name + end + def test_check_continue + produced = produce_body.next(27) + assert_equal Label , produced.class + assert produced.name.start_with?("continue_") + end + end +end diff --git a/test/mom/helper.rb b/test/mom/helper.rb index b1472284..a7d90196 100644 --- a/test/mom/helper.rb +++ b/test/mom/helper.rb @@ -24,17 +24,32 @@ module Risc preamble.each{ produced = produced.next } produced end + + def as_block( block_input , method_input = "main_local = 5") + "#{method_input} ; self.main{|val| #{block_input}}" + end def as_test_main "class Test; def main(arg);#{@input};end;end" end - def produce_instructions + def to_target assert @expect , "No output given" - linker = RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_risc(as_test_main).translate(:interpreter) - compiler = linker.assemblers.find{|c| c.callable.name == :main and c.callable.self_type.object_class.name == :Test} - compiler.instructions + RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_target(as_test_main,:interpreter) end - def check_nil - produced = produce_instructions + def find_main + assert @expect , "No output given" + linker = to_target + linker.assemblers.find{|c| c.callable.name == :main and c.callable.self_type.object_class.name == :Test} + end + def produce_instructions + find_main.instructions + end + def produce_block + linker = to_target + linker.assemblers.each {|c| puts c.callable.name} + linker.block_compilers.first.instructions + end + def check_nil( instructions = nil ) + produced = instructions || produce_instructions compare_instructions( produced , @expect) end def check_return diff --git a/test/mom/test_block_compiler.rb b/test/mom/test_block_compiler.rb index 579b03d9..c4f50a66 100644 --- a/test/mom/test_block_compiler.rb +++ b/test/mom/test_block_compiler.rb @@ -1,85 +1,23 @@ -require_relative "../helper" +require_relative "helper" module Mom class TestBlockCompiler < MiniTest::Test - include MomCompile + include ScopeHelper def setup - Parfait.boot!(Parfait.default_test_options) - @ins = compile_first_block( "local = 5") + code = as_test_main_block("return 5" , "a = 1") + @risc = RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_risc(code) end - def test_block_compiles - assert_equal Mom::SlotLoad , @ins.class , @ins + def test_collection + assert_equal Risc::RiscCollection, @risc.class end - def test_slot_is_set - assert @ins.left + def test_main_compiler + assert_equal :main , @risc.method_compilers.first.callable.name end - def test_slot_starts_at_message - assert_equal :message , @ins.left.known_object - end - def test_slots_left - assert_equal [:frame , :local] , @ins.left.slots - end - def test_slot_assigns_something - assert @ins.right - end - def test_slot_assigns_int - assert_equal Mom::IntegerConstant , @ins.right.known_object.class + def test_main_block_compiler + assert_equal :main , @risc.method_compilers.first.block_compilers.first.in_method.name + assert_equal :main_block , @risc.method_compilers.first.block_compilers.first.callable.name end end - - class TestAssignMomInstanceToLocal < MiniTest::Test - include MomCompile - def setup - Parfait.boot!(Parfait.default_test_options) - @ins = compile_first_block( "local = @a" , "@a = 5") #second arg in method scope - end - def test_class_compiles - assert_equal Mom::SlotLoad , @ins.class , @ins - end - def test_slots_left - assert_equal [:frame, :local] , @ins.left.slots - end - def test_slots_right - assert_equal [:receiver, :a] , @ins.right.slots - end - end - - class TestAssignToArg < MiniTest::Test - include MomCompile - - def setup - Parfait.boot!(Parfait.default_test_options) - @ins = compile_first_block( "arg = 5") - end - - def test_class_compiles - assert_equal Mom::SlotLoad , @ins.class , @ins - end - def test_slot_is_set - assert @ins.left - end - def test_slots_left - assert_equal [:caller,:caller, :arguments, :arg] , @ins.left.slots - end - end - - class TestAssignMomToInstance < MiniTest::Test - include MomCompile - def setup - Parfait.boot!(Parfait.default_test_options) - end - def test_assigns_const - @ins = compile_first_block( "@a = 5") - assert_equal Mom::SlotLoad , @ins.class , @ins - assert_equal Mom::IntegerConstant , @ins.right.known_object.class , @ins - end - def test_assigns_move - @ins = compile_first_block( "@a = arg") - assert_equal Mom::SlotLoad , @ins.class , @ins - assert_equal Mom::SlotDefinition , @ins.right.class , @ins - end - end - end diff --git a/test/mom/test_mom_collection.rb b/test/mom/test_mom_collection.rb index 09cf9426..4328e39b 100644 --- a/test/mom/test_mom_collection.rb +++ b/test/mom/test_mom_collection.rb @@ -21,12 +21,6 @@ module Mom def test_compilers_bare assert_equal 21 , MomCollection.new.compilers.length end - def test_returns_constants - assert_equal Array , @comp.constants.class - end - def test_has_constant_before - assert_equal [] , @comp.constants - end def test_append_class assert_equal MomCollection, (@comp.append @comp).class end diff --git a/test/support/compiling.rb b/test/support/compiling.rb index 281d142b..ec14a05c 100644 --- a/test/support/compiling.rb +++ b/test/support/compiling.rb @@ -16,39 +16,31 @@ module ScopeHelper def as_test_main( statements ) in_Test("def main(arg) ; #{statements}; end") end + + def as_test_main_block( block_input = "return 5", method_input = "main_local = 5") + as_test_main("#{method_input} ; self.main{|val| #{block_input}}") + end + end module VoolCompile include ScopeHelper include Mom - def compile_vool_method(input) - statements = RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_vool(as_main(input)) - assert statements.is_a?(Vool::Statement) , statements.class - statements - end - def compile_method(input) + + def compile_first_method( input ) + inut = as_test_main( input ) collection = RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_mom(input) assert collection.is_a?(Mom::MomCollection) compiler = collection.compilers.first assert compiler.is_a?(Mom::MethodCompiler) + assert_equal Mom::MethodCompiler , compiler.class compiler end - def compile_first_method( input ) - ret = compile_method( as_test_main( input )) - assert_equal Mom::MethodCompiler , ret.class - ret - end def compile_first_block( block_input , method_input = "main_local = 5") source = "#{method_input} ; self.main{|val| #{block_input}}" - vool = Ruby::RubyCompiler.compile( as_test_main(source) ).to_vool - mom_c = vool.to_mom(nil) - compiler = mom_c.method_compilers.find{|c| c.get_method.name == :main and c.get_method.self_type.object_class.name == :Test} - block = nil - vool.each {|b| block = b if b.is_a?(Vool::BlockStatement)} - assert block - block_c = compiler.block_compilers.first - assert block_c - block.body.to_mom(block_c) + risc_col = RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_risc( as_test_main(source) ) + compiler = risc_col.method_compilers.find{|c| c.get_method.name.to_s.start_with?("implicit") } + assert_equal 1 , compiler.class end def check_array( should , is ) index = 0 @@ -79,34 +71,6 @@ end module MomCompile include ScopeHelper - def compile_method(input) - statements = RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_vool(input) - assert statements.is_a?(Vool::ClassStatement) - ret = statements.to_mom(nil) - assert_equal Parfait::Class , statements.clazz.class , statements - @method = statements.clazz.get_method(:main) - assert_equal Parfait::VoolMethod , @method.class - ret - end - def compile_first_method( input ) - ret = compile_method( as_test_main( input )) - assert_equal Mom::MomCompiler , ret.class - compiler = ret.method_compilers.find{|c| c.get_method.name == :main and c.get_method.self_type.object_class.name == :Test} - assert_equal Risc::MethodCompiler , compiler.class - @method.source.to_mom( compiler ) - end - def compile_first_block( block_input , method_input = "main_local = 5") - source = "#{method_input} ; self.main{|val| #{block_input}}" - vool = Ruby::RubyCompiler.compile( as_test_main(source) ).to_vool - mom_c = vool.to_mom(nil) - compiler = mom_c.method_compilers.find{|c| c.get_method.name == :main and c.get_method.self_type.object_class.name == :Test} - block = nil - vool.each {|b| block = b if b.is_a?(Vool::BlockStatement)} - assert block - block_c = compiler.block_compilers.first - assert block_c - block.body.to_mom(block_c) - end def compile_mom(input) RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_mom(input) end diff --git a/test/vool/blocks/test_assign.rb b/test/vool/blocks/test_assign.rb index 2c6c4d3e..9afb3a70 100644 --- a/test/vool/blocks/test_assign.rb +++ b/test/vool/blocks/test_assign.rb @@ -6,25 +6,25 @@ module VoolBlocks def setup Parfait.boot!(Parfait.default_test_options) - @ins = compile_first_block( "local = 5") + @ins = compile_first_block( "local = 5" ) end def test_block_compiles assert_equal Mom::SlotLoad , @ins.class , @ins end - def test_slot_is_set + def pest_slot_is_set assert @ins.left end - def test_slot_starts_at_message + def pest_slot_starts_at_message assert_equal :message , @ins.left.known_object end - def test_slots_left + def pest_slots_left assert_equal [:frame , :local] , @ins.left.slots end - def test_slot_assigns_something + def pest_slot_assigns_something assert @ins.right end - def test_slot_assigns_int + def pest_slot_assigns_int assert_equal Mom::IntegerConstant , @ins.right.known_object.class end end @@ -35,13 +35,13 @@ module VoolBlocks Parfait.boot!(Parfait.default_test_options) @ins = compile_first_block( "local = @a" , "@a = 5") #second arg in method scope end - def test_class_compiles + def pest_class_compiles assert_equal Mom::SlotLoad , @ins.class , @ins end - def test_slots_left + def pest_slots_left assert_equal [:frame, :local] , @ins.left.slots end - def test_slots_right + def pest_slots_right assert_equal [:receiver, :a] , @ins.right.slots end end @@ -54,13 +54,13 @@ module VoolBlocks @ins = compile_first_block( "arg = 5") end - def test_class_compiles + def pest_class_compiles assert_equal Mom::SlotLoad , @ins.class , @ins end - def test_slot_is_set + def pest_slot_is_set assert @ins.left end - def test_slots_left + def pest_slots_left assert_equal [:caller,:caller, :arguments, :arg] , @ins.left.slots end end @@ -70,12 +70,12 @@ module VoolBlocks def setup Parfait.boot!(Parfait.default_test_options) end - def test_assigns_const + def pest_assigns_const @ins = compile_first_block( "@a = 5") assert_equal Mom::SlotLoad , @ins.class , @ins assert_equal Mom::IntegerConstant , @ins.right.known_object.class , @ins end - def test_assigns_move + def pest_assigns_move @ins = compile_first_block( "@a = arg") assert_equal Mom::SlotLoad , @ins.class , @ins assert_equal Mom::SlotDefinition , @ins.right.class , @ins