bit of line wrapping

This commit is contained in:
Torsten Ruger 2015-03-25 17:29:39 +02:00
parent d758a23eb6
commit aee36d9f5f
7 changed files with 99 additions and 82 deletions

View File

@ -57,8 +57,8 @@ Parse simple code, using Parslet. This has been seperated out as it's own gem, s
Parsing is a surprisingly fiddly process, very space and order sensitive. But Parslet is great and simple
expressions (including function definitions and calls) are starting to work.
I spent some time on the parse testing framework, so it is safe to fiddle and add. In fact it is very modular and
so ot is easy to add.
I spent some time on the parse testing framework, so it is safe to fiddle and add.
In fact it is very modular and so ot is easy to add.
### Virtual: Compile the Ast
@ -94,8 +94,8 @@ So the current staus is that i can
#### Blocks
Implement ruby Blocks, and make new vm classes to deal with that. This is in fact a little open, but i have a general
notion that blocks are "just" methods with even more implicit arguments.
Implement ruby Blocks, and make new vm classes to deal with that. This is in fact a little open,
but i have a general notion that blocks are "just" methods with even more implicit arguments.
#### Exceptions
@ -103,8 +103,9 @@ Implement Exceptions. Conceptionally this is not so difficult in an oo machine a
I have a post about it http://salama.github.io/2014/06/27/an-exceptional-though.html
which boild down to the fact that we can treat the address to return to in an exception quite like a return address
from a function. Ie just another implicit parameter (as return is really an implicit parameter, a little like self for oo)
which boild down to the fact that we can treat the address to return to in an exception quite
like a return address from a function. Ie just another implicit parameter
(as return is really an implicit parameter, a little like self for oo)
### C linking

View File

