cd /news/developer-tools/i-turned-notebook-pseudocode-into-a-… · home › topics › developer-tools › article
[ARTICLE · art-143068] src=dev.to ↗ pub= topic=developer-tools verified=true sentiment=↑ positive

I turned notebook pseudocode into a real programming language — C++17 VM and all

A 14-year-old developer released X++ v0.4.1, an intent-driven programming language whose strict pseudocode syntax compiles and runs on a zero-dependency native VM written from scratch in C++17, with an AOT backend that emits portable C++ compiled to machine code. Benchmarks included in the release show the native AOT path running a 1..5,000,000 summation in 50 ms versus 381 ms for CPython 3.11, and recursive fib(28) in 10 ms versus 55 ms. The project also ships a browser playground backed by a JavaScript port of the VM, validated by a harness that requires byte-identical stdout, stderr and exit codes across 40+ programs.

by read4 min views1 publishedOct 1, 2026

The first program I ever wrote was in a school notebook. A guessing game, in plain steps: pick a number, ask the player, if too low say "too low." I couldn't run it, obviously. Notebooks don't have compilers.

That annoyed me more than it should have. Every beginner can write an algorithm in plain language — the syntax is the gatekeeper, not the logic. So a year ago, at 13, I started building the unreasonable version of the fix: a programming language where the pseudocode is the code.

This week it hit v0.4.1 — a native VM written from scratch in C++17, zero dependencies, and an AOT backend that compiles your program to machine code. It's called X++ (more on the name later, unfortunately).

Programming For Everyone

Same pseudocode. Same ease. Now a real native VM.

X++ is an intent-driven language: you write strict pseudocode (or loose English steps for the AI mode), type one command, and it booms. Version 0.4.1 adds a zero-dependency native VM (C++17) so your programs run without Python — the Python stack is still available for the legacy and AI paths.

x run app.xp, done..xp straight to machine code (via portable C++ emitted by the backend, compiled with your system compiler)..xbc (.bc)…

RNM=ZITR

fn fib(n):
  if n <= 1:
    return n
  end
  return fib(n-1) + fib(n-2)
end

loop i from 0 to 10:
  out i, fib(i)
end

That's a complete program. x run fib.xp prints the table.

The entire language fits in a tweet's worth of rules: blocks end with end. No types, no brackets, no semicolons. push 4 to nums reads like what it does. Errors say division by zero, not TypeError: unsupported operand type(s) for /: 'int' and 'int'. Errors you can catch, too:

safe:
  x = 1 / 0
fail e:
  out "caught:", e
end

Lists, dicts, loop x in list, loop i from 1 to 10 step 2, closures, recursion, and/ or that short-circuit. That's the whole shape of it.

v0.3 was, I'll admit it, a Python transpiler. X++ went in, Python came out, exec happened. It worked! It also felt like cheating. And it meant my "language" died without Python installed and ran at Python speed.

So for v0.4 I wrote a real engine — no dependencies, pure C++17:

nil + 1 returns nil instead of erroring, because the nil tag collides with a float path in my arithmetic. I've been calling it "nil propagation" until someone convinces me it's a bug. You pick the engine with one header line: RNM=ZITR (VM), RNM=ZCOM (bytecode AOT), RNM=ZJIT (native). Same .xp file, same language, three different machines underneath.

Workload CPython 3.11 ZITR (my VM) ZJIT (native AOT)
sum 1..5,000,000 381 ms 202 ms 50 ms
fib(28), recursive 55 ms 91 ms 10 ms

Asterisks, because I'd rather say them first:

bash bench/test_all.sh reproduces everything — run it and post your numbers, good or bad. The project's website has a playground that runs X++ entirely in your browser — a full JavaScript port of the VM's semantics. I didn't trust myself to write the same language twice (correctly, it turns out), so I built a test harness that runs 40+ programs on both engines and requires byte-identical stdout, stderr, and exit codes.

It caught real things. My favorite: while porting sum(), I discovered the native version drops the integer total if a float shows up later in the list — a genuine bug in my C++ accumulator. I reproduced it faithfully in the JavaScript port anyway, because right now divergence scares me more than bugs. Both get fixed in 0.4.2. Fidelity first, correctness second, apparently.

sum() thing above. What's next: modules (use "file.xp"), a register JIT with profiling feedback, and native FFI.

The part of a project you can't see from the inside is the part you got wrong — so benchmark it, break it, open issues, argue with me about end vs indentation. The feedback form on the site goes straight to my inbox and the issue tracker is right there. Sharp feedback is the most useful thing you can hand me.

The website html and css was LLM generated, so if you smell AI there then you are right, also same is true for the readme because I don't have the skills to write a proper cool README so sorry for that too.

— Aagastya Verma · Atom Software

── more in #developer-tools 4 stories · sorted by recency
── more on @x++ 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/i-turned-notebook-ps…] indexed:0 read:4min 2026-10-01 · —