A concise, safe, and readable scripting language built with Rust.
Lingot is designed to be easy to learn for non-programmers while remaining powerful for experienced developers. It features type inference, string interpolation, built-in file operations, shell interop, and a minimal keyword set — all compiled to a fast native binary.
- Minimal syntax — 26 reserved keywords, semicolons optional,
//comments - Type inference — types are inferred at initialization and locked (optional annotations)
- Immutable by default —
letis immutable,let dynenables reassignment - String interpolation —
"Hello {name}, you are {age}" - Built-in file operations —
read(),write().to(),move().to(),delete(),list() - Shell interop —
shell("git status")executes system commands - Error handling —
try/catch+failwith automatic propagation - Functions — first-class, generic via monomorphisation
- REPL — interactive mode for quick experiments
- Fast — ~1 MB native binary, instant startup
cargo install lingotgit clone https://github.com/theoctano/lingot.git
cd lingot
cargo build --release
cp target/release/lingot /usr/local/bin/Create hello.ling:
let name = "World"
display("Hello {name}!")
let numbers = [1, 2, 3, 4, 5]
repeat {
display("{n} squared = {n * n}")
} for (n in numbers)
Run it:
lingot run hello.linglet name = "Alice" // immutable, type inferred as Text
let dyn counter = 0 // mutable, type inferred as Number
counter = counter + 1 // ok
counter = "hello" // error: type locked to Number
let greet (who) {
return "Hello {who}!"
}
display(greet("World")) // Hello World!
display(greet(42)) // Hello 42!
if (score > 100) {
display("High score!")
} else {
display("Keep trying")
}
while (x > 0) {
x = x - 1
}
repeat {
display(i)
} for (i in 1..10)
repeat {
display(item)
} for (item in items)
let divide (a, b) {
if (b == 0) {
fail "Division by zero"
}
return a / b
}
try {
let result = divide(10, 0)
display(result)
} catch (error) {
display("Error: {error}")
}
try {
let status = shell("git status")
display(status)
} catch (error) {
display("Command failed: {error}")
}
write("Hello from Lingot!").to("output.txt")
let content = read("output.txt")
display(content)
move("output.txt").to("archive/output.txt")
rename("archive/output.txt").to("backup.txt")
delete("archive/backup.txt")
let files = list(".")
display(files)
| Function | Description |
|---|---|
display(value) |
Print a value to stdout |
shell(command) |
Execute a system command, return stdout |
read(path) |
Read a file, return its content as Text |
write(content).to(path) |
Write content to a file |
move(source).to(dest) |
Move a file |
rename(path).to(name) |
Rename a file |
delete(path) |
Delete a file or directory |
list(path) |
List directory contents |
prefix(path).with(text) |
Add a prefix to a filename |
suffix(path).with(text) |
Add a suffix to a filename |
Lingot supports both symbolic and keyword-based operators:
| Symbolic | Keyword | Description |
|---|---|---|
&& |
and |
Logical AND |
|| |
or |
Logical OR |
! |
not |
Logical NOT |
== |
is |
Equality |
!= |
is not |
Inequality |
> |
greater than |
Greater than |
< |
lesser than |
Less than |
| Type | Example |
|---|---|
Text |
"hello" |
Number |
42, 3.14 |
Bool |
true, false |
List |
[1, 2, 3] |
Void |
implicit return of functions without return |
Numbers unify integers and floats. Integer division stays integer (7 / 2 = 3), float involvement produces floats (7.0 / 2 = 3.5). Division by zero is always a fail.
Lingot is a scripting language. The shell() function executes arbitrary system commands. Only run .ling scripts you trust, the same way you would with bash or Python scripts.
File operations (read, write, move, delete) use Rust's standard library directly with no shell intermediary.
lingot run <file.ling> # Run a script
lingot repl # Start the interactive REPL
lingot --version # Show version
lingot --help # Show helpMIT