TinyLang

A complete programming language interpreter built from scratch in Python โ€” lexer, parser, AST, closures, first-class functions, and more.

248 Tests Passing 60+ Builtins Pure Python Zero Dependencies
tinylang
// Counter using closures
fn make_counter(start) {
    let count = start
    fn increment() {
        count = count + 1
        return count
    }
    return increment
}

let counter = make_counter(0)
print(counter())  // 1
print(counter())  // 2
print(counter())  // 3

// Arrow functions + higher-order
let double = (x) => x * 2
let triple = (x) => x * 3

print(double(5))   // 10
print(triple(5))   // 15
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

// Map, filter, reduce
let evens = filter((n) => n % 2 == 0, numbers)
let doubled = map((n) => n * 2, evens)
let total = reduce((a, b) => a + b, doubled, 0)

print(total)  // 60

// Pipeline operator
let result = [1, 2, 3, 4, 5] |> sum |> str
print(result)  // "15"

// Memoization
fn memoize(func) {
    let cache = {}
    return fn(n) {
        let key = str(n)
        if has(cache, key) { return cache[key] }
        let result = func(n)
        cache[key] = result
        return result
    }
}
// Structured error handling
fn validate_age(age) {
    if type(age) != "int" {
        throw {
            "type": "TypeError",
            "message": "Age must be an integer"
        }
    }
    if age < 0 or age > 150 {
        throw {
            "type": "ValueError",
            "message": format("Invalid age: {}", age)
        }
    }
    return true
}

try {
    validate_age(200)
} catch err {
    print(err["type"])    // ValueError
    print(err["message"]) // Invalid age: 200
}
// Binary search
fn binary_search(arr, target) {
    let low = 0
    let high = len(arr) - 1

    while low <= high {
        let mid = floor((low + high) / 2)
        if arr[mid] == target { return mid }
        else if arr[mid] < target { low = mid + 1 }
        else { high = mid - 1 }
    }
    return -1
}

let arr = [2, 5, 8, 12, 16, 23, 38, 56]
print(binary_search(arr, 23))  // 5

// Caesar cipher
fn caesar(text, shift) {
    let result = []
    for ch in split(text, "") {
        let code = ord(ch)
        if code >= 97 and code <= 122 {
            push(result, char(((code - 97 + shift) % 26) + 97))
        } else { push(result, ch) }
    }
    return join(result, "")
}
print(caesar("hello", 13))  // uryyb
5,300+
Lines of Code
248
Tests Passing
60+
Built-in Functions
0
Dependencies

Compiler Pipeline

๐Ÿ“
Source
TinyLang code
โ†’
๐Ÿ”ค
Lexer
Tokenizer
โ†’
๐ŸŒณ
Parser
Recursive-descent
โ†’
๐Ÿ—‚๏ธ
AST
30+ node types
โ†’
โšก
Interpreter
Tree-walking

Language Features

๐Ÿงฌ

First-Class Functions

Functions are values โ€” pass them around, return from other functions, store in arrays and dictionaries.

๐Ÿ”’

Closures

Lexical scoping with closure capture. Functions remember their defining environment.

โšก

Arrow Functions

Concise lambda syntax: (x) => x * 2. Perfect for map, filter, reduce.

๐Ÿ”—

Pipeline Operator

Chain transformations cleanly: data |> process |> format.

๐Ÿ›ก๏ธ

Error Handling

Try/catch/throw with structured errors. Throw any value โ€” strings, dicts, arrays.

๐Ÿ“ฆ

Module System

Import and organize code with import "module" as m.

๐ŸŽจ

Rich Types

Integers, floats, strings, booleans, null, arrays, dictionaries with dot-access methods.

๐Ÿงช

Comprehensive Builtins

60+ built-in functions for I/O, math, strings, collections, and functional programming.

๐Ÿ’ป

Interactive REPL

Multi-line input detection, colored output, and built-in commands for exploration.

Get Started

$ pip install git+https://github.com/hajirufai/tinylang.git

$ tinylang