homing in on line length 100

This commit is contained in:
Torsten Ruger 2015-05-30 12:20:39 +03:00
parent 33d464f032
commit e651b57d08
29 changed files with 159 additions and 108 deletions

View File

@ -88,7 +88,7 @@ inlining, but i have at least an idea.
### Sof
**S**alama **O**bject **F**ile format is a yaml ike format to look at code dumps and help testing.
**S**alama **O**bject **F**ile format is a yaml like format to look at code dumps and help testing.
The dumper is ok and does produce (as intended) considerably denser dumps than yaml
When a reader is done (not started) the idea is to use sof as pre-compiled, language independent

View File

@ -9,15 +9,15 @@ module Arm
# Also, shortcuts are created to easily instantiate Instruction objects.
# Example: pop -> StackInstruction.new( {:opcode => :pop}.merge(options) )
# Instructions work with options, so you can pass anything in, and the only thing the functions does
# is save you typing the clazz.new. It passes the function name as the :opcode
# Instructions work with options, so you can pass anything in, and the only thing the functions
# does is save you typing the clazz.new. It passes the function name as the :opcode
class ArmMachine
# conditions specify all the possibilities for branches. Branches are b + condition
# Example: beq means brach if equal.
# :al means always, so bal is an unconditional branch (but b() also works)
CONDITIONS = [ :al , :eq , :ne , :lt , :le, :ge, :gt , :cs , :mi , :hi , :cc , :pl, :ls , :vc , :vs ]
CONDITIONS = [:al ,:eq ,:ne ,:lt ,:le ,:ge,:gt ,:cs ,:mi ,:hi ,:cc ,:pl,:ls ,:vc ,:vs]
# here we create the shortcuts for the "standard" instructions, see above
# Derived machines may use own instructions and define functions for them if so desired
@ -67,8 +67,8 @@ module Arm
# an actual machine must create derived classes (from this base class)
# These instruction classes must follow a naming pattern and take a hash in the contructor
# Example, a mov() opcode instantiates a Register::MoveInstruction
# for an Arm machine, a class Arm::MoveInstruction < Register::MoveInstruction exists, and it will
# be used to define the mov on an arm machine.
# for an Arm machine, a class Arm::MoveInstruction < Register::MoveInstruction exists, and it
# will be used to define the mov on an arm machine.
# This methods picks up that derived class and calls a define_instruction methods that can
# be overriden in subclasses
def self.define_instruction_one(inst , clazz , defaults = {} )

View File

@ -28,7 +28,8 @@ module Arm
#codition codes can be applied to many instructions and thus save branches
# :al => always , :eq => equal and so on
# eq mov if equal :moveq r1 r2 (also exists as function) will only execute if the last operation was 0
# eq mov if equal :moveq r1 r2 (also exists as function) will only execute
# if the last operation was 0
COND_CODES = {
:al => 0b1110, :eq => 0b0000,
:ne => 0b0001, :cs => 0b0010,
@ -39,7 +40,8 @@ module Arm
:ge => 0b1010, :gt => 0b1100,
:vs => 0b0110
}
#return the bit pattern for the @attributes[:condition_code] variable, which signals the conditional code
# return the bit pattern for the @attributes[:condition_code] variable,
# which signals the conditional code
def cond_bit_code
COND_CODES[@attributes[:condition_code]] or throw "no code found for #{@attributes[:condition_code]}"
end
@ -96,7 +98,8 @@ module Arm
op = 0
#codes that one can shift, first two probably most common.
# l (in lsr) means logical, ie unsigned, a (in asr) is arithmetic, ie signed
{'lsl' => 0b000, 'lsr' => 0b010, 'asr' => 0b100, 'ror' => 0b110, 'rrx' => 0b110}.each do |short, bin|
shift_codes = {'lsl' => 0b000, 'lsr' => 0b010, 'asr' => 0b100, 'ror' => 0b110, 'rrx' => 0b110}
shift_codes.each do |short, bin|
long = "shift_#{short}".to_sym
if shif = @attributes[long]
# TODO delete this code, AFTER you understand it

