still working on the method dispatch

This commit is contained in:
Torsten Ruger 2014-06-13 23:41:45 +03:00
parent ebf117a63a
commit a7551ea8b6
10 changed files with 79 additions and 39 deletions

View File

@ -102,6 +102,11 @@ module Arm
syscall( function.insertion_point , 4 ) # 4 == write
end
# stop, do not return
def exit function #, string
syscall( function.insertion_point , 1 ) # 1 == exit
end
# the number (a Vm::integer) is (itself) divided by 10, ie overwritten by the result
# and the remainder is overwritten (ie an out argument)

View File

@ -26,9 +26,8 @@ module Ast
raise "uups #{clazz}.#{name}" unless clazz
#class qualifier, means call from metaclass
clazz = clazz.meta_class
value = clazz
puts "CLAZZ #{value}"
function = clazz.get_or_create_function(name)
puts "CLAZZ #{clazz}"
clazz
end
end

View File

@ -7,20 +7,33 @@ module Ast
def compile context
into = context.function
params = args.collect{ |a| a.compile(context) }
if receiver.is_a?(NameExpression) and (receiver.name == :self)
function = context.current_class.get_or_create_function(name)
value_receiver = Vm::Integer.new(Vm::RegisterMachine.instance.receiver_register)
else
puts "compiling receiver #{receiver} (call #{name})"
if receiver.is_a? ModuleName
clazz = context.object_space.get_or_create_class receiver.name
function = clazz.resolve_function name
elsif receiver.is_a?(StringExpression) or receiver.is_a?(IntegerExpression)
#TODO obviously the class is wrong, but you gotta start somewhere
clazz = context.object_space.get_or_create_class :Object
function = clazz.resolve_function name
value_receiver = receiver.compile(context)
function = context.current_class.get_or_create_function(name)
end
# this lot below should go, since the compile should handle all
if receiver.is_a? VariableExpression
elsif receiver.is_a?(NameExpression)
if(receiver.name == :self)
function = context.current_class.resolve_function(name)
value_receiver = Vm::Integer.new(Vm::RegisterMachine.instance.receiver_register)
else
value_receiver = receiver.compile(context)
# TODO HACK warning: should determine class dynamically
function = context.current_class.resolve_function(name)
end
elsif receiver.is_a? VariableExpression
raise "not implemented instance var:#{receiver}"
else
#This , how does one say nowadays, smells. Smells of unused polymorphism actually
raise "Not sure this is possible, but never good to leave elses open #{receiver} #{receiver.class}"
# this lot below should go, since the compile should handle all
end
raise "No such method error #{3.to_s}:#{name}" if (function.nil?)
raise "No receiver error #{inspect}:#{value_receiver}:#{name}" if (value_receiver.nil?)
raise "No such method error #{inspect}" if (function.nil?)
raise "No receiver error #{inspect}:#{receiver}" if (value_receiver.nil?)
call = Vm::CallSite.new( name , value_receiver , params , function)
current_function = context.function
into.push([]) unless current_function.nil?
@ -30,7 +43,6 @@ module Ast
after = into.new_block("#{name}#{@@counter+=1}")
into.insert_at after
into.pop([]) unless current_function.nil?
puts "compile call #{function.return_type}"
function.return_type
end
end

View File

@ -22,7 +22,7 @@ module Boot
me = get_function.receiver
var_name = get_function.args.first
return_to = get_function.return_type
index_function = context.object_space.get_or_create_class(:Object).get_or_create_function(:index_of)
index_function = context.object_space.get_or_create_class(:Object).resolve_function(:index_of)
get_function.push( [me] )
get_function.call( index_function )
after_body = get_function.new_block("after_index")

View File

@ -5,6 +5,13 @@ module Core
# We use this module syntax to avoid the (ugly) self (also eases searching).
module ClassMethods
def exit context
function = Vm::Function.new(:exit , Vm::Integer , [] )
ret = Vm::RegisterMachine.instance.exit(function)
function.set_return ret
function
end
def putstring context
function = Vm::Function.new(:putstring , Vm::Integer , [] )
ret = Vm::RegisterMachine.instance.write_stdout(function)
@ -18,7 +25,7 @@ module Core
context.object_space.add_object buffer # and save it (function local variable: a no no)
int = putint_function.receiver
moved_int = putint_function.new_local
utoa = context.object_space.get_or_create_class(:Object).get_or_create_function(:utoa)
utoa = context.object_space.get_or_create_class(:Object).resolve_function(:utoa)
putint_function.instance_eval do
mov( moved_int , int ) # move arg up
add( int , buffer ,nil ) # string to write to (add string address to pc)

