1 unstable release

Uses new Rust 2024

new 0.1.0 May 13, 2026

#378 in Programming languages


Used in 4 crates

MIT license

215KB
5.5K SLoC

A three-layer programming language ecosystem — designed for both humans and AI agents. Named after types, its core concept.

Strict compiler rules and enforced conventions make it hard to write bad code — for anyone. Lints are errors, not warnings.

T is fully implemented — a C-level language with two syntaxes (SLN and C-style), compiling to C. Ty is functional — adds generics, const execution, callable tuples, operator overloading, and UFCS on top of T. Tyr compiles end-to-end — natural-language syntax with phonotactic auto-bracketing, compiling through Ty to C.

T: Tutorial | Reference | C Interop Ty: Tutorial | Reference | T Interop Tyr: Tutorial


C, but consistent

T is explicit and low-level: no generics, no closures, no garbage collection. Everything you need from C, nothing you don't. Newtypes replace structs, aliases, and constructors.

SLN Syntax (.sln.t)

fn fibonacci (n) (i32) i64
    label loop (i a b) (i32 i64 i64) (0 0 1)
    if (>= i n)
        return a
    jump loop (+ i 1) b (+ a b)

print "fib(20) =" (fibonacci 20)

C Syntax (.c.t)

fn fibonacci(n: i32) -> i64 {
    label loop(i: i32 = 0, a: i64 = 0, b: i64 = 1);
    if i >= n { return a; }
    jump loop(i + 1, b, a + b);
}

print("fib(20) =", fibonacci(20));

Both syntaxes parse to the same AST. No fn main needed — top-level statements are auto-wrapped.

Features

  • Newtypes: type Meters = f64 creates a distinct type (not an alias). Implicit downcast, explicit upcast via Meters: 42.0 / (Meters 42.0). Tuple newtypes (type Point = x & y) replace structs, with fields resolved by type. Enum newtypes (type Result = ok | err) are sum types.
  • Types: bool, i8i128, u8u128, isize/usize, f32, f64, pointers (&T/|T), arrays ([T]N), vectors ({T}N), slices ([T]), tuples, enums, named types, functions
  • Control flow: if/else, match, label/jump (loops via goto with parameters), defer
  • Bindings (type annotations optional, types are inferred):
    • let x 42 — value, not addressable
    • ref x 42 — immutable reference (&T), auto-deref in value contexts
    • var x 42 — mutable reference (|T), auto-deref in value contexts, assignable
  • Auto-deref: var and ref are automatically dereferenced for operators, conditions, print, return, etc. — and automatically passed by reference to pointer parameters.
  • Pointers: &T shared, |T mutable. Field access (.) preserves the reference state.
  • Slices: arr[] creates a slice from an array, arr[start, end] creates a sub-slice
  • Repeat literals: [0]5 expands to [0, 0, 0, 0, 0], {0.0}3 for vectors
  • Assignment returns old value (set / :=): x, y := y, x is swap. let old = current := new_value captures the replaced value.
  • Multi-let: let x, y = 1, 2; / (let x 1 y 2) — multiple bindings in one statement
  • Compound assignment: +=, -=, *=, /= / (set+ x 1), (set- x 1)
  • Defer: defer statement executes before every return and at function end (LIFO order)
  • Lints (always errors, not warnings): unused bindings, self-assignment, chained swap, compound assignment, unreachable code, division by zero, dead labels, recursion, nesting depth (max 4), unnecessary return, unnecessary intermediate variable, duplicate type definitions, identity casts
  • Visibility: pub for external linkage (default is internal/static). import/extern for C interop.
  • Import: import "file.c.t" (source expansion), import "lib.th" (header format), import "stdio.h" (C header)
  • Stdlib: import "math.th", "memory.th", "string.th", "file.th", "process.th", "convert.th"
  • Number literals: decimal, hex (0xFF, 0x14.8), octal (0o77), binary (0b1010), with underscore separators (1_000)
  • Three-way cast system: Type: value for newtype construction, .Type for newtype downcast, as for unsafe pointer casts only (pointer↔integer, pointer↔pointer). Numeric conversions use constructor: u32: x. No implicit conversions.
  • Type-based arguments: function arguments matched by type, not position. Same-type and subtype parameters rejected — use newtypes. Shorthand: fn test(x, y) = fn test(x: x, y: y). Pointer shorthand: fn f(|Node).
  • Null pointers: null keyword, compatible with any pointer type. pointer == null / pointer != null for checks. pointer == 0 rejected.
  • Function pointers: call(f, x) / (call f x) for indirect calls
  • Print: print outputs arguments separated by spaces with newline — print x "hello" 3.14
  • WGSL backend: t wgsl file.c.t generates WebGPU shading language (shader compilation)
  • Constants: const MAX u32 1024

