ivm

package
v1.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 22, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package ivm implements a stack-based instruction VM for the English language. It compiles AST programs to flat instruction sequences (chunks) and executes them with a register-free, stack-based dispatch loop.

Compared with the tree-walk evaluator in the vm package, the instruction VM:

  • Avoids the overhead of virtual method dispatch on each AST node
  • Produces compact binary bytecode that is faster to load than serialised AST
  • Makes future optimisations (constant folding, dead-code elimination) easier

File layout:

ivm.go       – package doc, public entry points (Compile, Execute)
opcode.go    – Opcode type and opcode constants
chunk.go     – Chunk (instruction stream + constant pool + name pool)
compiler.go  – Compiler: walks the AST and emits instructions
machine.go   – Machine: runs a Chunk using a value stack
encoding.go  – Binary serialisation / deserialisation of Chunks

Index

Constants

View Source
const InstructionFormatVersion uint8 = 3

InstructionFormatVersion is the bytecode format version for instruction-based .101 files.

Variables

View Source
var MagicBytes = []byte{0x10, 0x1E, 0x4E, 0x47}

Magic bytes and version for .101 instruction-format files.

Functions

func Decompile

func Decompile(chunk *Chunk) string

Decompile decompiles chunk and returns Python source code.

func EncodeChunk

func EncodeChunk(chunk *Chunk) ([]byte, error)

EncodeChunk serialises a Chunk to binary (without file header).

func EncodeFile

func EncodeFile(chunk *Chunk) ([]byte, error)

EncodeFile serialises chunk with magic header + version byte.

func EncodeFileWithSource

func EncodeFileWithSource(chunk *Chunk, source string) ([]byte, error)

EncodeFileWithSource serialises chunk with magic header + version byte and appends the original source code as a trailing section so the file can be transpiled to Python without the original .abc file. The trailer format is: [uint32-LE source_len][source UTF-8 bytes]. If source is empty the trailer is omitted and the output is identical to EncodeFile.

func Execute

func Execute(chunk *Chunk, builtin BuiltinFunc, predefined map[string]interface{}) (interface{}, error)

Execute runs a compiled Chunk and returns the last value (or nil). builtin is the stdlib function dispatcher. predefined is a map of pre-defined constant values (e.g. math.Pi).

func Listing

func Listing(chunk *Chunk, title string, useColor bool) string

Listing produces an opcode-level listing of chunk and all its sub-chunks. title is used in the header (e.g. "<module>", "function add", etc.).

func OpName

func OpName(op Opcode) string

OpName returns a human-readable name for an opcode.

Types

type BinOp

type BinOp uint32

BinOp encodes a binary operator.

const (
	BinAdd BinOp = iota
	BinSub
	BinMul
	BinDiv
	BinMod
	BinEq
	BinNeq
	BinLt
	BinLte
	BinGt
	BinGte
)

func (BinOp) String

func (b BinOp) String() string

String method for BinOp for the listing.

type BuiltinFunc

type BuiltinFunc func(name string, args []interface{}) (interface{}, error)

BuiltinFunc is the stdlib function dispatcher.

type Chunk

type Chunk struct {
	Constants  []interface{} // number (float64), string, bool, nil
	Names      []string      // variable/function names
	Code       []Instruction
	Funcs      []*FuncChunk // user-defined function sub-chunks
	StructDefs []*StructDef // struct type definitions
}

Chunk is a compiled instruction stream together with its supporting data pools.

func Compile

func Compile(prog *ast.Program) (*Chunk, error)

Compile compiles an ast.Program to a Chunk.

func DecodeChunk

func DecodeChunk(data []byte) (*Chunk, error)

DecodeChunk deserialises a Chunk from raw binary (without file header).

func DecodeFile

func DecodeFile(data []byte) (*Chunk, error)

DecodeFile verifies magic + version and deserialises the chunk. Any embedded source trailer is silently ignored; use DecodeFileAll to retrieve it.

func DecodeFileAll

func DecodeFileAll(data []byte) (*Chunk, string, error)

DecodeFileAll verifies magic + version, deserialises the chunk, and returns any embedded source code. The returned source is empty when the file was produced without a source trailer (e.g. compiled with an older version of the tool).

func NewChunk

func NewChunk() *Chunk

NewChunk allocates an empty Chunk.

func (*Chunk) AddConst

