diff --git a/lib/parfait/module.rb b/lib/parfait/module.rb index cb5189e7..7bec3eb5 100644 --- a/lib/parfait/module.rb +++ b/lib/parfait/module.rb @@ -48,17 +48,17 @@ module Parfait end def get_instance_method fname - fname = fname.to_sym + raise "uups #{fname}.#{fname.class}" unless fname.is_a? Word @instance_methods.detect{ |fun| fun.name == fname } end # get the method and if not found, try superclasses. raise error if not found def resolve_method m_name + raise "uups #{m_name}.#{m_name.class}" unless m_name.is_a? Word method = get_instance_method(m_name) unless method unless( @name == "Object" ) - supr = Space.space.get_class_by_name(@super_class_name) - method = supr.resolve_method(m_name) + method = @super_class.resolve_method(m_name) end end raise "Method not found #{m_name}, for #{@name}" unless method diff --git a/lib/parfait/space.rb b/lib/parfait/space.rb index 4924f58e..cfd612a5 100644 --- a/lib/parfait/space.rb +++ b/lib/parfait/space.rb @@ -31,13 +31,9 @@ module Parfait # all is good after this init #global objects (data) @objects = Parfait::List.new_object - #@symbols = Parfait::List.new_object end attr_reader :classes , :objects , :symbols, :messages, :next_message , :next_frame - @@SPACE = { :names => [:classes,:objects,:symbols,:messages, :next_message , :next_frame] , - :types => [Virtual::Reference,Virtual::Reference,Virtual::Reference,Virtual::Reference,Virtual::Reference]} - # need a two phase init for the object space (and generally parfait) because the space # is an interconnected graph, so not everthing is ready def late_init @@ -46,9 +42,6 @@ module Parfait @next_message = @messages.first @next_frame = @frames.first end - def old_layout - @@SPACE - end @@object_space = nil # Make the object space globally available @@ -64,9 +57,6 @@ module Parfait def add_object o return if @objects.include?(o) @objects.push o - if o.is_a? Symbol - @symbols << o - end end # this is the way to instantiate classes (not Parfait::Class.new) diff --git a/lib/register/builtin/array.rb b/lib/register/builtin/array.rb index 2e4b2d8f..a289dda9 100644 --- a/lib/register/builtin/array.rb +++ b/lib/register/builtin/array.rb @@ -2,15 +2,15 @@ module Builtin class Array module ClassMethods def get context , index = Virtual::Integer - get_function = Virtual::CompiledMethod.new(:get , [ Virtual::Integer] , Virtual::Integer , Virtual::Integer ) + get_function = Virtual::CompiledMethodInfo.create_method(:get , [ Virtual::Integer] , Virtual::Integer , Virtual::Integer ) return get_function end def set context , index = Virtual::Integer , object = Virtual::Reference - set_function = Virtual::CompiledMethod.new(:set , [Virtual::Integer, Virtual::Reference] ) + set_function = Virtual::CompiledMethodInfo.create_method(:set , [Virtual::Integer, Virtual::Reference] ) return set_function end def push context , object = Virtual::Reference - push_function = Virtual::CompiledMethod.new(:push , [Virtual::Reference] ) + push_function = Virtual::CompiledMethodInfo.create_method(:push , [Virtual::Reference] ) return push_function end end diff --git a/lib/register/builtin/integer.rb b/lib/register/builtin/integer.rb index 52d14a8c..7263593a 100644 --- a/lib/register/builtin/integer.rb +++ b/lib/register/builtin/integer.rb @@ -8,7 +8,9 @@ module Builtin # As we write before we recurse (save a push) we write the number backwards # arguments: string address , integer def utoa context - utoa_function = Virtual::CompiledMethod.new(:utoa , [ Virtual::Integer ] , Virtual::Integer ,Virtual::Integer ) + utoa_function = Virtual::CompiledMethodInfo.create_method("Integer" ,"utoa" , [ Virtual::Integer ] ) + function.info.return_type = Virtual::Integer + function.info.receiver = Virtual::Integer return utoa_function str_addr = utoa_function.receiver number = utoa_function.args.first @@ -17,8 +19,8 @@ module Builtin # make char out of digit (by using ascii encoding) 48 == "0" utoa_function.instance_eval do add( remainder , remainder , 48) - strb( remainder, str_addr ) - sub( str_addr, str_addr , 1 ) + strb( remainder, str_addr ) + sub( str_addr, str_addr , 1 ) cmp( number , 0 ) callne( utoa_function ) end @@ -26,7 +28,9 @@ module Builtin end def putint context - putint_function = Virtual::CompiledMethod.new(:putint , [] , Virtual::Integer ,Virtual::Integer ) + putint_function = Virtual::CompiledMethodInfo.create_method("Integer","putint" , [] ) + putint_function.info.return_type = Virtual::Integer + putint_function.info.receiver = Virtual::Integer return putint_function buffer = Parfait::Word.new(" ") # create a buffer context.object_space.add_object buffer # and save it (function local variable: a no no) @@ -48,21 +52,23 @@ module Builtin putint_function end - # testing method, hand coded fibo, expects arg in receiver_register + # testing method, hand coded fibo, expects arg in receiver_register # result comes in return_register # a hand coded version of the fibonachi numbers # not my hand off course, found in the net http://www.peter-cockerell.net/aalp/html/ch-5.html def fibo context - fibo_function = Virtual::CompiledMethod.new(:fibo , [] , Virtual::Integer ,Virtual::Integer ) + fibo_function = Virtual::CompiledMethodInfo.create_method("Integer","fibo" , [] ) + fibo_function.info.return_type = Virtual::Integer + fibo_function.info.receiver = Virtual::Integer return fibo_function result = fibo_function.return_type int = fibo_function.receiver - + last = fibo_function.new_block("return") - + f1 = fibo_function.new_local f2 = fibo_function.new_local - + fibo_function.instance_eval do cmp int , 1 mov( result, int , condition_code: :le) @@ -73,8 +79,8 @@ module Builtin loop = fibo_function.new_block("loop") fibo_function.insert_at loop - - fibo_function.instance_eval do #loop through + + fibo_function.instance_eval do #loop through add f1 , f1 , f2 # f1 = f1 + f2 sub f2 , f1 , f2 # f2 = f1 -f2 sub int , int , 1 # todo: set.. should do below cmp, but doesn't , set_update_status: 1 @@ -82,10 +88,10 @@ module Builtin bne( loop ) mov( result , f1 ) end - + fibo_function end end - extend ClassMethods + extend ClassMethods end -end \ No newline at end of file +end diff --git a/lib/register/builtin/kernel.rb b/lib/register/builtin/kernel.rb index 9f5f9bec..02483998 100644 --- a/lib/register/builtin/kernel.rb +++ b/lib/register/builtin/kernel.rb @@ -4,38 +4,42 @@ module Builtin # main entry point, ie __init__ calls this # defined here as empty, to be redefined def main context - function = Virtual::CompiledMethod.new(:main , [] , Virtual::Integer) + function = Virtual::CompiledMethodInfo.create_method("Kernel","main" , []) + function.info.return_type = Virtual::Integer return function end # this is the really really first place the machine starts. # it isn't really a function, ie it is jumped to (not called), exits and may not return # so it is responsible for initial setup (and relocation) def __init__ context - function = Virtual::CompiledMethod.new(:__init__ , [] , Virtual::Integer) - clazz = Virtual::Machine.instance.space.get_class_by_name "Kernel" - method = clazz.resolve_method :main + function = Virtual::CompiledMethodInfo.create_method("Kernel","__init__" , []) + function.info.return_type = Virtual::Integer + clazz = Virtual::Machine.instance.class_mappings["Kernel"] + method = clazz.resolve_method Virtual::new_word "main" me = Virtual::Self.new(Virtual::Reference) code = Virtual::Set.new(Virtual::Self.new(me.type), me) - function.add_code(code) - function.add_code Virtual::MethodCall.new(method) + function.info.add_code(code) + function.info.add_code Virtual::MethodCall.new(method) return function end def putstring context - function = Virtual::CompiledMethod.new(:putstring , [] ) + function = Virtual::CompiledMethodInfo.create_method("Kernel" , "putstring" , [] ) return function ret = Virtual::RegisterMachine.instance.write_stdout(function) function.set_return ret function end def exit context - function = Virtual::CompiledMethod.new(:exit , [] , Virtual::Integer) + function = Virtual::CompiledMethodInfo.create_method("Kernel","exit" , []) + function.info.return_type = Virtual::Integer return function ret = Virtual::RegisterMachine.instance.exit(function) function.set_return ret function end def __send context - function = Virtual::CompiledMethod.new(:__send , [] , Virtual::Integer) + function = Virtual::CompiledMethodInfo.create_method("Kernel" ,"__send" , [] ) + function.info.return_type = Virtual::Integer return function end end diff --git a/lib/register/builtin/object.rb b/lib/register/builtin/object.rb index 59dd975f..2d60bfd5 100644 --- a/lib/register/builtin/object.rb +++ b/lib/register/builtin/object.rb @@ -6,7 +6,8 @@ module Builtin # set/get instance variable use it. # This is just a placeholder, as we code this in ruby, but the instance methods need the definition before. def index_of context , name = Virtual::Integer - index_function = Virtual::CompiledMethod.new(:index_of , Virtual::Reference , [Virtual::Reference] , Virtual::Integer ) + index_function = Virtual::CompiledMethodInfo.create_method("Object" , "index_of" , [Virtual::Reference] ) + index_function.info.return_type = Virtual::Integer return index_function end @@ -23,7 +24,7 @@ module Builtin # end # The at_index is just "below" the api, something we need but don't want to expose, so we can't code the above in ruby def _get_instance_variable context , name = Virtual::Integer - get_function = Virtual::CompiledMethod.new(:_get_instance_variable , [ Virtual::Reference ] , Virtual::Reference ,Virtual::Mystery ) + get_function = Virtual::CompiledMethodInfo.create_method("Object","_get_instance_variable" , [ Virtual::Reference ] ) return get_function me = get_function.receiver var_name = get_function.args.first @@ -44,7 +45,7 @@ module Builtin end def _set_instance_variable(context , name = Virtual::Integer , value = Virtual::Integer ) - set_function = Virtual::CompiledMethod.new(:_set_instance_variable ,[Virtual::Reference ,Virtual::Reference], Virtual::Reference ,Virtual::Mystery ) + set_function = Virtual::CompiledMethodInfo.create_method("Object","_set_instance_variable" ,[Virtual::Reference ,Virtual::Reference] ) return set_function receiver set_function me = set_function.receiver diff --git a/lib/register/builtin/word.rb b/lib/register/builtin/word.rb index 68676233..ed634799 100644 --- a/lib/register/builtin/word.rb +++ b/lib/register/builtin/word.rb @@ -1,18 +1,6 @@ module Builtin class Word module ClassMethods - def get context , index = Virtual::Integer - get_function = Virtual::CompiledMethod.new(:get , [ Virtual::Integer] , Virtual::Integer , Virtual::Integer ) - return get_function - end - def set context , index = Virtual::Integer , char = Virtual::Integer - set_function = Virtual::CompiledMethod.new(:set , [Virtual::Integer, Virtual::Integer] , Virtual::Integer ,Virtual::Integer ) - return set_function - end - def puts context - puts_function = Virtual::CompiledMethod.new(:puts , [] ) - return puts_function - end end extend ClassMethods end diff --git a/lib/virtual/boot.rb b/lib/virtual/boot.rb index 0ee2905a..95853139 100644 --- a/lib/virtual/boot.rb +++ b/lib/virtual/boot.rb @@ -1,5 +1,7 @@ module Virtual + # Booting is a complicated, so it is extracted into this file, even it has only one entry point + class Machine # The general idea is that compiling is creating an object graph. Functionally @@ -16,24 +18,25 @@ module Virtual # (not use the normal initialize way) def boot_parfait! @space = Parfait::Space.new_object + # map from the vm - class_name to the Parfait class (which carries parfait name) + class_mappings = {} #will later become instance variable values = [ "Value" , "Integer" , "Kernel" , "Object"].collect {|cl| Virtual.new_word(cl) } value_classes = values.collect { |cl| @space.create_class(cl) } layouts = { "Word" => [] , + "List" => [] , "Space" => ["classes","objects"], "Layout" => ["object_class"] , - "Method" => ["name" , "arg_names" , "locals" , "tmps"] , - "Module" => ["name","instance_methods", "super_class", "meta_class"], "Class" => ["object_layout"], - "Dictionary" => ["keys" , "values"], - "List" => [] } - # map from the vm - class_name to the Parfait class (which carries parfait name) - class_mappings = {} + "Dictionary" => ["keys" , "values"] , + "Method" => ["name" , "arg_names" , "locals" , "tmps"] , + "Module" => ["name" , "instance_methods", "super_class", "meta_class"] + } layouts.each do |name , layout| class_mappings[name] = @space.create_class(Virtual.new_word(name)) end - value_classes[1].set_super_class( value_classes[0] ) # #set superclass (value) for object - value_classes[3].set_super_class( value_classes[0] ) # and integer + value_classes[1].set_super_class( value_classes[0] ) # #set superclass (value) for integer + value_classes[3].set_super_class( value_classes[0] ) # and object class_mappings.each do |name , clazz| # and the rest clazz.set_super_class(value_classes[3]) # superclasses are object end @@ -49,6 +52,9 @@ module Virtual # lookup half created class info # but it must be done before going through the objects (next step) @class_mappings = class_mappings + class_mappings["Integer"] = value_classes[1] #need for further booting + class_mappings["Kernel"] = value_classes[2] #need for further booting + class_mappings["Object"] = value_classes[3] #need for further booting # now update the layout on all objects created so far, # go through objects in space @@ -56,23 +62,25 @@ module Virtual o.init_layout end # and go through the space instance variables which get created before the object list + + boot_functions! end - # boot the classes, ie create a minimal set of classes with a minimal set of functions + # classes have booted, now create a minimal set of functions # minimal means only that which can not be coded in ruby - # CompiledMethods are grabbed from respective modules by sending the method name. This should return the - # implementation of the method (ie a method object), not actually try to implement it (as that's impossible in ruby) + # Methods are grabbed from respective modules by sending the method name. This should return the + # implementation of the method (ie a method object), not actually try to implement it + # (as that's impossible in ruby) def boot_functions! - @space = Parfait::Space.new - boot_classes! # very fiddly chicken 'n egg problem. Functions need to be in the right order, and in fact we # have to define some dummies, just for the other to compile # TODO: go through the virtual parfait layer and adjust function names to what they really are - obj = @space.get_class_by_name "Object" + obj = @class_mappings["Object"] [:index_of , :_get_instance_variable , :_set_instance_variable].each do |f| obj.add_instance_method Builtin::Object.send(f , nil) + puts "Object add #{f}" end - obj = @space.get_class_by_name "Kernel" + obj = @class_mappings["Kernel"] # create main first, __init__ calls it @main = Builtin::Kernel.send(:main , @context) obj.add_instance_method @main @@ -85,18 +93,10 @@ module Virtual # the point of which is that by the time main executes, all is "normal" @init = Block.new(:_init_ , nil ) @init.add_code(Register::RegisterMain.new(underscore_init)) - obj = @space.get_class_by_name "Integer" + obj = @class_mappings["Integer"] [:putint,:fibo].each do |f| obj.add_instance_method Builtin::Integer.send(f , nil) end - obj = @space.get_class_by_name Virtual.new_word "Word" - [:get , :set , :puts].each do |f| - obj.add_instance_method Builtin::Word.send(f , nil) - end - obj = space.get_class_by_name "List" - [:get , :set , :push].each do |f| - obj.add_instance_method Builtin::Array.send(f , nil) - end end end end diff --git a/lib/virtual/parfait_adapter.rb b/lib/virtual/parfait_adapter.rb index 54e49cbd..afc9de4e 100644 --- a/lib/virtual/parfait_adapter.rb +++ b/lib/virtual/parfait_adapter.rb @@ -24,9 +24,6 @@ module FakeMem end module Parfait - Space.class_eval do - attr_accessor :vm_objects - end # Objects memory functions. Object memory is 1 based # but we implement it with ruby array (0 based) and use 0 as type-word # These are the same functions that Builtin implements at run-time diff --git a/lib/virtual/passes/send_implementation.rb b/lib/virtual/passes/send_implementation.rb index d9d4d5b6..dbc57259 100644 --- a/lib/virtual/passes/send_implementation.rb +++ b/lib/virtual/passes/send_implementation.rb @@ -13,7 +13,7 @@ module Virtual next unless code.is_a? MessageSend new_codes = [ ] ref = code.me - raise "only refs implemented #{me.inspect}" unless ( ref.type == Reference) + raise "only refs implemented #{ref.inspect}" unless ( ref.type == Reference) # value known at compile time, got do something with it if(ref.value) me = ref.value @@ -22,7 +22,7 @@ module Virtual elsif( me.is_a? Parfait::Object ) # get the function from my class. easy peasy puts "Me is #{me.class}" - method = me.get_class.get_instance_method(code.name) + method = me.get_class.get_instance_method(Virtual.new_word code.name) raise "Method not implemented #{me.class}.#{code.name}" unless method new_codes << MethodCall.new( method ) else diff --git a/test/virtual/test_hello.rb b/test/virtual/test_hello.rb index 099a3d93..e0712fd1 100644 --- a/test/virtual/test_hello.rb +++ b/test/virtual/test_hello.rb @@ -22,7 +22,7 @@ HERE check end - def ttest_puts_string + def test_puts_string @string_input = <