Language Reference

M++ Reference

Complete language specification for M++ — a statically-typed, LLVM-compiled systems language with no external runtime.

Basics

Every M++ program starts with a main function.

fn main() {
    // entry point
}

Variables

let x = 42;             // immutable, type inferred
let mut counter = 0;    // mutable

let x: int = 42;        // explicit type annotation

const MAX_SIZE: int = 1024;  // compile-time constant

Comments

// single-line comment

/* multi-line
   comment */

Types

Primitive Types

TypeSizeDescription
int8 bytes64-bit signed integer
float8 bytes64-bit floating point (IEEE 754)
bool1 bytetrue or false
stringheapUTF-8 string with length metadata
ptr8 bytesraw untyped pointer
voidno value (function return only)

Collection Types

let nums: [int] = [1, 2, 3, 4, 5];   // array
let m: map[string, int];              // map (hash map)
let s = slice(nums, 1, 3);            // slice (view into array)

Generic Types

Option<T>   // Some(value) or None — optional value
Result[T]   // ok(value) or err(message) — fallible return
rc<T>       // reference-counted smart pointer

Type Aliases

type Id = int;
type Callback = fn(string) -> void;

Functions

fn add(a: int, b: int) -> int {
    return a + b;
}

fn greet(name: string) -> string {
    return "Hello, " + name + "!";
}

// Default arguments
fn connect(host: string, port: int = 8080) -> string {
    return host + ":" + to_string(port);
}

// Recursive
fn factorial(n: int) -> int {
    if n <= 1 {
        return 1;
    }
    return n * factorial(n - 1);
}

fn main() {
    print(add(3, 4));            // 7
    print(greet("R2ND"));        // Hello, R2ND!
    print(connect("localhost"));  // localhost:8080
    print(factorial(5));          // 120
}

Control Flow

If / Else

if x > 0 {
    print("positive");
} else if x < 0 {
    print("negative");
} else {
    print("zero");
}

While Loop

let mut i = 0;
while i < 10 {
    print(i);
    i = i + 1;
}

For Loop

// range (exclusive end)
for i in 0..10 {
    print(i);
}

// iterate over array
let names = ["Alice", "Bob", "Carol"];
for name in names {
    print(name);
}

Break & Continue

for i in 0..100 {
    if i == 5 { break; }
    if i % 2 == 0 { continue; }
    print(i);
}

Match

// match on values
match x {
    1 => print("one"),
    2 => print("two"),
    _ => print("other"),
}

// match on enum variants
match shape {
    Shape::Circle(r)    => print("circle r=" + to_string(r)),
    Shape::Rect(w, h)   => print("rect " + to_string(w) + "x" + to_string(h)),
    Shape::Point        => print("point"),
}

Structs

struct Point {
    x: float,
    y: float,
}

// Method definition
fn Point.length(self: Point) -> float {
    return sqrt(self.x * self.x + self.y * self.y);
}

fn Point.scale(self: Point, factor: float) -> Point {
    return Point { x: self.x * factor, y: self.y * factor };
}

fn main() {
    let p = Point { x: 3.0, y: 4.0 };
    print(p.length());       // 5.0
    let p2 = p.scale(2.0);
    print(p2.x);             // 6.0
}

Enums

Simple Enum

enum Direction {
    North,
    South,
    East,
    West,
}

let dir = Direction::North;

Enum with Payloads

enum Shape {
    Circle(float),        // radius
    Rect(float, float),   // width, height
    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,
    }
}

Traits

// Define a trait
trait Describable {
    fn describe(self) -> string;
}

// Implement for a type
struct Cat {
    name: string,
}

impl Describable for Cat {
    fn describe(self: Cat) -> string {
        return "Cat named " + self.name;
    }
}

// Use trait as a type constraint
fn print_description<T: Describable>(item: T) {
    print(item.describe());
}

fn main() {
    let c = Cat { name: "Whiskers" };
    print_description(c);   // Cat named Whiskers
}

Generics

Generic Functions

fn identity<T>(x: T) -> T {
    return x;
}

fn first<T>(arr: [T]) -> T {
    return arr[0];
}

Generic Structs

struct Box<T> {
    value: T,
}

fn Box.get<T>(self: Box<T>) -> T {
    return self.value;
}

let b = Box { value: 42 };
print(b.get());   // 42

Type Constraints

fn print_all<T: Describable>(items: [T]) {
    for item in items {
        print(item.describe());
    }
}

Closures

// Lambda syntax
let double = |x: int| -> int { return x * 2; };
print(double(5));   // 10