View File

@ -36,8 +36,10 @@ module Arm
if arg.is_a?(Virtual::Block) or arg.is_a?(Parfait::Method)
#relative addressing for jumps/calls
diff = arg.position - self.position
# but because of the arm "theoretical" 3- stage pipeline, we have to subtract 2 words (fetch/decode)
# But, for methods, this happens to be the size of the object header, so there it balances out, but not blocks
# but because of the arm "theoretical" 3- stage pipeline,
# we have to subtract 2 words (fetch/decode)
# But, for methods, this happens to be the size of the object header,
# so there it balances out, but not blocks
diff -= 8 if arg.is_a?(Virtual::Block)
arg = diff
end

View File

@ -19,12 +19,12 @@ module Arm
attr_accessor :to , :from
# arm intructions are pretty sensible, and always 4 bytes (thumb not supported)
# but not all constants fit into the part of the instruction that is left after the instruction code,
# so large moves have to be split into two instructions.
# but not all constants fit into the part of the instruction that is left after the instruction
# code, so large moves have to be split into two instructions.
# we handle this "transparently", just this instruction looks longer
# alas, full transparency is not achieved as we only know when to use 2 instruction once we know where the
# other object is, and that position is only set after code positions have been determined (in link) and so
# see below in assemble
# alas, full transparency is not achieved as we only know when to use 2 instruction once we
# know where the other object is, and that position is only set after code positions have been
# determined (in link) and so see below in assemble
def mem_length
@extra ? 8 : 4
end
@ -52,13 +52,14 @@ module Arm
operand = op_with_rot
immediate = 1
else
# unfortunately i was wrong in thinking the pi is armv7. The good news is the code below implements
# the movw instruction (armv7 for moving a word) and works
# unfortunately i was wrong in thinking the pi is armv7. The good news is the code
# below implements the movw instruction (armv7 for moving a word) and works
#armv7 raise "Too big #{right} " if (right >> 16) > 0
#armv7 operand = (right & 0xFFF)
#armv7 immediate = 1
#armv7 rn = (right >> 12)
# a little STRANGE, that the armv7 movw (move a 2 byte word) is an old test opcode, but there it is
# a little STRANGE, that the armv7 movw (move a 2 byte word) is an old test opcode,
# but there it is
#armv7 @attributes[:opcode] = :tst
raise "No negatives implemented #{right} " if right < 0
# and so it continues: when we notice that the const doesn't fit, first time we raise an
@ -74,7 +75,8 @@ module Arm
raise "no fit for #{right}" unless operand
immediate = 1
@extra = ArmMachine.add( to , to , (right & 0xFF) )
#TODO: this is still a hack, as it does not encode all possible values. The way it _should_ be done
#TODO: this is still a hack, as it does not encode all possible values.
# The way it _should_ be done
# is to check that the first part is doabe with u8_with_rr AND leaves a u8 remainder
end
elsif (right.is_a?(Symbol) or right.is_a?(::Register::RegisterReference))

View File

@ -43,16 +43,16 @@ module Arm
syscall( function.insertion_point , 1 ) # 1 == exit
end
# the number (a Virtual::integer) is (itself) divided by 10, ie overwritten by the result
# and the remainder is overwritten (ie an out argument)
# not really a function, more a macro,
# not really a function, more a macro,
def div10 function, number , remainder
# Note about division: devision is MUCH more expensive than one would have thought
# And coding it is a bit of a mind leap: it's all about finding a a result that gets the
# And coding it is a bit of a mind leap: it's all about finding a a result that gets the
# remainder smaller than an int. i'll post some links sometime. This is from the arm manual
tmp = function.new_local
function.instance_eval do
function.instance_eval do
sub( remainder , number , 10 )
sub( number , number , number , shift_lsr: 2)
add( number , number , number , shift_lsr: 4)
@ -67,7 +67,8 @@ module Arm
end
def syscall block , num
# This is very arm specific, syscall number is passed in r7, other arguments like a c call ie 0 and up
# This is very arm specific, syscall number is passed in r7,
# other arguments like a c call ie 0 and up
sys = Virtual::Integer.new( Virtual::RegisterReference.new(SYSCALL_REG) )
ret = Virtual::Integer.new( Virtual::RegisterReference.new(RETURN_REG) )
block.add_code mov( sys , num )
@ -78,4 +79,3 @@ module Arm
end
end

