Topaz is a new VM heavily based on Sean Barrett's SLUX. The VM has the following rough goals:
Random bits:


Data types:


Stuff in the file:

The file layout is a header with stuff (slux has a checksum, which seems like a potentially cool idea), then a list of special objects, then a list of property id/property names, then all the object definitions, then all the string definitions, then all the list/hash definitions, then all the function definitions.

The list of special objects is a set of (id number, special-type string) pairs. The id number is that of some object used elsewhere in the game (it can be defined in the object definition section but that definition will be ignored), and the special type is 'system' or 'glk' or 'regex' or something. This is the type not the name of the object, which can be anything in the compiler (and just gets reduced to an id number anyway). An object mentioned in the special objects list is considered to be defined, and any method calls on the object are handled by the interpreter internally rather than actually looking up the method definition and evaluating that. For example, if object 32 is of type 'system', and you call 32.'exit', it might exit the program or something. It won't actually attempt to look up the exit property and evaluate it on the object. It should probably be an error to have multiple objects defined as being the same type.

The property name/property id thing is a mapping of property names to id numbers. The bytecode generally only uses id numbers to reference properties, and if you use a string it needs to be converted to a thing of type property (which is a property id number) first. The use of this table is 1) to handle merging different bytecode files and 2) people can use dynamic property lookup (ie, strings) and this table provides for the conversion. Also 3) for debugging.

Objects are of course a list of object id number, size of definition, object flags, superclass list, then a list of property id/value pairs. Values are strings/ints/lists/hashes/objects/property -- these are all of course references to the actual thing, not the things themselves (except ints).

The string definitions are just, I dunno, a bunch of strings. They should be compressed somehow, maybe a la the z-machine or maybe a la how slux does it or maybe something fancier. Some provision should be made for internationalization/unicode.

List/hash definitions. I figure lists and hashes can go in the same space, and hashes'll just be lists that definitely have even size. The only downside is now you have to store a type bit before each thing in the list/hash section to say whether it's a list or a hash, right?

Function definitions. This is, I guess, just a big block of bytecode that gets indexed into. Ok, no, wait, functions should probably have lists of their bytecode size, and how much stack space they'll take up, and how many arguments they take, and so on. This could all get handled with initial opcodes in the function but I'm not sure there's a win doing it that way.

And that's it for that.


The I/O system. You can change the I/O system at will in this VM. There is a method on the system object (which means "the object of type 'system'") which gets you a new I/O object of the requested type (or fails, and presumably returns nil or something). The 'bootstrap' I/O system is guaranteed to exist and be requestable (and in fact is requested at startup). This supports, I dunno, a single stream a la stdout and a single line-input-only stream a la stdin. It's possible that the io system object should always be referenced as system.io like how java does it. The alternative is, what? The programmer will have to call request_io("bootstrap"), -- ok, I can already see this is going to be lamer. So system.request_io("glk") will either set the I/O system to glk or do nothing, and return 1/0 accordingly, and you can access the I/O system object with system.io.
I think the only other thing is opcodes. Presumably it works like this:
.. no, ok, I'm not going to write out all the opcodes. There should be all the obvious ones, from the z-spec/slux spec/tads spec (ha ha). We can eliminate any of the ones dealing with I/O, and some things that are not called particularly often should be methods on special objects, not opcodes in themselves. So the questions are, basically,
I think this is the whole spec. Ok, except for restore/restart/undo. The way those work (plus start, when you first load the game) is, when one of the four is executed, the call stack is cleared, every object in the game is reset to the appropriate state, and then system.main is called, with one of 'start', 'restore', etc being passed as an argument to it. Uh, and this suggests that you can in fact have user-defined methods on special objects.