func (c *Chunk) AddConst(v interface{}) uint32

AddConst appends a constant to the pool and returns its index. Constants are NOT deduplicated so every literal gets its own slot.

func (*Chunk) AddName

func (c *Chunk) AddName(s string) uint32

AddName appends a name to the pool, deduplicating by value, and returns the index.

func (*Chunk) CurrentPos

func (c *Chunk) CurrentPos() int

CurrentPos returns the index of the next instruction to be emitted. Used to record jump source positions for later patching.

func (*Chunk) Emit

func (c *Chunk) Emit(op Opcode, operand uint32)

Emit appends an instruction to the code stream.

func (*Chunk) PatchJump

func (c *Chunk) PatchJump(pos int, target uint32)

PatchJump overwrites the operand of a previously emitted jump instruction.

type Compiler

type Compiler struct {
	// contains filtered or unexported fields
}

Compiler walks an AST and emits instructions into a Chunk.

type FieldDef

type FieldDef struct {
	Name             string
	TypeName         string
	DefaultExprChunk *Chunk // compiled default-value expression, or nil
}

FieldDef describes a single struct field.

type FuncChunk

type FuncChunk struct {
	Name   string
	Params []string
	Body   *Chunk
}

FuncChunk is the compiled representation of a user-defined function.

type Instruction

type Instruction struct {
	Op      Opcode
	Operand uint32
}

Instruction is a single VM instruction: an opcode plus a 32-bit operand.

type Machine

type Machine struct {
	// contains filtered or unexported fields
}

Machine executes a compiled Chunk.

type Opcode

type Opcode byte

Opcode is a single-byte instruction code.