View File

@ -1,9 +1,10 @@
module Arm
# Arm stores the return address in a register (not on the stack)
# The register is called link , or lr for short . Maybe because it provides the "link" back to the caller (?)
# The register is called link , or lr for short .
# Maybe because it provides the "link" back to the caller (?)
# the vm defines a register for the location, so we store it there.
# the vm defines a register for the location, so we store it there.
class SaveImplementation
def run block

View File

@ -12,7 +12,7 @@ module Virtual
# PS: can't say i fancy the << self syntax and am considerernig adding a
# keyword for it, like meta
# In effect it is a very similar construct to def self.function(...)
# So one could write def meta.function(...) and thus define on the meta-class
# So one could write def meta.function(...) and thus define on the meta-class
class MetaClass < Object
# no name, nor nothing. as this is just the object really
@ -44,7 +44,8 @@ module Virtual
# get the function and if not found, try superclasses. raise error if not found
def resolve_method name
fun = get_function name
# TODO THE BOOK says is class A derives from B , then the metaclass of A derives from the metaclass of B
# TODO THE BOOK says is class A derives from B , then the metaclass of
# A derives from the metaclass of B
# just get to it ! (and stop whimpering)
raise "Method not found #{name} , for #{inspect}" unless fun
fun

View File

@ -14,7 +14,8 @@ module Parfait
# The Space contains all objects for a program. In functional terms it is a program, but in oo
# it is a collection of objects, some of which are data, some classes, some functions
# The main entry is a function called (of all things) "main", This _must be supplied by the compling
# The main entry is a function called (of all things) "main".
# This _must be supplied by the compled code (similar to c)
# There is a start and exit block that call main, which receives an List of strings
# While data ususally would live in a .data section, we may also "inline" it into the code

View File

@ -1,12 +1,13 @@
module Register
class LinkException < Exception
end
# Assmble the object space into a binary.
# Assemble the object space into a binary.
# Link first to get positions, then assemble
# link and assemble functions for each class are close to each other, so to get them the same.
# meaning: as the link function determines the length of an object and the assemble actually writes the bytes
# they are pretty much dependant. In an earlier version they were functions on the objects, but now it
# has gone to a visitor pattern.
# The link function determines the length of an object and the assemble actually
# writes the bytes they are pretty much dependant. In an earlier version they were
# functions on the objects, but now it has gone to a visitor pattern.
class Assembler
TYPE_REF = 0
TYPE_INT = 1
@ -119,7 +120,9 @@ module Register
# write type and layout of the instance, and the variables that are passed
# variables ar values, ie int or refs. For refs the object needs to save the object first
def assemble_self( object , variables )
raise "Object(#{object.object_id}) not linked #{object.inspect}" unless @objects[object.object_id]
unless @objects[object.object_id]
raise "Object(#{object.object_id}) not linked #{object.inspect}"
end
type = type_word(variables)
@stream.write_uint32( type )
write_ref_for(object.layout[:names] )
@ -207,9 +210,8 @@ module Register
private
# write means we write the resulting address straight into the assembler stream (ie don't return it)
# write means we write the resulting address straight into the assembler stream
# object means the object of which we write the address
# and we write the address into the self, given as second parameter
def write_ref_for object
@stream.write_sint32 object.position
end

View File

@ -2,7 +2,8 @@
module Builtin
module Integer
module ClassMethods
# The conversion to base10 is quite a bit more complicated than i thought. The bulk of it is in div10
# The conversion to base10 is quite a bit more complicated than i thought.
# The bulk of it is in div10
# We set up variables, do the devision and write the result to the string
# then check if were done and recurse if neccessary
# As we write before we recurse (save a push) we write the number backwards

View File

@ -4,7 +4,8 @@ module Builtin
# return the index of the variable. Now "normal" code can't really do anything with that, but
# 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 = Virtual::Integer
index_function = Virtual::CompiledMethodInfo.create_method("Object" , "index_of" , [Virtual::Reference] )
index_function.info.return_type = Virtual::Integer
@ -22,7 +23,8 @@ module Builtin
# i = self.index_of(var)
# return at_index(i)
# end
# 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
# 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 = Virtual::Integer
get_function = Virtual::CompiledMethodInfo.create_method("Object","_get_instance_variable" , [ Virtual::Reference ] )
return get_function

View File

@ -2,7 +2,8 @@ module Register
# RegisterReference is not the name for a register, "only" for a certain use of it.
# 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 RegisterReference then use that register
# but which register can be changed, and _all_ instructions sharing the RegisterReference then
# use that register
# In other words a simple level of indirection, or change from value to reference sematics.
class RegisterReference

View File

@ -15,8 +15,8 @@ module Virtual
# They also have local variables.
# Code-wise Methods are made up from a list of Blocks, in a similar way blocks are made up of Instructions
# The function starts with one block, and that has a start and end (return)
# Code-wise Methods are made up from a list of Blocks, in a similar way blocks are made up of
# Instructions. The function starts with one block, and that has a start and end (return)
# Blocks can be linked in two ways:
# -linear: flow continues from one to the next as they are sequential both logically and
@ -59,7 +59,9 @@ module Virtual
# add an instruction after the current (insertion point)
# the added instruction will become the new insertion point
def add_code instruction
raise instruction.inspect unless (instruction.is_a?(Instruction) or instruction.is_a?(Register::Instruction))
unless (instruction.is_a?(Instruction) or instruction.is_a?(Register::Instruction))
raise instruction.inspect
end
@current.add_code(instruction) #insert after current
self
end
@ -79,21 +81,24 @@ module Virtual
used.uniq
end
# control structures need to see blocks as a graph, but they are stored as a list with implict branches
# control structures need to see blocks as a graph, but they are stored as a list with implict
# branches
# So when creating a new block (with new_block), it is only added to the list, but instructions
# still go to the current one
# With this function one can change the current block, to actually code it.
# This juggling is (unfortunately) neccessary, as all compile functions just keep puring their code into the
# method and don't care what other compiles (like if's) do.
# This juggling is (unfortunately) neccessary, as all compile functions just keep puring their
# code into the method and don't care what other compiles (like if's) do.
# Example: while, needs 2 extra blocks
# 1 condition code, must be its own blockas we jump back to it
# - the body, can actually be after the condition as we don't need to jump there
# 2 after while block. Condition jumps here
# After block 2, the function is linear again and the calling code does not need to know what happened
# After block 2, the function is linear again and the calling code does not need to know what
# happened
# But subsequent statements are still using the original block (self) to add code to
# So the while expression creates the extra blocks, adds them and the code and then "moves" the insertion point along
# So the while expression creates the extra blocks, adds them and the code and then "moves"
# the insertion point along
def current block
@current = block
self

View File

@ -79,7 +79,9 @@ module Virtual
#attr_reader :left, :right
def self.compile_assignment expression , method
raise "must assign to NameExpression , not #{expression.left}" unless expression.left.instance_of? Ast::NameExpression
unless expression.left.instance_of? Ast::NameExpression
raise "must assign to NameExpression , not #{expression.left}"
end
r = Compiler.compile(expression.right , method )
raise "oh noo, nil from where #{expression.right.inspect}" unless r
index = method.has_arg(Virtual.new_word name)

