From 672ccb351d4af0def138c3a37339cf3528eca9d4 Mon Sep 17 00:00:00 2001 From: Torsten Ruger Date: Fri, 27 Apr 2018 09:59:01 +0300 Subject: [PATCH] fix argument hoisting arguments in vool must be simple variables finally did the hoisting to do that --- lib/vool/statements/basic_values.rb | 7 +++- lib/vool/statements/send_statement.rb | 33 +++++++++++------ test/vool/normalization/helper.rb | 13 +++++++ .../vool/normalization/test_send_statement.rb | 35 +++++++++++++++++++ 4 files changed, 76 insertions(+), 12 deletions(-) create mode 100644 test/vool/normalization/helper.rb create mode 100644 test/vool/normalization/test_send_statement.rb diff --git a/lib/vool/statements/basic_values.rb b/lib/vool/statements/basic_values.rb index c8e16654..7d2876d1 100644 --- a/lib/vool/statements/basic_values.rb +++ b/lib/vool/statements/basic_values.rb @@ -16,7 +16,9 @@ module Vool def ct_type Parfait.object_space.get_class_by_name(:Integer).instance_type end - #gobble it up + def to_s + value.to_s + end def each(&block) end end @@ -65,6 +67,9 @@ module Vool def ct_type @my_type end + def to_s + "self" + end end class SuperExpression < Statement end diff --git a/lib/vool/statements/send_statement.rb b/lib/vool/statements/send_statement.rb index 78c7eb97..b98efe39 100644 --- a/lib/vool/statements/send_statement.rb +++ b/lib/vool/statements/send_statement.rb @@ -18,16 +18,31 @@ module Vool end def normalize - #TODO normalize arguments. In first stage args must be variables or hoisted (like while/if) - # later sends ok, but then they must execute - # (currently we only use the args as slot_definition so they are not "momed") - @arguments.each_with_index do |arg , index | - raise "arg #{index} does not provide slot definition #{arg}" unless arg.respond_to?(:slot_definition) - raise "Sends not implemented yet at #{index}:#{arg}" if arg.is_a?(SendStatement) + statements = Statements.new([]) + arguments = [] + @arguments.dup.each_with_index do |arg , index | + normalize_arg(arg , arguments , statements) end - SendStatement.new(@name, @receiver , @arguments) + if statements.empty? + return SendStatement.new(@name, @receiver , @arguments) + else + statements << SendStatement.new(@name, @receiver , arguments) + return statements + end + end + def normalize_arg(arg , arguments , statements) + if arg.respond_to?(:slot_definition) and !arg.is_a?(SendStatement) + arguments << arg + return + end + assign = LocalAssignment.new( "tmp_#{arg.object_id}".to_sym, arg) + statements << assign + arguments << assign.name end + def to_s + "#{receiver}.#{name}(#{arguments.join(',')})" + end def each(&block) block.call(self) block.call(@receiver) @@ -44,10 +59,6 @@ module Vool # A Send breaks down to 2 steps: # - Setting up the next message, with receiver, arguments, and (importantly) return address # - a CachedCall , or a SimpleCall, depending on wether the receiver type can be determined - # - # FIXME: we now presume direct (assignable) values for the arguments and receiver. - # in a not so distant future, temporary variables will have to be created - # and complex statements hoisted to assign to them. pps: same as in conditions def to_mom( in_method ) @receiver = SelfExpression.new(in_method.for_type) if @receiver.is_a?(SelfExpression) if(@receiver.ct_type) diff --git a/test/vool/normalization/helper.rb b/test/vool/normalization/helper.rb new file mode 100644 index 00000000..ce8408a3 --- /dev/null +++ b/test/vool/normalization/helper.rb @@ -0,0 +1,13 @@ +require_relative "../helper" + +module Vool + module Norm + + class NormTest < MiniTest::Test + + def normalize(input) + RubyCompiler.compile(input).normalize + end + end + end +end diff --git a/test/vool/normalization/test_send_statement.rb b/test/vool/normalization/test_send_statement.rb new file mode 100644 index 00000000..2df12806 --- /dev/null +++ b/test/vool/normalization/test_send_statement.rb @@ -0,0 +1,35 @@ +require_relative "helper" + +module Vool + module Norm + + class TestSendSimple < NormTest + def test_simple + lst = normalize("foo") + assert_equal SendStatement , lst.class + end + def test_constant_args + lst = normalize("foo(1,2)") + assert_equal SendStatement , lst.class + end + end + class TestSendSend < NormTest + def setup + super + @stm = normalize("foo(1 - 2)") + end + def test_many + assert_equal Statements , @stm.class + end + def test_assignment + assert_equal LocalAssignment , @stm.first.class + end + def test_name + assert @stm.first.name.to_s.start_with?("tmp_") , @stm.first.name + end + def test_assigned + assert_equal SendStatement , @stm.first.value.class + end + end + end +end