TulparLang is an open-source, statically-typed, ahead-of-time compiled
programming language built on LLVM 18. It pairs Python-shaped syntax
with native binary performance — within ~1.5–1.8× of gcc -O2 on
integer microbenchmarks (loopsum, fib(35)), and on a localhost
JSON-API micro-benchmark the listen_async Wings listener serves
~1.9× the throughput of Node.js' built-in http — and ships with a
batteries-included standard library so you can build a production
HTTP/HTTPS API without installing a single external dependency.
Files use the .tpr extension. The whole toolchain — compiler, runtime,
package manager, formatter, language server, and REST framework — is a
single ~7 MB executable. Source code, identifiers, and strings are
UTF-8 throughout, with first-class support for both Turkish and English
keywords and diagnostics.
Use it for: dependency-free native backend services, REST APIs and microservices, CLI tools, scripting and automation. The sweet spot is "Python-shaped ergonomics with a single-binary deploy and no runtime to install on the target machine" — if that matches your shape, the rest of the README is for you.
Highlights:
- Native HTTP/HTTPS server — four listener flavours (sync, thread-
per-connection, worker pool, single-thread event loop) plus a TLS
listener with OpenSSL, all in the bundled
wings/wings_tlsstdlib. - First-class JSON — built-in type, literal syntax, dot access,
toJson/fromJsonround-trips, no library import required. - AOT-compiled native binaries —
tulpar build foo.tprproduces a standalone executable you can ship without the Tulpar toolchain. - One-line installer with auto-update —
iwr ... | iexon Windows,curl ... | bashon Linux/macOS, thentulpar updateto roll forward.
Windows (PowerShell):
iwr -useb https://tulparlang.dev/install.ps1 | iexLinux / macOS:
curl -fsSL https://tulparlang.dev/install.sh | bashBoth scripts download the latest release, drop tulpar into a per-user
location (%LOCALAPPDATA%\Programs\Tulpar on Windows, ~/.local/bin
on Linux/macOS), and wire up PATH. No admin rights needed. Run
tulpar update later to upgrade in place.
Prefer the GUI? Download tulpar-setup-windows-x64.exe from the
latest release
— per-user install, Start Menu entry, Add/Remove Programs entry.
Every release ships with SHA256SUMS.txt (asset hashes) and
SHA256SUMS.txt.asc (a detached GPG signature over that manifest by
the TulparLang Release key). The install scripts already verify the
SHA-256 hashes; the GPG signature is an optional extra layer.
# Import the release-signing public key (one-time)
curl -fsSL https://raw.githubusercontent.com/hamer1818/TulparLang/main/release-public.asc \
| gpg --import
# Verify (download both files from the release page first)
gpg --verify SHA256SUMS.txt.asc SHA256SUMS.txt
sha256sum -c SHA256SUMS.txtPublic key fingerprint:
CE5C 22BD EA61 58BC 8221 3A7E 4396 41B3 0E8D FDEE
The key is ed25519, valid until 2028-05-09, used only for release
signing. If gpg --verify reports Good signature and the
fingerprint matches, the manifest came from the release workflow
unchanged.
Create hello.tpr:
str message = "Merhaba, dünya!";
print(message);
func square(int n): int {
return n * n;
}
print(square(5)); // 25
Run it:
tulpar hello.tprThe default tulpar <file> invocation AOT-compiles via LLVM and runs
the resulting native binary — Python-shaped syntax, native-binary
performance (see Performance for the actual numbers).
import "wings";
func home(req) {
return {"hello": "world", "ts": now_iso8601()};
}
get("/", home);
serve(8080);
tulpar build api.tpr && ./api
curl http://127.0.0.1:8080/
# {"hello":"world","ts":"2026-05-07T18:30:00Z"}model() creates the SQLite table, resource() wires five REST routes
plus request validation (422) and Swagger /docs — all queries run as
bound-parameter SQL:
import "wings";
import "orm";
database("notes.db");
json Note = model("notes", {"id": "pk", "title": "str!", "done": "bool"});
resource("/notes", Note); // GET/POST /notes, GET/PUT/DELETE /notes/:id
serve(); // :8484 + /docs
Custom endpoints live right next to it, with ActiveRecord-style calls:
Note.find(3), Note.where("done = ?", [0]), Note.create({...}),
Note.save(obj). See
examples/wings_orm_resource.tpr
and the full cheatsheet in WINGS_CHEATSHEET.md.
Need HTTPS? Swap serve(8080) for
wings_tls(8443, "server.crt", "server.key") and you're terminating
TLS via OpenSSL with the same handler API. Wings auto-registers
/healthz + /metrics and answers CORS preflights so a browser can
hit the API immediately.
Long-lived connections take over the socket and signal
{"_stream": 1} so wings skips its normal response envelope:
import "wings";
func events() {
int fd = wings_current_fd();
socket_send(fd, wings_sse_headers());
int i = 0;
while (i < 5) {
socket_send(fd, wings_sse_event("tick", "{\"n\":" + toString(i) + "}"));
sleep(300);
i = i + 1;
}
return {"_stream": 1};
}
get("/events", "events");
listen(8093);
curl -N http://127.0.0.1:8093/events will print 5 tick frames live.
WebSocket handlers use wings_ws_upgrade(req) for the handshake,
wings_ws_send_text(fd, payload) + wings_ws_recv_frame(fd) for the
frame loop, and the same {"_stream": 1} return value.
Vendored stdlib (wings, router, http_client, orm, …) is
embedded in the binary — no install step. Third-party packages flow
through tulpar pkg:
tulpar pkg init my-app # writes tulpar.toml + default registry URL
tulpar pkg search # browse the catalog (empty query = all)
tulpar pkg search wings # filter by name + description
tulpar pkg info demo # version list, downloads, install hint
tulpar pkg add demo@^1.0 # add a dependency line
tulpar pkg install # vendor everything into tulpar_modules/
tulpar pkg publish --token $T # publish current package to the registrytulpar pkg init seeds the canonical registry
(https://api.pkg.tulparlang.dev); override via the [registry] url
line in tulpar.toml, --registry <url> flag, or TULPAR_REGISTRY
env. Semver ranges are full 2.0.0 (^, ~, *, >=,<, pre-release
plus build metadata). Installs go through a lockfile (tulpar.lock)
with SHA-256 checksums so re-installs are byte-stable.
- Native speed. LLVM 18 AOT compilation. ~1.5–1.8× of
gcc -O2on integer microbenchmarks; on a localhost JSON-API microbenchmark thelisten_asyncWings listener is 1.91× Node.js'httpand 2.91× CPython'sThreadingHTTPServerin throughput. See benchmarks/RESULTS.md for the full table and methodology. - No build step for prototyping.
tulpar file.tprruns in one step.tulpar build file.tprproduces a standalone native binary when you want to ship. - Batteries included. Wings (HTTP server, four listener flavours + TLS), TulparAPI (FastAPI-style routing), ORM (SQLite), HTTP client, sockets, threads, regex, CSV, datetime, structured logging, OpenAPI generation — all in the default install. No package manager required for the standard library.
- First-class JSON.
jsonis a built-in type with literal syntax ({"k": v}), dot access (obj.key), andtoJson/fromJsonround-trips that survive Unicode, embedded quotes, deeply nested structures, and large arrays. - HTTPS out of the box. Statically linked OpenSSL on every
platform. Both client (
http_get("https://...")) and server (wings_tls(...)) work with no extra setup. - UTF-8 native. Source code, strings, identifiers, error messages
all UTF-8. Localised CLI follows the system locale; override with
TULPAR_LANG=trorTULPAR_LANG=en. - Single-binary toolchain. One
tulparexecutable bundles the AOT/LLVM compiler, package manager, formatter, language server, and self-updater. - Editor-aware. A real LSP server (
tulpar --lsp) drives the bundled VS Code extension with Rust-style diagnostics, hover types, completion, go-to-definition, find-references, rename, and signature help. - Cross-platform. Linux, macOS (Apple Silicon + Intel), Windows (MSYS2 MinGW build). WebAssembly target available for browser use.
Baked from local benchmark run (best of 5). Last run: 2026-05-21T08:23:24Z UTC · commit
d91f184· runnerWindows·developer machine(16 CPUs). Methodology + Local Run instructions: benchmarks/CI.md.
Scope. All numbers below are microbenchmarks — tight integer loops and small JSON handlers on a single machine, localhost loopback for HTTP. They isolate compiler / runtime / scheduler costs and let Tulpar be compared against C, Rust, Go, Node, etc. on the same shape of workload. They do not model real production traffic (cold starts, large payloads, distributed clients, p99 tail latency, GC pressure under load). Treat them as a peer-comparison floor for the hot path, not as a production projection.
10M-iteration sum and recursive fib(35). See
benchmarks/RESULTS.md for the raw numbers from
the most recent CI run and the optimization-pipeline writeup.
Wall time of the inner loop, best of 5 runs. Lower is faster.
| Workload | Tulpar AOT (LLVM) | C (gcc -O2) | Rust (-O3) | Go | Node.js | Python |
|---|---|---|---|---|---|---|
| loopsum (ms) | 59.2 | 25.4 | 24.4 | 33.6 | 48.3 | 554.8 |
| fib(35) (ms) | 82.6 | 37.7 | 48.0 | 73.6 | 109.4 | 945.7 |
| ackermann(3,8) (ms) | 59.3 | 24.1 | 27.9 | 33.9 | 50.5 | 261.2 |
| tak(18,12,6) (ms) | 56.9 | 22.4 | 24.3 | 29.6 | 42.7 | 26.6 |
| sieve(100K) (ms) | 62.1 | 24.8 | 24.4 | 30.2 | 43.4 | 34.2 |
| struct_sum (ms) | 57.5 | 24.8 | 24.9 | 36.0 | 67.9 | 1393.1 |
| struct_arr_push (ms) | 103.9 | 31.6 | 32.4 | 37.9 | 179.0 | 305.3 |
Tulpar AOT lands at 2.19×–3.29× of C (gcc -O2) on these microbenchmarks (i.e. C-comparable, with a small multiplicative gap), 0.7–1.7× faster than Node.js, and 0–24× faster than Python.
3000 GETs across 4 keep-alive connections, single localhost loop. Same JSON handler running on every server.
3 000 GETs over 4 keep-alive connections; single localhost run; each server hosting the same JSON handler. Apples-to-apples view: one client thread per connection. Higher req/sec is better.
| Server | Scheduling model | req/sec | vs Node.js |
|---|---|---|---|
| Tulpar listen_pool | worker pool sized to host CPU count, sharing accept() | 64 085 | 2.77× faster |
| Tulpar evented + cache | evented + wire-byte cache for cached_get routes | 62 057 | 2.68× faster |
| Tulpar listen_evented | single thread, poll()-multiplexed | 60 316 | 2.61× faster |
| Tulpar listen_async | OS thread spawned per connection | 50 244 | 2.17× faster |
| Tulpar listen | single thread, one request at a time | 29 458 | 1.27× faster |
| Node.js http | single-thread event loop | 23 133 | (baseline) |
| Python ThreadingHTTP | OS thread spawned per request | 14 755 | 1.57× slower |
5 of the Tulpar Wings listeners at this concurrency beat Node.js' built-in http, by 1.27×–2.77× depending on scheduling model.
12 000 GETs over 16 keep-alive connections; single localhost run; each server hosting the same JSON handler. Same per-thread workload as the low-concurrency block, scaled up to surface multi-core scaling. Higher req/sec is better.
| Server | Scheduling model | req/sec | vs Node.js |
|---|---|---|---|
| Tulpar listen_evented | single thread, poll()-multiplexed | 56 303 | 1.65× faster |
| Tulpar evented + cache | evented + wire-byte cache for cached_get routes | 55 843 | 1.64× faster |
| Tulpar listen_pool | worker pool sized to host CPU count, sharing accept() | 55 143 | 1.62× faster |
| Tulpar listen_async | OS thread spawned per connection | 54 385 | 1.59× faster |
| Node.js http | single-thread event loop | 34 138 | (baseline) |
| Tulpar listen | single thread, one request at a time | 28 422 | 1.20× slower |
| Python ThreadingHTTP | OS thread spawned per request | 14 611 | 2.34× slower |
4 of the Tulpar Wings listeners under this load beat Node.js' built-in http, by 1.59×–1.65× depending on scheduling model.
Reproduce locally: see benchmarks/CI.md for how to run the full CPU and HTTP benchmark suite.
Wings is the embedded HTTP framework. The front door is serve():
serve() picks the branded default port 8484, serve(8080) binds an
explicit port, and serve(8080, 4) runs a 4-worker thread pool. The
listeners below are the advanced modes behind it; the handler API stays
the same, only the scheduling model changes:
| Listener | Best for |
|---|---|
listen(port) |
Sync. One in-flight request. Simplest. |
listen_async(port) |
Thread per connection. Best for short bursts. |
listen_pool(port, n) |
Pre-spawned workers. Best sustained RPS. |
listen_evented(port) |
Single-thread + poll() / WSAPoll. Best for many idle keep-alive conns (chat, dashboards, SSE). |
wings_tls(port, cert, key) |
HTTPS via OpenSSL. Same handler API. |
All five share _request, _response, route counters, /healthz /
/metrics auto-routes, OPTIONS preflight handling, structured
logging, and OpenAPI 3.0 generation via wings_openapi(title, version).
Long-lived connection types (Server-Sent Events, WebSocket upgrade)
take over the socket and return {"_stream": 1} so the dispatcher
skips its envelope build — see Streaming
above and examples/api_wings_sse.tpr /
examples/32_wings_ws_frames.tpr
for end-to-end demos.
The full list lives at https://tulparlang.dev/reference/cli/; the short version:
tulpar <file.tpr> # Run via AOT (the only execution path; native speed)
tulpar build <file.tpr> [out] # Standalone native binary
tulpar fmt <file.tpr> # Source formatter
tulpar typecheck <file.tpr> # Standalone typechecker
tulpar pkg <subcommand> # Package manager:
# init, list, add, remove, install,
# search, info, publish
tulpar doc <file.tpr> # Markdown reference generator
tulpar debug <file.tpr> # DAP server (VS Code debugger)
tulpar --lsp # Language server (editor integration)
tulpar version # Show installed version
tulpar update [--check] # Self-update from tulparlang.dev
tulpar --help # Show command referenceCLI output language follows the system locale — Turkish on TR
machines, English everywhere else. Override with TULPAR_LANG=tr or
TULPAR_LANG=en. The [typecheck] warnings always run as a build
pre-pass; suppress with --no-typecheck or TULPAR_NO_TYPECHECK=1.
Prerequisites: GCC or Clang, LLVM 18+, CMake 3.14+. Optional:
OpenSSL (enables https:// for the HTTP client and wings_tls).
Linux / macOS:
./build.shWindows (MSYS2 MinGW64):
.\build.ps1
# or: build.batDirect CMake (incremental):
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -jbuild.sh and build.ps1 wipe the build directory each time. For
incremental rebuilds during development, use CMake directly. The
output is a tulpar (tulpar.exe on Windows) copied to the repo root
plus libtulpar_runtime.a linked by AOT-compiled user binaries.
// Static types with inference
int x = 42;
float pi = 3.14159;
str name = "Tulpar";
bool active = true;
// Number literals
int hex = 0xFF; // 255
int oct = 0o755; // 493
int bin = 0b1010; // 10
// First-class JSON
json user = {
"name": "Ali",
"age": 30,
"address": { "city": "Istanbul" }
};
print(user.address.city); // dot access works
// Custom types
type Person {
str name;
int age;
}
Person p = { name: "Ali", age: 25 };
// Control flow
for (int i = 0; i < 10; i++) { print(i); }
// Error handling
try {
risky();
} catch (e) {
print("Error: " + toString(e));
} finally {
cleanup();
}
// Threading
int mu = mutex_create();
func worker(json arg) {
mutex_lock(mu);
// critical section
mutex_unlock(mu);
}
int t = thread_create(worker, 42);
thread_detach(t);
Full guide at https://tulparlang.dev/guide/syntax/ · single-page language reference at https://tulparlang.dev/reference/language/.
All modules below are embedded in the binary — import "name"
just works, no package install required.
| Module | Purpose |
|---|---|
wings |
HTTP server — sync, async, pool, and evented listeners |
wings_tls |
HTTPS server with OpenSSL — same handler API as wings |
tulpar_api |
FastAPI-style routing & JSON envelopes on top of Wings |
router |
Express-style URL routing & middleware |
http_utils |
HTTP request parsing & response building primitives |
http_client |
Outbound HTTP/HTTPS — http_get, http_post_json, … |
middleware |
Built-in middleware (logger, CORS, auth, rate-limit) |
socket |
TCP socket wrappers + poll / non-blocking helpers |
async |
setTimeout / setInterval / promise scaffolding |
orm |
SQLite ORM — define_model, orm_create, orm_where |
test |
Jest-style assertion framework + suite runner |
Native built-ins (no import needed):
| Category | Functions |
|---|---|
| I/O | print, input, inputInt, inputFloat |
| Type conversion | toInt, toFloat, toString, toBool |
| Math | abs, sqrt, pow, mod, sin, cos, tan, log, exp, floor, ceil, round, random, randint, min, max |
| String | length, upper, lower, trim, split, join, replace, substring, contains, startsWith, endsWith, indexOf |
| Regex | regex_match, regex_search, regex_capture, regex_replace |
| CSV | csv_parse, csv_emit |
| Array / object | push, pop, length, range, keys |
| JSON | toJson, fromJson, parse_cookies |
| Date / time | timestamp, time_ms, now_iso8601, format_iso8601, parse_iso8601, weekday, date_add_seconds, clock_ms, sleep |
| File | file_read, file_write, file_exists, file_delete, file_append, file_glob |
| Process / env | env, exit |
| Sockets | socket_server, socket_client, socket_accept, socket_send, socket_receive, socket_close, socket_set_nonblocking, socket_poll |
| TLS (server) | tls_init, tls_accept, tls_recv, tls_send, tls_close, tls_ctx_free |
| HTTP (native) | http_request, http_parse_request, http_create_response, http_status_text, path_match, parse_query, http_recv_request, http_should_keepalive |
| Wings helpers | wings_openapi, wings_metrics_prom, wings_cookies, log_info, log_error, wings_current_fd, wings_sse_headers, wings_sse_event, wings_ws_upgrade, wings_ws_send_text, wings_ws_send_close, wings_ws_send_pong, wings_ws_send_frame, wings_ws_recv_frame, wings_ws_accept_key |
| Crypto / encode | sha1, sha1_hex, sha256, base64_encode, base64_decode |
| Database | db_open, db_execute, db_query, db_close (vendored SQLite3) |
| Threading | thread_create, thread_detach, thread_join, mutex_create, mutex_lock, mutex_unlock, mutex_destroy |
| Memory arena | arena_save, arena_restore (per-request bounded memory) |
TulparLang/
├── src/
│ ├── lexer/ # Tokenization
│ ├── parser/ # Recursive-descent parser, AST nodes
│ ├── typeinfer/ # Type inference (build pre-pass)
│ ├── aot/ # LLVM 18 AOT backend (the only execution path)
│ ├── vm/ # Shared runtime: aot_* builtins, arena allocator, value types
│ ├── lsp/ # Language Server Protocol
│ ├── fmt/ # Source formatter
│ ├── pkg/ # Package manager (tulpar.toml + lockfile)
│ ├── cli/ # Subcommands (update, etc.)
│ └── common/ # Localization, version, platform shims, TLS plumbing
├── lib/ # Standard library (Tulpar source, embedded at build)
├── runtime/ # cJSON, ARC heap, native FFI
├── examples/ # 47 example programs
├── benchmarks/ # Multi-language benchmark suite (CPU + HTTP)
├── tests/ # Smoke tests + lib/test.tpr regression suites
├── installer/ # Inno Setup script for Windows installer
├── wasm/ # WebAssembly target (separate build)
└── cmake/ # CMake modules + EmbedLibraries.cmake
Tulpar follows the C/Rust/Go model — a single AOT/LLVM execution path.
tulpar <file> AOT-compiles and runs; there is no VM fallback, so an AOT
failure is a hard error.
| Component | Role |
|---|---|
| AOT (LLVM 18) | The only execution path. LLVM IR → native via clang. |
src/vm/ runtime |
Shared runtime linked into AOT'd binaries (the aot_* builtins, arena allocator, value types) — not an interpreter. |
The bytecode VM interpreter and the REPL were removed in v3.0.0
(2026-06-15); --vm/--run are ignored with a warning and --repl prints a
removal notice. The legacy tree-walk interpreter and x64 JIT were retired
earlier, in May 2026. See STATUS.md.
Dozens of example programs live in examples/. A few highlights:
| File | Demonstrates |
|---|---|
01_hello_world.tpr |
Basic syntax, types, arithmetic |
06_data_structures.tpr |
Arrays + JSON |
10_try_catch.tpr |
Error handling |
12_threaded_server.tpr |
Threaded HTTP server |
13_database.tpr |
SQLite via the built-in db_* API |
api_wings_crud.tpr |
REST CRUD on top of Wings |
api_wings_sse.tpr |
Server-Sent Events via the streaming dispatcher |
32_wings_ws_frames.tpr |
WebSocket send/recv frame round-trip |
31_crypto_sse_ws.tpr |
sha1 / base64 / WS accept-key + SSE formatting |
tulpar_api_demo.tpr |
Full TulparAPI app with middleware |
benchmark.tpr |
The fib / loopsum benchmark workloads |
Run any of them with tulpar examples/<file>.tpr.
Full docs (Türkçe & English) at https://tulparlang.dev.
Quick links:
- Getting Started — install + first program
- Language Reference — single-page lookup
- Wings HTTP Server — listener API + routing
- Package Manager —
tulpar.toml, lockfile, semver ranges - CLI Reference — every flag and subcommand
Local docs in this repo:
- docs/PLATFORM_SUPPORT.md — per-OS prerequisites, build steps, troubleshooting
- RELEASING.md — how stable releases are cut
- STATUS.md — current shipping status + open gaps
- Fork the repository
- Create a feature branch (
git checkout -b feature/name) - Commit your changes
- Push to the branch
- Open a Pull Request
Issues and design discussions welcome at https://github.com/hamer1818/TulparLang/issues.
MIT — see LICENSE.
Hamza Ortatepe · @hamer1818