adding receiver and a register abstraction

This commit is contained in:
Torsten Ruger 2014-06-06 21:49:03 +03:00
parent c59f22f11f
commit 6433a394e7
6 changed files with 56 additions and 23 deletions

View File

@ -7,19 +7,21 @@ module Ast
locals = {} locals = {}
params.each_with_index do |param , index| params.each_with_index do |param , index|
arg = param.name arg = param.name
arg_value = Vm::Integer.new(index+1) arg_value = Vm::Integer.new(index+2)
locals[arg] = arg_value locals[arg] = arg_value
args << arg_value args << arg_value
end end
# class depends on receiver # class depends on receiver
if receiver.nil? if receiver.nil?
clazz = context.current_class clazz = context.current_class
me = Vm::Integer.new( Vm::Function::RECEIVER_REG )
else else
c = context.object_space.get_or_create_class receiver.name.to_sym c = context.object_space.get_or_create_class receiver.name.to_sym
clazz = c.meta_class clazz = c.meta_class
raise "get the constant loaded to 1"
end end
function = Vm::Function.new(name , args ) function = Vm::Function.new(name , me , args )
clazz.add_function function clazz.add_function function
parent_locals = context.locals parent_locals = context.locals

View File

@ -6,7 +6,7 @@ module Boot
# set/get instance variable use it. # 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. # 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 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 return index_function
end end
@ -18,7 +18,7 @@ module Boot
# end # 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 # 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 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] me = get_function.args[0]
var_name = get_function.args[1] var_name = get_function.args[1]
return_to = get_function.return_type return_to = get_function.return_type

View File

@ -2,11 +2,11 @@ module Boot
class String class String
module ClassMethods module ClassMethods
def get context , index = Vm::Integer 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 return get_function
end end
def set context , index = Vm::Integer , char = Vm::Integer 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 return set_function
end end
end end

View File

@ -32,8 +32,8 @@ module Core
function function
end end
def putint context , arg = Vm::Integer def putint context
putint_function = Vm::Function.new(:putint , [arg] , arg ) putint_function = Vm::Function.new(:putint , Vm::Integer , [] , Vm::Integer )
buffer = Vm::StringConstant.new(" ") # create a buffer buffer = Vm::StringConstant.new(" ") # create a buffer
context.object_space.add_object buffer # and save it (function local variable: a no no) context.object_space.add_object buffer # and save it (function local variable: a no no)
int = putint_function.args.first 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 # As we write before we recurse (save a push) we write the number backwards
# arguments: string address , integer # arguments: string address , integer
def utoa context 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] str_addr = utoa_function.args[0]
number = utoa_function.args[1] number = utoa_function.args[1]
remainder = utoa_function.new_local remainder = utoa_function.new_local
@ -79,7 +79,7 @@ module Core
# a hand coded version of the fibonachi numbers # a hand coded version of the fibonachi numbers
# not my hand off course, found in the net from a basic introduction # not my hand off course, found in the net from a basic introduction
def fibo context 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) result = Vm::Integer.new(7)
int = fibo_function.args[0] int = fibo_function.args[0]
count = fibo_function.new_local count = fibo_function.new_local

View File

@ -27,16 +27,27 @@ module Vm
class Function < Code 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() super()
@name = name.to_sym @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 = Array.new(args.length)
args.each_with_index do |arg , i| args.each_with_index do |arg , i|
if arg.is_a?(Value) if arg.is_a?(Value)
@args[i] = arg @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 else
@args[i] = arg.new(i+1) @args[i] = arg.new(i+1+RECEIVER_REG)
end end
end end
set_return return_type set_return return_type
@ -48,14 +59,14 @@ module Vm
@blocks = [] @blocks = []
end 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 def set_return type_or_value
@return_type = type_or_value || Vm::Integer @return_type = type_or_value || Vm::Integer
if @return_type.is_a?(Value) 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 else
@return_type = @return_type.new(7) @return_type = @return_type.new(RETURN_REG)
end end
end end
def arity def arity
@ -63,13 +74,14 @@ module Vm
end end
def new_local type = Vm::Integer 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 l = type.new(register + 1) # one for the type register 0, TODO add type as arg0 implicitly
puts "new local #{l.register}" puts "new local #{l.register}"
# raise "Register overflow in function #{name}" if l.register > 6 # raise "Register overflow in function #{name}" if l.register > 6
@locals << l @locals << l
l l
end end
#BUG - must save receiver
def save_locals context , into def save_locals context , into
save = args.collect{|a| a.register } + @locals.collect{|l| l.register} save = args.collect{|a| a.register } + @locals.collect{|l| l.register}

View File

@ -48,21 +48,40 @@ module Vm
end end
end end
# This is what it is when we don't know what it is. # RegisterUSe is _not_ the name for a register, "only" for a certain use of it.
# Must be promoted to A Word-Value to to anything # 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 # remembering that our oo machine is typed, no overloading or stuff
class Word < Value class Word < Value
attr_accessor :register attr_accessor :used_register
def register
@used_register.register
end
def inspect def inspect
self.class.name + "(r#{register})" self.class.name + "(r#{used_register.register})"
end end
def to_s def to_s
inspect inspect
end end
def initialize reg 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 raise inspect if reg == nil
end end
def length def length