collapsed slot classes into one

different slot operation have different right sides
mom assignment tests work again
157 others don’t
This commit is contained in:
Torsten Ruger
2018-03-15 20:33:38 +05:30
parent 3247c2036c
commit 79bf416e58
23 changed files with 140 additions and 233 deletions

View File

@ -38,43 +38,21 @@ So to put a layer in the middle of those two, MOM will be:
### Linked list
But, see below, in two steps
But, very much like Risc, just higher level so it's easier to understand
### Use object memory
object to object transfer
no registers
no registers (one could see the current message as the only register)
### Instruction based
So a machine rather than a language. No control structures, but compare and jump instructions.
So mom is a machine layer, rather than a language.
No control structures, but compare and jump instructions.
No send or call, just objects and jump.
Again in two steps, see below
Machine capabilities (instructions) for basic operations. Use of macros for higher level.
## Two step approach
To make the transition even easier, it is done in two steps.
## 1. Everything but control structures
wSo we go from language to machine as the first step, in terms of memory instructions.
Memory gets moved around between the main machine objects (frames and messages).
But control structures stay "intact", so we stay at tree structure
## 2. Flattening control structures
By flattening control structures and introducing jumps instead, we go from tree to linked
list of instructions.
After this, it is quite trivial to translate to risc, as it mostly expands instructions.
## The future
I hope that in the future this simple 2 stage pipeline will expand into more steps.
This is the ideal layer to do code analysis and meaningful optimisations, as one can still
understand what is going on in higher terms.

View File

@ -29,8 +29,6 @@ require_relative "truth_check"
require_relative "not_same_check"
require_relative "jump"
require_relative "slot_load"
require_relative "slot_move"
require_relative "slot_constant"
require_relative "return_sequence"
require_relative "message_setup"
require_relative "argument_transfer"

View File

@ -1,25 +0,0 @@
module Mom
# A SlotConstant moves a constant into a known Slot.
# Eg when you write a = 5 , the 5 becomes a constant, and so the right side
# the a is an instance variable on the current frame, and the frame is an instance
# of the current message, so the effect is something like message.frame.a = 5
# @left: See SlotLoad, an array of symbols
# @right: A Constant from parse, ie an instance of classes in basc_value, like TrueConstant
class SlotConstant < SlotLoad
def initialize(left , right)
super
raise "right not constant, #{right}" unless right.is_a? Mom::Constant
end
def to_risc(context)
reg = context.use_reg( @right.ct_type)
const = Risc.load_constant(self, @right , reg)
const.set_next Risc.reg_to_slot(self, reg , @left.known_object, @left.slots.first)
context.release_reg(reg)
return const
end
end
end

View File

@ -3,9 +3,10 @@ module Mom
# SlotLoad is an abstract base class for moving data into a slot
# A Slot is basically an instance variable, but it must be of known type
#
# The value loaded can be a constant (SlotConstant) or come from another Slot (SlotMove)
# The value loaded (the right hand side) can be a constant (Mom::Constant) or come from
# another Slot (SlotDefinition)
#
# The Slot is the left hand side, the right hand side being determined by the subclass.
# The Slot on the left hand side is always a SlotDefinition.
# The only known object (*) for the left side is the current message, which is a bit like
# the oo version of a PC (program Counter)
# (* off course all class objects are global, and so they are allowed too)
@ -17,25 +18,46 @@ module Mom
# From the outside a send is neccessary, both for get and set, (which goes through the method
# resolution and guarantees the correct method for a type), in other words perfect data hiding.
#
# @left: is an array of symbols, that specifies the first the object, and then the Slot.
# The first element is either a known type name (Capitalized symbol of the class name) ,
# or the symbol :message
# And subsequent symbols must be instance variables on the previous type.
# Examples: [:message , :receiver] or [:Space : :next_message]
# @left: A SlotDefinition, or an array that can be passed to the constructor of the
# SlotDefinition (see there)
#
# @right: depends on the derived Class
# @right: Either a SlotDefinition or a Constant
#
class SlotLoad < Instruction
attr_reader :left , :right
def initialize(left , right)
left = SlotDefinition.new(left.shift , left) if left.is_a? Array
right = SlotDefinition.new(right.shift , right) if right.is_a? Array
raise "right not Mom, #{right.to_s}" unless right.is_a?( SlotDefinition )or right.is_a? Mom::Constant
@left , @right = left , right
raise "left not SlotDefinition, #{left}" unless left.is_a? SlotDefinition
end
def to_risc_load(context)
reg = context.use_reg( @right.ct_type)
const = Risc.load_constant(self, @right , reg)
const.set_next Risc.reg_to_slot(self, reg , @left.known_object, @left.slots.first)
context.release_reg(reg)
return const
end
def to_risc_move(context)
reg = context.use_reg(:int)#( @right.ct_type)
const = Risc.load_constant(self, @right , reg)
# const.set_next Risc.reg_to_slot(self, reg , @left.known_object, @left.slots.first)
# context.release_reg(reg)
return const
end
end
class SlotDefinition
attr_reader :known_object , :slots
# is an array of symbols, that specifies the first the object, and then the Slot.
# The first element is either a known type name (Capitalized symbol of the class name) ,
# or the symbol :message
# And subsequent symbols must be instance variables on the previous type.
# Examples: [:message , :receiver] or [:Space : :next_message]
def initialize( object , slots)
@known_object , @slots = object , slots
slot = [slot] unless slot.is_a?(Array)

