| src | ||
| .envrc | ||
| .gitignore | ||
| build.zig | ||
| build.zig.zon | ||
| flake.lock | ||
| flake.nix | ||
| LICENSE | ||
| README.md | ||
Owa
A small experimental virtual machine and interpreter for an interpreted language, written in Zig.
Owa provides a minimal bytecode format, a stack-based VM, and an object model with prototype inheritance and "magic" hooks. It is designed as a playground for building a compact interpreter, adding opcodes, and experimenting with native/built-in functions.
Features
- Stack-based VM: executes a custom bytecode (
OwaInstruction). - Interpreter/threads:
OwaInterpretermanagesOwaThreadinstances that run frames and bytecode. - Frames and locals: each call executes in an
OwaFramewith its own instruction pointer and locals map. - Object model:
OwaObjectsupports attributes, prototype chain, and a callable function slot. - Magic hooks: predefined magic names (
__call,__str, etc.) enable dynamic behavior. - Builtins module: includes basic objects such as
OWA_NULLand a nativeprintfunction.
Getting Started
Prerequisites
- Zig (0.12+ recommended)
Build and Run
zig build
zig build run
This builds the Owa executable and runs the demo program from src/main.zig.
How It Works
Bytecode and Instructions
Instructions are defined in src/vm/instruction.zig as a tagged union OwaInstruction with an underlying enum(u8) opcode. Examples include Nop, LoadConst, Call, Return, and simple stack/rotation ops. Programs are encoded to bytes and then decoded during execution.
const encoded = try OwaInstruction.encode_program(&.{
OwaInstruction{ .LoadConst = 0 }, // push builtins.print
OwaInstruction{ .LoadConst = 1 }, // push OWA_NULL
OwaInstruction{ .Call = 1 }, // call print with 1 arg
OwaInstruction{ .Return = {} },
}, allocator);
Interpreter and Threads
OwaInterpreterinitializes memory, holds thread and module lists, and canspawn()newOwaThreads.OwaThreadmanages a value stack and a currentOwaFrame; it repeatedly decodes bytecode and dispatches instructions.OwaFrametracks the function being executed, the instruction pointer (ip), a link to the previous frame, and a locals map.
Object Model
OwaObject holds:
attrs: attribute map (StringHashMapUnmanaged)prototype: optional prototype linkcall_fn: optional function (either bytecode-backed or native)
The VM resolves attribute access via getAttr and prototype chaining. Callability is resolved through call_fn or the __call magic attribute.
Builtins
The modules/builtins module defines core objects and natives:
OWA_NULL: the null valueprint: a native function printing its arguments
Example
src/main.zig demonstrates creating an interpreter and running a tiny program that calls the builtin print with OWA_NULL:
const std = @import("std");
const owa = @import("Owa");
const modules = @import("modules");
pub fn main() !void {
const allocator = std.heap.page_allocator;
var interpreter = try owa.OwaInterpreter.init(allocator);
var thread1 = try interpreter.spawn();
var func = owa.OwaFunction{
.owa = .{
.code = try owa.OwaInstruction.encode_program(&.{
owa.OwaInstruction{ .LoadConst = 0 }, // builtins.print
owa.OwaInstruction{ .LoadConst = 1 }, // OWA_NULL
owa.OwaInstruction{ .Call = 1 },
owa.OwaInstruction{ .Return = {} },
}, allocator),
.var_const = &.{
&modules.builtins.print,
&modules.builtins.OWA_NULL,
},
},
};
try thread1.execute(&func);
interpreter.deinit();
}
Project Structure
src/mod.zig: re-exports core VM types (instructions, objects, interpreter, etc.).src/main.zig: demo entry point.src/vm/instruction.zig: opcodes and encode/decode utilities.src/core/object.zig: object model and attribute logic.src/core/function.zig: function union (bytecode vs native) and flags.src/core/frame.zig: call frame and locals.src/core/thread.zig: thread state, dispatch loop, and call mechanics.src/core/interpreter.zig: interpreter lifecycle and thread management.src/core/magic.zig: magic names like__call,__str, etc.src/modules/builtins/: built-in objects and native functions.build.zig: Zig build configuration (modules, executable, run step).
Roadmap
- More opcodes (arithmetic, control flow, comparisons, etc.).
- Exception handling and error objects.
- Strings, numbers, and collections as first-class runtime objects.
- Module system and loader.
- Basic standard library.
License
See LICENSE for details.