View File

@ -4,7 +4,8 @@ module Virtual
def self.compile_if expression , method
# to execute the logic as the if states it, the blocks are the other way around
# so we can the jump over the else if true ,and the else joins unconditionally after the true_block
# so we can the jump over the else if true ,
# and the else joins unconditionally after the true_block
merge_block = method.info.new_block "if_merge" # last one, created first
true_block = method.info.new_block "if_true" # second, linked in after current, before merge
false_block = method.info.new_block "if_false" # directly next in order, ie if we don't jump we land here

View File

@ -10,7 +10,8 @@ module Virtual
puts "Created class #{clazz.name.inspect}"
expression.expressions.each do |expr|
# check if it's a function definition and add
# if not, execute it, but that does means we should be in salama (executable), not ruby. ie throw an error for now
# if not, execute it, but that does means we should be in salama (executable), not ruby.
# ie throw an error for now
raise "only functions for now #{expr.inspect}" unless expr.is_a? Ast::FunctionExpression
#puts "compiling expression #{expression}"
expression_value = Compiler.compile(expr,method )

View File

@ -15,7 +15,9 @@ module Virtual
if expression_value.is_a?(IntegerConstant) or expression_value.is_a?(ObjectConstant)
return_reg.load into , expression_value
else
return_reg.move( into, expression_value ) if expression_value.register_symbol != return_reg.register_symbol
if expression_value.register_symbol != return_reg.register_symbol
return_reg.move( into, expression_value )
end
end
#function.set_return return_reg
return return_reg

View File

@ -1,10 +1,11 @@
module Virtual
# the first instruction we need is to stop. Off course in a real machine this would be a syscall, but that is just
# an implementation (in a programm it would be a function).
# the first instruction we need is to stop. Off course in a real machine this would be a syscall,
# but that is just an implementation (in a programm it would be a function).
# But in a virtual machine, not only do we need this instruction,
# it is indeed the first instruction as just this instruction is the smallest possible programm for the machine.
# it is indeed the first instruction as just this instruction is the smallest possible programm
# for the machine.
# As such it is the next instruction for any first instruction that we generate.
class Halt < Instruction
end

View File

@ -1,7 +1,9 @@
module Virtual
# Get a instance variable by _name_ . So we have to resolve the name to an index to trnsform into a Slot
# The slot may the be used in a set on left or right hand. The transformation is done by GetImplementation
# Get a instance variable by _name_ . So we have to resolve the name to an index to
# transform into a Slot
# The slot may the be used in a set on left or right hand.
# The transformation is done by GetImplementation
class InstanceGet < Instruction
def initialize name
@name = name.to_sym

View File

@ -1,8 +1,8 @@
module Virtual
# class for Set instructions, A set is basically a mem move.
# to and from are indexes into the known objects(frame,message,self and new_message), these are represented as slots
# (see there)
# to and from are indexes into the known objects(frame,message,self and new_message),
# these are represented as slots (see there)
# from may be a Constant (Object,Integer,String,Class)
class Set < Instruction
def initialize to , from

View File

