linked list of methods instead of list of methods

api changes slightly, especially for each, but mostly sama sama
This commit is contained in:
Torsten Ruger 2018-04-02 16:36:43 +03:00
parent ad497b34f1
commit fb29fb6431
10 changed files with 73 additions and 26 deletions

View File

@ -24,7 +24,7 @@ module Elf
# for debug add labels for labels # for debug add labels for labels
Parfait.object_space.each_type do |type| Parfait.object_space.each_type do |type|
type.methods.each do |f| type.each_method do |f|
f.cpu_instructions.each do |label| f.cpu_instructions.each do |label|
next unless label.is_a?(Risc::Label) next unless label.is_a?(Risc::Label)
add_symbol "#{type.name}::#{f.name}:#{label.name}" , Positioned.position(label) add_symbol "#{type.name}::#{f.name}:#{label.name}" , Positioned.position(label)

View File

@ -75,7 +75,7 @@ module Parfait
def collect_methods def collect_methods
methods = [] methods = []
each_type do | type | each_type do | type |
type.methods.each do |meth| type.each_method do |meth|
methods << meth methods << meth
end end
end end

View File

@ -52,7 +52,7 @@ module Parfait
# this part of the init is seperate because at boot time we can not use normal new # this part of the init is seperate because at boot time we can not use normal new
# new is overloaded to grab the type from space, and before boot, that is not set up # new is overloaded to grab the type from space, and before boot, that is not set up
def init_lists(hash) def init_lists(hash)
@methods = List.new @methods = nil
@names = List.new @names = List.new
@types = List.new @types = List.new
raise "No type Type in #{hash}" unless hash[:type] raise "No type Type in #{hash}" unless hash[:type]
@ -68,7 +68,8 @@ module Parfait
def method_names def method_names
names = List.new names = List.new
@methods.each do |method| return names unless @methods
@methods.each_method do |method|
names.push method.name names.push method.name
end end
names names
@ -95,25 +96,39 @@ module Parfait
if self.is_a?(Class) and (method.for_type != self) if self.is_a?(Class) and (method.for_type != self)
raise "Adding to wrong class, should be #{method.for_class}" raise "Adding to wrong class, should be #{method.for_class}"
end end
found = get_method( method.name ) if get_method( method.name )
if found remove_method(method.name)
@methods.delete(found)
end end
@methods.push method method.set_next( @methods )
@methods = method
#puts "#{self.name} add #{method.name}" #puts "#{self.name} add #{method.name}"
method method
end end
def remove_method( method_name ) def remove_method( method_name )
found = get_method( method_name ) raise "May not remove method_missing" if method_name == :method_missing
raise "No such method #{method_name} in #{self.name}" unless found raise "No such method #{method_name} in #{self.name}" unless @methods
@methods.delete(found) if( @methods.name == method_name)
@methods = @methods.next_method
return true
end
method = @methods
while(method && method.next_method)
if( method.next_method.name == method_name)
method.set_next( method.next_method.next_method )
return true
else
method = method.next_method
end
end
raise "No such method #{method_name} in #{self.name}"
end end
def get_method( fname ) def get_method( fname )
raise "get_method #{fname}.#{fname.class}" unless fname.is_a?(Symbol) raise "get_method #{fname}.#{fname.class}" unless fname.is_a?(Symbol)
#if we had a hash this would be easier. Detect or find would help too #if we had a hash this would be easier. Detect or find would help too
@methods.each do |m| return nil unless @methods
@methods.each_method do |m|
return m if(m.name == fname ) return m if(m.name == fname )
end end
nil nil
@ -133,6 +148,13 @@ module Parfait
sup.instance_type.resolve_method(fname) sup.instance_type.resolve_method(fname)
end end
def methods_length
return 0 unless @methods
len = 0
@methods.each_method { len += 1}
return len
end
def == other def == other
self.object_id == other.object_id self.object_id == other.object_id
end end
@ -195,6 +217,10 @@ module Parfait
end end
end end
def each_method(&block)
return unless @methods
@methods.each_method(&block)
end
def to_hash def to_hash
hash = {} hash = {}
each do |name , type| each do |name , type|

View File

@ -22,7 +22,7 @@ module Parfait
class TypedMethod < Object class TypedMethod < Object
attr_reader :name , :risc_instructions , :for_type , :cpu_instructions attr_reader :name , :risc_instructions , :for_type , :cpu_instructions
attr_reader :arguments , :frame , :binary attr_reader :arguments , :frame , :binary , :next_method
# not part of the parfait model, hence ruby accessor # not part of the parfait model, hence ruby accessor
attr_accessor :source attr_accessor :source
@ -118,5 +118,12 @@ module Parfait
"#{@for_type.object_class.name}:#{name}(#{arguments.inspect})" "#{@for_type.object_class.name}:#{name}(#{arguments.inspect})"
end end
def each_method( &block )
block.call( self )
next_method.each_method( &block ) if next_method
end
def set_next( method )
@next_method = method
end
end end
end end

View File

