start on yield statement
This commit is contained in:
parent
2e086a78e2
commit
18994d2b4b
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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|
|
||||
|
@ -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)
|
||||
|
84
lib/vool/statements/yield_statement.rb
Normal file
84
lib/vool/statements/yield_statement.rb
Normal 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
|
27
test/vool/ruby_compiler/test_yield_statement.rb
Normal file
27
test/vool/ruby_compiler/test_yield_statement.rb
Normal 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
|
0
test/vool/to_mom/test_yield_statement.rb
Normal file
0
test/vool/to_mom/test_yield_statement.rb
Normal file
Loading…
Reference in New Issue
Block a user