View File

@ -28,23 +28,20 @@ module Vm
f
end
# way of creating new functions that have not been parsed.
def get_or_create_function name
# get the function and if not found, try superclasses. raise error if not found
def resolve_function name
fun = get_function name
unless fun or name == :Object
supr = @context.object_space.get_or_create_class(@super_class)
fun = supr.get_function name
puts "#{supr.functions.collect(&:name)} for #{name} GOT #{fun.class}" if name == :index_of
end
unless fun
fun = Core::Kernel.send(name , @context)
@functions << fun
end
raise "Method not found :#{name}, for #{inspect}" unless fun
fun
end
def inspect
"BootClass #{@name} , super #{@super_class} #{@functions.length} functions"
"BootClass #{@name} < #{@super_class}:#{@functions.collect(&:name)}"
end
def to_s
inspect

View File

@ -64,12 +64,16 @@ module Vm
# dummies, just for the other to compile
obj = get_or_create_class :Object
[:index_of , :_get_instance_variable].each do |f|
puts "adding #{f}"
puts "Boot Object::#{f}"
obj.add_function Boot::Object.send(f , @context)
end
[:utoa, :putstring,:putint,:fibo,:exit].each do |f|
puts "Boot Kernel::#{f}"
obj.add_function Core::Kernel.send(f , @context)
end
obj = get_or_create_class :String
[:get , :set].each do |f|
puts "adding #{f}"
puts "Boot String::#{f}"
obj.add_function Boot::String.send(f , @context)
end
end

View File

@ -30,14 +30,13 @@ module Vm
puts "no function for :#{name} in Meta #{@me_self.inspect}" unless f
f
end
# way of creating new functions that have not been parsed.
def get_or_create_function name
# get the function and if not found, try superclasses. raise error if not found
def resolve_function name
fun = get_function name
unless fun or name == :Object
supr = @me_self.context.object_space.get_or_create_class(@super_class)
fun = supr.get_function name
puts "#{supr.functions.collect(&:name)} for #{name} GOT #{fun.class}"
end
# TODO THE BOOK says is class A derives from B , then the metaclass of A derives from the metaclass of B
# just get to it ! (and stop whimpering)
raise "Method not found #{name} , for #{inspect}" unless fun
fun
end

View File

@ -6,6 +6,27 @@ class TestClass < MiniTest::Test
def test_class
@string_input = <<HERE
class Object
def raise()
putstring()
exit()
end
def method_missing(name,args)
name.raise()
end
def class()
l = @layout
return l.class()
end
def resolve_method(name)
clazz = class()
function = clazz._get_instance_variable(name)
index = clazz.index_of(name)
if( function == 0 )
name.raise()
else
return function
end
end
def index_of( name )
l = @layout
return l.index_of(name)
@ -13,10 +34,6 @@ class Object
def layout()
return @layout
end
def class()
l = @layout
return l.class()
end
end
class Class
def Class.new_object( length )

View File

@ -31,12 +31,12 @@ HERE
# not my hand off course, found in the net from a basic introduction
def test_kernel_fibo
int = Vm::Integer.new(Vm::RegisterMachine.instance.receiver_register)
fibo = @object_space.get_or_create_class(:Object).get_or_create_function(:fibo)
fibo = @object_space.get_or_create_class(:Object).resolve_function(:fibo)
main = @object_space.main
main.mov int , 10
main.call( fibo )
main.mov( Vm::RegisterMachine.instance.receiver_register , Vm::RegisterMachine.instance.return_register )
putint = @object_space.get_or_create_class(:Object).get_or_create_function(:putint)
putint = @object_space.get_or_create_class(:Object).resolve_function(:putint)
main.call( putint )
@should = [0x0,0x40,0x2d,0xe9,0x1,0x0,0x52,0xe3,0x2,0x0,0xa0,0xd1,0x7,0x0,0x0,0xda,0x1,0x30,0xa0,0xe3,0x0,0x40,0xa0,0xe3,0x4,0x30,0x83,0xe0,0x4,0x40,0x43,0xe0,0x1,0x20,0x42,0xe2,0x1,0x0,0x52,0xe3,0xfa,0xff,0xff,0x1a,0x3,0x0,0xa0,0xe1,0x0,0x80,0xbd,0xe8]
@target = [:Object , :fibo]