const (
	// ── Constants ─────────────────────────────────────────────────────────
	OP_LOAD_CONST   Opcode = iota // push constants[operand]
	OP_LOAD_NOTHING               // push nil

	// ── Variables ─────────────────────────────────────────────────────────
	OP_LOAD_VAR           // push env[names[operand]]
	OP_STORE_VAR          // env.Set(names[operand], pop())
	OP_DEFINE_VAR         // env.Define(names[operand], pop(), false)
	OP_DEFINE_CONST       // env.Define(names[operand], pop(), true)
	OP_DEFINE_TYPED       // pop value, pop type_name_str; env.DefineTyped(names[operand], type, val, false)
	OP_DEFINE_TYPED_CONST // pop value, pop type_name_str; env.DefineTyped(names[operand], type, val, true)
	OP_TOGGLE_VAR         // toggle boolean at names[operand]

	// ── Arithmetic / comparison ────────────────────────────────────────────
	OP_BINARY_OP // binary operation; operand encodes BinOp
	OP_UNARY_OP  // unary operation; operand encodes UnaryOp

	// ── Control flow ──────────────────────────────────────────────────────
	OP_JUMP          // jump to operand (absolute)
	OP_JUMP_IF_FALSE // pop condition; jump to operand if false/error
	OP_JUMP_IF_TRUE  // pop condition; jump to operand if true

	// ── Scope ─────────────────────────────────────────────────────────────
	OP_PUSH_SCOPE // push a new child environment
	OP_POP_SCOPE  // restore parent environment

	// ── Functions ─────────────────────────────────────────────────────────
	OP_DEFINE_FUNC // define function; operand = func chunk index in chunk.Funcs
	OP_CALL        // call function; operand = argc<<16 | name_idx
	OP_CALL_METHOD // call method; operand = argc<<16 | method_name_idx; object on stack below args
	OP_RETURN      // return top of stack (or nil if stack empty)

	// ── Output ────────────────────────────────────────────────────────────
	OP_PRINT // print; operand = count<<1 | newline_flag

	// ── Collections ───────────────────────────────────────────────────────
	OP_BUILD_LIST   // build list; operand = element count
	OP_BUILD_RANGE  // build range; pop end, pop start; push list
	OP_BUILD_ARRAY  // build typed array; operand = element count; pop type name string after elements
	OP_BUILD_LOOKUP // push empty lookup table
	OP_INDEX_GET    // pop index, pop list; push list[index]
	OP_INDEX_SET    // operand = list name index; pop value, pop index; list[index] = value
	OP_LENGTH       // pop value; push length

	// ── Lookup table ──────────────────────────────────────────────────────
	OP_LOOKUP_GET // pop key, pop table; push table[key]
	OP_LOOKUP_SET // operand = table name index; pop value, pop key; table[key] = value
	OP_LOOKUP_HAS // pop key, pop table; push bool (key in table)

	// ── Type operations ───────────────────────────────────────────────────
	OP_TYPEOF           // pop value; push type name string
	OP_CAST             // operand = type name index; pop value; push cast(value, type)
	OP_NIL_CHECK        // operand: 1=is_something, 0=is_nothing; pop value; push bool
	OP_ERROR_TYPE_CHECK // operand = type name index; pop value; push bool

	// ── Input ─────────────────────────────────────────────────────────────
	OP_ASK // operand: 1=has_prompt, 0=no_prompt; [pop prompt;] push input line

	// ── Location ──────────────────────────────────────────────────────────
	OP_LOCATION // operand = name index; push address string

	// ── Struct ────────────────────────────────────────────────────────────
	OP_DEFINE_STRUCT // operand = struct def index in chunk.StructDefs
	OP_NEW_STRUCT    // operand = field_count<<16 | struct_name_idx; pop field values; push struct instance
	OP_GET_FIELD     // operand = field name index; pop object; push field value
	OP_SET_FIELD     // operand = field_name_idx; pop value, then load object by name (object_name in next operand via names); simpler: pop value, pop object; set field

	// ── Error handling ────────────────────────────────────────────────────
	OP_RAISE     // operand = type_name_idx (0 = generic/RuntimeError); pop message
	OP_TRY_BEGIN // operand = catch offset; push try frame
	OP_TRY_END   // pop try frame; operand = end offset (jump past catch+finally)
	OP_CATCH     // operand = error_var_name_idx; bind error var (type check moved to handleError)

	// OP_TRY_SET_ERRORTYPE sets the error-type filter on the top try frame.
	// operand = nameIdx+1 (0 means catch-all / no filter).
	// Emitted immediately after OP_TRY_BEGIN when the catch clause has a type filter.
	OP_TRY_SET_ERRORTYPE

	// OP_TRY_SET_FINALLY records the bytecode offset where the finally body starts.
	// operand = finally_offset. Emitted after OP_TRY_BEGIN (and optional OP_TRY_SET_ERRORTYPE).
	// When set, handleError will jump to this offset (instead of the catch handler) on a type
	// mismatch, run the finally body, and then re-raise via OP_RERAISE_PENDING.
	OP_TRY_SET_FINALLY

	// OP_RERAISE_PENDING re-raises frame.pendingError if it is set.
	// Emitted at the end of every finally body so that a type-mismatch error gets
	// re-propagated after the finally block finishes.
	OP_RERAISE_PENDING

	// ── Error type declaration ────────────────────────────────────────────
	OP_DEFINE_ERROR_TYPE // operand = name_idx<<16 | parent_name_idx (0 = no parent)

	// ── Reference / copy ──────────────────────────────────────────────────
	OP_MAKE_REFERENCE // operand = name index; push reference value
	OP_MAKE_COPY      // pop value; push deep copy

	// ── Swap ──────────────────────────────────────────────────────────────
	OP_SWAP_VARS // operand = name1_idx<<16 | name2_idx

	// ── Import ────────────────────────────────────────────────────────────
	OP_IMPORT // operand = flags (importAll<<2 | isSafe<<1 | hasItems); top of stack = path string

	// ── Line tracking ─────────────────────────────────────────────────────
	OP_SET_LINE // operand = line number

	// ── Stack management ──────────────────────────────────────────────────
	OP_POP // discard top of stack
)

type ReferenceValue

type ReferenceValue struct {
	Name string
	Env  *ivmEnv
}

ReferenceValue holds a reference to a named variable in a specific scope.

type StructDef

type StructDef struct {
	Name    string
	Fields  []*FieldDef
	Methods []*FuncChunk
}

StructDef is the compiled representation of a struct type declaration.

type StructInstance

type StructInstance struct {
	DefName string
	DefRef  *StructDef
	Fields  map[string]interface{}
}

StructInstance is the ivm runtime representation of a struct instance. Field values are mutable through the pointer.

type UnaryOp

type UnaryOp uint32

UnaryOp encodes a unary operator.

const (
	UnaryNeg UnaryOp = iota // arithmetic negation
	UnaryNot                // logical not
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL