⚠️ Alpha Status: Quadrate is under active development. APIs may change, and some features are incomplete. Not recommended for production use yet.
Canonical repository: https://git.sr.ht/~klahr/quadrate Issues and patches welcome on both SourceHut and GitHub.
A modern stack-based language that compiles to native code.
Quadrate combines the elegance of Forth's stack-oriented programming with contemporary features like static typing, modules, and LLVM-powered native compilation. Whether you need a standalone systems language or an embedded scripting engine, Quadrate compiles to native machine code.
Documentation: https://quad.r8.rs
🚀 Native Compilation Compiles directly to native machine code via LLVM. No VM overhead, no garbage collection pauses—predictable execution with LLVM optimizations.
⚡ Dual-Mode Operation
- Standalone: Compile
.qdfiles to executables like C/C++ - Embedded: JIT-compile scripts at runtime in your C/C++ applications
📦 Zero-Dependency Binaries Statically linked executables with no runtime dependencies. Ship a single binary that runs anywhere.
🔧 Systems Programming Direct memory access, pointer manipulation, and FFI with C libraries. Build anything from CLI tools to game engines.
🎯 Explicit and Predictable Stack-based semantics make data flow obvious. No hidden allocations, no implicit conversions—you control everything.
git clone https://git.sr.ht/~klahr/quadrate
cd quadrate
make release && sudo make installBuild Requirements:
- Meson build system
- C11 and C++20 compiler (GCC or Clang)
- LLVM ≥14.0 (for JIT/embedding features only)
All other dependencies are automatically downloaded and built as subprojects.
Create hello.qd:
fn main() {
"Hello, World!" print nl
}Compile and run:
quadc -r hello.qdThat's it! The -r flag compiles and immediately runs your program.
Values live on an explicit stack. Functions manipulate the stack directly:
fn main() {
5 3 + // Stack: [5] [3] → [8]
print nl // Print 8 and newline
}Functions declare their stack effects using type signatures:
use math
fn square(x:f64 -- result:f64) {
math::sq
}
fn distance(x1:f64 y1:f64 x2:f64 y2:f64 -- dist:f64) {
// (x2-x1)² + (y2-y1)²
swap rot - math::sq // Calculate (x2-x1)²
rot rot - math::sq // Calculate (y2-y1)²
+ math::sqrt // Add and take square root
}
fn main() {
7.0 square print nl // 49.0
0.0 0.0 3.0 4.0 distance print nl // 5.0
}The signature (x:f64 y:f64 -- result:f64) means: "Consumes two f64 values from the stack, produces one f64 result."
| Operation | Effect | Description |
|---|---|---|
dup |
(a -- a a) |
Duplicate top value |
drop |
(a -- ) |
Discard top value |
swap |
(a b -- b a) |
Swap top two values |
over |
(a b -- a b a) |
Copy second value to top |
rot |
(a b c -- b c a) |
Rotate top three values |
fn main() {
// Conditionals
10 5 > if {
"10 is greater" print nl
} else {
"5 is greater" print nl
}
// For loops (start end step)
0 10 1 for i {
i print nl // i is the loop counter
}
// While loops
0
loop {
dup print nl
inc
dup 10 >= if { break }
}
drop
// Pattern matching
42 switch {
0 { "zero" print nl }
42 { "answer" print nl }
_ { "other" print nl }
}
}use math
use fmt
fn hypotenuse(a:f64 b:f64 -- c:f64) {
math::sq swap math::sq + math::sqrt
}
fn main() {
3.0 4.0 hypotenuse
"Hypotenuse: %f\n" fmt::printf
}Quadrate includes batteries for common tasks:
| Module | Purpose | Key Functions |
|---|---|---|
| fmt | Formatted I/O | printf, sprintf, scanf |
| io | File operations | open, read, write, close, read_file |
| mem | Memory management | alloc, free, copy, zero, get_byte, set_byte |
| str | String manipulation | concat, split, substr, replace, len |
| math | Math and linear algebra | sin, cos, sqrt, Vec2, Vec3, Mat4, Quat |
| bits | Bit manipulation | and, or, xor, lshift, rshift |
| limits | Integer limits | MaxInt, MinInt, MaxUint |
| Module | Purpose | Key Functions |
|---|---|---|
| os | System interface | env, exec, getpid, getcwd, exit |
| time | Time & sleep | now, sleep, Second, Millisecond |
| thread | Threading | spawn, join, detach, Mutex, Channel, WaitGroup |
| signal | Signal handling | trap, pending, clear, SigInt, SigTerm |
| Module | Purpose | Key Functions |
|---|---|---|
| rand | Random numbers | new, int, range, bool, with_seed |
| path | File path manipulation | dirname, basename, ext, join, is_absolute |
| sb | String builder | new, append, append_char, build, clear |
| bytes | Byte arrays | new, get, set, len, to_str |
| strconv | String conversion | itoa, atoi, ftoa, atof |
| unicode | Unicode support | is_letter, is_digit, to_upper, to_lower |
| flag | CLI argument parsing | string, int, bool, parse |
| testing | Unit testing | assert_eq, assert_ne, assert_true, fail |
These modules are available as separate packages via quadpm:
| Module | Purpose | Repository |
|---|---|---|
| base64 | Base64 encoding | quadrate-language/base64 |
| compress | Compression | quadrate-language/compress |
| crypto | SHA-256, CRC32, etc. | quadrate-language/crypto |
| ct | Compile-time execution | quadrate-language/ct |
| hex | Hex encoding | quadrate-language/hex |
| hof | Higher-order functions | quadrate-language/hof |
| http | HTTP client/server | quadrate-language/http |
| json | JSON parsing | quadrate-language/json |
| log | Logging | quadrate-language/log |
| net | TCP networking | quadrate-language/net |
| regex | Regular expressions | quadrate-language/regex |
| sort | Array sorting | quadrate-language/sort |
| sqlite | SQLite database | quadrate-language/sqlite |
| tls | TLS/SSL | quadrate-language/tls |
| uri | URI parsing/building | quadrate-language/uri |
| uuid | UUID generation | quadrate-language/uuid |
Example with formatted output:
use fmt
use time
fn main() {
time::now "Current time: %d\n" fmt::printf
}use uuid
use rand
fn main() {
// Generate random UUID
uuid::v4 print nl
// Random number generation
rand::new -> rng
rng 1 100 rand::range -> rng -> n
"Random 1-100: " print n print nl
}use path
fn main() {
"/home/user/docs/report.pdf" -> p
p path::dirname print nl // /home/user/docs
p path::basename print nl // report.pdf
p path::ext print nl // .pdf
}Quadrate's JIT engine lets you embed scripting in your applications. Scripts compile to native code at runtime via LLVM—no interpreter overhead.
#include <qd/qd.h>
int main() {
// Create runtime context
qd_context* ctx = qd_create_context(1024);
// Create module and add Quadrate code
qd_module* math = qd_get_module(ctx, "math");
qd_add_script(math, "fn double(x:i64 -- result:i64) { 2 * }");
// JIT compile to native code
qd_build(math);
// Execute (pushes 5, calls double, prints 10)
qd_execute(ctx, "5 math::double print nl");
qd_free_context(ctx);
return 0;
}Expose C/C++ functions to Quadrate scripts:
#include <qd/qd.h>
#include <time.h>
// Native function callable from Quadrate
qd_exec_result get_timestamp(qd_context* ctx) {
time_t now = time(nullptr);
return qd_push_i(ctx, static_cast<int64_t>(now));
}
int main() {
qd_context* ctx = qd_create_context(1024);
qd_module* utils = qd_get_module(ctx, "utils");
// Register C function
qd_register_function(utils, "get_timestamp", reinterpret_cast<void(*)()>(get_timestamp));
qd_build(utils);
// Call native Quadrate function, and print the result
qd_execute(ctx, "utils::get_timestamp print nl");
qd_free_context(ctx);
return 0;
}# Compile and link
clang++ myapp.cc -o myapp -lqd -lqdrt
# Run
./myappKey Features:
- JIT Compilation: Scripts compile to native code via LLVM
- Multiple Modules: Organize code, load modules dynamically
- Two-Way FFI: Call C from Quadrate and vice versa
- Incremental Building: Add scripts over time, compile once
- Zero-Copy Stack Access: Direct manipulation via low-level API
See examples/embed/ for complete working examples.
Experiment with Quadrate interactively:
$ quad repl
# or: quadrepl
[]> 5 3
[5 3]> +
[8]> dup
[8 8]> *
[64]> print
64
[]>REPL Commands:
clear- Clear the stackCtrl-D- Exit REPL
Keep your code consistent:
quad fmt myfile.qdquadfmt myfile.qd # Preview formatting
quadfmt -w myfile.qd # Format in placeIDE integration via LSP:
quadlspSupports:
- Syntax highlighting
- Auto-completion
- Go-to-definition
- Real-time diagnostics
- Function signature hints
| Tool | Purpose |
|---|---|
| quad | Unified CLI (quad build, quad run, quad test, quad fmt, etc.) |
| quadc | Compiler (-r run, -o output, -g debug info, --save-temps keep intermediate files) |
| quadfmt | Code formatter with consistent style |
| quadlint | Static analyzer for common issues |
| quadlsp | Language server for IDE integration |
| quadrepl | Interactive REPL for quick experimentation |
| quaduses | Analyze module dependencies and function usage |
| quadpm | Package manager for installing and managing libraries |
# Clone repository
git clone https://git.sr.ht/~klahr/quadrate
cd quadrate
# Debug build (default)
make
# Release build (optimized)
make release
# Run test suite
make tests
# Run tests with valgrind (memory leak detection)
make valgrind
# Build example programs
make examples
# Format source code
make format
# Install
make install
# Uninstall
make uninstall
# Clean build artifacts
make clean# Custom build with Meson directly
meson setup build --buildtype=release -Dbuild_tests=true
meson compile -C build
meson test -C build --print-errorlogsQuadrate generates full DWARF debug information:
# Compile with debug symbols
quad build -g -o myprogram myprogram.qd
# Debug with GDB
gdb ./myprogramInside GDB:
(gdb) break main # Break in main function
(gdb) break myfile.qd:42 # Break at line 42 in source
(gdb) run
(gdb) print ctx->st->size # Inspect stack size
(gdb) print ctx->st->data[0] # Examine stack valuesDebug Features:
- Source-level debugging (step through
.qdfiles line-by-line) - Breakpoints on functions and line numbers
- Stack inspection via
ctxvariable - Full integration with GDB, LLDB, and IDE debuggers
Quadrate includes a built-in test framework for writing and running unit tests.
Use the test keyword to define test blocks, and assertion functions from the testing module:
use testing
test "basic arithmetic" {
2 3 + 5 testing::assert_eq
10 5 - 5 testing::assert_eq
}
test "string comparison" {
"hello" "hello" testing::assert_eq
"foo" "bar" testing::assert_ne
}
test "boolean checks" {
1 testing::assert_true
0 testing::assert_false
"non-empty" testing::assert_true
"" testing::assert_false
}| Function | Description |
|---|---|
testing::assert_eq |
Assert two values are equal (works with any type) |
testing::assert_ne |
Assert two values are not equal |
testing::assert_true |
Assert value is truthy (non-zero, non-empty) |
testing::assert_false |
Assert value is falsy (zero, empty, null) |
testing::fail |
Unconditionally fail with a message |
All assertions are polymorphic—they work with integers, floats, strings, and pointers.
# Compile and run tests
quad test myfile_test.qdRunning 3 tests...
✓ basic_arithmetic
✓ string_comparison
✗ intentional_failure
2 passed, 1 failed
Tests return exit code 0 if all pass, 1 if any fail—making them suitable for CI pipelines.
When an assertion fails, it prints detailed information:
Assertion failed: assert_eq
expected: 5 (i64)
got: 10 (i64)
Stack trace:
0: myfile.qd::test(basic arithmetic)
use io
use mem
use fmt
fn process_file(filename:str -- ) {
// Open file for reading
io::Read io::open! -> file
// Allocate buffer for reading
1024 mem::alloc! -> buffer
// Read and process data
file buffer 1024 io::read! -> bytes_read
bytes_read "Read %d bytes\n" fmt::printf
// Cleanup
buffer mem::free
file io::close!
}
fn main() {
"input.txt" process_file
}use time
fn update() {
// Update game state
}
fn render() {
// Render frame
}
fn main() {
time::Millisecond 16 * -> frame_time // 60 FPS = 16.67ms
loop {
time::now -> start_time
update
render
time::now start_time - -> elapsed
frame_time elapsed > if {
frame_time elapsed - time::sleep
}
}
}Tested:
- Linux x86_64 (Arch Linux, Debian, Haiku)
Potentially Compatible:
- Linux aarch64, FreeBSD, other Unix-like systems
Contributions for testing on other platforms are welcome.
Compiler Requirements:
- C11 and C++20 compiler (GCC 10+ or Clang 10+)
- LLVM 14+
We enthusiastically welcome contributions!
Report bugs and request features: SourceHut: https://todo.sr.ht/~klahr/quadrate GitHub: https://github.com/quadrate-lang/quadrate/issues
Email patches to: ~klahr/quadrate@lists.sr.ht
New to sourcehut's email workflow? See: https://man.sr.ht/git.sr.ht/send-email.md
Or use GitHub: Submit pull requests if you prefer
git clone https://git.sr.ht/~klahr/quadrate
cd quadrate
make # Build debug version
make tests # Run test suite
make format # Format code before committingGNU General Public License v3.0
Quadrate is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
See LICENSE for full terms.
Portions of this codebase were initially drafted with AI assistance and subsequently reviewed, modified, and maintained by humans. All code meets the same quality standards regardless of origin.
~klahr — https://sr.ht/~klahr
- Documentation: https://quad.r8.rs
- Repository: https://git.sr.ht/~klahr/quadrate
- Issue Tracker: https://todo.sr.ht/~klahr/quadrate
- Mailing List: ~klahr/quadrate@lists.sr.ht