A fast, simple programming language inspired by Python and Go — clean syntax, goroutine-based concurrency, and garbage collection.
_____ _
|_ _(_)_ __ ___ ___ _ __ __ _ ___ ___
| | | | '_ ' _ \ / _ \ '_ \ / _' / __/ __|
| | | | | | | | | __/ |_) | (_| \__ \__ \
|_| |_|_| |_| |_|\___| .__/ \__,_|___/___/
|_|
File extension: .tp | Version: 0.1.0 | Built in: Go
# Run a file
timepass run hello.tp
# Start the REPL
timepass
# Check version
timepass --versionprintln("Hello, World!")
git clone https://github.com/timepass-lang/timepass
cd timepass
go build -o timepass ./cmd/timepass
# Add to PATH (Linux/macOS)
sudo mv timepass /usr/local/bin/
# Windows: move timepass.exe to a directory on your PATHlet x = 10 // immutable (like const)
var y = 20 // mutable
// Optional type annotations
let name: str = "Alice"
var count: int = 0
| Type | Example |
|---|---|
int |
42, -7 |
float |
3.14, -0.5 |
str |
"hello", 'world' |
bool |
true, false |
null |
null |
list |
[1, 2, 3] |
map |
{"key": "val"} |
// Basic
fun greet(name: str) -> str {
return "Hello, " + name + "!"
}
// Anonymous / lambda
let double = fun(x) { return x * 2 }
// Closures
fun make_counter() {
var n = 0
return fun() {
n += 1
return n
}
}
let c = make_counter()
println(c()) // 1
println(c()) // 2
// if / elif / else
if score >= 90 {
println("A")
} elif score >= 80 {
println("B")
} else {
println("C")
}
// for-in loop
for i in range(5) {
print(str(i) + " ")
}
// iterate a list
for item in ["a", "b", "c"] {
println(item)
}
// while loop
var x = 10
while x > 0 {
x -= 1
}
// break / continue
for i in range(10) {
if i == 3 { continue }
if i == 7 { break }
print(str(i) + " ")
}
range(5) // [0, 1, 2, 3, 4]
range(2, 8) // [2, 3, 4, 5, 6, 7]
range(0, 10, 2) // [0, 2, 4, 6, 8]
// Also works with .. syntax in for loops
for i in 1..6 { // 1, 2, 3, 4, 5
print(str(i) + " ")
}
var nums = [1, 2, 3, 4, 5]
nums[0] // 1
nums[-1] // 5 (negative indexing)
len(nums) // 5
append(nums, 6) // [1, 2, 3, 4, 5, 6]
pop(nums) // removes and returns 6
sort(nums) // sorted copy
reverse(nums) // reversed copy
slice(nums, 1, 3) // [2, 3]
var person = {"name": "Alice", "age": 30}
person["name"] // "Alice"
person["city"] = "NYC" // add/update
has(person, "age") // true
delete(person, "age") // remove key
keys(person) // ["name", "city"]
values(person) // ["Alice", "NYC"]
struct Point {
x: int,
y: int
}
struct Person {
name: str,
age: int
}
let p = Point{x: 3, y: 4}
println(p.x) // 3
// Mutate fields
var counter = Point{x: 0, y: 0}
counter.x = 10
Inspired by Go's concurrency model — lightweight goroutines communicate via channels.
// Create a channel
let ch = chan()
// Launch a goroutine
go {
var sum = 0
for i in range(100) {
sum += i
}
ch <- sum // send to channel
}
let result = <-ch // receive from channel
println(result) // 4950
// Fan-out: multiple goroutines writing to one channel
let results = chan()
for i in range(5) {
go {
results <- i * i
}
}
var total = 0
var got = 0
while got < 5 {
total += <-results
got += 1
}
println("Sum of squares: " + str(total))
let s = "Hello, World!"
len(s) // 13
upper(s) // "HELLO, WORLD!"
lower(s) // "hello, world!"
trim(" hi ") // "hi"
split("a,b,c", ",") // ["a", "b", "c"]
join(["a","b","c"], "-") // "a-b-c"
replace(s, "World", "tp") // "Hello, tp!"
contains(s, "World") // true
startswith(s, "Hello") // true
endswith(s, "!") // true
// Method syntax also works
s.upper()
s.lower()
s.split(",")
s.contains("World")
abs(-5) // 5
max(3, 7) // 7
min(3, 7) // 3
sqrt(16.0) // 4
pow(2, 10) // 1024
floor(3.7) // 3
ceil(3.2) // 4
round(3.5) // 4
rand() // random float 0..1
rand(100) // random int 0..99
int("42") // 42
float("3.14") // 3.14
str(100) // "100"
bool(0) // false
bool("hello") // true
type(42) // "int"
type([]) // "list"
| Function | Description |
|---|---|
print(...) |
Print without newline |
println(...) |
Print with newline |
input(prompt) |
Read line from stdin |
len(x) |
Length of str/list/map |
range(n) / range(start, end) |
Generate integer list |
append(list, val) |
Append to list (mutates) |
pop(list) / pop(list, i) |
Remove last or index i |
sort(list) |
Return sorted copy |
reverse(list|str) |
Return reversed copy |
slice(list, start, end) |
Sub-list |
keys(map) |
Map keys as list |
values(map) |
Map values as list |
has(map, key) |
Check key existence |
delete(map, key) |
Remove key |
split(str, sep) |
Split string |
join(list, sep) |
Join list to string |
upper(str) / lower(str) |
Case conversion |
trim(str) |
Strip whitespace |
contains(str|list, val) |
Membership test |
replace(str, old, new) |
String replace |
int(x) / float(x) / str(x) |
Type conversion |
type(x) |
Get type name |
abs(n) / sqrt(n) / pow(b,e) |
Math |
max(...) / min(...) |
Max/min |
floor(n) / ceil(n) / round(n) |
Rounding |
rand() / rand(n) |
Random numbers |
format(fmt, ...) |
Printf-style formatting |
assert(cond, msg) |
Assertion |
panic(msg) |
Raise error |
exit(code) |
Exit program |
now() |
Unix time in ms |
sleep(ms) |
Sleep milliseconds |
See the examples/ directory:
| File | Description |
|---|---|
| hello.tp | Hello World |
| fibonacci.tp | Recursive, iterative, memoized Fibonacci |
| structs.tp | Structs and instances |
| closures.tp | Closures, HOFs, currying, memoize |
| concurrent.tp | Goroutines and channels |
| algorithms.tp | Sorting, searching, primes, string algorithms |
| Python | timepass | |
|---|---|---|
| Concurrency | Crippled by the GIL — only one thread runs at a time | Real goroutines — thousands run truly in parallel |
| Startup time | ~100ms (imports, bytecode) | <5ms — just runs |
| Syntax noise | def, self, __init__, decorators... |
fun, done. No boilerplate |
| Mutability | Everything is mutable, accidents happen | let vs var — intent is explicit |
| Distribution | "Did you install the right Python version?" | Single binary — copy and run |
| JavaScript | timepass | |
|---|---|---|
null vs undefined |
Two kinds of nothing, endless undefined is not a function |
One null, consistent behaviour |
== vs === |
[] == false is true. Yes, really. |
== always does what you expect |
| Async model | Callback hell → Promise chains → async/await | go { } — just works, no await keyword noise |
| Type coercion | "5" + 3 = "53", "5" - 3 = 2 |
No silent coercion. Ever. |
| Packaging | node_modules (150MB for hello world) |
Zero dependencies |
| Go | timepass | |
|---|---|---|
| Error handling | if err != nil on every line |
Errors as values, no ceremony |
| Syntax | var x int = 5, := vs = confusion |
let x = 5 — one way, obvious |
| Scripting | Requires package main, func main(), compile step |
Just write code and run it |
| Dynamic typing | Strictly typed (verbose for scripts) | Inferred, flexible for fast prototyping |
| Learning curve | Steep for newcomers | Python-like readability from day one |
| Rust | timepass | |
|---|---|---|
| Memory model | Borrow checker — powerful but takes weeks to learn | GC handles it — just write logic |
| Compile time | 30s+ for large projects | Interpreted — instant feedback |
| Syntax | Lifetimes, &mut, Box<T>, Arc<Mutex<T>> |
No lifetime annotations, ever |
| Use case | Systems, OS, embedded | Scripting, tools, automation, learning |
Write it like Python. Run it like Go.
- Simple enough to learn in an afternoon
- Powerful enough for real concurrent programs
- Fast enough to not get in your way
- Small enough to fit in one binary you can send to anyone
timepass doesn't try to be the fastest language or the most type-safe language. It tries to be the language where you spend time on your problem, not on the language.
That's the whole point. It's timepass — but for your boilerplate, not your ideas.
- Fast compilation, excellent concurrency primitives
- Cross-platform binaries with zero dependencies
- Simple to ship: just one executable
The interpreter walks the AST directly (no bytecode compilation). This gives:
- Simple, debuggable implementation
- Fast startup time
- Good enough performance for scripting workloads
Future: a bytecode VM pass would give ~10-100x speedup for compute-heavy code.
timepass leverages Go's garbage collector. All timepass objects are Go heap objects managed by Go's concurrent tri-color mark-and-sweep GC. This gives:
- Automatic memory management
- No manual
free()needed - Concurrent GC with minimal stop-the-world pauses
The go { ... } syntax spawns a real Go goroutine. Channels are Go chan objects:
- M:N scheduling: many goroutines → few OS threads
- ~2KB per goroutine vs ~1MB per OS thread
- Channel-based message passing (no shared memory races)
Source code
↓ Lexer (pkg/lexer)
Token stream
↓ Parser (pkg/parser)
AST (Abstract Syntax Tree)
↓ Interpreter (pkg/interpreter)
Result
timepass-programming-language/
├── cmd/timepass/main.go # Entry point: REPL + file runner
├── pkg/
│ ├── lexer/
│ │ ├── token.go # Token types and keywords
│ │ └── lexer.go # Tokenizer
│ ├── parser/
│ │ ├── ast.go # AST node types
│ │ └── parser.go # Recursive descent parser
│ └── interpreter/
│ ├── object.go # Runtime value types
│ ├── environment.go # Variable scopes (lexical)
│ ├── builtins.go # Built-in functions
│ └── interpreter.go # Tree-walking evaluator
├── examples/ # Example .tp programs
├── docs/ # Language spec (WIP)
└── go.mod
- Bytecode VM for better performance
- Module system (
import "mymodule") - Error handling (
try/catchor Result type) - Standard library (file I/O, HTTP, JSON)
- Type checker / static analysis
- String interpolation (
"Hello {name}") - Pattern matching
- Integer ranges as first-class iterables
- Variadic functions
-
deferstatement (like Go)
MIT