@ -1,34 +1,37 @@
module Virtual
# The Virtual Machine is a value based virtual machine in which ruby is implemented. While it is value based,
# it resembles oo in basic ways of object encapsulation and method invokation, it is a "closed" / static sytem
# in that all types are know and there is no dynamic dispatch (so we don't bite our tail here).
# The Virtual Machine is a value based virtual machine in which ruby is implemented.
# While it is value based, it resembles oo in basic ways of object encapsulation and method
# invocation, it is a "closed" / static sytem in that all types are know and there is no
# dynamic dispatch (so we don't bite our tail here).
#
# 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 the opposite from
# ruby, which has several loops, many redundant if forms and the like.
# - realistic means it is easy to implement on a 32 bit machine (arm) and possibly 64 bit. Memory access, a stack,
# some registers of same size are the underlying hardware. (not ie byte machine)
# - low level means it's basic instructions are realively easily implemented in a register machine. ie send is not
# a an instruction but a function.
# - minimal means that if one thing can be implemented by another, it is left out. This is quite
# the opposite from ruby, which has several loops, many redundant if forms and the like.
# - realistic means it is easy to implement on a 32 bit machine (arm) and possibly 64 bit.
# Memory access,some registers of same size are the underlying hardware. (not ie byte machine)
# - low level means it's basic instructions are realively easily implemented in a register machine.
# ie send is not a an instruction but a function.
#
# 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.
# 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.
#
# The ast is transformed to virtaul-machine objects, some of which represent code, some data.
#
# The next step transforms to the register machine layer, which is what actually executes.
#
# More concretely, a virtual machine is a sort of oo turing machine, it has a current instruction, executes the
# instructions, fetches the next one and so on.
# More concretely, a virtual machine is a sort of oo turing machine, it has a current instruction,
# executes the instructions, fetches the next one and so on.
# Off course the instructions are not soo simple, but in oo terms quite so.
#
# The machine is virtual in the sense that it is completely modeled in software,
# it's complete state explicitly available (not implicitly by walking stacks or something)
# The machine has a no register, but local variables, a scope at each point in time.
# Scope changes with calls and blocks, but is saved at each level. In terms of lower level implementation this means
# that the the model is such that what is a variable in ruby, never ends up being just on the pysical stack.
# Scope changes with calls and blocks, but is saved at each level. In terms of lower level
# implementation this means that the the model is such that what is a variable in ruby,
# never ends up being just on the pysical stack.
#
class Machine

View File

@ -1,21 +1,23 @@
module Virtual
# So when an object calls a method, or sends a message, this is what it sends: a Message
# A message contains the sender, return and exceptional return addresses,the arguments, and a slot for the frame.
# A message contains the sender, return and exceptional return addresses,the arguments,
# and a slot for the frame.
# As such it is a very run-time object, deep in the machinery as it were, and does not have meaningful
# methods you could call at compile time.
# As such it is a very run-time object, deep in the machinery as it were, and does not have
# meaningful methods you could call at compile time.
# The methods that are there, are nevertheless meant to be called at compile time and generate code, rather than
# executing it.
# The methods that are there, are nevertheless meant to be called at compile time and generate
# code, rather than executing it.
# The caller creates the Message and passes control to the receiver's method
# The receiver create a new Frame to hold local and temporary variables and (later) creates default values for
# arguments that were not passed
# The receiver create a new Frame to hold local and temporary variables and (later) creates
# default values for arguments that were not passed
# How the actual finding of the method takes place (acording to the ruby rules) is not simple, but as there is a
# guaranteed result (be it method_missing) it does not matter to the passing mechanism described
# How the actual finding of the method takes place (acording to the ruby rules) is not simple,
# but as there is a guaranteed result (be it method_missing) it does not matter to the passing
# mechanism described
# During compilation Message and frame objects are created to do type analysis

View File

@ -25,7 +25,9 @@ module FakeMem
end
#TODO, this is copied from module Positioned, maybe avoid duplication ?
def position
raise "position accessed but not set at #{mem_length} for #{self.inspect[0...1000]}" if @position == nil
if @position == nil
raise "position accessed but not set at #{mem_length} for #{self.inspect[0...1000]}"
end
@position
end
def set_position pos

View File

