I I Language C-shaped systems programming

Transpiles to C

The I systems programming language

I keeps the target close to C while making declarations, generics, module output, and metaprogramming feel smaller and more direct.

Direct

Generates C, keeps the runtime visible, and lets the normal C toolchain do the final native build.

Generic

Monomorphized structs and procedures give you reusable data structures without moving into C++.

Reflective

Structs and enums produce metadata for fields, offsets, names, sizes, and future tooling.

Quickstart

Build, translate, compile

Initialize modules

Pull Haikal, tree-sitter, and support scripts.

git submodule update --init --recursive

Build compiler

Uses Bunyan to run Haikal codegen before CMake.

python bunyan.py build debug

Run sample

Generates C from src/main.i.

python bunyan.py run debug

End-to-end smoke test

Translate, compile the generated C, and run it.

i.bat

Features

Small syntax, real C output

I is designed as a focused compiler front-end. The generated C remains visible and normal toolchains do the final build.

Declaration-first syntax

Variables, types, procedures, and globals use name: type, keeping type information near the symbol being introduced.

Generics with monomorphization

Generic structs and procs use <T>. Concrete uses such as Array<i32> emit concrete C names.

Template specialization

Known types in generic positions specialize the body, so print<Payload> is the typed extension point behind printfmt.

Constraint-style requirements

Procedures can declare a requirement like proc<T:hash>, then call the matching typed implementation.

C-shaped control flow

if, for, while, do while, switch, break, and continue map directly to C.

Interop by design

Use external for declarations that already exist in C headers and external_emit when I should emit a prototype.

Generated module headers

The compiler writes a companion header next to the generated C so imports can type-check against I modules.

Reflection metadata

Struct and enum output includes reflection records for names, sizes, fields, offsets, and enum values.

Readable diagnostics

Lexer, parser, and semantic errors include source path, line, and column.

C Interop

Use C without hiding it

I emits C includes, defines, declarations, and line directives. The generated C is an artifact you can inspect and debug.

Imports

import "math.i"
cinclude "stdio.h"
define("SAHA_IMPLEMENTATION")

import is for I modules. C headers are included through emitted C includes.

External declarations

puts: proc(text: *const char)->i32 = { external; }
fx_step: proc(dt: f32)->void = { external_emit; }

external type-checks only. external_emit also writes a C prototype.

Compiler CLI

build\I.exe compile [input.i] -o [output.c]
build\I.exe check [input.i] --diagnostics=json

Use compile, check, symbols, or lsp. The old positional compile form still works.

Build Flow

What happens when you run it

  1. 1

    Bunyan configures the repo with CMake and clang-cl.

  2. 2

    Haikal scans src/main.c for template(Vec(...)) declarations and generates container headers.

  3. 3

    CMake builds I.exe.

  4. 4

    I.exe translates .i source into C and a companion header.

  5. 5

    The C compiler turns the generated C into the native executable.