I Wrote a Compiler for My Own Programming Language

This past Friday I officially tagged the first release of Sunder, a C-like systems programming language and compiler for x86-64 Linux. Here is “Hello World” in Sunder:

import "std/io.sunder";

func main() void {
    std::println("Hello, world!");
}

I have been working on Sunder for a little over half a year now1. Although the project is still in its infancy, the language and compiler already support an impressive number of features including, but not limited to:

Comments:

# this is a comment in Sunder

Variables:

var foo: byte = 0xFF;

Compile-time constants stored in read-only memory:

const bar: byte = 0xFF;

Functions with 0 to N parameters and a single return type/value:

func max(a: ssize, b: ssize) ssize {
    if a > b {
        return a;
    }
    return b;
}

Data types including:

Expressions including:

If statements (using the keywords if, elif, and else):

if condition {
  # body
}

if condition0 {
  # body
}
elif condition1 { # there may be 0 -> N elif components
  # body
}
else { # there may be at most one else component
  # body
}

Looping constructs including:

Dump statements which write the raw bytes of an object to standard error (really useful for debugging):

dump (:[3]u16)[0xAB, 0xBC, 0xDE]; # AB 00 BC 00 DE 00

Return statements:

return 123;

Assignment statements (assignment is a statement and not an expression):

foo = 0xAA;

Namespaces:

# lib/std/io.sunder
namespace std;

Module imports and multi-file compilation:

import "std/io.sunder";

The typeof operator which evaluates to the type of an expression:

var m: ssize = 123;
var n: typeof(m) = m + 1;

Automatic index out-of-bounds, integer overflow, integer underflow, and divide-by-zero checking:

# When this expression is executed the program will print the following
# error message and exit:
#
# fatal: arithmetic operation produces out-of-range result
0xFFFFu16 + 1u16;

Constant expression evaluation:

const x: u16 = 123 + 456 * 2;
const y: [1 + 2]u16 = (:[3]u16)[0...];

Order-independent top-level declarations:

const c: ssize = b + 1s;
const a: ssize = 1s;
const b: ssize = a + 1s;

And more!

The Sunder compiler and standard library try to do as much from scratch as reasonably possible. The compiler is written in strict C99 and requires only nasm and ld for assembling and linking. Sunder executables are statically linked without any dependency on libc:

~$ cd ~/sources/sunder/
~/sources/sunder$ sunder-compile -o hello examples/hello.sunder
~/sources/sunder$ ./hello
Hello, world!
~/sources/sunder$ ldd ./hello
	not a dynamic executable

I should be clear that Sunder is not a wannabe C replacement; I am working on this project purely as an academic exercise. Sunder is still very much a “toy” programming language and I don’t have the time, energy, or desire to partake in the race to replace C. However, the project is built on a solid foundation and I am looking forward to improving on the language, compiler, and standard library over the coming weeks, months, and (maybe) years.

There is no shortage of work to be done on the Sunder project. The language has no concept of user-defined struct types, nor does it have a concept of generics, both of which are required to develop the abstractions and interfaces I would like to have within Sunder’s standard library. There is also a fair bit of cleanup needed in the compiler. Although I am extraordinarily pleased with the compiler’s overall architecture, it is almost impossible to get everything right on the first try, and the project has accrued enough technical debt to warrant a few refactoring passes before I go around adding any new features. That being said, this project has consumed my nights and weekends for the past seven or so months, and having reached the major milestone of a first release, I think I am going to take a bit of a break to focus more on my family and personal (non-side-project) life for a little while. I will still be working on Sunder, but in the near future my effort on this project is going to be mostly focused on piecemeal refactoring of the compiler without any drastic changes to the language or standard library.

Anyway that’s all I have for this blog post. For those interested, the main Sunder repository and issue tracker can be found on GitHub and a mirror can be found on SourceHut. I am extremely happy with how this project has turned out so far and I am super proud of how much I have grown as a language and compiler author. Cheers!

Footnotes


  1. A backup copy of the project repository shows that the initial commit occurred on 2021-02-19.