Skip to content

cowboycodr/tscc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

tscc

A compiler that takes TypeScript syntax and compiles it to native machine code via LLVM.

Not a transpiler. Not a runtime. tscc produces standalone native binaries from .ts files.

tscc run examples/hello.ts

Performance

All benchmarks on Apple Silicon M3. Best of 3 runs.

Recursive Fibonacci — fib(40)

Runtime Time Relative Memory
tscc 0.28s 1.0x 1.2 MB
C (cc -O3) 0.28s 1.0x 1.2 MB
Rust (rustc -O, i64) 0.28s 1.0x 1.4 MB
Rust (rustc -O, f64) 0.41s 1.5x slower 1.4 MB
Bun 1.3 0.48s 1.7x slower 27 MB
Node 25 0.79s 2.8x slower 49 MB

Loop Sum — sum(0..1_000_000_000)

Runtime Time Relative
tscc < 0.01s --
Rust (rustc -O) < 0.01s --
Bun 1.3 0.88s --
Node 25 1.47s --

Both tscc and Rust produce effectively instant results — LLVM optimizes the entire loop into a closed-form computation at compile time.

Why is tscc fast?

  • LLVM O3 — Full optimization pipeline (loop vectorization, SLP vectorization, function inlining, dead code elimination)
  • Native CPU targeting — Generates code tuned for the exact CPU (-mcpu=native)
  • Integer narrowing — Analysis pass detects when number values can compile as i64 instead of f64, enabling LLVM's integer-specific optimizations (accumulator transformation, strength reduction)
  • No runtime overhead — No JIT warmup, no garbage collector, no event loop. Just a native binary
  • Tiny binariesfib(40) compiles to a 37 KB binary (vs 441 KB for Rust)

Compilation Speed

Mode Time
Optimized (O3) ~90ms
Debug (no optimization) ~80ms

Install

Requires LLVM 18 and Rust.

# Install LLVM 18
brew install llvm@18

# Set environment variables (add to your shell profile)
export LLVM_SYS_180_PREFIX=/opt/homebrew/opt/llvm@18
export LIBRARY_PATH="/opt/homebrew/lib:$LIBRARY_PATH"

# Build tscc
cargo install --path .

Usage

# Compile and run
tscc run file.ts

# Compile to binary
tscc build file.ts            # outputs ./file
tscc build file.ts -o output  # custom output path

# Flags
tscc run file.ts --benchmark  # time execution
tscc build file.ts --debug    # skip optimization (faster compile)
tscc build file.ts --emit-ir  # print LLVM IR

Examples

// hello.ts
function greet(name: string): string {
    return `Hello, ${name}!`
}

console.log(greet("World"))

let numbers = [10, 20, 30]
console.log("Second:", numbers[1])

let double = (x: number): number => x * 2
console.log(double(21))  // 42
$ tscc run examples/hello.ts
Hello, World!
Second: 20
42

Objects and classes compile to zero-overhead LLVM structs:

class Point {
    x: number
    y: number
    constructor(x: number, y: number) {
        this.x = x
        this.y = y
    }
    toString(): string {
        return this.x + "," + this.y
    }
}

let p = new Point(3, 4)
console.log(p)            // { x: 3, y: 4, toString: [complex] }
console.log(p.toString()) // 3,4

See examples/ for more.

Architecture

TypeScript source
    |
    +- Lexer -------- Hand-written scanner
    +- Parser ------- Recursive descent + Pratt precedence
    +- Type Checker -- Structural typing, inference
    +- Codegen ------ LLVM IR via inkwell
    +- Optimizer ---- LLVM O3 + native CPU targeting
    +- Linker ------- Links with pre-compiled runtime
    |
    Native binary

Written in Rust. Single crate. ~9,000 lines of Rust + ~285 lines of C runtime.

The runtime (runtime/runtime.c) provides print functions, string operations, math functions, and array support. It is compiled once at cargo build time and embedded directly into the tscc binary — no C toolchain is required on the user's machine to compile TypeScript files.

