Direct
Generates C, keeps the runtime visible, and lets the normal C toolchain do the final native build.
Transpiles to C
I keeps the target close to C while making declarations, generics, module output, and metaprogramming feel smaller and more direct.
Generates C, keeps the runtime visible, and lets the normal C toolchain do the final native build.
Monomorphized structs and procedures give you reusable data structures without moving into C++.
Structs and enums produce metadata for fields, offsets, names, sizes, and future tooling.
Quickstart
Pull Haikal, tree-sitter, and support scripts.
git submodule update --init --recursive
Uses Bunyan to run Haikal codegen before CMake.
python bunyan.py build debug
Generates C from src/main.i.
python bunyan.py run debug
Translate, compile the generated C, and run it.
i.bat
Features
I is designed as a focused compiler front-end. The generated C remains visible and normal toolchains do the final build.
Variables, types, procedures, and globals use name: type, keeping type information near the symbol being introduced.
Generic structs and procs use <T>. Concrete uses such as Array<i32> emit concrete C names.
Known types in generic positions specialize the body, so print<Payload> is the typed extension point behind printfmt.
Procedures can declare a requirement like proc<T:hash>, then call the matching typed implementation.
if, for, while, do while, switch, break, and continue map directly to C.
Use external for declarations that already exist in C headers and external_emit when I should emit a prototype.
The compiler writes a companion header next to the generated C so imports can type-check against I modules.
Struct and enum output includes reflection records for names, sizes, fields, offsets, and enum values.
Lexer, parser, and semantic errors include source path, line, and column.
C Interop
I emits C includes, defines, declarations, and line directives. The generated C is an artifact you can inspect and debug.
import "math.i"
cinclude "stdio.h"
define("SAHA_IMPLEMENTATION")
import is for I modules. C headers are included through emitted C includes.
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.
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
Bunyan configures the repo with CMake and clang-cl.
Haikal scans src/main.c for template(Vec(...)) declarations and generates container headers.
CMake builds I.exe.
I.exe translates .i source into C and a companion header.
The C compiler turns the generated C into the native executable.