Skip to main content

Hello, world

esque has string literals and a tiny print surface but no general I/O, so the "hello world" of the language is a program that exits with a number you chose. That is enough to teach you everything about the toolchain.

The shortest program

Save this as hello.esq:

fn main() -> i32 = 42

That is the entire program. main is a function with zero parameters that returns i32 (a 32-bit signed integer). The body of any fn in esque is a single expression introduced by =, no return, no braces required.

Compile and run

./esquec build hello.esq -o hello
./hello; echo $?
# 42

The exit status of the process is whatever main returned. That is the contract.

Add some arithmetic

fn main() -> i32 = (10 + 3) * 2 - 1
./esquec build hello.esq -o hello
./hello; echo $?
# 25

esque parses arithmetic with the precedence you expect: * and / bind tighter than + and -; parentheses override.

If you want stdout output instead of just an exit code, use the print_i32 intrinsic. Functions that perform I/O must be annotated @io:

@io fn main() -> i32 = print_i32(7)
./esquec build hello.esq -o hello
./hello
# 7
echo $?
# 7

print_i32 writes its argument followed by a newline, then returns its argument unchanged so the call can sit in expression position. That is why the exit status above is 7: main simply forwards the return value of print_i32(7). To exit with a different code, sequence the print and yield a separate value, e.g. @io fn main() -> i32 = { print_i32(7); 0 }.

There is also print_f32 for floats and print_str for strings. The @io effect tracks side effects in the type system: a pure function (no @io annotation) cannot call an @io function.

Inspect the pipeline

The compiler can dump every intermediate stage:

./esquec build hello.esq --emit=ast # parsed AST
./esquec build hello.esq --emit=ceir # core IR (SSA, ANF, fully typed)
./esquec build hello.esq --emit=mir # matrix IR
./esquec build hello.esq --emit=asm # hex of emitted machine code per fn
./esquec build hello.esq --emit=obj -o hello.o # stop at the .o file

These are explained in the Reference → Compiler internals.

Next: Tour of esque