vihaco / virtual ISA & machine framework
Author’s guide
  1. Start here
  2. The mental model
  3. Your first machine
  4. Essential concepts
  5. Dialects and instructions
  6. Writing components
  7. Preparing messages
  8. Stack inputs and outputs
  9. Writing composites
  10. Executing one instruction
  11. Handling effects
  12. Running programs
  13. Images and Loadables
  14. Parsing source
  15. Loading SST programs
  16. Emitting SST from a compiler
  17. Binary formats
  18. Patterns for larger machines
  19. Testing and extending
  20. Pattern parser reference

Loading SST programs

SST’s future: SST may become unsupported or be superseded by a bytecode format plus a disassembler. It is not a promised long-term compiler target.

If you’re writing a compiler, start with emitting SST from a compiler for the file format and metadata you must produce. This chapter describes the consuming loader.

Loading an SST program means choosing its section, reading the declarations, resolving symbols, and building a module. Do this outside the mutable execution machine, then pair the result with the machine when it’s ready.

Read a section

Start with SstFile<C>::from_text(source). The type C interprets the file’s global context; use NoContext when you have no global data. From root(), child(name) and children() let you pick sections for independently loaded programs. These section names describe the file structure, rather than routes to instruction destinations.

A section view gives you the header and source body. Pass it to ParsedModule::<SourceInstruction, Type, Header>::parse_section(section), using your composite’s syntax instruction type as SourceInstruction. You’ll get header declarations and functions with typed instruction bodies.

Collect declarations before lowering

Use HeaderDeclarations<Declaration> to parse the declarations individually. Your metadata-class enum can include ProgramMetadata alongside your own configuration declarations. Collect them into a state object you write, reject duplicates, and check required settings before building execution artifacts. You can prepare the declarations in a different order from how they appear in the file.

ProgramMetadata supplies every non-code field:

  • Functions, with their signatures, reserved local counts, and instruction ranges.
  • Labels, strings, constants, and source symbols.
  • The entry function, if there is one.
  • Your application’s extra metadata.

The order of each table determines its indices. Function names, parameter names, and filenames refer into the string table. main_function selects an entry in the function table; it isn’t an instruction address.

Function ranges count decoded instructions and use an exclusive end address. A function’s local count includes its parameters. The producer supplies any extra locals; the loader doesn’t infer them from instructions.

Prepare capabilities and lower

MetadataLoweringContext::new(&metadata) prepares the standard function, label, and string capabilities. If custom instructions need more lookup services, you can extend it or use your own context.

Call lower_functions_with_metadata(functions, &metadata, &mut context) to check the declarations and tables, then lower the bodies. Before lowering each function, the driver prepares its full local label scope. That’s how a branch can refer to a label farther down the function.

Assemble the result with metadata.into_module(code). It keeps your table order and checks standard value references. If your declarations need a different runtime metadata type, use map_extra. You can then wrap the module in an Image and pair it with a machine in a Loadable.

If lowering fails, it returns no partial instruction vector. Any changes already made to the context remain, though; the pipeline doesn’t roll them back.

Run the complete example

The repository’s Loadable example and its SST file put the whole sequence together. They include an application header, tables in a different order from the function bodies, a helper call, and a forward branch.

Run it from a checkout:

cargo run -p vihaco-stdlib --features program-image-execution --example loadable

The result is [42]. To try another file, pass its source path after --. Once construction finishes, the loader drops the file view and source. The image owns the runtime instructions and metadata it needs.

Binary formats covers loading encoded programs.

On this page
  1. Read a section
  2. Collect declarations before lowering
  3. Prepare capabilities and lower
  4. Run the complete example