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])
|
sendd = process(block_node.children[0])
|
||||||
args = process(block_node.children[1])
|
args = process(block_node.children[1])
|
||||||
body = process(block_node.children[2])
|
body = process(block_node.children[2])
|
||||||
sendd.block = BlockStatement.new(args , body)
|
sendd.add_block BlockStatement.new(args , body)
|
||||||
sendd
|
sendd
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def on_yield(node)
|
||||||
|
args = process_all(node.children)
|
||||||
|
YieldStatement.new(args)
|
||||||
|
end
|
||||||
|
|
||||||
def on_args(args)
|
def on_args(args)
|
||||||
args.children.collect{|a| process(a)}
|
args.children.collect{|a| process(a)}
|
||||||
end
|
end
|
||||||
|
@ -77,3 +77,4 @@ require_relative "statements/statements"
|
|||||||
require_relative "statements/send_statement"
|
require_relative "statements/send_statement"
|
||||||
require_relative "statements/variables"
|
require_relative "statements/variables"
|
||||||
require_relative "statements/while_statement"
|
require_relative "statements/while_statement"
|
||||||
|
require_relative "statements/yield_statement"
|
||||||
|
@ -23,14 +23,20 @@ module Vool
|
|||||||
MethodStatement.new( @name , @args , @body.normalize)
|
MethodStatement.new( @name , @args , @body.normalize)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
def has_yield?
|
||||||
|
each{|statement| return true if statement.is_a?(YieldStatement)}
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
def make_arg_type( )
|
def make_arg_type( )
|
||||||
type_hash = {}
|
type_hash = {}
|
||||||
@args.each {|arg| type_hash[arg] = :Object }
|
@args.each {|arg| type_hash[arg] = :Object }
|
||||||
|
type_hash[:implicit_block] = :Object if has_yield?
|
||||||
Parfait::NamedList.type_for( type_hash )
|
Parfait::NamedList.type_for( type_hash )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
def make_frame
|
def make_frame
|
||||||
type_hash = {}
|
type_hash = {}
|
||||||
@body.each do |node|
|
@body.each do |node|
|
||||||
|
@ -17,8 +17,14 @@ module Vool
|
|||||||
@arguments ||= []
|
@arguments ||= []
|
||||||
end
|
end
|
||||||
|
|
||||||
def block=( block )
|
def block
|
||||||
@block = block
|
return nil if arguments.empty?
|
||||||
|
bl = arguments.last
|
||||||
|
bl.is_a?(BlockStatement) ? bl : nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_block( block )
|
||||||
|
@arguments << block
|
||||||
end
|
end
|
||||||
|
|
||||||
def normalize
|
def normalize
|
||||||
@ -54,6 +60,7 @@ module Vool
|
|||||||
@arguments.each do |arg|
|
@arguments.each do |arg|
|
||||||
block.call(arg)
|
block.call(arg)
|
||||||
end
|
end
|
||||||
|
self.block.each(block) if self.block
|
||||||
end
|
end
|
||||||
|
|
||||||
# lazy init this, to keep the dependency (which goes to parfait and booting) at bay
|
# 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
|
# - 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
|
# - a CachedCall , or a SimpleCall, depending on wether the receiver type can be determined
|
||||||
def to_mom( in_method )
|
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)
|
@receiver = SelfExpression.new(in_method.for_type) if @receiver.is_a?(SelfExpression)
|
||||||
if(@receiver.ct_type)
|
if(@receiver.ct_type)
|
||||||
simple_call(in_method)
|
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