mostly comments

This commit is contained in:
Torsten Ruger 2014-07-25 11:48:06 +03:00
parent 8d7b353f33
commit 7df1490da8
4 changed files with 71 additions and 8 deletions

63
lib/ast/README.md Normal file
View File

@ -0,0 +1,63 @@
### Ast
The Ast (abstract syntax tree) is created by kide-reader gem and the classes defined there
### Compiling
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.
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.
- the static part are objects like the constants, but also defined classes and their methods
- the dynamic part is the code, which is stored as streams of instructions in the MethodDefinition
Too make things a little simpler, we create a very high level instruction stream at first and then run
transformation and optimisation passes on the stream to improve it.
Each ast class gets a compile method that does the compilation.
#### Method Definition and Instructions
The first argument to the compile method is the MethodDefinition. All code is encoded as a stream of Instructions in the
MethodDefinition. In fact Instructions are a linked list and so the MethodDefinition only hold the head, and the current
insertion point.
Code is added to the method (using add()), rather than working with the actual instructions. This is so each compile 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.
Also it is important to define how instructions, which is is in a ohysical machine 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 stack.
When a Method needs to make a call, or send a message, it creates a Message object. Messages contain return addresses and
arguemnts.
Then the machine must find the method to call.
Then a new Method receives the message, creates a Frame for local and temporary variables and continues execution.
The important thing here is that Messages and Frames are normal objects.
Anf interestingly we can partly use ruby to find the method, so in a way it is not just a top down transformation. but
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.
*
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

@ -3,7 +3,7 @@ module Ast
class CallSiteExpression < Expression
# attr_reader :name, :args , :receiver
@@counter = 0
def compile method , message
me = receiver.compile( method, message )
with = args.collect{|a| a.compile( method,message)}

View File

@ -11,7 +11,7 @@ module Virtual
# - 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 and "object" . A fixed number of objects exist
# 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.
@ -19,12 +19,12 @@ module Virtual
# The next step transforms to the register machine layer, which is what actually executes.
#
# More concretely, an virtual machine is a sort of oo turing machine, it has a current instruction, executes the
# 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 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
@ -34,9 +34,9 @@ module Virtual
def initialize
the_end = Halt.new
@frame = Message.new(the_end , the_end , :Object)
@message = Message.new(the_end , the_end , :Object)
end
attr_reader :frame
attr_reader :message
# run the instruction stream given. Instructions are a graph and executing means traversing it.
# If there is no next instruction the machine stops

View File

@ -13,7 +13,7 @@ module VirtualHelper
parts = Parser::Transform.new.apply(syntax)
machine = Virtual::Machine.new
main = Virtual::MethodDefinition.main
expressions = parts.compile( main, machine.frame )
expressions = parts.compile( main, machine.message )
should = YAML.load(@output.gsub("RETURN_MARKER" , "\n"))
assert_equal should , expressions , expressions.to_yaml.gsub("\n" , "RETURN_MARKER") + "\n" + expressions.to_yaml
end