A memory-safe language for embedded systems that compiles to C
Features • Quick Look • Building • Status • Docs
A programming language designed for embedded systems (ARM Cortex-M0 through M7). Compiles to C, runs natively on bare metal.
This started as a hobby project called dyms back in September. After a few rewrites between Go and Rust, it became Carv — a language that compiles to C with the goal of being safe, small, and suitable for microcontrollers.
The focus is now squarely on embedded systems: sized integer types, volatile memory access, packed structs for register maps, and cross-compilation to ARM targets.
Carv compiles to C and targets embedded hardware (ARM Cortex-M series). No interpreter, no runtime — just clean C output that works with gcc or arm-none-eabi-gcc.
Features that actually work:
- Sized integer types (
u8,u16,u32,u64,i8,i16,i32,i64,f32,f64,usize,isize) volatile<T>for memory-mapped I/Opackedclasses for register maps (__attribute__((packed)))staticvariables for BSS/data section placement- ARM cross-compilation (
carv build --target arm) - Static typing with inference
- Method chaining with
. let/mut/constwith proper immutability enforcement- Compound assignment (
+=,-=,*=,/=,%=,&=,|=,^=) - Classes with methods
- Result types (
Ok/Err) with pattern matching for-inloops over arrays, strings, and maps- Closures with environment capture
- Module system with
require - String interpolation with
f"hello {name}" - Ownership system (move semantics)
- Borrowing (
&T/&mut T) - Interfaces (
interface/implwith vtable-based dispatch) - Async/await (compiles to state machines)
- 40+ built-in functions
// sized types for embedded
let counter: u32 = 0;
let flags: u8 = 0xFF;
let temperature: f32 = 23.5;
// volatile for hardware registers
let status: volatile<u32> = 0;
// packed struct for register maps
packed class GPIO_Regs {
moder: u32 = 0
otyper: u32 = 0
ospeedr: u32 = 0
pupdr: u32 = 0
idr: u32 = 0
odr: u32 = 0
}
// static variables
static let buffer: [64]u8 = [0; 64];
// method chaining
let result = sensor.read().calibrate().to_celsius();
// ownership: move semantics
let s = "hello";
let t = s; // s is moved, now invalid
// error handling without exceptions
fn divide(a: i32, b: i32) {
if b == 0 {
return Err("division by zero");
}
return Ok(a / b);
}
let x = divide(10, 2)?;
// classes
class Point {
x: i32 = 0
y: i32 = 0
}
// closures
let multiplier = 3;
let triple = fn(x: i32) -> i32 {
return x * multiplier;
};
// math.carv
pub fn add(a: i32, b: i32) -> i32 {
return a + b;
}
// main.carv
require { add } from "./math";
println(f"1 + 2 = {add(1, 2)}");
git clone https://github.com/dev-dami/carv
cd carv
make buildThen:
./build/carv build file.carv # compile to binary (host)
./build/carv build --target arm file.carv # compile for ARM Cortex-M
./build/carv emit-c file.carv # emit generated C source
./build/carv repl # start interactive REPL
./build/carv lsp # start language server
./build/carv init # create new project with carv.toml
./build/carv add mylib --git <url> # add a dependency
./build/carv install # install all dependencies
./build/carv pkg list # list installed packages
./build/carv pkg update # update dependencies
./build/carv pkg publish # publish package to GitHubFor ARM targets, you need arm-none-eabi-gcc installed.
No need to clone or build — grab a pre-built binary directly:
# Install latest release
curl -fsSL https://raw.githubusercontent.com/dev-dami/carv/main/scripts/install.sh | bash
# Install a specific version
curl -fsSL https://raw.githubusercontent.com/dev-dami/carv/main/scripts/install.sh | bash -s -- v0.5.1-betaThe script auto-detects your OS/architecture, downloads the matching binary from GitHub releases, and installs it to /usr/local/bin (or ~/.local/bin).
Supported platforms: Linux (amd64, arm64), macOS (amd64, arm64), Windows (amd64).
- Lexer, parser, type checker
- C code generation (AOT only)
- Static typing with inference
- Sized integer types (
u8-u64,i8-i64,f32,f64,usize,isize) -
volatile<T>for memory-mapped I/O -
packedclasses for register maps -
staticvariable declarations - ARM cross-compilation (
--target arm)
- Primitives (int, float, string, bool, char + all sized variants)
- Arrays and hash maps
- Result types (
Ok/Err) with pattern matching - Classes with methods
- Ownership system (move semantics)
- Borrowing (
&T/&mut T) - Arena allocator in codegen
- Automatic drop insertion
- First-class functions
- Closures with capture
- Method chaining (
.) - Higher-order functions
- Interfaces (
interface/implwith vtables) - Module system (
require) - String interpolation (
f"...") - Async/await (state-machine codegen)
- Project config (
carv.toml) - Build scripts
- REPL with history, tab completion,
:type,:load,:clear - LSP server (diagnostics, hover, go-to-definition, completion)
- VS Code extension (syntax highlighting + LSP client)
- Package manager (
carv pkg, semver resolution, lock files, GitHub registry) - HAL modules (GPIO, UART, SPI, I2C, Timers)
- Self-hosting
$ carv repl
carv 0.5.1-beta - Type :help for commands
>>> let x = 42;
>>> :type x
i32
>>> :load script.carv
>>> :clearREPL features: command history, tab completion, multi-line input, :help, :type, :clear, :load.
Carv has a built-in package manager with semver resolution and lock files:
carv add mylib --git https://github.com/user/mylib --version "^1.0.0"
carv install
carv pkg list
carv pkg update
carv pkg publishDependencies are resolved transitively, with cycle detection. Lock files (carv.lock) pin exact versions for reproducible builds. Packages are published via git tags on GitHub.
Start the language server with carv lsp (stdio transport). Provides:
- Diagnostics — type errors, ownership violations, warnings
- Hover — type info on hover
- Go-to-definition — jump to symbol definition
- Completion — keyword and symbol suggestions
A VS Code extension is included in editors/vscode/ with syntax highlighting and LSP client integration.
MIT
Built for blinking LEDs, reading sensors, and writing to registers — without the footguns of raw C.