On a very high level the compilation and execution of scripts works as you listed.
There is no documentation for the code. I do try to keep the code comments as clear as possible though, and the code is broken down by the logical modules. Each file normally only holds one class, with a similar name as the file itself, so it should be easy to localize in which file to look for something.
Here's a brief explanation of what the principal modules are:
as_tokenizer.cpp has the logic for identifying individual tokens in the source code. It uses the definitions in as_tokendef.h for that.
as_parser.cpp has the logic for interpreting the sequence of tokens into declarations, statements, etc (i.e. building the AST)
as_builder.cpp orchestrates the script compilation. it is responsible for passing the source code to the parser, identify variables, types, and functions that has been declared, and then invoke the compiler to compile the bytecode for the functions
as_compiler.cpp has the logic for compiling the bytecode based on the AST (this is by far the most complex piece of the library)
as_bytecode.cpp holds the intermediate structure that the compiler creates and also the logic for doing post-compilation bytecode optimizations
as_restore.cpp has the logic for saving and loading already compiled bytecode (this is the second most complex piece of the library)
as_module.cpp is the structure where the final compiled script is stored
as_context.cpp is the virtual machine that executes the bytecode
as_engine.cpp is the central piece that holds everything together, and where the application registered interface is stored :)
The SVN has a test_features project that I use for testing. Every time anything is changed I compile and execute this to verify the result. This is to avoid unexpected side-effects (of course, sometimes they slip through anyway ). With every bug I fix I add new test cases to this project so the same bugs shouldn't reoccur later on.
Every time I implement something new, I usually start by thinking about what needs to be changed in the code (usually by marking the impacts with // TODO: in the code itself). Once I have a fair idea of the impacts I write the test cases with the expected results, and only after this do I start the actual coding of the new feature. This way I can make incremental changes without breaking everything else.