Status

Early stage. 195 tests passing, 44 pending. The goal is drop-in compatibility with existing TypeScript projects. Currently covers the core language features needed for compute-heavy programs.

TypeScript Feature Coverage

195 passing / 44 not yet implemented — 82% of test suite

Literals & Primitives

Feature Status Test
Integer literals console.log(42)
Float literals console.log(3.14)
Negative numbers console.log(-7)
Zero console.log(0)
Large integers console.log(1000000)
String (double quotes) console.log("hello")
String (single quotes) console.log('world')
Empty string console.log("")
Boolean true console.log(true)
Boolean false console.log(false)
null console.log(null)
undefined console.log(undefined)
BigInt literals 9007199254740993n

Variables

Feature Status Test
let with number let x = 10
let with string let s = "hi"
let with boolean let b = true
const const x = 99
Type annotations let x: number = 5
String type annotation let s: string = "typed"
Boolean type annotation let b: boolean = false
Reassignment x = 2
Multiple variables let a = 1; let b = 2
Uninitialized let let x: number (defaults to 0)
Optional semicolons let x = 42
var declarations var x = 42

Arithmetic Operators

Feature Status Test
Addition + 2 + 3
Subtraction - 10 - 4
Multiplication * 3 * 7
Division / 10 / 4
Modulo % 10 % 3
Exponentiation ** 2 ** 10
Operator precedence 2 + 3 * 4 = 14
Parenthesized expressions (2 + 3) * 4 = 20
Postfix ++ / -- x++, x--
Prefix ++ / -- ++x, --x
Unary negate -x
+= -= *= /= x += 3

Comparison Operators

Feature Status Test
< > <= >= 1 < 2, 5 > 3
== != 5 == 5, 5 != 6
=== !== 5 === 5, 5 !== 5
Boolean equality true == true

Logical Operators

Feature Status Test
&& true && true
|| false || true
! !true
Complex logical true && !false || false
Numeric && / || 1 && 1, 0 || 1
Nullish coalescing ?? null ?? 42
Optional chaining ?. obj?.a

Strings

Feature Status Test
Concatenation + "hello" + " world"
String + number "value: " + 42
String + boolean "it is " + true
.length "hello".length
.toUpperCase() "hello".toUpperCase()
.toLowerCase() "HELLO".toLowerCase()
.charAt() "hello".charAt(1)
.indexOf() "hello world".indexOf("world")
.includes() "hello world".includes("world")
.substring() "hello world".substring(0, 5)
.slice() "hello world".slice(-5)
.trim() " hello ".trim()
Template literals `value is ${x}`
Chained methods " Hello ".trim().toUpperCase()
.startsWith() "hello".startsWith("he")
.endsWith() "hello".endsWith("lo")
.repeat() "ab".repeat(3)
.split() "a,b,c".split(",")
.replace() "hello".replace("l", "r")
.padStart() "5".padStart(3, "0")

Control Flow

Feature Status Test
if if (true) { ... }
if/else if (x) { ... } else { ... }
if/else if/else chained conditions
while while (i < 5) { ... }
for for (let i = 0; i < n; i++)
Nested loops for { for { ... } }
Block scoping { let y = 2 }
break if (i == 5) break
continue if (i == 2) continue
Ternary ? : true ? 1 : 2
do...while do { i++ } while (i < 5)
switch/case switch (x) { case 1: ... }
for...of for (let x of arr)
for...in for (let key in obj)
Labeled statements outer: for (...)

Functions

