A compiled programming language with a Lark parser frontend and LLVM backend that produces native binaries.
PARENTAL ADVISORY
This project is a result of a thought process when I asked myself "how hard is it to create a programming language?" Then I went and wrote:
fn main():
return(0)
I spent a couple of hours reading about grammar parsers, AST, LLVM, and similar stuff, and then after some time I had a compiled executable file that did nothing.
Then I started working on print() and then on variables, soon
after this I realized that this is going way too slow and I will
need to ask peoplerobots to help me. Then things really took
off.
Long story short, now I am vibe coding a programming language, losing my mind trying to convince LLMs to output the code that I want, and I generally know much more about compilers that I used to know. It's been fun.
If you are triggered by mediocre and badly written code, you might want to stay away. Or you might find this funny.
Apart from this section, most of the things in the documentation were just briefly checked for sanity, and revised by a human. Same goes for code. A rough estimate is that 80% of the code was iteratively generated by LLMs. Then LLMs were used to refactor this code. Obvious mistakes spotted by a human were then corrected mostly by LLMs. This code base is in some parts quite ridiculous and can bring even seasoned developers and code reviewers to tears. You have been warned.
Sushi is actively tested on macOS (Apple Silicon) and Linux (via CI). No testing has been done on Windows yet, so the current status is unknown.
What is the goal with Sushi? Mostly me teaching myself about compilers and related subjects, and playing around with LLMs. At one point I will decide that I added enough features, then I will try and turn it into a self-hosted compiler.
Sushi Lang is a statically-typed compiled language designed with safety, simplicity, and performance in mind. The compiler follows a clean multi-pass architecture with comprehensive semantic analysis and LLVM-powered code generation.
Key Features:
- Static type system with explicit casting
- Generic types with compile-time monomorphization (
Result@(T, E),Maybe@(T),List@(T),HashMap@(K, V), user-defined structs, enums, and functions) - Generic functions with automatic type inference and perk constraints
- Perks (traits/interfaces) for polymorphic behavior with static dispatch
- Error propagation operator (
??) for ergonomic error handling - Parameter modes: a parameter borrows by default,
nomhands the value over, andpeek/pokeborrow by pointer, all with compile-time borrow checking Own@(T)heap allocation for recursive types (linked lists, trees)- Extension methods for zero-cost method chaining
- Closures / lambdas (
|x| expr) with RAII-managed, move-semantics captures - First-class functions (
fn(i32) -> i32values, passable and callable) - Foreign Function Interface (
unsafe external "C") for calling C libraries - Variadic functions (memory-safe native
...Tarray sugar; C...for FFI bindings) - Variadic generics / parameter packs (
...Ts: Perk+expand(x in args), compile-time unrolled) - Rust-style enums with exhaustive pattern matching
- Automatic memory management (RAII) for structs, arrays, and collections
- Full UTF-8 Unicode support
- Native code generation via LLVM
- Incremental compilation with per-unit object file caching
# Compile a program
./sushic hello.sushi
# Run the compiled binary
./hello
# Optimization levels
./sushic --opt O2 program.sushi # Recommended: balanced performance
./sushic --opt O3 program.sushi # Maximum performance
# Create and use libraries
./sushic --lib --lib-version 1.0.0 mylib.sushi -o mylib.slib # Compile to library
export SUSHI_LIB_PATH=. # Set library path
./sushic main.sushi # use <lib/mylib> in sourcefn main() i32:
println("Mostly Harmless")
return Result.Ok(0)
- Installation and Setup - Get Sushi running on your machine
- Language Guide - Friendly tour of Sushi's features
- Examples - Learn by example (29 hands-on programs)
- Language Reference - Complete syntax and semantics
- Standard Library - Built-in types and functions
- Error Handling -
Result@(T),Maybe@(T), and??operator - Memory Management - RAII, references, and ownership
- Generics - Generic types and compile-time monomorphization
- Perks - Traits/interfaces for polymorphic behavior
- Compiler Reference - CLI options and optimization levels
- Libraries - Creating and using reusable libraries
- Architecture - Compiler design and structure
- Semantic Passes - Pass-by- pass analysis
- Backend - LLVM code generation
All functions return Result@(T) for type-safe error handling:
fn divide(i32 a, i32 b) i32:
if (b == 0):
return Result.Err(StdError.Error)
return Result.Ok(a / b)
fn main() i32:
let i32 result = divide(10, 2).realise(0)
println("Result: {result}")
return Result.Ok(0)
The ?? operator unwraps values or propagates errors automatically:
use <io/fs>
fn read_config() string | IoError:
let File f = open("config.txt", FileMode.Read())??
let string content = f.read_all()??
f.close()??
return Result.Ok(content)
Exhaustive pattern matching with enums:
enum Status:
Idle()
Working(i32 progress)
Done()
fn check(Status s) ~:
match s:
Status.Idle() -> println("Idle")
Status.Working(progress) -> println("Progress: {progress}%")
Status.Done() -> println("Completed")
return Result.Ok(~)
Type-safe generics with zero runtime overhead:
struct Pair@(T, U):
T first
U second
fn main() i32:
let Pair@(i32, string) p = Pair(first: 42, second: "answer")
println("{p.second}: {p.first}")
return Result.Ok(0)
Compile-time borrow checking and RAII. A parameter borrows unless it says nom, and a
marked mode is written at both ends:
fn increment(poke i32 counter) ~:
counter := counter + 1
return Result.Ok(~)
fn eat(nom i32[] items) i32:
return Result.Ok(items.len()) # items is freed here
fn main() i32:
let i32 count = 0
increment(poke count)
println("Count: {count}") # 1
let i32[] data = from([1, 2, 3])
println(eat(nom data).realise(-1))
# println(data.len()) # CE2405: data was handed over
return Result.Ok(0)
Static polymorphism through perks with zero runtime overhead:
perk Hashable:
fn hash() u64
struct Point:
i32 x
i32 y
extend Point with Hashable:
fn hash() u64:
return (self.x as u64) + (self.y as u64)
# Generic function with perk constraint
fn compute_hash@(T: Hashable)(T value) u64:
return Result.Ok(value.hash())
fn main() i32:
let Point p = Point(10, 20)
let u64 h = compute_hash(p)?? # Type inferred automatically
println("Hash: {h}")
return Result.Ok(0)
Heterogeneous, perk-constrained parameter packs, fully monomorphized at compile time:
perk Display:
fn display() string
extend i32 with Display:
fn display() string:
return "int:42"
extend string with Display:
fn display() string:
return self.clone()
fn print_all@(...Ts: Display)(...Ts args) ~:
expand(a in args): # compile-time unrolled, not a runtime loop
println(a.display())
return Result.Ok(~)
fn main() i32:
print_all(42, "hi") # monomorphizes per (arity, type-tuple)
print_all() # arity-0: expand body runs 0 times
return Result.Ok(0)
See the variadics design doc for the full design and Phase-1 limitations.
| Level | Description | Use Case |
|---|---|---|
none / O0 |
No optimization | Debugging |
mem2reg |
Basic SROA (default) | Quick builds |
O1 |
Basic optimizations | Fast compilation |
O2 |
Moderate optimizations | Recommended for production |
O3 |
Aggressive optimizations | Maximum performance |
# Development
./sushic program.sushi
# Production
./sushic --opt O2 program.sushi -o app# Run test suite
python tests/run_tests.py
# Run with runtime validation, enforcing every EXPECT_* directive
python tests/run_tests.py --enhanced
# Run only the leak-annotated subset (the same check, a faster gate)
python tests/run_tests.py --leaks-only
# Filter specific tests
python tests/run_tests.py --filter hashmap--enhanced executes each compiled binary and enforces the # EXPECT_* directives it
declares, including EXPECT_NO_LEAKS: the binary is re-run under a malloc-interposer
(tests/leakcheck) and any outstanding allocation fails the test. --leaks-only runs the
same check over just the tests carrying that directive.
CI (GitHub Actions) additionally runs ruff and mypy (blocking over a growing set of
type-checked packages, informational over the full tree) as a lint gate, and the
cross-platform leak gate (tests/run_tests.py --leaks-only) on both Linux and macOS before
the full suites run.
Check out the examples directory for hands-on learning:
- 01-hello.sushi - Basic program structure
- 04-strings.sushi - String operations
- 07-result.sushi - Error handling
- 15-lists.sushi - Generic lists
- 16-hashmaps.sushi - Hash tables
- 28-ffi.sushi - Foreign function interface
sushi/
├── sushi_lang/ # Main package (installed to site-packages)
│ ├── compiler/ # CLI entry point, pipeline & caching
│ ├── grammar.lark # Lark grammar specification
│ ├── internals/ # Diagnostics, parser, error registry
│ ├── semantics/ # Semantic analysis passes
│ │ ├── passes/ # Multi-pass type checking
│ │ └── generics/ # Generic type system
│ ├── backend/ # LLVM code generation
│ │ ├── expressions/ # Expression emission
│ │ ├── statements/ # Statement emission
│ │ └── types/ # Type-specific codegen
│ ├── sushi_stdlib/ # Standard library
│ │ ├── src/ # Python IR generators
│ │ └── dist/ # Precompiled .bc files
│ └── packager/ # Nori package manager CLI
├── sushic # Development wrapper script
├── tests/ # Test suite
└── docs/ # Documentation
Sushi combines:
- Rust's safety - Ownership, borrowing, explicit error handling
- Python's simplicity - Clean syntax, readable code
- C's performance - Zero-cost abstractions, native binaries
- Python 3.13+ (managed by uv)
- LLVM 20 (llvmlite 0.45 requirement)
- cmake (required for building llvmlite)
# Install uv (if not already installed)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Install cmake (macOS)
brew install cmake
# Install LLVM 20
brew install llvm@20
# Install Python dependencies
uv sync --dev
# Build standard library
uv run python sushi_lang/sushi_stdlib/build.py
# Test installation
./sushic --helpImportant: LLVM 20 is keg-only on macOS. The build process will automatically use the correct version through the LLVM_CONFIG environment variable if needed.
# Compile with debug output
./sushic --traceback --dump-ll program.sushi
# View AST
./sushic --dump-ast program.sushi
# Save LLVM IR
./sushic --write-ll program.sushi
cat program.ll
# Run test suite
uv run python tests/run_tests.py
# Run with runtime validation
uv run python tests/run_tests.py --enhancedSushi can be packaged as a Python wheel for easy installation without requiring users to set up LLVM or clone the repository.
# Build the wheel (requires hatchling)
uv build --wheel
# The wheel will be created in dist/
ls dist/
# sushi_lang-0.12.0-py3-none-any.whl# Install in a virtual environment
pip install sushi_lang-0.12.0-py3-none-any.whl
# The sushic command is now availablScan report · 2026-09-11
- ✓ Prohibited terms or links
- ✓ Repository eligibility
- ✓ slopscore.md paperwork
- ✓ Content policy
- ✓ Risk review
0 comments
log in to comment.