Fix forgotten block compiler

Especially on the way down to risc
This commit is contained in:
Torsten Rüger 2019-08-13 19:32:17 +03:00
parent 8036b23593
commit 155c042009
16 changed files with 250 additions and 183 deletions

View File

@ -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
#

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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