Vexon: What Building a Small Bytecode Language Taught Me About Runtime Design
Vexon is an experimental programming language I’ve been building to better understand how languages work end to end — from parsing and compilation to execution on a virtual machine.
Rather than focusing on features or syntax novelty, Vexon is designed as a learning-driven language: small, readable, and complete enough to run real programs without hiding behind host-language abstractions.
This post explains what Vexon is, how it’s built, and what kinds of design lessons have come from actually using it.
What Is Vexon?
Vexon is a lightweight scripting language with:
-
a custom lexer
-
a hand-written parser
-
a compiler that emits bytecode
-
a stack-based virtual machine that executes that bytecode
Everything is implemented from scratch. There is no transpilation to another language’s AST or runtime.
At a high level, the pipeline looks like this:
The goal is not performance parity with production languages, but clarity of behavior and control over execution.
Why a Custom VM?
Building a VM forces you to answer questions that are easy to ignore when embedding into an existing runtime:
-
How are stack frames created and destroyed?
-
What invariants must hold before and after each instruction?
-
How are errors propagated without corrupting state?
-
What happens when a program doesn’t exit?
Vexon’s VM is intentionally simple:
-
stack-based execution
-
explicit call frames
-
predictable instruction flow
-
no hidden background behavior
This simplicity makes bugs visible instead of mysterious.
Long-Running Programs Expose Real Problems
Early Vexon programs were short scripts — arithmetic, conditionals, functions. Everything appeared correct.
That changed once I started writing programs that run continuously, such as:
-
simulation loops
-
timer-driven logic
-
simple game-style updates (e.g. Pong-like logic)
These programs exposed issues that never appeared in short scripts:
-
stack growth due to missed cleanup paths
-
state not being restored correctly after errors
-
instruction pointer drift across iterations
This was a key lesson: programs that don’t exit are a better test of a runtime than programs that do.
Debugging at the VM Level
Traditional source-level debugging wasn’t very helpful. The real problems lived below the language syntax.
What worked instead:
-
dumping VM state (stack, frames, instruction pointer)
-
logging execution at instruction boundaries
-
comparing dumps across iterations to detect drift
Seeing what the VM thought was happening made bugs obvious — especially mismatched push/pop paths and incorrect frame teardown.
This led directly to improvements in Vexon’s runtime consistency.
Tooling Before Features
One of the most important outcomes of Vexon so far is a shift in priorities.
Instead of adding more language features, the focus moved to:
-
better internal visibility
-
structured runtime dumps
-
deterministic error handling
-
tooling that explains why something broke
These improvements made the language easier to extend safely later.
Where Vexon Is Headed
Vexon is still experimental, but it’s already useful as:
-
a language design playground
-
a VM and compiler learning project
-
a testbed for tooling ideas (dump formats, debuggers, GUIs)
Future work is focused on:
-
better introspection tooling
-
optional GUI frontends
-
richer diagnostics
-
more real programs to stress-test the design
Closing Thoughts
Vexon exists because building a language forces you to confront details most programmers never need to think about — and that’s exactly the point.
If you’re interested in:
-
how languages are built
-
how bytecode VMs behave
-
or why tooling matters as much as syntax
then following Vexon’s development might be useful.
No comments:
Post a Comment