Experimental language prototype

CX Language

CX is an experiment in building a friendlier C-like language and toolchain that transpiles to readable C. It works for examples and small programs, but the language and standard library are still changing.

Command line

Try CX from a terminal

cx new hello-cx
cd hello-cx
cx run
cx test
cx test --std

Transpiles to C

Readable output is the point

CX keeps the language close to C and lowers features into ordinary C shapes: structs, functions, enums, tagged records, function pointers, and explicit allocator calls.

CX
fn add(a: int, b: int) -> int {
    let total: int = a + b;
    return total;
}
C
int add(int a, int b)
{
    int total = a + b;
    return total;
}

Language tour

Small feature set, sharp edges rounded off

C, But Friendlier

  • Functions with return types
  • Struct methods and extensions
  • Top-level constants and globals
  • Named initializers

Useful Type Power

  • Generics for reusable containers
  • Tagged unions with match
  • Interfaces as C vtables
  • Structural requirements

Tooling First

  • Transpile, build, run
  • Project config with cx.toml
  • Built-in test discovery
  • Readable generated C

Examples

Real CX code

Vec and Foreach

import c.stdio;

fn main() -> int {
    let values = Vec<int>.create();
    values.add(10);
    values.add(20);
    values.add(30);

    foreach value in values {
        printf("Value %d\n", value);
    }

    values.free();
    return 0;
}

Tagged Union

union Value {
    Number: int;
    Position: Point;
}

fn score(value: Value*) -> int {
    match value {
        Number: n => return n;
        Position: p => return p.x + p.y;
        _ => return 0;
    }
}

Tests

test "stack length" {
    let stack = Stack<int>.create();
    stack.push(10);
    expect(stack.length == 1);
    stack.free();
}

Standard library

Small core, useful primitives

Allocator-aware containers

Vec<T> can use the default C allocator or a caller-provided allocator, so the same container works with heap memory, fixed buffers, arenas, and future allocator shapes.

import std.core;

fn main() -> int {
    let buffer: u8[256];
    let fixed: FixedBufferAllocator =
        FixedBufferAllocator.from_buffer(&buffer[0], 256);
    let allocator: Allocator = fixed;

    let values: Vec<int> = Vec<int>.with_allocator(&allocator, 4);
    values.add(10);
    values.add(20);
    values.add(30);

    let total: int = 0;
    foreach value in values {
        total += value;
    }

    values.free();
    return 0;
}

Vec<T>

let values = Vec<int>.create();
values.add(10);
values.add(20);
values.free();

StringView

let text = StringView.from_cstr(" hi ");
let trimmed = text.trim();
let ok = trimmed.equals_cstr("hi");

StringBuilder

let builder = StringBuilder.create();
builder.append_cstr("hello");
builder.append_char(' ');
builder.append_cstr("cx");
builder.free();

HashMap<K, V>

let routes = HashMap<StringView, int>.create();
routes.put(StringView.from_cstr("/health"), 200);
let status = routes.get(StringView.from_cstr("/health"));
routes.free();

HashSet<T>

let seen = HashSet<int>.create();
seen.add(10);
let ok = seen.contains(10);
seen.free();

Option<T>

let value = StringView.from_cstr("123").parse_int();
if (value.has_value) {
    return value.value;
}

Result<T, E>

let file = File.open("data.txt");
if (file.is_ok) {
    file.value.free();
}

File

let file = File.create("notes.txt");
file.write_cstr("hello cx");
file.free();

Path

let path = StringView.from_cstr("src/main.cx");
let name = Path.file_name(path);
let ext = Path.extension(path);

Bitmap

let bitmap = Bitmap.create(64, 64);
bitmap.clear(Color32 { r: 16, g: 16, b: 16, a: 255 });
bitmap.save("image.bmp");
bitmap.free();

Allocator

let buffer: u8[256];
let fixed = FixedBufferAllocator.from_buffer(&buffer[0], 256);
let allocator: Allocator = fixed;

JsonWriter

let json = JsonWriter.create();
json.begin_object();
json.name("ok");
json.bool_value(true);
json.end_object();
json.free();

Current shape

A native-code playground that can grow into a serious tool

CX is not a finished language yet. It is a working prototype for exploring better C ergonomics: native output, explicit memory, generics, tagged unions, interfaces, and a small standard library.

View source on GitHub