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, punctuation
lexer.zigTokenizer with comment skipping, string/number/identifier support
ast.zigAST node definitions with packed string refs and extra data array
parser.zigRecursive descent parser with precedence climbing for expressions
checker.zigType checker with scoped symbol table, struct and function registration
codegen.zigC emitter — interface→struct, console.log→printf, type-driven output
main.zigCLI entry point

Supported types

number→ double
boolean→ bool
string→ const char*
void→ void
i32→ int32_t
i64→ int64_t
f32→ float
f64→ double
T[]→ 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:

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.