Simple to write. safe to run.
do divmod(a i64, b i64) -> (i64, i64) {
return a / b, a % b
}
do main() {
const name string = "Grayscale"
mut total i64 = 0
for i in range(1, 6) {
total += i
}
mut quotient, remainder = divmod(total, 4)
if remainder == 0 {
println("${name}: ${total} divides evenly")
} or quotient > 3 {
println("${name}: ${total} / 4 = ${quotient} remainder ${remainder}")
} otherwise {
println("${name}: ${total} is small")
}
}
const Shape enum {
Circle(f64)
Rect(f64, f64)
Point
}
const Vec struct {
x i64
y i64
do scale(self Vec, factor i64) -> Vec {
return Vec{x: self.x * factor, y: self.y * factor}
}
}
do area(shape Shape) -> f64 {
when shape {
is Shape.Circle(radius) { return 3.14159 * radius * radius }
is Shape.Rect(w, h) { return w * h }
default { return 0.0 }
}
}
do main() {
mut v = Vec{x: 2, y: 3}
mut scaled = v.scale(factor: 5)
println("scaled: ${scaled.x}, ${scaled.y}")
println("rect: ${area(Shape.Rect(3.0, 4.0))}")
}
import @io
do cleanup() {
println("cleanup ran")
}
do load(path string) -> (string, Error) {
ensure cleanup()
mut content = io.read_file(path) or_return
return content, nil
}
do main() {
mut content, err = load("missing.txt")
if err != nil {
println("could not load file")
} otherwise {
println(content)
}
}
import @math
do main() {
println("sqrt(144) = ${math.sqrt(144.0)}")
}
- Simplicity — Readable, opinionated syntax — bitwise and membership operators are real keywords (
bit_and,bit_xor,not_in), not punctuation — with familiar per-file aliases (fn,switch/case,elif/else,while,defer) for those who prefer them. Helpful compile-time errors & warnings and runtime panics. Useful CLI commands likegray man,gray check,gray new, andgray watch. - Flexibility — Build scripts and dev tooling, cross-platform CLI utilities, HTTP/JSON backend services, SQLite-backed apps, network daemons, and batch data processing, or learning systems programming fundamentals.
- Modularity — Beyond a small builtin core, everything else needs an import. Stdlib modules, your own
.grayfiles, and C headers can all be imported. - Safety — An automatic scope-based arena management memory model with a compile-time pointer checker that proves no pointer is ever readable after its memory is reclaimed, bounds-checked arrays, strings, and maps, overflow-checked arithmetic, division-by-zero protection, nil pointer checks, stack depth guards, NO pointer arithmetic. The guardrails are on unless you explicitly opt in to unsafe operations like raw pointers (
raw()), manual memory management (@mem), threading (@threads), or C interop (extern import)
@arrays · @atomic · @binary · @channels · @chars · @crypto · @csv · @encoding · @fmt · @http
@io · @json · @maps · @math · @mem · @net · @os · @random · @regex
@runtime · @server · @sqlite · @strconv · @strings · @sync · @threads · @time · @uuid
Download the latest release for your platform from the Releases page. No dependencies required.
Requires Go 1.23+ and a C compiler — GCC 7+ or Clang 5+ (GNU C extensions required).
git clone https://github.com/grayscale-lang/grayscale.git
cd grayscale
make build
make installGrayscale builds on Windows with MinGW-w64.
winget install BrechtSanders.WinLibs.POSIX.UCRT.Base # or: choco install mingw
git clone https://github.com/grayscale-lang/grayscale.git
cd grayscale
make buildmake build, make test, and make clean work the same as on macOS and
Linux. make needs a POSIX shell, which MSYS2 and Git Bash both provide.
The compiler finds MinGW in its default install locations automatically —
it does not need to be on PATH.
| Command | Description | Example |
|---|---|---|
gray <file> |
Compile and run | gray main.gray |
gray build <file> -o <name> |
Compile to a distributable binary | gray build main.gray -o myapp |
gray build <file> --emit-c |
Emit generated C source to a file (no binary) | gray build main.gray --emit-c |
gray build <file> --arena-limit=<size> |
Cap arena memory (KB/MB/GB; default: 1GB) | gray build main.gray --arena-limit=256MB |
gray check <file> |
Type check without compiling | gray check main.gray |
gray test [path...] |
Compile and run #test functions |
gray test ./src/... |
gray watch <file> |
Watch for changes, re-run on save | gray watch main.gray |
gray fmt <path> |
Format .gray source files in place |
gray fmt . or gray fmt ./... |
gray fmt --check <path> |
Check formatting without modifying files (CI gate) | gray fmt --check ./... |
gray doc <file> |
Generate docs from #doc attributes |
gray doc main.gray |
gray new <name> |
Scaffold a new project | gray new myproject |
gray report |
Print system info for bug reports | gray report |
gray verify |
Run the built-in language verification test suite | gray verify |
gray update |
Update to the latest stable version | gray update |
gray update --pre |
Update to the latest pre-release (alpha/beta) | gray update --pre |
gray install <version> |
Install a specific version by semver | gray install x.y.z |
gray version |
Show version info | gray version |
gray man |
Show help for the man command | gray man |
gray man <module> |
Show info about a stdlib module | gray man strings |
gray man <function> |
Show info about a stdlib function | gray man to_upper |
gray man <struct> |
Show info about a stdlib struct type | gray man HttpRequest |
gray cross build <file> --target <target> |
Cross-compile for another platform via Zig | gray cross build main.gray --target linux-amd64 |
gray cross targets |
List supported cross-compilation targets | gray cross targets |
Note: Zig is only required for cross-compilation (
gray cross). Native builds use the system C compiler.
gray update # latest stable
gray update --pre # latest pre-release Note: The latest pre-release may be very out of date
gray install x.y.z # pin to an exact versiongray update checks for new versions, shows the changelog, and upgrades both the gray CLI and the compiler. Pass --pre to pick up the latest alpha, beta, or rc. Use gray install <version> to install an exact version by semver — downgrades and pre-release tags (e.g. 0.2.0-beta.1) are supported.
Grayscale was previously known as EZ. The ez update command from older EZ versions cannot upgrade to Grayscale automatically. To migrate, uninstall EZ and do a fresh install of Grayscale using the instructions in the Install section above.
- Language standard
- Contributing guide
- Benchmark suite —
make benchmarktimes real-shaped programs
Grayscale is in active development. The language is usable for personal projects and dev tools. Breaking changes may occur frequently.
MIT License - Copyright (c) 2025-Present Marshall A Burns
See LICENSE for details.
Thank you to everyone who has contributed to Grayscale!



























