# Tig (tc-lang) — Simplest possible, usable systems language

# Tig 🦁

> Simplest possible, usable systems language

Repo: https://github.com/alonsovm44/tc-lang
Stars: ~40 · License: MIT (per README badge; GitHub API reports no detected SPDX license file) · Primary language: C · Version: 1.3.1s/1.3.2 · Platforms: Windows, Linux, macOS · Description: "A minimalistic ergonomic layer over C"

> Disclaimer: For stage0, Tig can use AI codegen for the C core (but test thoroughly); for stage1 of self-hosting, handwritten code only. See CONTRIBUTING.md.
> Note: see dogfood/ folder for non-trivial examples of Tig being used.

Tig is a minimalistic systems programming language.

## What's New in v1.3.2
1. Added C compiler flags using `--`
2. Added freestanding parameter to enable freestanding mode
3. Multiple file linking support
4. Added binary and hex literals
5. Removed old function syntax
6. Removed extern blocks

## Project Goals
1. Make the first usable systems language from Mexico.
2. Explore the bare minimum of what a systems language must have to be usable, modern and ergonomic.
3. Learn C and master Tig.
4. Make an OS with it.
5. Get a job.

## Philosophy

Why it was made: the author wanted an ergonomic systems language capable of anything, with fewer keywords than Go, no GC and without heavy runtime overhead; as safe as possible (but not necessarily proving safety). A language one could master and teach to others, and put Mexico on the map.

Backend: for now, C11. Core Ideal: Tig has to fit in a single person's head. Small but powerful.

Core principle:
> Everything that can be built with libraries has to be built with libraries. The core language is small.
> Explicit is better than implicit, but exceptions can be made.
> Flexibility over rigidity.
> Anything C can run, we run: anywhere C has run, we will run.

## Features

- **18 keywords** — `if`, `loop`, `break`, `defer`, `ret`, `strun`, `fn`, `use`, `pin`, `match`, `else`, `enum`, `async`, `select`, `throw`, `try`, `catch`, `raw`.
- **Zero-boilerplate async** — automatic runtime initialization, no manual setup.
- **Async functions** — `async fn`.
- **Concurrent data structures** — built-in `queue<T>` and `stack<T>`.
- **Ownership transfer** — `@` operator for safe resource transfer.
- **Select statements** — multi-operation waiting with `select`.
- **Pin** — keep variables alive across async boundaries.
- **No hidden magic** — no GC, no type inference, no shadowing, no aliasing.
- **Raw pointers** (`->`) and **fat pointers** (`=>`) with built-in slicing.
- **Manual memory** — `alloc()` / `free()` with `defer` for cleanup.
- **Packed structs** — no padding, predictable layout.
- **Rust-style errors** — colored diagnostics with source lines and carets.
- **One-step compile** — `tightc source.tc -c app` transpiles and compiles in one command.
- **Inline imports** — `@use "lib.tc"` inlines another `.tc` file at compile time.
- **CLI args** — `i32 fn main: =>->i8 args { ... }`.

## Quick Start
```bash
make                                # build the compiler (requires make)
./tigc stdlib/io.tc -o stdlib/io.h  # compile stdlib headers (once)
./tigc samples/fizzbuzz.tc -c fizzbuzz
./fizzbuzz
```

## How It Works

Tig is a source-to-source compiler (transpiler) written in ~4,600 lines of C. It reads `.tc` files and outputs portable C11.

```
source.tc -> [Lexer] -> [Parser] -> [AST] -> [Checker] -> [Emitter] -> output.c -> gcc/clang -> binary
```

### Pipeline
1. **Lexer** (`lexer.c`) — tokenizes source; tracks line/col for error reporting.
2. **Parser** (`parser.c`) — builds AST; handles operator precedence, scope-level `pin` enforcement, and `@use` file inlining (recursive parse + splice).
3. **Emitter** (`emitter.c`) — walks the AST and outputs C11. Most constructs are 1:1:

| Tig | Emitted C |
|---|---|
| `=>i32 s` | `tc_fat_i32 s` (struct with `.ptr` + `.len`) |
| `defer { free(p) }` | scope-exit statements emitted in reverse order before `}`/`return` |
| `pin x` | nothing emitted — enforced at parse time (compile error on reassignment) |
| `@use "lib.tc"` | declarations inlined directly into AST (no `#include`) |
| `alloc(T, n)` | `TC_ALLOC(T, n)` → `calloc(n, sizeof(T))` |
| `=>->i8 args` in main | `main(int argc, char **argv)` + local fat pointer wrapping them |

