sr-lang is a personal, experimental programming language and compiler built as a way to learn compiler construction by building something real.
The project started small and gradually accumulated features as I explored parsing, semantic analysis, type systems, and backend design. As a result, some parts are relatively solid while others are experimental, incomplete, or rough around the edges.
This is intentional.
The goal of sr-lang is exploration and learning, not polish or production readiness. Bugs, awkward designs, and missing pieces reflect my learning process at the time they were written, and improving or replacing them is part of the project’s value.
sr-lang is a learning-first project.
It prioritizes:
- Real implementations over toy examples
- Exploration over premature optimization
- Iteration over stability
If you’re looking for a polished or production-ready language, this is probably not it. If you’re interested in how languages are built — and rebuilt — this project is meant for that.
The language is designed with a focus on modern language features, explicit control, and compiler extensibility.
- Variables & Constants: Flexible declarations with type inference (
:=) or explicit typing (:), and compile-time constants (::). - Literals: Comprehensive support for integer (decimal, hex, octal, binary), floating-point, character, string (including raw and byte strings), and boolean literals.
- Operators: A full suite of arithmetic, comparison, logical, bitwise, and assignment operators, including overflow-aware arithmetic (wrapping
+%and saturating+|). - Functions & Procedures: Define functions (
fn) with return values or procedures (proc) for side effects. Supports default arguments, variadic parameters (any), and external function declarations (extern). - Control Flow:
- Conditional Expressions:
if/elseexpressions. - Loops:
whileloops (boolean, pattern-matching, infinite) andforloops for iteration over collections or ranges. - Labeled Control:
breakandcontinuestatements, including labeled versions for nested loops andbreakwith a return value. - Pattern Matching: Powerful
matchexpressions for exhaustive pattern matching over values.
- Conditional Expressions:
- Error Handling:
- Error Union Types:
SuccessType!ErrorTypefor handleable errors. - Propagation: The
!operator for concise error propagation. - Handling:
catchfor error handling blocks andorelsefor providing default values on error. - Cleanup:
deferanderrdeferstatements for guaranteed resource cleanup on scope exit (success or error).
- Error Union Types:
- Basic Types: Built-in support for various integer widths (
i32,u64), floating-point numbers (f32,f64), booleans, and strings. - Aggregates:
- Structs: Custom data structures with named fields.
- Enums: Enumerated types, including C-style and integer-backed enums.
- Variants (Sum Types): Powerful discriminated unions with tuple-like or struct-like payloads, enabling exhaustive pattern matching.
- Unions: Untagged unions where fields share the same memory.
- Collections:
- Tuples: Fixed-size, ordered collections of heterogeneous types.
- Arrays: Fixed-size, homogeneous collections (
[N]T). - Slices: Dynamic views into arrays (
[]T). - Dynamic Arrays: Growable, heap-allocated arrays (
[dyn]T) withappend,len, andcapacityoperations. - Maps: Associative arrays (
[KeyType:ValueType]).
- Pointers & Memory: Raw pointers (
*T), constant pointers (*const T), address-of operator (&), and dereference operator (.*or*). - Type Casting: Explicit postfix cast operators for normal (
.()), bitwise (.^), saturating (.|), wrapping (.%), and checked (.?) conversions.
- Attributes: Apply metadata to functions, types, and fields using
@[]syntax. - Closures & Higher-Order Functions: Define anonymous functions (
|x|) that can capture their environment, enabling functional programming patterns. - Asynchronous Programming:
asyncprocedures andasyncblocks, with the.awaitoperator for non-blocking execution. - Compile-Time Execution (
comptime): Execute code during compilation for assertions, code generation, and static analysis. - Code as Data (
codeblocks): Capture Abstract Syntax Trees (ASTs) as first-class values, allowing for programmatic manipulation andinsertion into the program. - MLIR Integration: Embed raw MLIR constructs (
mlir { ... }) directly into the source code for fine-grained control over the intermediate representation. - Assembly Integration: Write functions directly in assembly (
asm { ... }) for performance-critical sections. - Reflection: Support for both compile-time and runtime reflection to inspect and manipulate types and values.
- Compile-Time Polymorphism: Achieved through static duck typing using the
anytype and compile-time functions as "concepts."
- Packages: Every
.srfile declares a package at the top of the file (package foo).- Entry points (
zig build run -- path/to/app.sr) must declarepackage main, mirroring Go/Odin executables. - When a directory is imported (for example
import "std/io"orimport "vendor/raylib"), the compiler loadsmain.srfrom that directory and expects the package name to match the directory basename (e.g.package io).
- Entry points (
- Imports: Organize code into modules and import them using the
importkeyword with fully qualified package paths (e.g.math :: import "examples/imports/math").
To build and run the compiler, you will need:
- Zig Compiler: The project is built using Zig.
- LLVM/MLIR Development Libraries: The compiler links against MLIR for its backend.
- Clang 20: Required for compiling generated LLVM IR (opaque pointers); ensure
clang/clang++resolve to clang-20.
On Ubuntu 22.04, you can install and map clang-20 like this:
sudo apt-get update
sudo apt-get install -y lsb-release wget software-properties-common gnupg
curl -fsSL https://apt.llvm.org/llvm.sh -o /tmp/llvm.sh
chmod +x /tmp/llvm.sh
sudo /tmp/llvm.sh 20
sudo ln -sf "$(command -v clang-20)" /usr/local/bin/clang
sudo ln -sf "$(command -v clang++-20)" /usr/local/bin/clang++If you don’t want to build from source, you can download a prebuilt binary from the GitHub Releases page and run it directly.
- Tested on Ubuntu 22.04 and Arch Linux
- Other Linux distributions may work, but are not guaranteed
Go to the latest GitHub Release and download the binaries.
./bin/src --help # Prints usage
./bin/src run hello.sr # Compiles and runs the programThe build currently assumes system paths that may need adjustment for your machine. Check build.zig and update:
LLVM_HOME_S(defaults to/usr/local/lib) to your LLVM/MLIR installlibdirectory.- The hardcoded
libstdc++path (/usr/lib/libstdc++.so.6) if your distro uses a different location.
Optional integrations (Triton, Torch, Skia) are also configured with hardcoded paths; see build.zig and the vendor sections below if you want to enable them.
git clone https://github.com/llvm/llvm-project
export LLVM_HOME=llvm-project
cd llvm-project
mkdir build
cd build
cmake -G Ninja ../llvm -DLLVM_ENABLE_PROJECTS=mlir;llvm -DLLVM_TARGETS_TO_BUILD="Native;NVPTX;AMDGPU" -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_ASSERTIONS=ON -DCMAKE_C_COMPILER="clang" -DCMAKE_CXX_COMPILER="clang++" -DLLVM_ENABLE_LLD=ON
ninja
cmake --install .If you want a portable Linux release without rebuilding LLVM/MLIR every time, use the Docker flow in this repo.
Build the base image once:
./build_release_image.shThen build
./release_docker.shThe release flow requires clang-20. The scripts map clang and clang++ to clang-20 to avoid opaque-pointers linker errors when compiling generated LLVM IR.
This produces sr-lang-0.1.0-linux-x86_64.tar.gz from zig-out and caches LLVM/MLIR under _llvm/build-<commit>/.
Navigate to the root of the sr-lang repository and run:
zig buildRelease Build:
zig build -Doptimize=ReleaseFast
This command will compile the sr-lang compiler executable.
To run the "hello world" example:
zig build run -- examples/hello.srAlternatively, after building, you can directly run the executable (debug build name):
./zig-out/bin/sr_lang examples/hello.srRelease version (Why two different names? Because I can.):
./zig-out/bin/src examples/hello.srWhen launching Triton kernels, you can control the runtime cache with:
SR_TRITON_NOCACHE=1disables module/function caching (always reloads).SR_TRITON_RELOAD=1reloads PTX if the file mtime changes; logs when a reload happens.
zig build testzig build checkcd third-party/triton # make sure to pull submodules
python -m venv .venv --prompt triton
source .venv/bin/activate
pip install -r python/requirements.txt # build-time dependencies
export LLVM_BUILD_DIR=$HOME/llvm-project/build
LLVM_INCLUDE_DIRS=$LLVM_BUILD_DIR/include \
LLVM_LIBRARY_DIR=$LLVM_BUILD_DIR/lib \
LLVM_SYSPATH=$LLVM_BUILD_DIR \
pip install -e .
Install via system package manager.
Download LibTorch from PyTorch website and extract to an appropriate location.
export LIBTORCH=path/to/libtorch
cd vendor/torch/torch-sys/libtch
makeTo link torch, link vendor/torch/torch-sys/libtch/libtorch_api.so.
Install Skia using system package manager if available, or build from source.
cd vendor/skiac
makeTo link skia, link vendor/skiac/libskia.so.
The language is in an alpha state. This means:
- The language syntax and semantics are subject to change.
- Many features are implemented but may not be fully stable or correctly integrated.
- The compiler is under active development, and contributions are welcome (see below).
src/: Contains the core Zig source code for the compiler, including AST definitions, type checking, and MLIR code generation.examples/: A collection of.srsource files showcasing various language features and syntax.tests/: A collection of.srsource files used for testing and validation.std/: A very basic collection of standard library modules, such asio,math, andstring.vendor/: A collection of external packages that can be imported using theimportkeyword.build.zig: The Zig build script for the project.
features.md: Detailed language feature inventory derived from compiler sources.docs/: In-progress design notes and documentation.BUGS.md: Known issues and sharp edges.TODO.md: Short- and long-term work items.
Contributions are welcome! Please feel free to open issues or pull requests.
This project is intentionally incomplete in many areas, which makes it a good place to learn and experiment without fear of breaking something critical.
If you’re new to compilers, programming languages, or open source in general, here are some concrete ways to get involved:
The standard library is currently very minimal. This is a great opportunity to design and implement foundational pieces from scratch, such as:
- Basic data structures (arrays, maps, strings, etc.)
- I/O utilities
- Math and numeric helpers
- Error and result utilities
Ownership of entire modules is encouraged.
Many language features exist but lack thorough testing.
Contributions here include:
- Writing
.srtest cases for language features - Adding regression tests for existing bugs
- Improving coverage for edge cases
This is one of the best ways to learn how the language actually behaves.
Documentation is sparse and evolving.
Help is welcome for:
- Writing small language guides or explanations
- Adding annotated examples in the
examples/directory - Documenting language features that already exist but aren’t explained yet
Clear docs are just as valuable as code.
For contributors interested in compiler internals:
- Improving diagnostics and error messages
- Refactoring or simplifying parts of the AST or type checker
- Exploring alternative MLIR lowering strategies
- Cleaning up experimental or unused code paths
This is a good place to learn how real compiler codebases evolve.
If you’re unsure where to start:
- Look for issues labeled
good-first-issueorhelp-wanted - Open an issue to ask questions or propose an idea
- Submit a small exploratory PR — imperfect contributions are expected
Learning and iteration matter more than polish here.
This project is licensed under the GNU General Public License v3.0 (GPLv3). See the LICENSE file for the full text.