The Prelude module contains commonly used functions and types that are imported implicitly into every module.



A string type that owns its contents.

Strings in Ante are null terminated and contain a length field.

type Str = c8* cStr, usz len


let s1 = "Hello"
let s2 = Str("Hello".cStr, 5usz)
let s3 = Str(strdup "hi", 2usz)

Maybe ’t

Represents either the presence of a value with Some, or the absence of a value with None.

type Maybe 't =
   | Some 't
   | None

Maybe is often used throughout the standard library to represent failure. For example, if an allocation can fail None is returned instead of a null pointer. Unlike null pointers and error codes, the Maybe type forces the error case to be checked via a match expression before its value is used.


//Parsing integers can fail if the string is
//non-numeric so represent failure with None
fun parse_int: Str s -> Maybe i32
    if not is_numeric s then
        return None
    Some int

assert <| parse_int "54" = Some 54

//print None
match parse_int "non-numeric string" with
| Some n -> print n
| None -> print "None"


Represents a lazy range of values from start to end incrementing by step each time. This range is start-inclusive and end-exclusive.

type Range = i32 start end step


//print 0 to 9 inclusive
let r = Range(0, 10, 1)
for x in r do print x

//corresponding C code:
//for(int i = 0; i < 10; i += 1){
//    printf("%d\n", i);

