moonshot

technical

c0

c0 compiles to freestanding binaries, code that assumes no runtime and no standard library beneath it,which is the only way a language can be used to write a kernel because the thing it is meant to write is a kernel. the feature set grows only when moonshot actually needs it. that is why c0 was pushed past the point of merely compiling itself, and on toward being a real, capable language.

one type

c0 has a single value type, int, a 64-bit signed integer.there is no unsigned type and no array type. a consequence worth knowing is that division is signed and truncating, so packed bit patterns are kept below 32 bits where the sign bit cannot interfere. numbers, characters, truth values and addresses are all an int. memory is handled through an address value, and the builtins below read and write through it.

the shape of a program

the syntax is a small, familiar subset of C. functions (up to sixteen parameters, the first six in registers, the rest on the stack, with recursion), global and local variables, if/else, while, for, the usual arithmetic and comparison operators, character literals with escapes, string literals, and // comments. a program starts at main. source can be split across files with the include directive, which coff resolves by plain textual substitution.

include "file.c0";

// this is a comment.
int main() {
    int i = 0;
    int sum = 0;
    while (i < 5) {
        sum = sum + i;
        i = i + 1;
    }
    return sum;
}

naming memory instead of counting it

c0 has no structs, but it has layout. a layout declaration does not introduce a new value type. it just gives names to a run of 8-byte offsets, so code that would otherwise be store64(e + 16, v) can read e.vx = v instead. everything is still an int and a layout is a naming convention over the load/store builtins, not a second type system next to them.

layout Entity {
    int x;
    int y;
    int vx;
    int vy;
}

int main() {
    int e;
    e = alloc(sizeof(Entity));
    e.x = 10;
    e.vx = 1;
    return e.x + e.vx;
}

sizeof(Name) resolves at compile time to that layout's field count times 8. the result is a plain integer, usable anywhere one is, most often right inside alloc(...).

field names live in one flat table shared by every layout in the program, not one scoped per layout. c0 has no type system, so e.x cannot be checked against "the layout e was allocated as." the first layout to declare a field name fixes its offset and any other layout reusing that name must declare it at the same position, otherwise it is a compile error. two layouts can each have their own x and y as long as both agree x comes first. this is the same "trust the programmer, one flat namespace" spirit as c0's single function/global namespace.

builtins instead of a standard library

there is no standard library. a small set of builtins covers what the language itself cannot express. alloc hands out zeroed memory, and load8/store8/load64/store64 read and write it a byte or eight bytes at a time. print and write produce output, open and read take files in, and exit ends the program. hosted programs (like coff itself) get argc/argv. the kernel uses none of the hosted builtins and talks to hardware through the load/store pair instead.

the set is not frozen, a builtin is added when moonshot needs one the language cannot otherwise reach, the same rule the language itself grows by. a general standard library, though, is not a goal, for now, the kernel is meant to build what it needs out of the primitives above.

the whole language

this is the entire vocabulary, c0 is small enough that it fits in a list.

types
int only, a 64-bit signed integer, which also stands in for characters, truth values and addresses.
keywords
int, extern, if, else, while, for, return, break, continue, layout, sizeof.
directives
include "file.c0"; splices another source file in as text, resolved by coff before compilation.
structure
functions of up to sixteen parameters (recursion allowed), global and local variables, layout declarations (named offsets, not a real aggregate type, see above), and main as the entry point.
operators
the arithmetic + - * /, the comparisons == != < <= > >=, and = for assignment.
literals
integers, character literals with escapes, and string literals.
comments
// to the end of the line.
builtins
alloc, load8, store8, load64, store64, print, write, open, read, exit, and (hosted only) argc, argv, described just above.

things are missing on purpose

a feature is added when moonshot produces a concrete need for it, and not before, because every feature the language gains is also code the compiler must carry, correctly, forever. c0 has to stay small enough that its compiler can be held in your head and re-verified against the bootstrap oracle.