diff --git a/lib/mom/instruction/truth_check.rb b/lib/mom/instruction/truth_check.rb index 75b2c409..f9a1c010 100644 --- a/lib/mom/instruction/truth_check.rb +++ b/lib/mom/instruction/truth_check.rb @@ -1,10 +1,21 @@ module Mom # A base class for conditions in MOM - # Just a marker, no real functionality for now - + # Checks (if in code, compare in assm) jump or not, depending + # The logic we choose is closer to the code logic (the asm is reversed) + # When we write an if, the true is the next code, so the Check logic is + # that if the check passes, no jump happens + # This means you need to pass the false label, where to jump to if the + # check does not pass + # Note: In assembler a branch on 0 does just that, it branches if the condition + # is met. This means that the asm implementation is somewhat the reverse + # of the Mom names. But it's easier to understand (imho) class Check < Instruction - + attr_reader :false_jump + def initialize(false_jump) + @false_jump = false_jump + raise "Jump target must be a label #{false_jump}" unless false_jump.is_a?(Label) + end end # The funny thing about the ruby truth is that is is anything but false or nil @@ -15,8 +26,10 @@ module Mom class TruthCheck < Check attr_reader :condition - def initialize(condition) + def initialize(condition , false_jump) + super(false_jump) @condition = condition + raise "condition must be slot_definition #{condition}" unless condition.is_a?(SlotDefinition) end def to_risc(compiler) diff --git a/lib/vool/statements/assign_statement.rb b/lib/vool/statements/assign_statement.rb index eb1c7cf8..89ba9dd3 100644 --- a/lib/vool/statements/assign_statement.rb +++ b/lib/vool/statements/assign_statement.rb @@ -14,9 +14,7 @@ module Vool def chain_assign(assign , method) return assign unless @value.is_a?(SendStatement) - first = @value.to_mom(method) - first.next = assign - return first + @value.to_mom(method) << assign end def each(&block) diff --git a/lib/vool/statements/basic_values.rb b/lib/vool/statements/basic_values.rb index 782676d9..d6bf7781 100644 --- a/lib/vool/statements/basic_values.rb +++ b/lib/vool/statements/basic_values.rb @@ -49,8 +49,8 @@ module Vool def initialize(type = nil) @my_type = type end - def to_mom(in_method) - @clazz = in_method.clazz + def slot_definition(in_method) + @my_type = in_method.for_type Mom::SlotDefinition.new(:message , [:receiver]) end def ct_type diff --git a/lib/vool/statements/method_statement.rb b/lib/vool/statements/method_statement.rb index 21c29c22..edb44245 100644 --- a/lib/vool/statements/method_statement.rb +++ b/lib/vool/statements/method_statement.rb @@ -4,7 +4,7 @@ module Vool def initialize( name , args , body , clazz = nil) @name , @args , @body = name , args , body - raise "no bod" unless body + raise "no bod" unless @body @clazz = clazz end diff --git a/lib/vool/statements/send_statement.rb b/lib/vool/statements/send_statement.rb index 16b9f9c6..26f8cf75 100644 --- a/lib/vool/statements/send_statement.rb +++ b/lib/vool/statements/send_statement.rb @@ -46,6 +46,12 @@ module Vool end end + # When used as right hand side, this tells what data to move to get the result into + # a varaible. It is (off course) the return value of the message + def slot_definition(in_method) + Mom::SlotDefinition.new(:message ,[ :return_value]) + end + def message_setup(in_method) setup = Mom::MessageSetup.new(in_method) << Mom::SlotLoad.new([:message , :next_message , :receiver] , @receiver.slot_definition(in_method)) diff --git a/lib/vool/statements/statements.rb b/lib/vool/statements/statements.rb index 4bcc9248..9644d29b 100644 --- a/lib/vool/statements/statements.rb +++ b/lib/vool/statements/statements.rb @@ -28,7 +28,7 @@ module Vool self end - # create machine instructions + # create mom instructions def to_mom( method ) raise "Empty list ? #{statements.length}" unless @statements[0] flat = @statements.shift.to_mom(method) @@ -48,13 +48,21 @@ module Vool end def normalize - Statements.new(@statements.collect{|s| s.normalize}) + if( single? ) + first.normalize + else + Statements.new(@statements.collect{|s| s.normalize}) + end end end class ScopeStatement < Statements def normalize - ScopeStatement.new(@statements.collect{|s| s.normalize}) + if( single? ) + first.normalize + else + ScopeStatement.new(@statements.collect{|s| s.normalize}) + end end end end diff --git a/lib/vool/statements/while_statement.rb b/lib/vool/statements/while_statement.rb index b075ce1d..ca2485bb 100644 --- a/lib/vool/statements/while_statement.rb +++ b/lib/vool/statements/while_statement.rb @@ -3,49 +3,34 @@ require_relative "normalizer" module Vool class WhileStatement < Statement include Normalizer - attr_reader :condition , :statements + attr_reader :condition , :body - def initialize( condition , statements ) + def initialize( condition , body ) @condition = condition - @statements = statements - simplify_condition + @body = body end - def normalize(method) - cond , rest = *normalize_name(@condition) - me = WhileStatement.new(cond , @statements.normalize(method)) + def normalize + cond , rest = *normalize_name(@condition.normalize) + me = WhileStatement.new(cond , @body.normalize) return me unless rest rest << me + rest end def to_mom( method ) - statements = @statements.to_mom( method ) - condition , hoisted = hoist_condition( method ) - cond = Mom::TruthCheck.new(condition.to_mom(method)) - check = Mom::WhileStatement.new( cond , statements ) - check.hoisted = hoisted.to_mom(method) if hoisted - check + merge_label = Mom::Label.new( "merge_label_#{object_id}") + cond_label = Mom::Label.new( "cond_label_#{object_id}") + cond_label << Mom::TruthCheck.new(condition.slot_definition(method) , merge_label) + cond_label << @body.to_mom(method) + cond_label << Mom::Jump.new(cond_label) + cond_label << merge_label end - def flatten(options = {}) - merge_label = Label.new( "merge_label_#{object_id}") - cond_label = Label.new( "cond_label_#{object_id}") - @nekst = cond_label - @nekst.append(hoisted.flatten) if hoisted - @nekst.append condition.flatten( true_label: cond_label , false_label: merge_label) - @nekst.append merge_label - @nekst - end - - def simplify_condition - return unless @condition.is_a?(ScopeStatement) - @condition = @condition.first if @condition.single? - end - - def collect(arr) - @condition.collect(arr) - @statements.collect(arr) - super + def each(&block) + block.call(self) + @condition.each(&block) + @body.each(&block) end end diff --git a/test/support/compiling.rb b/test/support/compiling.rb index 83a899b9..c75ac739 100644 --- a/test/support/compiling.rb +++ b/test/support/compiling.rb @@ -22,11 +22,13 @@ module MomCompile include CompilerHelper def compile_first_method input - lst = Vool::VoolCompiler.ruby_to_vool as_test_main( input ) - assert_equal Parfait::Class , lst.clazz.class , lst - @method = lst.clazz.get_method(:main) + # works a lot like Vool.ruby_to_vool + statements = Vool::RubyCompiler.compile as_test_main( input ) + statements = statements.normalize + res = statements.create_objects + assert_equal Parfait::Class , statements.clazz.class , statements + @method = statements.clazz.get_method(:main) assert_equal Parfait::VoolMethod , @method.class - res = lst.create_objects #puts "#{res.class}" res end diff --git a/test/vool/to_mom/test_while_condition.rb b/test/vool/to_mom/test_while_condition.rb index bb2a72a9..0ed7e0f5 100644 --- a/test/vool/to_mom/test_while_condition.rb +++ b/test/vool/to_mom/test_while_condition.rb @@ -4,24 +4,25 @@ require_relative "helper" module Vool class TestWhileConditionMom < MiniTest::Test include MomCompile + include Mom def setup Risc.machine.boot - @stats = compile_first_method( "while(@a == 5) ; 5.mod4 ; end") - @first = @stats.first + @ins = compile_first_method( "while(5.mod4) ; 5.mod4 ; end") end - def test_if_compiles_as_array - assert_equal Mom::WhileStatement , @first.class , @stats - end - def test_condition_compiles_to_slot - assert_equal Mom::TruthCheck , @first.condition.class + def test_condition_compiles_to_check + assert_equal TruthCheck , @ins.next(6).class end def test_condition_is_slot - assert_equal Mom::SlotDefinition , @first.condition.condition.class , @stats + assert_equal SlotDefinition , @ins.next(6).condition.class , @ins end def test_hoisetd - assert_equal Mom::SlotLoad , @first.hoisted.class + assert_equal MessageSetup , @ins.class end + def test_array + check_array [MessageSetup,SlotLoad,ArgumentTransfer,SimpleCall,SlotLoad,Label,TruthCheck,MessageSetup,SlotLoad,ArgumentTransfer,SimpleCall,Jump,Label] , @ins + end + end end