//Ranges can also be constructed with ..
let arr = [2, 3, 5, 6, 8]
for i in 0 .. arr.len do
    print (arr#i)


A file that can be read from.

type InFile = File


let f = InFile "file.txt"

let line1 = f.next_line ()
let line2 = f.next_line ()

for line in InFile "file2.txt" do
    print line


A file that can be written to. If the file does not yet exist, a new one will be created. An already existing file will be overwritten by default or appended to if the append flag was passed when the OutFile was made.

type OutFile = File


let f = OutFile "out.txt"
f.write "Hello!\n"
fclose f

let f_append = OutFile "out.txt" Append 
f_append.write "Hello again!"

C Types

Wrappers for some common types in C.


type File = void*


type FilePos = void*



Types that implement either Iterable or Iterator are able to be used in for loops as an iterator.

Types that are Iterable are not directly iterated over but provide a function that returns an object that can iterate over them. This is useful for types that would be too expensive to be copied or want to prevent mutation and would rather provide an immutable view that can iterate over them.

trait Iterable
    fun into_iter: Iterable i -> Iterator


Types that implement either Iterable or Iterator are able to be used in for loops as an iterator.

Iterators are immutable and return a new Iterator on each run of the loop.

trait Iterator
    fun next: Iterator i -> Iterator
    fun unwrap: Iterator i -> 't
    fun has_next: Iterator i -> bool

Implemented by Range and InFile in the prelude.

An iterator in a for loop is implicitly translated by the compiler into a while loop using the functions above. All for loops in the form:

for e in iterator do

Are equivalent to the following while loop:

mut i = iterator
while has_next i do
    let e = unwrap i
    i := next i

Example Implementation

type BackwardsRange = i32 start end

ext BackwardsRange : Iterator
    fun next: BackwardsRange r =
        BackwardsRange(r.start-1, r.end)

    fun unwrap: BackwardsRange r =

    fun has_next: BackwardsRange r =
        r.start > r.end



Compares the structural equality of two values.

fun (=): Maybe l r -> bool
!inline fun (=): 't* l r -> bool
fun (=): void* l r =
    Ante.error "Cannot call = on a void*!  Use 'is' to compare addresses!"
fun (=): Str l r -> bool


Equal to not (a = b)

!inline fun (!=): Str l r -> bool


Compare the identity (referential equality) of two values.

!inline fun (is): Str l r -> bool


Dumps the type and value of an expression to stdout during compile-time

ante fun Ante.debug: 't t


Returns the size of a type in Bytes. Accepts types or values as an argument

ante fun Ante.sizeof: 't t -> usz

Store values during compile-time to be retrieved later. Storing a value with stores it in an internal table in the compiler separate to the scope table of variables. This results in variables stored with this function being able to be retrieved later at a possibly different global scope.

Values stored with this function will not be able to be retrieved through any way except for the function Ante.lookup.

ante fun c8* name, 't val


ante fun store_val:
    let pi = 3.14159265 "my val" v

store_val ()

Ante.lookup "my val" ?
    Some n -> print n
    None -> Ante.error "my val not found!"


Lookup variables stored with

Ante.lookup will never reference variables not stored with

ante fun Ante.lookup: c8* name -> Maybe 't


Issues a compilation error with the given message.

This function will mark the function that issued it as having errored and will cease compilation of the function.

This function should only be used in compile-time code. If used in normal code that contains values not known during compile-time (non-ante values), this function will always be compiled and thus always issue an error even if it is behind an else branch that may or may not execute.

ante fun Ante.error: c8* msg


type Context =
    bool debug

//load config during compile-time
//useful to change compilation options with a cfg file automatically
ante fun load_config: Str config_name -> Context
    let f = config_name ?
        None -> Ante.error "Config file ${config_name} not found"

    let res = f.find_regex "debug = (true|false)"
    bool.parse res ?
        Some b -> Context b
        None -> Ante.error "Config must set debug to either true or false"

let cfg = load_config "config.cfg"
Ante.set_mode (if cfg.debug then Debug else Release)


Emits the llvm intermediate representation of the current module to stdout.

ante fun Ante.emitIR:


Instruct the compiler to forget about a function and remove it from the list of functions able to be called. This will not affect any call instances that were already compiled and already refer to this function.

Useful in the repl to redefine functions

ante fun Ante.forget: c8* function_name

Example (repl)

: fun get_num := 4
: get_num ()
: fun get_num := 5
(unknown file): 3,8-14  error: Function get_num was redefined

: Ante.forget "get_num"
: fun get_num := 6
: get_num ()


Prints a value with no endline.

!inline fun i8.printne: i8 x
!inline fun i16.printne: i16 x
!inline fun i32.printne: i32 x
!inline fun i64.printne: i64 x
!inline fun isz.printne: isz x
!inline fun u8.printne: u8 x
!inline fun u16.printne: u16 x
!inline fun u32.printne: u32 x
!inline fun u64.printne: u64 x
!inline fun usz.printne: usz x
!inline fun f16.printne: f16 x
!inline fun f32.printne: f32 x
!inline fun f64.printne: f64 x
!inline fun c8.printne: c8 x
!inline fun bool.printne: bool b
!inline fun printne: c8* s
!inline fun printne: Str s
!inline fun printne: 't x

The unspecialized printne:'t will attempt to cast its argument to a Str before outputting the Str.


Print a value with a trailing newline.

Print uses printne internally and thus only printne needs to be implemented for a type to be printable. If a type is not directly printable, print:'t will attempt to convert it to a Str before printing.

!inline fun print: 't x
!inline fun Str.print: Str s


Performs the cast of a Str to a c8* c-string.

This cast returns a non-owning reference to the cStr field of the string.

!implicit !inline fun c8*.init: Str s -> c8*


Returns a new string that is the reverse of the given string.

fun Str.reverse: Str s -> Str


assert <| reverse "hello" = "olleh"


Create a string from the given value.

fun Str.init: i64 i -> Str
fun Str.init: u64 i -> Str
!inline fun Str.init: i8 x -> Str
!inline fun Str.init: i16 x -> Str
!inline fun Str.init: i32 x -> Str
!inline fun Str.init: isz x -> Str
!inline fun Str.init: u8 x -> Str
!inline fun Str.init: u16 x -> Str
!inline fun Str.init: u32 x -> Str
!inline fun Str.init: usz x -> Str
!inline fun Str.init: c8* cStr -> Str


let five = Str.init 5

let two_thousand = Str.init 2000_u16

//T.init functions are cast functions and
//thus the .init can be omitted
let fifty = Str 50usz

let hi = Str (strdup "hi")


Parses an unsigned integer from a string.

If the string is non-numeric or contains a floating-point or negative number this function will return None. Otherwise, it will return Some value.

fun u64.parse: Str s -> Maybe u64


assert <| u64.parse "53" = Some 53_u64

assert <| u64.parse "-5" = None


Parses a signed integer from a string.

If the string is non-numeric or contains a floating-point or negative number this function will return None. Otherwise, it will return Some value.

fun i64.parse: Str s -> Maybe i64


assert <| u64.parse "-1000" = Some(-1000_i64)

assert <| u64.parse "23.5" = None


Returns true if a is in the range r

fun (in): i32 a, Range r -> bool


3 in 1..5  //=> true

4 in 2..4  //=> false

0 in 0..5  //=> true


Creates an end-exclusive range with a step of 1.

fun (..): i32 start end -> Range

Creates an end-exclusive range with a step equal to the difference of the first two elements in the range.

fun (..): i32,i32 first_two, i32 end -> Range


Vec(1..4)  //=> [1, 2, 3]

Vec( (0,5)..25 )  //=> [0, 5, 10, 15, 20]

Vec( (5,4)..0 )  //=> [5, 4, 3, 2, 1]


The append operator. Appends two strings together and returns a new string leaving the two given strings intact.

fun (++): Str s1 s2 -> Str


let s = "hello " ++ "world"
assert (s = "hello world")


Retrieves the character at the given index from the string.

!inline fun (#): Str s, i32 index -> c8

Replace the original character at index i with a new character.

!inline fun (#): mut Str s, i32 i, c8 c


Creates an InFile from the given file name.

!inline fun InFile.init: Str fName -> InFile


let f = InFile "file.txt"


Creates an InFile from the given file name.

If the file does not exist yet, a new one will be created.

!inline fun OutFile.init: Str fName -> OutFile


let f = OutFile "out.txt"


Write the given text to a file. If the file already exists it will be overwritten.

!inline fun OutFile.write: OutFile f, c8* cStr
!inline fun OutFile.write: OutFile f, c8 c
!inline fun OutFile.write: OutFile f, Str s


let f = OutFile "out.txt"

f.write "Hello"
f.write ' '
f.write "World"


Returns the next line from a file up to but not including the newline character. If the end of the file is reached an empty string will be returned on all successive calls.

fun InFile.next_line: InFile f -> Str
//Given the file "in.txt" containing:
//hello there

let f = InFile "in.txt"
next_line f  //=> "hi"
next_line f  //=> "hello there"
next_line f  //=> ""
next_line f  //=> ""


Print a message without a trailing newline to stdout then get and return user input.

fun input: c8* msg -> Str


let s = input "Enter your name: "
// s now contains input from stdin

C Functions


fun printf: c8* fmt, ... -> i32


fun puts: c8* str -> i32


fun putchar: c8 char


fun getchar: -> c8


fun exit: i32 status


fun malloc: usz size -> void*


fun calloc: usz num size -> void*


fun realloc: void* ptr, usz size -> void*


fun free: void* mem


fun memcpy: void* dest src, usz bytes -> void* /*dest*/


fun system: c8* cmd -> i32


fun strlen: c8* str -> usz


fun fopen: c8* fName, c8* mode -> File


fun fclose: File file


fun fputs: c8* str, OutFile file


fun fputc: c8 char, OutFile file


fun fgetc: InFile file -> c8


fun fgets: c8* str, i32 numBytes, InFile file -> c8*


fun ungetc: c8 c, InFile file -> i32


fun fgetpos: File f, FilePos fp


fun ftell: File f -> i64


fun fsetpos: File f, FilePos fp


fun fseek: File f, i64 offset, i32 origin


fun feof: InFile f -> bool


fun ferror: File f -> bool