ماه — "moon" in Persian
A small language, built entirely from scratch.
Mah is a hand-written lexer, parser, resolver, bytecode compiler, and VM for its own portable bytecode format -- plus a formatter, a real language server, and editor integrations. Every one of them pure Python, standard library only, with zero third-party runtime dependencies anywhere in the toolchain. A native Rust runtime runs the exact same bytecode.
struct Point { x, y }
fn add(a, b) {
return Point { x: a.x + b.x, y: a.y + b.y }
}
let p = add(Point { x: 1, y: 2 }, Point { x: 3, y: 4 })
print(p) # Point { x: 4, y: 6 }
enum Shape {
Circle { r },
Square { s },
Empty
}
fn area(s) {
match s {
Shape.Circle { r } => { 3 * r * r }
Shape.Square { s } => { s * s }
Shape.Empty => { 0 }
}
}
print(area(Shape.Circle { r: 5 })) # 75Get started
Clone the repo and run programs immediately -- nothing to pip install. Once mah is on your PATH (make install-mah), every command
below works from anywhere.
mah init my-app # scaffolds mah-project.toml, src/main.mh, docs/
cd my-app
mah run # runs the entry point from mah-project.toml
mah build # writes every [[target]], e.g. build/my-app.mahcmah run ./examples/prime_numbers.mh # compile and run directly
mah build ./examples/structs.mh # -> structs.mahc
mah runc ./examples/structs.mahc # run compiled bytecode
mah format ./examples # rewrite .mh files in the standard layoutmake vm # build mah-vm (needs cargo)
mah run --vm rust ./examples/structs.mh # run on the native runtime
mah build --self-contained ./examples/structs.mh -o structs
./structs # runs with no mah install neededWhat's in the language
Closures that capture by reference
Heap-allocated Frames linked by a static chain (the classic SCP/DCP technique) mean a closure that outlives its call still sees later mutations of the variables it captured -- like JavaScript, not Python.
Structs, enums, and pattern matching
struct fields have no types; enum variants can be unit or struct-shaped. match handles literals, some/none, struct/enum destructuring, range patterns, guards, and wildcards.
Rust-style traits
trait declares required and default methods; impl Trait for Type implements them, including for your own types and (orphan-rule-respecting) built-ins like Number.
Lazy iterators and ranges
map/filter/skip/take/reduce work lazily over ranges, Strings, Vectors, Maps, and any type that implements Iterable + Iterator -- plus for loops and range patterns.
Cooperative async
detach any call or expression to get a Promise back, then .await it. Single-threaded and cooperative -- no hidden threads.
Default params and kwargs
fn greet(name, greeting = "Hello") and greet("Mah", greeting: "Salam") -- defaults and keyword arguments work for functions, methods, and static calls alike.
Modules with export/import
export fn / export let mark what's visible to importers; import "lib.mh" or import m from "lib" bring it in, flat or namespaced. Diamond imports and cycles are safe.
mah format
A whitespace-only formatter that verifies its own output: same tokens, same comments, same AST before it ever writes a file.
A real LSP + VS Code / Neovim
Live diagnostics, hover, completion, go-to-definition, cross-file rename, and format-on-save -- built on the same resolver the compiler uses, not a second analysis.
Portable bytecode, two VMs
mah build compiles to a portable .mahc format (docs/MAHC_FORMAT.md) with both a Python reference VM and a from-scratch Rust runtime (mah-vm) -- plus self-contained, dependency-free executables.
Project manifests
mah init scaffolds mah-project.toml, src/main.mh, and docs written for coding agents. mah run / mah build / mah check work from any subdirectory.
Optional type annotations
fn add(a: Number, b: Number) -> Number { a + b } -- syntax and generics exist today; a static type checker with inference is the next milestone (see /docs/types).
Closures capture by reference
let counter = fn() {
let count = 0
return fn() {
count = count + 1
return count
}
}
let next = counter()
print(next()) # 1
print(next()) # 2Async: detach, then .await
fn slow(n) { sleep_async(10); n * 2 }
let a = detach slow(21)
let b = detach { sleep_async(5); "from a block" }
print(a.await, b.await) # 42 from a blockTooling that isn't an afterthought
mah lsp is a dependency-free LSP built directly on the same resolver the compiler
uses: live diagnostics, hover, completion, go-to-definition, cross-file rename, and
document formatting. It ships with a VS Code extension and Neovim integration
(tree-sitter grammar + ftplugin).
mah build compiles to a portable .mahc bytecode file that runs on
the Python VM or the from-scratch Rust runtime (--vm rust), and mah build --self-contained bundles the runtime and bytecode into one executable
file that needs neither Python nor mah installed to run.