### What it is not
Not memory safe — no borrow checker, no GC; memory management is manual (arenas planned). Provides safety features: fat pointers, self-cleaning error functions, defer statements. No optimizer, no IR, no type-inference pass, no code generation beyond string concatenation of C. Can leverage LLVM flags from gcc/clang. Output is always readable, debuggable C (inspect with `tightc source.tc -o source.c`).

### What Tig is good for
CLI tools (tiny/no runtime overhead); embedded / bare-metal (no runtime, no allocator required, packed structs); game engine internals (manual memory, no GC pauses); learning compilers (small enough to read in an afternoon); C codebases that want better ergonomics.

## Syntax highlights

Hello world:
```
use "stdlib/io.tc"
fn i32 main: {
    print("hello, world")
    ret 0
}
```

- **Variables** are C-like, mutable by default; uninitialized default to `0`. `pin PI` makes a variable immutable in the current scope.
- **Functions:** `fn i32 add: i32 a, i32 b { ret a + b }`. Varargs via `...`.
- **Strunions** (`strun`) — a struct/union spectrum ([struct]—[strun]—[union]). `&` marks a union element sharing memory; anonymous types provide padding/grouping. Struns can contain methods (`fn void printPoint: self { ... }`).
- **Pointers:** `->` raw (address-of/deref), `=>` fat pointer (`.ptr`/`.len`), slicing `arr[1:3]`, pointer combos (`->->`, `=>->`, `->=>`, `=>=>`). Struct pointer access via `.>` (same as C's `->`).
- **Control flow:** `if/else if/else`, `loop { ... break }` (infinite), `loop if (cond) { ... }` (while alias), `match` statements with `_` wildcard and `=` arms.
- **Memory:** `alloc(i32, 100)` + `defer free(arr)` (braceless defer allowed).
- **Imports:** `use "lib.tc"` (link precompiled `.h`) vs `@use "lib.tc"` (inline `.tc` at compile time).
- **C FFI:** `"C"{ #include "clib.h" }`.
- **Error reporting:** Rust-style `error[E000]` diagnostics with source lines/carets; `tightc --error E000` prints help.

### Error system
Errors are a built-in type via `error`. An error is a function-like unit carrying context params plus handling/cleanup code, invoked with `throw`. `try`/`catch` blocks handle them; catch blocks work like `match` (specify which errors to catch and what return value to use, `_` wildcard).
```tig
error zero_division: i32 a, i32 b { printf("Error, division by zero: %d / %d", a, b) }
fn f64 divide: i32 a, i32 b {
    if(b == (f32)0){ throw zero_division(a, b) }
    return (f64)a / (f64)b
}
```
Note: error system may be tricky in freestanding environments (no longjmp, no debug printf).

### Async
Zero-boilerplate: `async fn void worker: i32 x { ... }`; calling it auto-initializes the runtime (no `async_init()`/`async_shutdown()`). Async functions are always void; communicate via channels (`queue<T>`/`stack<T>` from `stdlib/snq.tc`). `select { task1() => {...} task2() => {...} }` waits on multiple operations.

## Types
`i8`→`char`, `i16`→`int16_t`, `i32`→`int32_t`, `i64`→`int64_t`, `u8`→`uint8_t`, `u16`→`uint16_t`, `u32`→`uint32_t`, `u64`→`uint64_t`, `f32`→`float`, `f64`→`double`, `void`→`void`.

## Compiler usage
```bash
tigc <input.tc> [-o output.c] [-c binary] [-t] -- [clang/gcc flags]
```
- `-o file.c` — emit transpiled C (`.h` gets `#pragma once`)
- `-c binary` — transpile + compile to binary (auto-detects gcc/clang)
- `-t` — keep temporary files
- (none) — print transpiled C to stdout

## Hot reloading
Global hot reloading of functions, `strun` definitions, and enums — recompile shared libraries on-the-fly without restarting the running app. Host/DLL splitting architecture: `main` compiled into the host executable; all other functions/structs/enums compiled into a versioned shared library (`hotlib_N.dll` / `hotlib_N.so`), exported automatically. Host stubs check the current library version, reload on change, and execute via function pointers; old version files auto-cleaned. Flags: `-H <libname>` (enable hot reload), `--hot` (rebuild only the hot library), `-t/--temp`. See `dogfood/HOTSWAPPING/`.

## Project structure
```
tc-lang/
  compiler/
    include/   # headers
    src/       # compiler source (C)
  stdlib/      # standard library (.tc)
  samples/     # example programs
  docs/        # language specification
  Makefile
```

## Stdlib
Simple stdlib wrapping libc plus runtimes for stacks/queues and async functions.

Built by @alonsovm44.
