Work's been hectic lately, so I haven't had as much time to work on Ocean, with other responsibilities at home and such. Anyway, here's what's been happening of late. The byte code generator for the bootstrapper is almost done. So, as the ultimate test, I started writing the interpreter. Nothing fancy, nothing interesting (yet). I quickly hit a roadblock. Picking types for fields works pretty well, however, types for functions (methods, if you prefer that parlance) do not. The return type is not inferred at all, which causes an issue when trying to infer types for some variables and the parameter types are also not inferred. The attempts to fix these bugs quickly and easily have resulted in some clumsy code (like, for example, a "junk generator" that is used to generate "throw away" byte code and infer types).
So, a decision needs to be made. Here are the ideas I am looking at. Resurrecting the C# interpreter (it was deleted from Subversion a while ago) and using it to interpret the compiler compiling itself and the "real" interpreter. This has a great deal of merit. The C# interpreter was pretty much working, except for a few features that were missing like continuations and macros. This need not be a problem. I do not typically use either feature when writing Scheme code and could probably avoid it. However, it might prove to be easier to use these advanced features in the code for the "real" compiler, as it is planned to include some rather beefy features behind the scenes. This is not a deal breaker for two reasons. First of all, the language the bootstrapper understands does not currently support either of these features, so if the interpreter does not offer them, it is not losing any ground. Continuations could probably be implemented slowly, but accurately in this ethereal "bootstrapping interpreter" without too much extra work. Alternatively, something truly odd (and slow) could be done. The C# interpreter could be used to interpret a fully featured interpreter which itself interprets the compiler compiling itself and the fully featured interpreter. So, the idea would look like this:
C# Interpreter -> Scheme Interpreter -> Compiler (as it compiles itself and the Scheme Interpreter).
The idea wouldn't be fast when building, but it would allow fully featured code to be used in the compiler itself. If continuations were added to the C# interpreter and macros (through an external library, perhaps) to the Scheme, the work could be split and all the features attained.
The competing plan of action is to continue implementing the bootstrap compiler. The compiler itself could use a simple, aggressive form of SUA based on Algorithm 2.1 in the paper "Storage Use Analysis and its Applications" by Manuel Serrano and Marc Feeley (available here). Types could then be inferred and the code cleaned. Continuations could wait until they are built with the final compiler and macros could be added to the interpreter as above so that the picture becomes:
C# Compiler -> Scheme Interpreter -> Scheme Compiler (compiling itself and the interpreter)
We could then gain macros, but not continuations, when writing the compiler itself and we could use neither in the Scheme interpreter. The build, however, should be much quicker.
What to do? I am leaning heavily towards the latter and will probably start writing some code to see how it works out. I expect macros to be a far more important feature for this type of work than continuations which are, largely, a fancy form of goto. If continuations are used often, it amounts to high-brow spaghetti code, made with bigger and badder spaghetti.