Fixing ruby send with arguments
When send has complex args, mostly more sends, we hoist those out and pass created temporary variables
This commit is contained in:
parent
31ae0a9670
commit
84b9811e55
@ -17,6 +17,7 @@ module Ruby
|
|||||||
@arguments ||= []
|
@arguments ||= []
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# we "normalize" or flatten any complex argument expressions into a list
|
||||||
def to_vool
|
def to_vool
|
||||||
statements = Vool::Statements.new([])
|
statements = Vool::Statements.new([])
|
||||||
arguments = []
|
arguments = []
|
||||||
@ -31,12 +32,23 @@ module Ruby
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# this is called for each arg and if the arg is not constant or Variable
|
||||||
|
# we create a tmp variable and assign to that, hoising all the calls.
|
||||||
|
# the effect is of walking the call tree now,
|
||||||
|
# rather than using a stack to do that at runtime
|
||||||
def normalize_arg(arg , arguments , statements)
|
def normalize_arg(arg , arguments , statements)
|
||||||
if arg.is_a?(Constant) and !arg.is_a?(CallStatement)
|
vool_arg = arg.to_vool
|
||||||
arguments << arg.to_vool
|
if arg.is_a?(Constant)
|
||||||
|
arguments << vool_arg
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
assign = Vool::LocalAssignment.new( "tmp_#{arg.object_id}".to_sym, arg.to_vool)
|
if( vool_arg.is_a?(Vool::Statements))
|
||||||
|
while(vool_arg.length > 1)
|
||||||
|
statements << vool_arg.shift
|
||||||
|
end
|
||||||
|
vool_arg = vool_arg.shift
|
||||||
|
end
|
||||||
|
assign = Vool::LocalAssignment.new( "tmp_#{arg.object_id}".to_sym, vool_arg)
|
||||||
statements << assign
|
statements << assign
|
||||||
arguments << Vool::LocalVariable.new(assign.name)
|
arguments << Vool::LocalVariable.new(assign.name)
|
||||||
end
|
end
|
||||||
|
@ -20,13 +20,16 @@ module Ruby
|
|||||||
def length
|
def length
|
||||||
@statements.length
|
@statements.length
|
||||||
end
|
end
|
||||||
|
def shift
|
||||||
|
@statements.shift
|
||||||
|
end
|
||||||
def [](i)
|
def [](i)
|
||||||
@statements[i]
|
@statements[i]
|
||||||
end
|
end
|
||||||
def <<(o)
|
def <<(o)
|
||||||
@statements << o
|
@statements << o
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
def to_vool
|
def to_vool
|
||||||
if( single? )
|
if( single? )
|
||||||
first.to_vool
|
first.to_vool
|
||||||
|
@ -5,6 +5,8 @@ module Vool
|
|||||||
def initialize(name , value )
|
def initialize(name , value )
|
||||||
raise "Name nil #{self}" unless name
|
raise "Name nil #{self}" unless name
|
||||||
raise "Value nil #{self}" unless value
|
raise "Value nil #{self}" unless value
|
||||||
|
raise "Value cant be Assignment #{value}" if value.is_a?(Assignment)
|
||||||
|
raise "Value cant be Statements #{value}" if value.is_a?(Statements)
|
||||||
@name , @value = name , value
|
@name , @value = name , value
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -19,6 +21,7 @@ module Vool
|
|||||||
|
|
||||||
def chain_assign(assign , compiler)
|
def chain_assign(assign , compiler)
|
||||||
return assign unless @value.is_a?(CallStatement)
|
return assign unless @value.is_a?(CallStatement)
|
||||||
|
raise "Move me to ruby layer"
|
||||||
@value.to_mom(compiler) << assign
|
@value.to_mom(compiler) << assign
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -30,6 +30,9 @@ module Vool
|
|||||||
def prepend(o)
|
def prepend(o)
|
||||||
@statements = [o] + @statements
|
@statements = [o] + @statements
|
||||||
end
|
end
|
||||||
|
def shift
|
||||||
|
@statements.shift
|
||||||
|
end
|
||||||
|
|
||||||
# to_mom all the statements. Append subsequent ones to the first, and return the
|
# to_mom all the statements. Append subsequent ones to the first, and return the
|
||||||
# first.
|
# first.
|
||||||
|
@ -9,10 +9,6 @@ module Ruby
|
|||||||
RubyCompiler.compile(input)
|
RubyCompiler.compile(input)
|
||||||
end
|
end
|
||||||
|
|
||||||
def ruby_to_vool(input)
|
|
||||||
FIXMERubyXCompiler.new(input).ruby_to_vool
|
|
||||||
end
|
|
||||||
|
|
||||||
def assert_raises_muted &block
|
def assert_raises_muted &block
|
||||||
orig_stdout = $stdout
|
orig_stdout = $stdout
|
||||||
$stdout = StringIO.new
|
$stdout = StringIO.new
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
require_relative "helper"
|
require_relative "helper"
|
||||||
|
|
||||||
module Ruby
|
module Ruby
|
||||||
class TestSendFoo < MiniTest::Test
|
class TestSendNoArg < MiniTest::Test
|
||||||
include RubyTests
|
include RubyTests
|
||||||
def setup
|
def setup
|
||||||
@lst = compile( "foo")
|
@lst = compile( "foo")
|
||||||
@ -22,7 +22,7 @@ module Ruby
|
|||||||
assert_equal "self.foo()" , @lst.to_s
|
assert_equal "self.foo()" , @lst.to_s
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
class TestSendBar < MiniTest::Test
|
class TestSendSimpleArg < MiniTest::Test
|
||||||
include RubyTests
|
include RubyTests
|
||||||
def setup
|
def setup
|
||||||
@lst = compile( "bar(1)")
|
@lst = compile( "bar(1)")
|
||||||
@ -63,5 +63,30 @@ module Ruby
|
|||||||
lst = compile( "super(1)")
|
lst = compile( "super(1)")
|
||||||
assert_nil lst.name
|
assert_nil lst.name
|
||||||
end
|
end
|
||||||
|
class TestSendSendArgs < MiniTest::Test
|
||||||
|
include RubyTests
|
||||||
|
def setup
|
||||||
|
@lst = compile( "call(arg1, arg2(more))")
|
||||||
|
end
|
||||||
|
def test_one_arg
|
||||||
|
assert_equal SendStatement , @lst.class
|
||||||
|
end
|
||||||
|
def test_one_arg_name
|
||||||
|
assert_equal :call , @lst.name
|
||||||
|
end
|
||||||
|
def test_one_arg_args
|
||||||
|
assert_equal SendStatement , @lst.arguments.first.class
|
||||||
|
end
|
||||||
|
def test_one_arg_args_args
|
||||||
|
assert_equal 0 , @lst.arguments.first.arguments.length
|
||||||
|
end
|
||||||
|
def test_two_arg_args
|
||||||
|
assert_equal SendStatement , @lst.arguments[1].class
|
||||||
|
end
|
||||||
|
def test_two_arg_args_args
|
||||||
|
assert_equal SendStatement , @lst.arguments[1].arguments.first.class
|
||||||
|
assert_equal :more , @lst.arguments[1].arguments.first.name
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
require_relative "helper"
|
require_relative "helper"
|
||||||
|
|
||||||
module Ruby
|
module Ruby
|
||||||
class TestSendFooVool < MiniTest::Test
|
class TestSendNoArgVool < MiniTest::Test
|
||||||
include RubyTests
|
include RubyTests
|
||||||
def setup
|
def setup
|
||||||
@lst = compile( "foo").to_vool
|
@lst = compile( "foo").to_vool
|
||||||
@ -19,7 +19,7 @@ module Ruby
|
|||||||
assert_equal [] , @lst.arguments
|
assert_equal [] , @lst.arguments
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
class TestSendBarVool < MiniTest::Test
|
class TestSendSimpleArgVool < MiniTest::Test
|
||||||
include RubyTests
|
include RubyTests
|
||||||
def setup
|
def setup
|
||||||
@lst = compile( "bar(1)").to_vool
|
@lst = compile( "bar(1)").to_vool
|
||||||
|
70
test/ruby/test_send_statement2.rb
Normal file
70
test/ruby/test_send_statement2.rb
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
require_relative "helper"
|
||||||
|
|
||||||
|
module Ruby
|
||||||
|
module LastBar
|
||||||
|
include RubyTests
|
||||||
|
def test_last_class
|
||||||
|
assert_equal Vool::SendStatement , @lst.last.class
|
||||||
|
end
|
||||||
|
def test_last_name
|
||||||
|
assert_equal :last , @lst.last.name
|
||||||
|
end
|
||||||
|
def test_last_arg
|
||||||
|
assert_equal Vool::LocalVariable , @lst.last.arguments.first.class
|
||||||
|
end
|
||||||
|
def test_lst_class
|
||||||
|
assert_equal Vool::Statements , @lst.class
|
||||||
|
end
|
||||||
|
def test_lst_no_statements
|
||||||
|
@lst.statements.each{|st| assert( ! st.is_a?(Vool::Statements) , st.class)}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
class TestSendSendArgVool < MiniTest::Test
|
||||||
|
include LastBar
|
||||||
|
def setup
|
||||||
|
@lst = compile( "last(foo(1))").to_vool
|
||||||
|
end
|
||||||
|
def test_classes
|
||||||
|
assert_equal Vool::Statements , @lst.class
|
||||||
|
assert_equal Vool::LocalAssignment , @lst.first.class
|
||||||
|
assert_equal Vool::SendStatement , @lst.last.class
|
||||||
|
end
|
||||||
|
def test_foo1
|
||||||
|
assert_equal Vool::SendStatement , @lst.first.value.class
|
||||||
|
assert_equal :foo , @lst.first.value.name
|
||||||
|
assert_equal Vool::IntegerConstant , @lst.first.value.arguments.first.class
|
||||||
|
end
|
||||||
|
end
|
||||||
|
class Test3SendVool < MiniTest::Test
|
||||||
|
include LastBar
|
||||||
|
def setup
|
||||||
|
@lst = compile( "last(foo(more(1)))").to_vool
|
||||||
|
end
|
||||||
|
def test_classes
|
||||||
|
assert_equal Vool::Statements , @lst.class
|
||||||
|
assert_equal Vool::LocalAssignment , @lst.first.class
|
||||||
|
assert_equal Vool::SendStatement , @lst.last.class
|
||||||
|
end
|
||||||
|
def test_foo
|
||||||
|
assert_equal Vool::SendStatement , @lst.first.value.class
|
||||||
|
assert_equal :more , @lst.first.value.name
|
||||||
|
assert_equal Vool::IntegerConstant , @lst.first.value.arguments.first.class
|
||||||
|
end
|
||||||
|
end
|
||||||
|
class Test5SendVool < MiniTest::Test
|
||||||
|
include LastBar
|
||||||
|
def setup
|
||||||
|
@lst = compile( "last(foo(more(even_more(1),and_more(with_more))))").to_vool
|
||||||
|
end
|
||||||
|
def test_classes
|
||||||
|
assert_equal Vool::Statements , @lst.class
|
||||||
|
assert_equal Vool::LocalAssignment , @lst.first.class
|
||||||
|
assert_equal Vool::SendStatement , @lst.last.class
|
||||||
|
end
|
||||||
|
def test_foo
|
||||||
|
assert_equal Vool::SendStatement , @lst.first.value.class
|
||||||
|
assert_equal :even_more , @lst.first.value.name
|
||||||
|
assert_equal Vool::IntegerConstant , @lst.first.value.arguments.first.class
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue
Block a user