diff --git a/lib/ast/basic_expressions.rb b/lib/ast/basic_expressions.rb index ae8a01dd..c6832968 100644 --- a/lib/ast/basic_expressions.rb +++ b/lib/ast/basic_expressions.rb @@ -5,7 +5,9 @@ module Ast class IntegerExpression < Expression # attr_reader :value def compile method , message - Virtual::IntegerConstant.new value + to = Virtual::Return.new(Integer) + method.add_code Virtual::Set.new( to , Virtual::IntegerConstant.new(value)) + to end end @@ -34,10 +36,11 @@ module Ast # otherwise it's a method without args and a send is ussued. # this makes the namespace static, ie when eval and co are implemented method needs recompilation def compile method , message - return Virtual::Self.new( Virtual::Mystery.new ) if name == :self + return Virtual::Self.new( Virtual::Mystery ) if name == :self if method.has_var(name) message.compile_get(method , name ) else + raise "Unimplemented" message.compile_send( method , name , Virtual::Self.new( Virtual::Mystery.new ) ) end end diff --git a/lib/ast/call_site_expression.rb b/lib/ast/call_site_expression.rb index 1c84789a..0a933db8 100644 --- a/lib/ast/call_site_expression.rb +++ b/lib/ast/call_site_expression.rb @@ -1,13 +1,18 @@ module Ast - # assignment, like operators are really function calls + # operators are really function calls class CallSiteExpression < Expression # attr_reader :name, :args , :receiver def compile method , message me = receiver.compile( method, message ) - with = args.collect{|a| a.compile( method,message)} - message.compile_send( method , name , me , with ) + method.add_code Virtual::Set.new(Virtual::NewSelf.new, me) + args.each_with_index do |arg , i| + val = arg.compile( method, message) #compile in the running method, ie before passing control + method.add_code Virtual::Set.new(Virtual::NewMessageSlot.new(i ,val.type ) , val ) + end + method.add_code Virtual::MessageSend.new(name) #and pass control + Virtual::Return.new( method.return_type ) end def scratch diff --git a/lib/ast/function_expression.rb b/lib/ast/function_expression.rb index 3e846525..a0724e62 100644 --- a/lib/ast/function_expression.rb +++ b/lib/ast/function_expression.rb @@ -4,9 +4,9 @@ module Ast def compile method , message args = params.collect do |p| raise "error, arguemnt must be a identifier, not #{p}" unless p.is_a? NameExpression - Virtual::Argument.new( p.name , Virtual::Mystery.new ) + p.name end - r = receiver ? receiver.compile(method,message) : Virtual::SelfReference.new + r = receiver ? receiver.compile(method,message) : Virtual::Self.new() method = Virtual::MethodDefinition.new(name , args , r ) #frame = frame.new_frame return_type = nil diff --git a/lib/virtual/constants.rb b/lib/virtual/constants.rb index 0319cd67..f36183fd 100644 --- a/lib/virtual/constants.rb +++ b/lib/virtual/constants.rb @@ -34,7 +34,9 @@ module Virtual @string = str end attr_reader :string - + def type + Virtual::Reference + end def result= value class_for(MoveInstruction).new(value , self , :opcode => :mov) end diff --git a/lib/virtual/instruction.rb b/lib/virtual/instruction.rb index 227a2cf0..ca952e56 100644 --- a/lib/virtual/instruction.rb +++ b/lib/virtual/instruction.rb @@ -37,13 +37,6 @@ module Virtual end end - module Named - def initialize name - @name = name - end - attr_reader :name - end - # the first instruction we need is to stop. Off course in a real machine this would be a syscall, but that is just # an implementation (in a programm it would be a function). But in a virtual machine, not only do we need this instruction, # it is indeed the first instruction as just this instruction is the smallest possible programm for the machine. @@ -73,13 +66,6 @@ module Virtual class UnconditionalBranch < Branch end - class MessageGet < Instruction - include Named - end - class FrameGet < Instruction - include Named - end - class MessageSend < Instruction def initialize name , args = [] @name = name.to_sym @@ -88,30 +74,14 @@ module Virtual attr_reader :name , :args end - class FrameSet < Instruction - def initialize name , val - @name = name.to_sym - @value = val + # class for Set instructions, A set is basically a mem move. + # to and from are indexes into the known objects(frame,message,self and new_message), or from may be a constant + class Set < Instruction + def initialize to , from + @to = to + @from = from end - attr_reader :name , :value + attr_reader :to , :from end - class MessageSet < Instruction - def initialize name , val - @name = name.to_sym - @value = val - end - attr_reader :name , :value - end - - class LoadSelf < Instruction - def initialize val - @value = val - end - attr_reader :value - end - - class ObjectGet < Instruction - include Named - end end diff --git a/lib/virtual/message.rb b/lib/virtual/message.rb index 2c538ce0..fecb1fe7 100644 --- a/lib/virtual/message.rb +++ b/lib/virtual/message.rb @@ -44,12 +44,6 @@ module Virtual method.get_var(name) end - def compile_send method , name , me , with = [] - method.add_code Virtual::LoadSelf.new(me) - method.add_code MessageSend.new(name , with ) - Return.new( method.return_type ) - end - def compile_set method , name , val method.set_var(name,val) if method.has_arg(name) diff --git a/lib/virtual/method_definition.rb b/lib/virtual/method_definition.rb index 2340e16d..fe57d1cb 100644 --- a/lib/virtual/method_definition.rb +++ b/lib/virtual/method_definition.rb @@ -32,9 +32,9 @@ module Virtual class MethodDefinition < Virtual::Object #return the main function (the top level) into which code is compiled def MethodDefinition.main - MethodDefinition.new(:main , [] , Virtual::SelfReference ) + MethodDefinition.new(:main , [] ) end - def initialize name , args , receiver = Virtual::SelfReference.new , return_type = Virtual::Mystery , start = MethodEnter.new() + def initialize name , args , receiver = Virtual::Self.new , return_type = Virtual::Mystery , start = MethodEnter.new() @name = name.to_sym @args = args @locals = [] diff --git a/lib/virtual/slot.rb b/lib/virtual/slot.rb new file mode 100644 index 00000000..9dc6a047 --- /dev/null +++ b/lib/virtual/slot.rb @@ -0,0 +1,65 @@ +module Virtual + # Slots are named, or rather indexed, storage locations that are typed. + # Four of those locations exist and those correspond to subclasses: + # - the message that has been received: MessageSlot + # - the frame of the method that is executing (local variables): FrameSlot + # - self as an object: SelfSlot + # - a message that will be sent, NewMessageSlot + + # additionally frame, self and return are slots in Message and NewMessage + + class Slot < Value + RETURN = 0 + SELF = 1 + + attr_accessor :index , :type + private #abstract base class + def initialize index , type + @index = index + @type = type + end + end + + class MessageSlot < Slot + def initialize index , type = Mystery + super + end + end + class FrameSlot < Slot + def initialize index , type = Mystery + super + end + end + class SelfSlot < Slot + def initialize index , type = Mystery + super + end + end + class NewMessageSlot < Slot + def initialize index , type = Mystery + super + end + end + + class Return < MessageSlot + def initialize type = Mystery + super( RETURN , type ) + end + end + class NewReturn < NewMessageSlot + def initialize type = Mystery + super( RETURN , type ) + end + end + class Self < MessageSlot + def initialize type = Mystery + super( SELF , type ) + end + end + class NewSelf < NewMessageSlot + def initialize type = Mystery + super( SELF , type ) + end + end + +end diff --git a/lib/virtual/type.rb b/lib/virtual/type.rb index 512c591d..21b24a53 100644 --- a/lib/virtual/type.rb +++ b/lib/virtual/type.rb @@ -6,58 +6,17 @@ module Virtual class Type def == other return false unless other.class == self.class - Sof::Util.attributes(self).each do |a| - begin - left = send(a) - rescue NoMethodError - next # not using instance variables that are not defined as attr_readers for equality - end - begin - right = other.send(a) - rescue NoMethodError - return false - end - return false unless left.class == right.class - return false unless left == right - end return true end - - def inspect - self.class.name + ".new(" + attributes.collect{|a| send(a).inspect }.join(",")+ ")" - end end class Integer < Type - - def initialize - end - end class Reference < Type - - def initialize clazz = nil - @clazz = clazz - end - attr_accessor :clazz - - def at_index block , left , right - block.ldr( self , left , right ) - self - end end - class SelfReference < Reference - end - class Mystery < Type - def initialize - end - def as type - type.new - end - end end diff --git a/lib/virtual/value.rb b/lib/virtual/value.rb index 509f59b6..99aa518a 100644 --- a/lib/virtual/value.rb +++ b/lib/virtual/value.rb @@ -27,37 +27,10 @@ module Virtual end return true end - private + private #can't instantiate, must be constant or variable def initialize end end - - class Variable < Value - - def initialize name , type - @name = name.to_sym - @type = type - end - attr_accessor :name , :type - end - # The subclasses are not strictly speaking neccessary at this def point - # i just don't want to destroy the information for later optimizations - # - # All variables are stored in frames and quite possibly in order arg,local,tmp - class Return < Variable - def initialize type - super(:return , type) - end - end - class Self < Variable - def initialize type - super(:self , type) - end - end - class Argument < Variable - end - class Local < Variable - end - class Temp < Variable - end end + +require_relative "slot" \ No newline at end of file diff --git a/test/virtual/test_methods.rb b/test/virtual/test_methods.rb index efe4a714..d00f9abf 100644 --- a/test/virtual/test_methods.rb +++ b/test/virtual/test_methods.rb @@ -9,7 +9,18 @@ def foo(x) 5 end HERE - @output = "---RETURN_MARKER- &1 !ruby/object:Virtual::MethodDefinitionRETURN_MARKER name: :fooRETURN_MARKER args:RETURN_MARKER - !ruby/object:Virtual::ArgumentRETURN_MARKER name: :xRETURN_MARKER type: !ruby/object:Virtual::Mystery {}RETURN_MARKER locals: []RETURN_MARKER tmps: []RETURN_MARKER receiver: !ruby/object:Virtual::SelfReferenceRETURN_MARKER clazz: RETURN_MARKER return_type: !ruby/object:Virtual::IntegerConstantRETURN_MARKER integer: 5RETURN_MARKER blocks:RETURN_MARKER - &2 !ruby/object:Virtual::BlockRETURN_MARKER method: *1RETURN_MARKER name: :fooRETURN_MARKER branch: RETURN_MARKER codes:RETURN_MARKER - !ruby/object:Virtual::MethodEnter {}RETURN_MARKER - !ruby/object:Virtual::BlockRETURN_MARKER method: *1RETURN_MARKER name: :foo_returnRETURN_MARKER branch: RETURN_MARKER codes:RETURN_MARKER - !ruby/object:Virtual::MethodReturn {}RETURN_MARKER current: *2RETURN_MARKER" + @output = "---RETURN_MARKER- &1 !ruby/object:Virtual::MethodDefinitionRETURN_MARKER name: :fooRETURN_MARKER args:RETURN_MARKER - :xRETURN_MARKER locals: []RETURN_MARKER tmps: []RETURN_MARKER receiver: !ruby/object:Virtual::SelfRETURN_MARKER index: 1RETURN_MARKER type: !ruby/class 'Virtual::Mystery'RETURN_MARKER return_type: &2 !ruby/object:Virtual::ReturnRETURN_MARKER index: 0RETURN_MARKER type: !ruby/class 'Integer'RETURN_MARKER blocks:RETURN_MARKER - &3 !ruby/object:Virtual::BlockRETURN_MARKER method: *1RETURN_MARKER name: :fooRETURN_MARKER branch: RETURN_MARKER codes:RETURN_MARKER - !ruby/object:Virtual::MethodEnter {}RETURN_MARKER - !ruby/object:Virtual::SetRETURN_MARKER to: *2RETURN_MARKER from: !ruby/object:Virtual::IntegerConstantRETURN_MARKER integer: 5RETURN_MARKER - !ruby/object:Virtual::BlockRETURN_MARKER method: *1RETURN_MARKER name: :foo_returnRETURN_MARKER branch: RETURN_MARKER codes:RETURN_MARKER - !ruby/object:Virtual::MethodReturn {}RETURN_MARKER current: *3RETURN_MARKER" + check + end + + def test_puts_string + @string_input = <