A small LLVM-based compiler for a safe, arena-oriented systems language. C<< focuses on deterministic, zero-runtime behavior and direct C ABI interoperability.
mkdir -p build
cd build
cmake ..
cmake --build .Compile a C<< source file:
./cshift examples/hello.cll -o helloEmit LLVM IR:
./cshift examples/hello.cll --emit-llvmEmit assembly:
./cshift examples/hello.cll --emit-asmCompile only to object file:
./cshift examples/hello.cll -cSemantic check only:
./cshift examples/hello.cll --check-onlyimport std;
entry
{
puts("Hello, C<< world!");
}
C<< is designed to be safe without fighting the compiler, and easy to use without runtime abstractions. So it does not have a GC (Garbage Collector), Borrow Checker or similar things and is fully arena-based. The runtime is only a minimal C-file for the standard library. It strictly separates:
- Data Patterns
- Logic Units
In summary, the design goals are:
- Performance
- Determinism
- Developer Experience
- Memory Safety
- Zero Runtime Abstractions
- Full C-ABI-interop with extern functions
- Cross Compilation
VOP (Vertical Ownership Programming) can be explained like this:
- A pointer MUST only point to a variable with a depth <= its own, while depth defines the current arena.
- A scope is equal to a arena, except of the lexical scopes (namespaces, structs, etc.). When the scope ends, the arena gets deleted.
- Functions MUST not use return values. VOP only uses tunnels, similar to pointers, declared under 'Syntax'
- A tunnel may not transfer data containing pointers to arenas that will be destroyed.
- reset clears the current arena. Forbidden if child arenas contain pointers into it.
Single-line and multiline comments are supported:
// Single-line comment
/* Multiline comment
spanning multiple lines */
C<< contains the following primitive Types:
int8
int16
int32
int64
uint8
uint16
uint32
uint64
float32
float64
bool
string
T*
Structs MUST only contain data, no methods. example:
struct Player
{
int32 id;
float32 health;
}
Enums are integer-backed. example:
enum Status : uint8 { Active, Inactive }
A pointer is never null. A variable is valid or voided. Any variable may be in the voided state. Accessing a variable wich could be voided without an switch-guard causes compile-time termination.
entry
{
int32 x;
int32* p = &x;
move x;
switch(p)
{
case valid {}
case voided {}
}
}
string banner = raw<until "Your_delimitter">
###########
# Hello C<< #
###########
Your_delimitter
puts(raw<3>
I can type \n here or \0 or \t and nothing happens
A Real newline is integrated into the string
No matter what you write here the string does not break.
);
Definition:
def name(parameters)
{
// arena
}
Properties:
- Functions have no type, but it is recommended to comment out their tunneled type.
- Functions may contain any number of tunnel operations.
- A function call is a statement.
- Tunnel values produced inside a function appear in the call scope if they were reserved.
- Inline usage of function results is forbidden except in reserve-initializers. Example:
def compute(int32 x) // tunnels int32 doubled
{
tunnel x * 2 -> int32 doubled;
}
classic:
reserve int32 result;
add(5, 7);
inline:
reserve int32 result = add(5, 7);
A function can tunnel multiple values. All values wich were reserved in the past and are tunneled by the function get filled. The others are ignored.
def compute(int32 x, int32 y)
{
tunnel x + y -> int32 sum;
tunnel x * y -> int32 product;
}
entry
{
reserve int32 sum;
reserve int32 product;
compute(8, 4);
}
Arrays:
T[] // arena-bound array
Slices:
T[:] // pointer + length, non-owning
Slices may only reference arenas that outlive them.
for (int32 i = 0; i < 5;)
{
// arena
i += 1;
}
Supported constructs:
if/elseswitch/case/defaultwhileforforeachbreak— exit innermost loop or switchcontinue— restart next loop iteration
Each iteration of while/for/foreach is its own sub-arena. Tunnels inside switch/case must target variables in the parent scope.
Generic programming via compile-time template instantiation:
template<typename T>
struct Vector
{
T* data;
uint64 len;
uint64 capacity;
}
template<typename T>
def vec_push(Vector<T>* v, T elem)
{
// implementation
tunnel result -> int32 success;
}
Templates are fully instantiated at compile time, enabling zero-runtime polymorphism and safe generic containers.
The standard library (std.cll) provides 16+ high-performance generic containers:
Core Containers:
Vector<T>— chunk-based dynamic array (zero-copy allocation)HashMap<K, V>— hash table with chainingLinkedList<T>— doubly-linked listSet<T>— hash set for unique elementsDeque<T>— double-ended queue with ring bufferRingBuffer<T>— fixed-size circular buffer (lock-free safe)Pool<T>— object pool for allocation-free patterns
Utility Types:
Pair<A, B>— simple tupleLazy<T>— compute-on-demand cachingBitSet— compact bitfield operationsGuard— RAII-style scope guards for cleanupStringBuilder— efficient chunked string buildingBuffer<T>— safe typed buffers with capacity managementSortedVec<T>— sorted containers with custom comparators
All use template-based generic monomorphization for compile-time type safety and zero-runtime overhead.
Syntax:
import <type> <fn_name> (<params>);
This Project is licensed under the Apache 2.0 License