../

Day 1: Building WyrdLang

Welcome to the first post in what I hope will be an interesting journey—building a programming language from scratch. The programming language will be named as WyrdLang, and over the coming weeks, I’ll be documenting the entire process of implementing a tree-walk interpreter.

Why “WyrdLang”? In Old English, wyrd means fate or destiny. And yes, it also sounds like “weird” which is perfectly fitting for a language with unconventional keywords that sounds like words from a fairytale.

I won’t be building this language without any reference or a good resource. I’m going to follow the excellent book Crafting Interpreters by Robert Nystrom.

Crafting Interpreters

This book is a masterpiece, it walks you through building not one, but two complete interpreters for a language called Lox. The first interpreter, jlox, is a tree-walk interpreter written in Java. It focuses on concepts and correctness, building a clean, understandable implementation. The second interpreter, clox, is written in C and includes a bytecode compiler and virtual machine for serious performance.

I’ll be focusing on the first interpreter the tree-walk approach, but with a twist.

The WyrdLang Difference

While I’m following the structure and wisdom of Crafting Interpreters, I’m making some significant changes:

1. C++ Instead of Java

The original jlox is written in Java, but I’m porting it to C++. Because I’m more comfortable with C++. While Java is an excellent teaching language, I want to work in a language where I can focus on language implementation concepts rather than fighting with unfamiliar syntax. This means I’ll be dealing with manual memory management (or smart pointers), templates instead of generics, and all the quirks that make C++ both powerful and occasionally a maddening disaster.

2. Different Keywords

Here’s one of the unique aspects of WyrdLang. Instead of standard programming keywords, I’m using a different set of keywords inspired by fairy tales. This is mostly for fun and to make the implementation feel more personal, but the core goal remains building a functional, well-designed interpreter.

Original KeywordWyrdLang KeywordMeaning
varenchantDeclare a variable
funspellDefine a function
classclanDefine a class
ifwhenConditional execution
elseotherwiseAlternative branch
whileaslongasWhile loop
forcycleFor loop
returnmanifestReturn a value
printcastPrint output
trueayeBoolean true
falsenayBoolean false
nilemptinessNull/nil value
andtogetherLogical AND
oreitherLogical OR
thisthineCurrent object reference
superelderSuperclass reference

Here’s what code looks like in WyrdLang:

enchant greeting = "Hello, World!"
cast greeting

spell summonDragon(name) {
    when (name == "Smaug") {
        manifest "The dragon awakens!"
    } otherwise {
        manifest "A dragon arrives: " + name
    }
}

enchant result = summonDragon("Smaug")
cast result

What is a Programming Language ?

Before we embark on building our own language, let’s step back and understand what a programming language actually is and how it works.

At its heart, a programming language is a bridge between human thought and machine execution. When we write code, we’re expressing our intentions about what we want the computer to do, in a form that’s somewhere between natural human language and the raw binary that CPUs understand. Computers only understand sequences of 1s and 0s. That’s it. Everything else—variables, functions, loops, classes is a beautiful illusion we’ve constructed to make programming manageable for human minds.

From Text to Execution

Imagine implementing a programming language as climbing a mountain. we start at the bottom with raw source code in our hands, just a string of characters that a pogrammer typed. As we climb up the mountain, we transform this text through various stages, each one revealing more about what the program means:

mountain climb flowchart

At the peak, we have a complete understanding of what the programmer wants. Then we descend the other side, transforming that high-level understanding into progressively lower-level representations until we reach something the computer can actually execute.

The Two Paths: Compilers vs. Interpreters

There are two main approaches to implementing a programming language:

Compilers:

Interpreters:

In reality, many modern languages blur the line between these categories. Python compiles to bytecode before interpreting it. Java compiles to bytecode, then a JIT (Just-In-Time) compiler translates hot paths to machine code at runtime. It’s complicated, and gloriously so.

Building WyrdLang

I’m setting out to build WyrdLang as a tree-walk interpreter the simpler of the two main approaches to creating an interpreter. Here’s what that means:

What is a Tree-Walk Interpreter?

A tree-walk interpreter works by:

  1. Scanning the source code into tokens (lexical analysis)
  2. Parsing those tokens into an Abstract Syntax Tree (AST)
  3. Walking that tree structure, evaluating each node to execute the program

It’s called “tree-walk” because the interpreter literally traverses the tree structure, executing operations as it visits each node. It’s intuitive, relatively simple to implement, and most importantly for learning, we can understand every single piece of it.

The downside of the tree-walk approach is that they are slower than more sophisticated approaches like bytecode virtual machines or JIT (Just-In-Time) compilation. But for a learning project and a language inspired by fairy tales, speed isn’t my primary concern.

The Journey Ahead

Over the coming weeks, I’ll be documenting my journey building WyrdLang. Each blog post will cover a specific aspect of language implementation:

Along the way, I’ll encounter bugs, design decisions, and implementation challenges. I’ll share the failures alongside the successes, the confusing moments alongside the revelations.

Why Build a Programming Language?

Fair question. Here’s my answer:

1. To Understand How Things Really Work

Building a programming language is the ultimate “peek behind the curtain,” moving you from driving the car to building the engine from scratch. By mastering low-level mechanics like scoping and memory overhead, you stop guessing at performance and start writing better code in every other language.

2. Incredible Learning Experience

Implementing a language tests every programming skill I have:

By the end of this journey, I guarantee that I’ll be a better programmer.

3. Little Languages Are Everywhere

I will be able to create domain-specific languages: configuration formats, scripting systems for your application, query languages, markup formats. Understanding how languages work makes you better at designing these “little languages” that power so much of modern software.

What’s Next?

In the next post, I’ll dive into the first concrete step: scanning. We’ll learn how to take raw source code just a string of characters and break it into meaningful tokens. We’ll build the lexer that can recognize WyrdLang’s fairy tale keywords and transform text like enchant x = 42 into a stream of tokens the parser can understand.

We’ll talk about:

But that’s for next time. For now, I’m setting up my development environment, sketching out the initial architecture, and preparing for the first lines of code.


A Note on Open Source

I’ll be sharing all the WyrdLang source code on GitHub as I build it.

Tags: /wyrdlang/ /interpreter/ /crafting-interpreters/ /cpp/ /c++/ /programming-language/