Eskiueskiu v0.7.0
Quickstart

Get Eskiu running

Download a prebuilt binary, write your first program, and run it. A few minutes start to finish, with no toolchain to assemble.

Install

Grab the build for your platform. The standard library ships inside the tarball, so imports work the moment it's unpacked.

↓ Linux (x86-64) ↓ macOS (Apple Silicon) ↓ Windows (x86-64) (experimental)

Windows is experimental: the compiler runs and emits object files, but end-to-end linking, exceptions, and networking are still being ported across the 0.7.x releases.

Unpack it into /usr/local and check the version:

# macOS (Apple Silicon)
tar -xzf eskiuc-macos-arm64.tar.gz -C /usr/local

# Linux (x86-64)
tar -xzf eskiuc-linux-x86_64.tar.gz -C /usr/local

# Windows (x86-64): unzip, then add the bin\ folder to PATH
Expand-Archive eskiuc-windows-x86_64.zip -DestinationPath C:\eskiu

eskiuc --version
Eskiu 0.7.0 (LLVM ...)

The tarball installs:

Linking needs a C toolchain on your machine (clang or gcc), the same one Rust and Clang call to produce a binary. macOS has it via the Xcode command-line tools; on Linux, install build-essential (or gcc).

Hello, Eskiu

Create hello.esk:

extern int printf(string fmt, ...);

int add(int a, int b) {
    return a + b;
}

int main() {
    int result = add(5, 3);
    printf("Hello from Eskiu!\n");
    printf("Result: %d\n", result);
    return 0;
}

Compile and run it in one step. eskiuc run builds a temporary native binary, runs it, and cleans up:

eskiuc run hello.esk
Hello from Eskiu!
Result: 8

Or keep the binary. When the -o name has no .o extension, eskiuc links it into an executable for you:

eskiuc hello.esk -o hello && ./hello

Want just the object file? Use a .o name, then link it yourself:

eskiuc hello.esk -o hello.o && clang hello.o -o hello && ./hello

A struct with a method

Structs hold data. Methods are plain functions that take a pointer to the struct as their first argument.

extern int printf(string fmt, ...);

struct Point {
    int x;
    int y;
}

int Point_sum(Point* self) {
    return self.x + self.y;
}

int main() {
    let p: Point;
    p.x = 3;
    p.y = 7;
    int s = Point_sum(&p);
    printf("sum = %d\n", s);   // sum = 10
    return 0;
}

alloc / free with pointer arithmetic

alloc<T>(n) (from the <mem> stdlib) allocates n elements of type T and returns a typed pointer. Index with []. Call free when you're done. The memory is yours to account for.

import <mem>;
extern int printf(string fmt, ...);

int main() {
    *int buf = alloc<int>(4);
    buf[0] = 10;
    buf[1] = 20;
    buf[2] = 30;
    buf[3] = 40;
    int sum = buf[0] + buf[1] + buf[2] + buf[3];
    printf("sum = %d\n", sum);   // sum = 100
    free(buf);
    return 0;
}

Lambdas

Functions are first-class values. Write a lambda with the same syntax as a regular function, minus the name:

extern int printf(string fmt, ...);

int apply(fn(int)->int f, int x) {
    return f(x);
}

int main() {
    let double_it: fn(int)->int = int(int x) { return x * 2; };
    printf("%d\n", double_it(5));          // 10
    printf("%d\n", apply(double_it, 4));   // 8
    return 0;
}

fn(int)->int is the function-pointer type. The lambda int(int x) { ... } produces a value of that type.

What's next