--- layout: salama title: Salama, a simple and minimal oo machine ---
Just a small primer (left over from the start), really the book is the best starting point
This is the easy to understand part, that's why it's first, it's the code
from salama-arm , which is quite stable.
It creates binary code according to the arm specs. All about shifting bits in the
right way.
As an abstraction it is not far away from assembler. I mapped the memnonics to function calls and the registers
can be symbols or Values (from vm). But on the whole this is as low level as it gets.
Different types of instructions are implemented by different classes. To make machine dependant code possible,
those classes are derived from Vm versions.
There is an intel directory which contains an expanded version of wilson, but it has yet to be made to fit into
the architecture. So for now salama produces arm code.
There is an elf directory wich builds actual executables, a mini implementation of the elf standard.
Parsing is relatively straightforward too, it's code is found in
it's own repository .
It parses more than can be processed, but much less than ruby is.
We all know ruby, so it's just a matter of getting the rules right.
If only! Ruby is full of niceties that actually make parsing it quite difficult. But at the moment that story
hasn't even started.
Traditionally, yacc or bison or talk of lr or ll would come in here and all but a few would zone out. But llvm has
proven that recursive descent parsing is a viable alternative, also for big projects. And Parslet puts that into
a nice ruby framework for us.
Parslet lets us use modules for parts of the parser, so those files are pretty self-explanitory.
Not all is done, but a good start.
Parslet also has a seperate Transformation pass, and that creates the AST. Those class names are also
easy, so you can guess what an IfExpression represents.
The Virtual machine layer is where it gets interesting, but also a little fuzzy.
After some trying around the virtual machine layer has become a completely self contained layer to describe and
implement an oo machine. In other words it has no reference to any physical machine, that is the next layer down.
One can get headaches quite easily while thinking about implementing an oo machine in oo, it's just so difficult to
find the boundaries. To determine those, i like to talk of types (not classes) for the objects (values) in which the
vm is implemented. Also it is neccessary to remove ambiguity about what message sending means.
One way to think of this (helps to keep sane) is to think of the types of the system known at compile time. In the
simplest case this could be object reference and integer. The whole vm functionality can be made to work with only
those two types, and it is not specified how the type information is stored. but off course there needs to be a
way to check it at run-time.
The vm has an instruction set that, apart from basic integer manipulation, only alows for memory access into an
object. Instead of an implicit stack, we use activation frames and store all variables explicitly.
Compilation happens in Passes. A single pass is a small piece of code to do just a very small part of the
whole compilation.
Logically there are four distinct steps. From the parsed AST we compile a datastructure that includes instructions
for an object machine. The next step is a (still abstract) register machine, before the actual binary for the
arm is generated.
The Register machine layer is a relatively close abstraction of hardware.
The step from OO machine to Arm had proved to large, also partially due to the cryptic arm names.
The register machine has registers, indexed addressing, a pc and all the sort of normal things one would expect.
The machine has it's own (abstract) instruction set, which serves mainly to give understandable names.
The mapping to arm is quite straightforward.
Ruby is very dynamic, and so it has a relatively large run-time. Parfait is that Run-time.
Parfait includes all the functionality a ruby program could not do without, Array, Hash, Object, Class, etc.
Parfait does not include any stdlib or indeed core functionality if it doesn't have too.
Parfait is coded in ruby, but not all functionality can be coded in ruby, so there is Builtin
Builtin is the part of the vm that can not be coded in ruby. It is not, as may be imagined, a set of instructions,
but rather a set of modules.
Modules of Builtin have functions that implement functionality that can not be coded in ruby. Ie array access.
The functions take a VM::Method and provide the code as a set of instructions. This may be seen as the assembler
layer if the vm.