A minimal, LLM-friendly programming language with mandatory testing and unambiguous syntax.
NanoLang transpiles to C for native performance while providing a clean, modern syntax optimized for both human readability and AI code generation.
Self-hosting: NanoLang supports true self-hosting via a Stage 0 → Stage 1 → Stage 2 bootstrap (
make bootstrap); see planning/SELF_HOSTING.md.
git clone https://github.com/jordanhubbard/nanolang.git
cd nanolang
make buildThis builds the compiler:
bin/nanoc- NanoLang compiler (transpiles to C)
Create hello.nano:
fn greet(name: string) -> string {
return (+ "Hello, " name)
}
shadow greet {
assert (str_equals (greet "World") "Hello, World")
}
fn main() -> int {
(println (greet "World"))
return 0
}
shadow main {
assert true
}
Run it:
# Compile to native binary
./bin/nanoc hello.nano -o hello
./helloNanoLang is actively tested and supported on:
- Ubuntu 22.04+ (x86_64)
- Ubuntu 24.04 (ARM64) - Raspberry Pi, AWS Graviton, etc.
- macOS 14+ (ARM64/Apple Silicon)
- FreeBSD
Windows 10/11 users: NanoLang runs perfectly on Windows via WSL2 (Windows Subsystem for Linux).
# In PowerShell (as Administrator)
wsl --install -d UbuntuAfter installation, restart your computer, then:
# Inside WSL Ubuntu terminal
git clone https://github.com/jordanhubbard/nanolang.git
cd nanolang
make
./bin/nanoc examples/language/nl_hello.nano -o hello
./helloWhy WSL? NanoLang's dependencies (SDL2, ncurses, pkg-config) are Unix/POSIX libraries. WSL2 provides a full Linux environment with near-native performance on Windows.
Note: Native Windows binaries (.exe) are not currently supported, but may be added in a future release via cross-compilation.
These platforms should work but are not actively tested in CI:
- macOS Intel (via Rosetta 2 on Apple Silicon, or native on older Macs)
- Other Linux distributions (Arch, Fedora, Debian, etc.)
- OpenBSD (requires manual dependency installation)
- Prefix Notation - No operator precedence:
(+ a (* b c))is always clear - Mandatory Testing - Every function requires a
shadowtest block - Static Typing - Catch errors at compile time
- Generic Types - Generic unions like
Result<T, E>for error handling - Compiled Language - Transpiles to C for native performance
- Immutable by Default - Use
let mutfor mutability - C Interop - Easy FFI via modules with automatic package management
- Module System - Automatic dependency installation via
module.json - Standard Library - Growing stdlib with
Result<T,E>, string ops, math, and more
- User Guide (HTML) - Progressive tutorial + executable snippets
- Getting Started - 15-minute tutorial
- Quick Reference - Syntax cheat sheet
- Language Specification - Complete reference
- Examples - Working examples (all runnable)
# Variables (immutable by default)
let x: int = 42
let mut counter: int = 0
# Functions with mandatory tests
fn add(a: int, b: int) -> int {
return (+ a b)
}
shadow add {
assert (== (add 2 3) 5)
assert (== (add -1 1) 0)
}
# Control flow
if (> x 0) {
(println "positive")
} else {
(println "negative or zero")
}
# Loops
let mut i: int = 0
while (< i 10) {
print i
set i (+ i 1)
}
No operator precedence to remember:
# Crystal clear - no ambiguity
(+ a (* b c)) # a + (b * c)
(and (> x 0) (< x 10)) # x > 0 && x < 10
(/ (+ a b) (- c d)) # (a + b) / (c - d)
# Primitives
int, float, bool, string, void
# Composite types
struct Point { x: int, y: int }
enum Status { Pending = 0, Active = 1, Complete = 2 }
# Generic lists
let numbers: List<int> = (List_int_new)
(List_int_push numbers 42)
# First-class functions
fn double(x: int) -> int { return (* x 2) }
let f: fn(int) -> int = double
# Generic unions (NEW!)
union Result<T, E> {
Ok { value: T },
Err { error: E }
}
let success: Result<int, string> = Result.Ok { value: 42 }
let failure: Result<int, string> = Result.Err { error: "oops" }
NanoLang includes a growing standard library:
union Result<T, E> {
Ok { value: T },
Err { error: E }
}
fn divide(a: int, b: int) -> Result<int, string> {
if (== b 0) {
return Result.Err { error: "Division by zero" }
}
return Result.Ok { value: (/ a b) }
}
fn main() -> int {
let result: Result<int, string> = (divide 10 2)
/* Note: Result helper functions (is_ok/unwrap/etc) are planned once
* generic functions are supported. For now, use match.
*/
match result {
Ok(v) => (println v.value),
Err(e) => (println e.error)
}
return 0
}
See examples/README.md for the complete list.
NanoLang includes several modules with automatic dependency management:
- ncurses - Terminal UI (interactive games, text interfaces)
- sdl - 2D graphics, windows, input (
brew install sdl2) - sdl_mixer - Audio playback (
brew install sdl2_mixer) - sdl_ttf - Font rendering (
brew install sdl2_ttf) - glfw - OpenGL window management (
brew install glfw)
Modules automatically install dependencies via package managers (Homebrew, apt, etc.) when first used. See docs/MODULE_SYSTEM.md for details.
# Build (3-stage component bootstrap)
make build
# Run full test suite
make test
# Quick test (language tests only)
make test-quick
# Build all examples
make examples
# Launch the examples browser
make examples-launcher
# Validate user guide snippets (extract → compile → run)
make userguide-check
# Build static HTML for the user guide
make userguide-html
# Options:
# CMD_TIMEOUT=600 # per-command timeout (seconds)
# USERGUIDE_TIMEOUT=600 # build timeout (seconds)
# USERGUIDE_BUILD_API_DOCS=1 # regenerate API reference
# NANO_USERGUIDE_HIGHLIGHT=0 # disable highlighting (CI default)
# Serve the user guide locally (dev)
make -C userguide serve
# Clean build
make clean
# Install to /usr/local/bin (override with PREFIX=...)
sudo make installOn BSD systems (FreeBSD/OpenBSD/NetBSD), use GNU make: gmake build, gmake test, etc.
NanoLang is designed to be LLM-friendly with unambiguous syntax and mandatory testing. To teach an AI system to code in NanoLang:
- MEMORY.md - Complete LLM training reference with patterns, idioms, debugging workflows, and common errors
- spec.json - Formal language specification (types, stdlib, syntax, operations)
- Examples - Runnable examples demonstrating all features
- Read
MEMORY.mdfirst - covers syntax, patterns, testing, debugging - Reference
spec.jsonfor stdlib functions and type details - Study examples for idiomatic usage patterns
The combination of MEMORY.md (practical guidance) + spec.json (formal reference) provides complete coverage for code generation and understanding.
We welcome contributions! Areas where you can help:
- Add examples and tutorials
- Improve documentation
- Report bugs or suggest features
- Create new modules
- Implement standard library functions
See CONTRIBUTING.md for guidelines.
Current: Production-ready compiler with full self-hosting support.
- ✅ Complete language implementation (lexer, parser, typechecker, transpiler)
- ✅ Compiled language (transpiles to C for native performance)
- ✅ Static typing with inference
- ✅ Structs, enums, unions, generics
- ✅ Module system with auto-dependency management
- ✅ 49+ standard library functions
- ✅ 90+ working examples
- ✅ Shadow-test framework
- ✅ FFI support for C libraries
- ✅ Memory safety features
See docs/ROADMAP.md for future plans.
NanoLang solves three problems:
- LLM Code Generation - Unambiguous syntax reduces AI errors
- Testing Discipline - Mandatory tests improve code quality
- Simple & Fast - Minimal syntax, native performance
Design Philosophy:
- Minimal syntax (18 keywords vs 32 in C)
- One obvious way to do things
- Tests are part of the language, not an afterthought
- Transpile to C for maximum compatibility
Apache License 2.0 - See LICENSE file for details.