diff --git a/lib/mom/method_compiler.rb b/lib/mom/method_compiler.rb index 90deb321..85c56c05 100644 --- a/lib/mom/method_compiler.rb +++ b/lib/mom/method_compiler.rb @@ -69,7 +69,7 @@ module Mom return ["arg#{index}".to_sym] end index = @callable.frame_type.variable_index(name) - raise "no such local or argument #{name}" unless index + raise "no such local or argument #{name} for #{callable.name}:#{callable.frame_type.hash}" unless index return ["local#{index}".to_sym] end diff --git a/lib/parfait/class.rb b/lib/parfait/class.rb index 95be1300..4fdc2423 100644 --- a/lib/parfait/class.rb +++ b/lib/parfait/class.rb @@ -17,7 +17,7 @@ module Parfait class Class < Behaviour - attr_reader :name , :super_class_name , :single_class + attr_reader :name , :super_class_name def self.type_length 6 @@ -30,7 +30,11 @@ module Parfait super(instance_type) @name = name @super_class_name = superclass - @single_class = SingletonClass.new( self , self.type || @name) + end + + def single_class + return @single_class if @single_class + @single_class = SingletonClass.new( self ) end def rxf_reference_name diff --git a/lib/parfait/singleton_class.rb b/lib/parfait/singleton_class.rb index a5b1eef9..e0646a25 100644 --- a/lib/parfait/singleton_class.rb +++ b/lib/parfait/singleton_class.rb @@ -25,16 +25,21 @@ module Parfait 8 end - def initialize( clazz , clazz_type) - raise "No type for #{clazz.name}" unless clazz_type - super( clazz_type ) + def initialize( clazz ) + clazz_hash = clazz.type.to_hash @clazz = clazz + super( Type.for_hash(clazz_hash , self , 1) ) + @clazz.set_type( @instance_type ) end def rxf_reference_name @clazz.name end + def name + :"#{clazz.name}.Single" + end + def inspect "SingletonClass(#{@clazz.name})" end diff --git a/lib/parfait/type.rb b/lib/parfait/type.rb index 9acd2cc4..4cac23f7 100644 --- a/lib/parfait/type.rb +++ b/lib/parfait/type.rb @@ -4,7 +4,7 @@ module Parfait # you want to store values by name (instance variable names). # # One could (like mri), store the names in each object, but that is wasteful in both -# time and space. +# time and space (time for access, space to store implicitly known names ). # Instead we store only the values, and access them by index (bit like c++). # The Type allows the mapping of names to index. @@ -17,20 +17,27 @@ module Parfait # for every Type instance. # But, as we want every Object to have a class, the Type carries that class. -# So the type of type has an entry "object_class" +# So the type of type has an entry "object_class", ir Type has an instance object_class. # But Objects must also be able to carry methods themselves (ruby calls singleton_methods) -# and those too are stored in the Type (both type and class include behaviour) +# and those too are stored in the Type. Those type instances are called singleton +# types, in analogy to the singleton classes they represent. +# In other words, "usually" a type represents a whole group of objects (instances of a +# class at the time the type was the instance_type). But for Singletons, ie objects +# that have a singleton class, the type is only for that object. -# The object is an "List" (memory location) of values of length n +# An object is an "List" (memory location) of values of length n # The Type is a list of n names and n types that describe the values stored in an # actual object. # Together they turn the object into a hash like structure # For types to be a useful concept, they have to be unique and immutable. Any "change", # like adding a name/type pair, will result in a new type instance. +# Type identity can be checked by the hash function, so two types are the same when their +# hashes are the same. The hash is made up of hashing all instance names and the class +# name. -# The Type class carries a hash of types of the systems, which is used to ensure that +# The Space class carries a hash of types of the systems, which is used to ensure that # there is only one instance of every type. Hash and equality are defined on type # for this to work. @@ -39,24 +46,31 @@ module Parfait attr_reader :object_class , :names , :types , :methods def self.type_length - 5 + 6 end - def self.for_hash( hash , object_class = :Object) + # This is the default way to create new type, because we add it to the + # global list, to space. + # The hash (actually the keys of the hash) and the object_class define the + # identity of the type, which can be checked with the hash function. + # single is by default 0, meaning you have to specify explicitly (1) for + # it to be a "singleton" type (see class description) + def self.for_hash( hash , object_class = :Object , single = 0) name = object_class if(object_class.is_a?(Symbol)) object_class = Object.object_space.get_class_by_name(object_class) end raise "No such class #{name}" unless object_class hash = {type: object_class.name }.merge(hash) unless hash[:type] - new_type = Type.new( object_class , hash) + new_type = Type.new( object_class , hash , single) Object.object_space.add_type(new_type) end # should not be called directly. Use Type.for_hash instead, that adds the - # type to the global list - def initialize( object_class , hash ) + # type to the global list and does sym->class conversion if neccessary + def initialize( object_class , hash , single ) super() + @is_single = single @object_class = object_class @methods = nil @names = List.new @@ -68,6 +82,10 @@ module Parfait end end + def is_single? + @is_single == 1 + end + def class_name @object_class&.name end diff --git a/lib/parfait/vool_method.rb b/lib/parfait/vool_method.rb index c166156b..450c0bbb 100644 --- a/lib/parfait/vool_method.rb +++ b/lib/parfait/vool_method.rb @@ -20,6 +20,7 @@ module Parfait @args_type = args_type @frame_type = frame_type @source = source + #raise source.to_s if name == :type_length raise "Name must be symbol" unless name.is_a?(Symbol) raise "args_type must be type" unless args_type.is_a?(Parfait::Type) raise "frame_type must be type" unless frame_type.is_a?(Parfait::Type) diff --git a/lib/risc/collector.rb b/lib/risc/collector.rb index 95ba9aee..131d776e 100644 --- a/lib/risc/collector.rb +++ b/lib/risc/collector.rb @@ -67,6 +67,9 @@ module Risc def self.position!( objekt ) return false if Position.set?(objekt) return true if objekt.is_a? ::Integer + return true if objekt.is_a? ::NilClass + return true if objekt.is_a? ::TrueClass + return true if objekt.is_a? ::FalseClass return true if objekt.is_a?( Risc::Label) #puts "ADD #{objekt.class.name}" unless objekt.is_a?( Parfait::Object) or objekt.is_a?( Symbol) diff --git a/lib/risc/parfait_boot.rb b/lib/risc/parfait_boot.rb index 05841fc2..9e3c139b 100644 --- a/lib/risc/parfait_boot.rb +++ b/lib/risc/parfait_boot.rb @@ -29,7 +29,7 @@ module Parfait space = Space.new( ) type_names.each do |name , ivars | ivars[:type] = :Type - instance_type = Type.new(name , ivars) + instance_type = Type.new(name , ivars , 0) space.add_type instance_type space.classes[name] = Class.new(name , nil , instance_type) end @@ -51,7 +51,6 @@ module Parfait classes.each do |name , cl| object_type = Parfait.object_space.get_type_by_class_name(name) raise "nil type" unless object_type - cl.single_class.instance_eval{ @instance_type = class_type} cl.instance_eval{ @instance_type = object_type} cl.instance_eval{ @super_class_name = super_names[name] || :Object} object_type.instance_eval{ @object_class = cl } @@ -140,7 +139,8 @@ module Parfait true_object: :TrueClass, false_object: :FalseClass , nil_object: :NilClass}, TrueClass: {}, Type: {names: :List , types: :List , - object_class: :Class, methods: :CallableMethod } , + object_class: :Class, methods: :CallableMethod , + is_single: :Object} , VoolMethod: { name: :Word , args_type: :Type , frame_type: :Type } , Word: {char_length: :Integer , next_word: :Word} , } diff --git a/lib/vool/class_method_expression.rb b/lib/vool/class_method_expression.rb index e432df02..c7cd3faf 100644 --- a/lib/vool/class_method_expression.rb +++ b/lib/vool/class_method_expression.rb @@ -41,7 +41,7 @@ module Vool def to_s(depth = 0) arg_str = @args.collect{|a| a.to_s}.join(', ') - at_depth(depth , "def self.#{name}(#{arg_str})\n#{@body.to_s(depth + 1)}end") + at_depth(depth , "def self.#{name}(#{arg_str})\n#{@body.to_s(1)}\nend") end private diff --git a/lib/vool/method_expression.rb b/lib/vool/method_expression.rb index 0590f15a..de90548a 100644 --- a/lib/vool/method_expression.rb +++ b/lib/vool/method_expression.rb @@ -50,7 +50,7 @@ module Vool def to_s(depth = 0) arg_str = @args.collect{|a| a.to_s}.join(', ') - at_depth(depth , "def #{name}(#{arg_str})\n#{@body.to_s(depth + 1)}\nend") + at_depth(depth , "def #{name}(#{arg_str})\n#{@body.to_s(1)}\nend") end private diff --git a/lib/vool/statements.rb b/lib/vool/statements.rb index 8d7b9f44..8f5a2d0a 100644 --- a/lib/vool/statements.rb +++ b/lib/vool/statements.rb @@ -72,11 +72,7 @@ module Vool first = stats.shift.to_mom(compiler) while( nekst = stats.shift ) next_mom = nekst.to_mom(compiler) - if next_mom.is_a?(Mom::BlockCompiler) - compiler.block_compilers << next_mom - else - first.append next_mom - end + first.append next_mom end first end diff --git a/test/parfait/test_class.rb b/test/parfait/test_class.rb index c802ba42..fe31bff8 100644 --- a/test/parfait/test_class.rb +++ b/test/parfait/test_class.rb @@ -48,6 +48,20 @@ module Parfait @space.get_class.add_instance_variable(:counter , :Integer) assert before != @space.get_class.instance_type.hash end - + def test_has_single + assert_equal SingletonClass , @try.single_class.class + end + def test_before_not_single_type + assert_equal false , @try.type.is_single? + end + def test_single_type_not_class + hash_after = @try.single_class.instance_type.hash + assert_equal @try.type.hash , hash_after + end + def test_single_type_not_class_before + hash_before = @try.type.hash + hash_after = @try.single_class.instance_type.hash + refute_equal hash_before , hash_after + end end end diff --git a/test/parfait/test_singleton_class.rb b/test/parfait/test_singleton_class.rb index 8e4ce436..1332099e 100644 --- a/test/parfait/test_singleton_class.rb +++ b/test/parfait/test_singleton_class.rb @@ -49,5 +49,11 @@ module Parfait @try.add_instance_variable(:counter , :Integer) assert_equal @try.clazz.type , @try.instance_type end + def test_name + assert_equal :"Try.Single" , @try.name + end + def test_type_is_single + assert_equal true , @try.instance_type.is_single? + end end end diff --git a/test/parfait/type/test_basic.rb b/test/parfait/type/test_basic.rb index f10f8f46..8a2b5546 100644 --- a/test/parfait/type/test_basic.rb +++ b/test/parfait/type/test_basic.rb @@ -13,35 +13,29 @@ module Parfait def test_type_index assert_equal @mess.get_type , @mess.get_internal_word(Parfait::TYPE_INDEX) , "mess" end - def test_type_is_first type = @mess.get_type assert_equal 0 , type.variable_index(:type) end - def test_length assert @mess assert @mess.get_type assert_equal 31 , @mess.get_type.instance_length , @mess.get_type.inspect end - def test_names assert @type.names end def test_types assert @type.types end - def test_type_length assert_equal 31 , @mess.get_type.instance_length , @mess.get_type.inspect end - def test_type_length_index type = @mess.get_type.get_type assert_equal 4 , type.variable_index(:methods) assert_equal type.object_class , type.get_internal_word(3) end - def test_no_index_below_0 type = @mess.get_type names = type.names @@ -50,12 +44,10 @@ module Parfait assert type.variable_index(n) >= 0 end end - def test_attribute_set @mess.set_receiver( 55) assert_equal 55 , @mess.receiver end - def test_variable_index assert_equal 1 , @type.variable_index(:next_message) end @@ -68,7 +60,6 @@ module Parfait def test_type_for assert_equal :Message , @type.type_for(:next_message) end - def test_remove_me type = @mess.get_type assert_equal type , @mess.get_internal_word(0) @@ -83,5 +74,9 @@ module Parfait int_class = @space.get_type_by_class_name(:Integer) assert_equal :Integer, int_class.object_class.name end + def test_create_single + single = Type.for_hash( {} , :Object ,1) + assert_equal true , single.is_single? + end end end diff --git a/test/risc/interpreter/calling/test_minus.rb b/test/risc/interpreter/calling/test_minus.rb index bfd2a8b5..dfc1a566 100644 --- a/test/risc/interpreter/calling/test_minus.rb +++ b/test/risc/interpreter/calling/test_minus.rb @@ -38,7 +38,7 @@ module Risc ret = main_ticks(49) assert_equal FunctionReturn , ret.class assert_equal :r3 , ret.register.symbol - assert_equal 38236 , @interpreter.get_register(ret.register) + assert_equal 36540 , @interpreter.get_register(ret.register) end end end diff --git a/test/risc/test_collector.rb b/test/risc/test_collector.rb index 96a8a16d..fec8e424 100644 --- a/test/risc/test_collector.rb +++ b/test/risc/test_collector.rb @@ -38,7 +38,7 @@ module Risc end def len - 1479 + 1426 end def test_collect_all_types @@ -70,7 +70,7 @@ module Risc end def len - 2959 + 2906 end end end diff --git a/test/risc/test_interpreter.rb b/test/risc/test_interpreter.rb index c39f363d..7d133fd3 100644 --- a/test/risc/test_interpreter.rb +++ b/test/risc/test_interpreter.rb @@ -54,7 +54,7 @@ module Risc end def test_pc @interpreter.tick - assert_equal t = 37800 , @interpreter.pc + assert_equal t = 36104 , @interpreter.pc @interpreter.tick assert_equal t + 4 , @interpreter.pc end diff --git a/test/risc/test_linker.rb b/test/risc/test_linker.rb index 758c7826..8a254c93 100644 --- a/test/risc/test_linker.rb +++ b/test/risc/test_linker.rb @@ -24,7 +24,7 @@ module Risc assert_equal 0 , Position.get(@linker.cpu_init).at end def test_cpu_at - assert_equal "0x941c" , Position.get(@linker.cpu_init.first).to_s + assert_equal "0x8d7c" , Position.get(@linker.cpu_init.first).to_s end def test_cpu_label assert_equal Position , Position.get(@linker.cpu_init.first).class diff --git a/test/rubyx/parfait/test_integer.rb b/test/rubyx/parfait/test_integer.rb index fd78654c..3dd3f0cf 100644 --- a/test/rubyx/parfait/test_integer.rb +++ b/test/rubyx/parfait/test_integer.rb @@ -1,7 +1,7 @@ require_relative "../helper" module RubyX - class TestIntegerCompile# < MiniTest::Test + class TestIntegerCompile < MiniTest::Test include ParfaitHelper def setup @compiler = compiler @@ -26,14 +26,17 @@ module RubyX assert_equal :Data8 , vool[3].name end def test_mom - mom = @compiler.ruby_to_mom source + vool = @compiler.ruby_to_vool source + vool.to_parfait + #puts vool + mom = vool.to_mom(nil) assert_equal Mom::MomCollection , mom.class end - def test_risc + def est_risc risc = compiler.ruby_to_risc source assert_equal Risc::RiscCollection , risc.class end - def test_binary + def est_binary risc = compiler.ruby_to_binary source , :interpreter assert_equal Risc::Linker , risc.class end diff --git a/test/rubyx/rt_parfait/test_object.rb b/test/rubyx/rt_parfait/test_object.rb index 1d08d9a7..b50b93f6 100644 --- a/test/rubyx/rt_parfait/test_object.rb +++ b/test/rubyx/rt_parfait/test_object.rb @@ -48,7 +48,7 @@ module RubyX end end end - class TestObjectRtTest #< Minitest::Test + class TestObjectRtTest < Minitest::Test self.class.include ParfaitHelper include Risc::Ticker diff --git a/test/vool/class_send/test_class_send_inherited.rb b/test/vool/class_send/test_class_send_inherited.rb index 037f87ab..50d133a9 100644 --- a/test/vool/class_send/test_class_send_inherited.rb +++ b/test/vool/class_send/test_class_send_inherited.rb @@ -40,7 +40,7 @@ module Vool assert_equal SimpleCall, @ins.next(2).class assert_equal :one_plus, @ins.next(2).method.name assert_equal Parfait::Type, @ins.next(2).method.self_type.class - assert_equal :Class, @ins.next(2).method.self_type.object_class.name + assert_equal :"Space.Single", @ins.next(2).method.self_type.object_class.name end end end diff --git a/test/vool/class_send/test_send_class.rb b/test/vool/class_send/test_send_class.rb index c904abca..af17b105 100644 --- a/test/vool/class_send/test_send_class.rb +++ b/test/vool/class_send/test_send_class.rb @@ -4,9 +4,25 @@ module Vool class TestSendClassMom < MiniTest::Test include VoolCompile + def class_main + <<-eos + class Space + def self.one_plus(one) + return 1 + 1 + end + end + class Space + def main(arg) + return Space.one_plus(1) + end + end + eos + end + def setup - @compiler = compile_main( "Object.get_internal_word(0)" , "Object.get" ) - @ins = @compiler.mom_instructions.next + source = "class Integer < Data4;def +(other);X.int_operator(:+);end;end;" + class_main + ret = RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_mom(source) + @ins = ret.compilers.find_compiler_name(:main).mom_instructions.next end def test_array @@ -37,10 +53,10 @@ module Vool def test_call_is assert_equal SimpleCall, @ins.next(2).class assert_equal Parfait::CallableMethod, @ins.next(2).method.class - assert_equal :get_internal_word, @ins.next(2).method.name + assert_equal :one_plus, @ins.next(2).method.name end def test_call_has_right_receiver - assert_equal "Class_Type", @ins.next(2).method.self_type.name + assert_equal "Space.Single_Type", @ins.next(2).method.self_type.name end end end diff --git a/test/vool/test_class_method_expression.rb b/test/vool/test_class_method_expression.rb index 0fd09c35..7e08951a 100644 --- a/test/vool/test_class_method_expression.rb +++ b/test/vool/test_class_method_expression.rb @@ -5,7 +5,7 @@ module Vool include VoolCompile def class_code - "class Space;def self.meth;return 1 ; end;end" + "class Space;def self.meth; return meth(22 + 22) ; end;end" end def setup Parfait.boot!(Parfait.default_test_options) @@ -33,5 +33,16 @@ module Vool m = clazz.single_class.instance_type.get_method(:meth) assert m , "no type method :meth" end + def as_mom + @clazz.to_parfait + @clazz.to_mom(nil) + end + def test_mom + assert_equal :meth , as_mom.method_compilers.callable.name + end + def test_mom_frame + callable = as_mom.method_compilers.callable + assert callable.frame_type.names.last.to_s.start_with?("tmp_") , "no tmp_ variable #{callable.frame_type.names}" + end end end