M++ is a statically-typed compiled language targeting LLVM IR. It has a C++-like feel with a clean modern syntax — structs, enums, generics, traits, closures, C FFI, and manual memory control. The compiler is self-hosted: written in M++ and compiled by itself.
Part of the R2ND ecosystem — a project to rebuild the entire software stack from scratch with zero external dependencies.
struct Point { x: float, y: float }
fn distance(a: Point, b: Point) -> float {
let dx = a.x - b.x;
let dy = a.y - b.y;
return sqrt(dx * dx + dy * dy);
}
fn main() {
let p1 = Point { x: 0.0, y: 0.0 };
let p2 = Point { x: 3.0, y: 4.0 };
print("distance: " + to_string(distance(p1, p2)));
// Output: distance: 5.0
}
| Category | Features |
|---|---|
| Types | int, float, bool, string, ptr, structs, enums, generics |
| Abstractions | Functions, closures/lambdas, traits, type aliases |
| Collections | Arrays [T], maps map[K,V], slices |
| Control flow | if/else, while, for..in, match, break, continue |
| Error handling | Result[T], Option<T>, ok(), err(), unwrap() |
| Memory | Manual (alloc/free), reference counting (rc<T>), slices, defer |
| Low-level | Bitwise ops, casting (as), sizeof, raw pointers, *ptr deref |
| Modules | import "file.mpp" — multi-file compilation |
| C interop | extern fn — link against any C library |
| Self-hosted | The compiler is written in M++ and compiles itself |
- LLVM/Clang 14+ — needed to compile the LLVM IR output to a native binary
- Windows x86_64 (Linux support in progress)
mpp.exe— pre-built bootstrap binary included in this repo
git clone https://github.com/mathiassol/mpp
cd mpp
.\mpp.exe examples\hello.mpp --llvm
.\hello.exe
# Output: Hello R2NDCreate myprogram.mpp:
fn main() {
let name = input("What is your name? ");
print("Hello, " + name + "!");
}
Compile and run:
.\mpp.exe myprogram.mpp --llvm
.\myprogram.exe.\mpp.exe examples\structs.mpp --llvm && .\structs.exe
.\mpp.exe examples\generics.mpp --llvm && .\generics.exe
.\mpp.exe examples\closures.mpp --llvm && .\closures.exe
.\mpp.exe examples\memory.mpp --llvm && .\memory.exestruct Person {
name: string,
age: int
}
fn Person.greet(self: Person) -> string {
return "Hi, I'm " + self.name + " and I'm " + to_string(self.age);
}
fn main() {
let p = Person { name: "Alice", age: 30 };
print(p.greet());
}
enum Shape {
Circle(float),
Rect(float, float),
Point
}
fn area(s: Shape) -> float {
match s {
Shape::Circle(r) => { return 3.14159 * r * r; }
Shape::Rect(w, h) => { return w * h; }
Shape::Point => { return 0.0; }
}
}
trait Describable {
fn describe(self) -> string;
}
fn print_all<T: Describable>(items: [T]) {
for item in items {
print(item.describe());
}
}
fn divide(a: int, b: int) -> Result[int] {
if b == 0 { return err("division by zero"); }
return ok(a / b);
}
fn main() {
let r = divide(10, 0);
if is_ok(r) {
print(to_string(unwrap(r)));
} else {
print("Error: " + unwrap_err(r));
}
}
fn process_data() {
let buf: ptr = alloc(1024);
defer { free(buf); } // guaranteed cleanup on any exit path
// ... use buf ...
memset(buf, 0, 1024);
}
fn apply(f: fn(int) -> int, x: int) -> int {
return f(x);
}
fn main() {
let base = 10;
let add_base = |x: int| -> int { return x + base; }; // captures base
print(to_string(apply(add_base, 5))); // 15
}
extern fn printf(fmt: string, val: int) -> int;
extern fn sqrt(x: float) -> float;
fn main() {
let result = sqrt(2.0);
printf("sqrt(2) = %f\n", result as int);
}
| File | What it demonstrates |
|---|---|
hello.mpp |
Basic I/O, entry point |
variables.mpp |
Variables, types, type inference |
functions.mpp |
Functions, default arguments |
structs.mpp |
Structs, methods, field access |
enums.mpp |
Enums with payloads, pattern matching |
generics.mpp |
Generic functions and structs |
traits.mpp |
Trait definitions and implementations |
closures.mpp |
Lambdas, higher-order functions, capturing |
error_handling.mpp |
Result[T] and Option<T> |
modules.mpp |
Multi-file imports |
defer.mpp |
Defer / RAII-style cleanup |
lowlevel.mpp |
Bitwise ops, casting, sizeof, raw pointers |
memory.mpp |
alloc/free, rc<T> reference counting, slices |
ffi.mpp |
Calling C functions via extern fn |
maps.mpp |
map[K, V] — hash maps |
arrays.mpp |
Arrays, append, pop, slicing |
string_interp.mpp |
String operations and formatting |
bootstrap/ Self-hosted compiler source (written in M++)
tokens.mpp Token type definitions
ast.mpp AST node types
lexer.mpp Tokenizer / lexer
parser.mpp Recursive descent parser
typechecker.mpp Type checker and inference
codegen.mpp LLVM IR code generator
main.mpp Compiler entry point and CLI
mpp.ll Last compiled IR (bootstrap artifact)
src/
runtime/
mpp_runtime_llvm.c Runtime library: strings, arrays, maps, I/O, memory
examples/ One example file per major language feature
tests/ Test runner and expected output files
docs/
LANGUAGE.md Full language reference
ROADMAP.md Development roadmap and planned features
The M++ compiler is self-hosted — it compiles itself.
# Rebuild the compiler using the existing mpp.exe
.\mpp.exe bootstrap\mpp.mpp --llvm
# This produces a new mpp.exe
# Run the test suite
powershell -ExecutionPolicy Bypass -File tests\run_bootstrap_tests.ps1| Type | Description | Size |
|---|---|---|
int |
64-bit signed integer | 8 bytes |
float |
64-bit floating point | 8 bytes |
bool |
Boolean (true / false) |
1 byte |
string |
UTF-8 string (heap-allocated) | — |
ptr |
Raw untyped pointer | 8 bytes |
[T] |
Dynamic array of T |
— |
map[K, V] |
Hash map | — |
Option<T> |
Value or None |
— |
Result[T] |
Value or error string | — |
rc<T> |
Reference-counted pointer | — |
M++ uses structured manual memory — no garbage collector, no runtime overhead:
| Kind | Lifetime | Cleanup |
|---|---|---|
Stack values (int, float, bool) |
Automatic | None needed |
Structs with drop() |
Scope-based | Called automatically |
Raw pointers (ptr) |
Manual | free() required |
Reference counts (rc<T>) |
Ref-counted | Freed at count 0 |
Arrays [T] |
Runtime-managed | Currently leaked (planned fix) |
| Strings | Runtime-managed | Currently leaked (planned fix) |
Use defer { free(p); } for deterministic, RAII-style cleanup.
All standard library functions are built-in — no import required.
I/O: print, input
Strings: len, substr, split, contains, trim, replace, to_upper, to_lower, index_of, join, char_at
Conversion: to_string, to_int, to_float, int_to_char, char_to_int
Arrays: len, append, pop, arr_copy
Maps: map_set, map_get, map_has, map_del, map_keys
Math: sqrt, abs, min, max, pow, floor, ceil, round, sin, cos, log
Files: file_read, file_write, file_append, file_exists
Memory: alloc, realloc, free, memcpy, memset, rc_new, rc_clone, rc_release
System: exit, assert
→ Full reference: docs/LANGUAGE.md
- Language Reference — complete syntax, types, stdlib, and memory model
- Website Docs — full web-based language reference
- Getting Started — step-by-step setup guide
Educational project by Mathias.