mostly comments
This commit is contained in:
parent
8d7b353f33
commit
7df1490da8
63
lib/ast/README.md
Normal file
63
lib/ast/README.md
Normal 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.
|
@ -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)}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user