Sometimes, you just have to create a programming language
Table of Contents
Goals
The goal of this project was to create a compiler that generates JVM bytecode. My criteria for success were simple: implement variable declarations, condition statements, loops, function definitions, and function calls. Anything else would make this project stretch longer than I want.
The repository is on my GitHub profile: https://github.com/IfeSunmola/earth-lang
Initially, I tried to generate C code, but it wasn’t as straightforward as I thought.
Sample Code
See the samples directory in the repository for more examples.
fn add(a: int, b: float) float {
// yeet is equivalent to `return`
yeet a + b
}
fn sayHello(name: str) {
var greeting: str = "Hello " + name
_ = yapln(greeting)
}
fn main() {
// All expressions MUST be attached to a statement. Since `yapln` returns
// `nada`, we can attach it to an unnamed statement with _.
// Below is equivalent to `var res: nada = sayHello("Cassi")`
_ = sayHello("Cassi")
var sum: float = add(1, 2.0)
// To keep it simple, yapln only accepts strings, so we must convert.
_ = yapln(floatToStr(sum))
}
The title of this article doesn’t really give justice to how much of an obsession creating a compiler/programming language was. Sometimes, I gave up on working on it before I even started. Don’t believe me? Look at the following screenshot from my GitHub profile:
I’m embarrassed to say that’s not all:
Do us both a favour and don’t ask about the names I chose 🤝
Why did I do this?
It seemed like a fun thing to do. Sure, there were times when I wanted to smash my PC and fight with my brain because I couldn’t figure out why code generation wasn’t working for something, but it was fun (Stockholm syndrome?).
Why did I keep “failing”?
To clarify, my definition of “failing” is if I come back to the project like a week later, and the code seems foreign to me, or I don’t understand why I did something a certain way.
-
I was trying to do too much with little knowledge, which eventually led to being overwhelmed/frustrated.
-
I was trying to force Java into a language that it’s not.
- I blame my mini Haskell obsession for this. There wasn’t one specific
thing that made me “fail.” It was the little things such as:
- All methods must return something,
- Avoiding exceptions
- Keeping methods pure, e.t.c.
- Java has added a lot of functional features over the years, but it still remains an object-oriented language where mutability is easier than immutability, and exceptions are the norm. Trying to break away from that in your entire codebase is just begging for future headache.
- I blame my mini Haskell obsession for this. There wasn’t one specific
thing that made me “fail.” It was the little things such as:
-
I apparently don’t understand C as much as I thought? I initially started by trying to generate C, but I kept hitting roadblocks. My first attempt at JVM byte code generation was successful, so maybe the universe is trying to tell me something.
-
I spent too much time trying to come up with the “best solution” for everything, and when I eventually found the “best solution”, I got confused and forgot why I was even trying to solve the problem. This would be somewhat justified if I’m creating a library or software for real-world use, but I’m not. (Sidenote: The “best solution” was, in fact, not the best)
Although earth-lang
succeeded based on my definition, I probably won’t
understand much of it in a few months, especially the code generation part. The
class file API was designed in a way that forced me to rely on references to the
current builder
object. It works, but it felt hacky.
I’m sure there’s a better way to go about it, but I couldn’t figure it out and
did not want to spend too much time on it.