Notes
2026/03/31
The goal is to build a language that use the same bytecode as input and output, so that the same bytecode VM can operate in stages.
TUPLE instruction that doesn't just encode how many (logical) elements on the stack it contains (that's the bytecode-as-input perspective) but also how many stack slots the entire tuple occupies, which is the sum of the sizes of its elements and all their descendants (that's the bytecode-as-runtime-representation perspective).CALL instruction, which specifies at which stage it is called, from 0 to n. This number effectively represents a “delay”, because calls at stage 0 are called immediately, while calls at stage 1 will be called when the output bytecode of stage 0 is evaluated in the next stage.CALL instructions in the resulting output bytecode are decremented by that minimum stage value.CALL instructions targeting the stage currently being evaluated? This would make it possible for a stage to decide whether or not it's done, but would break the guarantee of having a fixed number of stages. It nevertheless seems like supporting an arbitrary number of (dynamic) stages would be a valuable feature, as it allows a stage to signal that some of its calls aren't done, while allowing the rest of the evaluation of that stage to continue. A stage would then have to emit a CALL instruction of stage 0 (the one currently being executed), possibly through a special DELAYED_CALL instruction.0 to n semantics and to keep runtime calls unannotated, while annotating comptime stages, e.g. with @foo(...) for a comptime call that happens before runtime and @@foo(...) for a call that happens at the comptime stage before the comptime stage before runtime. (It might also make sense to have a separate “delay” annotation that goes the opposite way and marks function calls as happening in a later runtime stage.)n might be called in stage n, we want to guarantee that staged evaluation happens bottom-up, so that functions fully evaluate any staged calls inside their bodies before they are themselves called. If function instructions are assumed to point to an offset in the (input) bytecode, we need to maintain a mapping from input bytecode offset to (already evaluated) functions.