Retro 11.6.1 coming soon

This week I've received a few patches from Marc Simpson which fix a bug in retro.fs (Ngaro in ANS Forth) and add support for treating doc{ }doc as comments in vim.

I'll be pushing a small maintenance update incorporating these (and possibly some other small things) for Retro 11.6 next week. If anyone has patches they want included, please send them to me so I can have time to test and merge them.

Apologue updates

I've been working on Apologue each evening this week. And a lot of progress has been made. When I began working on this I had just finished putting together the skeleton of a user interface, which was very rough. It consisted of a code editor, and a stack display (which was literally just a text representation of the stack items in a text area).

Now it's grown into a much more complete tool. I have an editor view, with the code editor, stack display, and a status/error log area. There's a memory browser which lets me browse the named symbols in the dictionary or any allocated slice, viewing the raw values, ASCII values, and byte codes for each item.

I also have begun a documentation browser, though it's still very sparse at present.

Loading screen

Loading screen

The editor / stack view

The editor / stack view

The memory browser.

The memory browser.

Embedded documentation

Embedded documentation

Overall I'm pretty pleased with it. There's a lot of stuff I still want to do, but it's working well enough that I can do most of my Parable experiments on my iPad now. In the near future I'm planning to expand the embedded documentation to cover everything I've written so far, make a few further improvements to the memory browser, and enable persistent sessions so that I don't have to manually reload/evaluate to continue where I left off.

Apologue: Parable on iOS

I recently began working on an interface for Parable using a native iOS UI. At present it's still really rough in terms of UI, but it has finally reached a point where the core functionality is working.

I have considered running code on the device, but for now will use the server-side implementation of Parable instead. The Python implementation is already working nicely and is much better tested than the C implementation. And this avoids a bunch of battery drain, memory, and onboard performance issues. (Though it does present some issues with regards to bandwidth. A typical response set is around 500KiB in size).

So at this point I can launch it, enter code, and get a resulting stack. But there's a lot more that can be done. The server side response set includes a lot of other things (like the symbol table, memory maps, and a memory dump) that should be exposed via the client UI. My intention now is to finish the client side data parsing, refactor the view and model implementations, and then refine the interface into something that's substantially more pleasing to work with. Then I can start adding in other useful things, like a dictionary and memory view.

It also gives me a motivation to improve the server side. I really should cache the stuff that's not immediately needed (raw memory dump), and maybe allow for incremental modifications to a session so that each evaluation doesn't have to start from scratch.

An Overview of Function Classes in Retro

For the past few generations, the interpreter and compiler for Retro have been built around a concept I refer to as a function class. Specifically, the behavior of the system is determined by functions that handle the named symbols in the dictionary as they are encountered. For instance, things that are always run when encountered are handled by one function. Things that get compiled during a definition, but run when interpreting are handled by a separate function. And so forth.

This is a little different than in a classical Forth approach. A classical Forth will have a bit field in the header, with a bit for "immediate" functions, and maybe others for "compile only" or other special cases. Retro instead has a pointer to the class handler function for the entry.

When a function is found, a pointer to its definition (xt) is pushed to the stack. Then a pointer to the class handler is pushed. And finally the class handler is invoked (normally via withClass). The handler will look at the xt on the stack, and any internal system states it cares about, then do the proper action with the xt.

So a simple interpreter-only system basically just a simple class handler something like:

: .always-run( Xt - )
do ;

If we want to allow for compiling, this is easy enough to add. We could simply add a compiler variable to tell us if the compiler is on or off and then do:

: .compile-or-run( Xt - )
compiler @ [ , ] [ do ] if ;

There are no defined limits on the number of possible class handlers, or the amount of state they can process. We could easily define class handlers for different data types, functions that can only be invoked at compile time, optimizing definitions, inlining functions, or other behaviors with ease.

This has many benefits to me. It keeps the main processing loop simple, allows easy expansion and customization going forward, and neatly folds a lotion functionality  into a simple conceptual model.