// Passing lambdas as arguments
fn apply(f: fn(int) -> int, x: int) -> int {
    return f(x);
}
print(apply(double, 7));   // 14

// Capturing variables from enclosing scope
let factor = 3;
let triple = |x: int| -> int { return x * factor; };
print(triple(4));   // 12

Error Handling

Result[T]

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, 2);
    if r.is_ok() {
        print(r.unwrap());        // 5
    }

    let r2 = divide(10, 0);
    print(r2.unwrap_err());       // division by zero
}

Option<T>

fn find_first(arr: [int], target: int) -> Option<int> {
    for i in 0..len(arr) {
        if arr[i] == target {
            return Some(i);
        }
    }
    return None;
}

fn main() {
    let idx = find_first([1, 2, 3, 4], 3);
    if idx.is_some() {
        print(idx.unwrap());   // 2
    }
}

Modules

M++ uses file-based modules. Imports are resolved relative to the source file being compiled.

// math_helpers.mpp
fn square(x: int) -> int {
    return x * x;
}

fn cube(x: int) -> int {
    return x * x * x;
}

Import and use in another file:

import "math_helpers.mpp";

fn main() {
    print(square(4));   // 16
    print(cube(3));     // 27
}

C FFI

Declare C functions with extern fn. The linker resolves them at compile time.

extern fn sin(x: float) -> float;
extern fn cos(x: float) -> float;
extern fn printf(fmt: ptr, ...) -> int;

fn main() {
    let s = sin(3.14159 / 2.0);
    print(s);   // ~1.0
}

Linking with a C file

# Compile M++ source to LLVM IR
.mpp.exe myapp.mpp --llvm

# Manually link LLVM IR with a C translation unit
clang myapp.ll my_c_lib.c -o myapp.exe

Defer

defer schedules a block to execute when the enclosing scope exits — regardless of how it exits. Multiple defers run in LIFO order.

fn process_file() {
    let p = alloc(1024);
    defer { free(p); }   // runs at scope exit, even on early return

    // ... use p ...
    print("working");
    // free(p) called here automatically
}

// LIFO order demonstration
fn main() {
    defer { print("third"); }
    defer { print("second"); }
    defer { print("first"); }
    // Prints: first, second, third
}

Low-Level

Bitwise Operations

let a = 0b1010;
let b = 0b1100;

print(a & b);   // AND  → 0b1000  (8)
print(a | b);   // OR   → 0b1110  (14)
print(a ^ b);   // XOR  → 0b0110  (6)
print(~a);      // NOT  → bitwise complement
print(a << 2);  // left shift
print(b >> 1);  // right shift

Casting

let x: int = 42;
let f: float = x as float;   // 42.0

let pi: float = 3.14;
let n: int = pi as int;       // 3 (truncates)

Sizeof

print(sizeof(int));    // 8
print(sizeof(float));  // 8
print(sizeof(bool));   // 1
print(sizeof(ptr));    // 8

Raw Pointers

let p: ptr = alloc(8);   // allocate 8 bytes on heap
*p = 42;                 // write through pointer
let val = *p;            // dereference
free(p);                 // deallocate

// Address-of operator
let x = 100;
let p2: ptr = &x;

// Null pointer
let null_p: ptr = null;

Memory

Memory Model

StorageDescription
int, float, bool, ptrFixed-size values allocated on the call stack
structStored by value on the stack unless explicitly heap-allocated
stringHeap-allocated UTF-8 data with length metadata
[T] arrayHeap-allocated contiguous block of elements
ptrManual heap memory — caller responsible for free()
rc<T>Reference-counted heap allocation — freed when count reaches 0

Manual Allocation

let p  = alloc(size);              // allocate N bytes
let p2 = realloc(p, new_size);    // resize allocation
free(p2);                          // deallocate

Memory Operations

memset(p, 0, 64);         // zero 64 bytes starting at p
memcpy(dst, src, 32);     // copy 32 bytes from src to dst

Reference Counting

let r  = rc_new(42);       // create rc<int> with value 42
let r2 = rc_clone(r);      // clone — increments ref count
print(rc_count(r));        // 2

print(rc_get(r));          // 42
rc_set(r, 100);
print(rc_get(r2));         // 100  (r and r2 share the same value)

rc_release(r);
rc_release(r2);            // count reaches 0 → memory freed

Slices

let arr = [10, 20, 30, 40, 50];
let s   = slice(arr, 1, 4);    // view of elements at index 1, 2, 3
print(slice_len(s));            // 3
print(slice_get(s, 0));         // 20

