diff --git a/lib/parfait.rb b/lib/parfait.rb index e7d82079..2c37587f 100644 --- a/lib/parfait.rb +++ b/lib/parfait.rb @@ -22,32 +22,3 @@ require_relative "parfait/type" require_relative "parfait/cache_entry" require_relative "parfait/message" require_relative "parfait/space" -module Parfait - # temporary shorthand getter for the space - # See implementation, space is now moved to inside the Object class - # (not module anymore), but there is a lot of code (about 100, 50/50 li/test) - # still calling this old version and since it is shorter . . . - def self.object_space - Object.object_space - end - - class Object - # redefine the runtime version - def self.new( *args ) - object = self.allocate - # have to grab the class, because we are in the ruby class not the parfait one - cl = Parfait.object_space.get_class_by_name( self.name.split("::").last.to_sym) - # and have to set the type before we let the object do anything. otherwise boom - object.set_type cl.instance_type - object.send :initialize , *args - object - end - - # Setter fo the boot process, only at runtime. - # only one space exists and it is generated at compile time, not runtime - def self.set_object_space( space ) - @object_space = space - end - - end -end diff --git a/lib/parfait/class.rb b/lib/parfait/class.rb index 457f1688..4df67556 100644 --- a/lib/parfait/class.rb +++ b/lib/parfait/class.rb @@ -30,7 +30,7 @@ module Parfait super(instance_type) @name = name @super_class_name = superclass - @meta_class = MetaClass.new( self ) + @meta_class = MetaClass.new( self , self.type || @name) end def rxf_reference_name diff --git a/lib/parfait/meta_class.rb b/lib/parfait/meta_class.rb index 5155bfa0..da4324e7 100644 --- a/lib/parfait/meta_class.rb +++ b/lib/parfait/meta_class.rb @@ -25,10 +25,9 @@ module Parfait 8 end - def initialize( clazz ) - type = Object.object_space.get_type_by_class_name(:Object) - raise "No type for #{clazz.name}" unless type - super( type ) + def initialize( clazz , clazz_type) + raise "No type for #{clazz.name}" unless clazz_type + super( clazz_type ) @clazz = clazz end diff --git a/lib/parfait/space.rb b/lib/parfait/space.rb index 8ae1d591..a926771a 100644 --- a/lib/parfait/space.rb +++ b/lib/parfait/space.rb @@ -30,36 +30,6 @@ module Parfait 8 end - def initialize( classes , pages) - @classes = classes - @types = Dictionary.new - classes.each do |name , cl| - add_type(cl.instance_type) - end - @factories = Dictionary.new - [:Integer , :ReturnAddress , :Message].each do |fact_name| - for_type = classes[fact_name].instance_type - page_size = pages[fact_name] || 1024 - factory = Factory.new( for_type , page_size ) - factory.get_more - factories[ fact_name ] = factory - end - init_message_chain( factories[ :Message ].reserve ) - init_message_chain( factories[ :Message ].next_object ) - @true_object = Parfait::TrueClass.new - @false_object = Parfait::FalseClass.new - @nil_object = Parfait::NilClass.new - end - - def init_message_chain( message ) - prev = nil - while(message) - message.initialize - message._set_caller(prev) if prev - prev = message - message = message.next_message - end - end # return the factory for the given type # or more exactly the type that has a class_name "name" def get_factory_for(name) @@ -88,11 +58,6 @@ module Parfait types[hash] = type end - # get a type by the type hash (the hash is what uniquely identifies the type) - def get_type_for( hash ) - @types[hash] - end - # all methods form all types def get_all_methods methods = [] diff --git a/lib/parfait/type.rb b/lib/parfait/type.rb index 6ad902ad..63259ad1 100644 --- a/lib/parfait/type.rb +++ b/lib/parfait/type.rb @@ -197,7 +197,9 @@ module Parfait end def set_object_class(oc) - raise "object class should be a class, not #{oc.class}" unless oc.is_a?(Class) + unless oc.is_a?(Class) #but during boot a symbol is ok + raise "object class should be a class, not #{oc.class}" unless oc.is_a?(Symbol) + end @object_class = oc end @@ -267,7 +269,8 @@ module Parfait def hash index = 1 - hash_code = Type.str_hash( object_class.name ) + name = object_class.is_a?(Symbol) ? object_class : object_class.name + hash_code = Type.str_hash(name) each do |name , type| item_hash = Type.str_hash(name) + Type.str_hash(type) hash_code += item_hash + (item_hash / 256 ) * index diff --git a/lib/risc.rb b/lib/risc.rb index e983631c..43e44134 100644 --- a/lib/risc.rb +++ b/lib/risc.rb @@ -22,9 +22,9 @@ end require_relative "risc/position/position" require_relative "risc/platform" +require "parfait" require_relative "risc/parfait_boot" require_relative "risc/parfait_adapter" -require "parfait" require_relative "risc/linker" require_relative "risc/callable_compiler" require_relative "risc/method_compiler" diff --git a/lib/risc/parfait_adapter.rb b/lib/risc/parfait_adapter.rb index f0623973..618772b9 100644 --- a/lib/risc/parfait_adapter.rb +++ b/lib/risc/parfait_adapter.rb @@ -2,7 +2,63 @@ require_relative "fake_memory" module Parfait - class Object ; end + class Object + # redefine the runtime version + def self.new( *args ) + object = self.allocate + Parfait.set_type_for(object) + object.send :initialize , *args + object + end + # Setter fo the boot process, only at runtime. + # only one space exists and it is generated at compile time, not runtime + def self.set_object_space( space ) + @object_space = space + end + end + + def self.set_type_for(object) + return unless(Parfait.object_space) + name = object.class.name.split("::").last.to_sym + # have to grab the class, because we are in the ruby class not the parfait one + cl = Parfait.object_space.get_class_by_name( name ) + # and have to set the type before we let the object do anything. otherwise boom + raise "No such class #{name} for #{object}" unless cl + object.set_type cl.instance_type + end + + class Space < Object + + # Space can only ever be creared at compile time, not runtime + def initialize( ) + @classes = Dictionary.new + @types = Dictionary.new + @factories = Dictionary.new + @true_object = Parfait::TrueClass.new + @false_object = Parfait::FalseClass.new + @nil_object = Parfait::NilClass.new + end + def init_mem(pages) + [:Integer , :ReturnAddress , :Message].each do |fact_name| + for_type = classes[fact_name].instance_type + page_size = pages[fact_name] || 1024 + factory = Factory.new( for_type , page_size ) + factory.get_more + factories[ fact_name ] = factory + end + init_message_chain( factories[ :Message ].reserve ) + init_message_chain( factories[ :Message ].next_object ) + end + def init_message_chain( message ) + prev = nil + while(message) + message.initialize + message._set_caller(prev) if prev + prev = message + message = message.next_message + end + end + end class DataObject < Object def self.allocate r = super @@ -35,7 +91,7 @@ module Parfait # 0 -based index def set_internal_word(index , value) name = Parfait.name_for_index(self , index) - raise "no string #{name.class}" unless name.is_a?(Symbol) + raise "not sym for #{index} in #{self}:#{self.type}:#{name.class}" unless name.is_a?(Symbol) instance_eval("@#{name}=value" ) value end diff --git a/lib/risc/parfait_boot.rb b/lib/risc/parfait_boot.rb index 922c0f1d..e46ada6f 100644 --- a/lib/risc/parfait_boot.rb +++ b/lib/risc/parfait_boot.rb @@ -1,43 +1,11 @@ -module Boot - # Booting is complicated, so it is extracted into this file, even it has only one entry point - - # a ruby object as a placeholder for the parfait Space during boot - class Space - attr_reader :classes , :types - def initialize - @types = {} - @classes = {} - end - - def get_class_by_name(name) - cl = @classes[name] - raise "No class for #{name}" unless cl - cl - end - def get_type_by_class_name(name) - @types[name] - end - end - - # another ruby object to shadow the parfait, just during booting. - # all it needs is the type, which we make the Parfait type - class Class - attr_reader :instance_type - - def initialize( type) - @instance_type = type - end - end -end - module Parfait # The general idea is that compiling is creating an object graph. Functionally # one tends to think of methods, and that is complicated enough, sure. # But for an object system the graph includes classes and all instance variables # - # And so we have a chicken and egg problem. At the end of the boot function we want to have a - # working Space object + # And so we have a chicken and egg problem. At the end of the boot function we want + # to have a working Space object # But that has instance variables (List and Dictionary) and off course a class. # Or more precisely in rubyx, a Type, that points to a class. # So we need a Type, but that has Type and Class too. hmmm @@ -47,73 +15,41 @@ module Parfait # (PPS: The "real" solution is to read a rx-file graph and not do this by hand # That graph can be programatically built and written (with this to boot that process :-)) - # There are some helpers below, but the roadmap is something like: - # - create all the Type instances, with their basic types, but no classes - # - create a BootSpace that has BootClasses , used only during booting - # - create the Class objects and assign them to the types - # - flesh out the types , create the real space - # - and finally load the methods + + # temporary shorthand getter for the space + # See implementation, space is now moved to inside the Object class + # (not module anymore), but there is a lot of code (about 100, 50/50 li/test) + # still calling this old version and since it is shorter . . . + def self.object_space + Object.object_space + end + def self.boot!(options) - Parfait::Object.set_object_space( nil ) # in case we are rebooting - types = boot_types - boot_boot_space( types ) - classes = boot_classes( types ) - fix_types( types , classes ) - space = Space.new( classes , options ) - Parfait::Object.set_object_space( space ) - end - - # types is where the snake bites its tail. Every chain ends at a type and then it - # goes around (circular references). We create them from the list below, just as empty - # shells, that we pass back, for the BootSpace to be created - def self.boot_types - types = {} + space = Space.new( ) type_names.each do |name , ivars | - types[name] = Type.allocate + ivars[:type] = :Type + instance_type = Type.new(name , ivars) + space.add_type instance_type + space.classes[name] = Class.new(name , nil , instance_type) end - type_type = types[:Type] - types.each do |name , type | - type.set_type(type_type) - end - types - end - - # The BootSpace is an object that holds fake classes, that hold _real_ types - # Once we plug it in we can use .new - # then we need to create the parfait classes and fix the types before creating a Space - def self.boot_boot_space(types) - boot_space = Boot::Space.new - types.each do |name , type| - clazz = Boot::Class.new(type) - boot_space.classes[name] = clazz - boot_space.types[name] = type - end - Parfait::Object.set_object_space( boot_space ) - end - - # when running code instantiates a class, a type is created automatically - # but even to get our space up, we have already instantiated all types - # so we have to continue and allocate classes and fill the data by hand - # and off cource we can't use space.create_class , but still they need to go there - def self.boot_classes(types) - classes = Dictionary.new - classes.type = types[:Dictionary] - type_names.each do |name , vars| - super_c = super_class_names[name] || :Object - clazz = Class.new(name , super_c , types[name] ) - classes[name] = clazz - end - classes + # cant set it before or new will try to take types from it + Parfait::Object.set_object_space( space ) + fix_types + space.init_mem(options) end # Types are hollow shells before this, so we need to set the object_class # and initialize the list variables (which we now can with .new) - def self.fix_types(types , classes) - type_names.each do |name , ivars | - type = types[name] - clazz = classes[name] - type.set_object_class( clazz ) - type.init_lists({type: :Type }.merge(ivars)) + def self.fix_types + ObjectSpace.each_object(Parfait::Object) { |o| Parfait.set_type_for(o) } + classes = Parfait.object_space.classes + class_type = Parfait.object_space.get_type_by_class_name(:Class) + types = Parfait.object_space.types + classes.each do |name , cl| + object_type = Parfait.object_space.get_type_by_class_name(name) + cl.meta_class.set_instance_variable(:@instance_type, class_type) + cl.set_instance_variable( :@instance_type , object_type) + object_type.set_object_class(cl) end end @@ -196,4 +132,5 @@ module Parfait # FIXME Now that we use instance variables in parfait, they should be parsed # and the type_names generated automatically end + end diff --git a/test/parfait/test_space.rb b/test/parfait/test_space.rb index 5795cbf9..87de0bc6 100644 --- a/test/parfait/test_space.rb +++ b/test/parfait/test_space.rb @@ -48,7 +48,7 @@ module Parfait def test_word_class word = @space.classes[:Word] assert word.instance_type - t_word = @space.get_type_for(word.instance_type.hash) + t_word = @space.types[word.instance_type.hash] assert_equal word.instance_type.hash , t_word.hash assert_equal word.instance_type.object_id , t_word.object_id end diff --git a/test/parfait/test_space2.rb b/test/parfait/test_space2.rb index b6450ada..ea93ed6b 100644 --- a/test/parfait/test_space2.rb +++ b/test/parfait/test_space2.rb @@ -18,7 +18,7 @@ module Parfait def test_types_hashes types = @space.types types.each do |has , type| - assert has.is_a?(::Integer) , has.inspect + assert has.is_a?(::Integer) , has.class end end def test_classes_types_in_space_types @@ -29,14 +29,14 @@ module Parfait def test_class_types_are_stored @space.classes.each do |name,clazz| - assert @space.get_type_for(clazz.instance_type.hash) + assert @space.types[clazz.instance_type.hash] end end def test_class_types_are_identical @space.classes.each do |name , clazz| - cl_type = @space.get_type_for(clazz.instance_type.hash) - assert_equal cl_type.object_id , clazz.instance_type.object_id + cl_type = @space.types[clazz.instance_type.hash] + assert_equal cl_type.object_id , clazz.instance_type.object_id , name end end diff --git a/test/parfait/type/test_hash.rb b/test/parfait/type/test_hash.rb index d509b6ce..1a6af7de 100644 --- a/test/parfait/type/test_hash.rb +++ b/test/parfait/type/test_hash.rb @@ -14,7 +14,7 @@ module Parfait end def test_length - assert @types.length > 11 + assert_equal 27 , @types.length end def test_two_hashs_not_equal