@ -3,14 +3,18 @@ module Virtual
# Frames and Message are very similar apart from the class name
# - All existing instances are stored in the space for both
# - Size is currently 2, ie 16 words (TODO a little flexibility here would not hurt, but the mountain is big)
# - Unused instances for a linked list with their first instance variable. This is HARD coded to avoid any lookup
# - Size is currently 2, ie 16 words
# (TODO a little flexibility here would not hurt, but the mountain is big)
# - Unused instances for a linked list with their first instance variable.
# This is HARD coded to avoid any lookup
# Just as a reminder: a message object is created before a send and holds return address/message and arguemnts + self
# frames are created upon entering a method and hold local and temporary variables
# as a result one of each is created for every single method call. A LOT, so make it fast luke
# Note: this is off course the reason for stack based implementations that just increment a known pointer/register or
# something. But i think most programs are memory bound and a few extra instructions don't hurt.
# Just as a reminder: a message object is created before a send and holds return address/message
# and arguemnts + self frames are created upon entering a method and hold local and temporary
# variables as a result one of each is created for every single method call.
# A LOT, so make it fast luke
# Note: this is off course the reason for stack based implementations that just increment
# a known pointer/register or something. But i think most programs are memory bound
# and a few extra instructions don't hurt.
# After all, we are buying a big prize:oo, otherwise known as sanity.
class FrameImplementation

View File

@ -1,7 +1,9 @@
module Virtual
# This implements instance variable get (not the opposite of Set, such a thing does not exists, their slots)
# This implements instance variable get (not the opposite of Set,
# such a thing does not exists, their slots)
# Ivar get needs to acces the layout, find the index of the name, and shuffle the data to return register
# Ivar get needs to acces the layout, find the index of the name,
# and shuffle the data to return register
# In short it's so complicated we implement it in ruby and stick the implementation here
class GetImplementation
def run block

View File

@ -4,9 +4,11 @@ module Virtual
# That off course opens up an endless loop possibility that we stop by
# implementing Class and Module methods
# Note: I find it slightly unsemetrical that the NewMessage object needs to be created before this instruction
# This is because all expressions create a (return) value and that return value is overwritten by the next
# expression unless saved. And since the message is the place to save it it needs to exist. qed
# Note: I find it slightly unsymmetrical that the NewMessage object needs to be created
# before this instruction.
# This is because all expressions create a (return) value and that return value is
# overwritten by the next expression unless saved.
# And since the message is the place to save it it needs to exist. qed
class SendImplementation
def run block
block.codes.dup.each do |code|

View File

@ -4,18 +4,22 @@ module Virtual
# Data in a Block is usefull in the same way data in objects is. Plocks being otherwise just code.
#
# But the concept is not quite straigtforwrd: If one thinks of a Plock embedded in a normal method,
# the a data in the Plock would be static data. In OO terms this comes quite close to a Proc, if the data is the local
# variables. Quite possibly they shall be used to implement procs, but that is not the direction now.
# the a data in the Plock would be static data. In OO terms this comes quite close to a Proc,
# if the data is the local variables.
# Quite possibly they shall be used to implement procs, but that is not the direction now.
#
# For now we use Plocks behaind the scenes as it were. In the code that you never see, method invocation mainly.
#
# In terms of implementation the Plock is a Block with data (Not too much data, mainly a couple of references).
# The block writes it's instructions as normal, but a jump is inserted as the last instruction. The jump is to the
# next block, over the data that is inserted after the block code (and so before the next)
# For now we use Plocks behaind the scenes as it were. In the code that you never see,
# method invocation mainly.
#
# In terms of implementation the Plock is a Block with data
# (Not too much data, mainly a couple of references).
# The block writes it's instructions as normal, but a jump is inserted as the last instruction.
# The jump is to the next block, over the data that is inserted after the block code
# (and so before the next)
#
# It follows that Plocks should be linear blocks.
class Plock < Block
def initialize(name , method , next_block )
super
@data = []

View File

@ -2,7 +2,9 @@ require_relative "type"
module Positioned
def position
raise "position accessed but not set at #{mem_length} for #{self.inspect[0...500]}" if @position == nil
if @position == nil
raise "position accessed but not set at #{mem_length} for #{self.inspect[0...500]}"
end
@position
end
def set_position pos