turned out to be a rewrite of boot process
and also attribute handling and fake_memory luckily there are tests and all is green again
This commit is contained in:
parent
f8cb33ec5e
commit
2d0424a370
1
Gemfile
1
Gemfile
@ -6,6 +6,7 @@ gem "rake"
|
||||
|
||||
gem "salama-reader" , :github => "salama/salama-reader"
|
||||
gem "salama-object-file" , :github => "salama/salama-object-file"
|
||||
#gem "salama-object-file" , :path => "../salama-object-file"
|
||||
gem "salama-arm" , :github => "salama/salama-arm"
|
||||
|
||||
gem "codeclimate-test-reporter", require: nil
|
||||
|
@ -6,7 +6,7 @@ GIT
|
||||
|
||||
GIT
|
||||
remote: git://github.com/salama/salama-object-file.git
|
||||
revision: 9e49f2e725dbad48edc151419882b159505b2e9b
|
||||
revision: fbae6a02764dbe97e01e4833f9ffffe09879b100
|
||||
specs:
|
||||
salama-object-file (0.2.0)
|
||||
|
||||
@ -56,3 +56,6 @@ DEPENDENCIES
|
||||
salama-arm!
|
||||
salama-object-file!
|
||||
salama-reader!
|
||||
|
||||
BUNDLED WITH
|
||||
1.10.5
|
||||
|
@ -12,9 +12,9 @@ module Parfait
|
||||
class BinaryCode < Word
|
||||
def initialize name
|
||||
super(0)
|
||||
@name = name
|
||||
self.name = name
|
||||
end
|
||||
attr_reader :name
|
||||
attribute :name
|
||||
|
||||
# this is a sof check if there are instance variables or "structure"
|
||||
# have to override false, as word answers true
|
||||
@ -22,7 +22,7 @@ module Parfait
|
||||
false
|
||||
end
|
||||
def to_s
|
||||
"BinaryCode #{@name}"
|
||||
"BinaryCode #{self.name}"
|
||||
end
|
||||
|
||||
def == other
|
||||
|
@ -14,16 +14,13 @@ require_relative "meta_class"
|
||||
|
||||
module Parfait
|
||||
class Class < Module
|
||||
attribute :object_layout
|
||||
|
||||
def initialize name , super_class
|
||||
super( name , super_class)
|
||||
# the layout for this class (class = object of type Class) carries the class
|
||||
# as an instance. The relation is from an object through the Layout to it's class
|
||||
@object_layout = Layout.new(self)
|
||||
end
|
||||
|
||||
def object_layout
|
||||
@object_layout
|
||||
self.object_layout = Layout.new(self)
|
||||
end
|
||||
|
||||
def allocate_object
|
||||
@ -31,7 +28,7 @@ module Parfait
|
||||
end
|
||||
|
||||
def add_instance_name name
|
||||
@object_layout.push name
|
||||
self.object_layout.push name
|
||||
end
|
||||
|
||||
def sof_reference_name
|
||||
|
@ -2,35 +2,25 @@
|
||||
|
||||
module Parfait
|
||||
class Dictionary < Object
|
||||
attribute :keys
|
||||
attribute :values
|
||||
# only empty initialization for now
|
||||
#
|
||||
# internally we store keys and values in lists, which means this does **not** scale well
|
||||
def initialize
|
||||
super()
|
||||
@keys = List.new()
|
||||
@values = List.new()
|
||||
end
|
||||
|
||||
# return all values as a list
|
||||
# TODO, list should be copied to avoid inconcisencies
|
||||
def values()
|
||||
@values
|
||||
end
|
||||
|
||||
# return all keys as a list
|
||||
# TODO, list should be copied to avoid inconcisencies
|
||||
def keys()
|
||||
@keys
|
||||
self.keys = List.new()
|
||||
self.values = List.new()
|
||||
end
|
||||
|
||||
# are there any key/value items in the list
|
||||
def empty?
|
||||
@keys.empty?
|
||||
self.keys.empty?
|
||||
end
|
||||
|
||||
# How many key/value pairs there are
|
||||
def length()
|
||||
return @keys.get_length()
|
||||
return self.keys.get_length()
|
||||
end
|
||||
|
||||
# get a value fot the given key
|
||||
@ -39,7 +29,7 @@ module Parfait
|
||||
def get(key)
|
||||
index = key_index(key)
|
||||
if( index )
|
||||
@values.get(index)
|
||||
self.values.get(index)
|
||||
else
|
||||
nil
|
||||
end
|
||||
@ -52,11 +42,11 @@ module Parfait
|
||||
|
||||
# private method
|
||||
def key_index(key)
|
||||
len = @keys.get_length()
|
||||
len = self.keys.get_length()
|
||||
index = 1
|
||||
found = nil
|
||||
while(index <= len)
|
||||
if( @keys.get(index) == key)
|
||||
if( self.keys.get(index) == key)
|
||||
found = index
|
||||
break
|
||||
end
|
||||
@ -69,10 +59,10 @@ module Parfait
|
||||
def set(key , value)
|
||||
index = key_index(key)
|
||||
if( index )
|
||||
@keys.set(index , value)
|
||||
self.keys.set(index , value)
|
||||
else
|
||||
@keys.push(key)
|
||||
@values.push(value)
|
||||
self.keys.push(key)
|
||||
self.values.push(value)
|
||||
end
|
||||
value
|
||||
end
|
||||
@ -85,9 +75,9 @@ module Parfait
|
||||
# yield to each key value pair
|
||||
def each
|
||||
index = 1
|
||||
while index <= @keys.get_length
|
||||
key = @keys.get(index)
|
||||
value = @values.get(index)
|
||||
while index <= self.keys.get_length
|
||||
key = self.keys.get(index)
|
||||
value = self.values.get(index)
|
||||
yield key , value
|
||||
index = index + 1
|
||||
end
|
||||
|
@ -22,10 +22,11 @@
|
||||
|
||||
module Parfait
|
||||
class Layout < List
|
||||
attribute :object_class
|
||||
|
||||
def initialize( object_class )
|
||||
super()
|
||||
@object_class = object_class
|
||||
self.object_class = object_class
|
||||
end
|
||||
|
||||
def == other
|
||||
@ -45,23 +46,30 @@ module Parfait
|
||||
|
||||
# beat the recursion! fixed known offset for class object in the layout
|
||||
def get_object_class()
|
||||
return @object_class
|
||||
return self.object_class
|
||||
end
|
||||
|
||||
def object_instance_names
|
||||
names = List.new
|
||||
index = 1
|
||||
index = 2 # first is object_class
|
||||
while index <= self.get_length
|
||||
item = get(index)
|
||||
names.push item
|
||||
index = index + 1
|
||||
end
|
||||
self
|
||||
|
||||
names
|
||||
end
|
||||
|
||||
# index of a variable name into the layout.
|
||||
# layout is a list, so lowest index is 1
|
||||
# :layout is a variable for every object, so 1 is taken for :layout
|
||||
# still, the index is the same.
|
||||
def variable_index name
|
||||
index_of(name)
|
||||
end
|
||||
|
||||
def sof_reference_name
|
||||
"#{@object_class.name}_Layout"
|
||||
"#{self.object_class.name}_Layout"
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -9,18 +9,19 @@
|
||||
|
||||
module Parfait
|
||||
class Message < Object
|
||||
attributes [:next_message , :frame, :caller]
|
||||
attributes [:receiver , :return_address , :return_value , :name]
|
||||
|
||||
def initialize next_m
|
||||
@next_message = next_m
|
||||
@frame = Frame.new()
|
||||
@caller = nil
|
||||
self.next_message = next_m
|
||||
self.frame = Frame.new()
|
||||
self.caller = nil
|
||||
super()
|
||||
end
|
||||
|
||||
attr_reader :next_message , :frame , :caller # aka prev_message
|
||||
attr_reader :receiver , :return_address , :return_value , :name
|
||||
|
||||
def set_caller caller
|
||||
@caller = caller
|
||||
self.caller = caller
|
||||
end
|
||||
|
||||
def get_type_for(name)
|
||||
|
@ -18,26 +18,26 @@ module Parfait
|
||||
|
||||
def initialize(object)
|
||||
super()
|
||||
@functions = []
|
||||
@me_self = object
|
||||
self.functions = []
|
||||
self.me_self = object
|
||||
end
|
||||
|
||||
# in a non-booting version this should map to _add_singleton_method
|
||||
def add_function function
|
||||
raise "not a function #{function}" unless function.is_a? Virtual::Function
|
||||
raise "syserr " unless function.name.is_a? Symbol
|
||||
@functions << function
|
||||
self.functions << function
|
||||
end
|
||||
|
||||
def get_function name
|
||||
name = name.to_sym
|
||||
f = @functions.detect{ |f| f.name == name }
|
||||
f = self.functions.detect{ |f| f.name == name }
|
||||
return f if f
|
||||
if( @me_self == "Object" )
|
||||
puts "no function for :#{name} in Meta #{@me_self.inspect}"
|
||||
if( self.me_self == "Object" )
|
||||
puts "no function for :#{name} in Meta #{self.me_self.inspect}"
|
||||
return nil
|
||||
else #recurse up class hierachy unless we're at Object
|
||||
return @me_self.context.object_space.get_class_by_name(@me_self.super_class).get_function name
|
||||
return self.me_self.context.object_space.get_class_by_name(self.me_self.super_class).get_function name
|
||||
end
|
||||
end
|
||||
|
||||
@ -52,7 +52,7 @@ module Parfait
|
||||
end
|
||||
|
||||
def to_s
|
||||
"#{inspect} on #{@me_self}, #{@functions.length} functions"
|
||||
"#{inspect} on #{self.me_self}, #{self.functions.length} functions"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -22,14 +22,14 @@ module Parfait
|
||||
def initialize clazz , name , arg_names
|
||||
super()
|
||||
raise "No class #{name}" unless clazz
|
||||
@for_class = clazz
|
||||
@name = name
|
||||
@code = BinaryCode.new name
|
||||
@arg_names = arg_names
|
||||
@locals = List.new
|
||||
@tmps = List.new
|
||||
self.for_class = clazz
|
||||
self.name = name
|
||||
self.code = BinaryCode.new name
|
||||
self.arg_names = arg_names
|
||||
self.locals = List.new
|
||||
self.tmps = List.new
|
||||
end
|
||||
attr_reader :name , :arg_names , :for_class , :code , :locals , :tmps
|
||||
attributes [:name , :arg_names , :for_class , :code , :locals , :tmps]
|
||||
|
||||
|
||||
# determine whether this method has a variable by the given name
|
||||
@ -46,32 +46,32 @@ module Parfait
|
||||
# determine whether this method has an argument by the name
|
||||
def has_arg name
|
||||
raise "uups #{name}.#{name.class}" unless name.is_a? Symbol
|
||||
@arg_names.index_of name
|
||||
self.arg_names.index_of name
|
||||
end
|
||||
|
||||
# determine if method has a local variable or tmp (anonymous local) by given name
|
||||
def has_local name
|
||||
raise "uups #{name}.#{name.class}" unless name.is_a? Symbol
|
||||
index = @locals.index_of(name)
|
||||
index = @tmps.index_of(name) unless index
|
||||
index = self.locals.index_of(name)
|
||||
index = self.tmps.index_of(name) unless index
|
||||
index
|
||||
end
|
||||
|
||||
def ensure_local name
|
||||
index = has_local name
|
||||
return index if index
|
||||
@locals.push name
|
||||
@locals.get_length
|
||||
self.locals.push name
|
||||
self.locals.get_length
|
||||
end
|
||||
|
||||
def get_var name
|
||||
var = has_var name
|
||||
raise "no var #{name} in method #{self.name} , #{@locals} #{@arg_names}" unless var
|
||||
raise "no var #{name} in method #{self.name} , #{self.locals} #{self.arg_names}" unless var
|
||||
var
|
||||
end
|
||||
|
||||
def sof_reference_name
|
||||
@name
|
||||
self.name
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -13,25 +13,23 @@
|
||||
|
||||
module Parfait
|
||||
class Module < Object
|
||||
attribute :name
|
||||
attribute :instance_methods
|
||||
attribute :super_class
|
||||
attribute :meta_class
|
||||
|
||||
def initialize name , superclass
|
||||
super()
|
||||
@name = name
|
||||
@instance_methods = List.new
|
||||
@super_class = superclass
|
||||
@meta_class = nil#MetaClass.new(self)
|
||||
self.name = name
|
||||
self.instance_methods = List.new
|
||||
self.super_class = superclass
|
||||
self.meta_class = nil#MetaClass.new(self)
|
||||
end
|
||||
|
||||
def name
|
||||
@name
|
||||
end
|
||||
|
||||
def instance_methods
|
||||
@instance_methods
|
||||
end
|
||||
|
||||
def method_names
|
||||
names = List.new
|
||||
@instance_methods.each do |method|
|
||||
self.instance_methods.each do |method|
|
||||
names.push method.name
|
||||
end
|
||||
names
|
||||
@ -42,36 +40,36 @@ module Parfait
|
||||
raise "syserr #{method.name.class}" unless method.name.is_a? Symbol
|
||||
found = get_instance_method( method.name )
|
||||
if found
|
||||
@instance_methods.delete(found)
|
||||
self.instance_methods.delete(found)
|
||||
#raise "existed in #{self.name} #{Sof.write found.source.blocks}"
|
||||
end
|
||||
@instance_methods.push method
|
||||
self.instance_methods.push method
|
||||
#puts "#{self.name} add #{method.name}"
|
||||
method
|
||||
end
|
||||
|
||||
def remove_instance_method method
|
||||
@instance_methods.delete method
|
||||
self.instance_methods.delete method
|
||||
end
|
||||
|
||||
def create_instance_method name , arg_names
|
||||
raise "uups #{name}.#{name.class}" unless name.is_a?(Symbol)
|
||||
clazz = Space.object_space.get_class_by_name(self.name)
|
||||
raise "??? #{self.name}" unless clazz
|
||||
Method.new( clazz , name , arg_names )
|
||||
def create_instance_method method_name , arg_names
|
||||
raise "uups #{method_name}.#{method_name.class}" unless method_name.is_a?(Symbol)
|
||||
clazz = get_layout().object_class()
|
||||
raise "??? #{method_name}" unless clazz
|
||||
Method.new( clazz , method_name , arg_names )
|
||||
end
|
||||
|
||||
# this needs to be done during booting as we can't have all the classes and superclassses
|
||||
# instantiated. By that logic it should maybe be part of vm rather.
|
||||
# On the other hand vague plans to load the hierachy from sof exist, so for now...
|
||||
def set_super_class sup
|
||||
@super_class = sup
|
||||
self.super_class = sup
|
||||
end
|
||||
|
||||
def get_instance_method fname
|
||||
raise "uups #{fname}.#{fname.class}" unless fname.is_a?(Symbol)
|
||||
#if we had a hash this would be easier. Detect or find would help too
|
||||
@instance_methods.each do |m|
|
||||
self.instance_methods.each do |m|
|
||||
return m if(m.name == fname )
|
||||
end
|
||||
nil
|
||||
@ -82,8 +80,8 @@ module Parfait
|
||||
raise "uups #{m_name}.#{m_name.class}" unless m_name.is_a?(Symbol)
|
||||
method = get_instance_method(m_name)
|
||||
return method if method
|
||||
if( @super_class )
|
||||
method = @super_class.resolve_method(m_name)
|
||||
if( self.super_class )
|
||||
method = self.super_class.resolve_method(m_name)
|
||||
raise "Method not found #{m_name}, for \n#{self}" unless method
|
||||
end
|
||||
method
|
||||
|
@ -19,11 +19,26 @@ module Parfait
|
||||
|
||||
def self.new *args
|
||||
object = self.allocate
|
||||
#HACK, but used to do the adapter in the init, bu that is too late now
|
||||
object.fake_init if object.respond_to?(:fake_init) # at compile, not run-time
|
||||
# have to grab the class, because we are in the ruby class not the parfait one
|
||||
cl = Space.object_space.get_class_by_name( self.name.split("::").last.to_sym)
|
||||
# and have to set the layout before we let the object do anything. otherwise boom
|
||||
object.set_layout cl.object_layout
|
||||
|
||||
object.send :initialize , *args
|
||||
#puts "NEW #{object.class}"
|
||||
object
|
||||
end
|
||||
|
||||
def self.attributes names
|
||||
names.each{|name| attribute(name) }
|
||||
end
|
||||
|
||||
def self.attribute name
|
||||
define_method(name) { get_instance_variable(name) }
|
||||
define_method("#{name}=".to_sym) { |value| set_instance_variable(name , value) }
|
||||
end
|
||||
|
||||
def == other
|
||||
self.object_id == other.object_id
|
||||
end
|
||||
@ -42,8 +57,8 @@ module Parfait
|
||||
# data that every object carries.
|
||||
def get_class()
|
||||
l = get_layout()
|
||||
puts "Layout #{l.class} in #{self.class} , #{self}"
|
||||
l.get_object_class()
|
||||
#puts "Layout #{l.class} in #{self.class} , #{self}"
|
||||
l.object_class()
|
||||
end
|
||||
|
||||
# private
|
||||
@ -60,6 +75,7 @@ module Parfait
|
||||
|
||||
def get_layout()
|
||||
l = internal_object_get(LAYOUT_INDEX)
|
||||
#puts "get layout for #{self.class} returns #{l.class}"
|
||||
raise "No layout #{self.object_id.to_s(16)}:#{self.class} " unless l
|
||||
return l
|
||||
end
|
||||
@ -70,6 +86,7 @@ module Parfait
|
||||
|
||||
def get_instance_variable name
|
||||
index = instance_variable_defined(name)
|
||||
#puts "getting #{name} at #{index}"
|
||||
return nil if index == nil
|
||||
return internal_object_get(index)
|
||||
end
|
||||
@ -81,7 +98,7 @@ module Parfait
|
||||
end
|
||||
|
||||
def instance_variable_defined name
|
||||
get_layout().index_of(name)
|
||||
get_layout().variable_index(name)
|
||||
end
|
||||
|
||||
def word_length
|
||||
|
@ -22,22 +22,19 @@ module Parfait
|
||||
class Space < Object
|
||||
|
||||
def initialize
|
||||
super()
|
||||
Parfait::Space.set_object_space self
|
||||
@classes = Parfait::Dictionary.new
|
||||
raise "Space can not be instantiated by new, you'd need a space to do so. Chicken and egg"
|
||||
end
|
||||
attr_reader :classes , :first_message
|
||||
attributes [:classes , :first_message]
|
||||
|
||||
# need a two phase init for the object space (and generally parfait) because the space
|
||||
# is an interconnected graph, so not everthing is ready
|
||||
def late_init
|
||||
message = Message.new(nil)
|
||||
5.times do
|
||||
@first_message = Message.new message
|
||||
message.set_caller @first_message
|
||||
message = @first_message
|
||||
self.first_message = Message.new message
|
||||
message.set_caller self.first_message
|
||||
message = self.first_message
|
||||
end
|
||||
init_layout
|
||||
end
|
||||
|
||||
@@object_space = nil
|
||||
@ -64,8 +61,8 @@ module Parfait
|
||||
# return nili if no such class. Use bang version if create should be implicit
|
||||
def get_class_by_name name
|
||||
raise "uups #{name}.#{name.class}" unless name.is_a?(Symbol)
|
||||
c = @classes[name]
|
||||
puts "MISS, no class #{name} #{name.class}" unless c # " #{@classes}"
|
||||
c = self.classes[name]
|
||||
#puts "MISS, no class #{name} #{name.class}" unless c # " #{self.classes}"
|
||||
c
|
||||
end
|
||||
|
||||
@ -82,7 +79,7 @@ module Parfait
|
||||
def create_class name , superclass
|
||||
raise "uups #{name.class}" unless name.is_a? Symbol
|
||||
c = Class.new(name , superclass)
|
||||
@classes[name] = c
|
||||
self.classes[name] = c
|
||||
end
|
||||
|
||||
def sof_reference_name
|
||||
|
@ -18,16 +18,6 @@ require "virtual/passes/get_implementation"
|
||||
require "virtual/passes/enter_implementation"
|
||||
require "virtual/passes/set_optimisation"
|
||||
|
||||
Sof::Volotile.add(Parfait::Object , [:memory])
|
||||
Sof::Volotile.add(Parfait::Method , [:memory])
|
||||
Sof::Volotile.add(Parfait::Class , [:memory])
|
||||
Sof::Volotile.add(Parfait::Layout , [:memory])
|
||||
Sof::Volotile.add(Parfait::Space , [:memory])
|
||||
Sof::Volotile.add(Parfait::Frame , [:memory])
|
||||
Sof::Volotile.add(Parfait::Message , [:memory])
|
||||
Sof::Volotile.add(Parfait::BinaryCode , [:memory])
|
||||
Sof::Volotile.add(Virtual::Block , [:method])
|
||||
Sof::Volotile.add(Virtual::MethodSource , [:current])
|
||||
|
||||
class Fixnum
|
||||
def fits_u8?
|
||||
|
@ -16,78 +16,112 @@ module Virtual
|
||||
#
|
||||
# The way out is to build empty shell objects and stuff the neccessary data into them
|
||||
# (not use the normal initialize way)
|
||||
def boot_parfait!
|
||||
@space = Parfait::Space.new
|
||||
# map from the vm - class_name to the Parfait class (which carries parfait name)
|
||||
class_mappings = {} #will later become instance variable
|
||||
#
|
||||
# There are some helpers below, but the roadmap is something like:
|
||||
# - create all the layouts, with thier layouts, but no classes
|
||||
# - create a space by "hand" , using allocate, not new
|
||||
# - create the class objects and assign them to the layouts
|
||||
def boot_space
|
||||
space_dict = object_with_layout Parfait::Dictionary
|
||||
space_dict.keys = object_with_layout Parfait::List
|
||||
space_dict.values = object_with_layout Parfait::List
|
||||
|
||||
values = [ :Value , :Integer , :Kernel , :Object]
|
||||
value_classes = values.collect { |cl| @space.create_class(cl,nil) }
|
||||
layouts = { :Word => [] ,
|
||||
@space = object_with_layout Parfait::Space
|
||||
@space.classes = space_dict
|
||||
Parfait::Space.set_object_space @space
|
||||
end
|
||||
def boot_layouts
|
||||
@layouts = {}
|
||||
layout_names.each do |name , ivars |
|
||||
@layouts[name] = layout_for( name , ivars)
|
||||
end
|
||||
layout_layout = @layouts[:Layout]
|
||||
@layouts.each do |name , layout |
|
||||
layout.set_layout(layout_layout)
|
||||
end
|
||||
end
|
||||
|
||||
def boot_classes
|
||||
# when running code instantiates a class, a layout is created automatically
|
||||
# but even to get our space up, we have already instantiated all layouts
|
||||
# so we have to continue and allocate classes and fill the data by hand
|
||||
# and off cource we can't use space.create_class , but still they need to go there
|
||||
classes = space.classes
|
||||
layout_names.each do |name , vars|
|
||||
cl = object_with_layout Parfait::Class
|
||||
cl.object_layout = @layouts[name]
|
||||
@layouts[name].object_class = cl
|
||||
cl.instance_methods = object_with_layout Parfait::List
|
||||
# puts "instance_methods is #{cl.instance_methods.class}"
|
||||
cl.name = name
|
||||
classes[name] = cl
|
||||
end
|
||||
object_class = classes[:Object]
|
||||
# superclasses other than default object
|
||||
supers = { :BinaryCode => :Word , :Layout => :List , :Class => :Module ,
|
||||
:Object => :Kernel , :Kernel => :Value, :Integer => :Value }
|
||||
layout_names.each do |classname , ivar|
|
||||
next if classname == :Value # has no superclass
|
||||
clazz = classes[classname]
|
||||
super_name = supers[classname]
|
||||
if super_name
|
||||
clazz.set_super_class classes[super_name]
|
||||
else
|
||||
clazz.set_super_class object_class
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def boot_parfait!
|
||||
boot_layouts
|
||||
boot_space
|
||||
boot_classes
|
||||
|
||||
@space.late_init
|
||||
|
||||
#puts Sof.write(@space)
|
||||
boot_functions!
|
||||
end
|
||||
|
||||
# helper to create a Layout, name is the parfait name, ie :Layout
|
||||
def layout_for( name , ivars )
|
||||
l = Parfait::Layout.allocate.fake_init
|
||||
l.add_instance_variable :layout
|
||||
ivars.each {|n| l.add_instance_variable n }
|
||||
l
|
||||
end
|
||||
|
||||
# create an object with layout (ie allocate it and assign layout)
|
||||
# meaning the lauouts have to be booted, @layouts filled
|
||||
# here we pass the actual (ruby) class
|
||||
def object_with_layout(cl)
|
||||
o = cl.allocate.fake_init
|
||||
name = cl.name.split("::").last.to_sym
|
||||
o.set_layout @layouts[name]
|
||||
o
|
||||
end
|
||||
|
||||
def layout_names
|
||||
{ :Word => [] ,
|
||||
:List => [] ,
|
||||
# Assumtion is that name is the last of message
|
||||
:Message => [:next_message , :receiver , :frame , :return_address , :return_value,
|
||||
:caller , :name ],
|
||||
:MetaClass => [],
|
||||
:Integer => [],
|
||||
:Object => [],
|
||||
:Kernel => [], #fix, kernel is a class, but should be a module
|
||||
:BinaryCode => [],
|
||||
:Space => [:classes , :first_message ],
|
||||
:Frame => [:next_frame ],
|
||||
:Layout => [:object_class] ,
|
||||
:Class => [:object_layout ],
|
||||
# TODO fix layouts for inherited classes. Currently only :Class and the
|
||||
# instances are copied (shame on you)
|
||||
:Class => [:object_layout , :name , :instance_methods , :super_class , :meta_class],
|
||||
:Dictionary => [:keys , :values ] ,
|
||||
:Method => [:name , :code ,:arg_names , :locals , :tmps ] ,
|
||||
:Method => [:name , :code ,:arg_names , :for_class, :locals , :tmps ] ,
|
||||
:Module => [:name , :instance_methods , :super_class , :meta_class ]
|
||||
}
|
||||
layouts.each do |name , layout|
|
||||
class_mappings[name] = @space.create_class(name , nil)
|
||||
end
|
||||
value_classes[1].set_super_class( value_classes[0] ) # #set superclass (value) for integer
|
||||
value_classes[2].set_super_class( value_classes[0] ) # and kernel (TODO is module)
|
||||
value_classes[3].set_super_class( value_classes[2] ) # and object (TODO hacked to kernel)
|
||||
class_mappings.each do |name , clazz| # and the rest
|
||||
clazz.set_super_class(value_classes[3]) # superclasses are object
|
||||
end
|
||||
# next create layouts by adding instance variable names to the layouts
|
||||
class_mappings.each do |name , clazz|
|
||||
variables = layouts[name]
|
||||
variables.each do |var_name|
|
||||
clazz.object_layout.add_instance_variable var_name
|
||||
end
|
||||
end
|
||||
# superclass and layout corrections
|
||||
supers = { :BinaryCode => :Word , :Layout => :List , :Class => :Module }
|
||||
supers.each do |classname , superclass_name|
|
||||
clazz = class_mappings[classname]
|
||||
super_class = class_mappings[superclass_name]
|
||||
# set_super_class has no sideeffects, so setting twice ok
|
||||
clazz.set_super_class super_class
|
||||
# Add superclass layout too
|
||||
super_class.object_layout.each do |var|
|
||||
clazz.object_layout.add_instance_variable var
|
||||
end
|
||||
end
|
||||
|
||||
# now store the classes so we can hand them out later during object creation
|
||||
# this can not be done earlier, as parfait objects are all the time created and would
|
||||
# lookup half created class info
|
||||
# but it must be done before going through the objects (next step)
|
||||
@class_mappings = class_mappings
|
||||
class_mappings[:Integer ] = value_classes[1] #need for further booting
|
||||
class_mappings[:Kernel ] = value_classes[2] #need for further booting
|
||||
class_mappings[:Object ] = value_classes[3] #need for further booting
|
||||
|
||||
@space.late_init
|
||||
|
||||
# add_object @space
|
||||
|
||||
class_mappings.values.each {|v| v.init_layout }
|
||||
|
||||
# now update the layout on all objects created so far,
|
||||
# go through objects in space
|
||||
@objects.each do | o |
|
||||
o.init_layout
|
||||
end
|
||||
boot_functions!
|
||||
end
|
||||
|
||||
# classes have booted, now create a minimal set of functions
|
||||
@ -99,19 +133,19 @@ module Virtual
|
||||
# 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
|
||||
# TODO go through the virtual parfait layer and adjust function names to what they really are
|
||||
obj = @class_mappings[:Object ]
|
||||
obj = @space.get_class_by_name(:Object)
|
||||
[:main , :_get_instance_variable , :_set_instance_variable].each do |f|
|
||||
obj.add_instance_method Register::Builtin::Object.send(f , nil)
|
||||
end
|
||||
obj = @class_mappings[:Kernel ]
|
||||
obj = @space.get_class_by_name(:Kernel)
|
||||
# create dummy main first, __init__ calls it
|
||||
[:exit,:__send , :__init__ ].each do |f|
|
||||
obj.add_instance_method Register::Builtin::Kernel.send(f , nil)
|
||||
end
|
||||
|
||||
@class_mappings[:Word].add_instance_method Register::Builtin::Word.send(:putstring , nil)
|
||||
@space.get_class_by_name(:Word).add_instance_method Register::Builtin::Word.send(:putstring , nil)
|
||||
|
||||
obj = @class_mappings[:Integer ]
|
||||
obj = @space.get_class_by_name(:Integer)
|
||||
[:putint,:fibo].each do |f|
|
||||
obj.add_instance_method Register::Builtin::Integer.send(f , nil)
|
||||
end
|
||||
|
@ -42,7 +42,7 @@ module Virtual
|
||||
def initialize
|
||||
@parser = Parser::Salama.new
|
||||
@passes = [ FIRST_PASS ]
|
||||
@objects = []
|
||||
@objects = {}
|
||||
@booted = false
|
||||
end
|
||||
attr_reader :passes , :space , :class_mappings , :init , :objects , :booted
|
||||
@ -92,8 +92,8 @@ module Virtual
|
||||
|
||||
# Objects are data and get assembled after functions
|
||||
def add_object o
|
||||
return false if @objects.include?(o)
|
||||
@objects.push o
|
||||
return false if @objects[o.object_id]
|
||||
@objects[o.object_id] = o
|
||||
true
|
||||
end
|
||||
|
||||
|
@ -4,25 +4,6 @@
|
||||
# To stay sane, we use the same classes that we use later, but "adapt" them to work in ruby
|
||||
# This affects mainly memory layout
|
||||
|
||||
module FakeMem
|
||||
def initialize
|
||||
super()
|
||||
@memory = [0,nil]
|
||||
@position = nil
|
||||
if Virtual.machine.class_mappings
|
||||
init_layout
|
||||
else
|
||||
#puts "No init for #{self.class}:#{self.object_id}"
|
||||
end
|
||||
end
|
||||
def init_layout
|
||||
vm_name = self.class.name.split("::").last.to_sym
|
||||
clazz = Virtual.machine.class_mappings[vm_name]
|
||||
raise "Class not found #{vm_name}" unless clazz
|
||||
raise "Layout not set #{vm_name}" unless clazz.object_layout
|
||||
self.set_layout clazz.object_layout
|
||||
end
|
||||
end
|
||||
module Virtual
|
||||
def self.new_list array
|
||||
list = Parfait::List.new
|
||||
@ -39,12 +20,13 @@ class Symbol
|
||||
include Positioned
|
||||
include Padding
|
||||
|
||||
def init_layout; end
|
||||
def has_layout?
|
||||
true
|
||||
end
|
||||
def get_layout
|
||||
Virtual.machine.class_mappings[:Word].object_layout
|
||||
l = Virtual.machine.space.classes[:Word].object_layout
|
||||
puts "LL #{l.class}"
|
||||
l
|
||||
end
|
||||
def word_length
|
||||
padded to_s.length
|
||||
@ -82,10 +64,15 @@ module Parfait
|
||||
# but we implement it with ruby array (0 based) and use 0 as type-word
|
||||
# These are the same functions that Builtin implements at run-time
|
||||
class Object
|
||||
include FakeMem
|
||||
include Padding
|
||||
include Positioned
|
||||
|
||||
def fake_init
|
||||
@memory = [0,nil]
|
||||
@position = nil
|
||||
self # for chaining
|
||||
end
|
||||
|
||||
# these internal functions are _really_ internal
|
||||
# they respresent the smallest code needed to build larger functionality
|
||||
# but should _never_ be used outside parfait. in fact that should be impossible
|
||||
@ -108,10 +95,6 @@ module Parfait
|
||||
# 1 -based index
|
||||
def internal_object_set(index , value)
|
||||
raise "failed init for #{self.class}" unless @memory
|
||||
#shaddowing layout so we can ignore memory in Sof
|
||||
if(index == LAYOUT_INDEX)
|
||||
@layout = value
|
||||
end
|
||||
@memory[index] = value
|
||||
end
|
||||
def internal_object_grow(length)
|
||||
@ -174,4 +157,20 @@ module Parfait
|
||||
string
|
||||
end
|
||||
end
|
||||
|
||||
## sof related stuff
|
||||
class Object
|
||||
# parfait versions are deliberately called different, so we "relay"
|
||||
# have to put the "@" on the names for sof to take them off again
|
||||
def instance_variables
|
||||
get_instance_variables.to_a.collect{ |n| "@#{n}".to_sym }
|
||||
end
|
||||
# name comes in as a ruby @var name
|
||||
def instance_variable_get name
|
||||
var = get_instance_variable name.to_s[1 .. -1].to_sym
|
||||
puts "getting #{name} #{var}"
|
||||
var
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -11,6 +11,7 @@ module Virtual
|
||||
return if object.nil?
|
||||
return unless Virtual.machine.add_object object
|
||||
#puts "adding #{object.class}"
|
||||
return unless object.respond_to? :has_layout?
|
||||
unless object.has_layout?
|
||||
object.init_layout
|
||||
end
|
||||
@ -19,8 +20,8 @@ module Virtual
|
||||
end
|
||||
layout = object.get_layout
|
||||
keep layout
|
||||
#puts "Layout #{layout.get_object_class.name} #{Machine.instance.objects.include?(layout)}"
|
||||
layout.each do |name|
|
||||
#puts "Layout #{layout.object_class.name} #{Machine.instance.objects.include?(layout)}"
|
||||
layout.object_instance_names.each do |name|
|
||||
inst = object.instance_variable_get "@#{name}".to_sym
|
||||
keep inst
|
||||
end
|
||||
|
@ -30,7 +30,7 @@ HERE
|
||||
check
|
||||
end
|
||||
|
||||
def test_string_put
|
||||
def ttest_string_put
|
||||
@string_input = <<HERE
|
||||
"Hello again\n".putstring()
|
||||
HERE
|
||||
|
@ -1,6 +1,7 @@
|
||||
require_relative "../helper"
|
||||
|
||||
class TestDictionary < MiniTest::Test
|
||||
Virtual.machine.boot #have to book, otherwise layouts etc not set
|
||||
|
||||
def setup
|
||||
@lookup = ::Parfait::Dictionary.new
|
||||
|
Loading…
Reference in New Issue
Block a user