theawakener0/Zod(opens in a new tab)
Language: Go
An interpreter programming language built in Go
- stars
- 4
- watchers
- 0
- forks
- 0
- open issues
- 0
- Last updated
- 10/30/2026
Language: Go
An interpreter programming language built in Go
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.
Prebuilt binaries for Linux, macOS, and Windows are attached to every GitHub Release.
curl -fsSL https://raw.githubusercontent.com/theawakener0/Zod/main/install.sh | shgo 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.
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.Users who maintain their own copy of the stdlib should set $ZOD_STDLIB; it takes priority over every other source.
nullif / elseif / else control flowfor loops, and infinite loopbreak and continuetry(expr) for recoverable errorsstdlib/ (std/fmt, std/str, std/array, …) via import "std/fmt" as fmtstd/... imports resolve automatically without a stdlib/ directoryprintln(), printf(), input(), etc.), arrays, and hashes (kept for compat)# if you installed manually run this go build -o zod .
Note
v0.8.0 removed the legacy tree-walking evaluator and the --eng=eval flag. The VM is now the only engine. --eng=vm is still accepted for compatibility, but the default command runs the VM.
# 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.
# if you installed using the script zod file.zd # if you installed using go install Zod file.zd
println("Hello, World!")
More runnable examples live in examples/.
| 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 |
| Category | Operators |
|---|---|
| Arithmetic | + - * / % |
| Comparison | == != < > <= >= |
| Logical | && || ! |
| Increment | ++ -- (prefix and postfix) |
| 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.
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.
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 |
__* names (about 50 intrinsics such as __print, __str_split, __read_file) are private implementation details backing std/*. Do not call them directly.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").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 the VM supports).array.push vs push) on the VM. 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.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.
Inspired by Thorsten Ball's Writing an Interpreter in Go and Writing a Compiler in Go.
MIT License. See LICENSE.