start on yield statement

This commit is contained in:
Torsten Ruger 2018-06-28 20:15:24 +03:00
parent 2e086a78e2
commit 18994d2b4b
7 changed files with 135 additions and 4 deletions

View File

@ -41,10 +41,15 @@ module Vool
sendd = process(block_node.children[0])
args = process(block_node.children[1])
body = process(block_node.children[2])
sendd.block = BlockStatement.new(args , body)
sendd.add_block BlockStatement.new(args , body)
sendd
end
def on_yield(node)
args = process_all(node.children)
YieldStatement.new(args)
end
def on_args(args)
args.children.collect{|a| process(a)}
end

View File

@ -77,3 +77,4 @@ require_relative "statements/statements"
require_relative "statements/send_statement"
require_relative "statements/variables"
require_relative "statements/while_statement"
require_relative "statements/yield_statement"

View File

@ -23,14 +23,20 @@ module Vool
MethodStatement.new( @name , @args , @body.normalize)
end
private
def has_yield?
each{|statement| return true if statement.is_a?(YieldStatement)}
return false
end
def make_arg_type( )
type_hash = {}
@args.each {|arg| type_hash[arg] = :Object }
type_hash[:implicit_block] = :Object if has_yield?
Parfait::NamedList.type_for( type_hash )
end
private
def make_frame
type_hash = {}
@body.each do |node|

View File

@ -17,8 +17,14 @@ module Vool
@arguments ||= []
end
def block=( block )
@block = block
def block
return nil if arguments.empty?
bl = arguments.last
bl.is_a?(BlockStatement) ? bl : nil
end
def add_block( block )
@arguments << block
end
def normalize
@ -54,6 +60,7 @@ module Vool
@arguments.each do |arg|
block.call(arg)
end
self.block.each(block) if self.block
end
# lazy init this, to keep the dependency (which goes to parfait and booting) at bay
@ -65,6 +72,7 @@ module Vool
# - 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
def to_mom( in_method )
@parfait_block = self.block.to_mom(in_method) if self.block
@receiver = SelfExpression.new(in_method.for_type) if @receiver.is_a?(SelfExpression)
if(@receiver.ct_type)
simple_call(in_method)

View File

@ -0,0 +1,84 @@
module Vool
class YieldStatement < Statement
attr_reader :arguments
def initialize(arguments )
@arguments = arguments
@arguments ||= []
end
def normalize
statements = Statements.new([])
arguments = []
@arguments.each_with_index do |arg , index |
normalize_arg(arg , arguments , statements)
end
if statements.empty?
return YieldStatement.new(@name, @receiver , @arguments)
else
statements << YieldStatement.new(@name, @receiver , arguments)
return statements
end
end
def normalize_arg(arg , arguments , statements)
if arg.respond_to?(:slot_definition) and !arg.is_a?(YieldStatement)
arguments << arg
return
end
assign = LocalAssignment.new( "tmp_#{arg.object_id}".to_sym, arg)
statements << assign
arguments << LocalVariable.new(assign.name)
end
def to_s
"#{receiver}.#{name}(#{arguments.join(',')})"
end
def each(&block)
block.call(self)
block.call(@receiver)
@arguments.each do |arg|
block.call(arg)
end
end
# A Send breaks down to 2 steps:
# - Setting up the next message, with receiver, arguments, and (importantly) return address
# - a SimpleCall,
def to_mom( in_method )
@parfait_block = @block.to_mom(in_method) if @block
@receiver = SelfExpression.new(in_method.for_type) if @receiver.is_a?(SelfExpression)
if(@receiver.ct_type)
simple_call(in_method)
else
raise "ERROR"
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,called_method)
setup = Mom::MessageSetup.new( called_method )
mom_receive = @receiver.slot_definition(in_method)
arg_target = [:message , :next_message , :arguments]
args = []
@arguments.each_with_index do |arg , index| # +1 because of type
args << Mom::SlotLoad.new( arg_target + [index + 1] , arg.slot_definition(in_method))
end
setup << Mom::ArgumentTransfer.new( mom_receive , args )
end
def simple_call(in_method)
type = @receiver.ct_type
called_method = type.resolve_method(@name)
raise "No method #{@name} for #{type}" unless called_method
message_setup(in_method,called_method) << Mom::SimpleCall.new(called_method)
end
end
end

View File

@ -0,0 +1,27 @@
require_relative "helper"
module Vool
class TestYieldStatement < MiniTest::Test
def setup()
input = "def plus_one; yield(0) ; end "
@lst = RubyCompiler.compile( input )
end
def test_method
assert_equal MethodStatement , @lst.class
end
def test_block
assert_equal YieldStatement , @lst.body.class
end
def test_block_args
assert_equal IntegerConstant , @lst.body.arguments.first.class
end
def test_method_yield?
assert_equal true , @lst.has_yield?
end
def test_method_args
Risc.machine.boot
assert_equal 2 , @lst.make_arg_type.get_length
end
end
end

View File