@ -6,10 +6,11 @@ The Ast (abstract syntax tree) is created by salama-reader gem and the classes d
The code in this directory compiles the AST to the virtual machine code.
If this were an intrepreter, we would just walk the tree and do what it says. Since it's not things are a little more
difficult, especially in time.
If this were an intrepreter, we would just walk the tree and do what it says.
Since it's not things are a little more difficult, especially in time.
When compiling we deal with two times, compile-time and run-time. All the headache comes from mixing those two up.*
When compiling we deal with two times, compile-time and run-time.
All the headache comes from mixing those two up.*
Similarly, the result of compiling is two-fold: a static and a dynamic part.
@ -23,27 +24,29 @@ Each ast class gets a compile method that does the compilation.
#### Compiled Method and Instructions
The first argument to the compile method is the CompiledMethod. All code is encoded as a stream of Instructions in the
CompiledMethod. Instructions are stored as a list of Blocks, and Blocks are the smallest unit of code, which is
always linear.
The first argument to the compile method is the CompiledMethod.
All code is encoded as a stream of Instructions in the CompiledMethod.
Instructions are stored as a list of Blocks, and Blocks are the smallest unit of code,
which is always linear.
Code is added to the method (using add_code), rather than working with the actual instructions. This is so each
compiling method can just do it's bit and be unaware of the larger structure that is being created.
Code is added to the method (using add_code), rather than working with the actual instructions.
This is so each compiling method can just do it's bit and be unaware of the larger structure that is being created.
The genearal structure of the instructions is a graph (what with if's and whiles and breaks and what),
but we build it to have one start and *one* end (return).
#### Messages and frames
The virtual machine instructions obviously operate on the virtual machine. Since the machine is virtual,
we have to define it, and since it is oo we define it in objects.
The virtual machine instructions obviously operate on the virtual machine.
Since the machine is virtual, we have to define it, and since it is oo we define it in objects.
Also it is important to define how instructions operate, which is is in a physical machine would be by changing
the contents of registers or some stack.
Also it is important to define how instructions operate, which is is in a physical machine would
be by changing the contents of registers or some stack.
Our machine is ot a register machine, but an object machine: it operates directly on objects and also has no seperat
stack, only objects. There are a number of objects which are accessible, and one can think of these (their addresses)
as register contents. And one wouldn't be far off as that is the implementation
Our machine is ot a register machine, but an object machine: it operates directly on objects and
also has no seperate stack, only objects. There are a number of objects which are accessible,
and one can think of these (their addresses) as register contents.
And one wouldn't be far off as that is the implementation
The objects the machine works on are:
@ -52,12 +55,14 @@ The objects the machine works on are:
- Self
- NewMessage
and working on means, these are the only objects which the machine accesses. Ie all others would have to be moved first.
and working on means, these are the only objects which the machine accesses.
Ie all others would have to be moved first.
When a Method needs to make a call, or send a Message, it creates a NewMessage object.
Messages contain return addresses and arguments.
Then the machine must find the method to call. This is a function of the virtual machine and is implemented in ruby.
Then the machine must find the method to call.
This is a function of the virtual machine and is implemented in ruby.
Then a new Method receives the Message, creates a Frame for local and temporary variables and continues execution.
@ -66,13 +71,15 @@ The important thing here is that Messages and Frames are normal objects.
And interestingly we can partly use ruby to find the method, so in a way it is not just a top down transformation.
Instead the sending goes back up and then down again.
The Message object is the second parameter to the compile method, the run-time part as it were. Why? Since it only
exists at runtime: to make compile time analysis possible (it is after all the Virtual version, not Parfait. ie
compile-time, not run-time). Especially for those times when we can resolve the method
at compile time.
The Message object is the second parameter to the compile method, the run-time part as it were.
Why? Since it only exists at runtime: to make compile time analysis possible
(it is after all the Virtual version, not Parfait. ie compile-time, not run-time).
Especially for those times when we can resolve the method at compile time.
*
As ruby is a dynamic language, it also compiles at run-time. This line of thought does not help though as it sort of mixes
the seperate times up, even they are not. Even in a running ruby programm the stages of compile and run are seperate.
Similarly it does not help to argue that the code is static too, not dynamic, as that leaves us with a worse working model.
As ruby is a dynamic language, it also compiles at run-time. This line of thought does not help
though as it sort of mixes the seperate times up, even they are not.
Even in a running ruby programm the stages of compile and run are seperate.
Similarly it does not help to argue that the code is static too, not dynamic,
as that leaves us with a worse working model.

View File

@ -1,7 +1,7 @@
### Builtin module
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 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.

View File

@ -18,27 +18,27 @@ And thus parfait can be used at run-time.
It's too simple: just slips off the mind like a fish into water.
Parfait has a brother, the Builtin module. Builtin contains everything that can not be coded in ruby, but we stil need
(things like array access).
Parfait has a brother, the Builtin module. Builtin contains everything that can not be coded in ruby,
but we stil need (things like array access).
#### Example: Message send
It felt a little stupid that it took me so long to notice that sending a message is very closely related to the
existing ruby method Object.send
Off course Object.send takes symbol and the arguments and has the receiver, so all the elements of our Messaage are there.
And the process that Object.send needs to do is exactly that: send that message, ie find the correct method according to
the old walk up the inheritance tree rules and dispatch it.
Off course Object.send takes symbol and the arguments and has the receiver, so all the elements of our
Messaage are there. And the process that Object.send needs to do is exactly that:
send that message, ie find the correct method according to the old walk up the inheritance tree rules and dispatch it.
And as all this happens at runtime, "all" we have to do is code this logic. And since it is at runtime,
we can do it in ruby (as i said, this get's compiled and run, just like the program).
But what about the infinite loop problem:
There was a little step left out: Off course the method gets compiled at compile-time and so we don't just blindly dispatch:
we catch the simple cases that we know about: layout, type instance variables and compile time known functions. Part of
those are some that we just don't allow to be overridden.
Also what in ruby is object.send is Message.send in salama, as it is the message we are sending and which defines all the
data we need (not the object). The object receives, it does not send.
There was a little step left out: Off course the method gets compiled at compile-time and so
we don't just blindly dispatch: we catch the simple cases that we know about:
layout, type instance variables and compile time known functions.
Part of those are some that we just don't allow to be overridden.
Also what in ruby is object.send is Message.send in salama, as it is the message we are sending and
which defines all the data we need (not the object). The object receives, it does not send.

View File

@ -23,27 +23,28 @@ There are four virtual objects that are accessible (we can access their variable
- Frame (local and tmp variables)
- NewMessage ( to build the next message sent)
These are pretty much the first four registers. When the code goes from virtual to register, we use register instructions
to replace virtual ones.
These are pretty much the first four registers. When the code goes from virtual to register,
we use register instructions to replace virtual ones.
Eg: A Virtual::Set can move data around inside those objects. And since in Arm this can not be done in one instruciton,
we use two, one to move to an unused register and then into the destination. And then we need some fiddling of bits
to shift the type info.
Eg: A Virtual::Set can move data around inside those objects.
And since in Arm this can not be done in one instruction, we use two, one to move to an unused register
and then into the destination. And then we need some fiddling of bits to shift the type info.
Another simple example is a Call. A simple case of a Class function call resolves the class object, and with the
method name the function to be found at compile-time. And so this results in a Register::Call, which is an Arm
instruction.
Another simple example is a Call. A simple case of a Class function call resolves the class object,
and with the method name the function to be found at compile-time.
And so this results in a Register::Call, which is an Arm instruction.
A C call
---------
Ok, there are no c calls. But syscalls are very similar. This is not at all as simple as the nice Class call described
above.
Ok, there are no c calls. But syscalls are very similar.
This is not at all as simple as the nice Class call described above.
For syscall in Arm (linux) you have to load registers 0-x (depending on call), load R7 with the syscall number and then
issue the software interupt instruction. If you get back something back, it's in R0.
For syscall in Arm (linux) you have to load registers 0-x (depending on call), load R7 with the
syscall number and then issue the software interupt instruction.
If you get back something back, it's in R0.
In short, lots of shuffling. And to make it fit with our four object architecture, we need the Message to hold the data
for the call and Sys (module) to be self. And then the actual functions do the shuffle, saving the data and restoring it.
In short, lots of shuffling. And to make it fit with our four object architecture,
we need the Message to hold the data for the call and Sys (module) to be self.
And then the actual functions do the shuffle, saving the data and restoring it.
And setting type information according to kernel documentation (as there is no runtime info)

View File

@ -2,9 +2,11 @@
Knowing what's going on while coding salama is not so easy: Hence the need to look at code dumps
Hence the need for a code/object file format (remember an oo program is just objects, some data, some code, all objects)
Hence the need for a code/object file format
(remember an oo program is just objects, some data, some code, all objects)
I started with yaml, which is nice in that it has a solid implementation, reads and writes, handles arbitrary objects, handles graphs and is a sort of readable text format.
I started with yaml, which is nice in that it has a solid implementation, reads and writes,
handles arbitrary objects, handles graphs and is a sort of readable text format.
But the "sort of" started to get to me, because
@ -26,7 +28,8 @@ The main starting goal was quite like yaml, but with
Ok, so we all heard about object files, it's the things compilers create so we don't have to have
huge compiles and can link them later.
Much fewer know what they include, and that is not because they are not very useful, but rather very complicated.
Much fewer know what they include, and that is not because they are not very useful,
but rather very complicated.
An object machine must off course have it's own object files, because:
@ -44,11 +47,13 @@ And so this is a little start, just some outputter.
#### Direction
The way this is meant to go (planned for 2020+) was a salama core with only a sof parser (as that is soo much simpler).
The way this is meant to go (planned for 2020+) was a salama core with only a sof parser
(as that is soo much simpler).
Then to_ruby for all the ast classes to be able to roundtrip ruby code.
Then go to storing sof in git, rather than ruby.
Then write a python/java parser and respective runtime conversion. Extracting common features. With the respective
to_python on the ast's to roundtrip that too. Have to since by now we work on sof's. Etc . ..
Then write a python/java parser and respective runtime conversion. Extracting common features.
With the respective to_python on the ast's to roundtrip that too.
Have to since by now we work on sof's. Etc . ..

View File

@ -8,30 +8,31 @@ 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.
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.
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 gem from source. Here we add compile functions to ast classes and
comile the ast layer into Virtual:: objects
*Ast* instances get created by the salama-reader gem from source.
Here we add compile functions to ast classes and comile the ast layer into Virtual:: objects
The main objects are BootSpace (lots of objects), BootClass (represents a class),
CompiledMethod (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.
**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 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.
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
@ -42,7 +43,8 @@ Object oriented systems have data hiding. So we have access to the inner state o
- 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.
A single instructions (Set) allows movement of data between these.
There are compare, branch and call intructions too.
### Micro
@ -53,7 +55,8 @@ As such we are aiming for integer and reference (type) support, and a minimal cl
(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 CompiledMethods in code and neccesarily machine dependant.
**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 CompiledMethods in code and neccesarily machine dependant.