@ -145,14 +145,15 @@ module Risc
false_object: :FalseClass , nil_object: :NilClass}, false_object: :FalseClass , nil_object: :NilClass},
NamedList: {}, NamedList: {},
Type: {names: :List , types: :List , Type: {names: :List , types: :List ,
object_class: :Class, methods: :List } , object_class: :Class, methods: :TypedMethod } ,
Class: {instance_methods: :List, instance_type: :Type, name: :Word, Class: {instance_methods: :List, instance_type: :Type, name: :Word,
super_class_name: :Word , instance_names: :List }, super_class_name: :Word , instance_names: :List },
Dictionary: {keys: :List , values: :List } , Dictionary: {keys: :List , values: :List } ,
CacheEntry: {cached_type: :Type , cached_method: :TypedMethod } , CacheEntry: {cached_type: :Type , cached_method: :TypedMethod } ,
TypedMethod: {name: :Word, source: :Object, risc_instructions: :Object, TypedMethod: {name: :Word, source: :Object, risc_instructions: :Object,
cpu_instructions: :Object, binary: :BinaryCode, cpu_instructions: :Object, binary: :BinaryCode,
arguments: :Type , for_type: :Type, frame: :Type } , arguments: :Type , for_type: :Type, frame: :Type ,
next_method: :TypedMethod} ,
} }
end end

View File

@ -55,10 +55,8 @@ module Risc
# This method is just a placeholder until boot is over and the real method is # This method is just a placeholder until boot is over and the real method is
# parsed. # parsed.
def resolve_method( context) def resolve_method( context)
compiler = compiler_for(:Word, :resolve_method , {:value => :Object} ) compiler = compiler_for(:Word, :resolve_method , {:value => :Type} )
args = compiler.method.arguments
len = args.instance_length
raise "Compiler arg number mismatch, method=#{args} " if len != 2
compiler.add_mom( Mom::ReturnSequence.new) compiler.add_mom( Mom::ReturnSequence.new)
return compiler.method return compiler.method
end end

View File

@ -99,6 +99,11 @@ module Risc
true true
end end
# Instruction interpretation starts here # Instruction interpretation starts here
def execute_DynamicJump
label = get_register(@instruction.register)
puts "Jump to :#{label}:"
set_instruction label
end
def execute_Branch def execute_Branch
label = @instruction.label label = @instruction.label
set_instruction label set_instruction label

View File

@ -149,13 +149,13 @@ class TestSpace < MiniTest::Test
def test_no_methods_in_types def test_no_methods_in_types
test_remove_methods test_remove_methods
@space.each_type do |type| @space.each_type do |type|
assert_equal 0 , type.methods.get_length , "name #{type.name}" assert_equal 0 , type.methods_length , "name #{type.name}"
end end
end end
def test_no_methods_in_classes def test_no_methods_in_classes
test_remove_methods test_remove_methods
@space.classes.each do |name , cl| @space.classes.each do |name , cl|
assert_equal 0 , cl.instance_type.methods.get_length , "name #{cl.name}" assert_equal 0 , cl.instance_type.methods_length , "name #{cl.name}"
end end
end end

View File

@ -25,24 +25,30 @@ class TestMethodApi < MiniTest::Test
@space.get_class_by_name(:Object).instance_type @space.get_class_by_name(:Object).instance_type
end end
def test_new_methods def test_new_methods
assert_equal @try_type.method_names.class, @try_type.methods.class assert_equal Parfait::List , @try_type.method_names.class
assert_equal @try_type.method_names.get_length , @try_type.methods.get_length assert_equal @try_type.method_names.get_length , @try_type.methods_length
end end
def test_add_method def test_add_method
before = @try_type.methods.get_length before = @try_type.methods_length
add_foo_to add_foo_to
assert_equal 1 , @try_type.methods.get_length - before assert_equal 1 , @try_type.methods_length - before
assert @try_type.method_names.inspect.include?(":foo") assert @try_type.method_names.inspect.include?(":foo")
end end
def test_remove_method def test_remove_method
add_foo_to add_foo_to
assert_equal true , @try_type.remove_method(:foo) assert @try_type.remove_method(:foo)
end end
def test_remove_not_there def test_remove_not_there
assert_raises RuntimeError do assert_raises RuntimeError do
@try_type.remove_method(:foo) @try_type.remove_method(:foo)
end end
end end
def test_remove_method_missing
# assert @try_type.get_method( :method_missing)
assert_raises RuntimeError do
@try_type.remove_method(:method_missing)
end
end
def test_create_method def test_create_method
args = Parfait::Type.for_hash( @try_class , { bar: :Integer}) args = Parfait::Type.for_hash( @try_class , { bar: :Integer})
@try_type.create_method :bar, args , empty_frame @try_type.create_method :bar, args , empty_frame

View File

@ -50,6 +50,10 @@ module Risc
assert_equal Label , call_ins.class assert_equal Label , call_ins.class
assert_equal "Word_Type.resolve_method" , call_ins.name assert_equal "Word_Type.resolve_method" , call_ins.name
end end
def est_dyn
cal = ticks(102)
assert_equal DynamicJump , cal.class
end
#should end in exit, but doesn't, becasue resolve never returns #should end in exit, but doesn't, becasue resolve never returns
def ttest_sys def ttest_sys
sys = ticks(20) sys = ticks(20)