2018-07-19 15:22:44 +02:00
|
|
|
module Ruby
|
2018-07-20 19:07:15 +02:00
|
|
|
# The way the ruby parser presents a call with a block is by wrapping the
|
|
|
|
# whole thing in a :block scope. It includes the send and the block definition.
|
|
|
|
#
|
|
|
|
# A block is in essence quite like a method, so the block definition is like a
|
|
|
|
# method definition, except it is not bound to the class direcly, but the enclosing
|
|
|
|
# method. The enclosing method also provides the scope.
|
2018-07-19 13:46:51 +02:00
|
|
|
class BlockStatement < Statement
|
2018-07-19 15:22:44 +02:00
|
|
|
attr_reader :send , :args , :body
|
2018-07-19 13:46:51 +02:00
|
|
|
|
2018-07-19 15:22:44 +02:00
|
|
|
def initialize( send , args , body )
|
|
|
|
@send , @args , @body = send , args , body
|
2018-07-19 13:46:51 +02:00
|
|
|
raise "no bod" unless @body
|
|
|
|
end
|
|
|
|
|
2018-07-20 19:07:15 +02:00
|
|
|
# In Vool we "hoist" the block definition through a local assignment, much
|
|
|
|
# as we would other complex args (bit like in the Normalizer)
|
|
|
|
# The block is then passed as a normal variable to the send. In other words, the
|
|
|
|
# BlockStatement resolves to a list of Statements, the last of which is the send
|
|
|
|
#
|
2018-07-19 13:59:10 +02:00
|
|
|
def to_vool
|
2018-07-20 19:07:15 +02:00
|
|
|
block_name = "implicit_block_#{object_id}".to_sym
|
|
|
|
block = Vool::BlockStatement.new( @args.dup , @body.to_vool)
|
|
|
|
assign = Vool::LocalAssignment.new( block_name , block)
|
|
|
|
sendd = @send.to_vool
|
|
|
|
if(sendd.is_a?(Vool::Statements))
|
|
|
|
ret = sendd
|
|
|
|
sendd = sendd.last
|
|
|
|
else
|
|
|
|
ret = Vool::Statements.new([sendd])
|
|
|
|
end
|
|
|
|
sendd.arguments << LocalVariable.new(block_name).to_vool
|
|
|
|
ret.prepend(assign)
|
|
|
|
ret
|
2018-07-19 13:46:51 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
end
|