diff --git a/lib/ast/call_site_expression.rb b/lib/ast/call_site_expression.rb index 1ad54092..2b9b3dff 100644 --- a/lib/ast/call_site_expression.rb +++ b/lib/ast/call_site_expression.rb @@ -6,16 +6,18 @@ module Ast def compile method , message me = receiver.compile( method, message ) + method.add_code Virtual::NewMessage.new method.add_code Virtual::Set.new(Virtual::NewSelf.new(me.type), me) method.add_code Virtual::Set.new(Virtual::NewName.new(), Virtual::StringConstant.new(name)) compiled_args = [] args.each_with_index do |arg , i| #compile in the running method, ie before passing control val = arg.compile( method, message) - compiled_args << val # move the compiled value to it's slot in the new message + to = Virtual::NewMessageSlot.new(i ,val.type , val) # (doing this immediately, not after the loop, so if it's a return it won't get overwritten) - method.add_code Virtual::Set.new(Virtual::NewMessageSlot.new(i ,val.type ) , val ) + method.add_code Virtual::Set.new(to , val ) + compiled_args << to end method.add_code Virtual::MessageSend.new(name , me , compiled_args) #and pass control # the effect of the method is that the NewMessage Return slot will be filled, return it diff --git a/lib/register/return_implementation.rb b/lib/register/return_implementation.rb index 881528a6..ccf402f9 100644 --- a/lib/register/return_implementation.rb +++ b/lib/register/return_implementation.rb @@ -2,6 +2,10 @@ module Register class ReturnImplementation def run block block.codes.dup.each do |code| + + #TODO + - move message to new meesage + - restore caller message and self / frame next unless code.is_a? Virtual::MethodReturn #load the return address into pc, affecting return. (other cpus have commands for this, but not arm) message = RegisterReference.new(:r0) diff --git a/lib/virtual/instruction.rb b/lib/virtual/instruction.rb index 3fd5544f..a6f57bd6 100644 --- a/lib/virtual/instruction.rb +++ b/lib/virtual/instruction.rb @@ -66,6 +66,11 @@ module Virtual class UnconditionalBranch < Branch end + class NewMessage < Instruction + end + class NewFrame < Instruction + end + class MessageSend < Instruction def initialize name , me , args = [] @name = name.to_sym diff --git a/lib/virtual/send_implementation.rb b/lib/virtual/send_implementation.rb index e75d1959..f3385c90 100644 --- a/lib/virtual/send_implementation.rb +++ b/lib/virtual/send_implementation.rb @@ -1,11 +1,17 @@ module Virtual # This implements the send logic # Send is so complicated that we actually code it in ruby and stick it in - # That off course opens up an endless loop possibility that we stop by reducing to Class and Module methods + # That off course opens up an endless loop possibility that we stop by + # implementing Class and Module methods + + # Note: I find it slightly unsemetrical that the NewMessage object needs to be created before this instruction + # This is because all expressions create a (return) value and that return value is overwritten by the next + # expression unless saved. And since the message is the place to save it it needs to exist. qed class SendImplementation def run block block.codes.dup.each do |code| next unless code.is_a? MessageSend + new_codes = [ ] ref = code.me raise "only refs implemented #{me.inspect}" unless ( ref.type == Reference) if(ref.value) @@ -16,14 +22,14 @@ module Virtual # get the function from my class. easy peasy method = me.clazz.get_instance_method(code.name) raise "Method not implemented #{clazz.name}.#{code.name}" unless method - call = FunctionCall.new( method ) - block.replace(code , call ) + new_codes << FunctionCall.new( method ) else raise "unimplemented #{code}" end else - raise "not constant/ known object for send #{me.inspect}" + raise "not constant/ known object for send #{ref.inspect}" end + block.replace(code , new_codes ) end end end