From a7551ea8b621bf3927050c33c6c7bf60ca08d061 Mon Sep 17 00:00:00 2001 From: Torsten Ruger Date: Fri, 13 Jun 2014 23:41:45 +0300 Subject: [PATCH] still working on the method dispatch --- lib/arm/arm_machine.rb | 5 +++++ lib/ast/basic_expressions.rb | 5 ++--- lib/ast/call_site_expression.rb | 36 ++++++++++++++++++++----------- lib/boot/object.rb | 2 +- lib/core/kernel.rb | 9 +++++++- lib/vm/boot_class.rb | 11 ++++------ lib/vm/boot_space.rb | 8 +++++-- lib/vm/meta_class.rb | 13 ++++++----- test/fragments/test_class.rb | 25 +++++++++++++++++---- test/fragments/test_while_fibo.rb | 4 ++-- 10 files changed, 79 insertions(+), 39 deletions(-) diff --git a/lib/arm/arm_machine.rb b/lib/arm/arm_machine.rb index bf3071bd..ebbe5cf3 100644 --- a/lib/arm/arm_machine.rb +++ b/lib/arm/arm_machine.rb @@ -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) diff --git a/lib/ast/basic_expressions.rb b/lib/ast/basic_expressions.rb index 161a3d8e..afa30178 100644 --- a/lib/ast/basic_expressions.rb +++ b/lib/ast/basic_expressions.rb @@ -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 diff --git a/lib/ast/call_site_expression.rb b/lib/ast/call_site_expression.rb index 7dc014d9..046234b8 100644 --- a/lib/ast/call_site_expression.rb +++ b/lib/ast/call_site_expression.rb @@ -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 diff --git a/lib/boot/object.rb b/lib/boot/object.rb index 7100381b..e8c85f9b 100644 --- a/lib/boot/object.rb +++ b/lib/boot/object.rb @@ -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") diff --git a/lib/core/kernel.rb b/lib/core/kernel.rb index c5a5a666..74157071 100644 --- a/lib/core/kernel.rb +++ b/lib/core/kernel.rb @@ -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) diff --git a/lib/vm/boot_class.rb b/lib/vm/boot_class.rb index 88ee5b87..dea66328 100644 --- a/lib/vm/boot_class.rb +++ b/lib/vm/boot_class.rb @@ -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 diff --git a/lib/vm/boot_space.rb b/lib/vm/boot_space.rb index 0e23795f..e086c7dd 100644 --- a/lib/vm/boot_space.rb +++ b/lib/vm/boot_space.rb @@ -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 diff --git a/lib/vm/meta_class.rb b/lib/vm/meta_class.rb index 1fd4a738..c4d7a8eb 100644 --- a/lib/vm/meta_class.rb +++ b/lib/vm/meta_class.rb @@ -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 diff --git a/test/fragments/test_class.rb b/test/fragments/test_class.rb index 77dbc380..4724b5c8 100644 --- a/test/fragments/test_class.rb +++ b/test/fragments/test_class.rb @@ -6,6 +6,27 @@ class TestClass < MiniTest::Test def test_class @string_input = <