Skip to content

Developer Journey

Roger Johansson edited this page Jan 15, 2026 · 6 revisions

Developer Journey

I built a JavaScript engine. In C#. From scratch.

Why? I wanted to see if I could.

How It Started

You know that feeling when you look at something and think "how hard can it be?"

That's basically my entire career. Akka.NET started as a weekend hack. Proto.Actor came from being annoyed at design decisions I made in Akka.NET.

And this? This started with three sentences typed into Codex:

"I want to create a JS execution engine using C#. It will need a js parser/grammar. I want to represent the result of the parser as S-expressions / CDR/Cons. The execution engine can then treat the code similar to lisp."

Parse JavaScript. Evaluate it like Lisp. Simple, right?

OK, fast forward 2.5 months and 3,036 commits later.

Turns out JavaScript is complicated. Who knew? (Everyone. Everyone knew.)

The Timeline

Nov 7, 2025   "How hard can it be?"
     |
     |-----> CPS for async (hard, apparently)
     |-----> Generators with state machines (harder)
     |-----> Test262 compliance tests (93,000 ways to be wrong)
     |
Dec 2025     "Maybe we need to refactor a bit"
     |-----> Source generators (because typing is boring)
     |-----> Complete async rewrite (take two)
     |-----> IR instructions (take three? four?)
     |
Jan 2026     "It actually works now"
     |-----> AST evaluators sent to /Legacy
     |-----> One execution model to rule them all

The Chapters

The Beginning

  • Chapter 1: Genesis - Three sentences, one Codex prompt, suddenly I'm building a JavaScript engine

Building the Runtime

The Great "Let's Fix Everything"

The IR Era

The Human Side

The Meta Game

The Numbers

What How Much
Total Commits 3,036
Time ~2.5 months
PRs 570+
Test262 Tests 93,000+
Times I Said "This Should Work"
Times It Actually Worked First Try 3

The Three-Headed Monster

At one point, we had three different execution models running at the same time:

Code Type How It Ran
Sync code AST tree-walking
Async functions CPS transformation
Generators IR state machine

One script could touch all three. Nice, right?

But: debugging was basically impossible. Which model was running? Good luck figuring that out.

function sync() { return 1; }           // AST
async function getData() { await x; }   // CPS transformed
function* gen() { yield 1; }            // IR state machine

So, we unified everything into IR. Much better.

Should've done that from the start. But where's the adventure in that? :-)

Why Though?

People ask me why I build these things. Akka.NET, Proto.Actor, and now a JavaScript engine?

Honestly? I just want to know if I can.

There's something satisfying about taking a complex problem and wrestling it into submission. JavaScript engines are supposed to be hard. V8 took years and hundreds of engineers. SpiderMonkey is ancient and battle-tested.

And here I am with Codex and stubbornness, seeing how far we can push it.

Turns out? Pretty far.


This is my journey building a JavaScript engine. Messy, honest, and there's probably a bug in there somewhere.

//Roger

Clone this wiki locally