Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Installation

not a thing yet lol

Quick Start

Now that Henceforth is installed, let's write and run a simple Hello World program. This guide will help you go from zero to a running program in just a few steps.

1. Create a new file

First, create a new directory and a file for your program:

mkdir hello-world
cd hello-world
touch main.hfs

2. Write your first program

Open main.hfs in your favorite text editor and add the following code:

// main.hfs
fn main: () -> () {
  @("Hello, world!") &> print;
  @pop;
}

This simple program prints "Hello, world!" to the terminal. If you don't understand some of the syntax, you can learn about it in the next section, or in the language reference.

3. Run the program

Once your file is ready, run it from the command line:

henceforth main.hfs

Expected output:

Hello, world!

4. What's next?

You're all set up and running code! In the next section, you'll get a glimpse into some of the language features.

Your First Henceforth Program

Now that you wrote and ran a Hello World program, let's dive into something a bit more involved.

Create a new directory, or just use the one from the previous step. Then, create a file called calculator.hfs.

Add the following code to it:

fn add: (i32 i32) -> (i32) {}

Currently, this code won't run, but let's break down what's happening.

  • fn declares a function
  • add is the function's name
  • After the colon, we have the function signature, in this case (i32 i32) -> (i32). This function takes two 32 bit ints, and returns one 32 bit int. In Henceforth, arguments don't have names - they're accessed from the stack instead (More on this below).

Now, let's complete this function:

fn add: (i32 i32) -> (i32) {
  @(+);
}
  • @(...) denotes a stack block. Everything inside these blocks manipulates the current function's stack.
  • When a function is executed, its arguments are put into that function's stack by the order they were passed.
Stack: [5, 3] // after calling add with the arguments (5 3)
  • + is a special stack operator that pops two numbers, adds them, and pushes the result to the function's stack. Stack state:
[5, 3]  // after calling add
  ↓
[8]     // after +
  • When a function returns, the function stack must have exactly what the function's return type says.

Now, to finish this, let's make our main function:

...
fn main: () -> () {
  @("5 + 3 = " 5 3);
  &> add;
  &> i32_to_str;
  @(+);
  &> print;
  @pop_all;
}
  • We create our function as before, main takes no arguments and has no return type.
  • We add the string "5 + 3 = " to the stack, followed by 5 and 3.
  • Then, we call add, moving the arguments with the &> operator.
  • We now call i32_to_str, which converts a number into a string, also moving the argument. Stack state:
["5 + 3 = ", "8"]
  • Since print only takes one argument, we concatenate the strings with +, similarly to how we added numbers.
  • We call print, moving its arguments, then we use the @pop_all keyword to pop the string we just printed.

Here's the complete program:

fn add: (i32 i32) -> (i32) {
  @(+);
}

fn main: () -> () {
  @("5 + 3 = " 5 3);
  &> add;
  &> i32_to_str;
  @(+);
  &> print;
  @pop_all;
}

Now, run it with henceforth calculator.hfs. The expected output should be:

5 + 3 = 8

Congratulations, you have now written a simple Henceforth program!

What's Next

Try experimenting with the code:

  • Change the numbers in the calculation
  • Create a subtract or multiply function
  • Add more operations to the output