Feature Status Test
Declarations function add(a, b) { return a + b }
Return values return a + b
Multiple params function f(a, b, c)
String params/returns function hello(name: string): string
Boolean returns function isPositive(n): boolean
Recursion function fib(n) { ... fib(n-1) }
Mutual calls double(double(x))
Local variables let result = x * 2
Void functions function sayHi(): void
Arrow (expression) let add = (a, b) => a + b
Arrow (block body) let f = (x) => { return x }
Function hoisting calling before declaration
Closures capturing outer variables
Default parameters function f(x = 10)
Rest parameters function f(...args: number[])
Spread syntax [...arr, 4, 5]
Function expressions let f = function() {}

Arrays

Feature Status Test
Literals [1, 2, 3]
Index access arr[1]
.length arr.length
.push() arr.push(4)
.pop() arr.pop()
.map() arr.map(x => x * 2)
.filter() arr.filter(x => x > 2)
.reduce() arr.reduce((a, b) => a + b, 0)
.forEach() arr.forEach(x => console.log(x))

Math Standard Library

Feature Status Test
Math.floor() Math.floor(3.7)
Math.ceil() Math.ceil(3.2)
Math.round() Math.round(3.5)
Math.abs() Math.abs(-5)
Math.sqrt() Math.sqrt(9)
Math.pow() Math.pow(2, 10)
Math.min() / Math.max() Math.min(3, 7)
Math.sin() / Math.cos() / Math.tan() trig functions
Math.log() / Math.exp() Math.log(Math.E)
Math.random() returns [0, 1)
Math.PI / Math.E constants

Console & Globals

Feature Status Test
console.log() single and multiple args
console.error() writes to stderr
console.warn() writes to stderr
typeof typeof 42 = "number"
parseInt() parseInt("42")
parseFloat() parseFloat("3.14")

Modules

Feature Status Test
export function export function square(x) {}
import { name } import { square } from "./math"
Multiple imports import { a, b } from "./utils"
Import aliasing as import { add as sum }
Default export export default 42
import * as import * as math from "./math"
Re-exports export { foo } from "./bar"

Objects & Classes

Feature Status Test
Object literals { x: 1, y: 2 }
Property access obj.x
Bracket access obj["x"]
Object methods obj.getX()
console.log(obj) { name: 'Kian', age: 19 }
Class declarations class Point { ... }
new + constructor new Point(3, 4)
Class methods p.toString()
Class inheritance class Dog extends Animal
Interfaces interface Point { x: number }
Array destructuring let [a, b] = [1, 2]
Object destructuring let { x, y } = { x: 1, y: 2 }

Type System

Feature Status Test
Type annotations let x: number, function f(): string
Type inference let x = 42 (inferred as number)
Union types string | number
Type aliases type ID = string | number
Enums (numeric) enum Color { Red, Green }
Enums (string) enum Direction { Up = "UP" }
Generics function identity<T>(x: T): T
Generic constraints <T extends { length: number }>
Tuple types [number, string]
Type assertions x as string
Type narrowing if (typeof val === "string")
String literal types type Dir = "up" | "down"
Intersection types Named & Aged
readonly readonly host: string
keyof keyof Point
Conditional types T extends number ? "yes" : "no"
Mapped types { [P in keyof T]: T[P] }
typeof in type position let y: typeof x
satisfies "red" satisfies Colors
as const [1, 2, 3] as const

Error Handling & Async

Feature Status Test
try/catch try { throw new Error() } catch (e) {}
try/finally try { ... } finally { ... }
async/await async function f() { await ... }
Promises Promise.resolve(42)

Built-in Objects

Feature Status Test
JSON.stringify() JSON.stringify({ a: 1 })
Map new Map()
Set new Set([1, 2, 3])
RegExp /hello/.test("hello world")
Number.isInteger() Number.isInteger(42)
Number.isFinite() Number.isFinite(42)
Number.isNaN() Number.isNaN(NaN)
.toFixed() (3.14).toFixed(2)

Advanced Features

Feature Status Test
Namespaces namespace Util { ... }
Decorators @log
Symbols Symbol("foo")
Generators function* range()

License

MIT

About

A compiler that compiles TypeScript to native machine code via LLVM

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages