From b7c2089046ba3018df97228da969d8c59dc85c36 Mon Sep 17 00:00:00 2001 From: Torsten Ruger Date: Tue, 3 Jun 2014 14:49:02 +0300 Subject: [PATCH] the further down this goes, the smaller the circles. Soon the point will come. And then back out --- lib/ast/call_site_expression.rb | 14 ++++++--- lib/ast/function_expression.rb | 12 ++++++-- lib/boot/object.rb | 51 +++++++++++++++++++++++++++++++++ lib/core/base_object.rb | 23 --------------- lib/core/kernel.rb | 21 -------------- lib/vm/boot_space.rb | 12 +++++++- test/fragments/test_class.rb | 13 ++++++--- 7 files changed, 90 insertions(+), 56 deletions(-) create mode 100644 lib/boot/object.rb delete mode 100644 lib/core/base_object.rb diff --git a/lib/ast/call_site_expression.rb b/lib/ast/call_site_expression.rb index ff9aae88..f9c01be8 100644 --- a/lib/ast/call_site_expression.rb +++ b/lib/ast/call_site_expression.rb @@ -4,15 +4,21 @@ module Ast class CallSiteExpression < Expression attr_reader :name, :args , :receiver - def initialize name, args , receiver = Ast::NameExpression.new("self") + def initialize name, args , receiver = Ast::NameExpression.new(:self) @name , @args , @receiver = name.to_sym , args , receiver end def compile context , into params = args.collect{ |a| a.compile(context, into) } - #TOOD, this needs dynamic resolution - function = context.current_class.get_or_create_function(name) - raise "Forward declaration not implemented (#{name}) #{inspect}" if function == nil + + r = context.current_class.name + if !receiver.nil? and receiver.name != :self + r = receiver.name + end + clazz = context.object_space.get_or_create_class r + + function = context.current_class.get_function(name) + raise "Forward declaration not implemented for #{clazz.name}:#{name} #{inspect}" if function == nil call = Vm::CallSite.new( name , params , function) current_function = context.function current_function.save_locals(context , into) if current_function diff --git a/lib/ast/function_expression.rb b/lib/ast/function_expression.rb index 806c47cc..e161ab32 100644 --- a/lib/ast/function_expression.rb +++ b/lib/ast/function_expression.rb @@ -31,10 +31,16 @@ module Ast locals[arg] = arg_value args << arg_value end - class_name = context.current_class.name - function = Vm::Function.new(name , args ) # class depends on receiver - context.current_class.add_function function + if receiver.nil? + clazz = context.current_class + else + c = context.object_space.get_or_create_class receiver.name.to_sym + clazz = c.meta_class + end + + function = Vm::Function.new(name , args ) + clazz.add_function function parent_locals = context.locals parent_function = context.function diff --git a/lib/boot/object.rb b/lib/boot/object.rb new file mode 100644 index 00000000..822c660c --- /dev/null +++ b/lib/boot/object.rb @@ -0,0 +1,51 @@ +module Boot + class Object + module ClassMethods + + # return the index of the variable. Now "normal" code can't really do anything with that, but + # set/get instance variable use it. + # This is just a placeholder, as we code this in ruby, but the instance methods need the definition before. + def index_of context , name = Vm::Integer + index_function = Vm::Function.new(:index_of , [Vm::Integer] , Vm::Integer ) + return index_function + end + + + # in ruby, how this goes is + # def _get_instance_variable var + # i = self.index_of(var) + # return at_index(i) + # end + # The at_index is just "below" the api, somehting we need but don't want to expose, so we can't code the above in ruby + def _get_instance_variable context , name = Vm::Integer + get_function = Vm::Function.new(:_get_instance_variable , [Vm::Integer , Vm::Integer ] , Vm::Integer ) + me = get_function.args[0] + var_name = get_function.args[1] + return_to = get_function.return_type + index_function = context.object_space.get_or_create_class(:Object).get_or_create_function(:index_of) + b = get_function.body + b.push( me ) + index = b.call( index_function ) + b.pop(me) + return_to.at_index( get_function.body , me , index ) + get_function.set_return return_to + return get_function + end + + def _set_instance_variable(name , value) + raise name + end + + def _get_singleton_method(name ) + raise name + end + def _add_singleton_method(method) + raise "4" + end + def initialize() + raise "4" + end + end + extend ClassMethods + end +end diff --git a/lib/core/base_object.rb b/lib/core/base_object.rb deleted file mode 100644 index dda53708..00000000 --- a/lib/core/base_object.rb +++ /dev/null @@ -1,23 +0,0 @@ -module Core - class BaseObject - - def _set_instance_variable(name , value) - return name - end - - def _get_instance_variable( name ) - return name - end - - def _get_singleton_method(name ) - return name - end - def _add_singleton_method(method) - return 4 - end - def initialize() - return 4 - end - - end -end diff --git a/lib/core/kernel.rb b/lib/core/kernel.rb index 09badc56..4985468d 100644 --- a/lib/core/kernel.rb +++ b/lib/core/kernel.rb @@ -20,27 +20,6 @@ module Core def function_exit block , f_name Vm::RegisterMachine.instance.function_exit block , f_name end - - # in ruby, how this goes is - # def _get_instance_variable var - # i = self.index_of(var) - # return at_index(i) - # end - # The at_index is just "below" the api, somehting we need but don't want to expose, so we can't code the above in ruby - def _get_instance_variable context , name = Vm::Integer - get_function = Vm::Function.new(:_get_instance_variable , [Vm::Integer , Vm::Integer ] , Vm::Integer ) - me = get_function.args[0] - var_name = get_function.args[1] - return_to = get_function.return_type - index_function = context.object_space.get_or_create_class(:Object).get_or_create_function(:index_of) - b = get_function.body - b.push( me ) - index = b.call( index_function ) - b.pop(me) - return_to.at_index( get_function.body , me , index ) - get_function.set_return return_to - return get_function - end #TODO this is in the wrong place. It is a function that returns a function object # while all other methods add their code into some block. --> kernel diff --git a/lib/vm/boot_space.rb b/lib/vm/boot_space.rb index 775b039d..7dc32814 100644 --- a/lib/vm/boot_space.rb +++ b/lib/vm/boot_space.rb @@ -3,6 +3,7 @@ require_relative "boot_class" require_relative "call_site" require "arm/arm_machine" require "core/kernel" +require "boot/object" module Vm # The BootSpace is contains all objects for a program. In functional terms it is a program, but on oo @@ -35,9 +36,18 @@ module Vm #main gets executed between entry and exit @main = Block.new("main",nil) @exit = Core::Kernel::main_exit Vm::Block.new("main_exit",nil) + boot_classes end attr_reader :context , :main , :classes , :entry , :exit + def boot_classes + # very fiddly chicken 'n egg problem. Functions need to be in the right order, and in fact we have to define some + # dummies, just for the other to compile + obj = get_or_create_class :Object + [:index_of , :_get_instance_variable].each do |f| + obj.add_function Boot::Object.send(f , @context) + end + end def add_object o return if @objects.include? o raise "must be derived from Code #{o.inspect}" unless o.is_a? Code @@ -45,7 +55,7 @@ module Vm end def get_or_create_class name - raise "uups #{name}" unless name.is_a? Symbol + raise "uups #{name}.#{name.class}" unless name.is_a? Symbol c = @classes[name] unless c c = BootClass.new(name,@context) diff --git a/test/fragments/test_class.rb b/test/fragments/test_class.rb index da32ea95..33f9e664 100644 --- a/test/fragments/test_class.rb +++ b/test/fragments/test_class.rb @@ -16,20 +16,25 @@ class Object return @layout.class() end end +class Class + def Class.new_object( length ) + return 4 + end +end class String + def String.new_string( len ) + return Class.new_object( len << 2 ) + end def length() return @length end - def self.new_string( len ) - 4 - end def plus(str) my_length = @length str_len = str.length() new_string = String.new_string(my_length + str_len) i = 0 while( i < my_length) do - char = self.get(i) + char = get(i) new_string.set(i , char) i = i + 1 end