ALPHA: breaking changes expected. What that means
NanoC

A five-minute tour

Every snippet below is compiled by the real compiler when this site is built; the C on the right is its actual output.

1. Functions and results

A function is f name(params) type. The last expression is the result, and < value returns early.

NanoC
f add(a: i32, b: i32) i32
  a + b
f main
  add(2, 3) != 5
C
int add(int a, int b) {
    return a + b;
}

int main(void) {
    return add(2, 3) != 5;
}

2. Locals and loops

name := literal infers a type from a literal. Otherwise write name: Type = value. Loops use plain C headers without braces.

NanoC
f main
  total := 0
  for i := 1; i <= 10; i++
    total += i
  total != 55
C
int main(void) {
    int total = 0;
    for (int i = 1; i <= 10; i++) {
        total += i;
    }
    return total != 55;
}

3. Branches and loop words

if, elif, else and while work as in C. ! breaks and ^ continues.

NanoC
f first_negative(a: *i32, n: i32) i32
  for i := 0; i < n; i++
    if a[i] < 0
      < i
  < -1
f main
  v: i32[] = {3, 1, -4, 1}
  first_negative(v, 4) != 2
C
int first_negative(int *a, int n) {
    for (int i = 0; i < n; i++) {
        if (a[i] < 0) {
            return i;
        }
    }
    return -1;
}

int main(void) {
    int v[] = {3, 1, -4, 1};
    return first_negative(v, 4) != 2;
}

4. Structs, unions, enums

NanoC
s Point
  x,y: f64
e Color red,green=5,blue
f main
  p: Point = {1, 2}
  p.x + p.y != 3 || blue != 6
C
typedef struct Point Point;
struct Point {
    double x,y;
};

typedef enum {
    red,
    green=5,
    blue
} Color;

int main(void) {
    Point p = {1, 2};
    return p.x + p.y != 3 || blue != 6;
}

5. Macros

@m defines a token template with $ captures. It runs before C is emitted and leaves no runtime trace.

NanoC
@m twice($x)
  (($x) * 2)
f main
  @twice(21) != 42
C
int main(void) {
    ((21) * 2) != 42;
}

6. Code that runs at translate time

@tt runs a small program while compiling and emits C. Here the compiler builds a table.

NanoC
@tt
  xs := []
  for i 0..4
    xs = push(xs, str(i * i))
  emit("static const int squares[] = {" + join(xs, ",") + "};")
f main
  squares[3] != 9
C
static const int squares[] = {0,1,4,9};

int main(void) {
    return squares[3] != 9;
}

7. Plain C stays plain C

Lines that NanoC does not recognize pass through, and @c embeds a verbatim C island.

NanoC
@c
  static int twice(int x) { return 2 * x; }
f main
  twice(21) != 42
C
static int twice(int x) { return 2 * x; }

int main(void) {
    return twice(21) != 42;
}

Where next