Standard Library

I/O

print("Hello, world!");    // print line to stdout
let line = input();        // read line from stdin

String Functions

FunctionSignatureDescription
lenlen(s: string) -> intLength in characters
substrsubstr(s, start, end) -> stringSubstring [start, end)
splitsplit(s, delim: string) -> [string]Split by delimiter
containscontains(s, sub: string) -> boolCheck if substring exists
starts_withstarts_with(s, prefix: string) -> boolPrefix check
ends_withends_with(s, suffix: string) -> boolSuffix check
trimtrim(s: string) -> stringStrip leading/trailing whitespace
index_ofindex_of(s, sub: string) -> intFirst occurrence index, -1 if not found
replacereplace(s, from, to: string) -> stringReplace all occurrences
to_upperto_upper(s: string) -> stringConvert to uppercase
to_lowerto_lower(s: string) -> stringConvert to lowercase
char_atchar_at(s: string, i: int) -> stringCharacter at index
str_repeatstr_repeat(s: string, n: int) -> stringRepeat string n times
str_concatstr_concat(a, b: string) -> stringConcatenate two strings
joinjoin(arr: [string], sep: string) -> stringJoin array with separator

Type Conversion

FunctionSignatureDescription
to_stringto_string(x) -> stringConvert any value to string
to_intto_int(s: string) -> intParse string as integer
to_floatto_float(s: string) -> floatParse string as float
int_to_charint_to_char(n: int) -> stringASCII code to single-character string
char_to_intchar_to_int(c: string) -> intCharacter to ASCII code

Array Functions

FunctionSignatureDescription
lenlen(arr: [T]) -> intNumber of elements
appendappend(arr: [T], value: T)Append element in-place
poppop(arr: [T]) -> TRemove and return last element
arr_copyarr_copy(arr: [T]) -> [T]Shallow copy of array

Map Functions

FunctionSignatureDescription
map_setmap_set(m, key: K, val: V)Insert or update a key
map_getmap_get(m, key: K) -> VGet value by key
map_hasmap_has(m, key: K) -> boolCheck if key exists
map_delmap_del(m, key: K)Delete a key
map_keysmap_keys(m) -> [K]Get all keys as array
lenlen(m) -> intNumber of entries

Math

FunctionDescription
sqrt(x: float) -> floatSquare root
abs(x) -> TAbsolute value (int or float)
min(a, b) -> TMinimum of two values
max(a, b) -> TMaximum of two values
pow(base: float, exp: float) -> floatbase raised to exp
floor(x: float) -> floatRound down to nearest integer
ceil(x: float) -> floatRound up to nearest integer
round(x: float) -> floatRound to nearest integer
sin(x: float) -> floatSine (radians)
cos(x: float) -> floatCosine (radians)
log(x: float) -> floatNatural logarithm

File I/O

FunctionSignatureDescription
file_readfile_read(path: string) -> stringRead entire file contents
file_writefile_write(path: string, content: string)Write (overwrite) file
file_appendfile_append(path: string, content: string)Append content to file
file_existsfile_exists(path: string) -> boolCheck if file exists

System

FunctionSignatureDescription
exitexit(code: int) -> voidExit process with status code
assertassert(cond: bool, msg: string)Abort with message if condition is false

Operators

Precedence (lowest → highest)

LevelOperatorsDescription
1||Logical OR
2&&Logical AND
3== !=Equality / Inequality
4< <= > >=Comparison
5|Bitwise OR
6^Bitwise XOR
7&Bitwise AND
8<< >>Bit shifts
9+ -Addition / Subtraction
10* / %Multiplication / Division / Modulo
11! ~ - * & as sizeofUnary operators
12. [] ()Member access / Index / Call

Assignment Operators

x  = 5;   // assign
x += 3;   // x = x + 3
x -= 2;   // x = x - 2
x *= 4;   // x = x * 4
x /= 2;   // x = x / 2

Keywords

All reserved keywords in M++:

fnletmutconstreturnifelsewhileforinbreakcontinuematchstructenumtraitimplimportexterndefertypetruefalsenullassizeofokerrSomeNone

Compilation

.\mpp.exe source.mpp --llvm

Produces source.ll (LLVM IR) and source.exe (native binary) in the same directory as the source file.

Compiler Flags

FlagDescription
--llvmEmit LLVM IR and compile to native binary (required for executable output)
--emit-irOnly emit the .ll file — skip the clang compilation step
--verbosePrint compiler debug and diagnostic output
--out <name>Specify the output binary filename