View File

@ -1,21 +0,0 @@
module Mom
#SlotMove is a SlotLoad where the right side is a slot, just like the left.
class SlotMove < SlotLoad
def initialize(left , right)
right = SlotDefinition.new(right.shift , right) if right.is_a? Array
raise "right not Mom, #{right.to_s}" unless right.is_a?( SlotDefinition )
super(left , right)
end
def to_risc(context)
reg = context.use_reg(:int)#( @right.ct_type)
const = Risc.load_constant(self, @right , reg)
# const.set_next Risc.reg_to_slot(self, reg , @left.known_object, @left.slots.first)
# context.release_reg(reg)
return const
end
end
end

View File

@ -1,13 +1,13 @@
# The *essential* step from vool to risc, is the one from a language to a machine. From statements
# that hang in the air, to an instruction set.
# The *essential* step from vool to risc, is the one from a language to a machine.
# From vools statements that hang in the air, to an instruction set.
#
# ### Tree based: So almost 1-1 from vool
# ### List based: Bit like Risc, just no registers
#
# ### Use object memory : object to object transfer + no registers
#
# ### Instruction based
#
# So a machine than language. No control structures, but compare and jump instructions.
# So a machine rather than a language. No control structures, but compare and jump instructions.
# No send or call, just objects and jump.
# Machine capabilities (instructions) for basic operations. Use of macros for higher level.
@ -15,4 +15,3 @@ module Mom
end
require_relative "instruction/instruction.rb"
require_relative "statement/statement.rb"

View File

@ -1,36 +0,0 @@
module Mom
class IfStatement < Statement
attr_reader :condition , :if_true , :if_false
attr_accessor :hoisted
def initialize( cond , if_true , if_false = nil)
@condition = cond
@if_true = if_true
@if_false = if_false
raise if_true.class unless if_true.is_a? Statement
end
def flatten(options = {})
true_label = Label.new( "true_label_#{object_id}")
false_label = Label.new( "false_label_#{object_id}")
merge_label = Label.new( "merge_label_#{object_id}")
first = condition.flatten( true_label: true_label , false_label: false_label)
if hoisted
head = hoisted.flatten
head.append first
else
head = first
end
head.append true_label
head.append if_true.flatten( merge_label: merge_label)
if( if_false)
head.append false_label
head.append if_false.flatten( merge_label: merge_label)
end
head.append merge_label
head
end
end
end

View File

@ -1,15 +0,0 @@
module Mom
class Statement
include Common::List
# flattening will change the structure from a tree to a linked list (and use
# nekst to do so)
def flatten(options = {})
raise "not implemented for #{self}"
end
end
end
require_relative "statements"
require_relative "if_statement"
require_relative "while_statement"

View File

@ -1,20 +0,0 @@
module Mom
class Statements < Statement
include Common::Statements
def flatten( options = {} )
flat = @statements.shift.flatten(options)
while( nekst = @statements.shift )
flat.append nekst.flatten(options)
end
flat
end
def initialize(arr)
super(arr)
arr.each {|s|
raise "Not a Statement #{s}" unless s.is_a?( Statement) or s.is_a?(Instruction)
}
end
end
end

View File

@ -1,25 +0,0 @@
module Mom
class WhileStatement < Statement
attr_reader :condition , :statements
attr_accessor :hoisted
def initialize( cond , statements)
@condition = cond
@statements = statements
end
def flatten(options = {})
merge_label = Label.new( "merge_label_#{object_id}")
cond_label = Label.new( "cond_label_#{object_id}")
@nekst = cond_label
@nekst.append(hoisted.flatten) if hoisted
@nekst.append condition.flatten( true_label: cond_label , false_label: merge_label)
@nekst.append merge_label
@nekst
end
end
end