diff --git a/lib/parfait/method.rb b/lib/parfait/method.rb new file mode 100644 index 00000000..6618334f --- /dev/null +++ b/lib/parfait/method.rb @@ -0,0 +1,70 @@ +# A Method (at runtime , sis in Parfait) is static object that primarily holds the executable +# code. + +# For reflection also holds arguments and such + +# + +module Parfait + + # static description of a method + # name + # arg_names + # known local variable names + # temp variables (numbered) + # executable code + + # ps, the compiler injects its own info, see virtual::compiled_method_info + + + class Method < Object + + def initialize name , arg_names + @name = name + @arg_names = arg_names + @locals = [] + @tmps = [] + end + attr_reader :name , :arg_names + attr_accessor :for_class + + + # determine whether this method has a variable by the given name + # variables are locals and and arguments + # used to determine if a send must be issued + # return index of the name into the message if so + def has_var name + name = name.to_sym + index = has_arg(name) + return index if index + has_local(name) + end + + # determine whether this method has an argument by the name + def has_arg name + @arg_names.index_of name.to_sym + end + + # determine if method has a local variable or tmp (anonymous local) by given name + def has_local name + name = name.to_sym + index = @locals.index(name) + index = @tmps.index(name) unless index + index + end + + def ensure_local name + index = has_local name + return index if index + @locals << name + @locals.length + end + + def get_var name + var = has_var name + raise "no var #{name} in method #{self.name} , #{@locals} #{@arg_names}" unless var + var + end + + end +end diff --git a/lib/parfait/module.rb b/lib/parfait/module.rb index 401aa428..34e4b752 100644 --- a/lib/parfait/module.rb +++ b/lib/parfait/module.rb @@ -15,15 +15,21 @@ module Parfait class Module < Object def initialize name , superclass @instance_methods = [] - @name = name.to_sym + @name = name @super_class = superclass @meta_class = Virtual::MetaClass.new(self) end def add_instance_method method - raise "not a method #{method.class} #{method.inspect}" unless method.is_a? Virtual::CompiledMethod + raise "not a method #{method.class} #{method.inspect}" unless method.is_a? Method raise "syserr " unless method.name.is_a? Symbol + method.for_class = self @instance_methods << method + method + end + + def create_instance_method name , arg_names + add_instance_method Method.new( name , arg_names ) end # this needs to be done during booting as we can't have all the classes and superclassses diff --git a/lib/virtual.rb b/lib/virtual.rb index 9d3e527b..fca4fda0 100644 --- a/lib/virtual.rb +++ b/lib/virtual.rb @@ -2,7 +2,7 @@ require "virtual/machine" require "virtual/compiler" require "virtual/instruction" -require "virtual/compiled_method" +require "virtual/compiled_method_info" require "virtual/slots/slot" require "virtual/type" require "virtual/constants" @@ -13,4 +13,4 @@ require "virtual/passes/enter_implementation" require "virtual/passes/frame_implementation" Sof::Volotile.add(Virtual::Block , [:method]) -Sof::Volotile.add(Virtual::CompiledMethod , [:current]) +Sof::Volotile.add(Virtual::CompiledMethodInfo , [:current]) diff --git a/lib/virtual/compile_parfait.rb b/lib/virtual/compile_parfait.rb index 15e4143b..5f98bb7f 100644 --- a/lib/virtual/compile_parfait.rb +++ b/lib/virtual/compile_parfait.rb @@ -49,30 +49,10 @@ module Parfait end end - class Parfait::List + class List def to_sof_node(writer , level , ref ) Sof.array_to_sof_node(self , writer , level , ref ) end - end - class Dictionary - def to_sof_node(writer , level , ref) - Sof.hash_to_sof_node( self , writer , level , ref) - end - end - - - Word.class_eval do - def to_s - string = "" - index = 1 - while( index <= self.length) - string[index - 1] = get_char(index).chr - index = index + 1 - end - string - end - end - List.class_eval do def to_a array = [] index = 1 @@ -83,6 +63,26 @@ module Parfait array end end + class Dictionary + def to_sof_node(writer , level , ref) + Sof.hash_to_sof_node( self , writer , level , ref) + end + end + + class Method + attr_accessor :info + end + class Word + def to_s + string = "" + index = 1 + while( index <= self.length) + string[index - 1] = get_char(index).chr + index = index + 1 + end + string + end + end end module Virtual diff --git a/lib/virtual/compiled_method.rb b/lib/virtual/compiled_method_info.rb similarity index 75% rename from lib/virtual/compiled_method.rb rename to lib/virtual/compiled_method_info.rb index a9c580cf..8a0720d0 100644 --- a/lib/virtual/compiled_method.rb +++ b/lib/virtual/compiled_method_info.rb @@ -1,14 +1,13 @@ require_relative "block" module Virtual - # static description of a method - # name - # arg_names (with defaults) + # the static info of a method (with its compiled code, argument names etc ) is part of the + # runtime, ie found in Parfait::Method + + # the info we create here is injected int the method and used only at compile-time # receiver - # code # return arg (usually mystery, but for coded ones can be more specific) - # known local variable names - # temp variables (numbered) + # # Methods are one step up from to VM::Blocks. Where Blocks can be jumped to, Methods can be called. @@ -28,27 +27,36 @@ module Virtual # These (eg if/while) blocks may themselves have linear blocks ,but the last of these # MUST have an uncoditional branch. And remember, all roads lead to return. - class CompiledMethod < Virtual::Object - #return the main function (the top level) into which code is compiled - def CompiledMethod.main - CompiledMethod.new(:main , [] ) + class CompiledMethodInfo + # return the main function (the top level) into which code is compiled + # this just create a "main" with create_method , see there + def self.main + self.create_method( "Object" , :main , [] ) end - def initialize name , arg_names , receiver = Virtual::Self.new , return_type = Virtual::Mystery - @name = name.to_sym - @class_name = "Object" - @arg_names = arg_names - @locals = [] - @tmps = [] - @receiver = receiver - @return_type = return_type + + # create method does two things + # first it creates the parfait method, for the given class, with given argument names + # second, it creates CompiledMethodInfo and attaches it to the method + # + # compile code then works with the method, but adds code tot the info + def self.create_method( class_name , method_name , args) + class_name = Virtual.new_word(class_name) if class_name.is_a? String + method_name = Virtual.new_word(method_name) if method_name.is_a? String + clazz = Machine.instance.space.get_class_by_name class_name + raise "No such class #{class_name}" unless clazz + method = clazz.create_instance_method(method_name , Virtual.new_list(args)) + method.info = CompiledMethodInfo.new + method + end + def initialize receiver = Virtual::Self.new , return_type = Virtual::Mystery # first block we have to create with .new , as new_block assumes a current enter = Block.new( "enter" , self ).add_code(MethodEnter.new()) @blocks = [enter] @current = enter new_block("return").add_code(MethodReturn.new) end - attr_reader :name , :arg_names , :receiver , :blocks - attr_accessor :return_type , :current , :class_name + attr_reader :receiver , :blocks + attr_accessor :return_type , :current # add an instruction after the current (insertion point) # the added instruction will become the new insertion point @@ -105,52 +113,12 @@ module Virtual return new_b end - # determine whether this method has a variable by the given name - # variables are locals and and arguments - # used to determine if a send must be issued - # return index of the name into the message if so - def has_var name - name = name.to_sym - index = has_arg(name) - return index if index - has_local(name) - end - - # determine whether this method has an argument by the name - def has_arg name - @arg_names.index name.to_sym - end - - # determine if method has a local variable or tmp (anonymous local) by given name - def has_local name - name = name.to_sym - index = @locals.index(name) - index = @tmps.index(name) unless index - index - end - - def ensure_local name - index = has_local name - return index if index - @locals << name - @locals.length - end - - def get_var name - var = has_var name - raise "no var #{name} in method #{self.name} , #{@locals} #{@arg_names}" unless var - var - end - def get_tmp name = "__tmp__#{@tmps.length}" @tmps << name Ast::NameExpression.new(name) end - def old_layout - Virtual::Object.layout - end # sugar to create instructions easily. # any method will be passed on to the RegisterMachine and the result added to the insertion block # With this trick we can write what looks like assembler, diff --git a/lib/virtual/compiler/basic_expressions.rb b/lib/virtual/compiler/basic_expressions.rb index f3244d21..825b5ebf 100644 --- a/lib/virtual/compiler/basic_expressions.rb +++ b/lib/virtual/compiler/basic_expressions.rb @@ -15,28 +15,28 @@ module Virtual def self.compile_integer expression , method int = IntegerConstant.new(expression.value) to = Return.new(Integer , int) - method.add_code Set.new( to , int) + method.info.add_code Set.new( to , int) to end def self.compile_true expression , method value = TrueConstant.new to = Return.new(Reference , value) - method.add_code Set.new( to , value ) + method.info.add_code Set.new( to , value ) to end def self.compile_false expression , method value = FalseConstant.new to = Return.new(Reference , value) - method.add_code Set.new( to , value ) + method.info.add_code Set.new( to , value ) to end def self.compile_nil expression , method value = NilConstant.new to = Return.new(Reference , value) - method.add_code Set.new( to , value ) + method.info.add_code Set.new( to , value ) to end @@ -50,9 +50,9 @@ module Virtual if method.has_var(expression.name) # either an argument, so it's stored in message if( index = method.has_arg(name)) - method.add_code MessageGet.new(name , index) + method.info.add_code MessageGet.new(name , index) else # or a local so it is in the frame - method.add_code FrameGet.new(name , index) + method.info.add_code FrameGet.new(name , index) end else call = Ast::CallSiteExpression.new(expression.name , [] ) #receiver self is implicit @@ -65,7 +65,7 @@ module Virtual clazz = Space.space.get_class_by_name name raise "uups #{clazz}.#{name}" unless clazz to = Return.new(Reference , clazz ) - method.add_code Set.new( to , clazz ) + method.info.add_code Set.new( to , clazz ) to end @@ -74,7 +74,7 @@ module Virtual value = Virtual.new_word(expression.string) to = Return.new(Reference , value) Machine.instance.space.add_object value - method.add_code Set.new( to , value ) + method.info.add_code Set.new( to , value ) to end @@ -85,16 +85,16 @@ module Virtual raise "oh noo, nil from where #{expression.right.inspect}" unless r index = method.has_arg(name) if index - method.add_code Set.new(Return.new , MessageSlot.new(index , r,type , r )) + method.info.add_code Set.new(Return.new , MessageSlot.new(index , r,type , r )) else index = method.ensure_local(expression.left.name) - method.add_code Set.new(Return.new , FrameSlot.new(index , r.type , r )) + method.info.add_code Set.new(Return.new , FrameSlot.new(index , r.type , r )) end r end def self.compile_variable expression, method - method.add_code InstanceGet.new(expression.name) + method.info.add_code InstanceGet.new(expression.name) Return.new( Mystery ) end end diff --git a/lib/virtual/compiler/callsite_expression.rb b/lib/virtual/compiler/callsite_expression.rb index 1d05be49..c2aa984e 100644 --- a/lib/virtual/compiler/callsite_expression.rb +++ b/lib/virtual/compiler/callsite_expression.rb @@ -6,9 +6,9 @@ module Virtual def self.compile_callsite expession , method me = Compiler.compile( expession.receiver , method ) - method.add_code NewMessage.new - method.add_code Set.new(NewSelf.new(me.type), me) - method.add_code Set.new(NewName.new(), Virtual.new_word(expession.name)) + method.info.add_code NewMessage.new + method.info.add_code Set.new(NewSelf.new(me.type), me) + method.info.add_code Set.new(NewName.new(), Virtual.new_word(expession.name)) compiled_args = [] expession.args.each_with_index do |arg , i| #compile in the running method, ie before passing control @@ -16,13 +16,13 @@ module Virtual # move the compiled value to it's slot in the new message to = 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 Set.new(to , val ) + method.info.add_code Set.new(to , val ) compiled_args << to end - method.add_code MessageSend.new(expession.name , me , compiled_args) #and pass control + method.info.add_code MessageSend.new(expession.name , me , compiled_args) #and pass control # the effect of the method is that the NewMessage Return slot will be filled, return it # (this is what is moved _inside_ above loop for such expressions that are calls (or constants)) - Return.new( method.return_type ) + Return.new( method.info.return_type ) end end end diff --git a/lib/virtual/compiler/function_expression.rb b/lib/virtual/compiler/function_expression.rb index f6586720..a87840d1 100644 --- a/lib/virtual/compiler/function_expression.rb +++ b/lib/virtual/compiler/function_expression.rb @@ -7,7 +7,7 @@ module Virtual p.name end r = expression.receiver ? Compiler.compile(expression.receiver, method ) : Self.new() - new_method = CompiledMethod.new(expression.name , args , r ) + new_method = CompiledMethodInfo.create_method(expression.name , args , r ) new_method.class_name = r.is_a?(Parfait::Class) ? r.name : method.class_name clazz = Machine.instance.space.get_class_by_name(new_method.class_name) clazz.add_instance_method new_method