2015-05-19 19:29:33 +02:00
|
|
|
module Virtual
|
|
|
|
|
2015-05-24 12:31:33 +02:00
|
|
|
# Booting is a complicated, so it is extracted into this file, even it has only one entry point
|
|
|
|
|
2015-05-19 19:29:33 +02:00
|
|
|
class Machine
|
|
|
|
|
|
|
|
# The general idea is that compiling is creating an object graph. Functionally
|
|
|
|
# one tends to think of methods, and that is complicated enough, sure.
|
2015-07-28 15:18:32 +02:00
|
|
|
# But for an object system the graph includes classes and all instance variables
|
2015-05-19 19:29:33 +02:00
|
|
|
#
|
2015-07-28 15:18:32 +02:00
|
|
|
# And so we have a chicken and egg problem. At the end of the boot function we want to have a
|
2015-05-19 19:29:33 +02:00
|
|
|
# working Space object
|
|
|
|
# But that has instance variables (List and Dictionary) and off course a class.
|
|
|
|
# Or more precisely in salama, a Layout, that points to a class.
|
|
|
|
# So we need a Layout, but that has Layout and Class too. hmmm
|
|
|
|
#
|
|
|
|
# The way out is to build empty shell objects and stuff the neccessary data into them
|
|
|
|
# (not use the normal initialize way)
|
2015-07-28 15:18:32 +02:00
|
|
|
# (PPS: The "real" solution is to read a sof graph and not do this by hand
|
|
|
|
# That graph can be programatically built and written (with this to boot that process :-))
|
|
|
|
|
2015-07-21 14:40:25 +02:00
|
|
|
# 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
|
2015-07-28 15:18:32 +02:00
|
|
|
def boot_parfait!
|
|
|
|
boot_layouts
|
|
|
|
boot_space
|
|
|
|
boot_classes
|
2015-05-19 19:29:33 +02:00
|
|
|
|
2015-07-28 15:18:32 +02:00
|
|
|
@space.late_init
|
|
|
|
|
|
|
|
#puts Sof.write(@space)
|
|
|
|
boot_functions!
|
2015-07-21 14:40:25 +02:00
|
|
|
end
|
2015-07-28 15:18:32 +02:00
|
|
|
|
|
|
|
# layouts is where the snake bites its tail. Every chain end at a layout and then it
|
|
|
|
# goes around (circular references). We create them from the list below and keep them
|
|
|
|
# in an instance variable (that is a smell, because after booting it is not needed)
|
2015-07-21 14:40:25 +02:00
|
|
|
def boot_layouts
|
|
|
|
@layouts = {}
|
|
|
|
layout_names.each do |name , ivars |
|
|
|
|
@layouts[name] = layout_for( name , ivars)
|
2015-05-23 11:15:06 +02:00
|
|
|
end
|
2015-07-21 14:40:25 +02:00
|
|
|
layout_layout = @layouts[:Layout]
|
|
|
|
@layouts.each do |name , layout |
|
|
|
|
layout.set_layout(layout_layout)
|
2015-05-19 19:29:33 +02:00
|
|
|
end
|
2015-07-21 14:40:25 +02:00
|
|
|
end
|
|
|
|
|
2015-07-28 15:18:32 +02:00
|
|
|
# once we have the layouts we can create the space by creating the instance variables
|
|
|
|
# by hand (can't call new yet as that uses the space)
|
|
|
|
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
|
|
|
|
|
|
|
|
@space = object_with_layout Parfait::Space
|
|
|
|
@space.classes = space_dict
|
|
|
|
Parfait::Space.set_object_space @space
|
|
|
|
end
|
|
|
|
|
|
|
|
# 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
|
2015-07-21 14:40:25 +02:00
|
|
|
def boot_classes
|
|
|
|
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
|
2015-05-22 21:51:36 +02:00
|
|
|
end
|
2015-07-21 14:40:25 +02:00
|
|
|
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
|
2015-05-31 13:45:28 +02:00
|
|
|
end
|
|
|
|
end
|
2015-07-21 14:40:25 +02:00
|
|
|
end
|
2015-05-30 10:55:46 +02:00
|
|
|
|
2015-07-21 14:40:25 +02:00
|
|
|
# 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
|
2015-05-31 12:02:29 +02:00
|
|
|
|
2015-07-21 14:40:25 +02:00
|
|
|
# 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
|
|
|
|
|
2015-07-28 15:18:32 +02:00
|
|
|
# the function really just returns a constant (just avoiding the constant)
|
|
|
|
# unfortuantely that constant condenses every detail about the system, class names
|
|
|
|
# and all instance variable names. Really have to find a better way
|
2015-07-21 14:40:25 +02:00
|
|
|
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] ,
|
|
|
|
# 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 , :for_class, :locals , :tmps ] ,
|
|
|
|
:Module => [:name , :instance_methods , :super_class , :meta_class ]
|
|
|
|
}
|
2015-05-19 19:29:33 +02:00
|
|
|
end
|
|
|
|
|
2015-05-24 12:31:33 +02:00
|
|
|
# classes have booted, now create a minimal set of functions
|
2015-05-19 19:29:33 +02:00
|
|
|
# minimal means only that which can not be coded in ruby
|
2015-05-24 12:31:33 +02:00
|
|
|
# Methods are grabbed from respective modules by sending the method name. This should return the
|
|
|
|
# implementation of the method (ie a method object), not actually try to implement it
|
|
|
|
# (as that's impossible in ruby)
|
2015-05-19 19:29:33 +02:00
|
|
|
def boot_functions!
|
|
|
|
# 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
|
2015-05-31 17:34:18 +02:00
|
|
|
# TODO go through the virtual parfait layer and adjust function names to what they really are
|
2015-07-21 14:40:25 +02:00
|
|
|
obj = @space.get_class_by_name(:Object)
|
2015-05-30 13:49:10 +02:00
|
|
|
[:main , :_get_instance_variable , :_set_instance_variable].each do |f|
|
2015-06-29 20:03:58 +02:00
|
|
|
obj.add_instance_method Register::Builtin::Object.send(f , nil)
|
2015-05-19 19:29:33 +02:00
|
|
|
end
|
2015-07-21 14:40:25 +02:00
|
|
|
obj = @space.get_class_by_name(:Kernel)
|
2015-07-28 15:18:32 +02:00
|
|
|
# create __init__ main first, __init__ calls it
|
2015-07-01 20:45:41 +02:00
|
|
|
[:exit,:__send , :__init__ ].each do |f|
|
2015-06-29 20:03:58 +02:00
|
|
|
obj.add_instance_method Register::Builtin::Kernel.send(f , nil)
|
2015-05-19 19:29:33 +02:00
|
|
|
end
|
2015-05-26 19:17:03 +02:00
|
|
|
|
2015-07-21 14:40:25 +02:00
|
|
|
@space.get_class_by_name(:Word).add_instance_method Register::Builtin::Word.send(:putstring , nil)
|
2015-07-01 20:45:41 +02:00
|
|
|
|
2015-07-21 14:40:25 +02:00
|
|
|
obj = @space.get_class_by_name(:Integer)
|
2015-08-04 21:01:20 +02:00
|
|
|
[:putint,:fibo , :plus].each do |f|
|
2015-06-29 20:03:58 +02:00
|
|
|
obj.add_instance_method Register::Builtin::Integer.send(f , nil)
|
2015-05-19 19:29:33 +02:00
|
|
|
end
|
2015-08-04 21:01:20 +02:00
|
|
|
# obj.alias :plus , :+
|
2015-05-26 19:17:03 +02:00
|
|
|
|
2015-05-19 19:29:33 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|