Kalang, My Abomination Language
This post will be far shorter and much messier than the one I wrote sixty minutes ago about a graph metric plugin for Obsidian because I've spent far much too time this weekend on projects that don't need precedence over responsibilities, but admittedly got it anyway. I want to share the fledgling Kalang, a programming language I've been building during those stolen hours when I should probably be doing something else.
tl;dr
I built a programming language called Kalang that emphasizes readability, immutability by default, and a syntax that feels familiar but cleaner. It's horrifically incomplete, likely full of bugs, and currently lacks proper documentation—but it compiles to C and has syntax highlighting for VSCode, so clearly it's enterprise-ready.
Kalang started as most of my projects do: an itch that wouldn't go away coupled with the dangerous thought, "how hard could it be?" The answer, as always, was "significantly harder than anticipated," but here we are anyway. The goal was/is self-compilation. That goal is quite far.
The core philosophy is simple: code should be obvious at first glance. Variables are immutable by default (add var
if you want mutability). Types are optional but not really but welcome because you probably should for now. Functions are first-class citizens. And everything should feel like it makes sense without consulting three different Stack Overflow posts. I get to pick all the features, so it should also just work according to how I want. Perfectly aligned with the language's ego-fulfilling name.
# here's what Kalang looks like
fn factorial(int n) -> int {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1); # I expect every CS student to be forced to learn this by 2030
}
fn main() {
# immutable by default
string message = "Hello, segfaults!";
# explicitly mutable because I'm too scared
# of Haskell's total immutability
var int counter = 10;
# match expressions because it looks awesome
match counter {
0 -> print("Zero");
1 -> print("One");
_ -> print("Many: " + counter);
}
}
Why build another language? Because apparently I hate free time and love syntax errors.
The compiler is written in C (fitting, since it outputs C), which has been both a blessing and a curse. The blessing: it's fast (the prototype in Python was miserably slow). The curse: memory management makes me question all my life choices at 2 AM. I love pointers! I love pointers! I hate pointers! I love pointers!
What works, sort of
Currently, Kalang can parse basic expressions, function declarations, and control flow structures. It has a working type, some sick REPL-only commands, and the code generator outputs reasonably legible C. There's also a small standard library for basic I/O and string operations.
The REPL follows a different syntax that had me questioning whether I was actually developing two languages at once. I envisioned it as an actually useful shell utility for Windows dwellers (me) who want to pretend that it's "basically the same" to just use WSL for Linux-related tasks (I know. I know.)
kalang> files
##(messy repo contents displayed here##
kalang> add -4 4 # yes, space-delineated arguments but ONLY if you use the REPL!!!
0
kalang> run notepad
# it actually does open, believe it or not
Tremendous work.
What doesn't work? Too much to list here. Error reporting is primitive. I spend a lot of time wondering if error reporting is broken, or if I wrote invalid Kalang, or if I wrote correct Kalang but the compiler is bugged (the answer is (paradoxically?) all three). There's no proper module system yet, and the runtime has more memory leaks than features. Also, I haven't gotten around to implementing proper closures, which makes functional programming somewhat... aspirational.
Absolutely unhinged priorities
Instead of fixing the memory leaks, I spent an entire evening building a VSCode syntax highlighter because, obviously, pretty colors are more important than proper memory management. This checks out for my prioritization skills.
You don't get to even appreciate the pretty colors in the examples because Prism.js obviously doesn't support it, and it would be an even worse use of my time to focus on that. And taking a screenshot of text in VSCode feels so, so wrong.
I also spent an inordinate amount of time on the match expression implementation, because pattern matching is cool. Meanwhile, basic array operations still have edge cases that will crash the interpreter if you look at them wrong. You can compile them at least! But you can't use them if they're compiled.
Should you use it?
Absolutely not, and the project is definitely in the stage of "too embarrassed to share". I did want to at least document it here so when it's totally the most popular language worldwide, tech journalists can discover this post. In reality, despite my troubles with this project, I've been having a lot of fun and I wanted to share that. Further, getting in over your head with these sorts of projects is the best way to learn, at least for me.
There are dozens of better languages built by people who actually know what they're doing. But if you're curious about language design or just enjoy watching somebody struggle to compile their code, stay tuned for updates.
I'll be over here, trying to fix that segfault that only happens during odd hours.