Zod Programming Language
Zod is a small (let's say it's a medium sized), interpreted, dynamically typed with a first-class functions, closures, arrays, hashes, and more.
Install
Prebuilt binaries for Linux, macOS, and Windows are attached to every GitHub Release.
Option 1: Download script
curl -fsSL https://raw.githubusercontent.com/theawakener0/Zod/main/install.sh | sh
Option 2: go install
go install github.com/theawakener0/Zod@latest
Requires Go 1.27 or newer and installs the Zod executable into your Go bin directory.
[!TIP]
The standard library is embedded in the binary, so a plain go install works out of the box — no separate stdlib/ directory is needed.
Standard library lookup
import "std/..." resolves modules in this order:
$ZOD_STDLIB environment variable (explicit override — wins).
stdlib/ next to the zod executable (GitHub release tarballs ship this).
stdlib/ in the current working directory.
stdlib/ in up to 5 parent directories of the working directory/script.
- The standard library embedded in the binary.
Users who maintain their own copy of the stdlib should set $ZOD_STDLIB; it takes priority over every other source.
Demo
Conway's Game of Life

Features
- First-class functions and closures
- Data types: integers, floats, booleans, strings, arrays, hashes, matrices, and
null
if / elseif / else control flow
- C-style
for loops, and infinite loop
break and continue
try(expr) for recoverable errors
- Standard library in
stdlib/ (std/fmt, std/str, std/array, …) via import "std/fmt" as fmt
- The standard library is also embedded in the binary, so
std/... imports resolve automatically without a stdlib/ directory
- Legacy core built-ins for I/O (
println(), printf(), input(), etc.), arrays, and hashes (kept for compat)
- An interactive REPL
Getting Started
Prerequisites
Build
# if you installed manually run this
go build -o zod .
[!NOTE]
ZodLang now has a new engine, the VM, which is faster and more powerful. You can run the old engine with --eng=eval.
Run the REPL
# if you installed using the script
zod
# if you installed using go install
Zod
Inside the REPL, type /clear to clear the screen and /exit to quit.
Run a script
# if you installed using the script
zod file.zd
# if you installed using the script and want to run the eval engine
zod --eng=eval file.zd
# if you installed using go install
Zod file.zd
# if you installed using go install and want to run the eval engine
Zod --eng=eval file.zd
Examples
Hello, World!
println("Hello, World!")
More runnable examples live in examples/.
Language Reference
Data types
| Type |
Example |
| Integer |
42, -7, 0 |
| Float |
3.14, -0.5, 20.0 |
| Boolean |
true, false |
| String |
"Hello, World!" |
| Array |
[1, 2, 3], [] |
| Hash |
{"name": "Zod"}, {} |
| Matrix |
matrix(2, 2, [1, 2, 3, 4]) |
| Bytes |
__bytes("hi") (private intrinsic; use std/*) |
| Error |
error("boom") |
| Null |
null |
Operators
| Category |
Operators |
| Arithmetic |
+ - * / % |
| Comparison |
== != < > <= >= |
| Logical |
&& || ! |
| Increment |
++ -- (prefix and postfix) |
Assignment
| Operator |
Meaning |
let |
Declare a new variable: let x = 5 |
:= |
Assign (declares if needed): x := 5 |
+= -= *= /= %= |
Compound assignment: x %= 2 |
Index assignment works on arrays and hashes too: nums[0] = 10, user["age"] += 1.
Modules
Bindings are private by default. Prefix a top-level let or := with pub to export it.
// pub_lib.zd
pub let version = 1
let secret = "hidden"
pub greet := fn(name) { "hello, " + name }
from "examples/pub_lib.zd" import * // all public bindings
from "examples/pub_lib.zd" import greet // listed public bindings only
import "examples/pub_lib.zd" as m // property access: m.version, m.greet("hi")
Importing or accessing a private binding is an error (e.g. secret is private). See docs/introduction.md (Modules & pub) and examples/modules_pub.zd for details.
Standard Library (preferred)
New code should use the standard library in stdlib/ (25 modules) instead of the legacy core built-ins below. Each module is imported by path with an alias:
import "std/fmt" as fmt
fmt.println("Hello, World!")
| Module |
Import example |
Key exports |
fmt |
import "std/fmt" as fmt |
print, println, eprint, printf, sprintf |
str |
import "std/str" as str |
split, join, slice, trim, upper, lower, replace, index_of, starts_with, ends_with, repeat, pad_left, pad_right, contains, to_int, to_float, is_empty, has_prefix, has_suffix |
array |
import "std/array" as array |
first, last, push, pop, pop_last, map, filter, find, any, all, reverse, flatten, join, sort, slice, range, make, zip, contains |
hash |
import "std/hash" as hash |
get, set, contains, has, del, keys, vals, merge, remove, from_pairs |
math |
import "std/math" as math |
pi, e, tau, abs, min, max, clamp, floor, ceil, round, exp, log, sqrt, pow, sin, cos, tan |
matrix |
import "std/matrix" as matrix |
new, eye, zeros, ones, rows, row, get, transpose, mul, det2, det3, det, inv2, inv |
rand |
import "std/rand" as rand |
seed, float, int, range, choice, shuffle |
time |
import "std/time" as time |
sleep, now_ms, now_s, elapsed_note |
os |
import "std/os" as os |
args, env_get, env_set, env_list, exit, cwd |
- The
__* names (about 50 intrinsics such as __print, __str_split, __read_file) are private implementation details backing std/*. Do not call them directly.
- New types:
Bytes (type(x) returns "BYTES") and Error values (type(error("x")) returns "ERROR"). New globals are error(msg) (creates an error value) and is_error(x) (tests for one); string() also formats Array, Hash, Matrix, Bytes, null, and Error (string(error("x")) returns "Error: x").
- Capture errors with
try(): let r = try(error("x")) returns [false, "x"]. A bare let e = error("x") halts evaluation by design, so always wrap error-producing expressions in try() (or nest them, e.g. string(error("x")), which works on both engines).
- An imported name shadows a same-named core built-in (e.g.
array.push vs push) on both engines. Several modules export the same name (join in str/array/path, contains in str/array/hash), so always import with an alias and call through it.
std/ lookup order and runnable examples are documented in docs.
Legacy core (kept for compat)
The original 24 built-ins below still work, but new code should use std/* instead.
| Function |
Description |
len(x) |
Length of a string, array, hash, or matrix |
println(...) |
Print each argument on its own line |
printf(fmt, ...) |
Formatted output (Go-style verbs) |
input(prompt) |
Read a line of input from the user |
int(x) |
Convert x to integer |
float(x) |
Convert x to float |
string(x) |
Convert x to string (also Array, Hash, Matrix, Bytes, null, Error → "Error: msg") |
type(x) |
Return the type name of x |
first(arr) |
First element of an array |
last(arr) |
Last element of an array |
push(arr, x) |
New array with x appended |
pop(arr) |
New array without its last element |
insert(hash, k, v) |
New hash with k: v added |
remove(hash, k) |
New hash without key k |
keys(hash) |
Array of keys in insertion order |
vals(hash) |
Array of values in insertion order |
contains(hash, k) |
Whether hash contains key k |
random(...) |
Random float in [0, 1); with one arg, in [0, x) |
matrix(r, c, data) |
Matrix with r rows and c cols from data |
make(size) / make(size, value) |
Create a new array with size elements, and value |
color(color, text) |
Change the color of text to color |
sleep(ms) |
Pause execution for ms milliseconds |
exp(x) |
e^x |
pi() |
π |
[!NOTE]
The color function is still under development so it doesn't have many colors.
for more details. Go to the docs.
Acknowledgments
Inspired by Thorsten Ball's Writing an Interpreter in Go and Writing a Compiler in Go.
License
MIT License. See LICENSE.