Documentation
Usage
zigtsc <input.ts> # print C to stdout zigtsc <input.ts> <output.c> # write C to file
zigtsc reads a .ts file, parses the TypeScript subset, type-checks it, and emits idiomatic C. The generated C compiles with any standard C compiler.
Build from source
git clone https://github.com/nathanjmorton/zigtsc cd zigtsc zig build -Doptimize=ReleaseFast export PATH="$PWD/zig-out/bin:$PATH"
Requires Zig 0.16.0.
Compiler pipeline
source.ts → Lexer → Tokens → Parser → AST → Type Checker → C Codegen → output.c
Each stage is a separate Zig source file with clear input/output boundaries.
token.zigToken type definitions — keywords, operators, literals, punctuationlexer.zigTokenizer with comment skipping, string/number/identifier supportast.zigAST node definitions with packed string refs and extra data arrayparser.zigRecursive descent parser with precedence climbing for expressionschecker.zigType checker with scoped symbol table, struct and function registrationcodegen.zigC emitter — interface→struct, console.log→printf, type-driven outputmain.zigCLI entry pointSupported types
number→ doubleboolean→ boolstring→ const char*void→ voidi32→ int32_ti64→ int64_tf32→ floatf64→ doubleT[]→ double* (simplified)interface Foo { ... }→ typedef struct { ... } Foo;Supported syntax
Variables
let x: number = 42; → double x = 42; const msg: string = "hi"; → const char* msg = "hi";
Functions
function add(a: number, b: number): number {
return a + b;
}
→ double add(double a, double b) {
return (a + b);
}Interfaces → Structs
interface Point { → typedef struct {
x: number; double x;
y: number; double y;
} } Point;Control flow
if / else if / else, while, for (C-style 3-part), return — all map directly to their C equivalents.
Expressions
Arithmetic (+ - * / %), comparison (< > <= >= == != === !==), logical (&& || !), assignment (= += -= *= /=), function calls, member access (a.b), index access (a[i]).
console.log
console.log(x) is transpiled to printf() with format strings inferred from types: %g for numbers, %s for strings, %d for booleans.
Explicitly excluded
These TypeScript features are intentionally unsupported for clean C mapping:
class,this, prototypes- Closures / capturing nested functions
async/await, Promises- Generics, union types,
any,unknown - Decorators, destructuring, spread, optional chaining
eval,new Function()
Memory model
Stack allocation by default for scalars and small structs. Arrays are heap-allocated with malloc — the caller is responsible for free. There is no garbage collector. The language is explicitly manual-memory, like C itself.
Examples
Three example programs are included in the examples/ directory:
hello.ts
const message: string = "hello world"; console.log(message);
fib.ts
function fib(n: number): number {
if (n <= 1) { return n; }
return fib(n - 1) + fib(n - 2);
}
const result: number = fib(10);
console.log(result);structs.ts
interface Point { x: number; y: number; }
function distance(a: Point, b: Point): number {
let dx: number = b.x - a.x;
let dy: number = b.y - a.y;
return dx * dx + dy * dy;
}
const p1: Point = { x: 0, y: 0 };
const p2: Point = { x: 3, y: 4 };
console.log(distance(p1, p2));Running tests
zig build test --summary all
The test suite includes 13 tests covering the lexer, parser, and end-to-end codegen. All tests pass with zero memory leaks.