fold last of the virtual into register
This commit is contained in:
@ -106,7 +106,7 @@ module Interpreter
|
||||
|
||||
def object_for reg
|
||||
id = get_register(reg)
|
||||
object = Virtual.machine.objects[id]
|
||||
object = Register.machine.objects[id]
|
||||
object.nil? ? id : object
|
||||
end
|
||||
|
||||
|
@ -24,7 +24,7 @@ module Parfait
|
||||
|
||||
# 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 "not a function #{function}" unless function.is_a? Register::Function
|
||||
# raise "syserr " unless function.name.is_a? Symbol
|
||||
# self.functions << function
|
||||
# end
|
||||
|
@ -13,7 +13,7 @@ module Parfait
|
||||
# known local variable names
|
||||
# executable code
|
||||
|
||||
# ps, the compiler injects its own info, see Virtual::MethodSource
|
||||
# ps, the compiler injects its own info, see Register::MethodSource
|
||||
|
||||
|
||||
class Method < Object
|
||||
|
@ -2,7 +2,7 @@ module Parfait
|
||||
class Variable < Object
|
||||
|
||||
def initialize type , name , value = nil
|
||||
raise "not type #{type}" unless Virtual.machine.space.get_class_by_name(type)
|
||||
raise "not type #{type}" unless Register.machine.space.get_class_by_name(type)
|
||||
self.type , self.name , self.value = type , name , value
|
||||
self.value = 0 if self.type == :Integer and value == nil
|
||||
raise "must give name for variable" unless name
|
||||
|
@ -16,7 +16,7 @@ module Parfait
|
||||
class Word < Object
|
||||
# initialize with length. For now we try to keep all non-parfait (including String) out
|
||||
# String will contain spaces for non-zero length
|
||||
# Virtual provides methods to create Parfait objects from ruby
|
||||
# Register provides methods to create Parfait objects from ruby
|
||||
def initialize len
|
||||
super()
|
||||
raise "Must init with int, not #{len.class}" unless len.kind_of? Fixnum
|
||||
|
@ -34,10 +34,10 @@ module Phisol
|
||||
end
|
||||
|
||||
# now we have to resolve the method name (+ receiver) into a callable method
|
||||
clazz = Virtual.machine.space.get_class_by_name(me.type)
|
||||
clazz = Register.machine.space.get_class_by_name(me.type)
|
||||
raise "No such class #{me.type}" unless clazz
|
||||
method = clazz.get_instance_method(name)
|
||||
#puts Virtual.machine.space.get_class_by_name(:Integer).method_names.to_a
|
||||
#puts Register.machine.space.get_class_by_name(:Integer).method_names.to_a
|
||||
raise "Method not implemented #{me.type}.#{name}" unless method
|
||||
Register.issue_call( @method , method )
|
||||
ret = use_reg( method.source.return_type )
|
||||
|
@ -19,7 +19,7 @@ module Phisol
|
||||
if( r != :self)
|
||||
raise "unimplemented case in function #{r}"
|
||||
else
|
||||
r = Virtual::Self.new()
|
||||
r = Register::Self.new()
|
||||
class_name = method.for_class.name
|
||||
end
|
||||
end
|
||||
@ -34,7 +34,7 @@ module Phisol
|
||||
#TODO check args / type compatibility
|
||||
@method.source.init @method
|
||||
else
|
||||
@method = Virtual::MethodSource.create_method(class_name, return_type, name , args )
|
||||
@method = Register::MethodSource.create_method(class_name, return_type, name , args )
|
||||
@method.for_class.add_instance_method @method
|
||||
end
|
||||
@method.source.receiver = r
|
||||
|
20
lib/register.rb
Normal file
20
lib/register.rb
Normal file
@ -0,0 +1,20 @@
|
||||
require "parfait"
|
||||
require "register/machine"
|
||||
#if we are in the ruby run-time / generating an executable
|
||||
require "register/positioned"
|
||||
require "register/padding"
|
||||
require "register/parfait_adapter"
|
||||
|
||||
require "phisol/compiler"
|
||||
require "register/method_source"
|
||||
|
||||
|
||||
class Fixnum
|
||||
def fits_u8?
|
||||
self >= 0 and self <= 255
|
||||
end
|
||||
end
|
||||
|
||||
require "register/instruction"
|
||||
require "register/register_value"
|
||||
require "register/assembler"
|
@ -238,5 +238,5 @@ module Register
|
||||
end
|
||||
end
|
||||
|
||||
Sof::Volotile.add(Register::Assembler , [:objects])
|
||||
Sof::Volotile.add(Assembler , [:objects])
|
||||
end
|
||||
|
@ -1,4 +1,4 @@
|
||||
module Virtual
|
||||
module Register
|
||||
|
||||
# Think flowcharts: blocks are the boxes. The smallest unit of linear code
|
||||
|
@ -1,4 +1,4 @@
|
||||
module Virtual
|
||||
module Register
|
||||
|
||||
# Booting is a complicated, so it is extracted into this file, even it has only one entry point
|
||||
|
||||
@ -147,19 +147,19 @@ module Virtual
|
||||
# TODO go through the virtual parfait layer and adjust function names to what they really are
|
||||
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)
|
||||
obj.add_instance_method Builtin::Object.send(f , nil)
|
||||
end
|
||||
obj = @space.get_class_by_name(:Kernel)
|
||||
# create __init__ main first, __init__ calls it
|
||||
[:exit,:__send , :__init__ ].each do |f|
|
||||
obj.add_instance_method Register::Builtin::Kernel.send(f , nil)
|
||||
obj.add_instance_method Builtin::Kernel.send(f , nil)
|
||||
end
|
||||
|
||||
@space.get_class_by_name(:Word).add_instance_method Register::Builtin::Word.send(:putstring , nil)
|
||||
@space.get_class_by_name(:Word).add_instance_method Builtin::Word.send(:putstring , nil)
|
||||
|
||||
obj = @space.get_class_by_name(:Integer)
|
||||
[:putint,:fibo , :plus].each do |f|
|
||||
obj.add_instance_method Register::Builtin::Integer.send(f , nil)
|
||||
obj.add_instance_method Builtin::Integer.send(f , nil)
|
||||
end
|
||||
end
|
||||
end
|
@ -4,9 +4,9 @@ The Builtin module contains functions that can not be coded in ruby.
|
||||
It is the other side of the parfait coin, part of the runtime.
|
||||
|
||||
The functions are organized by their respective class and get loaded in boot_classes! ,
|
||||
right at the start. (see virtual/boot.rb)
|
||||
right at the start. (see register/boot.rb)
|
||||
|
||||
These functions return their code, ie a Parfait::Method with a Virtual::MethodSource object,
|
||||
These functions return their code, ie a Parfait::Method with a MethodSource object,
|
||||
which can then be called by ruby code as if it were a "normal" function.
|
||||
|
||||
A normal ruby function is one that is parsed and transformed to code. But not all functionality can
|
||||
|
@ -5,7 +5,7 @@ module Register
|
||||
module ClassMethods
|
||||
include AST::Sexp
|
||||
def plus c
|
||||
plus_function = Virtual::MethodSource.create_method(:Integer,:Integer,:plus , [:Integer] )
|
||||
plus_function = MethodSource.create_method(:Integer,:Integer,:plus , [:Integer] )
|
||||
plus_function.source.set_return_type :Integer
|
||||
plus_function.source.receiver = :Integer
|
||||
|
||||
@ -15,7 +15,7 @@ module Register
|
||||
|
||||
me = Register.tmp_reg :Integer
|
||||
plus_function.source.add_code Register.get_slot(plus_function , :message , :receiver , me )
|
||||
add = Register::OperatorInstruction.new( plus_function, :add , me , tmp )
|
||||
add = OperatorInstruction.new( plus_function, :add , me , tmp )
|
||||
plus_function.source.add_code add
|
||||
plus_function.source.add_code Register.set_slot(plus_function , me , :message , :return_value )
|
||||
return plus_function
|
||||
@ -28,14 +28,14 @@ module Register
|
||||
# As we write before we recurse (save a push) we write the number backwards
|
||||
# arguments: string address , integer
|
||||
# def utoa context
|
||||
# utoa_function = Virtual::MethodSource.create_method(:Integer ,:utoa , [ :Integer ] )
|
||||
# utoa_function = MethodSource.create_method(:Integer ,:utoa , [ :Integer ] )
|
||||
# function.source.return_type = :Integer
|
||||
# function.source.receiver = :Integer
|
||||
# return utoa_function
|
||||
# # str_addr = utoa_function.receiver
|
||||
# # number = utoa_function.args.first
|
||||
# # remainder = utoa_function.new_local
|
||||
# # Virtual::RegisterMachine.instance.div10( utoa_function , number , remainder )
|
||||
# # RegisterMachine.instance.div10( utoa_function , number , remainder )
|
||||
# # # make char out of digit (by using ascii encoding) 48 == "0"
|
||||
# # utoa_function.instance_eval do
|
||||
# # add( remainder , remainder , 48)
|
||||
@ -48,7 +48,7 @@ module Register
|
||||
# end
|
||||
|
||||
def putint context
|
||||
putint_function = Virtual::MethodSource.create_method(:Integer,:Integer,:putint , [] )
|
||||
putint_function = MethodSource.create_method(:Integer,:Integer,:putint , [] )
|
||||
putint_function.source.set_return_type :Integer
|
||||
putint_function.source.receiver = :Integer
|
||||
return putint_function
|
||||
@ -68,7 +68,7 @@ module Register
|
||||
# add( int , buffer , nil ) # string to write to
|
||||
# mov( moved_int , buffer.length )
|
||||
# end
|
||||
# Virtual::RegisterMachine.instance.write_stdout(putint_function)
|
||||
# RegisterMachine.instance.write_stdout(putint_function)
|
||||
# putint_function
|
||||
end
|
||||
|
||||
@ -77,7 +77,7 @@ module Register
|
||||
# a hand coded version of the fibonachi numbers
|
||||
# not my hand off course, found in the net http://www.peter-cockerell.net/aalp/html/ch-5.html
|
||||
def fibo context
|
||||
fibo_function = Virtual::MethodSource.create_method(:Integer,:Integer,:fibo , [] )
|
||||
fibo_function = MethodSource.create_method(:Integer,:Integer,:fibo , [] )
|
||||
fibo_function.source.set_return_type :Integer
|
||||
fibo_function.source.receiver = :Integer
|
||||
return fibo_function
|
||||
|
@ -6,7 +6,7 @@ module Register
|
||||
# it isn't really a function, ie it is jumped to (not called), exits and may not return
|
||||
# so it is responsible for initial setup
|
||||
def __init__ context
|
||||
function = Virtual::MethodSource.create_method(:Kernel,:Integer,:__init__ , [])
|
||||
function = MethodSource.create_method(:Kernel,:Integer,:__init__ , [])
|
||||
function.source.set_return_type :Integer
|
||||
# no method enter or return (automatically added), remove
|
||||
function.source.blocks.first.codes.pop # no Method enter
|
||||
@ -21,20 +21,20 @@ module Register
|
||||
# And store the space as the new self (so the call can move it back as self)
|
||||
function.source.add_code Register.set_slot( function, space_reg , :new_message , :receiver)
|
||||
# now we are set up to issue a call to the main
|
||||
Register.issue_call( function , Virtual.machine.space.get_main)
|
||||
Register.issue_call( function , Register.machine.space.get_main)
|
||||
emit_syscall( function , :exit )
|
||||
return function
|
||||
end
|
||||
def exit context
|
||||
function = Virtual::MethodSource.create_method(:Kernel,:Integer,:exit , [])
|
||||
function = MethodSource.create_method(:Kernel,:Integer,:exit , [])
|
||||
function.source.set_return_type :Integer
|
||||
return function
|
||||
ret = Virtual::RegisterMachine.instance.exit(function)
|
||||
ret = RegisterMachine.instance.exit(function)
|
||||
function.set_return ret
|
||||
function
|
||||
end
|
||||
def __send context
|
||||
function = Virtual::MethodSource.create_method(:Kernel,:Integer ,:__send , [] )
|
||||
function = MethodSource.create_method(:Kernel,:Integer ,:__send , [] )
|
||||
function.source.set_return_type :Integer
|
||||
return function
|
||||
end
|
||||
|
@ -6,7 +6,7 @@ module Register
|
||||
# main entry point, ie __init__ calls this
|
||||
# defined here as empty, to be redefined
|
||||
def main context
|
||||
function = Virtual::MethodSource.create_method(:Object, :Integer , :main , [])
|
||||
function = MethodSource.create_method(:Object, :Integer , :main , [])
|
||||
return function
|
||||
end
|
||||
|
||||
@ -18,13 +18,13 @@ module Register
|
||||
# The at_index is just "below" the api, something we need but don't want to expose,
|
||||
# so we can't code the above in ruby
|
||||
def _get_instance_variable context , name = :Integer
|
||||
get_function = Virtual::MethodSource.create_method(:Object,:Integer, :_get_instance_variable , [ ] )
|
||||
get_function = MethodSource.create_method(:Object,:Integer, :_get_instance_variable , [ ] )
|
||||
return get_function
|
||||
# me = get_function.receiver
|
||||
# var_name = get_function.args.first
|
||||
# return_to = get_function.return_type
|
||||
#
|
||||
# index_function = ::Virtual.machine.space.get_class_by_name(:Object).resolve_method(:index_of)
|
||||
# index_function = ::Register.machine.space.get_class_by_name(:Object).resolve_method(:index_of)
|
||||
# # get_function.push( [me] )
|
||||
# # index = get_function.call( index_function )
|
||||
#
|
||||
@ -39,7 +39,7 @@ module Register
|
||||
end
|
||||
|
||||
def _set_instance_variable(context , name = :Integer , value = :Integer )
|
||||
set_function = Virtual::MethodSource.create_method(:Object,:Integer,:_set_instance_variable ,[] )
|
||||
set_function = MethodSource.create_method(:Object,:Integer,:_set_instance_variable ,[] )
|
||||
return set_function
|
||||
# receiver set_function
|
||||
# me = set_function.receiver
|
||||
|
@ -3,7 +3,7 @@ module Register
|
||||
module Word
|
||||
module ClassMethods
|
||||
def putstring context
|
||||
function = Virtual::MethodSource.create_method(:Word,:Integer , :putstring , [] )
|
||||
function = MethodSource.create_method(:Word,:Integer , :putstring , [] )
|
||||
function.source.add_code Register.get_slot( function , :message , :receiver , :new_message )
|
||||
Kernel.emit_syscall( function , :putstring )
|
||||
function
|
||||
|
@ -1,4 +1,4 @@
|
||||
module Virtual
|
||||
module Register
|
||||
|
||||
# collect anything that is in the space but and reachable from init
|
||||
module Collector
|
@ -24,8 +24,8 @@ module Register
|
||||
@index = index
|
||||
@register = register
|
||||
raise "not integer #{index}" unless index.is_a? Numeric
|
||||
raise "Not register #{register}" unless Register::RegisterValue.look_like_reg(register)
|
||||
raise "Not register #{array}" unless Register::RegisterValue.look_like_reg(array)
|
||||
raise "Not register #{register}" unless RegisterValue.look_like_reg(register)
|
||||
raise "Not register #{array}" unless RegisterValue.look_like_reg(array)
|
||||
end
|
||||
attr_accessor :array , :index , :register
|
||||
|
||||
|
@ -23,8 +23,8 @@ module Register
|
||||
@array = array
|
||||
@index = index
|
||||
raise "not integer #{index}" unless index.is_a? Numeric
|
||||
raise "Not register #{register}" unless Register::RegisterValue.look_like_reg(register)
|
||||
raise "Not register #{array}" unless Register::RegisterValue.look_like_reg(array)
|
||||
raise "Not register #{register}" unless RegisterValue.look_like_reg(register)
|
||||
raise "Not register #{array}" unless RegisterValue.look_like_reg(array)
|
||||
end
|
||||
attr_accessor :register , :array , :index
|
||||
def to_s
|
||||
|
@ -1,7 +1,7 @@
|
||||
require 'parslet/convenience'
|
||||
require_relative "collector"
|
||||
module Virtual
|
||||
# The Virtual Machine is a object based virtual machine in which ruby is implemented.
|
||||
module Register
|
||||
# The Register Machine is a object based virtual machine in which ruby is implemented.
|
||||
#
|
||||
# It is minimal and realistic and low level
|
||||
# - minimal means that if one thing can be implemented by another, it is left out. This is quite
|
||||
@ -118,7 +118,7 @@ module Virtual
|
||||
def boot
|
||||
boot_parfait!
|
||||
@init = Block.new("init", :__init__ )
|
||||
branch = Register::Branch.new( "__init__" , self.space.get_init.source.blocks.first )
|
||||
branch = Branch.new( "__init__" , self.space.get_init.source.blocks.first )
|
||||
@init.add_code branch
|
||||
@booted = true
|
||||
self
|
@ -1,6 +1,6 @@
|
||||
require_relative "block"
|
||||
|
||||
module Virtual
|
||||
module Register
|
||||
# the static info of a method (with its compiled code, argument names etc ) is part of the
|
||||
# runtime, ie found in Parfait::Method
|
||||
|
||||
@ -35,17 +35,17 @@ module Virtual
|
||||
def self.create_method( class_name , return_type , method_name , args)
|
||||
raise "create_method #{class_name}.#{class_name.class}" unless class_name.is_a? Symbol
|
||||
raise "create_method #{method_name}.#{method_name.class}" unless method_name.is_a? Symbol
|
||||
clazz = Virtual.machine.space.get_class_by_name class_name
|
||||
clazz = Register.machine.space.get_class_by_name class_name
|
||||
raise "No such class #{class_name}" unless clazz
|
||||
arguments = []
|
||||
args.each_with_index do | arg , index |
|
||||
unless arg.is_a? Parfait::Variable
|
||||
raise "not type #{arg}:#{arg.class}" unless Virtual.machine.space.get_class_by_name arg
|
||||
raise "not type #{arg}:#{arg.class}" unless Register.machine.space.get_class_by_name arg
|
||||
arg = Parfait::Variable.new arg , "arg#{index}".to_sym
|
||||
end
|
||||
arguments << arg
|
||||
end
|
||||
method = clazz.create_instance_method( method_name , Virtual.new_list(arguments))
|
||||
method = clazz.create_instance_method( method_name , Register.new_list(arguments))
|
||||
method.source = MethodSource.new(method , return_type)
|
||||
method
|
||||
end
|
||||
@ -63,11 +63,11 @@ module Virtual
|
||||
@current = enter
|
||||
ret = new_block("return")
|
||||
# move the current message to new_message
|
||||
ret.add_code Register::RegisterTransfer.new(self, Register.message_reg , Register.new_message_reg )
|
||||
ret.add_code RegisterTransfer.new(self, Register.message_reg , Register.new_message_reg )
|
||||
# and restore the message from saved value in new_message
|
||||
ret.add_code Register.get_slot(self,:new_message , :caller , :message )
|
||||
#load the return address into pc, affecting return. (other cpus have commands for this, but not arm)
|
||||
ret.add_code Register::FunctionReturn.new( self , Register.new_message_reg , Register.resolve_index(:message , :return_address) )
|
||||
ret.add_code FunctionReturn.new( self , Register.new_message_reg , Register.resolve_index(:message , :return_address) )
|
||||
@constants = []
|
||||
end
|
||||
attr_reader :blocks , :constants , :return_type
|
||||
@ -75,13 +75,13 @@ module Virtual
|
||||
|
||||
def set_return_type type
|
||||
return if type.nil?
|
||||
raise "not type #{type}" unless Virtual.machine.space.get_class_by_name type
|
||||
raise "not type #{type}" unless Register.machine.space.get_class_by_name type
|
||||
@return_type = type
|
||||
end
|
||||
# add an instruction after the current (insertion point)
|
||||
# the added instruction will become the new insertion point
|
||||
def add_code instruction
|
||||
unless instruction.is_a?(Register::Instruction)
|
||||
unless instruction.is_a?(Instruction)
|
||||
raise instruction.to_s
|
||||
end
|
||||
@current.add_code(instruction) #insert after current
|
||||
@ -93,7 +93,7 @@ module Virtual
|
||||
def locals_at l_block
|
||||
used =[]
|
||||
# call assigns the return register, but as it is in l_block, it is not asked.
|
||||
assigned = [ Register::RegisterValue.new(Virtual::RegisterMachine.instance.return_register) ]
|
||||
assigned = [ RegisterValue.new(RegisterMachine.instance.return_register) ]
|
||||
l_block.reachable.each do |b|
|
||||
b.uses.each {|u|
|
||||
(used << u) unless assigned.include?(u)
|
@ -1,4 +1,4 @@
|
||||
module Virtual
|
||||
module Register
|
||||
|
||||
# Remove all functions that are not called
|
||||
# Not called is approximated by the fact that the method name doesn't show up
|
||||
@ -11,7 +11,7 @@ module Virtual
|
||||
@gonners << f
|
||||
end
|
||||
end
|
||||
keep Virtual.machine.space.get_init
|
||||
keep Register.machine.space.get_init
|
||||
remove_remaining
|
||||
end
|
||||
|
||||
@ -25,7 +25,7 @@ module Virtual
|
||||
@gonners.delete function
|
||||
function.source.blocks.each do |block|
|
||||
block.codes.each do |code|
|
||||
keep code.method if code.is_a? Register::FunctionCall
|
||||
keep code.method if code.is_a? FunctionCall
|
||||
end
|
||||
end
|
||||
end
|
@ -4,7 +4,7 @@
|
||||
# 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 Virtual
|
||||
module Register
|
||||
def self.new_list array
|
||||
list = Parfait::List.new
|
||||
list.set_length array.length
|
||||
@ -24,7 +24,7 @@ class Symbol
|
||||
true
|
||||
end
|
||||
def get_layout
|
||||
l = Virtual.machine.space.classes[:Word].object_layout
|
||||
l = Register.machine.space.classes[:Word].object_layout
|
||||
#puts "LL #{l.class}"
|
||||
l
|
||||
end
|
||||
@ -42,7 +42,7 @@ class Symbol
|
||||
pos = cache_positions[self]
|
||||
if pos == nil
|
||||
str = "position accessed but not set, "
|
||||
str += "Machine has object=#{Virtual.machine.objects.has_key?(self.object_id)} "
|
||||
str += "Machine has object=#{Register.machine.objects.has_key?(self.object_id)} "
|
||||
raise str + " for Symbol:#{self}"
|
||||
end
|
||||
pos
|
@ -3,7 +3,7 @@
|
||||
module Positioned
|
||||
def position
|
||||
if @position.nil?
|
||||
str = "IN machine #{Virtual.machine.objects.has_key?(self.object_id)}, at #{self.object_id.to_s(16)}\n"
|
||||
str = "IN machine #{Register.machine.objects.has_key?(self.object_id)}, at #{self.object_id.to_s(16)}\n"
|
||||
raise str + "position not set for #{self.class} len #{word_length} for #{self.inspect[0...100]}"
|
||||
end
|
||||
@position
|
@ -1,7 +0,0 @@
|
||||
require_relative "instruction"
|
||||
require_relative "register_value"
|
||||
require_relative "assembler"
|
||||
|
||||
# So the memory model of the machine allows for indexed access into an "object" .
|
||||
# A fixed number of objects exist (ie garbage collection is reclaming, not destroying and
|
||||
# recreating) although there may be a way to increase that number.
|
@ -10,7 +10,6 @@ end
|
||||
|
||||
require 'parser/transform'
|
||||
require "salama-object-file"
|
||||
require "virtual"
|
||||
require "register/register"
|
||||
require "register"
|
||||
require "register/builtin/object"
|
||||
require "arm/arm_machine"
|
||||
|
@ -1,16 +0,0 @@
|
||||
require "parfait"
|
||||
require "virtual/machine"
|
||||
#if we are in the ruby run-time / generating an executable
|
||||
require "virtual/positioned"
|
||||
require "virtual/padding"
|
||||
require "virtual/parfait_adapter"
|
||||
|
||||
require "phisol/compiler"
|
||||
require "virtual/method_source"
|
||||
|
||||
|
||||
class Fixnum
|
||||
def fits_u8?
|
||||
self >= 0 and self <= 255
|
||||
end
|
||||
end
|
@ -1,62 +0,0 @@
|
||||
### Virtual OO Machine
|
||||
|
||||
This is really an OV (object value) not object oriented machine.
|
||||
|
||||
Integers and References are Values. We make them look like objects, sure, but they are not.
|
||||
Symbols have similar properties and those are:
|
||||
|
||||
- equality means identity
|
||||
- no change over lifetime
|
||||
|
||||
It's like with Atoms: they used to be the smallest possible physical unit. Now we have electrons,
|
||||
proton and neutrons. And so objects are made up of Values (not objects), integers, floats ,
|
||||
references and possibly more.
|
||||
|
||||
Values have type in the same way objects have a class. We keep track of the type of a value at runtime,
|
||||
also in an similar way that objects have their classes at runtime.
|
||||
|
||||
### Layers
|
||||
|
||||
*Ast* instances get created by the [salama-reader](https://github.com/salama/salama-reader) gem from
|
||||
source. Here we add compile functions to ast classes and compile the AST layer into
|
||||
Virtual::Objects and Parfait::Values
|
||||
|
||||
The main objects are Space (lots of objects), Parfait::Class ,
|
||||
Method and MethodSource (with Blocks and Instruction).
|
||||
|
||||
**Virtual** Instructions get further transformed into **register** instructions.
|
||||
This is done by an abstractly defined Register Machine with basic Intructions.
|
||||
A concrete implementation (like Arm) derives and creates derived Instructions.
|
||||
|
||||
The transformation is implemented as **passes** to make it easier to understand what is going on.
|
||||
Also this makes it easier to add functionality and optimisations from external (to the gem) sources.
|
||||
|
||||
The final transformation assigns Positions to all boot objects (Linker) and assembles them into a
|
||||
binary representation. The data- part is then a representation of classes in the **parfait** runtime.
|
||||
And the instrucions make up the funtions.
|
||||
|
||||
### Accessible Objects
|
||||
|
||||
Object oriented systems have data hiding. So we have access to the inner state of only four objects:
|
||||
|
||||
- Self
|
||||
- Message (arguments, method name, self)
|
||||
- Frame (local and tmp variables)
|
||||
- NewMessage ( to build the next message sent)
|
||||
|
||||
A single instructions (Set) allows movement of data between these.
|
||||
There are compare, branch and call intructions too.
|
||||
|
||||
### Micro
|
||||
|
||||
The micro-kernel idea is well stated by: If you can leave it out, do.
|
||||
|
||||
|
||||
As such we are aiming for integer and reference (type) support, and a minimal class system
|
||||
(object/class/aray/hash/string). It is possible to add types to the system in a similar way as we add classes,
|
||||
and also implement very machine dependent functionality which nevertheless is fully wrapped as OO.
|
||||
|
||||
**Parfait** is that part of the runtime that can be coded in ruby.
|
||||
It is parsed, like any other code and always included in the resulting binary.
|
||||
**Builtin** is the part of the runtime that can not be coded in ruby (but is still needed).
|
||||
This is coded by construction MethodSource in code and necessarily machine dependant.
|
Reference in New Issue
Block a user