Marshall Bowers

Conjurer of code. Devourer of art. Pursuer of æsthetics.

Crane: Week One

Sunday, June 18, 2023
556 words
3 minute read

Today marks one week since I started working on my programming language, Crane.

An Introduction

Crane is a language for writing robust and elegant software that will endure over time.

It's statically typed, compiles to native code with an (eventual) garbage collector1, and comes with the features you'd expect of a modern language, like sum types and no nulls.

Crane currently supports the following types:

  • () - The unit type
  • Uint64 - A 64-bit unsigned integer
  • String - An immutable string of UTF-8 characters

There's also the minimal beginnings of a standard library that contains the following functions:

fn print(value: String) {}

fn println(value: String) {}

fn int_add(a: Uint64, b: Uint64) -> Uint64 {}

fn int_to_string(value: Uint64) -> String {}

Here's an example of a small Crane program:

fn main() {
    let world = "世界"

    hello(world)
}

fn hello(name: String) {
    print("你好,")
    print(name)
    println("")
}

Running this through the Crane compiler will produce a single-file binary which we can then execute:

$ ./build/main
你好,世界。

Compile-time errors

Being a statically-typed language, Crane will provide you with helpful errors at compile time when there are issues with your program:

A Crane compile error: "Expected std::prelude::Uint64 but received std::prelude::String."

A Crane compile error: "Function hallo does not exist."

Building excellent compiler errors is going to be a lot of work, but I think it's an important aspect of the language. By putting in a good diagnostic framework early my hope is that it will help make it easier to build with good errors in mind.

Syntax

If you're familiar with Rust at all, you might have noticed that Crane's syntax is decidedly Rust-like. This is no accident.

I think Rust gets a tremendous amount right as a language, both in terms of syntax and language features. The design of Crane owes a lot to Rust as an inspiration.

Of course, there are—and will continue to be—differences as Crane evolves and comes into its own.

A Peek Under the Hood

The Crane compiler is written in Rust. This was an obvious choice for me.

Rust is very well-suited to compiler development, and there is a wealth of crates available to help with the language-building process.

Some of the crates that power the Crane compiler:

  • clap for powering the compiler CLI
  • logos for lexing
  • ariadne for reporting errors and diagnostics
  • inkwell for interacting with LLVM in the backend
  • insta for snapshot testing

At time of writing the Crane codebase is just shy of 2,500 lines of code:

cloc output for Crane. There are 2,356 lines of Rust code.


It's still very much early days for Crane and there's a long road ahead before it becomes a "real" language, but I'm very happy with the progress of this first week.

I expect to write more of these posts about Crane in the future.

In the meantime, you can check out the Crane repo on GitHub if you'd like to follow along with Crane's development.

1

Currently Crane programs just gratuitously leak memory.