The road ahead ( 2016-07-26 )
So, the plan, in short:
- I need to work a little more on docs. Reading them i notice they are still not up to date
- The Type system needs work
- The Method-Function relationship needs to be created
- Ruby compiler needs to be written
- Parfait moves back completely into ruby land
- Soml parser should be scrapped (or will become redundant by 2-4)
- The memory model needs reworking (global not object based memory)
2. Type system
A Type is an ordered list of associations from name to BasicType (Object/Integer). The class exists off course and has been implemented as an array with the names and BasicTypes laid out in sequence. This is basically fine, but support for navigation is missing.
The whole type system is basically graph. A type A is connected to a type B if it has exactly one different BasicType. So A needs to have exactly the same names, and exactly one different BasicType. Another way of saying this is that the two types are related if in the class that Type represents, exactly one variable changes type. This is off course exactly what happens when an assignment assigns a different type.
A and B are also related when A has exactly one more name entry than B , but os otherwise identical. This is what happens when a new variable is added too a class, or one is removed.
The implementation needs to establish this graph (possibly lazily), so that the traversal is fast. The most likely implementation seems a hash, so a hashing function has to be designed and the equals implemented.
3. Method-Function relationship
Just to get the naming clear: A method is at the ruby level, untyped. A Class has references to Methods.
Whereas a Function is at the level below, fully typed. Function’s arguments and local variables have a BasicType. Type has references to Functions.
A Function’s type is fully described by the combination of the arguments Type and the Frame Type. The Frame object is basically a wrapper for all local variables.
A (ruby) Method has N Function “implementations”. One function for each different combination of BasicTypes for arguments and local variables. Functions know which Method they belong to, because their parent Type class holds a reference to the Class that the Type describes.
4. Ruby Compiler
Currently there is only the Function level and the soml compiler. The ruby level / compiler is missing.
The Compiler generates Class objects, and Type objects as far as it can determine name and BasicTypes of the instance variables.
Then it creates Method objects for every Method parsed. Finally it must create all functions that needed. In a first brute-force approach this may mean creating functions for all possible type combinations.
Call-sites must then be “linked”. Linking here refers to the fact that the compiler can not determine how to call a function before it is created. So the functions get created in a first pass and calls and returns “linked” in a second. The return addresses used at the “soml” level are dependent on the BasicType that is being returned. This involves associating the code labels (at the function level) with the ast nodes they come from (at the method level). With this, the compiler ensures that the type of the variable receiving the return value is correct.
5. Parfait in ruby
After SOML was originally written, parts of the run-time (parfait) was ported to soml. This was done with the idea that the run-time is low level and thus needs to be fully typed. As it turns out this is only partly correct, in the sense that there needs to exist Function definitions (in the sense above) that implement basic functionality. But as the sub-chapter on the ruby compiler should explain, this does not mean the code has to written in a typed language.
After the ruby-compiler is implemented, the run-time can be implemented in ruby. While this may seem strange at first, one must remember that the ruby-compiler creates N Functions of each method for all possible type combinations. This means if the ruby method is correctly implemented, error handling, for type errors, will be correctly generated by the compiler.
6. SOML goodbye
By this time the soml language can be removed. Meaning the parser for the language and all documentation is not needed. The ruby-complier compilers straight into the soml internal representation (as the soml parser) and because parfait is back in ruby land, soml should be removed. Which is a relief, because there are definitely enough languages in the world.
7. Memory model rework
Slightly unrelated to the above (read: can be done at the same time), the memory model needs to be expanded. The current per object fake memory works fine, but leaves memory management in the compiler.
Since ultimately memory management should be part of the run-time, the model needs to be changed to a global one. This means class Page and Space should be implemented, and the fake memory mapped to a global array.