Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

501 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TulparLang

Build License Platform Website Releases

Python-easy syntax. C-class performance. HTTP-ready out of the box.


What is TulparLang?

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_tls stdlib.
  • First-class JSON — built-in type, literal syntax, dot access, toJson / fromJson round-trips, no library import required.
  • AOT-compiled native binariestulpar build foo.tpr produces a standalone executable you can ship without the Tulpar toolchain.
  • One-line installer with auto-update — iwr ... | iex on Windows, curl ... | bash on Linux/macOS, then tulpar update to roll forward.

Install

Windows (PowerShell):

iwr -useb https://tulparlang.dev/install.ps1 | iex

Linux / macOS:

curl -fsSL https://tulparlang.dev/install.sh | bash

Both 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.

Verifying releases

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.txt

Public 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.

Quick start

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.tpr

The 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).

Build a REST API in 8 lines

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"}

A persistent CRUD API in 7 lines

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.

Streaming (SSE / WebSocket)

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.

Package management

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 registry

tulpar 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.

Why TulparLang

  • Native speed. LLVM 18 AOT compilation. ~1.5–1.8× of gcc -O2 on integer microbenchmarks; on a localhost JSON-API microbenchmark the listen_async Wings listener is 1.91× Node.js' http and 2.91× CPython's ThreadingHTTPServer in throughput. See benchmarks/RESULTS.md for the full table and methodology.
  • No build step for prototyping. tulpar file.tpr runs in one step. tulpar build file.tpr produces 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. json is a built-in type with literal syntax ({"k": v}), dot access (obj.key), and toJson / fromJson round-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=tr or TULPAR_LANG=en.
  • Single-binary toolchain. One tulpar executable 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.

Performance

Baked from local benchmark run (best of 5). Last run: 2026-05-21T08:23:24Z UTC · commit d91f184 · runner Windows · 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.

CPU benchmarks

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.

HTTP throughput

3000 GETs across 4 keep-alive connections, single localhost loop. Same JSON handler running on every server.

Low concurrency

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.

High concurrency

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 — four ways to listen

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.

Command reference

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 reference

CLI 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.

Build from source

Prerequisites: GCC or Clang, LLVM 18+, CMake 3.14+. Optional: OpenSSL (enables https:// for the HTTP client and wings_tls).

Linux / macOS:

./build.sh

Windows (MSYS2 MinGW64):

.\build.ps1
# or: build.bat

Direct CMake (incremental):

cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j

build.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.

Language at a glance

// 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/.

Standard library

All modules below are embedded in the binaryimport "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)

Architecture

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

Execution model

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.

Examples

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.

Documentation

Full docs (Türkçe & English) at https://tulparlang.dev.

Quick links:

Local docs in this repo:

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/name)
  3. Commit your changes
  4. Push to the branch
  5. Open a Pull Request

Issues and design discussions welcome at https://github.com/hamer1818/TulparLang/issues.

License

MIT — see LICENSE.

Author

Hamza Ortatepe · @hamer1818


About

Statically-typed, AOT-compiled programming language with an LLVM backend — HTTP, JSON, SQLite, an ORM, and OpenAPI generation built into the runtime.

Topics

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages