Fix vool assignments after call rework

also small fix for if and return, as they need to execute sneds and yields (not just sends), so testing for Call not SendStatement
This commit is contained in:
Torsten Rüger 2019-08-16 20:39:08 +03:00
parent e6c30d98fb
commit 7c91a08d5b
9 changed files with 103 additions and 44 deletions

View File

@ -9,10 +9,10 @@ module Ruby
end
def to_vool
val , rest = *normalize_name(@return_value)
me = Vool::ReturnStatement.new(val.to_vool)
return me unless rest
Vool::Statements.new([ rest.to_vool , me])
val , hoisted = *normalized_vool(@return_value)
me = Vool::ReturnStatement.new(val)
return me unless hoisted
Vool::Statements.new( hoisted ) << me
end
def to_s(depth = 0)

View File

@ -1,5 +1,10 @@
module Vool
# Base class for assignments (local/ivar), works just as you'd expect
# Only "quirk" maybe, that arguments are like locals
#
# Only actual functionality here is the compile_assign_call which compiles
# the call, should the assigned value be a call.
class Assignment < Statement
attr_reader :name , :value
def initialize(name , value )
@ -19,9 +24,18 @@ module Vool
at_depth(depth , "#{@name} = #{@value}")
end
def chain_assign(assign , compiler)
# The assign instruction (a slot_load) is produced by delegating the slot to derived
# class
#
# When the right hand side is a CallStatement, it must be compiled, before the assign
# is executed
#
# Derived classes do not implement to_mom, only slot_position
def to_mom(compiler)
to = Mom::SlotDefinition.new(:message , self.slot_position(compiler))
from = @value.slot_definition(compiler)
assign = Mom::SlotLoad.new(self,to,from)
return assign unless @value.is_a?(CallStatement)
raise "Move me to ruby layer"
@value.to_mom(compiler) << assign
end
end

View File

@ -16,7 +16,7 @@ module Vool
merge_label = Mom::Label.new( self , "merge_label_#{object_id.to_s(16)}")
check = Mom::TruthCheck.new(condition.slot_definition(compiler) , false_label)
if @condition.is_a?(SendStatement)
if @condition.is_a?(CallStatement)
head = @condition.to_mom(compiler)
head << check
else

View File

@ -3,13 +3,16 @@ module Vool
class IvarAssignment < Assignment
def to_s(depth = 0)
"@#{super(depth)}"
at_depth(depth,"@#{super(0)}")
end
def to_mom( compiler )
to = Mom::SlotDefinition.new(:message ,[ :receiver , @name])
from = @value.slot_definition(compiler)
return chain_assign( Mom::SlotLoad.new(self,to,from) , compiler)
# We return the position where the local is stored. This is an array, giving the
# position relative to :message- A SlotLoad is constructed from this.
#
# As we know it is a instance variable, it is stored in the :receiver , and has
# the name @name
def slot_position( compiler )
[ :receiver , @name]
end
end

View File

@ -1,12 +1,16 @@
module Vool
# Local assignment really only differs in where the variable is actually stored,
# slot_position defines that
class LocalAssignment < Assignment
def to_mom( compiler )
slot_def = compiler.slot_type_for(@name)
to = Mom::SlotDefinition.new(:message ,slot_def)
from = @value.slot_definition(compiler)
return chain_assign( Mom::SlotLoad.new(self,to,from) , compiler)
# We return the position where the local is stored. This is an array, giving the
# position relative to :message- A SlotLoad is constructed from this.
#
# Only snag is that we do not know this position, as only the compiler knows
# if the variable name is a local or an arg. So we delegate to the compiler.
def slot_position( compiler )
compiler.slot_type_for(@name)
end
end

View File

@ -18,7 +18,7 @@ module Vool
def to_mom( compiler )
load = Mom::SlotLoad.new( self , [:message , :return_value] ,
@return_value.slot_definition(compiler) )
if @return_value.is_a?(SendStatement)
if @return_value.is_a?(CallStatement)
ret = @return_value.to_mom(compiler)
ret << load
else

View File

@ -2,7 +2,18 @@ module Vool
class Statements < Statement
attr_reader :statements
def initialize(statements)
@statements = statements
case statements
when nil
@statements = []
when Array
@statements = statements
when Statement
@statements = statements.statements
when Statement
@statements = [statements]
else
raise "Invalid class, must be Statement or Array, not #{statements.class}"
end
end
def empty?
@ -24,7 +35,11 @@ module Vool
@statements[i]
end
def <<(o)
@statements << o
if(o.is_a?(Statements))
o.each {|s| @statements << s }
else
@statements << o
end
self
end
def prepend(o)

View File

@ -8,8 +8,26 @@ module Ruby
def setup
@lst = compile( "@foo = a.call(b)").to_vool
end
def test_s
assert_equal "" , @lst.to_s
def test_class
assert_equal Vool::Statements , @lst.class
end
def test_first_class
assert_equal Vool::LocalAssignment , @lst[0].class
end
def test_first_name
assert @lst[0].name.to_s.start_with?("tmp_")
end
def test_second_class
assert_equal Vool::LocalAssignment , @lst[1].class
end
def test_second_name
assert @lst[1].name.to_s.start_with?("tmp_")
end
def test_last_class
assert_equal Vool::IvarAssignment , @lst[2].class
end
def test_second_name
assert_equal :foo, @lst[2].name
end
end
end

View File

@ -1,28 +1,6 @@
require_relative "helper"
module Ruby
class TestReturnStatementVool < MiniTest::Test
include RubyTests
def test_return_const
lst = compile( "return 1" ).to_vool
assert_equal Vool::ReturnStatement , lst.class
end
def test_return_value
lst = compile( "return 1" ).to_vool
assert_equal 1 , lst.return_value.value
end
def test_return_send
lst = compile( "return foo" ).to_vool
assert_equal Vool::LocalAssignment , lst.first.class
end
def test_return_send
lst = compile( "return foo" ).to_vool
assert lst.last.return_value.name.to_s.start_with?("tmp_")
assert_equal 2, lst.length
end
end
class TestReturnStatement < MiniTest::Test
include RubyTests
@ -43,4 +21,31 @@ module Ruby
end
end
class TestReturnStatementVool < MiniTest::Test
include RubyTests
def test_return_const
lst = compile( "return 1" ).to_vool
assert_equal Vool::ReturnStatement , lst.class
end
def test_return_value
lst = compile( "return 1" ).to_vool
assert_equal 1 , lst.return_value.value
end
def test_return_send
lst = compile( "return foo" ).to_vool
assert_equal Vool::ReturnStatement , lst.class
end
def test_return_send3
lst = compile( "return foo.bar.zoo" ).to_vool
assert_equal Vool::LocalAssignment , lst.first.class
assert lst.first.name.to_s.start_with?("tmp_")
end
def test_return_send4
lst = compile( "return foo.bar.zoo" ).to_vool
assert_equal Vool::ReturnStatement, lst[2].class
assert_equal :zoo, lst[2].return_value.name
end
end
end