Build & Run

t build file.c.t       # compile to binary
t run file.c.t         # compile and run
t c file.c.t           # output generated C
t wgsl file.c.t        # output generated WGSL
t check file.c.t       # parse + resolve (no compile)
t header lib.c.t       # generate .th header
t repl                 # interactive REPL (--sln for SLN)
t --version            # show version

Works with both .sln.t (SLN) and .c.t (C-syntax) files.


All the features you need. None that you don't.

The name says it: types matter. In Ty, every function is a type plus an implementation. Every operation has a name. The type system is the language. Compiles down to T.

Core Idea: fn = type + impl

type n = i32;
fn twice n -> i32 { n.i32 * 2 }

is sugar for:

type n = i32;
type twice = n;
impl twice -> i32 { n.i32 * 2 }

Constructing a tuple with an impl -> ReturnType auto-evaluates it. Without impl, construction produces data.

Generics

fn identity[T] T -> T { it }

print(identity(42), identity(true));

Generic parameter it is a placeholder for the concrete type. Each instantiation is monomorphized into a concrete function.

Features

  • Callable tuples: fn is sugar for type + impl — evaluation as construction
  • Generics: type and const parameters in [T] / []N syntax, monomorphized at compile time
  • Const execution: const fn evaluated at compile time — enables compile-time type construction
  • Operator overloading: import "operators.c.ty"; impl add[Vec2] & Vec2 -> Vec2 { ... }
  • UFCS: x.f(y) = f(x, y) — any argument can be the receiver
  • Implicit fields: impl point -> f64 { sqrt(x * x + y * y) } — tuple fields available directly
  • Impl blocks: make types callable with impl Type -> ReturnType { body }
  • No traits: polymorphism through type-based dispatch on tuples
  • Imports: Ty-to-Ty and Ty-to-T imports, stdlib access
  • REPL: ty repl — interactive, compiles through full Ty → T → C pipeline
  • Everything from T: newtypes, if/else, print, top-level statements

Build & Run

ty build file.c.ty     # compile to binary
ty run file.c.ty       # compile and run
ty c file.c.ty         # output generated C (via T)
ty check file.c.ty     # parse + resolve (no compile)
ty repl                # interactive REPL
ty --version           # show version

Think, then compute

Tyr is natural language-inspired. No parentheses, no braces — nesting is determined by each word's consonant structure. Compiles to Ty.

Core Idea: Words Are Syntax

Every word belongs to one of four types, recognizable from its consonants:

Word Type Structure Effect
Object Consonants before + after vowel Closes a level
Specifier Consonants only before vowel Qualifies next Object
Relation Consonants only after vowel Opens a level
Modifier Starts with stop (b/c/d) Transforms previous word
an van van          → add(1, 1) = 2
ul an van van zan   → mul(add(1, 1), 6) = 12
da an van van       → sub(1, 1) = 0     (da = opposite)
in an van van sum   → let sum = add(1, 1)

No definitions — types and operations are words in the vocabulary. Programs compose existing words.


Crate Structure

Crate Description
t-ree T AST definitions
t-parser_sln SLN source → T AST
t-parser_c C-syntax source → T AST
t-backend_c T AST → C code
t-backend_wgsl T AST → WGSL shader code
t-repl Shared REPL implementation
t T CLI
ty-ree Ty AST definitions (extends T with generics, lifetimes, impl)
ty-parser Ty C-syntax source → Ty AST
ty-parser_sln Ty SLN source → Ty AST
ty-backend_t Ty AST → T AST (monomorphization + lowering)
ty Ty CLI
tyr-core Abstract Tyr type-system traits (Evaluable, Specifier, Relation, Modifier)
tyr-syntax Tyr source → parsed sentences (phonotactics + auto-bracketing)
tyr-grammar Mathematical grammar (rational numbers, sets)
tyr-backend_ty Tyr sentences → Ty AST
tyr Tyr CLI + REPL

Dependencies

Error Reporting

All errors include line:column locations, corrected for import expansion. The resolver reports all errors at once instead of stopping at the first. Error messages suggest fixes:

Resolution error: 5:1: in 'sort': parameters 'index' (index) and 'ids' (|u64) have conflicting types — use distinct newtypes
Resolution error: 12:14: type u64 has no field 'u32'use 'u32: value' for numeric conversions
Parse error: 3:12: redundant parameter name 'n: meters'use 'meters' shorthand instead
Lint error: 8:5: use 'pos += <value>' instead of 'pos := pos + <value>'

Designed with AI in Mind

Strict rules, no ambiguity, and enforced conventions mean that AI-generated code is clean and correct by construction. The same properties make it pleasant for humans: less to remember, fewer surprises, one way to do things.

Dependencies