Pixardis Web IDE

Published by

on

AliExpress regret, compilers, WebAssembly, and educational mayhem disguised as a VM.


It Started with Garbage

Before the compiler, before the VM, there was just… bad hardware. Sandro (a colleague of mine) bought a pixel display off AliExpress. It wasn’t the worst thing ever (decent hardware, energy-efficient LEDs) but you couldn’t do anything with it. The bundled software was locked down, undocumented, and somehow managed to feel hostile.

So being the decent chap he is, he did the only rational thing: wrote a stack-based VM spec for a university compilers assignment that targets a virtual pixel display. Naturally. If he has to suffer, why suffer alone?

Naturally. Since my life is a 404, I looked at it, cackled and built a full compiler and VM in Rust. Because his JavaScript VM ran like a wounded 386 with thermal throttling. And because writing compilers for hardware that doesn’t want to be programmed is a personal calling. And because this is as close as I can get to having hot wax dropped on my eyes.


The Assignment

I have to admit (credit where credit is due – see what I did there?), this wasn’t some toy spec. The assignment (CPS2000) had it all:

  • Lexer: table-driven, FSA-based
  • Parser: hand-written LL(k)
  • Semantic analysis: type checking + scope rules
  • Codegen: stack-based IR called PixIR

The language, PArL, was expression-based, statically typed, and as unfriendly to implicit casting as a kernel dev is to GUI config tools. Every function returns a value. No shortcuts. No break, no continue, just raw iteration and conditionals.1

And yes, students had to implement the full stack. Because (looks at notes), what doesn’t kill you makes you stronger.


Writing the Compiler in Rust

The language spec came from Sandro. I took it and wrote a proper compiler in Rust, starting with a FSA for lexing, followed by a recursive descent parser that builds an AST. Type checking uses scoped symbol tables, enforcing strong typing and catching errors early. The code generation targets PixIR, the custom stack-based intermediate representation Sandro came up with.

It handles primitives, arrays, casting, arithmetic, control flow, functions, and custom hardware instructions like __randi, and __print.

Here’s what it looks like:
fun fibonacci(n:int) -> int {
    if (n == 0) {
        return 0;
    } else { 
        if (n == 1) {
            return 1;
        }
    }
    return fibonacci(n - 1) + fibonacci(n - 2);
}
let result:int = fibonacci(5);
__print result;

Yeah, it’s recursive. Yeah, it’s recursive. Yeah, it works. And yeah, it compiles to stack VM instructions. I’m not excluding divine intervention when I say this.


The VM: A Real One, Not a JS Sadness

The original JavaScript VM was… functional. In the way that wet cardboard is technically structural. Or that magenta is a colour. Or that Gone Home is a game. Or… ok, I think I’ve made my point.

So I built a real VM in Rust:

  • Operand and address stacks
  • Memory stack with scoped frames
  • Bytecode interpreter with arithmetic, control flow, and I/O
  • Hooks for pixel drawing and pseudo-random input

It runs fast. It handles dynamic execution. And it doesn’t melt when you write a loop. It’s 100% safe and 100% unsound.


Two Years in a Drawer

This thing has existed for over two years. But I couldn’t publish it. Because students were still doing the assignment (or variations of it), and releasing the source would’ve been like dropping answers on StackOverflow mid-semester. It might have sparked a surge in Rust adoption among undergrads, sure; but hey, free evangelism is not in my contract.

Now Sandro’s not teaching compilers anymore. The assignment’s been retired. The embargo is lifted.


Shoving It Into the Browser

When the news came in, I thought about making the repository public. But that felt boring. Then I wondered, “How hard would it be to make this run in the browser?”

Famous last words.

Two days later, the compiler and VM were compiled to WebAssembly, Monaco was hooked up as the editor, and Canvas was handling pixel output. In the native version, both keyboard input and pixel display were originally handled using Macroquad.

And now you can try it live in your browser.

No install. No setup. Just pixels and pain.


So What’s the Point?

Honestly? I still ask myself that. Why are we here? Just to suffer?

It wasn’t meant to be useful.

It just accidentally is.

If you’re learning compilers, stack-based languages, WebAssembly integration, then it’s kind of perfect. You’ll understand memory models, function calls, stack frames, codegen, all without having to dig through LLVM or sit through lectures.

This wasn’t built to teach. It just happens to do it well.

You have to be warned though: parsing the source is less like reading documentation and more like performing an arcane ritual – you might gain forbidden knowledge, but at the cost of your sanity.

Grant us eyes, grant us eyes.
Plant eyes on our brains… new ideas, of the higher plane!


Source, Examples, and Regret

GitHub Repo: keithbugeja/pixardis-web

Includes:

  • Compiler (Rust)
  • VM (Rust)
  • WebAssembly glue
  • Monaco IDE
  • Working examples: fibonacci, pong, etc.

Final Final Note

Yeah, it’s mostly in jest. Don’t take it personally… unless you wrote the original display firmware. Then yes, take it very personally.

The compiler and VM were actually written 2-3 years ago.

I couldn’t release the source at the time without detonating a live university assignment.

Now the assignment’s been retired and the embargo is lifted. So here it is.

This project is held together by duct tape, compiler warnings, and poor decisions.

Yes, it runs. No, I don’t know why.

If the code’s ugly, that’s your problem. If it’s beautiful, that’s by accident.

This is starting to read like a LinkedIn post.

Agree?

  1. Note that things might have changed in later incarnations of the assignment. ↩︎

Leave a Reply

Previous Post
Next Post

Discover more from Probably Works

Subscribe now to keep reading and get access to the full archive.

Continue reading