From 6433a394e7ecb4cefab3f51e3a55e2e0d76cd8f8 Mon Sep 17 00:00:00 2001 From: Torsten Ruger Date: Fri, 6 Jun 2014 21:49:03 +0300 Subject: [PATCH] adding receiver and a register abstraction --- lib/ast/function_expression.rb | 6 ++++-- lib/boot/object.rb | 4 ++-- lib/boot/string.rb | 4 ++-- lib/core/kernel.rb | 8 ++++---- lib/vm/function.rb | 28 ++++++++++++++++++++-------- lib/vm/values.rb | 29 ++++++++++++++++++++++++----- 6 files changed, 56 insertions(+), 23 deletions(-) diff --git a/lib/ast/function_expression.rb b/lib/ast/function_expression.rb index d2be2e49..cb4a9de0 100644 --- a/lib/ast/function_expression.rb +++ b/lib/ast/function_expression.rb @@ -7,19 +7,21 @@ module Ast locals = {} params.each_with_index do |param , index| arg = param.name - arg_value = Vm::Integer.new(index+1) + arg_value = Vm::Integer.new(index+2) locals[arg] = arg_value args << arg_value end # class depends on receiver if receiver.nil? clazz = context.current_class + me = Vm::Integer.new( Vm::Function::RECEIVER_REG ) else c = context.object_space.get_or_create_class receiver.name.to_sym clazz = c.meta_class + raise "get the constant loaded to 1" end - function = Vm::Function.new(name , args ) + function = Vm::Function.new(name , me , args ) clazz.add_function function parent_locals = context.locals diff --git a/lib/boot/object.rb b/lib/boot/object.rb index 9fead4ce..feddfde9 100644 --- a/lib/boot/object.rb +++ b/lib/boot/object.rb @@ -6,7 +6,7 @@ module Boot # 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 ) + index_function = Vm::Function.new(:index_of , Vm::Integer , [Vm::Integer] , Vm::Integer ) return index_function end @@ -18,7 +18,7 @@ module Boot # 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 ) + 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 diff --git a/lib/boot/string.rb b/lib/boot/string.rb index ecd43393..b1642ee9 100644 --- a/lib/boot/string.rb +++ b/lib/boot/string.rb @@ -2,11 +2,11 @@ module Boot class String module ClassMethods def get context , index = Vm::Integer - get_function = Vm::Function.new(:get , [Vm::Integer, Vm::Integer] , Vm::Integer ) + get_function = Vm::Function.new(:get , Vm::Integer , [ Vm::Integer] , Vm::Integer ) return get_function end def set context , index = Vm::Integer , char = Vm::Integer - set_function = Vm::Function.new(:set , [Vm::Integer, Vm::Integer, Vm::Integer] , Vm::Integer ) + set_function = Vm::Function.new(:set , Vm::Integer ,[Vm::Integer, Vm::Integer] , Vm::Integer ) return set_function end end diff --git a/lib/core/kernel.rb b/lib/core/kernel.rb index 4985468d..1a17c333 100644 --- a/lib/core/kernel.rb +++ b/lib/core/kernel.rb @@ -32,8 +32,8 @@ module Core function end - def putint context , arg = Vm::Integer - putint_function = Vm::Function.new(:putint , [arg] , arg ) + def putint context + putint_function = Vm::Function.new(:putint , Vm::Integer , [] , Vm::Integer ) buffer = Vm::StringConstant.new(" ") # create a buffer context.object_space.add_object buffer # and save it (function local variable: a no no) int = putint_function.args.first @@ -59,7 +59,7 @@ module Core # As we write before we recurse (save a push) we write the number backwards # arguments: string address , integer def utoa context - utoa_function = Vm::Function.new(:utoa , [Vm::Integer , Vm::Integer ] , Vm::Integer ) + utoa_function = Vm::Function.new(:utoa , Vm::Integer , [ Vm::Integer ] , Vm::Integer ) str_addr = utoa_function.args[0] number = utoa_function.args[1] remainder = utoa_function.new_local @@ -79,7 +79,7 @@ module Core # a hand coded version of the fibonachi numbers # not my hand off course, found in the net from a basic introduction def fibo context - fibo_function = Vm::Function.new(:fibo , [Vm::Integer] , Vm::Integer ) + fibo_function = Vm::Function.new(:fibo , Vm::Integer , [] , Vm::Integer ) result = Vm::Integer.new(7) int = fibo_function.args[0] count = fibo_function.new_local diff --git a/lib/vm/function.rb b/lib/vm/function.rb index 5f09d7b5..01f9e2d4 100644 --- a/lib/vm/function.rb +++ b/lib/vm/function.rb @@ -27,16 +27,27 @@ module Vm class Function < Code - def initialize(name , args = [] , return_type = nil) + TYPE_REG = 0 + RECEIVER_REG = 1 + RETURN_REG = 7 + + def initialize(name , receiver = Vm::Integer , args = [] , return_type = Vm::Integer) super() @name = name.to_sym + if receiver.is_a?(Value) + @receiver = receiver + raise "arg in non std register #{arg.inspect}" unless RECEIVER_REG == receiver.register + else + @receiver = receiver.new(RECEIVER_REG) + end + @args = Array.new(args.length) args.each_with_index do |arg , i| if arg.is_a?(Value) @args[i] = arg - raise "arg in non std register #{arg.inspect}" unless (i+1) == arg.register + raise "arg in non std register #{arg.inspect}" unless (i+1+RECEIVER_REG) == arg.register else - @args[i] = arg.new(i+1) + @args[i] = arg.new(i+1+RECEIVER_REG) end end set_return return_type @@ -48,14 +59,14 @@ module Vm @blocks = [] end - attr_reader :args , :entry , :exit , :body , :name , :return_type + attr_reader :args , :entry , :exit , :body , :name , :return_type , :revceiver def set_return type_or_value @return_type = type_or_value || Vm::Integer if @return_type.is_a?(Value) - raise "return in non std register #{@return_type.inspect}" unless 7 == @return_type.register + raise "return in non std register #{@return_type.inspect}" unless RETURN_REG == @return_type.register else - @return_type = @return_type.new(7) + @return_type = @return_type.new(RETURN_REG) end end def arity @@ -63,14 +74,15 @@ module Vm end def new_local type = Vm::Integer - register = args.length + @locals.length + register = args.length + 1 + @locals.length # one for the receiver implicit arg l = type.new(register + 1) # one for the type register 0, TODO add type as arg0 implicitly puts "new local #{l.register}" # raise "Register overflow in function #{name}" if l.register > 6 @locals << l l end - + #BUG - must save receiver + def save_locals context , into save = args.collect{|a| a.register } + @locals.collect{|l| l.register} into.push(save) unless save.empty? diff --git a/lib/vm/values.rb b/lib/vm/values.rb index c9cdcb68..982c6307 100644 --- a/lib/vm/values.rb +++ b/lib/vm/values.rb @@ -48,21 +48,40 @@ module Vm end end - # This is what it is when we don't know what it is. - # Must be promoted to A Word-Value to to anything + # RegisterUSe is _not_ the name for a register, "only" for a certain use of it. + # In a way it is like a variable name, a storage location. The location is a register off course, + # but which register can be changed, and _all_ instructions sharing the RegisterUse then use that register + # In other words a simple level of indirection, or change from value to reference sematics. + class RegisterUse + attr_accessor :register + def initialize r + @register = r + end + end + + # This is what it is when we don't know what it is. #TODO, better if it were explicitly a different type, not the base + # Must be promoted to A Word-Value to to anything makes is_a chaecking easier # remembering that our oo machine is typed, no overloading or stuff class Word < Value - attr_accessor :register + attr_accessor :used_register + + def register + @used_register.register + end def inspect - self.class.name + "(r#{register})" + self.class.name + "(r#{used_register.register})" end def to_s inspect end def initialize reg - @register = reg + if reg.is_a? Fixnum + @used_register = RegisterUse.new(reg) + else + @used_register = reg + end raise inspect if reg == nil end def length