- Rust 100%
| .cargo | ||
| docs | ||
| examples | ||
| src | ||
| .gitignore | ||
| Cargo.toml | ||
| Cross.toml | ||
| pyo3-cross-config.txt | ||
| README.md | ||
| thorn-macos-aarch64 | ||
Thorn
A programming language where crossing ecosystem boundaries is a first-class operation.
Installation
Option 1: Download pre-built binary
Download the latest release for your platform from the releases page, then:
# Linux/macOS
chmod +x thorn-*
sudo mv thorn-* /usr/local/bin/thorn
# Or keep it local
mv thorn-* ~/.local/bin/thorn # Make sure ~/.local/bin is in your PATH
Option 2: Build from source
cargo install --path .
Getting Started
# Install the thorn binary
cargo install --path .
# Run a program from anywhere
thorn run examples/basics/hello.thorn
That's it. No runtime installation, no virtual environments, no package managers.
Simple Example
print("Hello, Thorn!")
let name = "World"
print("Hello,", name)
Calling Python from Thorn
import foreign_py math from "math" {
fn sqrt(x: f32) -> f32
fn pow(x: f32, y: f32) -> f32
}
match math.sqrt(16.0) {
Ok(result) => print("sqrt(16) =", result)
Err(e) => print("Error:", e)
}
let value = math.pow(2.0, 10.0)?
print("2^10 =", value)
Foreign function calls automatically return Result<T, Error> for safe boundary crossing. Use ? to propagate errors.
Calling C from Thorn
import foreign_c math from "./libmath.dylib" {
fn add(a: i32, b: i32) -> i32
}
match math.add(5, 3) {
Ok(sum) => print("5 + 3 =", sum)
Err(Error::C(c_err)) => {
print("C error in", c_err.function)
print("Library:", c_err.library)
}
}
C functions work with basic types (integers, floats, strings, pointers). Support for 0-2 arguments currently.
Standard Library
let maybe = Some(42)
match maybe {
Some(val) => print("Got:", val)
None => print("Nothing")
}
let nums = [1, 2, 3, 4, 5]
print("Length:", nums.len())
let first = nums.get(0)
let map = HashMap::new()
.insert("name", "Thorn")
.insert("version", "0.1")
.insert("status", "working")
print(map.get("name"))
Generic types: Option<T>, Result<T, E>, array methods, HashMap<K, V>.
Pattern Matching
struct Point { x: i32, y: i32 }
let point = Point { x: 0, y: 7 }
match point {
Point { x: 0, y: 0 } => print("origin")
Point { x: 0, y } => print("on y-axis at", y)
Point { x, y: 0 } => print("on x-axis at", x)
Point { x, y } => print("at", x, y)
}
enum Shape {
Circle(f32),
Rectangle { width: f32, height: f32 }
}
let shape = Shape::Circle(5.0)
match shape {
Shape::Circle(r) => print("circle with radius", r)
Shape::Rectangle { width, height } => print("rectangle", width, "x", height)
}
What Works
- Variables and functions
- Structs and enums with full pattern matching
- Arrays with indexing and iteration
- Generic types:
Option<T>,Result<T, E>,HashMap<K, V> - Control flow:
if,while,for,match - Python FFI with automatic
Resultwrapping - C FFI with automatic
Resultwrapping - Error propagation with
?operator - String interpolation
- Method chaining
- Interactive REPL with line editing and history
Test coverage: 91 tests passing
What Doesn't Work Yet
- C FFI limited to 0-2 arguments and basic types
- Python FFI doesn't support objects or methods
- No WASM FFI
- Type checker exists but boundary types not enforced
- No compiler error improvements yet
- No borrowing/ownership system
- No generics beyond built-in types
Thorn is honest about its limitations. These are real constraints, not "coming soon."
Building from Source
# Install globally (recommended)
cargo install --path .
# Or build for development
cargo build
# Run tests
cargo test
# Development: run without installing
cargo run -- run examples/stdlib/option_basic.thorn
Examples
The examples/ directory contains working programs:
Basics:
hello.thorn- Hello worldcalculator.thorn- Functions and arithmeticdemo.thorn- Comprehensive features
Standard Library:
stdlib/option_basic.thorn- Option usagestdlib/vec_basic.thorn- Array methodsstdlib/hashmap_basic.thorn- HashMap operations
FFI:
ffi/c_ffi.thorn- Calling C functionsffi/c_strings.thorn- String handling with Cffi/python/python_basic.thorn- Python interop
Language Features:
match.thorn- Pattern matchingstructs.thorn- Struct definitionsenums.thorn- Sum typesarrays.thorn- Collections
CLI Usage
# Run a program
thorn run <file.thorn>
# Check syntax and show AST
thorn check <file.thorn>
# Interactive REPL
thorn repl
Why Thorn Exists
Most languages pretend foreign code doesn't exist. When you need to call Python from Rust, or C from Go, you write FFI bindings in a separate layer with different error handling, different types, and different conventions.
Thorn makes boundaries visible and safe by default. Every foreign function returns Result<T, Error>. The error tracks origin (::c, ::python, ::wasm). Pattern matching lets you handle errors by source:
match call_foreign_function() {
Ok(value) => use_value(value)
Err(Error::Python(py_err)) => handle_python_error(py_err)
Err(Error::C(c_err)) => handle_c_error(c_err)
}
This isn't a research language. It's for systems-aware builders working at ecosystem boundaries: game developers calling ML libraries, systems programmers using C APIs, engineers building polyglot systems.
Project Structure
ThornC/
├── src/
│ ├── lexer/ Tokenization
│ ├── parser/ AST generation
│ ├── ast/ AST definitions
│ ├── runtime/ Tree-walking interpreter
│ ├── typecheck/ Type checking (basic)
│ ├── interop/ FFI implementation (C, Python)
│ └── error/ Error types and handling
├── examples/ Working Thorn programs
└── docs/ Design documentation
Documentation
- Design Choices - Philosophy and goals
- Type System - Boundary types
- Memory Model - Ownership semantics
- Syntax Design - Language syntax
Contributing
Thorn is in active development. We welcome:
- Bug reports and feature requests
- Example programs showing real use cases
- Design feedback on FFI ergonomics
- Documentation improvements
Open an issue or submit a pull request.
Development Status
Current phase: Working prototype with FFI foundation
The core language works. Python and C FFI work for basic cases. The standard library has essential types. Pattern matching is complete. Tests pass.
What's next: expanding FFI capabilities, improving type checking at boundaries, better error messages.
License
MIT